#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  CREDITS VERSION crctab.c crctab.h makefile opts.h readme
#   release.notes version.h zmdm.c zmdm.h zmodem.doc zmodem.h zmrx.1
#   zmrx.c zmtx.1 zmtx.c
# Wrapped by paulj@xs4all on Mon Jul 18 01:50:22 1994
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f CREDITS -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"CREDITS\"
else
echo shar: Extracting \"CREDITS\" \(213 characters\)
sed "s/^X//" >CREDITS <<'END_OF_CREDITS'
Xcontributor               e-mail address                     item
XPaul Jongsma              paulj@hacktic.nl                   sunos port
XBart Massey               bart@cs.uoregon.edu                man pages
X
X
X
X
END_OF_CREDITS
if test 213 -ne `wc -c <CREDITS`; then
    echo shar: \"CREDITS\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f VERSION -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"VERSION\"
else
echo shar: Extracting \"VERSION\" \(5 characters\)
sed "s/^X//" >VERSION <<'END_OF_VERSION'
X1.02
END_OF_VERSION
if test 5 -ne `wc -c <VERSION`; then
    echo shar: \"VERSION\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f crctab.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"crctab.c\"
else
echo shar: Extracting \"crctab.c\" \(7950 characters\)
sed "s/^X//" >crctab.c <<'END_OF_crctab.c'
X
X/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
Xunsigned short crc16tab[256] = {
X    0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
X    0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
X    0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
X    0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
X    0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
X    0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
X    0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
X    0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
X    0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
X    0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
X    0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
X    0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
X    0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
X    0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
X    0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
X    0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
X    0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
X    0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
X    0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
X    0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
X    0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
X    0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
X    0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
X    0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
X    0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
X    0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
X    0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
X    0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
X    0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
X    0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
X    0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
X    0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0
X};
X
X/*
X * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
X * code or tables extracted from it, as desired without restriction.
X */
X
X/* First, the polynomial itself and its table of feedback terms.  The  */
X/* polynomial is                                                       */
X/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
X/* Note that we take it "backwards" and put the highest-order term in  */
X/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
X/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
X/* the MSB being 1.                                                    */
X
X/* Note that the usual hardware shift register implementation, which   */
X/* is what we're using (we're merely optimizing it by doing eight-bit  */
X/* chunks at a time) shifts bits into the lowest-order term.  In our   */
X/* implementation, that means shifting towards the right.  Why do we   */
X/* do it this way?  Because the calculated CRC must be transmitted in  */
X/* order from highest-order term to lowest-order term.  UARTs transmit */
X/* characters in order from LSB to MSB.  By storing the CRC this way,  */
X/* we hand it to the UART in the order low-byte to high-byte; the UART */
X/* sends each low-bit to hight-bit; and the result is transmission bit */
X/* by bit from highest- to lowest-order term without requiring any bit */
X/* shuffling on our part.  Reception works similarly.                  */
X
X/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
X/*                                                                     */
X/*     The table can be generated at runtime if desired; code to do so */
X/*     is shown later.  It might not be obvious, but the feedback      */
X/*     terms simply represent the results of eight shift/xor opera-    */
X/*     tions for all combinations of data and CRC register values.     */
X/*                                                                     */
X/*     The values must be right-shifted by eight bits by the "updcrc"  */
X/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
X/*     hardware you could probably optimize the shift in assembler by  */
X/*     using byte-swap instructions.                                   */
X
Xlong crc32tab[] = { /* CRC polynomial 0xedb88320 */
X0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
X0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
X0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
X0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
X0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
X0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
X0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
X0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
X0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
X0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
X0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
X0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
X0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
X0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
X0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
X0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
X0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
X0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
X0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
X0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
X0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
X0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
X0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
X0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
X0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
X0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
X0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
X0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
X0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
X0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
X0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
X0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
X};
X
X/* End of crctab.c */
END_OF_crctab.c
if test 7950 -ne `wc -c <crctab.c`; then
    echo shar: \"crctab.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f crctab.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"crctab.h\"
else
echo shar: Extracting \"crctab.h\" \(726 characters\)
sed "s/^X//" >crctab.h <<'END_OF_crctab.h'
X/*
X * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. 
X *  NOTE: First srgument must be in range 0 to 255.
X *        Second argument is referenced twice.
X * 
X * Programmers may incorporate any or all code into their programs, 
X * giving proper credit within the source. Publication of the 
X * source routines is permitted so long as proper credit is given 
X * to Stephen Satchell, Satchell Evaluations
X *
X * wow ! a whole macro ! lets copyright it.....
X */
X
Xextern unsigned short int  crc16tab[0x100];
Xextern unsigned long crc32tab[0x100];
X
X#define UPDCRC16(cp, crc) (crc16tab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
X
X#define UPDCRC32(b, c)    (crc32tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
X
X
END_OF_crctab.h
if test 726 -ne `wc -c <crctab.h`; then
    echo shar: \"crctab.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"makefile\"
else
echo shar: Extracting \"makefile\" \(336 characters\)
sed "s/^X//" >makefile <<'END_OF_makefile'
XCC=gcc
X#CFLAGS=-O -DUNITE
XCFLAGS=-O -DSUNOS4
X
Xall:	zmtx zmrx
X
Xzmtx:	zmtx.o zmdm.o crctab.o
X	$(CC) $(CFLAGS) $(OFLAG) zmtx.o zmdm.o crctab.o -o zmtx
X
Xzmrx:	zmrx.o zmdm.o crctab.o
X	$(CC) $(CFLAGS) $(OFLAG) zmrx.o zmdm.o crctab.o -o zmrx
X
Xzmtx.o:		zmtx.c
Xzmrx.o:		zmrx.c
X
Xzmdm.o:		zmdm.c
Xcrctab.o:	crctab.c
X
Xclean:
X	rm *.o
X	rm zmtx zmrx
X
X
END_OF_makefile
if test 336 -ne `wc -c <makefile`; then
    echo shar: \"makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f opts.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"opts.h\"
else
echo shar: Extracting \"opts.h\" \(259 characters\)
sed "s/^X//" >opts.h <<'END_OF_opts.h'
X/*
X * program argument parsing macros
X */
X
X#define OPT_STRING(l,p) case l: { p = s+1;       *s = 0; s-- ; break; }
X#define OPT_BOOL(l,p)   case l: { p = TRUE;                    break; }
X#define OPT_NUM(l,p)    case l: { p = atoi(s+1); *s = 0; s-- ; break; }
END_OF_opts.h
if test 259 -ne `wc -c <opts.h`; then
    echo shar: \"opts.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f readme -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"readme\"
else
echo shar: Extracting \"readme\" \(5244 characters\)
sed "s/^X//" >readme <<'END_OF_readme'
Xthis file was abstracted from the original zmodem.doc after one
Xnight I decided I had enough of all this marketing hype and wanted
Xto know what zmodem was all about without having to wade hip-deep
Xthrough advertising slogans. this text is !(C) MCS 1994
X
Xthe intended audience of this document are programmers looking for
Xa compact reference text on how zmodem works and what you should
Xknow to be able to implement conforming zmodem send and receive
Xsoftware. this is definitely not an 'end user' document and the
Xexamples and data structures are strongly biased towards the 'C'
Xlanguage. (what ? are there other languages ??)
X
Xa lot of work went into the preparation of this document; although
XI'm afraid I can't guarantee it's correctness. Jacques Mattheij
Xor MCS shall not be liable for any damages whatsoever. this file
Xis provided 'as is' for no fee whatsoever. use is at your own risk.
Xif these terms are unacceptable to you than delete these files NOW!.
X
Xchanges relative to zmodem.doc as provided by various sources:
X
X  - removal of all historical information
X  - removal of all plugs relating to omen technology products etc.
X    if something is public domain then leave it at that
X  - removal of all 'poetry' 
X  - removal of all references to xmodem ymodem kermit and so on
X  - removal of all overstrike typesetting tricks which make this
X    file practically uneditable and unviewable
X  - removal of a lot of irrelevant but nice facts about the wheater and
X    some other nice subjects for conversation
X  - removal of all implementation specific details referring to those
X    antiques of telecom 'rz' and 'sz'
X  - manifest constants added in the text.
X  - moved footnotes to the appropriate place in the text
X  - changed number base from octal to hex (welcome to the nineties)
X    admitted it looks less ivory tower but it reads a lot easier
X    for those who started programming after 1959
X
Xsome recomendations....
X
Xa lot has changed since the original zmodem came out. not so much in the 
Xprotocol as well as in the world around it. I would like to de-advertise 
Xseveral of zmodem's advanced features:
X
X  - command sending.
X    this is the hackers dream come true. a formalized backdoor into any
X    site supporting this file transfer protocol with a relatively easy
X    defeated security mechanism. don't implement it; just refuse it.
X
X  - file translation.
X    the zmodem protocol specification below contains a number of facilities
X    to change a file between one os and the next. THIS IS NOT THE PLACE !
X    a file TRANSFER protocol should do just that and with a minimum of fuss.
X    if you have to start worrying about wheter zmodem just garbled that 4MB
X    zip file of yours just downloaded from the states at $1 a minute you're 
X    ready for some agression. another point may be that the file size will
X    change which may give rise to a lot of bugs in zmodem implementations on
X    the far side of wherever you are downloading to / from. stick to
X    binary. it helps.
X
X  - use CRC32 and not CRC16
X    apart from the obvious (better error detection) the original CRC16 
X    implementation is buggy
X
X  - do not send the serial number in the ZFILE frame. this is not a 
X    very useful function
X
X  - in many places in the orignal zmodem.doc it was suggested that if
X    this or that failed you should step down and attempt a ymodem 
X    transfer. don't do that ! users know pretty good what they want
X    and if they specify a zmodem transfer give them one or give them
X    nothing. don't try to be smart. probably something is wrong and it
X    is better to exit with some informative message than to go ahead
X    with the wrong protocol; apart from keeping your source clean.
X
X  - don't use or implement the run length encoding. it is greatly 
X    hampered by not checking if run length encoding is needed. if
X    you specify that ability you're stuck with it. nowadays with
X    zip 2.0/unzip 5.0 and better there is absolutely no need for a file 
X    transfer protocol to busy itself with compression. for $200
X    you can buy a mnp class 10 modem which does all that and more
X    completely transparently without possibly triggering a host of
X    bugs in a relatively little exercised part of your hosts software.
X
X  - lzw encoding; see run length encoding.
X
X  - don't use the 'ZXSPARSE' option. chances of finding a system that
X    implements it are small and even then 10 : 1 that the file will
X    be sent compressed.
X
X  - don't send the 'rz\r' used in the original documentation.
X    this is a very nasty way of making a public domain protocol
X    dependant on a company. (sorry had to abide by that in the end;
X    some implementations trigger auto downloads on this)
X
XIn general; keep it simple ! stick to multiple file binary transfers and
Xtry to get some speed out of those boxes. time is spent well on optimizing
Xand cleaning your source rather than on some obscure seldomely used 
Xfeature which will clutter your code. 
X
XWhenever I give an example of how not to program in 'C' I refer to the
Xrz.c and sz.c sources. In more than one way these are true 'classics'.
XIf you intend to implement zmodem don't bother with these dinosaurs
X(to use a popular term); better to write it clean from the start.
X
X
X
X
X
X
X
X
X
END_OF_readme
if test 5244 -ne `wc -c <readme`; then
    echo shar: \"readme\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f release.notes -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"release.notes\"
else
echo shar: Extracting \"release.notes\" \(3496 characters\)
sed "s/^X//" >release.notes <<'END_OF_release.notes'
X1.02 release notes (18/07/94)
X
XCrash recovery now supported and the file date is set (which didn't happen
Xso far.) Added a CREDITS file. Mr. Paul Vixie (paul@vix.com; moderator
Xof comp.sources.unix) is currently reviewing the source in order to resolve
Xthe copyright mess. Shouldn't be a problem.
X
X1.01 release notes (17/07/94)
X
XWow, how's that, to be accussed of stealing copyrighted code by Mr. Forsberg
Xhimself... (well, it did cause the release to be retracted from 
Xcomp.sources.unix it's a shame). Fortunately it isn't true as anyone (except
Xmaybe Mr. Forsberg) can see for themselves. It seems we now have manual pages
Xwhich were contributed by Bart Massey (bart@cs.uoregon.edu).
Xto avoid problems in passing the file through ms-dos machines the archive
Xnow goes as zmXXX.zip where XXX is the version number. So far no technical
Xchanges; only a marked failure to communicate with sz and rz has been noted.
XAnybody interested in fixing this is welcome to do so; please mail us the 
Xchanges and they will be incorporated in the next release. I would like to
Xexpress my surprise at the ease with which the moderator of a usenet group
Xcan be bullied into retracting other peoples postings. 
X
X1.00 release notes (15/07/94)
X
XHi there,
X
XThis is the very first release of this fresh and unstable Zmodem implementation.
X
XMCS allows you to use and copy/modify this source under the following
Xconditions:
X
X  - MCS or Jacques Mattheij shall not be liable for any damages arising
X    from the use of this code
X  - the archive must be distributed as a whole leaving version numbers intact.
X    please do not distribute modifications; mail them back to us for inclusion
X    in the next release which should follow each other fairly quickly in 
X    the beginning
X  - you will not use this software for commercial purposes.
X    (commercial licenses are available contact us for info)
X
XYes! that's all the legal stuff you'll be getting from me. I'm a programmer
Xnot a lawyer. (the average piece of freeware these days can be shrunk
Xto an easy 50% without compression by removing the 200 line copyright message
Xabove each module).
X
XThe reason this code and the corresponding documentation were created is
Xdissatisfaction with the current public domain versions of zmodem and their
Xdocumentation. As of this writing the code runs on exactly ONE operating 
Xsystem and you are very likely never to have heard of it. (Unite!; runs on
Xthe 386 and better; microkernel etc..) So, this is likely not a plug and
Xplay package but with some help from the world out there and xs4all
X(the public internet access point in Amsterdam, The Netherlands) we can
Xturn it in to one. If someone would like to do a port; has a bug report or
Xwould like to send us a message use any of the possibilities below.
XEnjoy it and on to the next release
X
X             Jacques Mattheij.
X
X/* contact us through (in order of preference)                                */
X/*                                                                            */
X/*   email:          jacquesm@hacktic.nl                                      */
X/*   mail:           MCS                                                      */
X/*                   Prinses Beatrixlaan 535                                  */
X/*                   2284 AT  RIJSWIJK                                        */
X/*                   The Netherlands                                          */
X/*   voice phone:    31+070-3936926                                           */
X
X
X
X
X
END_OF_release.notes
if test 3496 -ne `wc -c <release.notes`; then
    echo shar: \"release.notes\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f version.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"version.h\"
else
echo shar: Extracting \"version.h\" \(85 characters\)
sed "s/^X//" >version.h <<'END_OF_version.h'
X/* the release version number as printed by the programs */
X
X#define VERSION "1.02"
X
END_OF_version.h
if test 85 -ne `wc -c <version.h`; then
    echo shar: \"version.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zmdm.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zmdm.c\"
else
echo shar: Extracting \"zmdm.c\" \(19033 characters\)
sed "s/^X//" >zmdm.c <<'END_OF_zmdm.c'
X/******************************************************************************/
X/* Project : Unite!       File : zmodem general        Version : 1.02         */
X/*                                                                            */
X/* (C) Mattheij Computer Service 1994                                         */
X/*                                                                            */
X/* contact us through (in order of preference)                                */
X/*                                                                            */
X/*   email:          jacquesm@hacktic.nl                                      */
X/*   mail:           MCS                                                      */
X/*                   Prinses Beatrixlaan 535                                  */
X/*                   2284 AT  RIJSWIJK                                        */
X/*                   The Netherlands                                          */
X/*   voice phone:    31+070-3936926                                           */
X/******************************************************************************/
X
X/*
X * zmodem primitives and other code common to zmtx and zmrx
X */
X
X#include <stdio.h>
X#include <termios.h>
X#include <signal.h>
X#ifdef UNITE
X#include <sys/select.h>
X#endif
X#ifdef SUNOS4
X#include <sys/types.h>
X#endif
X
X#include <sys/time.h>
X
X#include "zmodem.h"
X#define ZMDM
X#include "zmdm.h"
X#include "crctab.h"
X
X#if 0
X#define DEBUG
X#endif
X
Xint receive_32_bit_data;
Xint raw_trace;
Xint want_fcs_32 = TRUE;
Xlong ack_file_pos;				/* file position used in acknowledgement of correctly */
X								/* received data subpackets */
X
X/*
X * routines to make the io channel raw and restore it
X * to its normal state.
X */
X
Xstruct termios old_termios;
X
Xvoid
Xfd_init()
X
X{
X	struct termios t;
X
X	tcgetattr(0,&old_termios);
X
X	tcgetattr(0,&t);
X
X	t.c_iflag = 0;
X
X	t.c_oflag = 0;
X
X	t.c_lflag = 0;
X
X	t.c_cflag |= CS8;
X
X	tcsetattr(0,TCSANOW,&t);
X}
X
Xvoid
Xfd_exit()
X
X{
X	tcsetattr(0,TCSANOW,&old_termios);
X}
X
X/*
X * read bytes as long as rdchk indicates that
X * more data is available.
X */
X
Xvoid
Xrx_purge(void)
X
X{
X	struct timeval t;
X	fd_set f;
X	unsigned char c;
X
X	t.tv_sec = 0;
X	t.tv_usec = 0;
X
X	FD_ZERO(&f);
X	FD_SET(0,&f);
X
X	while (select(1,&f,NULL,NULL,&t)) {
X		read(0,&c,1);		
X	}
X
X}
X
Xint last_sent = -1;
X
X/* 
X * transmit a character. 
X * this is the raw modem interface
X */
X
Xvoid
Xtx_raw(int c)
X
X{
X#ifdef DEBUG
X	if (raw_trace) {
X		fprintf(stderr,"%02x ",c);
X	}
X#endif
X
X	last_sent = c & 0x7f;
X
X	putchar(c);
X}
X
X/*
X * transmit a character ZDLE escaped
X */
X
Xvoid
Xtx_esc(int c)
X
X{
X	tx_raw(ZDLE);
X	/*
X	 * exclusive or; not an or so ZDLE becomes ZDLEE
X	 */
X	tx_raw(c ^ 0x40);
X}
X
X/*
X * transmit a character; ZDLE escaping if appropriate
X */
X
Xvoid
Xtx(unsigned char c)
X
X{
X	switch (c) {
X		case ZDLE:
X			tx_esc(c);
X			return;
X			break;
X		case 0x8d:
X		case 0x0d:
X			if (escape_all_control_characters && last_sent == '@') {
X				tx_esc(c);
X				return;
X			}
X			break;
X		case 0x10:
X		case 0x90:
X		case 0x11:
X		case 0x91:
X		case 0x13:
X		case 0x93:
X			tx_esc(c);
X			return;
X			break;
X		default:
X			if (escape_all_control_characters && (c & 0x60) == 0) {
X				tx_esc(c);
X				return;
X			}
X			break;
X	}
X	/*
X	 * anything that ends here is so normal we might as well transmit it.
X	 */
X	tx_raw((int) c);
X}
X
X/*
X * send the bytes accumulated in the output buffer.
X */
X
Xvoid
Xtx_flush(void)
X
X{
X	fflush(stdout);
X}
X
X/* 
X * transmit a hex header.
X * these routines use tx_raw because we're sure that all the
X * characters are not to be escaped.
X */
X
Xvoid
Xtx_nibble(int n)
X
X{
X	n &= 0x0f;
X	if (n < 10) {
X		n += '0';
X	}
X	else {
X		n += 'a' - 10;
X	}
X
X	tx_raw(n);
X}
X
Xvoid
Xtx_hex(int h)
X
X{
X	tx_nibble(h >> 4);
X	tx_nibble(h);
X}
X
Xvoid
Xtx_hex_header(unsigned char * p)
X
X{
X	int i;
X	unsigned short int crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"tx_hheader : ");
X#endif
X
X	tx_raw(ZPAD);
X	tx_raw(ZPAD);
X	tx_raw(ZDLE);
X
X	if (use_variable_headers) {
X		tx_raw(ZVHEX);
X		tx_hex(HDRLEN);
X	}
X	else {
X		tx_raw(ZHEX);
X	}
X
X	/*
X 	 * initialise the crc
X	 */
X
X	crc = 0;
X
X	/*
X 	 * transmit the header
X	 */
X
X	for (i=0;i<HDRLEN;i++) {
X		tx_hex(*p);
X		crc = UPDCRC16(*p, crc);
X		p++;
X	}
X
X	/*
X 	 * update the crc as though it were zero
X	 */
X
X	crc = UPDCRC16(0,crc);
X	crc = UPDCRC16(0,crc);
X
X	/* 
X	 * transmit the crc
X	 */
X
X	tx_hex(crc >> 8);
X	tx_hex(crc);
X
X	/*
X	 * end of line sequence
X	 */
X
X	tx_raw(0x0d);
X	tx_raw(0x0a);
X
X	tx_raw(XON);
X
X	tx_flush();
X
X#ifdef DEBUG
X	fprintf(stderr,"\n");
X#endif
X}
X
X/*
X * Send ZMODEM binary header hdr
X */
X
Xvoid
Xtx_bin32_header(unsigned char * p)
X
X{
X	int i;
X	unsigned long crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"tx binary header 32 bits crc\n");
X	raw_trace = 1;
X#endif
X
X	tx_raw(ZPAD);
X	tx_raw(ZPAD);
X	tx_raw(ZDLE);
X
X	if (use_variable_headers) {
X		tx_raw(ZVBIN32);
X		tx(HDRLEN);
X	}
X	else {
X		tx_raw(ZBIN32);
X	}
X
X	crc = 0xffffffffL;
X
X	for (i=0;i<HDRLEN;i++) {
X		crc = UPDCRC32(*p,crc);
X		tx(*p++);
X	}
X
X	crc = ~crc;
X
X	tx(crc);
X	tx(crc >> 8);
X	tx(crc >> 16);
X	tx(crc >> 24);
X}
X
Xvoid
Xtx_bin16_header(unsigned char * p)
X
X{
X	int i;
X	unsigned int crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"tx binary header 16 bits crc\n");
X#endif
X
X	tx_raw(ZPAD);
X	tx_raw(ZPAD);
X	tx_raw(ZDLE);
X
X	if (use_variable_headers) {
X		tx_raw(ZVBIN);
X		tx(HDRLEN);
X	}
X	else {
X		tx_raw(ZBIN);
X	}
X
X	crc = 0;
X
X	for (i=0;i<HDRLEN;i++) {
X		crc = UPDCRC16(*p,crc);
X		tx(*p++);
X	}
X
X	crc = UPDCRC16(0,crc);
X	crc = UPDCRC16(0,crc);
X
X	tx(crc >> 8);
X	tx(crc);
X}
X
X
X/* 
X * transmit a header using either hex 16 bit crc or binary 32 bit crc
X * depending on the receivers capabilities
X * we dont bother with variable length headers. I dont really see their
X * advantage and they would clutter the code unneccesarily
X */
X
Xvoid
Xtx_header(unsigned char * p)
X
X{
X	if (can_fcs_32) {
X		if (want_fcs_32) {
X			tx_bin32_header(p);
X		}
X		else {
X			tx_bin16_header(p);
X		}
X	}
X	else {
X		tx_hex_header(p);
X	}
X}
X
X/*
X * data subpacket transmission
X */
X
Xvoid
Xtx_32_data(int sub_frame_type,unsigned char * p,int l)
X
X{
X	int c;
X	unsigned long crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"tx_32_data\n");
X#endif
X
X	crc = 0xffffffffl;
X
X	while (l > 0) {
X		crc = UPDCRC32(*p,crc);
X		tx(*p++);
X		l--;
X	}
X
X	crc = UPDCRC32(sub_frame_type, crc);
X
X	tx_raw(ZDLE);
X	tx_raw(sub_frame_type);
X
X	crc = ~crc;
X
X	tx((int) (crc      ) & 0xff);
X	tx((int) (crc >> 8 ) & 0xff);
X	tx((int) (crc >> 16) & 0xff);
X	tx((int) (crc >> 24) & 0xff);
X}
X
Xvoid
Xtx_16_data(int sub_frame_type,unsigned char * p,int l)
X
X{
X	unsigned short crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"tx_16_data\n");
X#endif
X
X	crc = 0;
X
X	while (l > 0) {
X		crc = UPDCRC16(*p,crc);
X		tx(*p++);
X		l--;
X	}
X
X	crc = UPDCRC16(sub_frame_type,crc);
X
X	tx_raw(ZDLE); 
X	tx_raw(sub_frame_type);
X	
X	crc = UPDCRC16(0,crc);
X	crc = UPDCRC16(0,crc);
X
X	tx(crc >> 8);
X	tx(crc);
X}
X
X/*
X * send a data subpacket using crc 16 or crc 32 as desired by the receiver
X */
X
Xvoid
Xtx_data(int sub_frame_type,unsigned char * p, int l)
X
X{
X	if (want_fcs_32 && can_fcs_32) {
X		tx_32_data(sub_frame_type,p,l);
X	}
X	else {	
X		tx_16_data(sub_frame_type,p,l);
X	}
X
X	if (sub_frame_type == ZCRCW) {
X		tx_raw(XON);
X	}
X
X	tx_flush();
X}
X
Xvoid
Xtx_pos_header(int type,long pos) 
X
X{
X	char header[5];
X
X	header[0]   = type;
X	header[ZP0] =  pos        & 0xff;
X	header[ZP1] = (pos >>  8) & 0xff;
X	header[ZP2] = (pos >> 16) & 0xff;
X	header[ZP3] = (pos >> 24) & 0xff;
X
X	tx_hex_header(header);
X}
X
Xvoid
Xtx_znak()
X
X{
X	fprintf(stderr,"tx_znak\n");
X
X	tx_pos_header(ZNAK,ack_file_pos);
X}
X
Xvoid
Xtx_zskip()
X
X{
X	tx_pos_header(ZSKIP,0L);
X}
X
X/*
X * receive any style header within timeout milliseconds
X */
X
Xvoid
Xalrm(int a)
X
X{
X	signal(SIGALRM,SIG_IGN);
X}
X
Xint
Xrx_poll()
X
X{
X	struct timeval t;
X	fd_set f;
X	unsigned char c;
X
X	t.tv_sec = 0;
X	t.tv_usec = 0;
X
X	FD_ZERO(&f);
X	FD_SET(0,&f);
X
X	if (select(1,&f,NULL,NULL,&t)) {
X		return 1;
X	}
X
X	return 0;
X}
X
Xunsigned char inputbuffer[1024];
Xint n_in_inputbuffer = 0;
Xint inputbuffer_index;
X
X/*
X * rx_raw ; receive a single byte from the line.
X * reads as many are available and then processes them one at a time
X * check the data stream for 5 consecutive CAN characters;
X * and if you see them abort. this saves a lot of clutter in
X * the rest of the code; even though it is a very strange place
X * for an exit. (but that was wat session abort was all about.)
X */
X
Xinline
Xint
Xrx_raw(int to)
X
X{
X	int n;
X	unsigned char c;
X	static int n_cans = 0;
X
X	if (n_in_inputbuffer == 0) {
X		/*
X		 * change the timeout into seconds; minimum is 1
X		 */
X
X		to /= 1000;
X		if (to == 0) {
X			to++;
X		}
X
X		/*
X	 	 * setup an alarm in case io takes too long
X		 */
X
X		signal(SIGALRM,alrm);
X
X		to /= 1000;
X
X		if (to == 0) {
X			to = 2;
X		}
X
X		alarm(to);
X
X		n_in_inputbuffer = read(0,inputbuffer,1024);
X
X		if (n_in_inputbuffer <= 0) {
X			n_in_inputbuffer = 0;
X		}
X
X		/*
X	 	 * cancel the alarm in case it did not go off yet
X		 */
X
X		signal(SIGALRM,SIG_IGN);
X
X		if (n_in_inputbuffer < 0 && (errno != 0 && errno != EINTR)) {
X			fprintf(stderr,"zmdm : fatal error reading device\n");
X			exit(1);
X		}
X
X		if (n_in_inputbuffer == 0) {
X			return TIMEOUT;
X		}
X
X		inputbuffer_index = 0;
X	}
X
X	c = inputbuffer[inputbuffer_index++];
X	n_in_inputbuffer--;
X
X	if (c == CAN) {
X		n_cans++;
X		if (n_cans == 5) {
X			/*
X			 * the other side is serious about this. just shut up;
X			 * clean up and exit.
X			 */
X			cleanup();
X
X			exit(CAN);
X		}
X	}
X	else {
X		n_cans = 0;
X	}
X
X	return c;
X}
X
X/*
X * rx; receive a single byte undoing any escaping at the
X * sending site. this bit looks like a mess. sorry for that
X * but there seems to be no other way without incurring a lot
X * of overhead. at least like this the path for a normal character
X * is relatively short.
X */
X
Xinline
Xint
Xrx(int to)
X
X{
X	int c;
X
X	/*
X	 * outer loop for ever so for sure something valid
X	 * will come in; a timeout will occur or a session abort
X	 * will be received.
X	 */
X
X	while (TRUE) {
X
X		/*
X	 	 * fake do loop so we may continue
X		 * in case a character should be dropped.
X		 */
X
X		do {
X			c = rx_raw(to);
X			if (c == TIMEOUT) {
X				return c;
X			}
X	
X			switch (c) {
X				case ZDLE:
X					break;
X				case 0x11:
X				case 0x91:
X				case 0x13:
X				case 0x93:
X					continue;			
X					break;
X				default:
X					/*
X	 				 * if all control characters should be escaped and 
X					 * this one wasnt then its spurious and should be dropped.
X					 */
X					if (escape_all_control_characters && (c & 0x60) == 0) {
X						continue;
X					}
X					/*
X					 * normal character; return it.
X					 */
X					return c;
X			}
X		} while (FALSE);
X	
X		/*
X	 	 * ZDLE encoded sequence or session abort.
X		 * (or something illegal; then back to the top)
X		 */
X
X		do {
X			c = rx_raw(to);
X
X			if (c == 0x11 || c == 0x13 || c == 0x91 || c == 0x93 || c == ZDLE) {
X				/*
X				 * these can be dropped.
X				 */
X				continue;
X			}
X
X			switch (c) {
X				/*
X				 * these four are really nasty.
X				 * for convenience we just change them into 
X				 * special characters by setting a bit outside the
X				 * first 8. that way they can be recognized and still
X				 * be processed as characters by the rest of the code.
X				 */
X				case ZCRCE:
X				case ZCRCG:
X				case ZCRCQ:
X				case ZCRCW:
X					return (c | ZDLEESC);
X					break;
X				case ZRUB0:
X					return 0x7f;
X					break;
X				case ZRUB1:
X					return 0xff;
X					break;
X				default:
X					if (escape_all_control_characters && (c & 0x60) == 0) {
X						/*
X						 * a not escaped control character; probably
X						 * something from a network. just drop it.
X						 */
X						continue;
X					}
X					/*
X					 * legitimate escape sequence.
X					 * rebuild the orignal and return it.
X					 */
X					if ((c & 0x60) == 0x40) {
X						return c ^ 0x40;
X					}
X					break;
X			}
X		} while (FALSE);
X	}
X
X	/*
X	 * not reached.
X	 */
X
X	return 0;
X}
X
X/*
X * receive a data subpacket as dictated by the last received header.
X * return 2 with correct packet and end of frame
X * return 1 with correct packet frame continues
X * return 0 with incorrect frame.
X * return TIMEOUT with a timeout
X * if an acknowledgement is requested it is generated automatically
X * here. 
X */
X
X/*
X * data subpacket reception
X */
X
Xint
Xrx_32_data(unsigned char * p,int * l)
X
X{
X	int c;
X	unsigned long rxd_crc;
X	unsigned long crc;
X	int sub_frame_type;
X
X#ifdef DEBUG
X	fprintf(stderr,"rx_32_data\n");
X#endif
X
X	crc = 0xffffffffl;
X
X	do {
X		c = rx(1000);
X
X		if (c == TIMEOUT) {
X			return TIMEOUT;
X		}
X		if (c < 0x100) {
X			crc = UPDCRC32(c,crc);
X			*p++ = c;
X			(*l)++;
X			continue;
X		}
X	} while (c < 0x100);
X
X	sub_frame_type = c & 0xff;
X
X	crc = UPDCRC32(sub_frame_type, crc);
X
X	crc = ~crc;
X
X	rxd_crc  = rx(1000);
X	rxd_crc |= rx(1000) << 8;
X	rxd_crc |= rx(1000) << 16;
X	rxd_crc |= rx(1000) << 24;
X
X	if (rxd_crc != crc) {
X		return FALSE;
X	}
X
X	ack_file_pos += *l;
X
X	return sub_frame_type;
X}
X
Xint
Xrx_16_data(register unsigned char * p,int * l)
X
X{
X	register int c;
X	int sub_frame_type;
X 	register unsigned short crc;
X	unsigned short rxd_crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"rx_16_data\n");
X#endif
X
X	crc = 0;
X
X	do {
X		c = rx(5000);
X
X		if (c == TIMEOUT) {
X			return TIMEOUT;
X		}
X		if (c < 0x100) {
X			crc = UPDCRC16(c,crc);
X			*p++ = c;
X			(*l)++;
X		}
X	} while (c < 0x100);
X
X	sub_frame_type = c & 0xff;
X
X	crc = UPDCRC16(sub_frame_type,crc);
X
X	crc = UPDCRC16(0,crc);
X	crc = UPDCRC16(0,crc);
X
X	rxd_crc  = rx(1000) << 8;
X	rxd_crc |= rx(1000);
X
X	if (rxd_crc != crc) {
X		return FALSE;
X	}
X
X	ack_file_pos += *l;
X
X	return sub_frame_type;
X}
X
Xint
Xrx_data(unsigned char * p, int * l)
X
X{
X	unsigned char zack_header[] = { ZACK, 0, 0, 0, 0 };
X	int sub_frame_type;
X	long pos;
X
X	/*
X	 * fill in the file pointer in case acknowledgement is requested.	
X	 * the ack file pointer will be updated in the subpacket read routine;
X	 * so we need to get it now
X	 */
X
X	pos = ack_file_pos;
X
X	/*
X	 * receive the right type of frame
X	 */
X
X	*l = 0;
X
X	if (receive_32_bit_data) {
X		sub_frame_type = rx_32_data(p,l);
X	}
X	else {	
X		sub_frame_type = rx_16_data(p,l);
X	}
X
X	switch (sub_frame_type)  {
X		case TIMEOUT:
X			return TIMEOUT;
X			break;
X		/*
X		 * frame continues non-stop
X		 */
X		case ZCRCG:
X			return FRAMEOK;
X			break;
X		/*
X		 * frame ends
X		 */
X		case ZCRCE:
X			return ENDOFFRAME;
X			break;
X		/*
X 		 * frame continues; ZACK expected
X		 */
X		case ZCRCQ:		
X			tx_pos_header(ZACK,pos);
X			return FRAMEOK;
X			break;
X		/*
X		 * frame ends; ZACK expected
X		 */
X		case ZCRCW:
X			tx_pos_header(ZACK,pos);
X			return ENDOFFRAME;
X			break;
X	}
X
X	return FALSE;
X}
X
Xinline
Xint
Xrx_nibble(int to) 
X
X{
X	int c;
X
X	c = rx(to);
X
X	if (c == TIMEOUT) {
X		return c;
X	}
X
X	if (c > '9') {
X		if (c < 'a' || c > 'f') {
X			/*
X			 * illegal hex; different than expected.
X			 * we might as well time out.
X			 */
X			return TIMEOUT;
X		}
X
X		c -= 'a' - 10;
X	}
X	else {
X		if (c < '0') {
X			/*
X			 * illegal hex; different than expected.
X			 * we might as well time out.
X			 */
X			return TIMEOUT;
X		}
X		c -= '0';
X	}
X
X	return c;
X}
X
Xint
Xrx_hex(int to)
X
X{
X	int n1;
X	int n0;
X
X	n1 = rx_nibble(to);
X
X	if (n1 == TIMEOUT) {
X		return n1;
X	}
X
X	n0 = rx_nibble(to);
X
X	if (n0 == TIMEOUT) {
X		return n0;
X	}
X
X	return (n1 << 4) | n0;
X}
X
X/*
X * receive routines for each of the six different styles of header.
X * each of these leaves rxd_header_len set to 0 if the end result is
X * not a valid header.
X */
X
Xvoid
Xrx_bin16_header(int to)
X
X{
X	int c;
X	int n;
X	unsigned short int crc;
X	unsigned short int rxd_crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"rx binary header 16 bits crc\n");
X#endif
X
X	crc = 0;
X
X	for (n=0;n<5;n++) {
X		c = rx(to);
X		if (c == TIMEOUT) {
X#ifdef DEBUG
X			fprintf(stderr,"timeout\n");
X#endif
X			return;
X		}
X		crc = UPDCRC16(c,crc);
X		rxd_header[n] = c;
X	}
X
X	crc = UPDCRC16(0,crc);
X	crc = UPDCRC16(0,crc);
X
X	rxd_crc  = rx(1000) << 8;
X	rxd_crc |= rx(1000);
X
X	if (rxd_crc != crc) {
X#ifdef DEBUG
X		fprintf(stderr,"bad crc %4.4x %4.4x\n",rxd_crc,crc);
X#endif
X		return;
X	}
X
X	rxd_header_len = 5;
X}
X
Xvoid
Xrx_hex_header(int to)
X
X{
X	int c;
X	int i;
X	unsigned short int crc = 0;
X	unsigned short int rxd_crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"rx_hex_header : ");
X#endif
X	for (i=0;i<5;i++) {
X		c = rx_hex(to);
X		if (c == TIMEOUT) {
X			return;
X		}
X		crc = UPDCRC16(c,crc);
X
X		rxd_header[i] = c;
X	}
X
X	crc = UPDCRC16(0,crc);
X
X	crc = UPDCRC16(0,crc);
X
X	/*
X	 * receive the crc
X	 */
X
X	c = rx_hex(to);
X
X	if (c == TIMEOUT) {
X		return;
X	}
X
X	rxd_crc = c << 8;
X
X	c = rx_hex(to);
X
X	if (c == TIMEOUT) {
X		return;
X	}
X
X	rxd_crc |= c;
X
X	if (rxd_crc == crc) {
X		rxd_header_len = 5;
X	}
X#ifdef DEBUG
X	else {
X		fprintf(stderr,"bad crc.\n");
X	}
X#endif
X
X	/*
X	 * drop the end of line sequence after a hex header
X	 */
X	c = rx(to);
X	if (c == CR) {
X		/*
X		 * both are expected with CR
X		 */
X		c = rx(to);
X	}
X}
X
Xvoid
Xrx_bin32_header(int to)
X
X{
X	int c;
X	int n;
X	unsigned long crc;
X	unsigned long rxd_crc;
X
X#ifdef DEBUG
X	fprintf(stderr,"rx binary header 32 bits crc\n");
X#endif
X
X	crc = 0xffffffffL;
X
X	for (n=0;n<5;n++) {
X		c = rx(1000);
X		if (c == TIMEOUT) {
X			return;
X		}
X		crc = UPDCRC32(c,crc);
X		rxd_header[n] = c;
X	}
X
X	crc = ~crc;
X
X	rxd_crc  = rx(1000);
X	rxd_crc |= rx(1000) << 8;
X	rxd_crc |= rx(1000) << 16;
X	rxd_crc |= rx(1000) << 24;
X
X	if (rxd_crc != crc) {
X		return;
X	}
X
X	rxd_header_len = 5;
X}
X
X/*
X * receive any style header
X * if the errors flag is set than whenever an invalid header packet is
X * received INVHDR will be returned. otherwise we wait for a good header
X * also; a flag (receive_32_bit_data) will be set to indicate whether data
X * packets following this header will have 16 or 32 bit data attached.
X * variable headers are not implemented.
X */
X
Xint
Xrx_header_raw(int to,int errors)
X
X{
X	int c;
X
X#ifdef DEBUG
X	fprintf(stderr,"rx header : ");
X#endif
X	rxd_header_len = 0;
X
X	do {
X		do {
X			c = rx_raw(to);
X			if (c == TIMEOUT) {
X				return c;
X			}
X		} while (c != ZPAD);
X
X		c = rx_raw(to);
X		if (c == TIMEOUT) {
X			return c;
X		}
X
X		if (c == ZPAD) {
X			c = rx_raw(to);
X			if (c == TIMEOUT) {
X				return c;
X			}
X		}
X
X		/*
X		 * spurious ZPAD check
X		 */
X
X		if (c != ZDLE) {
X#ifdef DEBUG
X			fprintf(stderr,"expected ZDLE; got %c\n",c);
X#endif
X			continue;
X		}
X
X		/*
X		 * now read the header style
X		 */
X
X		c = rx(to);
X
X		if (c == TIMEOUT) {
X			return c;
X		}
X
X#ifdef DEBUG
X		fprintf(stderr,"\n");
X#endif
X		switch (c) {
X			case ZBIN:
X				rx_bin16_header(to);
X				receive_32_bit_data = FALSE;
X				break;
X			case ZHEX:
X				rx_hex_header(to);
X				receive_32_bit_data = FALSE;
X				break;
X			case ZBIN32:
X				rx_bin32_header(to);
X				receive_32_bit_data = TRUE;
X				break;
X			default:
X				/*
X				 * unrecognized header style
X				 */
X#ifdef DEBUG
X				fprintf(stderr,"unrecognized header style %c\n",c);
X#endif
X				if (errors) {
X					return INVHDR;
X				}
X
X				continue;
X				break;
X		}
X		if (errors && rxd_header_len == 0) {
X			return INVHDR;
X		}
X
X	} while (rxd_header_len == 0);
X
X	/*
X 	 * this appears to have been a valid header.
X	 * return its type.
X	 */
X
X	if (rxd_header[0] == ZDATA) {
X		ack_file_pos = rxd_header[ZP0] | (rxd_header[ZP1] << 8) |
X			(rxd_header[ZP2] << 16) | (rxd_header[ZP3] << 24);
X	}
X
X	if (rxd_header[0] == ZFILE) {
X		ack_file_pos = 0l;
X	}
X
X#ifdef DEBUG
X	fprintf(stderr,"type %d\n",rxd_header[0]);
X#endif
X
X	return rxd_header[0];
X}
X
Xint
Xrx_header(int timeout)
X
X{
X	return rx_header_raw(timeout,FALSE);
X}
X
Xint
Xrx_header_and_check(int timeout)
X
X{
X	int type;
X	while (TRUE) {
X		type = rx_header_raw(timeout,TRUE);		
X
X		if (type != INVHDR) {
X			break;
X		}
X
X		tx_znak();
X	}
X
X	return type;
X}
X
X
X
X
X
END_OF_zmdm.c
if test 19033 -ne `wc -c <zmdm.c`; then
    echo shar: \"zmdm.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zmdm.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zmdm.h\"
else
echo shar: Extracting \"zmdm.h\" \(1801 characters\)
sed "s/^X//" >zmdm.h <<'END_OF_zmdm.h'
X/*
X * zmdm.h
X * zmodem primitives prototypes and global data
X * (C) Mattheij Computer Service 1994
X */
X
X#ifndef _ZMDM_H
X
X#define _ZMDM_H
X
X#ifdef ZMDM
X#define EXTERN
X#else
X#define EXTERN extern
X#endif
X
X#include <errno.h>
X
X#define TRUE  1
X#define FALSE 0
X
X#define ENDOFFRAME 2
X#define FRAMEOK    1
X#define TIMEOUT   -1											/* rx routine did not receive a character within timeout */
X#define INVHDR    -2											/* invalid header received; but within timeout */
X#define INVDATA   -3											/* invalid data subpacket received */
X#define ZDLEESC 0x8000											/* one of ZCRCE; ZCRCG; ZCRCQ or ZCRCW was received; ZDLE escaped */
X
X#define HDRLEN     5											/* size of a zmodme header */
X
XEXTERN int in_fp;												/* input file descriptor */
XEXTERN int out_fp;												/* output file descriptor */
XEXTERN unsigned char rxd_header[ZMAXHLEN];						/* last received header */
XEXTERN int rxd_header_len;										/* last received header size */
X
X/*
X * receiver capability flags
X * extracted from the ZRINIT frame as received
X */
X
XEXTERN int can_full_duplex;
XEXTERN int can_overlap_io;
XEXTERN int can_break;
XEXTERN int can_fcs_32;
XEXTERN int escape_all_control_characters;						/* guess */
XEXTERN int escape_8th_bit;
X
XEXTERN int use_variable_headers;								/* use variable length headers */
X
X/*
X * file management options.
X * only one should be on
X */
X
XEXTERN int management_newer;
XEXTERN int management_clobber;
XEXTERN int management_protect;
X
Xvoid
Xfd_init(void);													/* make the io channel raw */
X
Xvoid
Xfd_exit(void);													/* reset io channel to state before zmtx was called */
X
Xvoid
Xtx_hheader(unsigned char * buf,int n);
X
Xvoid
Xtx_bheader(unsigned char * buf,int n);
X
Xint
Xrx_header(int to);												/* receive any header with timeout in milliseconds */
X
X#endif
X
X
X
END_OF_zmdm.h
if test 1801 -ne `wc -c <zmdm.h`; then
    echo shar: \"zmdm.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zmodem.doc -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zmodem.doc\"
else
echo shar: Extracting \"zmodem.doc\" \(37474 characters\)
sed "s/^X//" >zmodem.doc <<'END_OF_zmodem.doc'
Xzmodem.doc !copyrighted by MCS 1994 use it anyway you like but don't complain
Xthis file should be accompanied by a readme which contains some background
Xinformation on implementing zmodem.
X
XGENERAL
X-------
X
X	Documentation about the zmodem protocol internals; should be sufficient
X	to implement a completely functional zmodem protocol suite.
X	
X	Zmodem is a file transfer protocol that attempts to maximize bandwidth
X	and minimize transfer times. it is a unidirectional protocol; i.e. the
X	return channel only transfers control information; no data. either side
X	may initiate the transfer; but the downloading site may respond to 
X	an initialization frame by auto starting the download software.
X	
X	Schematically a zmodem file transfer in progress looks like this:
X
X             |----------<< back channel <<-------------|
X       ------+-------                          --------+------
X       |   Sender   |                          |   Receiver  |
X       |  (upload)  |                          |  (download) |
X       --------------                          --------+------
X             |---------->> data channel >>-------------|
X
X	Multiple files may be transferred in one session.
X
XSAMPLE
X------
X
X	all zmodem transactions are done using frames. a frame consists
X	of a header followed by one or more data subpackets.
X	a typical (simple) zmodem file transfer looks like this :
X
X	    sender                      receiver
X
X		ZRQINIT(0)
X							        ZRINIT
X		ZFILE
X							        ZRPOS
X		ZDATA data ...
X		ZEOF
X							        ZRINIT
X		ZFIN
X							        ZFIN
X		OO
X
X	zmodem continuously	transmits data unless the receiver interrupts
X	the sender to request retransmission of garbled data.
X	zmodem in effect uses the entire file as a window.
X
XREQUIREMENTS
X------------
X
X	zmodem requires an 8 bit transfer medium; but allows encoded packets
X	for less transparent media.
X	zmodem escapes network control characters to allow operation with
X	packet switched networks.
X
X	To support full streaming, the transmission path should either assert
X	flow control or pass full speed transmission without loss of data.
X	Otherwise the zmodem sender must manage the window size.
X
X	zmodem places no constraints on the content files.
X
XLINK ESCAPE ENCODING
X--------------------
X
X	zmodem achieves data transparency by extending the 8 bit character set
X	(256 codes) with escape sequences based on the zmodem data link escape
X	character ZDLE
X
X	Link Escape coding permits variable length data subpackets without the
X	overhead of a separate byte count.  It allows the beginning of frames to
X	be detected without special timing techniques, facilitating rapid error
X	recovery.
X
X	Link Escape coding does add some overhead.  The worst case, a file
X	consisting entirely of escaped characters, would incur a 50% overhead.
X
X	The ZDLE character is special. ZDLE represents a control
X	sequence of some sort. If a ZDLE character appears in binary data,
X	it is prefixed with ZDLE, then sent as ZDLEE
X
X	5 consecutive CAN characters abort a zmodem session
X
X	Since CAN is not used in normal terminal operations, interactive
X	applications and communications programs can monitor the data flow for
X	ZDLE.  The following characters can be scanned to detect the ZRQINIT
X	header, the invitation to automatically download commands or files.
X
X	Receipt of five successive CAN characters will abort a zmodem session.
X	Eight CAN characters are sent (just to be on the safe side)
X
X	The receiving program decodes any sequence of ZDLE followed by a byte with
X	bit 6 set and bit 5 reset (upper case letter, either parity) to the
X	equivalent control character by inverting bit 6.  This allows the
X	transmitter to escape any control character that cannot be sent by the
X	communications medium. In addition, the receiver recognizes escapes for
X	0x7f and 0xff should these characters need to be escaped.
X
X	zmodem software escapes ZDLE (0x18), 0x10, 0x90, 0x11, 0x91, 0x13,
X	and 0x93. 
X	If preceded by 0x40 or 0xc0 (@), 0x0d and 0x8d are also escaped to
X	protect the Telenet command escape CR-@-CR. The receiver ignores
X	0x11, 0x91, 0x13, and 0x93 characters in the data stream.
X
XHEADERS
X-------
X
X	All zmodem frames begin with a header which may be sent in binary or HEX
X	form. Either form of the header contains the same raw information:
X
X	- A type byte
X
X	- Four bytes of data indicating flags and/or numeric quantities depending
X	  on the frame type
X
X	the maximum header information length is 16 bytes
X	the data subpackets following the header are maximum 1024 bytes long.
X
X             M         L
X      FTYPE  F3 F2 F1 F0   (flags frame)
X
X             L         M
X      FTYPE  P0 P1 P2 P3   (numeric frame)
X
X    Beware of the catch; flags and numbers are indexed the other way around !
X
X	16 BIT CRC BINARY HEADER
X	------------------------
X	
X		A binary header is sent by the sending program to the receiving
X		program. All bytes in a binary header are ZDLE encoded.
X	
X		A binary header begins with the sequence ZPAD, ZDLE, ZBIN.
X	
X		0 or more binary data subpackets with 16 bit CRC will follow depending
X		on the frame type.
X	
X		* ZDLE A TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2
X	
X	
X	32 BIT CRC BINARY HEADER
X	------------------------
X	
X		A "32 bit CRC" Binary header is similar to a Binary Header, except the
X		ZBIN (A) character is replaced by a ZBIN32 (C) character, and four
X		characters of CRC are sent.
X	
X		0 or more binary data subpackets with 32 bit CRC will follow depending
X		on the frame type.
X	
X		* ZDLE C TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 CRC-3 CRC-4
X	
X	HEX HEADER
X	----------
X	
X		The receiver sends responses in hex headers.  The sender also uses hex
X		headers when they are not followed by binary data subpackets.
X	
X		Hex encoding protects the reverse channel from random control 
X		characters. The hex header receiving routine ignores parity.
X	
X		use of hex headers by the receiving program allows control characters
X		to be used to interrupt the sender when errors are detected.
X		A HEX header may be used in place of a binary header
X		wherever convenient.
X		If a data packet follows a HEX header, it is protected with CRC-16.
X	
X		A hex header begins with the sequence ZPAD, ZPAD, ZDLE, ZHEX.  
X		The extra ZPAD character allows the sending program to detect
X		an asynchronous header (indicating an error condition) and then
X		get the rest of the header with a non-error specific routine.
X	
X		The type byte, the four position/flag bytes, and the 16 bit CRC
X		thereof are sent in hex using the character set 01234567890abcdef.
X		Upper case hex digits are not allowed.
X		Since this form of hex encoding detects many patterns of errors,
X		especially missing characters, a hex header with 32 bit CRC has not
X		been defined.
X	
X		A carriage return and line feed are sent with HEX headers.  The
X		receive routine expects to see at least one of these characters, two
X		if the first is CR.
X	
X		An XON character is appended to all HEX packets except ZACK and ZFIN.
X		The XON releases the sender from spurious XOFF flow control characters
X		generated by line noise. XON is not sent after ZACK headers to protect
X		flow control in streaming situations. XON is not sent after a ZFIN
X		header to allow proper session cleanup.
X	
X		0 or more data subpackets will follow depending on the frame type.
X	
X		* * ZDLE B TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 CR LF XON
X	
X		(TYPE, F3...F0, CRC-1, and CRC-2 are each sent as two hex digits.)
X	
X	BINARY DATA SUBPACKETS
X	----------------------
X	
X		Binary data subpackets immediately follow the associated binary header
X		packet.  A binary data packet contains 0 to 1024 bytes of data.
X		Recommended length values are 256 bytes below 2400 bps, 512 at 
X		2400 bps, and 1024 above 4800 bps or when the data link is known to
X		be relatively error free.
X	
X		No padding is used with binary data subpackets.  The data bytes are
X		ZDLE encoded and transmitted.  A ZDLE and frameend are then sent,
X		followed by two or four ZDLE encoded CRC bytes.  The CRC accumulates
X		the data bytes and frameend.
X	
XPROTOCOL TRANSACTION OVERVIEW
X-----------------------------	
X
X	zmodem timing is receiver driven.  The
X	transmitter should not time out at all, except to abort the program if no
X	headers are received for an extended period of time, say one minute.
X	
X	SESSION STARTUP
X	---------------
X
X		To start a zmodem file transfer session, the sending program is called
X		with the names of the desired file(s) and option(s).
X	
X		Then the sender may send a ZRQINIT header. The ZRQINIT header causes a
X		previously started receive program to send its ZRINIT header without
X		delay.
X	
X		In an interactive or conversational mode, the receiving application
X		may monitor the data stream for ZDLE.  The following characters may be 
X		scanned for B00 indicating a ZRQINIT header, a command to download
X		data.
X	
X		The sending program awaits a command from the receiving program to
X		start file transfers. 
X	
X		In case of garbled data, the sending program can repeat the invitation
X		to receive a number of times until a session starts.
X	
X		When the zmodem receive program starts, it immediately sends a ZRINIT
X		header to initiate zmodem file transfers, or a ZCHALLENGE header to
X		verify the sending program.  The receive program resends its header at
X		response time (default 10 second) intervals for a suitable period of
X		time (40 seconds total) before exitting.
X	
X		If the receiving program receives a ZRQINIT header, it resends the
X		ZRINIT header.  If the sending program receives the ZCHALLENGE header,
X		it places the data in ZP0...ZP3 in an answering ZACK header.
X	
X		If the receiving program receives a ZRINIT header, it is an echo
X		indicating that the sending program is not operational.
X	
X		Eventually the sending program correctly receives the ZRINIT header.
X	
X		The sender may then send an optional ZSINIT frame to define the
X		receiving program's Attn sequence, or to specify complete control
X		character escaping. if the receiver specifies the same or higher
X		level of escaping the ZSINIT frame need not be sent unless an Attn
X		sequence is needed.
X	
X		If the ZSINIT header specifies ESCCTL or ESC8, a HEX header is used,
X		and the receiver activates the specified ESC modes before reading the
X		following data subpacket.
X	
X		The receiver sends a ZACK header in response, containing 0.
X	
X	FILE TRANSMISSION
X	-----------------
X
X		The sender then sends a ZFILE header with zmodem Conversion,
X		Management, and Transport options (see ZFILE header type) followed
X		by a ZCRCW data subpacket containing the file name, file length and
X		modification date.
X
X		The receiver examines the file name, length, and date information
X		provided by the sender in the context of the specified transfer
X		options, the current state of its file system(s), and local security
X		requirements.  The receiving program should insure the pathname and
X		options are compatible with its operating environment and local
X		security requirements.
X
X		The receiver may respond with a ZSKIP header, which makes the sender
X		proceed to the next file (if any) in the batch.
X
X			The receiver has a file with the same name and length, may
X			respond with a ZCRC header with a byte count, which
X			requires the sender to perform a 32 bit CRC on the
X			specified number of bytes in the file and transmit the
X			complement of the CRC in an answering ZCRC header.the crc is
X			initialised to 0xfffffff; a byte count of 0 implies the entire
X			file the receiver uses this information to determine whether to
X			accept the file or skip it.  This sequence may be triggered
X			by the ZMCRC Management Option.
X
X		A ZRPOS header from the receiver initiates transmission of the file
X		data starting at the offset in the file specified in the ZRPOS header.
X		Normally the receiver specifies the data transfer to begin begin at
X		offset 0 in the file.
X
X			The receiver may start the transfer further down in the
X			file.  This allows a file transfer interrupted by a loss
X			of carrier or system crash to be completed on the next
X			connection without requiring the entire file to be
X			retransmitted. If downloading a file from a timesharing
X			system that becomes sluggish, the transfer can be
X			interrupted and resumed later with no loss of data.
X
X		The sender sends a ZDATA binary header (with file position) followed
X		by one or more data subpackets.
X	
X		The receiver compares the file position in the ZDATA header with the
X		number of characters successfully received to the file. If they do not
X		agree, a ZRPOS error response is generated to force the sender to the
X		right position within the file. (if the ZMSPARS option is used the
X		receiver instead seeks to the position given in the ZDATA header)
X
X		A data subpacket terminated by ZCRCG and CRC does not elicit a
X		response unless an error is detected; more data subpacket(s) follow
X		immediately.
X
X		ZCRCQ data subpackets expect a ZACK response with the
X		receiver's file offset if no error, otherwise a ZRPOS
X		response with the last good file offset.  Another data
X		subpacket continues immediately.  ZCRCQ subpackets are
X		not used if the receiver does not indicate full duplex ability
X		with the CANFDX bit.
X
X		ZCRCW data subpackets expect a response before the next frame is sent.
X		If the receiver does not indicate overlapped I/O capability with the
X		CANOVIO bit, or sets a buffer size, the sender uses the ZCRCW to allow
X		the receiver to write its buffer before sending more data.
X
X			A zero length data frame may be used as an idle
X			subpacket to prevent the receiver from timing out in
X			case data is not immediately available to the sender.
X
X		In the absence of fatal error, the sender eventually encounters end of
X		file.  If the end of file is encountered within a frame, the frame is
X		closed with a ZCRCE data subpacket which does not elicit a response
X		except in case of error.
X
X		The sender sends a ZEOF header with the file ending offset equal to
X		the number of characters in the file.  The receiver compares this
X		number with the number of characters received. If the receiver has
X		received all of the file, it closes the file.  If the file close was
X		satisfactory, the receiver responds with ZRINIT.  If the receiver has
X		not received all the bytes of the file, the receiver ignores the ZEOF
X		because a new ZDATA is coming. If the receiver cannot properly close
X		the file, a ZFERR header is sent.
X
X		After all files are processed, any further protocol
X		errors should not prevent the sending program from
X		returning with a success status.
X
X	SESSION CLEANUP
X	---------------
X
X		The sender closes the session with a ZFIN header.  The receiver
X		acknowledges this with its own ZFIN header.
X
X		When the sender receives the acknowledging header, it sends two
X		characters, "OO" (Over and Out) and exits.
X		The receiver waits briefly for the "O" characters, then exits
X		whether they were received or not.
X
X	SESSION ABORT SEQUENCE
X	----------------------
X
X		If the receiver is receiving data in streaming mode, the Attn
X		sequence is executed to interrupt data transmission before the Cancel
X		sequence is sent.  The Cancel sequence consists of eight CAN
X		characters and ten backspace characters.  zmodem only requires five
X		Cancel characters, the other three are "insurance".
X
X		The trailing backspace characters attempt to erase the effects of the
X		CAN characters if they are received by a command interpreter.
X
X	       char ses_abort_seq[] = {
X				24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
X	       };
X
X	ATTENTION SEQUENCE
X	------------------
X
X		The receiving program sends the Attn sequence whenever it detects an
X		error and needs to interrupt the sending program.
X
X		The default Attn string value is empty (no Attn sequence).  The
X		receiving program resets Attn to the empty default before each
X		transfer session.
X
X		The sender specifies the Attn sequence in its optional ZSINIT frame.
X		The Attn string is terminated with a null.
X
XFRAME TYPES
X-----------
X
X	The numeric values are listed at the end of this file.
X	Unused bits and unused bytes in the header (ZP0...ZP3) are set to 0.
X
X	ZRQINIT
X	-------
X
X		Sent by the sending program, to trigger the receiving program to send
X		its ZRINIT header.  
X		The sending program may
X		repeat the receive invitation (including ZRQINIT) if a response is
X		not obtained at first.
X
X		ZF0 contains ZCOMMAND if the program is attempting to send a command,
X		0 otherwise.
X
X	ZRINIT
X	------
X
X		Sent by the receiving program. ZF0 and ZF1 contain the  bitwise or
X		of the receiver capability flags:
X
X			CANCRY		receiver can decrypt
X			CANFDX		receiver can send and receive true full duplex
X			CANOVIO		receiver can receive data during disk I/O
X			CANBRK		receiver can send a break signal
X			CANCRY		receiver can decrypt
X			CANLZW		receiver can uncompress
X			CANFC32		receiver can use 32 bit Frame Check
X			ESCCTL		receiver expects ctl chars to be escaped
X			ESC8		receiver expects 8th bit to be escaped
X
X		ZP0 and ZP1 contain the size of the receiver's buffer in bytes, or 0
X		if nonstop I/O is allowed.
X
X		while all these capabilities are nice in theory most zmodem implem-
X		tations balk at anything other than 0,0. i.e. telix starts sending
X		35 byte packets when CANFC32 is on.
X
X	ZSINIT
X	------
X
X		The Sender sends flags followed by a binary data subpacket terminated
X		with ZCRCW.
X
X			TESCCTL		Transmitter expects ctl chars to be escaped
X			TESC8		Transmitter expects 8th bit to be escaped
X
X		The data subpacket contains the null terminated Attn sequence,
X		maximum length 32 bytes including the terminating null.
X
X	ZACK
X	----
X
X		Acknowledgment to a ZSINIT frame, ZCHALLENGE header, ZCRCQ or ZCRCW
X		data subpacket.  ZP0 to ZP3 contain file offset.  The response to
X		ZCHALLENGE contains the same 32 bit number received in the ZCHALLENGE
X		header.
X
X	ZFILE
X	-----
X		This frame denotes the beginning of a file transmission attempt.
X		ZF0, ZF1, and ZF2 may contain options. A value of 0 in each of these
X		bytes implies no special treatment.  Options specified to the
X		receiver override options specified to the sender with the exception
X		of ZCBIN.  A ZCBIN from the sender overrides any other Conversion
X		Option given to the receiver except ZCRESUM.  A ZCBIN from the
X		receiver overrides any other Conversion Option sent by the sender.
X
X
X		ZF0: CONVERSION OPTION
X		----------------------
X
X			If the receiver does not recognize the Conversion Option, an
X			application dependent default conversion may apply.
X
X			ZCBIN "Binary" transfer - inhibit conversion unconditionally
X
X			ZCNL Convert received end of line to local end of line
X			     convention.  The supported end of line conventions are
X			     CR/LF (most ASCII based operating systems except Unix
X			     and Macintosh), and NL (Unix).  Either of these two end
X			     of line conventions meet the permissible ASCII
X			     definitions for Carriage Return and Line Feed/New Line.
X			     Neither the ASCII code nor zmodem ZCNL encompass lines
X			     separated only by carriage returns.  Other processing
X			     appropriate to ASCII text files and the local operating
X			     system may also be applied by the receiver. (filtering
X			     RUBOUT NULL Ctrl-Z etc)
X
X			ZCRECOV Recover/Resume interrupted file transfer.  ZCREVOV is
X			     also useful for updating a remote copy of a file that
X			     grows without resending of old data.  If the destination
X			     file exists and is no longer than the source, append to
X			     the destination file and start transfer at the offset
X			     corresponding to the receiver's end of file.  This
X			     option does not apply if the source file is shorter.
X			     Files that have been converted (e.g., ZCNL) or subject
X			     to a single ended Transport Option cannot have their
X			     transfers recovered.
X
X		ZF1: Management Option
X		----------------------
X
X			If the receiver does not recognize the Management Option, the
X			file should be transferred normally.
X
X			The ZMSKNOLOC bit instructs the receiver to bypass the
X			current file if the receiver does not have a file with the
X			same name.
X
X			Five bits (defined by ZMMASK) define the following set of
X			mutually exclusive management options.
X
X				ZMNEWL Transfer file if destination file absent.  Otherwise,
X				transfer file overwriting destination if the source file
X				is newer or longer.
X
X				ZMCRC Compare the source and destination files.  Transfer if
X				file lengths or file polynomials differ.
X
X				ZMAPND Append source file contents to the end of the existing
X				destination file (if any).
X
X				ZMCLOB Replace existing destination file (if any).
X
X				ZMDIFF Transfer file if destination file absent.  Otherwise,
X				transfer file overwriting destination if files have
X				different lengths or dates.
X
X				ZMPROT Protect destination file by transferring file only if
X				the destination file is absent.
X
X				ZMNEW Transfer file if destination file absent.  Otherwise,
X				transfer file overwriting destination if the source file
X				is newer.
X
X		ZF2: TRANSPORT OPTION
X		---------------------
X
X			If the receiver does not implement the particular transport
X			option, the file is copied without conversion for later
X			processing. better not to use these; see readme
X
X			ZTLZW Lempel-Ziv compression.  Transmitted data will be
X			identical to that produced by compress 4.0 operating on
X			a computer with VAX byte ordering, using 12 bit
X			encoding.
X
X			ZTCRYPT Encryption.  An initial null terminated string
X			identifies the key.  Details to be determined.
X
X			ZTRLE Run Length encoding, Details to be determined.
X
X			A ZCRCW data subpacket follows with file name, file length,
X			modification date, and other information described in a later
X			chapter.
X
X		ZF3: EXTENDED OPTIONS
X		---------------------
X
X			The Extended Options are bit encoded.
X
X			ZTSPARS Special processing for sparse files, or sender managed
X			selective retransmission. Each file segment is transmitted as
X			a separate frame, where the frames are not necessarily
X			contiguous.  The sender should end each segment with a ZCRCW
X			data subpacket and process the expected ZACK to insure no data
X			is lost.  ZTSPARS cannot be used with ZCNL.
X
X	ZSKIP
X	-----
X
X		Sent by the receiver in response to ZFILE, makes the sender skip to
X		the next file.
X
X	ZNAK
X	----
X
X		Indicates last header was garbled.  (See also ZRPOS).
X
X	ZABORT
X	------
X
X		Sent by receiver to terminate batch file transfers when requested by
X		the user.  Sender responds with a ZFIN sequence. (or ZCOMPL in case of
X		server mode).
X
X	ZFIN
X	----
X
X		Sent by sending program to terminate a zmodem session. Receiver
X		responds with its own ZFIN.
X
X	ZRPOS
X	-----
X
X		Sent by receiver to force file transfer to resume at file offset
X		given in ZP0...ZP3.
X
X	ZDATA
X	-----
X
X		ZP0...ZP3 contain file offset. One or more data subpackets follow.
X
X	ZEOF
X	----
X
X		Sender reports End of File.  ZP0...ZP3 contain the ending file
X		offset.
X
X	ZFERR
X	-----
X
X		Error in reading or writing file, protocol equivalent to ZABORT.
X
X	ZCRC
X	----
X
X		Request (receiver) and response (sender) for file polynomial.
X		ZP0...ZP3 contain file polynomial.
X
X	ZCHALLENGE
X	----------
X
X		Request sender to echo a random number in ZP0...ZP3 in a ZACK frame.
X		Sent by the receiving program to the sending program to verify that
X		it is connected to an operating program, and was not activated by
X		spurious data or a Trojan Horse message. this is the most simply 
X		defeated security system ever invented. don't rely on it and better
X		still don't use or implement it. build your security measures around
X		starting the download at all and disallow explicit path names.
X
X	ZCOMPL
X	------
X
X		Request now completed.
X
X	ZCAN
X	----
X
X		This is a pseudo frame type in response to a
X		Session Abort sequence.
X
X	ZFREECNT
X	--------
X
X		Sending program requests a ZACK frame with ZP0...ZP3 containing the
X		number of free bytes on the current file system.  A value of 0
X		represents an indefinite amount of free space.
X
X	ZCOMMAND
X	--------
X
X		ZCOMMAND is sent in a binary frame.  ZF0 contains 0 or ZCACK1 (see
X		below).
X
X		A ZCRCW data subpacket follows, with the ASCII text command string
X		terminated with a NULL character.  If the command is intended to be
X		executed by the operating system hosting the receiving program
X		(e.g., "shell escape"), it must have "!" as the first character.
X		Otherwise the command is meant to be executed by the application
X		program which receives the command.
X
X		If the receiver detects an illegal or badly formed command, the
X		receiver immediately responds with a ZCOMPL header with an error
X		code in ZP0...ZP3.
X
X		If ZF0 contained ZCACK1, the receiver immediately responds with a
X		ZCOMPL header with 0 status.
X
X		Otherwise, the receiver responds with a ZCOMPL header when the
X		operation is completed.  The exit status of the completed command is
X		stored in ZP0...ZP3.  A 0 exit status implies nominal completion of
X		the command.
X
X		If the command causes a file to be transmitted, the command sender
X		will see a ZRQINIT frame from the other computer attempting to send
X		data.
X
X		The sender examines ZF0 of the received ZRQINIT header to verify it
X		is not an echo of its own ZRQINIT header.  It is illegal for the
X		sending program to command the receiving program to send a command.
X
X		If the receiver program does not implement command downloading, it
X		may display the command to the standard error output, then return a
X		ZCOMPL header.
X
X	ZFILE FRAME FILE INFORMATION SUBPACKET
X	--------------------------------------
X
X		zmodem sends the same file information with the ZFILE frame data
X
X		The pathname (file name) field is mandatory. each field after 
X		pathname is optional and separated from the previous one by 
X		a space. fields may not be skipped. the use of the optional
X		fields is (by definition) optional to the receiver.
X
X		PATHNAME
X		--------
X
X			The pathname (conventionally, the file name) is sent as a
X			null terminated ASCII string. 
X			No spaces are included in the pathname. 
X
X			Filename Considerations
X
X				- File names should be translated to lower case unless the
X				  sending system supports upper/lower case file names. This
X				  is a convenience for users of systems (such as Unix) which
X				  store filenames in upper and lower case.
X
X				- The receiver should accommodate file names in lower and
X				  upper case.
X	
X				- When transmitting files between different operating
X				  systems, file names must be acceptable to both the sender
X				  and receiving operating systems.  If not, transformations
X				  should be applied to make the file names acceptable. If
X				  the transformations are unsuccessful, a new file name may
X				  be invented be the receiving program.
X	
X				- If directories are included, they are delimited by /; i.e.,
X	    		  "subdir/foo" is acceptable, "subdir\foo" is not.
X	
X		LENGTH
X		------
X
X			The length field is stored as a decimal string
X			counting the number of data bytes in the file.
X
X			The zmodem receiver uses the file length as an estimate only.
X			It may be used to display an estimate of the transmission time,
X			and may be compared with the amount of free disk space.  The
X			actual length of the received file is determined by the data
X			transfer. A file may grow after transmission commences, and
X			all the data will be sent.
X
X		MODIFICATION DATE
X		-----------------
X
X			The mod date is sent as an octal number giving the time the
X			contents of the file were last changed measured in seconds from
X			Jan 1 1970 Universal Coordinated Time (GMT).  A date of 0
X			implies the modification date is unknown and should be left as
X			the date the file is received.
X
X			This standard format was chosen to eliminate ambiguities
X			arising from transfers between different time zones.
X
X		FILE MODE
X		---------
X
X			The file mode is stored as an octal string.
X			Unless the file originated from a Unix system, the file mode is
X			set to 0. 
X
X		SERIAL NUMBER
X		-------------
X
X			set this field to 0.
X
X		NUMBER OF FILES REMAINING
X		-------------------------
X
X			This field is coded as a decimal number, and includes the
X			current file.  This field is an estimate, and incorrect values
X			must not be allowed to cause loss of data.
X
X		NUMBER OF BYTES REMAINING 
X		-------------------------
X
X			This field is coded as a decimal number, and includes the
X			current file.  This field is an estimate, and incorrect values
X			must not be allowed to cause loss of data. 
X
X		FILE TYPE
X		---------
X
X			set this field to 0.
X
X		The file information is terminated by a null.  If only the pathname
X		is sent, the pathname is terminated with two nulls.  The length of
X		the file information subpacket, including the trailing null, must
X		not exceed 1024 bytes; a typical length is less than 64 bytes.
X
XSTREAMING TECHNIQUES / ERROR RECOVERY
X-------------------------------------
X
X	zmodem provides several data streaming methods
X	selected according to the limitations of the sending environment,
X	receiving environment, and transmission channel(s).
X	
X	WINDOW MANAGEMENT
X	-----------------
X
X		When sending data through a network, some nodes of the network store
X		data while it is transferred to the receiver.  7000 bytes and more of
X		transient storage have been observed.  Such a large amount of storage
X		causes the transmitter to "get ahead" of the receiver. 
X		This condition is not fatal but it does slow error recovery.
X		
X		To manage the window size, the sending program uses ZCRCQ data
X		subpackets to trigger ZACK headers from the receiver.  The returning
X		ZACK headers inform the sender of the receiver's progress.  When the
X		window size (current transmitter file offset - last reported receiver
X		file offset) exceeds a specified value, the sender waits for a
X		ZACK packet with a receiver file offset that reduces the window
X		size. ZRPOS and other error packets are handled normally.
X
X	FULL STREAMING WITH SAMPLING
X	----------------------------	
X
X		If the receiver can overlap serial I/O with disk I/O, and if the
X		sender can sample the reverse channel for the presence of data
X		without having to wait, full streaming can be used with no Attn
X		sequence required.  The sender begins data transmission with a ZDATA
X		header and continuous ZCRCG data subpackets.  When the receiver
X		detects an error, it executes the Attn sequence and then sends a
X		ZRPOS header with the correct position within the file.
X		
X		At the end of each transmitted data subpacket, the sender checks for
X		the presence of an error header from the receiver.  To do this, the
X		sender samples the reverse data stream for the presence of either a
X		ZPAD or CAN character (using rdchk() or a similar mechanism)
X		. Flow control characters (if present) are acted upon.
X		
X		Other characters (indicating line noise) increment a counter which is
X		reset whenever the sender waits for a header from the receiver.  If
X		the counter overflows, the sender sends the next data subpacket as
X		ZCRCW, and waits for a response.
X		
X		ZPAD indicates some sort of error header from the receiver.  A CAN
X		suggests the user is attempting to "stop the bubble machine" by
X		keyboarding CAN characters.  If one of these characters is seen, an
X		empty ZCRCE data subpacket is sent.  Normally, the receiver will have
X		sent an ZRPOS or other error header, which will force the sender to
X		resume transmission at a different address, or take other action.  In
X		the unlikely event the ZPAD or CAN character was spurious, the
X		receiver will time out and send a ZRPOS header.
X		The obvious choice of ZCRCW packet, which would trigger an ZACK from
X		the receiver, is not used because multiple in transit frames could
X		result if the channel has a long propagation delay.
X		
X		Then the receiver's response header is read and acted upon; starting
X		with a resinchronize.
X		
X		A ZRPOS header resets the sender's file offset to the correct
X		position.  If possible, the sender should purge its output buffers
X		and/or networks of all unprocessed output data, to minimize the
X		amount of unwanted data the receiver must discard before receiving
X		data starting at the correct file offset.  The next transmitted data
X		frame should be a ZCRCW frame followed by a wait to guarantee
X		complete flushing of the network's memory.
X	
X		If the receiver gets a ZACK header with an address that disagrees
X		with the sender address, it is ignored, and the sender waits for
X		another header.  A ZFIN, ZABORT, or TIMEOUT terminates the session; a
X		ZSKIP terminates the processing of this file.
X		
X		The reverse channel is then sampled for the presence of another
X		header from the receiver (if sampling is possible). if one is detected
X		another error header is read. Otherwise,
X		transmission resumes at the (possibly reset) file offset with a ZDATA
X		header followed by data subpackets.
X	
X	FULL STREAMING WITH REVERSE INTERRUPT
X	-------------------------------------	
X
X		The above method cannot be used if the reverse data stream cannot be
X		sampled without entering an I/O wait.  An alternate method is to
X		instruct the receiver to interrupt the sending program when an error
X		is detected.
X	
X		The receiver can interrupt the sender with a control character, break
X		signal, or combination thereof, as specified in the Attn sequence.
X		After executing the Attn sequence, the receiver sends a hex ZRPOS
X		header to force the sender to resend the lost data.
X		
X		When the sending program responds to this interrupt, it reads a HEX
X		header (normally ZRPOS) from the receiver and takes the action
X		described in the previous section. 
X	
X	FULL STREAMING WITH SLIDING WINDOW
X	----------------------------------	
X
X		If none of the above methods is applicable, hope is not yet lost.  If
X		the sender can buffer responses from the receiver, the sender can use
X		ZCRCQ data subpackets to get ACKs from the receiver without
X		interrupting the transmission of data. After a sufficient number of
X		ZCRCQ data subpackets have been sent, the sender can read one of the
X		headers that should have arrived in its receive interrupt buffer.
X	
X		A problem with this method is the possibility of wasting an excessive
X		amount of time responding to the receiver's error header.  It may be
X		possible to program the receiver's Attn sequence to flush the
X		sender's interrupt buffer before sending the ZRPOS header.
X
X	SEGMENTED STREAMING
X	-------------------
X
X		If the receiver cannot overlap serial and disk I/O, it uses the
X		ZRINIT frame to specify a buffer length which the sender will not
X		overflow.  The sending program sends a ZCRCW data subpacket and waits
X		for a ZACK header before sending the next segment of the file.
X
X		A sufficiently large receiving buffer allows throughput to closely
X		approach that of full streaming.  For example, 16kb segmented
X		streaming adds about 3 per cent to full streaming zmodem file
X		transfer times when the round trip delay is five seconds.
X
XCONSTANTS
X---------
X
X	ASCII
X	-----
X
X		SOH			0x01
X		STX			0x02
X		EOT			0x04
X		ENQ			0x05
X		ACK			0x06
X		LF			0x0a
X		CR			0x0d
X		XON			0x11
X		XOFF		0x13
X		NAK			0x15
X		CAN			0x18
X
X	ZMODEM	
X	------
X
X		ZPAD		0x2a	/* pad character; begins frames */
X		ZDLE		0x18	/* ctrl-x zmodem escape */
X		ZDLEE		0x58	/* escaped ZDLE */	
X
X		ZBIN		0x41	/* binary frame indicator (CRC16) */
X		ZHEX		0x42	/* hex frame indicator */
X		ZBIN32		0x43	/* binary frame indicator (CRC32) */
X		ZBINR32		0x44	/* run length encoded binary frame (CRC32) */
X
X		ZVBIN		0x61	/* binary frame indicator (CRC16) */
X		ZVHEX		0x62	/* hex frame indicator */
X		ZVBIN32		0x63	/* binary frame indicator (CRC32) */
X		ZVBINR32	0x64	/* run length encoded binary frame (CRC32) */
X
X		ZRESC		0x7e	/* run length encoding flag / escape character */
X
X	FRAME TYPES
X	-----------
X
X		ZRQINIT		0x00	/* request receive init (s->r) */
X		ZRINIT		0x01	/* receive init (r->s) */
X		ZSINIT		0x02	/* send init sequence (optional) (s->r) */
X		ZACK		0x03	/* ack to ZRQINIT ZRINIT or ZSINIT (s<->r) */
X		ZFILE		0x04	/* file name (s->r) */
X		ZSKIP		0x05	/* skip this file (r->s) */
X		ZNAK		0x06	/* last packet was corrupted (?) */
X		ZABORT		0x07	/* abort batch transfers (?) */
X		ZFIN		0x08	/* finish session (s<->r) */
X		ZRPOS		0x09	/* resume data transmission here (r->s) */
X		ZDATA		0x0a	/* data packet(s) follow (s->r) */
X		ZEOF		0x0b	/* end of file reached (s->r) */
X		ZFERR		0x0c	/* fatal read or write error detected (?) */
X		ZCRC		0x0d	/* request for file CRC and response (?) */
X		ZCHALLENGE	0x0e	/* security challenge (r->s) */
X		ZCOMPL		0x0f	/* request is complete (?) */	
X		ZCAN		0x10	/* pseudo frame; 
X							   other end cancelled session with 5* CAN */
X		ZFREECNT	0x11	/* request free bytes on file system (s->r) */
X		ZCOMMAND	0x12	/* issue command (s->r) */
X		ZSTDERR		0x13	/* output data to stderr (??) */
X
X	ZDLE SEQUENCES
X	--------------
X
X		ZCRCE		0x68	/* CRC next, frame ends, header packet follows */
X		ZCRCG		0x69	/* CRC next, frame continues nonstop */
X		ZCRCQ		0x6a	/* CRC next, frame continuous, ZACK expected */
X		ZCRCW		0x6b	/* CRC next, ZACK expected, end of frame */
X		ZRUB0		0x6c	/* translate to rubout 0x7f */
X		ZRUB1		0x6d	/* translate to rubout 0xff */
X
X	RECEIVER CAPABILITY FLAGS
X	-------------------------
X
X		CANFDX		0x01	/* Rx can send and receive true full duplex */
X		CANOVIO		0x02	/* Rx can receive data during disk I/O */
X		CANBRK		0x04	/* Rx can send a break signal */
X		CANCRY		0x08	/* Receiver can decrypt */
X		CANLZW		0x10	/* Receiver can uncompress */
X		CANFC32		0x20	/* Receiver can use 32 bit Frame Check */
X		ESCCTL		0x40	/* Receiver expects ctl chars to be escaped
X		ESC8		0x80	/* Receiver expects 8th bit to be escaped */
X
X
END_OF_zmodem.doc
if test 37474 -ne `wc -c <zmodem.doc`; then
    echo shar: \"zmodem.doc\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zmodem.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zmodem.h\"
else
echo shar: Extracting \"zmodem.h\" \(5734 characters\)
sed "s/^X//" >zmodem.h <<'END_OF_zmodem.h'
X/*
X * zmodem.h
X * zmodem constants
X * (C) Mattheij Computer Service 1994
X */
X
X#ifndef _ZMODEM_H
X
X#define _ZMODEM_H
X
X/*
X * ascii constants
X */
X
X#define	SOH			0x01
X#define	STX			0x02
X#define	EOT			0x04
X#define	ENQ			0x05
X#define	ACK			0x06
X#define	LF			0x0a
X#define	CR			0x0d
X#define	XON			0x11
X#define	XOFF		0x13
X#define	NAK			0x15
X#define	CAN			0x18
X
X/*
X * zmodem constants
X */
X
X#define ZMAXHLEN    0x10		/* maximum header information length */
X#define ZMAXSPLEN	0x400		/* maximum subpacket length */
X
X
X#define	ZPAD		0x2a		/* pad character; begins frames */
X#define	ZDLE		0x18		/* ctrl-x zmodem escape */
X#define	ZDLEE		0x58		/* escaped ZDLE */	
X
X#define	ZBIN		0x41		/* binary frame indicator (CRC16) */
X#define	ZHEX		0x42		/* hex frame indicator */
X#define	ZBIN32		0x43		/* binary frame indicator (CRC32) */
X#define	ZBINR32		0x44		/* run length encoded binary frame (CRC32) */
X
X#define	ZVBIN		0x61		/* binary frame indicator (CRC16) */
X#define	ZVHEX		0x62		/* hex frame indicator */
X#define	ZVBIN32		0x63		/* binary frame indicator (CRC32) */
X#define	ZVBINR32	0x64		/* run length encoded binary frame (CRC32) */
X
X#define	ZRESC		0x7e		/* run length encoding flag / escape character */
X
X/*
X * zmodem frame types
X */
X
X#define	ZRQINIT		0x00		/* request receive init (s->r) */
X#define	ZRINIT		0x01		/* receive init (r->s) */
X#define	ZSINIT		0x02		/* send init sequence (optional) (s->r) */
X#define	ZACK		0x03		/* ack to ZRQINIT ZRINIT or ZSINIT (s<->r) */
X#define	ZFILE		0x04		/* file name (s->r) */
X#define	ZSKIP		0x05		/* skip this file (r->s) */
X#define	ZNAK		0x06		/* last packet was corrupted (?) */
X#define	ZABORT		0x07		/* abort batch transfers (?) */
X#define	ZFIN		0x08		/* finish session (s<->r) */
X#define	ZRPOS		0x09		/* resume data transmission here (r->s) */
X#define	ZDATA		0x0a		/* data packet(s) follow (s->r) */
X#define	ZEOF		0x0b		/* end of file reached (s->r) */
X#define	ZFERR		0x0c		/* fatal read or write error detected (?) */
X#define	ZCRC		0x0d		/* request for file CRC and response (?) */
X#define	ZCHALLENGE	0x0e		/* security challenge (r->s) */
X#define	ZCOMPL		0x0f		/* request is complete (?) */	
X#define	ZCAN		0x10		/* pseudo frame; 
X								   other end cancelled session with 5* CAN */
X#define	ZFREECNT	0x11		/* request free bytes on file system (s->r) */
X#define	ZCOMMAND	0x12		/* issue command (s->r) */
X#define	ZSTDERR		0x13		/* output data to stderr (??) */
X
X/*
X * ZDLE sequences
X */
X
X#define	ZCRCE		0x68		/* CRC next, frame ends, header packet follows */
X#define	ZCRCG		0x69		/* CRC next, frame continues nonstop */
X#define	ZCRCQ		0x6a		/* CRC next, frame continuous, ZACK expected */
X#define	ZCRCW		0x6b		/* CRC next, frame ends,       ZACK expected */
X#define	ZRUB0		0x6c		/* translate to rubout 0x7f */
X#define	ZRUB1		0x6d		/* translate to rubout 0xff */
X
X/*
X * frame specific data.
X * entries are prefixed with their location in the header array.
X */
X
X/*
X * Byte positions within header array
X */
X
X#define FTYPE 0					/* frame type */
X
X#define ZF0	4					/* First flags byte */
X#define ZF1	3
X#define ZF2	2
X#define ZF3	1
X
X#define ZP0	1					/* Low order 8 bits of position */
X#define ZP1	2
X#define ZP2	3
X#define ZP3	4					/* High order 8 bits of file position */
X
X/*
X * ZRINIT frame
X * zmodem receiver capability flags
X */
X
X#define	ZF0_CANFDX		0x01	/* Receiver can send and receive true full duplex */
X#define	ZF0_CANOVIO		0x02	/* receiver can receive data during disk I/O */
X#define	ZF0_CANBRK		0x04	/* receiver can send a break signal */
X#define	ZF0_CANCRY		0x08	/* Receiver can decrypt DONT USE */
X#define	ZF0_CANLZW		0x10	/* Receiver can uncompress DONT USE */
X#define	ZF0_CANFC32		0x20	/* Receiver can use 32 bit Frame Check */
X#define	ZF0_ESCCTL		0x40	/* Receiver expects ctl chars to be escaped */
X#define	ZF0_ESC8		0x80	/* Receiver expects 8th bit to be escaped */
X
X#define ZF1_CANVHDR		0x01	/* Variable headers OK */
X
X/*
X * ZSINIT frame
X * zmodem sender capability
X */
X
X#define ZF0_TESCCTL 	0x40	/* Transmitter expects ctl chars to be escaped */
X#define ZF0_TESC8   	0x80	/* Transmitter expects 8th bit to be escaped */
X
X#define ZATTNLEN		0x20	/* Max length of attention string */
X#define ALTCOFF			ZF1		/* Offset to alternate canit string, 0 if not used */
X
X/*
X * ZFILE frame
X */
X
X/*
X * Conversion options one of these in ZF0
X */
X
X#define ZF0_ZCBIN		1		/* Binary transfer - inhibit conversion */
X#define ZF0_ZCNL		2		/* Convert NL to local end of line convention */
X#define ZF0_ZCRESUM		3		/* Resume interrupted file transfer */
X
X/*
X * Management include options, one of these ored in ZF1
X */
X
X#define ZF1_ZMSKNOLOC	0x80	/* Skip file if not present at rx */
X#define ZF1_ZMMASK		0x1f	/* Mask for the choices below */
X#define ZF1_ZMNEWL		1		/* Transfer if source newer or longer */
X#define ZF1_ZMCRC		2		/* Transfer if different file CRC or length */
X#define ZF1_ZMAPND		3		/* Append contents to existing file (if any) */
X#define ZF1_ZMCLOB		4		/* Replace existing file */
X#define ZF1_ZMNEW		5		/* Transfer if source newer */
X#define ZF1_ZMDIFF		6		/* Transfer if dates or lengths different */
X#define ZF1_ZMPROT		7		/* Protect destination file */
X#define ZF1_ZMCHNG		8		/* Change filename if destination exists */
X
X/*
X * Transport options, one of these in ZF2
X */
X
X#define ZF2_ZTNOR		0		/* no compression */
X#define ZF2_ZTLZW		1		/* Lempel-Ziv compression */
X#define ZF2_ZTRLE		3		/* Run Length encoding */
X
X/*
X * Extended options for ZF3, bit encoded
X */
X
X#define ZF3_ZCANVHDR	0x01	/* Variable headers OK */
X								/* Receiver window size override */
X#define ZF3_ZRWOVR 		0x04	/* byte position for receive window override/256 */
X#define ZF3_ZXSPARS		0x40	/* encoding for sparse file operations */
X
X/*
X * ZCOMMAND frame
X */
X
X#define ZF0_ZCACK1		0x01	/* Acknowledge, then do command */
X
X#endif
X
X
END_OF_zmodem.h
if test 5734 -ne `wc -c <zmodem.h`; then
    echo shar: \"zmodem.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zmrx.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zmrx.1\"
else
echo shar: Extracting \"zmrx.1\" \(953 characters\)
sed "s/^X//" >zmrx.1 <<'END_OF_zmrx.1'
X.TH ZMRX 1 "July 1994"
X.SH NAME
Xzmrx \- receive file using ZMODEM protocol
X.SH SYNOPSIS
X.B zmrx
X[
X.B \-jnopdvq
X] [
X.B \-l\fIline\fP
X]
X.SH DESCRIPTION
X.I zmrx
Xreceives a file using the ZMODEM file transfer protocol.
XBy default,
X.I zmrx
Xreads
X.I stdin
Xand writes
X.IR stdout.
X.SH OPTIONS
X.TP
X.B \-l\fIline\fP
XFile (typically a tty) to use for the transfer instead
Xof
X.IR stdin/stdout.
X.TP
X.B \-j
XJunk any path components of the filename: receive into the
Xbase filename in the current directory.
X.TP
X.B \-n
XTransfer only if source is newer than destination.
X.TP
X.B \-o,\-p
XOverwrite (protect) the destination if it exists.
XThe default is to protect the destination.  These
Xflags interact in a complicated way with similar
Xoptions at the receiving end -- see the protocol
Xspecification, or be careful.
X.TP
X.B \-v,\-q
XVerbose (quiet) mode.
X.TP
X.B \-d
XDebug mode.
X.SH "SEE ALSO"
X.PD
X.BR  zmtx(1), sz(1), rz(1)
X.SH AUTHOR
XJacques Mattheij <jacquesm@hacktic.nl>
END_OF_zmrx.1
if test 953 -ne `wc -c <zmrx.1`; then
    echo shar: \"zmrx.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zmrx.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zmrx.c\"
else
echo shar: Extracting \"zmrx.c\" \(10374 characters\)
sed "s/^X//" >zmrx.c <<'END_OF_zmrx.c'
X/******************************************************************************/
X/* Project : Unite!       File : zmodem receive        Version : 1.02         */
X/*                                                                            */
X/* (C) Mattheij Computer Service 1994                                         */
X/*                                                                            */
X/* contact us through (in order of preference)                                */
X/*                                                                            */
X/*   email:          jacquesm@hacktic.nl                                      */
X/*   mail:           MCS                                                      */
X/*                   Prinses Beatrixlaan 535                                  */
X/*                   2284 AT  RIJSWIJK                                        */
X/*                   The Netherlands                                          */
X/*   voice phone:    31+070-3936926                                           */
X/******************************************************************************/
X
X#include <ctype.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/stat.h>
X#include <string.h>
X#include <time.h>
X#include <utime.h>
X#include "version.h"
X
X#include "zmodem.h"
X#include "zmdm.h"
X#include "opts.h"
X
XFILE * fp = NULL;												/* fp of file being received or NULL */
Xlong mdate;														/* file date of file being received */
Xchar filename[0x80];											/* filename of file being received */
Xchar * name;													/* pointer to the part of the filename used in the actual open */
X
Xchar * line = NULL;												/* device to use for io */
Xint opt_v = FALSE;												/* show progress output */
Xint opt_d = FALSE;												/* show debug output */
Xint opt_q = FALSE;
Xint junk_pathnames = FALSE;										/* junk incoming path names or keep them */
Xunsigned char rx_data_subpacket[8192];							/* zzap = 8192 */
X
Xlong current_file_size;
Xtime_t transfer_start;
X
X/* 
X * show the progress of the transfer like this:
X * zmrx: receiving file "garbage" 4096 bytes ( 20%)
X * avoids the use of floating point.
X */
X
Xvoid
Xshow_progress(char * name,FILE * fp)
X
X{
X	int percentage;
X	time_t duration;
X	int cps;
X
X	if (current_file_size > 0) {
X		percentage = (ftell(fp) * 100) / current_file_size;
X	}
X	else {
X		percentage = 100;
X	}
X
X	duration = time(NULL) - transfer_start;
X
X	if (duration == 0l) {
X		duration = 1;
X	}
X
X	cps = ftell(fp) / duration;
X
X	fprintf(stderr,"zmrx: receiving file \"%s\" %8ld bytes (%3d %%/%5d cps)           \r",
X		name,ftell(fp),percentage,cps);
X}
X
X/*
X * receive a header and check for garbage
X */
X
X/*
X * receive file data until the end of the file or until something goes wrong.
X * the name is only used to show progress
X */
X
Xint 
Xreceive_file_data(char * name,FILE * fp)
X
X{
X	static int first = TRUE;
X	long pos;
X	int n;
X	int type;
X
X	/*
X 	 * create a ZRPOS frame and send it to the other side
X	 */
X
X	tx_pos_header(ZRPOS,ftell(fp));
X
X/*	fprintf(stderr,"re-transmit from %d\n",ftell(fp));
X*/
X	/*
X	 * wait for a ZDATA header with the right file offset
X	 * or a timeout or a ZFIN
X	 */
X
X	do {
X		do {
X			type = rx_header(10000);
X			if (type == TIMEOUT) {
X				return TIMEOUT;
X			}
X		} while (type != ZDATA);
X
X		pos = rxd_header[ZP0] | (rxd_header[ZP1] << 8) |
X			(rxd_header[ZP2] << 16) | (rxd_header[ZP3] << 24);
X	} while (pos != ftell(fp));
X		
X	do {
X		type = rx_data(rx_data_subpacket,&n);
X
X/*		fprintf(stderr,"packet len %d type %d\n",n,type);
X*/
X		if (type == ENDOFFRAME || type == FRAMEOK) {
X			fwrite(rx_data_subpacket,1,n,fp);
X		}
X
X		if (opt_v) {
X			show_progress(name,fp);
X		}
X
X	} while (type == FRAMEOK);
X
X	return type;
X}
X
Xvoid
Xtx_zrinit()
X
X{
X	unsigned char zrinit_header[] = { ZRINIT, 0, 0, 0, 4 | ZF0_CANFDX | ZF0_CANOVIO | ZF0_CANFC32 };
X
X	tx_hex_header(zrinit_header);
X}
X
X
X/*
X * receive a file
X * if the file header info packet was garbled then send a ZNAK and return
X * (using ZABORT frame)
X */
X
Xvoid
Xreceive_file()
X
X{
X	long size;
X	struct stat s;
X	int type;
X	int l;
X	int clobber;
X	int protect;
X	int newer;
X	int exists;
X	struct utimbuf tv;
X	char * mode = "wb";
X
X	/*
X	 * fetch the management info bits from the ZRFILE header
X	 */
X
X	/*
X	 * management option
X	 */
X
X	if (management_protect || (rxd_header[ZF1] & ZF1_ZMPROT)) {
X		protect = TRUE;
X	}
X	else {
X		if (management_clobber || (rxd_header[ZF1] & ZF1_ZMCLOB)) {
X			clobber = TRUE;
X		}
X	}
X
X	if (management_newer || (rxd_header[ZF1] & ZF1_ZMNEW)) {
X		newer = TRUE;
X	}
X
X	/*
X	 * read the data subpacket containing the file information
X	 */
X
X	type = rx_data(rx_data_subpacket,&l);
X
X	if (type != FRAMEOK && type != ENDOFFRAME) {
X		if (type != TIMEOUT) {
X			/*
X			 * file info data subpacket was trashed
X			 */
X			tx_znak();
X		}
X		return;
X	}
X
X	/*
X	 * extract the relevant info from the header.
X	 */
X
X	strcpy(filename,rx_data_subpacket);
X
X	if (junk_pathnames) {
X		name = strrchr(filename,'/');
X		if (name != NULL) {
X			name++;
X		}
X		else {
X			name = filename;
X		}
X	}
X	else {
X		name = filename;
X	}
X
X	if (opt_v) {
X		fprintf(stderr,"zmrx: receiving file \"%s\"\r",name);
X	}
X
X	sscanf(rx_data_subpacket + strlen(rx_data_subpacket) + 1,
X		"%ld %lo",&size,&mdate);
X
X	current_file_size = size;
X
X	/*
X	 * decide whether to transfer the file or skip it
X	 */
X
X	fp = fopen(name,"rb");
X
X	if (fp != NULL) {
X		exists = TRUE;
X
X		fstat(fileno(fp),&s);
X
X		fclose(fp);
X	}
X	else {
X		exists = FALSE;
X	}
X
X	/*
X	 * if the file already exists here the management options need to
X	 * be checked..
X	 */
X	if (exists) {
X		if (mdate == s.st_mtime) {
X			/*
X			 * this is crash recovery
X			 */
X			mode = "ab";
X		}
X		else {
X			/*
X		 	 * if the file needs to be protected then exit here.
X			 */
X			if (protect) {		
X				tx_pos_header(ZSKIP,0L);
X				return;
X			}
X			/*
X			 * if it is not ok to just overwrite it
X			 */
X			if (!clobber) {
X				/*
X				 * if the remote file has to be newer
X				 */
X				if (newer) {
X					if (mdate < s.st_mtime) {
X						tx_pos_header(ZSKIP,0L);
X						/*
X					 	 * and it isnt then exit here.
X					 	 */
X						return;
X					}
X				}
X			}
X		}
X	}
X
X	/*
X 	 * transfer the file
X	 * either not present; remote newer; ok to clobber or no options set.
X	 * (no options->clobber anyway)
X	 */
X
X	fp = fopen(name,mode);
X
X	if (fp == NULL) {
X		tx_pos_header(ZSKIP,0L);
X		if (opt_v) {
X			fprintf(stderr,"zmrx: can't open file %s\n",name);
X		}
X		return;
X	}
X
X	transfer_start = time(NULL);
X
X	while (ftell(fp) != size) {
X		type = receive_file_data(filename,fp);
X		if (type == ZEOF) {
X			break;
X		}
X	}
X
X	/*
X 	 * wait for the eof header
X	 */
X
X	while (type != ZEOF) {
X		type = rx_header_and_check(10000);
X	} 
X
X	/*
X	 * close and exit
X	 */
X
X	fclose(fp);
X
X	fp = NULL;
X
X	/*
X	 * set the time
X	 */
X
X	tv.actime = mdate;
X	tv.modtime = mdate;
X
X	utime(name, &tv);
X
X	/*
X	 * and close the input file
X	 */
X
X	if (opt_v) {
X		fprintf(stderr,"zmrx: received file \"%s\"                 \n",name);
X	}
X}
X
Xvoid
Xcleanup(void)
X
X{
X	struct utimbuf tv;
X
X	if (fp) {
X		fflush(fp);
X		fclose(fp);
X		/*
X		 * set the time (so crash recovery may work)
X		 */
X
X		tv.actime = mdate;
X		tv.modtime = mdate;
X
X		utime(name, &tv);
X	}
X
X	fd_exit();
X}
X
X
Xvoid
Xusage(void)
X
X{
X	printf("zmrx %s (C) Mattheij Computer Service 1994\n",VERSION);
X	printf("usage : zmrx options\n");
X	printf("	-lline      line to use for io\n");
X	printf("	-j    		junk pathnames\n");
X	printf("	-n    		transfer if source is newer\n");
X	printf("	-o    	    overwrite if exists\n");
X	printf("	-p          protect (don't overwrite if exists)\n");
X	printf("\n");
X	printf("	-d          debug output\n");
X	printf("	-v          verbose output\n");
X	printf("	-q          quiet\n");
X	printf("	(only one of -n -c or -p may be specified)\n");
X
X	cleanup();
X
X	exit(1);
X}
X
Xint
Xmain(int argc,char ** argv)
X
X{
X	int i;
X	char * s;
X	int type;
X
X	argv++;
X	while (--argc > 0 && ((*argv)[0] == '-')) {
X		for (s = argv[0]+1; *s != '\0'; s++) {
X			switch (toupper(*s)) {
X				OPT_BOOL('D',opt_d);
X				OPT_BOOL('V',opt_v);
X				OPT_BOOL('Q',opt_q);
X
X				OPT_BOOL('N',management_newer);
X				OPT_BOOL('O',management_clobber);
X				OPT_BOOL('P',management_protect);
X				OPT_BOOL('J',junk_pathnames);
X				OPT_STRING('L',line);
X				default:
X					printf("zmrx: bad option %c\n",*s);
X					usage();
X			}
X		}
X		argv++;
X	}
X
X	if (opt_d) {
X		opt_v = TRUE;
X	}
X
X	if (opt_q) {
X		opt_v = FALSE;
X		opt_d = FALSE;
X	}
X
X#if 0
X	if (!opt_v) {
X		freopen("/usr/src/utils/zmnew/trace","w",stderr);
X		setbuf(stderr,NULL);
X	}
X#endif
X
X	if ((management_newer + management_clobber + management_protect) > 1 || argc != 0) {
X		usage();
X	}
X
X	if (line != NULL) {	
X		if (freopen(line,"r",stdin) == NULL) {
X			fprintf(stderr,"zmrx can't open line for input %s\n",line);
X			exit(2);
X		}
X		if (freopen(line,"w",stdout) == NULL) {
X			fprintf(stderr,"zmrx can't open line for output %s\n",line);
X			exit(2);
X		}
X	}
X
X	/*
X	 * set the io device to transparent
X	 */
X
X	fd_init();	
X
X	/*
X	 * establish contact with the sender
X	 */
X
X	if (opt_v) {
X		fprintf(stderr,"zmrx: establishing contact with sender\n");
X	}
X
X	/*
X	 * make sure we dont get any old garbage
X	 */
X
X	rx_purge();
X
X	/*
X	 * loop here until contact is established.
X	 * another packet than a ZRQINIT should be received.
X	 */
X
X	i = 0;
X	do {
X		i++;
X		if (i > 10) {
X			fprintf(stderr,"zmrx: can't establish contact with sender\n");
X			cleanup();
X			exit(3);
X		}
X
X		tx_zrinit();
X		type = rx_header(7000);
X	} while (type == TIMEOUT || type == ZRQINIT);
X
X	if (opt_v) {
X		fprintf(stderr,"zmrx: contact established\n");
X		fprintf(stderr,"zmrx: starting file transfer\n");
X	}
X
X	/* 
X	 * and receive files
X	 * (other packets are acknowledged with a ZCOMPL but ignored.)
X	 */
X
X	do {
X		switch (type) {
X			case ZFILE:
X				receive_file();
X				break;
X			default:
X				tx_pos_header(ZCOMPL,0l);
X				break;
X		}
X
X		do {
X			tx_zrinit();
X
X			type = rx_header(7000);
X		} while (type == TIMEOUT);
X	} while (type != ZFIN);
X
X	/*
X	 * close the session
X	 */
X
X	if (opt_v) {
X		fprintf(stderr,"zmrx: closing the session\n");
X	}
X
X	{
X		int type;
X		unsigned char zfin_header[] = { ZFIN, 0, 0, 0, 0 };
X
X		tx_hex_header(zfin_header);
X	}
X
X	/*
X	 * wait for the over and out sequence
X	 */
X
X	{
X		int c;
X		do {
X			c = rx_raw();
X		} while (c != 'O' && c != TIMEOUT);
X
X		if (c != TIMEOUT) {
X			do {
X				c = rx_raw();
X			} while (c != 'O' && c != TIMEOUT);
X		}
X	}
X
X	if (opt_d) {
X		fprintf(stderr,"zmrx: cleanup and exit\n");
X	}
X
X	cleanup();
X
X	exit(0);
X
X	return 0;		/* to stop the compiler from complaining */
X}
X
X
X
X
END_OF_zmrx.c
if test 10374 -ne `wc -c <zmrx.c`; then
    echo shar: \"zmrx.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zmtx.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zmtx.1\"
else
echo shar: Extracting \"zmtx.1\" \(832 characters\)
sed "s/^X//" >zmtx.1 <<'END_OF_zmtx.1'
X.TH ZMTX 1 "July 1994"
X.SH NAME
Xzmtx \- transmit file using ZMODEM protocol
X.SH SYNOPSIS
X.B zmtx
X[
X.B \-nopdv
X] [
X.B \-l\fIline\fP
X]
X.SH DESCRIPTION
X.I zmtx
Xtransmits a file using the ZMODEM file transfer protocol.
XBy default,
X.I zmtx
Xreads
X.I stdin
Xand writes
X.IR stdout.
X.SH OPTIONS
X.TP
X.B \-l\fIline\fP
XFile (typically a tty) to use for the transfer instead
Xof
X.IR stdin/stdout.
X.TP
X.B \-n
XTransfer only if source is newer than destination.
X.TP
X.B \-o,\-p
XOverwrite (protect) the destination if it exists.
XThe default is to protect the destination.  These
Xflags interact in a complicated way with similar
Xoptions at the receiving end -- see the protocol
Xspecification, or be careful.
X.TP
X.B \-v
XVerbose mode.
X.TP
X.B \-d
XDebug mode.
X.SH "SEE ALSO"
X.PD
X.BR  zmrx(1), sz(1), rz(1)
X.SH AUTHOR
XJacques Mattheij <jacquesm@hacktic.nl>
X
END_OF_zmtx.1
if test 832 -ne `wc -c <zmtx.1`; then
    echo shar: \"zmtx.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f zmtx.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"zmtx.c\"
else
echo shar: Extracting \"zmtx.c\" \(12268 characters\)
sed "s/^X//" >zmtx.c <<'END_OF_zmtx.c'
X/******************************************************************************/
X/* Project : Unite!       File : zmodem transmit       Version : 1.02         */
X/*                                                                            */
X/* (C) Mattheij Computer Service 1994                                         */
X/*                                                                            */
X/* contact us through (in order of preference)                                */
X/*                                                                            */
X/*   email:          jacquesm@hacktic.nl                                      */
X/*   mail:           MCS                                                      */
X/*                   Prinses Beatrixlaan 535                                  */
X/*                   2284 AT  RIJSWIJK                                        */
X/*                   The Netherlands                                          */
X/*   voice phone:    31+070-3936926                                           */
X/******************************************************************************/
X
X#include <ctype.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/stat.h>
X#include <string.h>
X#include <time.h>
X#include "version.h"
X
X#include "zmodem.h"
X#include "zmdm.h"
X#include "opts.h"
X
X#define MAX_SUBPACKETSIZE 1024
X
Xchar * line = NULL;												/* device to use for io */
Xint opt_v = FALSE;												/* show progress output */
Xint opt_d = FALSE;												/* show debug output */
Xint subpacket_size = MAX_SUBPACKETSIZE;							/* data subpacket size. may be modified during a session */
Xint n_files_remaining;
Xunsigned char tx_data_subpacket[1024];
X
Xlong current_file_size;
Xtime_t transfer_start;
X
X/* 
X * show the progress of the transfer like this:
X * zmtx: sending file "garbage" 4096 bytes ( 20%)
X */
X
Xvoid
Xshow_progress(char * name,FILE * fp)
X
X{
X	time_t duration;
X	int cps;
X	int percentage;
X
X	if (current_file_size > 0) {
X		percentage = (ftell(fp) * 100) / current_file_size;
X	}
X	else {
X		percentage = 100;
X	}
X
X	duration = time(NULL) - transfer_start;
X
X	if (duration == 0l) {
X		duration = 1l;
X	}
X
X	cps = ftell(fp) / duration;
X
X	fprintf(stderr,"zmtx: sending file \"%s\" %8ld bytes (%3d %%/%5d cps)           \r",
X		name,ftell(fp),percentage,cps);
X}
X
X/*
X * send from the current position in the file
X * all the way to end of file or until something goes wrong.
X * (ZNAK or ZRPOS received)
X * the name is only used to show progress
X */
X
Xint
Xsend_from(char * name,FILE * fp)
X
X{
X	int n;
X	int type = ZCRCG;
X	char zdata_frame[] = { ZDATA, 0, 0, 0, 0 };
X
X	/*
X 	 * put the file position in the ZDATA frame
X	 */
X
X	zdata_frame[ZP0] =  ftell(fp)        & 0xff;
X	zdata_frame[ZP1] = (ftell(fp) >> 8)  & 0xff;
X	zdata_frame[ZP2] = (ftell(fp) >> 16) & 0xff;
X	zdata_frame[ZP3] = (ftell(fp) >> 24) & 0xff;
X
X	tx_header(zdata_frame);
X	/*
X	 * send the data in the file
X	 */
X
X	while (!feof(fp)) {
X		if (opt_v) {
X			show_progress(name,fp);
X		}
X
X		/*
X		 * read a block from the file
X		 */
X		n = fread(tx_data_subpacket,1,subpacket_size,fp);
X
X		if (n == 0) {
X			/*
X			 * nothing to send ?
X			 */
X			break;
X		}
X
X		/*
X		 * at end of file wait for an ACK
X		 */
X		if (ftell(fp) == current_file_size) {
X			type = ZCRCW;
X		}
X
X		tx_data(type,tx_data_subpacket,n);
X
X		if (type == ZCRCW) {
X			int type;
X			do {
X				type = rx_header(10000);
X				if (type == ZNAK || type == ZRPOS) {
X					return type;
X				}
X			} while (type != ZACK);
X
X			if (ftell(fp) == current_file_size) {
X				if (opt_d) {
X					fprintf(stderr,"end of file\n");
X				}
X				return ZACK;
X			}
X		}
X
X		/* 
X		 * characters from the other side
X		 * check out that header
X		 */
X
X		while (rx_poll()) {
X			int type;
X			int c;
X			c = rx_raw();
X			if (c == ZPAD) {
X				type = rx_header(1000);
X				if (type != TIMEOUT && type != ACK) {
X					return type;
X				}
X			}
X		}
X	}
X
X	/*
X	 * end of file reached.
X	 * should receive something... so fake ZACK
X	 */
X
X	return ZACK;
X}
X
X/*
X * send a file; returns true when session is aborted.
X * (using ZABORT frame)
X */
X
Xint
Xsend_file(char * name)
X
X{
X	long pos;
X	long size;
X	struct stat s;
X	FILE * fp;
X	unsigned char * p;
X	char zfile_frame[] = { ZFILE, 0, 0, 0, 0 };
X	char zeof_frame[] = { ZEOF, 0, 0, 0, 0 };
X	int wait_for_header;
X	int type;
X	char * n;
X
X	if (opt_v) {
X		fprintf(stderr,"zmtx: sending file \"%s\"\r",name);
X	}
X
X	/*
X	 * before doing a lot of unnecessary work check if the file exists
X	 */
X
X	fp = fopen(name,"rb");
X
X	if (fp == NULL) {
X		if (opt_v) {
X			fprintf(stderr,"zmtx: can't open file %s\n",name);
X		}
X		return;
X	}
X
X	fstat(fileno(fp),&s);
X	size = s.st_size;
X	current_file_size = size;
X
X	/*
X	 * the file exists. now build the ZFILE frame
X	 */
X
X	/*
X	 * set conversion option
X	 * (not used; always binary)
X	 */
X
X	zfile_frame[ZF0] = ZF0_ZCBIN;
X
X	/*
X	 * management option
X	 */
X
X	if (management_protect) {
X		zfile_frame[ZF1] = ZF1_ZMPROT;		
X		if (opt_d) {
X			fprintf(stderr,"zmtx: protecting destination\n");
X		}
X	}
X
X	if (management_clobber) {
X		zfile_frame[ZF1] = ZF1_ZMCLOB;
X		if (opt_d) {
X			fprintf(stderr,"zmtx: overwriting destination\n");
X		}
X	}
X
X	if (management_newer) {
X		zfile_frame[ZF1] = ZF1_ZMNEW;
X		if (opt_d) {
X			fprintf(stderr,"zmtx: overwriting destination if newer\n");
X		}
X	}
X
X	/*
X	 * transport options
X	 * (just plain normal transfer)
X	 */
X
X	zfile_frame[ZF2] = ZF2_ZTNOR;
X
X	/*
X	 * extended options
X	 */
X
X	zfile_frame[ZF3] = 0;
X
X	/*
X 	 * now build the data subpacket with the file name and lots of other
X	 * useful information.
X	 */
X
X	/*
X	 * first enter the name and a 0
X	 */
X
X	p = tx_data_subpacket;
X
X	/*
X	 * strip the path name from the filename
X	 */
X
X	n = strrchr(name,'/');
X	if (n == NULL) {
X		n = name;
X	}
X	else {
X		n++;
X	}
X
X	strcpy(p,n);
X
X	p += strlen(p) + 1;
X
X	/*
X	 * next the file size
X	 */
X
X	sprintf(p,"%ld ",size);
X
X	p += strlen(p);
X
X	/*
X 	 * modification date
X	 */
X
X	sprintf(p,"%lo ",s.st_mtime);
X
X	p += strlen(p);
X
X	/*
X	 * file mode
X	 */
X
X	sprintf(p,"0 ");
X
X	p += strlen(p);
X
X	/*
X	 * serial number (??)
X	 */
X
X	sprintf(p,"0 ");
X
X	p += strlen(p);
X
X	/*
X	 * number of files remaining
X	 */
X
X	sprintf(p,"%d ",n_files_remaining);
X
X	p += strlen(p);
X
X	/*
X	 * file type
X	 */
X
X	sprintf(p,"0");
X
X	p += strlen(p) + 1;
X
X	do {
X		/*
X	 	 * send the header and the data
X	 	 */
X
X		tx_header(zfile_frame);
X		tx_data(ZCRCW,tx_data_subpacket,p - tx_data_subpacket);
X	
X		/*
X		 * wait for anything but an ZACK packet
X		 */
X
X		do {
X			type = rx_header(10000);
X		} while (type == ZACK);
X
X		if (opt_d) {
X			fprintf(stderr,"type : %d\n",type);
X		}
X
X		if (type == ZSKIP) {
X			fclose(fp);
X			if (opt_v) {
X				fprintf(stderr,"zmtx: skipped file \"%s\"                       \n",name);
X			}
X			return;
X		}
X
X	} while (type != ZRPOS);
X
X	transfer_start = time(NULL);
X
X	do {
X		/*
X		 * fetch pos from the ZRPOS header
X		 */
X
X		if (type == ZRPOS) {
X			pos = rxd_header[ZP0] | (rxd_header[ZP1] << 8) | (rxd_header[ZP2] << 16) | (rxd_header[ZP3] << 24);
X		}
X
X		/*
X 		 * seek to the right place in the file
X		 */
X		fseek(fp,pos,0);
X
X		/*
X		 * and start sending
X		 */
X
X		type = send_from(n,fp);
X
X		if (type == ZFERR || type == ZABORT) {
X 			fclose(fp);
X			return TRUE;
X		}
X
X	} while (type == ZRPOS || type == ZNAK);
X
X	/*
X	 * file sent. send end of file frame
X	 * and wait for zrinit. if it doesnt come then try again
X	 */
X
X	zeof_frame[ZP0] =  s.st_size        & 0xff;
X	zeof_frame[ZP1] = (s.st_size >> 8)  & 0xff;
X	zeof_frame[ZP2] = (s.st_size >> 16) & 0xff;
X	zeof_frame[ZP3] = (s.st_size >> 24) & 0xff;
X
X	do {
X		tx_hex_header(zeof_frame);
X		type = rx_header(10000);
X	} while (type != ZRINIT);
X
X	/*
X	 * and close the input file
X	 */
X
X	if (opt_v) {
X		fprintf(stderr,"zmtx: sent file \"%s\"                                    \n",name);
X	}
X
X	fclose(fp);
X
X	return FALSE;
X}
X
Xvoid
Xcleanup(void)
X
X{
X	fd_exit();
X}
X
Xvoid
Xusage(void)
X
X{
X	printf("zmtx %s (C) Mattheij Computer Service 1994\n",VERSION);
X	printf("usage : zmtx options files\n");
X	printf("	-lline      line to use for io\n");
X	printf("	-n    		transfer if source is newer\n");
X	printf("	-o    	    overwrite if exists\n");
X	printf("	-p          protect (don't overwrite if exists)\n");
X	printf("\n");
X	printf("	-d          debug output\n");
X	printf("	-v          verbose output\n");
X	printf("	(only one of -n -c or -p may be specified)\n");
X
X	cleanup();
X
X	exit(1);
X}
X
Xint
Xmain(int argc,char ** argv)
X
X{
X	int i;
X	char * s;
X
X	argv++;
X	while (--argc > 0 && ((*argv)[0] == '-')) {
X		for (s = argv[0]+1; *s != '\0'; s++) {
X			switch (toupper(*s)) {
X				OPT_BOOL('D',opt_d);
X				OPT_BOOL('V',opt_v);
X
X				OPT_BOOL('N',management_newer);
X				OPT_BOOL('O',management_clobber);
X				OPT_BOOL('P',management_protect);
X				OPT_STRING('L',line);
X				default:
X					printf("zmtx: bad option %c\n",*s);
X					usage();
X			}
X		}
X		argv++;
X	}
X
X	if (opt_d) {
X		opt_v = TRUE;
X	}
X
X	if ((management_newer + management_clobber + management_protect) > 1 || argc == 0) {
X		usage();
X	}
X
X	if (line != NULL) {	
X		if (freopen(line,"r",stdin) == NULL) {
X			fprintf(stderr,"zmtx can't open line for input %s\n",line);
X			exit(2);
X		}
X		if (freopen(line,"w",stdout) == NULL) {
X			fprintf(stderr,"zmtx can't open line for output %s\n",line);
X			exit(2);
X		}
X	}
X
X	/*
X	 * set the io device to transparent
X	 */
X
X	fd_init();	
X
X	/*
X	 * clear the input queue from any possible garbage
X	 * this also clears a possible ZRINIT from an already started
X	 * zmodem receiver. this doesn't harm because we reinvite to
X	 * receive again below and it may be that the receiver whose
X	 * ZRINIT we are about to wipe has already died.
X	 */
X
X	rx_purge();
X
X	/*
X	 * establish contact with the receiver
X	 */
X
X	if (opt_v) {
X		fprintf(stderr,"zmtx: establishing contact with receiver\n");
X	}
X
X	i = 0;
X	do {
X		unsigned char zrqinit_header[] = { ZRQINIT, 0, 0, 0, 0 };
X		i++;
X		if (i > 10) {
X			fprintf(stderr,"zmtx: can't establish contact with receiver\n");
X			cleanup();
X			exit(3);
X		}
X
X		tx_raw('z');
X		tx_raw('m');
X		tx_raw(13);
X		tx_hex_header(zrqinit_header);
X	} while (rx_header(7000) != ZRINIT);
X
X	if (opt_v) {
X		fprintf(stderr,"zmtx: contact established\n");
X		fprintf(stderr,"zmtx: starting file transfer\n");
X	}
X
X	/*
X	 * decode receiver capability flags
X	 * forget about encryption and compression.
X	 */
X
X	can_full_duplex					= (rxd_header[ZF0] & ZF0_CANFDX)  != 0;
X	can_overlap_io					= (rxd_header[ZF0] & ZF0_CANOVIO) != 0;
X	can_break						= (rxd_header[ZF0] & ZF0_CANBRK)  != 0;
X	can_fcs_32						= (rxd_header[ZF0] & ZF0_CANFC32) != 0;
X	escape_all_control_characters	= (rxd_header[ZF0] & ZF0_ESCCTL)  != 0;
X	escape_8th_bit					= (rxd_header[ZF0] & ZF0_ESC8)    != 0;
X
X	use_variable_headers			= (rxd_header[ZF1] & ZF1_CANVHDR) != 0;
X
X	if (opt_d) {
X		fprintf(stderr,"receiver %s full duplex\n"          ,can_full_duplex               ? "can"      : "can't");
X		fprintf(stderr,"receiver %s overlap io\n"           ,can_overlap_io                ? "can"      : "can't");
X		fprintf(stderr,"receiver %s break\n"                ,can_break                     ? "can"      : "can't");
X		fprintf(stderr,"receiver %s fcs 32\n"               ,can_fcs_32                    ? "can"      : "can't");
X		fprintf(stderr,"receiver %s escaped control chars\n",escape_all_control_characters ? "requests" : "doesn't request");
X		fprintf(stderr,"receiver %s escaped 8th bit\n"      ,escape_8th_bit                ? "requests" : "doesn't request");
X		fprintf(stderr,"receiver %s use variable headers\n" ,use_variable_headers          ? "can"      : "can't");
X	}
X
X	/* 
X	 * and send each file in turn
X	 */
X
X	n_files_remaining = argc;
X
X	while (argc) {
X		if (send_file(*argv)) {
X			if (opt_v) {
X				fprintf(stderr,"zmtx: remote aborted.\n");
X			}
X			break;
X		}
X
X		n_files_remaining--;
X		argc--;
X		argv++;
X	}
X
X	/*
X	 * close the session
X	 */
X
X	if (opt_v) {
X		fprintf(stderr,"zmtx: closing the session\n");
X	}
X
X	{
X		int type;
X		unsigned char zfin_header[] = { ZFIN, 0, 0, 0, 0 };
X
X		tx_hex_header(zfin_header);
X		do {
X			type = rx_header(10000);
X		} while (type != ZFIN && type != TIMEOUT);
X		
X		/*
X		 * these Os are formally required; but they don't do a thing
X		 * unfortunately many programs require them to exit 
X		 * (both programs already sent a ZFIN so why bother ?)
X		 */
X
X		if (type != TIMEOUT) {
X			tx_raw('O');
X			tx_raw('O');
X		}
X	}
X
X	/*
X	 * c'est fini
X	 */
X
X	if (opt_d) {
X		fprintf(stderr,"zmtx: cleanup and exit\n");
X	}
X
X	cleanup();
X
X	exit(0);
X
X	return 0;
X}
X
X
X
X
END_OF_zmtx.c
if test 12268 -ne `wc -c <zmtx.c`; then
    echo shar: \"zmtx.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
