Added Experimental File areas

This commit is contained in:
Andrew Pamment 2016-04-03 09:26:17 +10:00
parent 955f6b6c06
commit d2b24c8dab
31 changed files with 9063 additions and 4 deletions

View File

@ -2,13 +2,14 @@ CC=cc
CFLAGS=-I/usr/local/include
DEPS = bbs.h
JAMLIB = jamlib/jamlib.a
ZMODEM = Xmodem/libzmodem.a
OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o chat_system.o email.o
OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o chat_system.o email.o files.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
magicka: $(OBJ)
$(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) -lutil
$(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) -lutil
.PHONY: clean

19
Xmodem/LICENSE Normal file
View File

@ -0,0 +1,19 @@
Copyright © 2001 Edward A. Falk
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

42
Xmodem/Makefile Normal file
View File

@ -0,0 +1,42 @@
# $Id: Makefile,v 1.2 2001/10/25 23:56:29 efalk Exp $
INC = -I..
#OPT = -g
OPT = -O
CFLAGS = $(OPT) $(INC) -DHAVE_STRDUP
AR = ar
RANLIB = ranlib
HDRS = crctab.h seriallog.h xmodem.h zmodem.h
SRCS = crctab.c seriallog.c zmodem.c zmodemr.c zmodemsys.c zmodemt.c zmutil.c
OBJS = $(SRCS:.c=.o)
libzmodem.a: $(OBJS)
-rm -f libzmodem.a
$(AR) cru libzmodem.a $(OBJS)
$(RANLIB) libzmodem.a
clean:
rm -f *.o *.s *.i
clobber: clean
rm -f *.a tags
tags: $(SRCS) $(HDRS)
ctags *.[ch]
.SUFFIXES: .i .s
.c.i:
$(CC) -E $(CFLAGS) $*.c > $@
.c.s:
$(CC) -S $(CFLAGS) $*.c
depend:
makedepend -- $(CFLAGS) -- $(SRCS)

197
Xmodem/checkcrc.c Normal file
View File

@ -0,0 +1,197 @@
#ifndef lint
static const char rcsid[] = "$Id: checkcrc.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
#include <stdio.h>
#include <sys/types.h>
#include "crctab.h"
static u_char msg0[] = {
0x2a, 0x18, 0x43, 0x0a, 0x00, 0x00, 0x00, 0x00,
0xbc, 0xef, 0x92, 0x8c,} ;
static u_char msg0c[] = {
0x2a, 0x18, 0x43, 0x0a, 0x00, 0x00, 0x00, 0x00,
0xbc, 0xef, 0x92, 0x8c, 0x0b, 0xdf,} ;
static u_char msg1[] = {
0x0a, 0x23, 0x69, 0x6e,
0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73,
0x79, 0x73, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69,
0x6f, 0x73, 0x2e, 0x68, 0x3e, 0x0a, 0x23, 0x69,
0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x22,
0x78, 0x6d, 0x6f, 0x64, 0x65, 0x6d, 0x2e, 0x68,
0x22, 0x0a, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x0a,
0x73, 0x65, 0x6e, 0x64, 0x43, 0x61, 0x6e, 0x63,
0x65, 0x6c, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x09,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73,
0x65, 0x6e, 0x64, 0x46, 0x6c, 0x75, 0x73, 0x68,
0x28, 0x43, 0x41, 0x4e, 0x29, 0x20, 0x7c, 0x7c,
0x20, 0x73, 0x65, 0x6e, 0x64, 0x46, 0x6c, 0x75,
0x73, 0x68, 0x28, 0x43, 0x41, 0x4e, 0x29, 0x20,
0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x0a, 0x09, 0x2f,
0x2a, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6f,
0x6e, 0x65, 0x20, 0x63, 0x68, 0x61, 0x72, 0x61,
0x63, 0x74, 0x65, 0x72, 0x2c, 0x20, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x6f, 0x6e,
0x7a, 0x65, 0x72, 0x6f, 0x20, 0x6f, 0x6e, 0x20,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x2a, 0x2f,
0x0a, 0x69, 0x6e, 0x74, 0x0a, 0x73, 0x65, 0x6e,
0x64, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x28, 0x63,
0x29, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, 0x09,
0x63, 0x20, 0x3b, 0x0a, 0x7b, 0x0a, 0x09, 0x2f,
0x2a, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2c,
0x20, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x20, 0x69,
0x6e, 0x70, 0x75, 0x74, 0x20, 0x70, 0x6f, 0x72,
0x74, 0x20, 0x2a, 0x2f, 0x0a, 0x09, 0x2f, 0x2a,
0x20, 0x54, 0x4f, 0x44, 0x4f, 0x3a, 0x20, 0x63,
0x61, 0x6c, 0x6c, 0x65, 0x72, 0x20, 0x70, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x61, 0x20,
0x77, 0x61, 0x79, 0x20, 0x18, 0x69, 0x4c, 0x5b,
0x62, 0x0f,
0x2a, 0x18, 0x43, 0x0a, 0x00, 0x00,
0x00, 0x00, 0xbc, 0xef, 0x92, 0x8c, 0x0a, 0x23,
0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20,
0x3c, 0x73, 0x79, 0x73, 0x2f, 0x74, 0x65, 0x72,
0x6d, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x3e, 0x0a,
0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65,
0x20, 0x22, 0x78, 0x6d, 0x6f, 0x64, 0x65, 0x6d,
0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x0a, 0x69, 0x6e,
0x74, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x43, 0x61,
0x6e, 0x63, 0x65, 0x6c, 0x28, 0x29, 0x0a, 0x7b,
0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x73, 0x65, 0x6e, 0x64, 0x46, 0x6c, 0x75,
0x73, 0x68, 0x28, 0x43, 0x41, 0x4e, 0x29, 0x20,
0x7c, 0x7c, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x46,
0x6c, 0x75, 0x73, 0x68, 0x28, 0x43, 0x41, 0x4e,
0x29, 0x20, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x0a,
0x09, 0x2f, 0x2a, 0x20, 0x73, 0x65, 0x6e, 0x64,
0x20, 0x6f, 0x6e, 0x65, 0x20, 0x63, 0x68, 0x61,
0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x2c, 0x20,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e,
0x6f, 0x6e, 0x7a, 0x65, 0x72, 0x6f, 0x20, 0x6f,
0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20,
0x2a, 0x2f, 0x0a, 0x69, 0x6e, 0x74, 0x0a, 0x73,
0x65, 0x6e, 0x64, 0x46, 0x6c, 0x75, 0x73, 0x68,
0x28, 0x63, 0x29, 0x0a, 0x09, 0x63, 0x68, 0x61,
0x72, 0x09, 0x63, 0x20, 0x3b, 0x0a, 0x7b, 0x0a,
0x09, 0x2f, 0x2a, 0x20, 0x66, 0x69, 0x72, 0x73,
0x74, 0x2c, 0x20, 0x66, 0x6c, 0x75, 0x73, 0x68,
0x20, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x70,
0x6f, 0x72, 0x74, 0x20, 0x2a, 0x2f, 0x0a, 0x09,
0x2f, 0x2a, 0x20, 0x54, 0x4f, 0x44, 0x4f, 0x3a,
0x20, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x20,
0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20,
0x61, 0x20, 0x77, 0x61, 0x79, 0x20, 0x18, 0x6b,
0x60, 0x3a, 0x6c, 0xe1,
} ;
static u_char msg2[] = {1} ;
#ifdef COMMENT
#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
#define updcrc(cp, crc) ( crctab[((crc>>8)^cp) & 255] ^ (crc<<8) )
#endif /* COMMENT */
static int addcrc(int data, int crc) ;
main()
{
u_short crc16 ;
u_long crc32 ;
int i,j ;
u_long k ;
u_char *msg = msg0 ;
int len = sizeof(msg0) ;
/* crc16 of message */
crc16 = 0 ;
crc32 = 0xffffffff ;
for(i=0; i<len; ++i)
{
crc16 = addcrc(msg[i], crc16) ;
}
printf("crc16=%4.4hx, ~crc16=%4.4hx\n", crc16, ~crc16&0xffff) ;
crc16 = addcrc(0, crc16) ;
crc16 = addcrc(0, crc16) ;
printf("crc16=%4.4hx, ~crc16=%4.4hx\n", crc16, ~crc16&0xffff) ;
/* crc of reception */
j = crc16 ;
crc16 = 0 ;
crc32 = 0xffffffff ;
for(i=0; i<len; ++i)
{
crc16 = addcrc(msg[i], crc16) ;
}
printf("crc16=%4.4hx, ~crc16=%4.4hx\n", crc16, ~crc16&0xffff) ;
crc16 = addcrc(j>>8, crc16) ;
crc16 = addcrc(j&0xff, crc16) ;
printf("crc16=%4.4hx, ~crc16=%4.4hx\n", crc16, ~crc16&0xffff) ;
#ifdef COMMENT
crc16 = 0 ;
crc32 = 0xffffffff ;
for(i=0; i<len; ++i)
{
crc16 = updcrc(msg[i], crc16) ;
crc32 = UPDC32(msg[i], crc32) ;
printf("%4.4x\n", crc16) ;
}
printf("crc16=%4.4hx, ~crc16=%4.4hx\n", crc16, ~crc16&0xffff) ;
printf("crc32=%8.8x, ~crc=%8.8x\n", crc32,~crc32) ;
#ifdef COMMENT
printf("\n") ;
printf("%2.2x\n", crc16&0xff) ;
printf("%2.2x\n", crc16>>8) ;
#endif /* COMMENT */
i = crc16 ;
crc16 = updcrc(i&0xff, crc16) ;
crc16 = updcrc(i>>8, crc16) ;
k = ~crc32 ;
crc32 = updcrc(k&0xff, crc32) ;
crc32 = updcrc((k>>8)&0xff, crc32) ;
crc32 = updcrc((k>>16)&0xff, crc32) ;
crc32 = updcrc((k>>24)&0xff, crc32) ;
printf("crc16=%4.4hx, ~crc16=%4.4hx\n", crc16, ~crc16&0xffff) ;
printf("crc32=%8.8x, ~crc=%8.8x\n", crc32,~crc32) ;
#endif /* COMMENT */
exit(0) ;
}
static int
addcrc(int data, int crc)
{
int j ;
crc ^= (unsigned short) data<<8;
for(j=0; j<8; ++j) {
if( crc & 0x8000 )
crc = (crc<<1) ^ 0x1021;
else
crc <<= 1 ;
}
return crc & 0xffff ;
}

182
Xmodem/crc.c Normal file
View File

@ -0,0 +1,182 @@
#ifndef lint
static const char rcsid[] = "$Id: crc.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
/*% cc -O -K -dos % -o crc.exe
*/
/*
* Crc - 32 BIT ANSI X3.66 CRC checksum files
*/
#include <stdio.h>
#define OK 0
#define ERROR (-1)
#define LINT_ARGS
/**********************************************************************\
|* *|
|* Demonstration program to compute the 32-bit CRC used as the frame *|
|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *|
|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *|
|* protocol). The 32-bit FCS was added via the Federal Register, *|
|* 1 June 1982, p.23798. I presume but don't know for certain that *|
|* this polynomial is or will be included in CCITT V.41, which *|
|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *|
|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *|
|* errors by a factor of 10^-5 over 16-bit FCS. *|
|* *|
\**********************************************************************/
/* Need an unsigned type capable of holding 32 bits; */
typedef unsigned long int UNS_32_BITS;
/*
* Copyright (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*/
/* First, the polynomial itself and its table of feedback terms. The */
/* polynomial is */
/* 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 */
/* Note that we take it "backwards" and put the highest-order term in */
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
/* the MSB being 1. */
/* Note that the usual hardware shift register implementation, which */
/* is what we're using (we're merely optimizing it by doing eight-bit */
/* chunks at a time) shifts bits into the lowest-order term. In our */
/* implementation, that means shifting towards the right. Why do we */
/* do it this way? Because the calculated CRC must be transmitted in */
/* order from highest-order term to lowest-order term. UARTs transmit */
/* characters in order from LSB to MSB. By storing the CRC this way, */
/* we hand it to the UART in the order low-byte to high-byte; the UART */
/* sends each low-bit to hight-bit; and the result is transmission bit */
/* by bit from highest- to lowest-order term without requiring any bit */
/* shuffling on our part. Reception works similarly. */
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
/* */
/* 1. The table can be generated at runtime if desired; code to do so */
/* is shown later. It might not be obvious, but the feedback */
/* terms simply represent the results of eight shift/xor opera- */
/* tions for all combinations of data and CRC register values. */
/* */
/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
/* be they sixteen or thirty-two bits wide. You simply choose the */
/* appropriate table. Alternatively, because the table can be */
/* generated at runtime, you can start by generating the table for */
/* the polynomial in question and use exactly the same "updcrc", */
/* if your application needn't simultaneously handle two CRC */
/* polynomials. (Note, however, that XMODEM is strange.) */
/* */
/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
/* of course, 32-bit entries work OK if the high 16 bits are zero. */
/* */
/* 4. The values must be right-shifted by eight bits by the "updcrc" */
/* logic; the shift must be unsigned (bring in zeroes). On some */
/* hardware you could probably optimize the shift in assembler by */
/* using byte-swap instructions. */
static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
#define UPDC32(octet, crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
int Block = 0; /* Pad file with 032's to multiple of Block */
main(argc, argv)
char **argv;
{
register errors = 0;
if (! strcmp(argv[1], "-x")) {
Block = 128; --argc; ++argv;
}
if (! strcmp(argv[1], "-k")) {
Block = 1024; --argc; ++argv;
}
while( --argc > 0)
errors |= crc32file( *++argv);
exit(errors != 0);
}
crc32file(name)
char *name;
{
register FILE *fin;
register unsigned long oldcrc32;
register unsigned long crc32;
register unsigned long oldcrc;
register c;
register long charcnt;
register long l;
oldcrc32 = 0xFFFFFFFF; charcnt = 0;
#ifdef M_I86SM
if ((fin=fopen(name, "rb"))==NULL)
#else
if ((fin=fopen(name, "r"))==NULL)
#endif
{
perror(name);
return ERROR;
}
while ((c=getc(fin))!=EOF) {
++charcnt;
oldcrc32 = UPDC32(c, oldcrc32);
}
if (ferror(fin)) {
perror(name);
fclose(fin); return ERROR;
}
else {
if (Block) {
for (l = charcnt; l % Block; ++l)
oldcrc32 = UPDC32(032, oldcrc32);
}
crc32 = oldcrc32; oldcrc = oldcrc32 = ~oldcrc32;
printf("%08lX %7ld ", oldcrc, charcnt);
if (Block == 128)
printf("%5ld+%3ld ", charcnt/Block, charcnt%Block);
if (Block == 1024)
printf("%5ld+%4ld ", charcnt/Block, charcnt%Block);
printf(" %s\n", name);
}
fclose(fin); return OK;
}

154
Xmodem/crctab.c Normal file
View File

@ -0,0 +1,154 @@
#ifndef lint
static const char rcsid[] = "$Id: crctab.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
/*
* Crc calculation stuff
*/
/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
unsigned short crctab[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
/*
* updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
* NOTE: First argument must be in range 0 to 255.
* Second argument is referenced twice.
*
* Programmers may incorporate any or all code into their programs,
* giving proper credit within the source. Publication of the
* source routines is permitted so long as proper credit is given
* to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
* Omen Technology.
*/
#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
/*
* Copyright (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*/
/* First, the polynomial itself and its table of feedback terms. The */
/* polynomial is */
/* 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 */
/* Note that we take it "backwards" and put the highest-order term in */
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
/* the MSB being 1. */
/* Note that the usual hardware shift register implementation, which */
/* is what we're using (we're merely optimizing it by doing eight-bit */
/* chunks at a time) shifts bits into the lowest-order term. In our */
/* implementation, that means shifting towards the right. Why do we */
/* do it this way? Because the calculated CRC must be transmitted in */
/* order from highest-order term to lowest-order term. UARTs transmit */
/* characters in order from LSB to MSB. By storing the CRC this way, */
/* we hand it to the UART in the order low-byte to high-byte; the UART */
/* sends each low-bit to hight-bit; and the result is transmission bit */
/* by bit from highest- to lowest-order term without requiring any bit */
/* shuffling on our part. Reception works similarly. */
/* The feedback terms table consists of 256, 32-bit entries. Notes: */
/* */
/* The table can be generated at runtime if desired; code to do so */
/* is shown later. It might not be obvious, but the feedback */
/* terms simply represent the results of eight shift/xor opera- */
/* tions for all combinations of data and CRC register values. */
/* */
/* The values must be right-shifted by eight bits by the "updcrc" */
/* logic; the shift must be unsigned (bring in zeroes). On some */
/* hardware you could probably optimize the shift in assembler by */
/* using byte-swap instructions. */
unsigned long cr3tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
#ifdef NFGM
long
UPDC32(b, c)
long c;
{
return (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF));
}
#else
#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
#endif
/* End of crctab.c */

13
Xmodem/crctab.h Normal file
View File

@ -0,0 +1,13 @@
/* @(#)crctab.h 1.2 96/09/13 */
/*
* Crc calculation stuff. See crctab.c
*/
extern unsigned short crctab[256] ;
#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
extern unsigned long cr3tab[] ;
#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))

913
Xmodem/main.c Normal file
View File

@ -0,0 +1,913 @@
#ifndef lint
static const char rcsid[] = "$Id: main.c,v 1.1.1.1 2001/03/08 00:01:48 efalk Exp $" ;
#endif
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @ @ @@@ @@@ @ @
* @@ @@ @ @ @ @@ @
* @ @ @ @@@@@ @ @ @ @
* @ @ @ @ @ @ @ @@
* @ @ @ @ @ @@@ @ @
*
* MAIN - demonstration zmodem program
*
* This program implements the x,y,z-modem protocols, using the
* zmodem library.
*
* Edward A. Falk
*
* Jan, 1995
*
*
*
**********/
static char usage [] =
"usage: zmodem -r [options]\n\
zmodem -s [options] file [file ...]\n\
-r receive files\n\
-s send files\n\
- file allows you to transmit files with '-' in their names\n\
-v verbose, more v's increase messages.\n\
-l /dev/ttyX use specified serial port instead of /dev/tty\n\
-b baud set baud rate\n\
-x file use xmodem, specify filename\n\
-y use ymodem\n\
-k use 1k, packets (ymodem, xmodem)\n\
-win nn set sliding window to nn bytes (send)\n\
-buf nn set input buffer size to nn bytes (receive)\n\
-L nn set packet length\n\
-e escape control characters\n\
-a ascii text\n\
-i image (binary data)\n\
-resume continue an interrupted transfer\n\
-new transfer only if newer\n\
-newl transfer only if newer or longer\n\
-diff transfer only if dates or lengths differ\n\
-crc transfer only if length or crc different\n\
-apnd append to existing file\n\
-clob force overwrite of existing files\n\
-prot do not overwrite existing files\n\
-chng change filename if destination exists\n\
-noloc do not transfer unless destination exists\n\
-[hq] this list\n" ;
#include <stdio.h>
/****
*
* Constants, typedefs, externals, globals, statics, macros, block data
*
****/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/termios.h>
#include <sys/param.h>
#include "zmodem.h"
#include "seriallog.h"
extern int errno ;
extern char *getenv() ;
/* compile-time parameters */
#define ESCCTRL 0 /* control characters need to be escaped */
#if !defined(CRTSCTS) && defined(CNEW_RTSCTS)
#define CRTSCTS CNEW_RTSCTS
#endif
static int baud = 0 ; /* requested baud rate */
static char *line = NULL ; /* requested serial line */
static int verbose = 0 ;
static int send = 0 ; /* send files */
static int receive = 0 ; /* receive */
static int xmodem = 0 ; /* use xmodem */
static int ymodem = 0 ; /* use ymodem */
static int escCtrl = ESCCTRL ;
static int ascii = 0 ; /* translate line endings */
static int binary = 0 ; /* don't translate line endings */
static int resume = 0 ; /* resume interrupted transfers */
static int xferType = 0 ; /* new,newl,diff,crc, etc. */
static int noloc = 0 ;
static int doCancel = 0 ;
static int doLogging = 0 ;
static int Corrupt = 0 ; /* deliberately corrupt data */
static int fileErrs ; /* used to track errors per file */
static int fileSent ; /* track amount sent */
static ZModem info ;
static int begun = 0 ;
static struct termios old_settings, new_settings ;
static int FinishXmit(ZModem *info) ;
static int DoReceive(ZModem *info) ;
static int InitXmit(ZModem *info) ;
static int XmitFile(char *filename, int f0, int f1, ZModem *info) ;
static void SendFile() ;
static void RcvFiles() ;
static void RcvXmodem() ;
static int getBaud() ;
static void resetCom() ;
static char *basename(char *name) ;
#ifdef SVr4
static void sighandle(int) ;
#else
static void sighandle() ;
#endif
extern FILE *SerialLogFile ;
extern FILE *zmodemlogfile ;
int
main(int argc, char **argv)
{
char *progname ;
#ifdef COMMENT
printf("%d\n", getpid()) ;
#endif /* COMMENT */
info.ifd = info.ofd = -1 ;
info.zrinitflags = 0 ;
info.zsinitflags = 0 ;
info.attn = NULL ;
info.packetsize = 0 ;
info.windowsize = 0 ;
info.bufsize = 0 ;
progname = basename(argv[0]) ;
if( strcmp(progname,"rz") == 0 )
receive = 1 ;
else if( strcmp(progname, "sz") == 0 )
send = 1 ;
++argv, --argc ; /* skip program name */
/* parse options */
for(; argc > 0 && **argv == '-'; ++argv, --argc )
{
if( strcmp(*argv, "-r") == 0 )
receive = 1 ;
else if( strcmp(*argv, "-s") == 0 )
send = 1 ;
else if( strncmp(*argv, "-v", 2) == 0 )
verbose += strlen(*argv)+1 ;
else if( strcmp(*argv, "-l") == 0 && --argc > 0 )
line = *++argv ;
else if( strcmp(*argv, "-b") == 0 && --argc > 0 )
baud = getBaud(atoi(*++argv)) ;
else if( strcmp(*argv, "-x") == 0 )
xmodem = 1 ;
else if( strcmp(*argv, "-y") == 0 )
ymodem = 1 ;
else if( strcmp(*argv, "-win") == 0 && --argc > 0 )
info.windowsize = atoi(*++argv) ;
else if( strcmp(*argv, "-buf") == 0 && --argc > 0 )
info.bufsize = atoi(*++argv) ;
else if( strcmp(*argv, "-L") == 0 && --argc > 0 )
info.packetsize = atoi(*++argv) ;
else if( strcmp(*argv, "-k") == 0 )
info.packetsize = 1024 ;
else if( strcmp(*argv, "-e") == 0 )
escCtrl = ESCCTL ;
else if( strcmp(*argv, "-a") == 0 )
ascii = 1 ;
else if( strcmp(*argv, "-i") == 0 )
binary = 1 ;
else if( strcmp(*argv, "-resume") == 0 )
resume = 1 ;
else if( strcmp(*argv, "-new") == 0 )
xferType = ZMNEW ;
else if( strcmp(*argv, "-newl") == 0 )
xferType = ZMNEWL ;
else if( strcmp(*argv, "-diff") == 0 )
xferType = ZMDIFF ;
else if( strcmp(*argv, "-crc") == 0 )
xferType = ZMCRC ;
else if( strcmp(*argv, "-apnd") == 0 )
xferType = ZMAPND ;
else if( strcmp(*argv, "-clob") == 0 )
xferType = ZMCLOB ;
else if( strcmp(*argv, "-prot") == 0 )
xferType = ZMPROT ;
else if( strcmp(*argv, "-chng") == 0 )
xferType = ZMCHNG ;
else if( strcmp(*argv, "-noloc") == 0 )
noloc = ZMSKNOLOC ;
else if( strcmp(*argv, "-h") == 0 ||
strcmp(*argv, "-q") == 0 )
{
fprintf(stderr, usage) ;
exit(0) ;
}
else if( strcmp(*argv, "-corrupt") == 0 )
Corrupt = 1 ;
else if( strcmp(*argv, "-log") == 0 )
doLogging = 1 ;
else if( strcmp(*argv, "-") == 0 ) {
++argv, --argc ; break ;
}
else {
fprintf(stderr, "unknown argument '%s' or missing value\n%s",
*argv, usage) ;
exit(2) ;
}
}
if( doLogging ) {
if( (SerialLogFile = fopen("xfer.log", "w")) == NULL )
perror("xfer.log") ;
if( (zmodemlogfile = fopen("zmodem.log","w")) == NULL )
perror("zmodem.log") ;
}
if( send ) {
for(; argc > 0; ++argv, --argc ) /* process filenames */
SendFile(*argv) ;
FinishXmit(&info) ;
}
else if( receive )
{
if( !xmodem )
RcvFiles() ;
else
for(; argc > 0; ++argv, --argc ) /* process filenames */
RcvXmodem(*argv) ;
}
else {
fprintf(stderr,
"either -s (send) or -r (receive) must be specified\n%s", usage) ;
exit(2) ;
}
resetCom() ;
exit(0) ;
}
static void
sighandle(int arg)
{
doCancel = 1 ;
}
static void
openCom()
{
char *ptr ;
if( line == NULL )
line = getenv("RZSZLINE") ;
if( baud == 0 && (ptr = getenv("RZSZBAUD")) != NULL )
baud = getBaud(atoi(ptr)) ;
if( line == NULL ) {
info.ifd = 0 ;
info.ofd = 1 ;
}
else if( (info.ifd = info.ofd = open(line, O_RDWR)) == -1 ) {
fprintf(stderr,
"cannot open %s, %s, use \"zmodem -h\" for more info\n",
line, strerror(errno)) ;
exit(2) ;
}
/* assumption: setting attributes for one half of channel will
* change both halves. This fails if different physical
* devices are used.
*/
tcgetattr(info.ifd,&old_settings) ;
new_settings = old_settings ;
#ifdef IUCLC
new_settings.c_iflag &=
~(ISTRIP|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXOFF|IMAXBEL) ;
#else
new_settings.c_iflag &=
~(ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IMAXBEL) ;
#endif
new_settings.c_oflag &= ~OPOST ;
new_settings.c_cflag &= ~(CSIZE|PARENB) ;
new_settings.c_cflag |= CS8 ;
if( baud != 0 ) {
cfsetospeed(&new_settings, baud) ;
cfsetispeed(&new_settings, baud) ;
}
else
baud = cfgetospeed(&old_settings) ;
new_settings.c_lflag = 0 ;
new_settings.c_cc[VMIN] = 32 ;
new_settings.c_cc[VTIME] = 1 ;
tcsetattr(info.ifd,TCSADRAIN, &new_settings) ;
info.zrinitflags = CANFDX|CANOVIO|CANBRK|CANFC32|escCtrl ;
info.zsinitflags = escCtrl ;
if( info.packetsize == 0 ) {
if( xmodem || ymodem )
info.packetsize = 128 ;
/* TODO: what about future high-speed interfaces? */
else if( baud < B2400 )
info.packetsize = 256 ;
else if( baud == B2400 )
info.packetsize = 512 ;
else
info.packetsize = 1024 ;
}
}
static void
resetCom()
{
tcsetattr(info.ifd,TCSADRAIN, &old_settings) ;
}
static void
SendFile(char *filename)
{
int f0, f1 ;
fileErrs = 0 ;
if( !begun ) /* establish connection */
{
openCom() ;
signal(SIGINT, sighandle) ;
signal(SIGTERM, sighandle) ;
signal(SIGHUP, sighandle) ;
if( InitXmit(&info) ) {
fprintf(stderr, "connect failed\n") ;
resetCom() ;
exit(1) ;
}
begun = 1 ;
}
if( ascii )
f0 = ZCNL ;
else if( binary )
f0 = ZCBIN ;
else if( resume )
f0 = ZCRESUM ;
else
f0 = 0 ;
f1 = xferType | noloc ;
if( XmitFile(filename, f0,f1, &info) ) {
fprintf(stderr, "connect failed\n") ;
resetCom() ;
exit(1) ;
}
}
static void
RcvFiles()
{
openCom() ;
signal(SIGINT, sighandle) ;
signal(SIGTERM, sighandle) ;
if( DoReceive(&info) ) {
fprintf(stderr, "connect failed\n") ;
resetCom() ;
exit(1) ;
}
}
static void
RcvXmodem(char *filename)
{
/* TODO: */
}
static int
getBaud(int b)
{
switch(b) {
case 50: return B50 ;
case 75: return B75 ;
case 110: return B110 ;
case 134: return B134 ;
case 150: return B150 ;
case 200: return B200 ;
case 300: return B300 ;
case 600: return B600 ;
case 1200: return B1200 ;
case 1800: return B1800 ;
case 2400: return B2400 ;
case 4800: return B4800 ;
case 9600: return B9600 ;
case 19200: return B19200 ;
case 38400: return B38400 ;
default: return 0 ;
}
}
/* TEST: randomly corrupt every 1000th byte */
static void
corrupt(u_char *buffer, int len)
{
extern double drand48() ;
while( --len >= 0 ) {
if( drand48() < 1./1000. )
*buffer ^= 0x81 ;
++buffer ;
}
}
static int
doIO(ZModem *info)
{
fd_set readfds ;
struct timeval timeout ;
int i ;
int len ;
u_char buffer[1024] ;
int done = 0 ;
while(!done)
{
FD_ZERO(&readfds) ;
FD_SET(info->ifd, &readfds) ;
timeout.tv_sec = info->timeout ;
timeout.tv_usec = 0 ;
i = select(info->ifd+1, &readfds,NULL,NULL, &timeout) ;
if( doCancel ) {
ZmodemAbort(info) ;
fprintf(stderr, "cancelled by user\n") ;
resetCom() ;
exit(3) ;
}
if( i<0 )
perror("select") ;
else if( i==0 )
done = ZmodemTimeout(info) ;
else {
len = read(info->ifd, buffer, sizeof(buffer)) ;
if( Corrupt )
corrupt(buffer, len) ;
if( SerialLogFile != NULL )
SerialLog(buffer, len, 1) ;
done = ZmodemRcv(buffer, len, info) ;
}
}
if( SerialLogFile != NULL )
SerialLogFlush() ;
return done ;
}
static int
InitXmit(ZModem *info)
{
int done ;
if( xmodem )
done = XmodemTInit(info) ;
else if( ymodem )
done = YmodemTInit(info) ;
else
done = ZmodemTInit(info) ;
if( !done )
done = doIO(info) ;
return done != ZmDone ;
}
static int
XmitFile(char *filename, int f0, int f1, ZModem *info)
{
int done ;
done = ZmodemTFile(filename,filename, f0,f1,0,0,
0,0, info) ;
switch( done ) {
case 0:
if( verbose )
fprintf(stderr, "Sending: \"%s\"\n", filename) ;
break ;
case ZmErrCantOpen:
fprintf(stderr, "cannot open file \"%s\": %s\n",
filename, strerror(errno)) ;
return 0 ;
case ZmFileTooLong:
fprintf(stderr, "filename \"%s\" too long, skipping...\n",
filename) ;
return 0 ;
case ZmDone:
return 0 ;
default:
return 1 ;
}
if( !done )
done = doIO(info) ;
return done != ZmDone ;
}
static int
FinishXmit(ZModem *info)
{
int done ;
done = ZmodemTFinish(info) ;
if( !done )
done = doIO(info) ;
return done != ZmDone ;
}
static int
DoReceive(ZModem *info)
{
int done ;
if( ymodem )
done = YmodemRInit(info) ;
else
done = ZmodemRInit(info) ;
if( !done )
done = doIO(info) ;
return done != ZmDone ;
}
int
ZXmitStr(u_char *buffer, int len, ZModem *info)
{
u_char b2[1024] ;
/* TEST: randomly corrupt every 1000th byte */
if( Corrupt )
{
bcopy(buffer, b2, len) ;
corrupt(b2, len) ;
buffer = b2 ;
}
if( SerialLogFile != NULL )
SerialLog(buffer, len, 0) ;
if( write(info->ofd, buffer, len) != len )
return ZmErrSys ;
return 0 ;
}
void
ZIFlush(ZModem *info)
{
if( SerialLogFile != NULL )
SerialLogFlush() ;
if( tcflush(info->ifd, TCIFLUSH) != 0 )
perror("TCIFLUSH") ;
}
void
ZOFlush(ZModem *info)
{
if( SerialLogFile != NULL )
SerialLogFlush() ;
if( tcflush(info->ifd, TCOFLUSH) != 0 )
perror("TCOFLUSH") ;
}
void
ZStatus(int type, int j, char *str)
{
switch( type ) {
case RcvByteCount:
if( verbose >= 2 )
fprintf(stderr, "received: %6d bytes\n", j) ;
break ;
case SndByteCount:
fileSent = j ;
if( verbose >= 2 )
fprintf(stderr, "sent: %6d bytes\n", j) ;
break ;
case RcvTimeout:
if( verbose )
fprintf(stderr, "receiver timeouts: %2d\n", j) ;
break ;
case SndTimeout:
if( verbose )
fprintf(stderr, "sender timeouts: %2d\n", j) ;
break ;
case RmtCancel:
fprintf(stderr, "transfer cancelled by remote\n") ;
break ;
case ProtocolErr:
if( verbose >= 3 )
fprintf(stderr, "protocol error: %2.2d\n", j) ;
break ;
case RemoteMessage:
fprintf(stderr, "remote message: %s\n",str) ;
break ;
case DataErr:
if( verbose >= 3 )
fprintf(stderr, "data errors: %2d\n", j) ;
#ifdef COMMENT
if( ++fileErrs > 20 )
{
/* something's wrong */
ZmodemAbort(&info) ;
}
#endif /* COMMENT */
break ;
case FileErr:
fprintf(stderr, "cannot write file: %s\n", strerror(errno)) ;
break ;
}
}
int
ZAttn(ZModem *info)
{
char *ptr ;
if( info->attn == NULL )
return 0 ;
for(ptr = info->attn; *ptr != '\0'; ++ptr) {
if( *ptr == ATTNBRK )
tcsendbreak(info->ifd, 0) ;
else if( *ptr == ATTNPSE )
sleep(1) ;
else
write(info->ifd, ptr, 1) ;
}
return 0 ;
}
FILE *
ZOpenFile(char *name, u_long crc, ZModem *info)
{
struct stat buf ;
int exists ; /* file already exists */
static int changeCount = 0 ;
char name2[MAXPATHLEN] ;
int apnd = 0 ;
int f0,f1 ;
FILE *rval ;
/* TODO: if absolute path, do we want to allow it?
* if relative path, do we want to prepend something?
*/
if( *name == '/' ) /* for now, disallow absolute paths */
return NULL ;
if( stat(name, &buf) == 0 )
exists = 1 ;
else if( errno == ENOENT )
exists = 0 ;
else
return NULL ;
/* if remote end has not specified transfer flags, we can
* accept the local definitions
*/
if( (f0=info->f0) == 0 ) {
if( ascii )
f0 = ZCNL ;
else if( binary )
f0 = ZCBIN ;
else if( resume )
f0 = ZCRESUM ;
else
f0 = 0 ;
}
if( (f1=info->f1) == 0 )
f1 = xferType | noloc ;
if( f0 == ZCRESUM ) { /* if exists, and we already have it, return */
if( exists && buf.st_size == info->len )
return NULL ;
apnd = 1 ;
}
/* reject if file not found and it most be there (ZMSKNOLOC) */
if( !exists && (f1 & ZMSKNOLOC) )
return NULL ;
switch( f1 & ZMMASK ) {
case 0: /* Implementation-dependent. In this case, we
* reject if file exists (and ZMSKNOLOC not set) */
if( exists && !(f1 & ZMSKNOLOC) ) {
fprintf(stderr, "%s already exists\n", name) ;
return NULL ;
}
break ;
case ZMNEWL: /* take if newer or longer than file on disk */
if( exists && info->date <= buf.st_mtime &&
info->len <= buf.st_size ) {
fprintf(stderr, "%s already exists\n", name) ;
return NULL ;
}
break ;
case ZMCRC: /* take if different CRC or length */
if( exists && info->len == buf.st_size && crc == FileCrc(name) )
{
fprintf(stderr, "%s already exists\n", name) ;
return NULL ;
}
break ;
case ZMAPND: /* append */
apnd = 1 ;
case ZMCLOB: /* unconditional replace */
break ;
case ZMNEW: /* take if newer than file on disk */
if( exists && info->date <= buf.st_mtime ) {
fprintf(stderr, "%s already exists and is newer\n", name) ;
return NULL ;
}
break ;
case ZMDIFF: /* take if different date or length */
if( exists && info->date == buf.st_mtime &&
info->len == buf.st_size )
{
fprintf(stderr, "%s already exists\n", name) ;
return NULL ;
}
break ;
case ZMPROT: /* only if dest does not exist */
if( exists )
{
fprintf(stderr, "%s already exists\n", name) ;
return NULL ;
}
break ;
case ZMCHNG: /* invent new filename if exists */
if( exists ) {
while( exists ) {
sprintf(name2, "%s_%d", name, changeCount++) ;
exists = stat(name2, &buf) == 0 || errno != ENOENT ;
}
name = name2 ;
}
break ;
}
/* here if we've decided to accept */
#ifdef COMMENT
if( exists && !apnd && unlink(name) != 0 )
return NULL ;
#endif /* COMMENT */
/* TODO: build directory path if needed */
if( verbose )
fprintf(stderr, "Receiving: \"%s\"\n", name) ;
rval = fopen(name, apnd ? "a" : "w") ;
if( rval == NULL )
perror(name) ;
return rval ;
}
int
ZWriteFile(u_char *buffer, int len, FILE *file, ZModem *info)
{
/* TODO: if ZCNL set in info->f0, convert
* newlines to local convention
*/
return fwrite(buffer, 1, len, file) == len ? 0 : ZmErrSys ;
}
int
ZCloseFile(ZModem *info)
{
struct timeval tvp[2] ;
fclose(info->file) ;
if( ymodem )
truncate(info->filename, info->len) ;
if( info->date != 0 ) {
tvp[0].tv_sec = tvp[1].tv_sec = info->date ;
tvp[0].tv_usec = tvp[1].tv_usec = 0 ;
utimes(info->filename, tvp) ;
}
if( info->mode & 01000000 )
chmod(info->filename, info->mode&0777) ;
return 0 ;
}
void
ZIdleStr(u_char *buffer, int len, ZModem *info)
{
#ifdef COMMENT
fwrite(buffer, 1,len, stdout) ;
#endif /* COMMENT */
}
void
ZFlowControl(int onoff, ZModem *info)
{
if( onoff ) {
new_settings.c_iflag |= IXON|IXANY|IXOFF ;
#ifdef COMMENT
new_settings.c_cflag |= CRTSCTS ;
#endif /* COMMENT */
}
else {
new_settings.c_iflag &= ~(IXON|IXANY|IXOFF) ;
new_settings.c_cflag &= ~CRTSCTS ;
}
tcsetattr(info->ifd,TCSADRAIN, &new_settings) ;
}
static char *
basename(char *name)
{
char *ptr ;
if( (ptr = strrchr(name, '/')) == NULL )
return name ;
else
return ++ptr ;
}

155
Xmodem/network.c Normal file
View File

@ -0,0 +1,155 @@
#ifndef lint
static const char rcsid[] = "$Id: network.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @ @ @@@@@ @@@@@ @ @ @@@ @@@@ @ @
* @@ @ @ @ @ @ @ @ @ @ @ @
* @ @ @ @@@ @ @ @ @ @ @ @@@@ @@@
* @ @@ @ @ @ @ @ @ @ @ @ @ @
* @ @ @@@@@ @ @ @ @@@ @ @ @ @
*
* NETWORK - Make network connection
*
* Routines provided here:
*
*
* void
* IpConnect()
* Make IP connection according to parameters in gcomm.h
*
* void
* IpDisConnect()
* Close IP connection.
*
*
*
* Edward A. Falk
*
* January, 1995
*
*
*
**********/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <varargs.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#ifdef COMMENT
#include <sys/ttold.h>
#include <sys/termio.h>
#endif /* COMMENT */
#include <termio.h>
#include <sys/stat.h>
#include <netdb.h> /* stuff used by tcp/ip */
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include "gcomm.h"
extern int errno ;
#ifdef COMMENT
extern char *sys_errlist[] ;
#endif /* COMMENT */
void
IpConnect()
{
int sockfd ;
int i,j ;
struct hostent *hostent ;
struct sockaddr_in sockaddr ;
int port ;
WindowStatus("Connecting...") ;
port = PortLookup(hostPort) ;
if( port == -1 )
return ;
bzero(&sockaddr, sizeof(sockaddr)) ;
sockaddr.sin_family = AF_INET ;
sockaddr.sin_port = htons(port) ;
hostent = gethostbyname(hostId) ;
if( hostent != NULL )
{
sockaddr.sin_addr = *(struct in_addr *) hostent->h_addr ;
}
else if( isdigit(hostId[0]) )
{
i = sscanf(hostId, "%d.%d.%d.%d",
&sockaddr.sin_addr.S_un.S_un_b.s_b1,
&sockaddr.sin_addr.S_un.S_un_b.s_b2,
&sockaddr.sin_addr.S_un.S_un_b.s_b3,
&sockaddr.sin_addr.S_un.S_un_b.s_b4) ;
if( i != 4 ) {
WindowStatus("Host address must be in dd.dd.dd.dd format") ;
return ;
}
}
else {
WindowStatus("Hostname not found") ;
return ;
}
sockfd = socket(AF_INET, SOCK_STREAM, 0) ;
if( sockfd < 0 ) {
WindowStatus("Cannot open socket: %s", sys_errlist[errno]) ;
return ;
}
i = connect(sockfd, &sockaddr, sizeof(sockaddr)) ;
if( i < 0 ) {
WindowStatus("Cannot connect to host: %s", sys_errlist[errno]) ;
close(sockfd) ;
return ;
}
ifd = ofd = sockfd ;
i = fcntl(ifd, F_GETFL, 0) ;
j = fcntl(ifd, F_SETFL, i|O_NDELAY) ;
connectionActive = 1 ;
connectTime0 = time(NULL) ;
WindowStatus("Connected") ;
}
void
IpDisConnect()
{
if( ifd == -1 )
return ;
close(ifd) ;
ifd = ofd = -1 ;
connectionActive = 0 ;
}

600
Xmodem/receive.c Normal file
View File

@ -0,0 +1,600 @@
#ifndef lint
static const char rcsid[] = "$Id: receive.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
#define TEST /* standalone test */
#include <unistd.h>
#include <string.h>
#include "zmodem.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/termios.h>
#include <sys/termio.h> /* define TCSBRK */
#include <sys/param.h>
extern int errno ;
static u_char zeros[4] = {0,0,0,0} ;
main(argc,argv)
int argc ;
char **argv ;
{
struct termios old_settings, new_settings ;
fd_set readfds ;
struct timeval timeout ;
int i ;
int len ;
char buffer[1024] ;
int done = 0 ;
int filecount = 0 ;
ZModem info ;
#ifdef TEST
static u_char Amsg0[] = {
0x72, 0x7a, 0x0d, 0x2a, 0x2a, 0x18, 0x42, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x11,
} ;
static u_char Amsg1[] = {
0x2a, 0x18, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00,
0x7d, 0xa4, 0xe2, 0xbc, 0x00, 0x18, 0x6b, 0x2f,
0xaa, 0xb9, 0x9b, 0x2a, 0x18, 0x43, 0x02, 0x00,
0x00, 0x00, 0x00, 0x7d, 0xa4, 0xe2, 0xbc,
} ;
static u_char Amsg2[] = {
0x00, 0x18, 0x6b, 0x2f, 0xaa, 0xb9, 0x9b, 0x2a,
0x18, 0x43, 0x04, 0x00, 0x00, 0x04, 0x00, 0xd9,
0x94, 0xce, 0x57,
} ;
static u_char Amsg3[] = {
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x2e,
0x63, 0x00, 0x31, 0x36, 0x39, 0x38, 0x36, 0x20,
0x35, 0x37, 0x30, 0x30, 0x36, 0x36, 0x37, 0x36,
0x37, 0x30, 0x20, 0x31, 0x30, 0x30, 0x36, 0x36,
0x34, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20,
0x30, 0x00, 0x18, 0x6b, 0x57, 0xed, 0x76, 0xb6,
} ;
static u_char Amsg4[] = {
0x2a, 0x18, 0x43, 0x0a, 0x00, 0x00, 0x00, 0x00,
0xbc, 0xef, 0x92, 0x8c, 0x0a, 0x23, 0x64, 0x65,
0x66, 0x69, 0x6e, 0x65, 0x09, 0x54, 0x45, 0x53,
0x54, 0x09, 0x2f, 0x2a, 0x20, 0x73, 0x74, 0x61,
0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x20,
0x74, 0x65, 0x73, 0x74, 0x20, 0x2a, 0x2f, 0x0a,
0x0a, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x20, 0x3c, 0x75, 0x6e, 0x69, 0x73, 0x74,
0x64, 0x2e, 0x68, 0x3e, 0x0a, 0x23, 0x69, 0x6e,
0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73,
0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x68, 0x3e,
0x0a, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x20, 0x22, 0x7a, 0x6d, 0x6f, 0x64, 0x65,
0x6d, 0x2e, 0x68, 0x22, 0x0a, 0x23, 0x69, 0x6e,
0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73,
0x79, 0x73, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x2e,
0x68, 0x3e, 0x0a, 0x0a, 0x23, 0x69, 0x6e, 0x63,
0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x66, 0x63,
0x6e, 0x74, 0x6c, 0x2e, 0x68, 0x3e, 0x0a, 0x23,
0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20,
0x3c, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x2e, 0x68,
0x3e, 0x0a, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75,
0x64, 0x65, 0x20, 0x3c, 0x73, 0x79, 0x73, 0x2f,
0x74, 0x69, 0x6d, 0x65, 0x2e, 0x68, 0x3e, 0x0a,
0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65,
0x20, 0x3c, 0x73, 0x79, 0x73, 0x2f, 0x74, 0x65,
0x72, 0x6d, 0x69, 0x6f, 0x73, 0x2e, 0x68, 0x3e,
0x0a, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x20, 0x3c, 0x73, 0x79, 0x73, 0x2f, 0x74,
0x65, 0x72, 0x6d, 0x69, 0x6f, 0x2e, 0x68, 0x3e,
0x09, 0x09, 0x2f, 0x2a, 0x20, 0x64, 0x65, 0x66,
0x69, 0x6e, 0x65, 0x20, 0x54, 0x43, 0x53, 0x42,
0x52, 0x4b, 0x20, 0x2a, 0x2f, 0x0a, 0x23, 0x69,
0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c,
0x73, 0x79, 0x73, 0x2f, 0x70, 0x61, 0x72, 0x61,
0x6d, 0x2e, 0x68, 0x3e, 0x0a, 0x0a, 0x65, 0x78,
0x74, 0x65, 0x72, 0x6e, 0x09, 0x69, 0x6e, 0x74,
0x09, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x20, 0x3b,
0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63,
0x09, 0x75, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x09,
0x7a, 0x65, 0x72, 0x6f, 0x73, 0x5b, 0x34, 0x5d,
0x20, 0x3d, 0x20, 0x7b, 0x30, 0x2c, 0x30, 0x2c,
0x30, 0x2c, 0x30, 0x7d, 0x20, 0x3b, 0x0a, 0x0a,
0x6d, 0x61, 0x69, 0x6e, 0x28, 0x61, 0x72, 0x67,
0x63, 0x2c, 0x61, 0x72, 0x67, 0x76, 0x29, 0x0a,
0x09, 0x69, 0x6e, 0x74, 0x09, 0x61, 0x72, 0x67,
0x63, 0x20, 0x3b, 0x0a, 0x09, 0x63, 0x68, 0x61,
0x72, 0x09, 0x2a, 0x2a, 0x61, 0x72, 0x67, 0x76,
0x20, 0x3b, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74,
0x72, 0x75, 0x63, 0x74, 0x09, 0x74, 0x65, 0x72,
0x6d, 0x69, 0x6f, 0x73, 0x09, 0x6f, 0x6c, 0x64,
0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x5f, 0x73,
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20,
0x3b, 0x0a, 0x09, 0x66, 0x64, 0x5f, 0x73, 0x65,
0x74, 0x09, 0x72, 0x65, 0x61, 0x64, 0x66, 0x64,
0x73, 0x20, 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x72,
0x75, 0x63, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65,
0x76, 0x61, 0x6c, 0x20, 0x74, 0x69, 0x6d, 0x65,
0x6f, 0x75, 0x74, 0x20, 0x3b, 0x0a, 0x09, 0x69,
0x6e, 0x74, 0x09, 0x69, 0x20, 0x3b, 0x0a, 0x09,
0x69, 0x6e, 0x74, 0x09, 0x6c, 0x65, 0x6e, 0x20,
0x3b, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x72, 0x09,
0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5b, 0x31,
0x30, 0x32, 0x34, 0x5d, 0x20, 0x3b, 0x0a, 0x09,
0x69, 0x6e, 0x74, 0x09, 0x64, 0x6f, 0x6e, 0x65,
0x20, 0x3d, 0x20, 0x30, 0x20, 0x3b, 0x0a, 0x09,
0x69, 0x6e, 0x74, 0x09, 0x66, 0x69, 0x6c, 0x65,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x3d, 0x20,
0x30, 0x20, 0x3b, 0x0a, 0x09, 0x5a, 0x4d, 0x6f,
0x64, 0x65, 0x6d, 0x09, 0x69, 0x6e, 0x66, 0x6f,
0x20, 0x3b, 0x0a, 0x0a, 0x23, 0x69, 0x66, 0x64,
0x65, 0x66, 0x09, 0x54, 0x45, 0x53, 0x54, 0x0a,
0x0a, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x09,
0x75, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x09, 0x41,
0x6d, 0x73, 0x67, 0x30, 0x5b, 0x5d, 0x20, 0x3d,
0x20, 0x7b, 0x0a, 0x09, 0x20, 0x20, 0x30, 0x78,
0x37, 0x32, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x61,
0x2c, 0x20, 0x30, 0x78, 0x30, 0x64, 0x2c, 0x20,
0x30, 0x78, 0x32, 0x61, 0x2c, 0x20, 0x30, 0x78,
0x32, 0x61, 0x2c, 0x20, 0x30, 0x78, 0x31, 0x38,
0x2c, 0x20, 0x30, 0x78, 0x34, 0x32, 0x2c, 0x20,
0x30, 0x78, 0x33, 0x30, 0x2c, 0x20, 0x0a, 0x09,
0x20, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x33, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x30,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x33, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x30,
0x2c, 0x20, 0x0a, 0x09, 0x20, 0x20, 0x30, 0x78,
0x33, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x30,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x33, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x64,
0x2c, 0x20, 0x30, 0x78, 0x30, 0x61, 0x2c, 0x20,
0x30, 0x78, 0x31, 0x31, 0x2c, 0x20, 0x0a, 0x09,
0x7d, 0x20, 0x3b, 0x0a, 0x73, 0x74, 0x61, 0x74,
0x69, 0x63, 0x09, 0x75, 0x5f, 0x63, 0x68, 0x61,
0x72, 0x09, 0x41, 0x6d, 0x73, 0x67, 0x31, 0x5b,
0x5d, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x20,
0x20, 0x30, 0x78, 0x32, 0x61, 0x2c, 0x20, 0x30,
0x78, 0x31, 0x38, 0x2c, 0x20, 0x30, 0x78, 0x34,
0x33, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x34, 0x2c,
0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30,
0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30,
0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c,
0x20, 0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x64,
0x64, 0x2c, 0x20, 0x30, 0x78, 0x35, 0x31, 0x2c,
0x20, 0x30, 0x78, 0x61, 0x32, 0x2c, 0x20, 0x30,
0x78, 0x33, 0x33, 0x2c, 0x20, 0x30, 0x78, 0x37,
0x35, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x34, 0x2c,
0x20, 0x30, 0x78, 0x36, 0x39, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x63, 0x2c, 0x20, 0x0a, 0x09, 0x20,
0x20, 0x30, 0x78, 0x37, 0x33, 0x2c, 0x20, 0x30,
0x78, 0x32, 0x65, 0x2c, 0x20, 0x30, 0x78, 0x36,
0x33, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c,
0x20, 0x30, 0x78, 0x33, 0x31, 0x2c, 0x20, 0x30,
0x78, 0x33, 0x31, 0x2c, 0x20, 0x30, 0x78, 0x33,
0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x37, 0x2c,
0x20, 0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x32,
0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x35, 0x2c,
0x20, 0x30, 0x78, 0x33, 0x37, 0x2c, 0x20, 0x30,
0x78, 0x33, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33,
0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c,
0x20, 0x30, 0x78, 0x33, 0x35, 0x2c, 0x20, 0x30,
0x78, 0x33, 0x36, 0x2c, 0x20, 0x0a, 0x09, 0x20,
0x20, 0x30, 0x78, 0x33, 0x31, 0x2c, 0x20, 0x30,
0x78, 0x33, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33,
0x34, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x30, 0x2c,
0x20, 0x30, 0x78, 0x33, 0x18, 0x6a, 0xf8, 0x0e,
0xd1, 0x2f, 0x31, 0x2c, 0x20, 0x30, 0x78, 0x33,
0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c,
0x20, 0x30, 0x78, 0x33, 0x36, 0x2c, 0x20, 0x0a,
0x09, 0x20, 0x20, 0x30, 0x78, 0x33, 0x36, 0x2c,
0x20, 0x30, 0x78, 0x33, 0x34, 0x2c, 0x20, 0x30,
0x78, 0x32, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33,
0x30, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x30, 0x2c,
0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20, 0x30,
0x78, 0x32, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33,
0x30, 0x2c, 0x20, 0x0a, 0x09, 0x20, 0x20, 0x30,
0x78, 0x32, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33,
0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c,
0x20, 0x30, 0x78, 0x31, 0x38, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x62, 0x2c, 0x20, 0x30, 0x78, 0x63,
0x63, 0x2c, 0x20, 0x30, 0x78, 0x38, 0x38, 0x2c,
0x20, 0x30, 0x78, 0x38, 0x36, 0x2c, 0x20, 0x0a,
0x09, 0x20, 0x20, 0x30, 0x78, 0x31, 0x61, 0x2c,
0x20, 0x0a, 0x09, 0x7d, 0x20, 0x3b, 0x0a, 0x73,
0x74, 0x61, 0x74, 0x69, 0x63, 0x09, 0x75, 0x5f,
0x63, 0x68, 0x61, 0x72, 0x09, 0x41, 0x6d, 0x73,
0x67, 0x32, 0x5b, 0x5d, 0x20, 0x3d, 0x20, 0x7b,
0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x32, 0x61,
0x2c, 0x20, 0x30, 0x78, 0x31, 0x38, 0x2c, 0x20,
0x30, 0x78, 0x34, 0x33, 0x2c, 0x20, 0x30, 0x78,
0x30, 0x34, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30,
0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x30, 0x30, 0x2c, 0x20, 0x0a, 0x09, 0x20, 0x20,
0x30, 0x78, 0x64, 0x64, 0x2c, 0x20, 0x30, 0x78,
0x35, 0x31, 0x2c, 0x20, 0x30, 0x78, 0x61, 0x32,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x33, 0x2c, 0x20,
0x30, 0x78, 0x37, 0x35, 0x2c, 0x20, 0x30, 0x78,
0x37, 0x34, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x39,
0x2c, 0x20, 0x30, 0x78, 0x36, 0x63, 0x2c, 0x20,
0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x37, 0x33,
0x2c, 0x20, 0x30, 0x78, 0x32, 0x65, 0x2c, 0x20,
0x30, 0x78, 0x36, 0x33, 0x2c, 0x20, 0x30, 0x78,
0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x31,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x31, 0x2c, 0x20,
0x30, 0x78, 0x33, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x37, 0x2c, 0x20, 0x0a, 0x09, 0x20, 0x20,
0x30, 0x78, 0x32, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x35, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x37,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x33, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x35,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x36, 0x2c, 0x20,
0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x33, 0x31,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x33, 0x34, 0x2c, 0x20, 0x30, 0x78,
0x32, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33, 0x31,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x33, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x36, 0x2c, 0x20, 0x0a, 0x09, 0x20, 0x20,
0x30, 0x78, 0x33, 0x36, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x34, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x30,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x32, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x33, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x30,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x32, 0x30,
0x2c, 0x20, 0x30, 0x78, 0x33, 0x30, 0x2c, 0x20,
0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78,
0x31, 0x38, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x62,
0x2c, 0x20, 0x30, 0x78, 0x63, 0x63, 0x2c, 0x20,
0x30, 0x78, 0x38, 0x38, 0x2c, 0x20, 0x30, 0x78,
0x38, 0x36, 0x2c, 0x20, 0x0a, 0x09, 0x20, 0x20,
0x30, 0x78, 0x31, 0x61, 0x2c, 0x20, 0x0a, 0x09,
0x7d, 0x20, 0x3b, 0x0a, 0x73, 0x74, 0x61, 0x74,
0x69, 0x63, 0x09, 0x75, 0x5f, 0x63, 0x68, 0x61,
0x72, 0x09, 0x41, 0x6d, 0x73, 0x67, 0x33, 0x5b,
0x5d, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x20,
0x20, 0x30, 0x78, 0x32, 0x61, 0x2c, 0x20, 0x30,
0x78, 0x31, 0x38, 0x2c, 0x20, 0x30, 0x78, 0x34,
0x33, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x61, 0x2c,
0x20, 0x30, 0x78, 0x30, 0x30, 0x2c, 0x20, 0x30,
0x78, 0x30, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x30,
0x30, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x30, 0x2c,
0x20, 0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x62,
0x63, 0x2c, 0x20, 0x30, 0x78, 0x65, 0x66, 0x2c,
0x20, 0x30, 0x78, 0x39, 0x32, 0x2c, 0x20, 0x30,
0x78, 0x38, 0x63, 0x2c, 0x20, 0x30, 0x78, 0x30,
0x61, 0x2c, 0x20, 0x30, 0x78, 0x32, 0x33, 0x2c,
0x20, 0x30, 0x78, 0x36, 0x39, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x65, 0x2c, 0x20, 0x0a, 0x09, 0x20,
0x20, 0x30, 0x78, 0x36, 0x33, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x63, 0x2c, 0x20, 0x30, 0x78, 0x37,
0x35, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x34, 0x2c,
0x20, 0x30, 0x78, 0x36, 0x35, 0x2c, 0x20, 0x30,
0x78, 0x32, 0x30, 0x2c, 0x20, 0x30, 0x78, 0x33,
0x63, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x33, 0x2c,
0x20, 0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x37,
0x39, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x33, 0x2c,
0x20, 0x30, 0x78, 0x32, 0x66, 0x2c, 0x20, 0x30,
0x78, 0x37, 0x34, 0x2c, 0x20, 0x30, 0x78, 0x36,
0x35, 0x2c, 0x20, 0x30, 0x78, 0x37, 0x32, 0x2c,
0x20, 0x30, 0x78, 0x36, 0x64, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x39, 0x2c, 0x20, 0x0a, 0x09, 0x20,
0x20, 0x30, 0x78, 0x36, 0x66, 0x2c, 0x20, 0x30,
0x78, 0x37, 0x33, 0x2c, 0x20, 0x30, 0x78, 0x32,
0x65, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x38, 0x2c,
0x20, 0x30, 0x78, 0x33, 0x65, 0x2c, 0x20, 0x30,
0x78, 0x30, 0x61, 0x2c, 0x20, 0x30, 0x78, 0x32,
0x33, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x39, 0x2c,
0x20, 0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x36,
0x65, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x33, 0x2c,
0x20, 0x30, 0x78, 0x36, 0x63, 0x2c, 0x20, 0x30,
0x78, 0x37, 0x35, 0x2c, 0x20, 0x30, 0x78, 0x36,
0x34, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x35, 0x2c,
0x20, 0x30, 0x78, 0x32, 0x30, 0x2c, 0x20, 0x30,
0x78, 0x32, 0x32, 0x2c, 0x20, 0x0a, 0x09, 0x20,
0x20, 0x30, 0x78, 0x37, 0x38, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x64, 0x2c, 0x20, 0x30, 0x78, 0x36,
0x66, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x34, 0x2c,
0x20, 0x30, 0x78, 0x36, 0x35, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x64, 0x2c, 0x20, 0x30, 0x78, 0x32,
0x65, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x38, 0x2c,
0x20, 0x0a, 0x09, 0x20, 0x20, 0x30, 0x78, 0x32,
0x32, 0x2c, 0x20, 0x30, 0x78, 0x30, 0x61, 0x2c,
0x20, 0x30, 0x78, 0x30, 0x61, 0x2c, 0x20, 0x30,
0x78, 0x30, 0x61, 0x2c, 0x20, 0x30, 0x78, 0x36,
0x39, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x65, 0x2c,
0x20, 0x30, 0x78, 0x37, 0x34, 0x2c, 0x20, 0x30,
0x78, 0x30, 0x61, 0x2c, 0x20, 0x0a, 0x09, 0x20,
0x20, 0x30, 0x78, 0x37, 0x33, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x35, 0x2c, 0x20, 0x30, 0x78, 0x36,
0x65, 0x2c, 0x20, 0x30, 0x78, 0x36, 0x34, 0x2c,
0x20, 0x30, 0x78, 0x34, 0x33, 0x2c, 0x20, 0x30,
0x78, 0x36, 0x18, 0x6a, 0x4a, 0xe5, 0x72, 0x71,
} ;
#define E(b) {b, sizeof(b)}
static struct {u_char *am; int len} Amsgs[] = {
E(Amsg0),
E(Amsg1),
E(Amsg2),
E(Amsg3),
E(Amsg4),} ;
#endif /* TEST */
/* try to trap uninit. variables */
memset(&info,0xa5,sizeof(info)) ;
info.zrinitflags = CANFDX|CANOVIO|CANBRK|CANFC32 ;
info.packetsize = 128 ;
info.bufsize = 0 ;
#ifdef TEST
done = ZmodemRInit(&info) ;
for(i=0; !done; ++i )
done = ZmodemRcv(Amsgs[i].am, Amsgs[i].len, &info) ;
#else
if( argc < 2 )
exit(2) ;
info.ifd = open(argv[1], O_RDWR) ;
if( info.ifd == -1 )
exit(1) ;
tcgetattr(info.ifd,&old_settings) ;
new_settings = old_settings ;
new_settings.c_iflag &=
~(ISTRIP|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXOFF|IMAXBEL) ;
new_settings.c_oflag = 0 ;
new_settings.c_cflag = B300|CS8|CREAD|CLOCAL ;
new_settings.c_lflag = 0 ;
new_settings.c_cc[VMIN] = 32 ;
new_settings.c_cc[VTIME] = 1 ;
tcsetattr(info.ifd,TCSADRAIN, &new_settings) ;
done = ZmodemRInit(&info) ;
while(!done)
{
FD_ZERO(&readfds) ;
FD_SET(info.ifd, &readfds) ;
timeout.tv_sec = info.timeout ;
timeout.tv_usec = 0 ;
i = select(info.ifd+1, &readfds,NULL,NULL, &timeout) ;
if( i<0 )
perror("select") ;
else if( i==0 )
done = ZmodemTimeout(&info) ;
else {
len = read(info.ifd, buffer, sizeof(buffer)) ;
done = ZmodemRcv(buffer, len, &info) ;
}
}
tcsetattr(info.ifd,TCSADRAIN, &old_settings) ;
#endif /* TEST */
exit(0) ;
}
int
ZXmitStr(buffer, len, info)
u_char *buffer ;
int len ;
ZModem *info ;
{
int i,j ;
u_char c ;
extern double drand48() ;
#ifdef TEST
for(i=0; i<len; i += 16)
{
printf(" ") ;
for(j=0; j<16 && i+j<len; ++j)
printf("%2.2x ", buffer[i+j]) ;
for(; j<16; ++j)
printf(" ") ;
printf(" |") ;
for(j=0; j<16 && i+j<len; ++j)
putchar(((c=buffer[i+j]) < 040 || c >= 0177) ? '.' : c ) ;
printf("|\n") ;
}
#else
#ifdef COMMENT
/* TEST: randomly corrupt one out of every 300 bytes */
for(i=0; i<len; ++i)
if( drand48() < 1./300. ) {
fprintf(stderr, "byte %d was %2.2x, is", i, buffer[i]) ;
buffer[i] ^= 1<<(lrand48()&7) ;
fprintf(stderr, " %2.2x\n", buffer[i]) ;
}
#endif /* COMMENT */
if( write(info->ifd, buffer, len) != len )
return ZmErrSys ;
#endif /* TEST */
return 0 ;
}
void
ZIFlush(info)
ZModem *info ;
{
}
void
ZOFlush(info)
ZModem *info ;
{
}
void
ZStatus(i,j,str)
{
fprintf(stderr,"status %d=%d\n",i,j) ;
}
int
ZAttn(info)
ZModem *info ;
{
char *ptr ;
int i = 0 ;
for(ptr = info->attn; *ptr != '\0'; ++ptr) {
if( *ptr == ATTNBRK )
ioctl(info->ifd, TCSBRK, 0) ;
else if( *ptr == ATTNPSE )
sleep(1) ;
else
write(info->ifd, ptr, 1) ;
}
return 0 ;
}
FILE *
ZOpenFile(name, crc, info)
char *name ;
u_long crc ;
ZModem *info ;
{
struct stat buf ;
int exists ; /* file already exists */
static int changeCount = 0 ;
char name2[MAXPATHLEN] ;
int apnd = 0 ;
int f0,f1,f2,f3 ;
/* TODO: if absolute path, do we want to allow it?
* if relative path, do we want to prepend something?
*/
if( *name == '/' ) /* for now, disallow absolute paths */
return NULL ;
if( stat(name, &buf) == 0 )
exists = 1 ;
else if( errno == ENOENT )
exists = 0 ;
else
return NULL ;
/* if remote end has not specified transfer flags, we can
* accept the local definitions
*/
if( f0 == ZCRESUM ) { /* if exists, and we already have it, return */
if( exists && buf.st_size == info->len )
return NULL ;
apnd = 1 ;
}
/* reject if file not found and it most be there (ZMSKNOLOC) */
if( !exists && (f1 & ZMSKNOLOC) )
return NULL ;
switch( f1 & ZMMASK ) {
case 0: /* Implementation-dependent. In this case, we
* reject if file exists (and ZMSKNOLOC not set) */
if( exists && !(f1 & ZMSKNOLOC) )
return NULL ;
break ;
case ZMNEWL: /* take if newer or longer than file on disk */
if( exists && info->date <= buf.st_mtime &&
info->len <= buf.st_size )
return NULL ;
break ;
case ZMCRC: /* take if different CRC or length */
if( exists && info->len == buf.st_size && crc == FileCrc(name) )
return NULL ;
break ;
case ZMAPND: /* append */
apnd = 1 ;
case ZMCLOB: /* unconditional replace */
break ;
case ZMNEW: /* take if newer than file on disk */
if( exists && info->date <= buf.st_mtime )
return NULL ;
break ;
case ZMDIFF: /* take if different date or length */
if( exists && info->date == buf.st_mtime &&
info->len == buf.st_size )
return NULL ;
break ;
case ZMPROT: /* only if dest does not exist */
if( exists )
return NULL ;
break ;
case ZMCHNG: /* invent new filename if exists */
if( exists ) {
while( exists ) {
sprintf(name2, "%s_%d", name, changeCount++) ;
exists = stat(name2, &buf) == 0 || errno != ENOENT ;
}
name = name2 ;
}
break ;
}
/* here if we've decided to accept */
if( exists && !apnd && unlink(name) != 0 )
return NULL ;
/* TODO: build directory path if needed */
return fopen(name, apnd ? "a" : "w") ;
}
int
ZWriteFile(buffer, len, file, info)
u_char *buffer ;
int len ;
FILE *file ;
ZModem *info ;
{
/* TODO: if ZCNL set in info->f0, convert
* newlines to local convention
*/
return fwrite(buffer, 1, len, file) == len ? 0 : ZmErrSys ;
}
int
ZCloseFile(info)
ZModem *info ;
{
fclose(info->file) ;
chmod(info->filename, info->mode&0777) ;
}

327
Xmodem/send.c Normal file
View File

@ -0,0 +1,327 @@
#ifndef lint
static const char rcsid[] = "$Id: send.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
#define TEST /* standalone test */
#include <unistd.h>
#include <string.h>
#include "zmodem.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/termios.h>
#include <sys/termio.h> /* define TCSBRK */
#include <sys/param.h>
extern int errno ;
static u_char zeros[4] = {0,0,0,0} ;
main(argc,argv)
int argc ;
char **argv ;
{
struct termios old_settings, new_settings ;
fd_set readfds ;
struct timeval timeout ;
int i ;
int len ;
char buffer[1024] ;
int done = 0 ;
int filecount = 0 ;
ZModem info ;
#ifdef TEST
static u_char Amsg0[] = {
0x43,
} ;
static u_char Amsg1[] = {
0x06, 0x43,
} ;
static u_char Amsg2[] = {
0x06,
} ;
static u_char Amsg3[] = {
0x06,
} ;
static u_char Amsg4[] = {
0x06, 0x43,
} ;
static u_char Amsg5[] = {
0x06, 0x43,
} ;
static u_char Amsg6[] = {
0x06,
} ;
static u_char Amsg7[] = {
0x06,
} ;
static u_char Amsg8[] = {
0x06,
} ;
static u_char Amsg9[] = {
0x06, 0x43,
} ;
#define E(b) {b, sizeof(b)}
static struct {u_char *bm; int len} Bmsgs[] = {
E(Amsg0),
E(Amsg1),
E(Amsg2),
E(Amsg3),
E(Amsg4),
E(Amsg5),
E(Amsg6),
E(Amsg7),
E(Amsg8),
E(Amsg9),} ;
#endif /* TEST */
/* try to trap uninit. variables */
memset(&info,0xa5,sizeof(info)) ;
info.zsinitflags = 0 ;
info.attn = "\17\336" ;
info.packetsize = 1024 ;
info.windowsize = 4096 ;
#ifdef TEST
done = YmodemTInit(&info) ;
for(i=0; !done; ++i )
done = ZmodemRcv(Bmsgs[i].bm, Bmsgs[i].len, &info) ;
done = ZmodemTFile("utils.c","utils.c", 0,0,0,0, 1,0, &info) ;
for(; !done; ++i )
done = ZmodemRcv(Bmsgs[i].bm, Bmsgs[i].len, &info) ;
done = ZmodemTFile("foo.c","foo.c", 0,0,0,0, 1,0, &info) ;
for(; !done; ++i )
done = ZmodemRcv(Bmsgs[i].bm, Bmsgs[i].len, &info) ;
done = ZmodemTFinish(info) ;
#else
if( argc < 2 )
exit(2) ;
info.ifd = open(argv[1], O_RDWR) ;
if( info.ifd == -1 )
exit(1) ;
tcgetattr(info.ifd,&old_settings) ;
new_settings = old_settings ;
new_settings.c_iflag &=
~(ISTRIP|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXOFF|IMAXBEL) ;
new_settings.c_oflag = 0 ;
new_settings.c_cflag = B300|CS8|CREAD|CLOCAL ;
new_settings.c_lflag = 0 ;
new_settings.c_cc[VMIN] = 32 ;
new_settings.c_cc[VTIME] = 1 ;
tcsetattr(info.ifd,TCSADRAIN, &new_settings) ;
InitXmit(&info) ;
XmitFile("utils.c",1,0,&info) ;
#ifdef COMMENT
XmitFile("foo",1,0,&info) ;
XmitFile("foo.c",1,0,&info) ;
XmitFile("raw",1,0,&info) ;
#endif /* COMMENT */
FinishXmit(&info) ;
tcsetattr(info.ifd,TCSADRAIN, &old_settings) ;
#endif /* TEST */
exit(0) ;
}
static int
doIO(info)
ZModem *info ;
{
fd_set readfds ;
struct timeval timeout ;
int i ;
int len ;
char buffer[1024] ;
int done = 0 ;
while(!done)
{
FD_ZERO(&readfds) ;
FD_SET(info->ifd, &readfds) ;
timeout.tv_sec = info->timeout ;
timeout.tv_usec = 0 ;
i = select(info->ifd+1, &readfds,NULL,NULL, &timeout) ;
if( i<0 )
perror("select") ;
else if( i==0 )
done = ZmodemTimeout(info) ;
else {
len = read(info->ifd, buffer, sizeof(buffer)) ;
done = ZmodemRcv(buffer, len, info) ;
}
}
return done ;
}
int
InitXmit(info)
ZModem *info ;
{
int done ;
done = ZmodemTInit(info) ;
if( !done )
done = doIO(info) ;
return done != ZmDone ;
}
XmitFile(filename,nfiles,nbytes,info)
char *filename ;
int nfiles, nbytes ;
ZModem *info ;
{
int done ;
done = ZmodemTFile(filename,filename, 0,ZMCLOB,0,0,
nfiles,nbytes, info) ;
if( done == ZmErrCantOpen || done == ZmFileTooLong )
return 0 ;
if( !done )
done = doIO(info) ;
return done != ZmDone ;
}
FinishXmit(info)
ZModem *info ;
{
int done ;
done = ZmodemTFinish(info) ;
if( !done )
done = doIO(info) ;
return done != ZmDone ;
}
int
ZXmitStr(buffer, len, info)
u_char *buffer ;
int len ;
ZModem *info ;
{
int i,j ;
u_char c ;
extern double drand48() ;
#ifdef TEST
for(i=0; i<len; i += 16)
{
printf(" ") ;
for(j=0; j<16 && i+j<len; ++j)
printf("%2.2x ", buffer[i+j]) ;
for(; j<16; ++j)
printf(" ") ;
printf(" |") ;
for(j=0; j<16 && i+j<len; ++j)
putchar(((c=buffer[i+j]) < 040 || c >= 0177) ? '.' : c ) ;
printf("|\n") ;
}
#else
#ifdef COMMENT
/* TEST: randomly corrupt one out of every 300 bytes */
for(i=0; i<len; ++i)
if( drand48() < 1./300. ) {
fprintf(stderr, "byte %d was %2.2x, is", i, buffer[i]) ;
buffer[i] ^= 1<<(lrand48()&7) ;
fprintf(stderr, " %2.2x\n", buffer[i]) ;
}
#endif /* COMMENT */
if( write(info->ifd, buffer, len) != len )
return ZmErrSys ;
#endif /* TEST */
return 0 ;
}
void
ZIFlush(info)
ZModem *info ;
{
}
void
ZOFlush(info)
ZModem *info ;
{
}
void
ZStatus(i,j,str)
{
fprintf(stderr,"status %d=%d\n",i,j) ;
}
int
ZAttn(info)
ZModem *info ;
{
char *ptr ;
int i = 0 ;
for(ptr = info->attn; *ptr != '\0'; ++ptr) {
if( *ptr == ATTNBRK )
ioctl(info->ifd, TCSBRK, 0) ;
else if( *ptr == ATTNPSE )
sleep(1) ;
else
write(info->ifd, ptr, 1) ;
}
return 0 ;
}
FILE *
ZOpenFile(name, f0,f1,f2,f3, len, date, mode, filesRem, bytesRem, crc)
char *name ;
int f0,f1,f2,f3, len, mode, filesRem, bytesRem ;
long date ;
u_long crc ;
{
}
int
ZWriteFile()
{}
ZCloseFile(info)
ZModem *info ;
{}
ZFlowControl(info)
ZModem *info ;
{}

86
Xmodem/seriallog.c Normal file
View File

@ -0,0 +1,86 @@
#ifndef lint
static const char rcsid[] = "$Id: seriallog.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
/* seriallog routines. Write data to log file, tagged with timestamp
* and channel.
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/time.h>
#include "seriallog.h"
static struct timeval timestamp = {0,0} ;
#define DTIME 1500 /* timeout, milliseconds */
static int which = -1 ; /* last transmitted */
static char obuf[4096] ;
static int olen = -1 ;
FILE *SerialLogFile = NULL ;
/* flush out buffered text */
void
SerialLogFlush()
{
int i ;
if( SerialLogFile == NULL )
return ;
if( which != -1 && olen > 0 )
{
i = fwrite((char *)&which, sizeof(int), 1, SerialLogFile) ;
i = fwrite((char *)&timestamp, sizeof(timestamp), 1, SerialLogFile) ;
i = fwrite((char *)&olen, sizeof(int), 1, SerialLogFile) ;
i = fwrite(obuf, 1, olen, SerialLogFile) ;
}
fflush(SerialLogFile) ;
which = -1 ;
olen = 0 ;
}
void
SerialLog(const void *data, int len, int w)
{
struct timezone z ;
struct timeval time ;
int dt ;
int i ;
if( SerialLogFile == NULL )
return ;
gettimeofday(&time, &z) ;
dt = (time.tv_sec - timestamp.tv_sec)*1000 +
(time.tv_usec - timestamp.tv_usec)/1000 ;
if( w != which || dt > DTIME ) {
SerialLogFlush() ;
which = w ;
timestamp = time ;
}
while( len > 0 )
{
if( olen+len > sizeof(obuf) )
SerialLogFlush() ;
i = len > sizeof(obuf) ? sizeof(obuf) : len ;
bcopy(data, obuf+olen, i) ;
olen += i ;
len -= i ;
}
}

11
Xmodem/seriallog.h Normal file
View File

@ -0,0 +1,11 @@
/* $Id: seriallog.h,v 1.2 2001/10/25 23:56:29 efalk Exp $ */
#ifndef SERIALLOG_H
#define SERIALLOG_H
extern FILE *SerialLogFile ;
extern void SerialLogFlush() ;
extern void SerialLog(const void *data, int len, int w) ;
#endif

133
Xmodem/utils.c Normal file
View File

@ -0,0 +1,133 @@
#ifndef lint
static const char rcsid[] = "$Id: utils.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @ @ @@@@@ @@@ @ @@@@
* @ @ @ @ @ @
* @ @ @ @ @ @@@
* @ @ @ @ @ @
* @@@ @ @@@ @@@@@ @@@@
*
* UTILS - utilities used by xmodem library.
*
* Routines provided here:
*
*
* name (args)
* Brief description.
*
* int sendCancel()
*
* send cancel string <CAN><CAN>
*
*
* int sendFlush(c)
* char c ;
*
* flush input, send one character, return nonzero on error
*
*
* int sendChr(c)
* char c ;
*
* send one character, return nonzero on error
*
*
* int sendStr(str, len)
* char *str ;
* int len ;
*
* send string, return nonzero on error
*
*
* int calcChecksum(ptr, count)
* char *ptr ;
* int count ;
*
* compute checksum (used by xmodem)
*
*
* Edward A. Falk
*
* January, 1995
*
*
*
**********/
#include <sys/termios.h>
#include <sys/ioctl.h>
#include "xmodem.h"
int
sendCancel()
{
return sendFlush(CAN) || sendFlush(CAN) ;
}
/* send one character, return nonzero on error */
int
sendFlush(char c)
{
/* first, flush input port */
/* TODO: caller provide a way to do this? */
if( xmRfd == -1 )
return XmErrNotOpen ;
/* TODO: caller provides flush */
if( ioctl(xmRfd, TCFLSH, TCIFLUSH) == -1 )
return XmErrSys ;
return sendChr(c) ;
}
/* send one character, return nonzero on error */
int
sendChr(char c)
{
/* TODO: caller provide character output func? */
if( xmTfd == -1 )
return XmErrNotOpen ;
return write(xmTfd, &c, 1) ==1 ? 0 : XmErrSys ;
}
/* send multiple characters, return nonzero on error */
int
sendStr(char *str, int len)
{
/* TODO: caller provide character output func? */
if( xmTfd == -1 )
return XmErrNotOpen ;
return write(xmTfd, str, len) == len ? 0 : XmErrSys ;
}
/* compute checksum */
int
calcChecksum(char *ptr, int count)
{
register int csum = 0 ;
while( --count >= 0 )
csum += (u_char) *ptr++ ;
return csum & 255 ;
}

111
Xmodem/xmodem.h Normal file
View File

@ -0,0 +1,111 @@
/* $Id: xmodem.h,v 1.2 2001/10/25 23:56:29 efalk Exp $ */
#include <sys/param.h>
typedef int bool ;
typedef enum {
Xmodem=0,
XmodemCrc=1,
WXmodem=2,
Ymodem=3,
YmodemG=4,
} Protocol ;
extern bool xmodem1k ; /* 1k blocks supported */
extern bool fileInfo ; /* ymodem: send file attributes? */
extern Protocol protocol ;
extern int xmTfd ; /* transmit file descriptor */
extern int xmRfd ; /* receive file descriptor */
extern int xmTimeout ; /* timeout, seconds */
extern char xmDefPath[MAXPATHLEN] ; /* default location (ymodem) */
extern char xmFilename[MAXPATHLEN] ; /* current filename */
/* error code definitions */
#define XmDone -1 /* done */
#define XmErrInt -2 /* internal error */
#define XmErrSys -3 /* system error, see errno */
#define XmErrNotOpen -4 /* communication channel not open */
#define XmErrCantOpen -5 /* can't open file, see errno */
#define XmErrInitTo -10 /* transmitter failed to respond to init req. */
#define XmErrSequence -11 /* packet received out of sequence */
#define XmErrCancel -12 /* cancelled by remote end */
#define XmErrRcvTo -13 /* remote end timed out during transfer */
#ifdef __STDC__
extern int XmodemRInit(char *path, Protocol p) ;
/* start receive protocol */
extern int XmodemRRcv(char c) ; /* call for each received char. */
extern int XmodemRTimeout() ; /* call if xmTimeout expires */
extern int XmodemRAbort() ; /* call to abort protocol */
extern int XmodemTInit(char *path, Protocol p) ;
/* start transmit protocol */
extern int XmodemTRcv(char c) ; /* call for each received char. */
extern int XmodemTTimeout() ; /* call if xmTimeout expires */
extern int XmodemTAbort() ; /* call to abort protocol */
extern int XmodemTFinish() ; /* call after last file sent (ymodem) */
#else
extern int XmodemRInit() ; /* start receive protocol */
extern int XmodemRRcv() ; /* call for each received char. */
extern int XmodemRTimeout() ; /* call if xmTimeout expires */
extern int XmodemRAbort() ; /* call to abort protocol */
extern int XmodemTInit() ; /* start transmit protocol */
extern int XmodemTRcv() ; /* call for each received char. */
extern int XmodemTTimeout() ; /* call if xmTimeout expires */
extern int XmodemTAbort() ; /* call to abort protocol */
#endif
/* INTERNAL */
#define SOH 1 /* ^A */
#define STX 2 /* ^B */
#define EOT 4 /* ^D */
#define ACK 6 /* ^F */
#define DLE 16 /* ^P */
#define XON 17 /* ^Q */
#define XOFF 19 /* ^S */
#define NAK 21 /* ^U */
#define SYN 22 /* ^V */
#define CAN 24 /* ^X */
#ifndef False
#define False 0
#define True 1
#endif
#define MAXERROR 10
#define INITTO 10 /* initialization timeout, basic xmodem */
#define INITTO2 3 /* initialization timeout */
#define PKTTO 5 /* in-packet receive timeout */
#define MAXPACKET 1024 /* max packet length */
#ifdef __STDC__
extern int sendCancel(), sendFlush(char),
sendChr(char), sendStr(char *,int) ;
extern int calcrc(char *ptr, int count) ;
extern int calcChecksum(char *ptr, int count) ;
#else
extern int sendCancel(), sendFlush(), sendChr(), sendStr() ;
extern int calcrc() ;
extern int calcChecksum() ;
#endif

417
Xmodem/xmodemr.c Normal file
View File

@ -0,0 +1,417 @@
#ifndef lint
static const char rcsid[] = "$Id: xmodemr.c,v 1.1.1.1 2001/03/08 00:01:48 efalk Exp $" ;
#endif lint
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @ @ @ @ @@@ @@@@ @@@@@ @ @ @@@@
* @ @ @@ @@ @ @ @ @ @ @@ @@ @ @
* @ @ @ @ @ @ @ @ @@@ @ @ @ @@@@
* @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
* @ @ @ @ @ @@@ @@@@ @@@@@ @ @ @ @ @
*
* XMODEMR - receiver side of xmodem/ymodem protocol
*
* Caller sets flags defined in xmodem.h as appropriate.
* (default is basic xmodem)
*
* This code is designed to be called from inside a larger
* program, so it is implemented as a state machine where
* practical.
*
*
* functions:
*
* XmodemRInit(char *filename, Protocol p)
* Initiate a receive
*
* XmodemRTimeout()
* called after timeout expired
*
* XmodemRRcv(char c)
* called after character received
*
* XmodemRAbort()
* abort transfer
*
* all functions return 0 on success, 1 on abort
*
*
*
* Edward A. Falk
*
* January, 1995
*
*
*
**********/
#include <stdio.h>
#include <sys/types.h>
#include "xmodem.h"
/* TODO: WXmodem */
bool xmodem1k = False ;
Protocol protocol = Xmodem ;
int xmTfd = -1 ;
int xmRfd = -1 ;
int xmTimeout = 0 ;
char xmDefPath[MAXPATHLEN] ;
char xmFilename[MAXPATHLEN] ;
typedef enum {
Start, /* waiting to begin */
Init, /* sent initial NAK, 'C' or 'W' */
Packet, /* receiving a packet */
Wait, /* wait for start of next packet */
} XmodemState ;
static bool ymodem ;
static XmodemState state = Start ;
static int errorCount = 0 ;
static int errorCount2 ;
static int ignoreCount ;
static int eotCount ; /* count EOT's, reject first one */
static int inCount ; /* characters received this packet */
static int pktLen ; /* length of this packet data */
static int pktHdrLen ; /* id, cmpl, checksum or crc */
static char packet[MAXPACKET+5], *optr ;
static int packetId ; /* id of last received packet */
static int packetCount ; /* # packets received */
static FILE *ofile ; /* output file fd */
static int fileLen, fileDate, fileMode ;
static int XmodemRStart() ;
static int processPacket() ;
static int rejectPacket() ;
static int acceptPacket() ;
int
XmodemRInit( char *file, Protocol prot )
{
int err ;
state = Start ;
protocol = prot ;
ymodem = prot == Ymodem || prot == YmodemG ;
if( ymodem )
strcpy(xmDefPath, file) ;
else
strcpy(xmFilename, file) ;
eotCount = errorCount = errorCount2 = 0 ;
if( err=XmodemRStart() )
return err ;
state = Init ;
packetId = ymodem ? 255 : 0 ;
packetCount = 0 ;
pktHdrLen = protocol == Xmodem ? 3 : 4 ;
return 0 ;
}
/* send startup character */
static int
XmodemRStart()
{
static char pchars[5] = {NAK,'C','W','C','C'} ;
static int timeouts[5] = {INITTO, INITTO2, INITTO2, INITTO, INITTO} ;
char c = pchars[(int)protocol] ;
int err ;
if( err=sendFlush(c) )
return err ;
xmTimeout = timeouts[(int)protocol] ;
return 0 ;
}
int
XmodemRRcv(char c)
{
errorCount = 0 ;
switch( state ) {
case Start: /* shouldn't happen, ignore */
if( c == CAN )
return XmErrCancel ;
break ;
case Init: /* waiting */
case Wait:
switch( c ) {
case SOH:
case STX:
pktLen = c == STX ? 1024 : 128 ;
inCount = 0 ;
optr = packet ;
state = Packet ;
xmTimeout = PKTTO ;
break ;
case EOT:
if( ++eotCount > 1 ) {
sendFlush(ACK) ;
if( ymodem )
return XmodemRInit() ; /* restart protocol */
else
return XmDone ;
}
else
return rejectPacket() ; /* make xmitter try again */
case CAN: return XmErrCancel ;
default: /* ignore all others */
if( ++ignoreCount > 1030 ) {
ignoreCount = 0 ;
return sendFlush(NAK) ;
}
break ;
}
break ;
case Packet: /* mid packet */
*optr++ = c ;
if( ++inCount >= pktLen + pktHdrLen )
ProcessPacket() ;
break ;
}
return 0 ;
}
int
XmodemRTimeout()
{
if( ++errorCount > MAXERROR )
return state == Init ? XmErrInitTo : XmErrRcvTo ;
switch( state ) {
case Start: return -1 ; /* shouldn't happen */
case Init:
if( ++errorCount2 >= 3 )
switch( protocol ) {
case WXmodem: protocol = XmodemCrc ; errorCount2 = 0 ; break ;
case XmodemCrc: protocol = Xmodem ; pktHdrLen = 3 ; break ;
}
return XmodemRStart() ;
case Wait: /* timeout while waiting */
case Packet: /* timeout in mid packet */
return rejectPacket() ;
}
}
int
XmodemRAbort()
{
return sendCancel() ;
}
static int
ProcessPacket()
{
int id = (u_char)packet[0] ;
int idc = (u_char)packet[1] ;
int i ;
if( idc != 255-id )
return rejectPacket() ;
if( id == packetId ) /* duplicate */
return acceptPacket() ;
if( id != (packetId+1)%256 ) { /* out of sequence */
(void) sendCancel() ;
return XmErrSequence ;
}
if( protocol == Xmodem )
{
/* compute checksum */
register int csum = calcChecksum(packet+2, pktLen) ;
if( csum != (u_char) packet[2+pktLen] )
return rejectPacket() ;
}
else
{
int crc0 = (u_char)packet[pktLen+2] << 8 | (u_char)packet[pktLen+3] ;
int crc1 = calcrc(packet+2, pktLen) ;
if( crc0 != crc1 )
return rejectPacket() ;
}
/* it's a good packet */
packetId = (packetId+1)%256 ;
/* is this the first packet? */
if( packetCount == 0 )
{
if( ymodem )
{
if( packet[2] == '\0' ) /* last file */
{
(void) acceptPacket() ;
return XmDone ;
}
if( packet[2] == '/' )
strcpy(xmFilename, packet+2) ;
else {
strcpy(xmFilename, xmDefPath) ;
strcat(xmFilename, packet+2) ;
}
fileLen = fileDate = fileMode = -1 ;
sscanf(packet+2+strlen(packet)+1, "%d %o %o",
&fileLen, &fileDate, &fileMode) ;
}
if( (ofile = fopen(xmFilename, "w")) == NULL ) {
sendCancel() ;
return XmErrCantOpen ;
}
if( ymodem ) {
packetCount = 1 ;
(void) acceptPacket() ;
return sendFlush('C') ;
}
else
state = Packet ;
}
++packetCount ;
/* TODO: ymodem: if this is last packet, truncate it */
if( (i=fwrite(packet+2, 1, pktLen, ofile)) != pktLen )
{
sendCancel() ;
return XmErrSys ;
}
else
return acceptPacket() ;
}
static int
rejectPacket()
{
state = Wait ;
xmTimeout = INITTO ;
return sendFlush(NAK) ;
}
static int
acceptPacket()
{
state = Wait ;
xmTimeout = INITTO ;
return sendFlush(ACK) ;
}
#ifdef COMMENT /* stand-alone testing */
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/termios.h>
main(argc,argv)
int argc ;
char **argv ;
{
struct termios old_settings, new_settings ;
fd_set readfds ;
struct timeval timeout ;
int i ;
int len ;
char buffer[1024] ;
bool done = False ;
if( argc < 2 )
exit(2) ;
xmTfd = xmRfd = open(argv[1], O_RDWR) ;
if( xmTfd == -1 )
exit(1) ;
tcgetattr(xmTfd,&old_settings) ;
new_settings = old_settings ;
new_settings.c_iflag &=
~(ISTRIP|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXOFF|IMAXBEL) ;
new_settings.c_oflag = 0 ;
new_settings.c_cflag = B300|CS8|CREAD|CLOCAL ;
new_settings.c_lflag = 0 ;
new_settings.c_cc[VMIN] = 32 ;
new_settings.c_cc[VTIME] = 1 ;
tcsetattr(xmTfd,TCSADRAIN, &new_settings) ;
xmodem1k = 0 ;
done = XmodemRInit("foo", XmodemCrc) != 0 ;
#ifdef COMMENT
xmodem1k = 1 ;
done = XmodemRInit("./", Ymodem) != 0 ;
#endif /* COMMENT */
while(!done)
{
FD_ZERO(&readfds) ;
FD_SET(xmTfd, &readfds) ;
timeout.tv_sec = xmTimeout ;
timeout.tv_usec = 0 ;
i = select(xmTfd+1, &readfds,NULL,NULL, &timeout) ;
if( i<0 )
perror("select") ;
else if( i==0 )
done = XmodemRTimeout() != 0 ;
else {
len = read(xmTfd, buffer, sizeof(buffer)) ;
for(i=0; !done && i<len; ++i)
done = XmodemRRcv(buffer[i]) != 0 ;
}
}
tcsetattr(xmTfd,TCSADRAIN, &old_settings) ;
exit(0) ;
}
#endif /* COMMENT */

410
Xmodem/xmodemt.c Normal file
View File

@ -0,0 +1,410 @@
#ifndef lint
static const char rcsid[] = "$Id: xmodemt.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @ @ @ @ @@@ @@@@ @@@@@ @ @ @@@@@
* @ @ @@ @@ @ @ @ @ @ @@ @@ @
* @ @ @ @ @ @ @ @ @@@ @ @ @ @
* @ @ @ @ @ @ @ @ @ @ @ @ @ @
* @ @ @ @ @ @@@ @@@@ @@@@@ @ @ @ @
*
* XMODEMT - transmit side of xmodem protocol
*
* Caller sets flags defined in xmodem.h as appropriate.
* (default is basic xmodem)
*
* This code is designed to be called from inside a larger
* program, so it is implemented as a state machine where
* practical.
*
* functions:
*
* XmodemTInit(char *filename, Protocol p)
* Initiate a receive
*
* XmodemTTimeout()
* called after timeout expired
*
* XmodemTRcv(char c)
* called after character received
*
* XmodemTFinish()
* last file (ymodem)
*
* XmodemTAbort()
* abort transfer
*
* all functions return 0 on success, 1 on abort
*
* Edward A. Falk
*
* January, 1995
*
*
*
**********/
#include <stdio.h>
#include <sys/types.h>
#include "xmodem.h"
bool fileInfo = False ;
/* TODO: WXmodem, YmodemG */
typedef enum {
File, /* waiting for initial protocol character */
FileWait, /* sent file header, waiting for ACK */
Start, /* waiting to begin */
Wait, /* sent a packet, waiting for ACK */
Eot, /* sent an EOT, waiting for ACK */
EndWait, /* sent null filename, waiting for ACK */
} XmodemState ;
static XmodemState state = Start ;
static bool ymodem ;
static bool useCrc ; /* receiver wants crc */
static int pktLen ; /* length of this packet data */
static int pktMaxLen ;
static char packet[MAXPACKET] ;
static char pktHdr[3], pktCrc[2] ;
static int packetId ; /* id of last received packet */
static int packetCount ; /* # packets received */
static FILE *ifile = NULL ; /* input file fd */
static int fileLen, fileDate, fileMode ;
static int sendFilename() ;
static int sendPacket() ;
static int buildPacket() ;
static int resendPacket() ;
int
XmodemTInit( char *file, Protocol prot )
{
int err ;
protocol = prot ;
ymodem = prot == Ymodem || prot == YmodemG ;
state = ymodem ? File : Start ;
strcpy(xmFilename, file) ;
if( (ifile = fopen(xmFilename, "r")) == NULL ) {
sendCancel() ;
return XmErrCantOpen ;
}
packetId = 1 ;
packetCount = 0 ;
pktMaxLen = xmodem1k ? 1024 : 128 ;
xmTimeout = 60 ;
return 0 ;
}
int
XmodemTRcv(char c)
{
if( c == CAN ) {
if( ifile != NULL )
fclose(ifile) ;
return XmErrCancel ;
}
switch( state ) {
case File: /* waiting for command, ymodem */
switch( c ) {
case NAK: useCrc = False ; return sendFilename() ;
case 'C': useCrc = True ; return sendFilename() ;
}
break ;
case FileWait: /* waiting for filename ACK */
switch( c ) {
case NAK: return resendPacket() ;
case ACK: state = Start ; return 0 ;
}
case Start: /* waiting for command, data */
switch( c ) {
case NAK: /* wants checksums */
if( !ymodem )
protocol = Xmodem ;
useCrc = False ;
return sendPacket() ;
case 'C': useCrc = True ; return sendPacket() ;
case 'W':
if( !ymodem ) {
protocol = WXmodem ;
useCrc = True ;
/* TODO: WXmodem */
}
}
break ;
case Wait: /* waiting for ACK */
switch( c ) {
case ACK: return sendPacket() ;
case NAK: return resendPacket() ;
}
break ; /* ignore all other characters */
case Eot: /* waiting for ACK after EOT */
switch( c ) {
case ACK: return XmDone ;
case NAK: return sendChr(EOT) ;
}
break ;
case EndWait: /* waiting for filename ACK */
switch( c ) {
case NAK: return resendPacket() ;
case ACK: return XmDone ;
}
}
return 0 ;
}
static int
sendFilename()
{
int i ;
char *ptr ;
pktLen = 128 ;
/* TODO: protect against long filenames */
strcpy(packet, xmFilename) ;
ptr = packet + strlen(packet) + 1 ;
/* TODO: get file info */
if( fileInfo ) {
sprintf(ptr, "%d %o %o %o", 0,0,0100644) ;
ptr += strlen(ptr) + 1 ;
}
/* TODO: what if file desc buffer too big? */
if( ptr > packet+128 )
pktLen = 1024 ;
i = pktLen - (ptr-packet) ;
bzero(ptr, i) ;
state = FileWait ;
packetId = 0 ;
return buildPacket() ;
}
int
XmodemTFinish()
{
int i ;
char *ptr ;
pktLen = 128 ;
bzero(packet, pktLen) ;
state = EndWait ;
packetId = 0 ;
return buildPacket() ;
}
static char *bufptr ;
static int buflen = 0 ;
static int
sendPacket()
{
int i ;
/* This code assumes that a incomplete reads can only happen
* after EOF. This will fail with pipes.
* TODO: try to make pipes work.
*/
state = Wait ;
if( buflen > 0 ) /* previous incomplete packet */
{
memcpy(packet, bufptr, 128) ;
bufptr += 128 ;
if( buflen < 128 )
for(i=buflen; i<128; ++i)
packet[i] = 0x1a ;
buflen -= 128 ;
pktLen = 128 ;
return buildPacket() ;
}
if( (i=fread(packet, 1,pktMaxLen, ifile)) <= 0 ) /* EOF */
{
state = Eot ;
return sendChr(EOT) ;
}
else if( i == pktMaxLen ) /* full buffer */
{
pktLen = i ;
return buildPacket() ;
}
buflen = i ;
bufptr = packet ;
pktLen = 128 ;
return buildPacket() ;
}
static int
buildPacket()
{
int i ;
pktHdr[0] = pktLen == 128 ? SOH : STX ;
pktHdr[1] = (char)packetId ;
pktHdr[2] = (char)(255-packetId) ;
++packetId ;
if( useCrc ) {
i = calcrc(packet, pktLen) ;
pktCrc[0] = (char) (i>>8) ;
pktCrc[1] = (char) (i & 0xff) ;
}
else
pktCrc[0] = (char) calcChecksum(packet, pktLen) ;
return resendPacket() ;
}
static int
resendPacket()
{
int i ;
(i=sendStr(pktHdr, 3)) || (i=sendStr(packet, pktLen)) ||
(i=sendStr(pktCrc, useCrc?2:1)) ;
return i ;
}
int
XmodemTTimeout()
{
switch( state ) {
case File:
case Start:
return XmErrInitTo ;
case FileWait:
case Wait:
case Eot:
return XmErrRcvTo ;
}
}
int
XmodemTAbort()
{
return sendCancel() ;
}
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/termios.h>
main(argc,argv)
int argc ;
char **argv ;
{
struct termios old_settings, new_settings ;
fd_set readfds ;
struct timeval timeout ;
int i ;
int len ;
char buffer[1024] ;
bool done = False ;
int filecount = 0 ;
if( argc < 2 )
exit(2) ;
xmTfd = xmRfd = open(argv[1], O_RDWR) ;
if( xmTfd == -1 )
exit(1) ;
tcgetattr(xmTfd,&old_settings) ;
new_settings = old_settings ;
new_settings.c_iflag &=
~(ISTRIP|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXOFF|IMAXBEL) ;
new_settings.c_oflag = 0 ;
new_settings.c_cflag = B300|CS8|CREAD|CLOCAL ;
new_settings.c_lflag = 0 ;
new_settings.c_cc[VMIN] = 32 ;
new_settings.c_cc[VTIME] = 1 ;
tcsetattr(xmTfd,TCSADRAIN, &new_settings) ;
xmodem1k = 1 ;
done = XmodemTInit("xmodem.h", Ymodem) != 0 ;
while(!done)
{
FD_ZERO(&readfds) ;
FD_SET(xmTfd, &readfds) ;
timeout.tv_sec = xmTimeout ;
timeout.tv_usec = 0 ;
i = select(xmTfd+1, &readfds,NULL,NULL, &timeout) ;
if( i<0 )
perror("select") ;
else if( i==0 )
done = XmodemTTimeout() != 0 ;
else {
len = read(xmTfd, buffer, sizeof(buffer)) ;
for(i=0; !done && i<len; ++i)
done = XmodemTRcv(buffer[i]) != 0 ;
}
if( done ) {
switch( ++filecount ) {
case 1:
done = XmodemTInit("crc.c", Ymodem) != 0 ;
break ;
case 2:
done = XmodemTFinish() ;
break ;
case 3: break ;
}
}
}
tcsetattr(xmTfd,TCSADRAIN, &old_settings) ;
exit(0) ;
}

900
Xmodem/zmodem.c Normal file
View File

@ -0,0 +1,900 @@
#ifndef lint
static const char rcsid[] = "$Id: zmodem.c,v 1.1.1.1 2001/03/08 00:01:48 efalk Exp $" ;
#endif
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @@@@@ @ @ @@@ @@@@ @@@@@ @ @
* @ @@ @@ @ @ @ @ @ @@ @@
* @ @ @ @ @ @ @ @ @@@ @ @ @
* @ @ @ @ @ @ @ @ @ @ @ @
* @@@@@ @ @ @ @@@ @@@@ @@@@@ @ @ @
*
* ZMODEM - main logic parser for zmodem library
*
*
* Routines provided here:
*
*
* name (args)
* Brief description.
*
* int ZmodemRcv(u_char *buffer, int len, ZModem *info)
* Call whenever characters are received. If this function
* returns ZmDone, previous function has completed successfully,
* either call ZmodemTFile() to start next file, or call
* ZmodemTFinish() to terminate the session.
*
*
* int
* ZmodemTimeout(ZModem *info)
* Call whenever the timeout period expires and no
* characters have been received.
*
* int
* ZmodemAttention(ZModem *info)
* Call whenever the attention sequence has been received
* from the remote end. It is safe to call this function
* from an interrupt handler.
*
* int
* ZmodemAbort(ZModem *info)
* Call to abort transfer. Physical connection remains
* open until you close it.
*
*
*
*
* Edward A. Falk
*
* January, 1995
*
*
*
**********/
#include <stdio.h>
/****
*
* Constants, typedefs, externals, globals, statics, macros, block data
*
****/
/* TODO: sample input before initial send */
/* TODO: more intelligent timeout dispatch */
/* TODO: read all pending input before sending next data packet out */
/* TODO: if received ZDATA while waiting for ZFILE/ZFIN, it's probably
leftovers */
/* TODO: enable flow control for zmodem, disable for X/YModem */
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include "zmodem.h"
#include "crctab.h"
static u_char zeros[4] = {0,0,0,0} ;
extern int YrcvChar( char c, register ZModem *info ) ;
extern int YrcvTimeout( register ZModem *info ) ;
extern void ZIdleStr(u_char *buffer, int len, ZModem *info) ;
/* LEXICAL BOX: handle characters received from remote end.
* These may be header, data or noise.
*
* This section is a finite state machine for parsing headers
* and reading input data. The info->chrCount field is effectively
* the state variable.
*/
static int FinishChar( char c, register ZModem *info ) ;
static int DataChar( u_char c, register ZModem *info ) ;
static int HdrChar( u_char c, register ZModem *info ) ;
static int IdleChar(u_char c, register ZModem *info) ;
extern int YsendChar() ;
static int ZProtocol(), ZDataReceived() ;
int
ZmodemRcv( register u_char *str, int len, register ZModem *info )
{
register u_char c ;
int err ;
info->rcvlen = len ;
while( --info->rcvlen >= 0 )
{
c = *str++ ;
if( c == CAN ) {
if( ++info->canCount >= 5 ) {
ZStatus(RmtCancel, 0, NULL) ;
return ZmErrCancel ;
}
}
else
info->canCount = 0 ;
if( info->InputState == Ysend ) {
if( (err = YsendChar(c, info)) )
return err ;
}
else if( info->InputState == Yrcv ) {
if( (err = YrcvChar(c, info)) )
return err ;
}
else if( c != XON && c != XOFF )
{
/* now look at what we have */
switch( info->InputState )
{
case Idle:
if( (err = IdleChar(c, info)) )
return err ;
break ;
case Inhdr:
if( (err = HdrChar(c, info)) )
return err ;
break ;
case Indata:
if( (err = DataChar(c, info)) )
return err ;
break ;
case Finish:
if( (err = FinishChar(c, info)) )
return err ;
break ;
default:
break ;
}
}
}
return 0 ;
}
/* handle character input while idling
* looking for ZPAD-ZDLE sequence which introduces a header
*/
static int
IdleChar(u_char c, register ZModem *info)
{
if( info->chrCount == 0 )
{
if( c == ZPAD )
++info->chrCount ;
else if( info->state == Sending && ++info->noiseCount > MaxNoise )
info->waitflag = 1 ;
else if( info->state == TStart && (c == 'C' || c == 'G' || c == NAK) )
{
/* switch to ymodem */
info->state = YTStart ;
info->InputState = Ysend ;
info->Protocol = YMODEM ;
return YsendChar(c, info) ;
}
else
ZIdleStr(&c, 1, info) ;
}
else
{
switch( c ) {
case ZPAD:
++info->chrCount ;
break ;
case ZDLE:
info->InputState = Inhdr ;
info->chrCount=0 ;
break ;
default:
while( --info->chrCount >= 0 )
ZIdleStr((u_char *)"*", 1, info) ;
info->chrCount = 0 ;
break ;
}
}
return 0 ;
}
static u_int
rcvHex( u_int i, char c )
{
if( c <= '9' )
c -= '0' ;
else if( c <= 'F' )
c -= 'A'-10 ;
else
c -= 'a'-10 ;
return (i<<4)+c ;
}
/* handle character input in a header */
static int
HdrChar( u_char c, register ZModem *info )
{
int i ;
int crc=0 ;
if( c == ZDLE ) {
info->escape = 1 ;
return 0 ;
}
if( info->escape ) {
info->escape = 0 ;
switch( c ) {
case ZRUB0: c = 0177 ; break ;
case ZRUB1: c = 0377 ; break ;
default: c ^= 0100 ; break ;
}
}
if( info->chrCount == 0 ) { /* waiting for format */
switch( c ) {
case ZHEX:
case ZBIN:
case ZBIN32:
info->DataType = c ;
info->chrCount = 1 ;
info->crc = (info->DataType != ZBIN32) ? 0 : 0xffffffffL ;
memset(info->hdrData,0,sizeof(info->hdrData)) ;
break ;
default:
info->InputState = Idle ;
info->chrCount = 0 ;
return ZXmitHdrHex(ZNAK, zeros, info) ;
}
return 0 ;
}
switch( info->DataType ) {
/* hex header is 14 hex digits, cr, lf. Optional xon is ignored */
case ZHEX:
if( info->chrCount <= 14 && !isxdigit(c) ) {
info->InputState = Idle ;
info->chrCount = 0 ;
return ZXmitHdrHex(ZNAK, zeros, info) ;
}
if( info->chrCount <= 14 ) {
i = (info->chrCount-1)/2 ;
info->hdrData[i] = rcvHex(info->hdrData[i], c) ;
}
if( info->chrCount == 16 ) {
crc = 0 ;
for(i=0; i<7; ++i)
crc = updcrc(info->hdrData[i], crc) ;
info->InputState = Idle ;
info->chrCount = 0 ;
if( (crc&0xffff) != 0 )
return ZXmitHdrHex(ZNAK, zeros, info) ;
else
return ZProtocol(info) ;
}
else
++info->chrCount ;
break ;
case ZBIN:
/* binary header is type, 4 bytes data, 2 bytes CRC */
info->hdrData[info->chrCount-1] = c ;
info->crc = updcrc(c, info->crc) ;
if( ++info->chrCount > 7 ) {
info->InputState = Idle ;
info->chrCount = 0 ;
if( (crc&0xffff) != 0 )
return ZXmitHdrHex(ZNAK, zeros, info) ;
else
return ZProtocol(info) ;
}
break ;
case ZBIN32:
/* binary32 header is type, 4 bytes data, 4 bytes CRC */
info->hdrData[info->chrCount-1] = c ;
info->crc = UPDC32(c, info->crc) ;
if( ++info->chrCount > 9 ) {
info->InputState = Idle ;
info->chrCount = 0 ;
if( info->crc != 0xdebb20e3 ) /* see note below */
return ZXmitHdrHex(ZNAK, zeros, info) ;
else
return ZProtocol(info) ;
}
break ;
}
return 0 ;
}
/* handle character input in a data buffer */
static int
DataChar( u_char c, register ZModem *info )
{
if( c == ZDLE ) {
info->escape = 1 ;
return 0 ;
}
if( info->escape ) {
info->escape = 0 ;
switch( c ) {
case ZCRCE:
case ZCRCG:
case ZCRCQ:
case ZCRCW:
info->PacketType = c ;
info->crcCount = (info->DataType == ZBIN32) ? 4 : 2 ;
if( info->DataType == ZBIN )
info->crc = updcrc(c, info->crc) ;
else
info->crc = UPDC32(c, info->crc) ;
return 0 ;
case ZRUB0: c = 0177 ; break ;
case ZRUB1: c = 0377 ; break ;
default: c ^= 0100 ; break ;
}
}
switch( info->DataType ) {
/* TODO: are hex data packets ever used? */
case ZBIN:
info->crc = updcrc(c, info->crc) ;
if( info->crcCount == 0 )
info->buffer[info->chrCount++] = c ;
else if( --info->crcCount == 0 ) {
return ZDataReceived(info, (info->crc&0xffff) == 0) ;
}
break ;
case ZBIN32:
info->crc = UPDC32(c, info->crc) ;
if( info->crcCount == 0 )
info->buffer[info->chrCount++] = c ;
else if( --info->crcCount == 0 ) {
return ZDataReceived(info, info->crc == 0xdebb20e3) ;
}
break ;
}
return 0 ;
}
/* wait for "OO" */
static int
FinishChar( char c, register ZModem *info )
{
if( c == 'O' ) {
if( ++info->chrCount >= 2 )
return ZmDone ;
}
else
info->chrCount = 0 ;
return 0 ;
}
int ZPF() ;
int Ignore() ;
int AnswerChallenge() ;
int GotAbort() ;
int GotCancel() ;
int GotCommand() ;
int GotStderr() ;
int RetDone() ;
static int GotCommandData() ;
static int GotStderrData() ;
/* PROTOCOL LOGIC: This section of code handles the actual
* protocol. This is also driven by a finite state machine
*
* State tables are sorted by approximate frequency order to
* reduce search time.
*/
/* Extra ZRINIT headers are the receiver trying to resync. */
/* If compiling for Send Only or Receive Only, convert table
* entries to no-ops so we don't have to link zmodem[rt].o
*/
#if SendOnly
#define RStartOps DoneOps
#define RSinitWaitOps DoneOps
#define RFileNameOps DoneOps
#define RCrcOps DoneOps
#define RFileOps DoneOps
#define RDataOps DoneOps
#define RFinishOps DoneOps
#define GotFileName Ignore
#define ResendCrcReq Ignore
#define GotSinitData Ignore
#define ResendRpos Ignore
#define GotFileData Ignore
#define SendRinit Ignore
#else
extern StateTable RStartOps[] ;
extern StateTable RSinitWaitOps[] ;
extern StateTable RFileNameOps[] ;
extern StateTable RCrcOps[] ;
extern StateTable RFileOps[] ;
extern StateTable RDataOps[] ;
extern StateTable RFinishOps[] ;
extern int GotFileName() ;
extern int ResendCrcReq() ;
extern int GotSinitData() ;
extern int ResendRpos() ;
extern int GotFileData() ;
extern int SendRinit() ;
#endif
#if RcvOnly
#define TStartOps DoneOps
#define TInitOps DoneOps
#define FileWaitOps DoneOps
#define CrcWaitOps DoneOps
#define SendingOps DoneOps
#define SendDoneOps DoneOps
#define SendWaitOps DoneOps
#define SendEofOps DoneOps
#define TFinishOps DoneOps
#define SendMoreFileData Ignore
#else
extern StateTable TStartOps[] ;
extern StateTable TInitOps[] ;
extern StateTable FileWaitOps[] ;
extern StateTable CrcWaitOps[] ;
extern StateTable SendingOps[] ;
extern StateTable SendDoneOps[] ;
extern StateTable SendWaitOps[] ;
extern StateTable SendEofOps[] ;
extern StateTable TFinishOps[] ;
extern int SendMoreFileData() ;
#endif
static StateTable CommandDataOps[] = {
#ifdef COMMENT
{ZRQINIT,f,1,1},
{ZRINIT,f,1,1},
{ZSINIT,f,1,1},
{ZACK,f,1,1},
{ZFILE,f,1,1},
{ZSKIP,f,1,1},
{ZNAK,f,1,1},
{ZABORT,f,1,1,TFinish},
{ZFIN,f,1,1},
{ZRPOS,f,1,1},
{ZDATA,f,1,1},
{ZEOF,f,1,1},
{ZFERR,f,1,1,TFinish},
{ZCRC,f,1,1},
{ZCHALLENGE,f,1,1},
{ZCOMPL,f,1,1},
{ZCAN,f,1,1},
{ZFREECNT,f,1,1},
{ZCOMMAND,f,1,1},
{ZSTDERR,f,1,1},
#endif /* COMMENT */
{99,ZPF,0,0,CommandData},
} ;
static StateTable CommandWaitOps[] = {
#ifdef COMMENT
{ZRQINIT,f,1,1},
{ZRINIT,f,1,1},
{ZSINIT,f,1,1},
{ZACK,f,1,1},
{ZFILE,f,1,1},
{ZSKIP,f,1,1},
{ZNAK,f,1,1},
{ZABORT,f,1,1,TFinish},
{ZFIN,f,1,1},
{ZRPOS,f,1,1},
{ZDATA,f,1,1},
{ZEOF,f,1,1},
{ZFERR,f,1,1,TFinish},
{ZCRC,f,1,1},
{ZCHALLENGE,f,1,1},
{ZCOMPL,f,1,1},
{ZCAN,f,1,1},
{ZFREECNT,f,1,1},
{ZCOMMAND,f,1,1},
{ZSTDERR,f,1,1},
#endif /* COMMENT */
{99,ZPF,0,0,CommandWait},
} ;
static StateTable StderrDataOps[] = {
#ifdef COMMENT
{ZRQINIT,f,1,1},
{ZRINIT,f,1,1},
{ZSINIT,f,1,1},
{ZACK,f,1,1},
{ZFILE,f,1,1},
{ZSKIP,f,1,1},
{ZNAK,f,1,1},
{ZABORT,f,1,1,TFinish},
{ZFIN,f,1,1},
{ZRPOS,f,1,1},
{ZDATA,f,1,1},
{ZEOF,f,1,1},
{ZFERR,f,1,1,TFinish},
{ZCRC,f,1,1},
{ZCHALLENGE,f,1,1},
{ZCOMPL,f,1,1},
{ZCAN,f,1,1},
{ZFREECNT,f,1,1},
{ZCOMMAND,f,1,1},
{ZSTDERR,f,1,1},
#endif /* COMMENT */
{99,ZPF,0,0,StderrData},
} ;
static StateTable DoneOps[] = {
{99,ZPF,0,0,Done},
} ;
static StateTable *tables[] = {
RStartOps,
RSinitWaitOps,
RFileNameOps,
RCrcOps,
RFileOps,
RDataOps,
RDataOps, /* RDataErr is the same as RData */
RFinishOps,
TStartOps,
TInitOps,
FileWaitOps,
CrcWaitOps,
SendingOps,
SendWaitOps,
SendDoneOps,
SendEofOps,
TFinishOps,
CommandDataOps,
CommandWaitOps,
StderrDataOps,
DoneOps,
} ;
char *hdrnames[] = {
"ZRQINIT",
"ZRINIT",
"ZSINIT",
"ZACK",
"ZFILE",
"ZSKIP",
"ZNAK",
"ZABORT",
"ZFIN",
"ZRPOS",
"ZDATA",
"ZEOF",
"ZFERR",
"ZCRC",
"ZCHALLENGE",
"ZCOMPL",
"ZCAN",
"ZFREECNT",
"ZCOMMAND",
"ZSTDERR",
} ;
/* This function is called (indirectly) by the ZmodemRcv()
* function when a full header has been received.
*/
static int
ZProtocol( register ZModem *info )
{
register StateTable *table ;
zmodemlog("received %s: %2.2x %2.2x %2.2x %2.2x = %lx\n",
hdrnames[info->hdrData[0]], info->hdrData[1],
info->hdrData[2], info->hdrData[3], info->hdrData[4],
ZDec4(info->hdrData+1)) ;
/* Flags are sent in F3 F2 F1 F0 order. Data is sent in P0 P1 P2 P3 */
info->timeoutCount = 0 ;
info->noiseCount = 0 ;
table = tables[(int)info->state] ;
while( table->type != 99 && table->type != info->hdrData[0] )
++table ;
zmodemlog(" state %s => %s, iflush=%d, oflush=%d, call %x\n",
sname(info), sname2(table->newstate), table->IFlush,
table->OFlush, table->func) ;
info->state = table->newstate ;
if( table->IFlush ) {info->rcvlen = 0 ; ZIFlush(info) ;}
if( table->OFlush ) ZOFlush(info) ;
return table->func(info) ;
}
static int
ZDataReceived( register ZModem *info, int crcGood )
{
switch( info->state ) {
case RSinitWait: return GotSinitData(info, crcGood) ;
case RFileName: return GotFileName(info, crcGood) ;
case RData: return GotFileData(info, crcGood) ;
case CommandData: return GotCommandData(info, crcGood) ;
case StderrData: return GotStderrData(info, crcGood) ;
default: return ZPF(info) ;
}
}
int
ZmodemTimeout( register ZModem *info )
{
/* timed out while waiting for input */
++info->timeoutCount ;
zmodemlog("timeout %d [%s]\n", info->timeoutCount, sname(info) ) ;
switch( info->state ) {
/* receive */
case RStart: /* waiting for INIT frame from other end */
if( info->timeoutCount > 4 )
return YmodemRInit(info) ;
case RSinitWait:
case RFileName:
if( info->timeout > 0 )
ZStatus(SndTimeout, info->timeoutCount, NULL) ;
if( info->timeoutCount > 4 )
return ZmErrRcvTo ;
info->state = RStart ;
return SendRinit(info) ;
case RCrc:
case RFile:
case RData:
ZStatus(SndTimeout, info->timeoutCount, NULL) ;
if( info->timeoutCount > 2 ) {
info->timeoutCount = 0 ;
info->state = RStart ;
return SendRinit(info) ;
}
return info->state == RCrc ? ResendCrcReq(info) : ResendRpos(info) ;
case RFinish:
ZStatus(SndTimeout, info->timeoutCount, NULL) ;
return ZmDone ;
case YRStart:
case YRDataWait:
case YRData:
case YREOF:
return YrcvTimeout(info) ;
/* transmit */
case TStart: /* waiting for INIT frame from other end */
case TInit: /* sent INIT, waiting for ZACK */
case FileWait: /* sent file header, waiting for ZRPOS */
case CrcWait: /* sent file crc, waiting for ZRPOS */
case SendWait: /* waiting for ZACK */
case SendEof: /* sent EOF, waiting for ZACK */
case TFinish: /* sent ZFIN, waiting for ZFIN */
case YTStart:
case YTFile:
case YTDataWait:
case YTData:
case YTEOF:
case YTFin:
ZStatus(RcvTimeout,0,NULL) ;
return ZmErrRcvTo ;
case Sending: /* sending data subpackets, ready for int */
return SendMoreFileData(info) ;
/* general */
case CommandData: /* waiting for command data */
case StderrData: /* waiting for stderr data */
return ZmErrSndTo ;
case CommandWait: /* waiting for command to execute */
return ZmErrCmdTo ;
case Done:
return ZmDone ;
default:
return 0 ;
}
}
int
ZmodemAttention( register ZModem *info )
{
/* attention received from remote end */
if( info->state == Sending ) {
ZOFlush(info) ;
info->interrupt = 1 ;
}
return 0 ;
}
int
ZmodemAbort( register ZModem *info )
{
static u_char canistr[] = {
CAN,CAN,CAN,CAN,CAN,CAN,CAN,CAN,8,8,8,8,8,8,8,8,8,8
} ;
info->state = Done ;
ZIFlush(info) ;
ZOFlush(info) ;
return ZXmitStr(canistr, sizeof(canistr), info) ;
}
/* used to completely ignore headers */
int
Ignore( ZModem *info )
{
return 0 ;
}
/* ignore header contents, return ZmDone */
int
RetDone( ZModem *info )
{
return ZmDone ;
}
/* ignore header contents, return ZmErrCancel */
int
GotCancel( ZModem *info )
{
return ZmErrCancel ;
}
/* utility: set up to receive a data packet */
int
dataSetup( register ZModem *info )
{
info->InputState = Indata ;
info->chrCount = 0 ;
info->crcCount = 0 ;
info->crc = (info->DataType != ZBIN32) ? 0 : 0xffffffffL ;
return 0 ;
}
/* called when a remote command received. For now, we
* refuse to execute commands. Send EPERM and ignore.
*/
int
GotCommand( ZModem *info )
{
u_char rbuf[4] ;
/* TODO: add command capability */
rbuf[0] = EPERM ;
rbuf[1] = rbuf[2] = rbuf[3] = 0 ;
return ZXmitHdrHex(ZCOMPL, rbuf, info) ;
}
static int
GotCommandData( register ZModem *info )
{
/* TODO */
return 0 ;
}
/* called when the remote system wants to put something to
* stderr
*/
int
GotStderr( register ZModem *info )
{
info->InputState = Indata ;
info->chrCount = 0 ;
return 0 ;
}
static int
GotStderrData( register ZModem *info )
{
info->buffer[info->chrCount] = '\0' ;
ZStatus(RemoteMessage, info->chrCount, (char *)info->buffer) ;
return 0 ;
}
/* Protocol failure: An unexpected packet arrived. This could
* be from many sources, such as old pipelined info finally arriving
* or a serial line with echo enabled. Report it and ignore it.
*/
int
ZPF( ZModem *info )
{
info->waitflag = 1 ; /* pause any in-progress transmission */
ZStatus(ProtocolErr, info->hdrData[0], NULL) ;
return 0 ;
}
int
AnswerChallenge( register ZModem *info )
{
return ZXmitHdrHex(ZACK, info->hdrData+1, info) ;
}
int
GotAbort( register ZModem *info )
{
ZStatus(RmtCancel, 0, NULL) ;
return ZXmitHdrHex(ZFIN, zeros, info) ;
}

709
Xmodem/zmodem.h Normal file
View File

@ -0,0 +1,709 @@
/* $Id: zmodem.h,v 1.2 2001/10/25 23:56:29 efalk Exp $ */
#ifndef ZMODEM_H
#define ZMODEM_H
/* Master header file for Zmodem protocol driver routines */
#if 0
These routines are intended to be incorportated into other programs,
and do not constitute a zmodem program by themselves, although a
demo zmodem program that uses these routines has been included.
All information pertaining to a transfer session is kept in a data
structure defined by the caller. This makes it possible for the
caller to drive multiple simultaneous sessions.
Caller provides I/O, timing and query routines. Caller remains
in control at all times. Typical use is to call these routines
from a select(2) loop.
Overview:
Transmit files:
1 Init ZModem structure and open communications channel.
2 Call ZmodemTInit() to begin protocol.
3 Read characters from remote end and pass them to
ZmodemRcv() until ZmodemRcv() returns ZmDone or an error.
4 Call ZmodemTFile() to begin transfer of a file.
5 Read characters from remote end and pass them to
ZmodemRcv() until ZmodemRcv() returns ZmDone or an error.
6 repeat steps 4&5 for all files.
7 Call ZmodemTFinish() to indicate that all files have been
transfered.
8 Read characters from remote end and pass them to
ZmodemRcv() until ZmodemRcv() returns ZmDone or an error.
Receive files:
1 Init ZModem structure and open communications channel.
2 Call ZmodemRInit() to begin protocol.
3 Read characters from remote end and pass them to
ZmodemRcv() until ZmodemRcv() returns ZmDone or an error.
In detail:
1) Create a ZModem structure as defined below and fill it in.
'ifd', 'ofd' are the file descriptors used for input and output.
The interpretation of ifd and ofd is entirely up to the calling
routines, since the caller will be providing I/O functions.
'zrinitflags' is composed of the flags described below.
They describe the receive channel capabilities
and affect how the protocol will be carried out.
Define these to receive files. When sending files, these
flags will be defined from the remote end.
'zsinitflags' is composed of the flags described below.
They describe the transmit channel capabilities
and affect how the protocol will be carried out.
Define these to send files. When receiving files, these
flags will be defined from the remote end.
'attn': For transmit, this is the optional nul-terminated
attention string to be sent by the receiver to interrupt the
transmission. For example, it might simply contain ^O to flush
the buffers, or it might interrupt the sending program. Caller
needs to handle this interrupt properly and call ZmodemAttention().
For receive, this is the optional nul-terminated attention string
defined at the remote end. Caller needs to provide a function that
can execute this sequence.
'timeout' is read-only, set by the zmodem package. It is the
timeout value in seconds. If this much time passes without
anything being received, caller should call the ZmodemTimeout()
function. Note that timeout may be zero, in which case the
ZTimeout function should be called immediately if no characters
are ready to be received.
'packetsize' is set to the preferred data packet size. Define
this when sending files. Recommended length values are 256
bytes below 2400 bps, 512 at 2400 bps, and 1024 above 4800 bps
or when the data link is known to be relatively error free.
Ignored during receive.
'bufsize' is set to the size of the receive buffer size. Define
this when receiving files. When sending files, this will be
defined at the other end.
'windowsize' is used to prevent network connections from
buffering too many characters during transmit. Setting
'windowsize' to nonzero causes zmodem to request status reports
from the receiver during transmit, and to pause if more than
this many bytes have been sent but not yet acknowledged. Set
to zero to turn off windowing. Ignored during receive.
Other fields are used to track the internal state of the zmodem
driver functions.
Since this is a source package, you are, of course, free to extend
the ZModem structure as you see fit.
2) Define the following functions:
int
ZXmitStr(u_char *str, int len, ZModem *info)
Transmit a buffer. Return 0 on success, ZmErrSys on error.
void
ZIFlush(ZModem *info)
Flush all unread input on receive channel. Do nothing if
this is not possible.
void
ZOFlush(ZModem *info)
Flush all buffered but not-yet-transmitted output
on transmit channel. Do nothing if this is not possible.
int
ZAttn(ZModem *info)
Send attention signal defined in ZModem->attn. Do
nothing if this field is NULL. Otherwise, this field
is a nul-terminated character string to be
transmitted. There are two special characters defined
below: ATTNBRK (0335) indicates that a BREAK signal
should be sent, and ATTNPSE (0336) represents a
1-second pause.
void
ZFlowControl(int onoff, ZModem *info)
Turn flow control on or off depending on the onoff flag.
void
ZStatus(int type, int value, char *status)
Called to provide status information. Ignore or display
at your option. Status string is not static, so copy
it if you need it beyond this call. Type is defined
below under "ZStatus() types".
FILE *
ZOpenFile(char *name, u_long crc, ZModem *info)
Called when receiving files, this function decides
whether or not to accept the specified file, and
if so, opens it for writing and returns the stdio
file handle. If this function decides not to accept
the file, or cannot open the file, it returns NULL
and the remote sender is told to skip this file.
info->f0-f3 are the transfer flags, described below under
"ZFILE transfer flags". These describe the type of
transfer desired (binary/ascii), and conditions for the
transfer, such as 'transfer if source newer or longer'.
info->len is the length of the file in bytes. info->date is
the last modification date of the file, in seconds since
1-jan-1970. info->mode is the unix file mode + 01000000, or
zero if not known. info->filesRem and info->bytesRem are the
number of files and bytes remaining to be transferred
if known, zero otherwise. 'crc' is the file crc-32 value.
This is only provided if F1 contains ZMCRC.
int
ZWriteFile(u_char *buffer, int len, FILE *file, ZModem *info)
Write a buffer of data to the file. Normally, you would
simply call fwrite(buffer, 1, len, file), but you may
want to translate line endings, etc. File transfer
flags are available as info->f0,f1,f2,f3.
Return 0 on success, ZmErrSys on failure, with errno
describing the failure.
int
ZCloseFile(ZModem *info)
Close file after successful completion. File modification
date and modes should be set at this time.
void
ZIdleStr(u_char *buffer, int len, ZModem *info)
Called to pass text that is received out-of-protocol.
This function may ignore or display this text at your
option.
3) Open the communications channel.
If possible, this should be a full-duplex channel with full
8-bit transmission. Hardware flow control and/or XON/XOFF
flow control should be enabled.
4) Call these routines:
All functions return 0 on success, nonzero on failure. See
"error code definitions", below.
Send:
int
ZmodemTInit(ZModem *info)
Begin a Zmodem transmit session.
int
ZmodemRcv(u_char *buffer, int len, ZModem *info)
Call whenever characters are received. If this function
returns ZmDone, previous function has completed successfully,
either call ZmodemTFile() to start next file, or call
ZmodemTFinish() to terminate the session.
int
ZmodemTimeout(ZModem *info)
Call whenever the timeout period expires and no
characters have been received.
int
ZmodemAttention(ZModem *info)
Call whenever the attention sequence has been received
from the remote end. It is safe to call this function
from an interrupt handler.
int
ZmodemTFile(char *filename, char *rfilename,
u_char f0,f1,f2,f3, int filesRem, int bytesRem, ZModem *info)
Begin transmitting a file. If filename is not NULL,
then this function will open it. Otherwise, info->file
must point to a stdio stream that is open for input.
It is preferable to provide the filename, so that
Zmodem can transmit file size and other information.
'rfilename' is the filename given to the remote end.
This may be the same as filename, the file part of
filename, or something else alltogether. 'rfilename'
must not be longer than the smallest data packet the
remote end might be willing to receive (about 200
characters). f0-f3 are transfer flags, see "ZCBIN"
below. 'filesRem' and 'bytesRem' are the number of files
and bytes remaining to be transmitted, if known; zero if
not.
If 'filename' cannot be accessed, ZmodemTFile() returns
ZmErrCantOpen. The link is still established, so you
need to either proceed with the next file or call
ZmodemTFinish().
int
ZmodemTFinish(ZModem *info)
Call after final file transfer has completed successfully.
int
ZmodemAbort(ZModem *info)
Call to abort transfer. Physical connection remains
open until you close it.
Receive:
int
ZmodemRInit(ZModem *info)
Call to get ready to receive first file. This function
will inform the sender that we are ready to receive.
int
ZmodemRcv(u_char *buffer, int len, ZModem *info)
Call whenever characters are received. If this
function returns ZmDone, all file transfers have
completed successfully.
int
ZmodemTimeout(ZModem *info)
Call whenever the timeout period expires and no
characters have been received.
int
ZmodemAbort(ZModem *info)
Call to abort transfer.
Ymodem and Xmodem:
int YmodemTInit(ZModem *info)
int XmodemTInit(ZModem *info)
int YmodemRInit(ZModem *info)
int XmodemRInit(ZModem *info)
Same semantics as ZmodemTInit and ZmodemRInit. It is
not normally necessary to call the Ymodem*Init() functions
as the Zmodem protocol will automatically switch to Ymodem
when needed.
Utility:
u_long
FileCrc(char *name)
Return CRC-32 of file.
5) Return Values:
ZmDone Done. Proceed with next file or ZmodemTFinish
(transmit) or exit (receive).
ZmErrInt Internal error. Link has been closed.
ZmErrSys System error, see errno. Link is closed.
ZmErrNotOpen not used.
ZmFileTooLong not used.
ZmFileCantWrite not used.
ZmErrCantOpen Can not open file, see errno. Link is still open.
ZmErrInitTo Transmitter failed to respond to init req. Link closed.
ZmErrSequence Packet received out of sequence. Link is closed.
ZmErrCancel Cancelled by remote end. Link is closed.
ZmErrRcvTo Remote end timed out during transfer. Link is closed.
ZmErrSndTo Remote end timed out during transfer. Link is closed.
ZmErrCmdTo Remote end timed out during transfer. Link is closed.
Note that "link is closed" means that the remote end is (presumably)
no longer operating. The actual communications channel is not
closed unless you close it. "Link is still open" means that the
remote end is still ready to receive the next file.
#endif
/* PARAMETERS
*
* The following #defines control the behavior of the Zmodem
* package. Note that these may be replaced with variables
* if you like. For example, "#define DoInitRZ" may be replaced
* with "extern int DoInitRz" to use a global variable, or with
* "#define DoInitRZ (info->doInitRz)" to use a variable you
* add to the ZModem structure.
*
* It is assumed that the compiler is good enough to optimize
* "if( 0 )" and "if( 1 )" cases. If not, you may wish to modify
* the source code to use #ifdef instead.
*/
#define DoInitRZ 1 /* send initial "rz\r" when transmitting */
#define AllowCommand 0 /* allow remote end to execute commands */
#define SendSample 1 /* sender can sample reverse channel */
#define SendAttn 1 /* sender can be interrupted with Attn signal */
#define ResponseTime 10 /* reasonable response time for sender to
* respond to requests from receiver */
#define SerialNo 1 /* receiver serial # */
#define MaxNoise 64 /* max "noise" characters before transmission
* pauses */
#define MaxErrs 20 /* Max receive errors before cancel */
#define AlwaysSinit 1 /* always send ZSINIT header, even if not
* needed, this makes protocol more robust */
#define SendOnly 0 /* compiles smaller version for send only */
#define RcvOnly 0 /* compiles smaller version for receive only */
/* constants */
#include <stdio.h>
#include <sys/types.h>
/* Internal State */
typedef enum zmstate {
/* receive */
RStart, /* sent RINIT, waiting for ZFILE or SINIT */
RSinitWait, /* got SINIT, waiting for data */
RFileName, /* got ZFILE, waiting for filename & info */
RCrc, /* got filename, want crc too */
RFile, /* got filename, ready to read */
RData, /* reading data */
RDataErr, /* encountered error, ignoring input */
RFinish, /* sent ZFIN, waiting for 'OO' */
/* transmit */
TStart, /* waiting for INIT frame from other end */
TInit, /* received INIT, sent INIT, waiting for ZACK */
FileWait, /* sent file header, waiting for ZRPOS */
CrcWait, /* sent file crc, waiting for ZRPOS */
Sending, /* sending data subpackets, ready for int */
SendWait, /* waiting for ZACK */
SendDone, /* file finished, need to send EOF */
SendEof, /* sent EOF, waiting for ZACK */
TFinish, /* sent ZFIN, waiting for ZFIN */
/* general */
CommandData, /* waiting for command data */
CommandWait, /* waiting for command to execute */
StderrData, /* waiting for stderr data */
Done,
/* x/ymodem transmit */
YTStart, /* waiting for 'G', 'C' or NAK */
YTFile, /* sent filename, waiting for ACK */
YTDataWait, /* ready to send data, waiting for 'C' */
YTData, /* sent data, waiting for ACK */
YTEOF, /* sent eof, waiting for ACK */
YTFin, /* sent null filename, waiting for ACK */
/* x/ymodem receive */
YRStart, /* sent 'C', waiting for filename */
YRDataWait, /* received filename, waiting for data */
YRData, /* receiving filename or data */
YREOF /* received first EOT, waiting for 2nd */
} ZMState ;
typedef struct {
int ifd ; /* input fd, for use by caller's routines */
int ofd ; /* output fd, for use by caller's routines */
FILE *file ; /* file being transfered */
int zrinitflags ; /* receiver capabilities, see below */
int zsinitflags ; /* sender capabilities, see below */
char *attn ; /* attention string, see below */
int timeout ; /* timeout value, in seconds */
int bufsize ; /* receive buffer size, bytes */
int packetsize ; /* preferred transmit packet size */
int windowsize ; /* max window size */
/* file attributes: read-only */
int filesRem, bytesRem ;
u_char f0,f1,f2,f3 ; /* file flags */
int len,mode,fileType ; /* file flags */
u_long date ; /* file date */
/* From here down, internal to Zmodem package */
ZMState state ; /* protocol internal state */
char *filename ; /* filename */
char *rfilename ; /* remote filename */
int crc32 ; /* use 32-bit crc */
int pktLen ; /* length of this packet */
int DataType ; /* input data type */
int PacketType ; /* type of this packet */
int rcvlen ;
int chrCount ; /* chars received in current header/buffer */
int crcCount ; /* crc characters remaining at end of buffer */
int canCount ; /* how many CAN chars received? */
int noiseCount ; /* how many noise chars received? */
int errorFlush ; /* ignore incoming data because of error */
u_char *buffer ; /* data buffer */
u_long offset ; /* file offset */
u_long lastOffset ; /* last acknowledged offset */
u_long zrposOffset ; /* last offset specified w/zrpos */
int ylen, bufp ; /* len,location of last Ymodem packet */
int fileEof ; /* file eof reached */
int packetCount ; /* # packets received */
int errCount ; /* how many data errors? */
int timeoutCount ; /* how many times timed out? */
int windowCount ; /* how much data sent in current window */
int atSign ; /* last char was '@' */
int lastCR ; /* last char was CR */
int escCtrl ; /* other end requests ctrl chars be escaped */
int escHibit ; /* other end requests hi bit be escaped */
int escape ; /* next character is escaped */
int interrupt ; /* received attention signal */
int waitflag ; /* next send should wait */
/* parser state */
enum {Idle, Padding, Inhdr, Indata, Finish, Ysend, Yrcv} InputState ;
enum {XMODEM, YMODEM, ZMODEM} Protocol ;
u_char hdrData[9] ; /* header type and data */
u_char fileFlags[4] ; /* file xfer flags */
u_long crc ; /* crc of incoming header/data */
enum {Full, StrWindow, SlidingWindow, Segmented} Streaming ;
} ZModem ;
/* ZRINIT flags. Describe receiver capabilities */
#define CANFDX 1 /* Rx is Full duplex */
#define CANOVIO 2 /* Rx can overlap I/O */
#define CANBRK 4 /* Rx can send a break */
#define CANCRY 010 /* Rx can decrypt */
#define CANLZW 020 /* Rx can uncompress */
#define CANFC32 040 /* Rx can use 32-bit crc */
#define ESCCTL 0100 /* Rx needs control chars escaped */
#define ESC8 0200 /* Rx needs 8th bit escaped. */
/* ZSINIT flags. Describe sender capabilities */
#define TESCCTL 0100 /* Tx needs control chars escaped */
#define TESC8 0200 /* Tx needs 8th bit escaped. */
/* ZFILE transfer flags */
/* F0 */
#define ZCBIN 1 /* binary transfer */
#define ZCNL 2 /* convert NL to local eol convention */
#define ZCRESUM 3 /* resume interrupted file xfer, or append to a
growing file. */
/* F1 */
#define ZMNEWL 1 /* transfer if source newer or longer */
#define ZMCRC 2 /* transfer if different CRC or length */
#define ZMAPND 3 /* append to existing file, if any */
#define ZMCLOB 4 /* replace existing file */
#define ZMNEW 5 /* transfer if source is newer */
#define ZMDIFF 6 /* transfer if dates or lengths different */
#define ZMPROT 7 /* protect: transfer only if dest doesn't exist */
#define ZMCHNG 8 /* change filename if destination exists */
#define ZMMASK 037 /* mask for above. */
#define ZMSKNOLOC 0200 /* skip if not present at Rx end */
/* F2 */
#define ZTLZW 1 /* lzw compression */
#define ZTRLE 3 /* run-length encoding */
/* F3 */
#define ZCANVHDR 1 /* variable headers ok */
#define ZRWOVR 4 /* byte position for receive window override/256 */
#define ZXSPARS 64 /* encoding for sparse file ops. */
/* ATTN string special characters. All other characters sent verbose */
#define ATTNBRK '\335' /* send break signal */
#define ATTNPSE '\336' /* pause for one second */
/* ZStatus() types */
#define RcvByteCount 0 /* value is # bytes received */
#define SndByteCount 1 /* value is # bytes sent */
#define RcvTimeout 2 /* receiver did not respond, aborting */
#define SndTimeout 3 /* value is # of consecutive send timeouts */
#define RmtCancel 4 /* remote end has cancelled */
#define ProtocolErr 5 /* protocol error has occurred, val=hdr */
#define RemoteMessage 6 /* message from remote end */
#define DataErr 7 /* data error, val=error count */
#define FileErr 8 /* error writing file, val=errno */
#define FileBegin 9 /* file transfer begins, str=name */
#define FileEnd 10 /* file transfer ends, str=name */
#define FileSkip 11 /* file being skipped, str=name */
/* error code definitions [O] means link still open */
#define ZmDone -1 /* done */
#define ZmErrInt -2 /* internal error */
#define ZmErrSys -3 /* system error, see errno */
#define ZmErrNotOpen -4 /* communication channel not open */
#define ZmErrCantOpen -5 /* can't open file, see errno [O] */
#define ZmFileTooLong -6 /* remote filename too long [O] */
#define ZmFileCantWrite -7 /* could not write file, see errno */
#define ZmDataErr -8 /* too many data errors */
#define ZmErrInitTo -10 /* transmitter failed to respond to init req. */
#define ZmErrSequence -11 /* packet received out of sequence */
#define ZmErrCancel -12 /* cancelled by remote end */
#define ZmErrRcvTo -13 /* remote receiver timed out during transfer */
#define ZmErrSndTo -14 /* remote sender timed out during transfer */
#define ZmErrCmdTo -15 /* remote command timed out */
/* zmodem-supplied functions: */
extern int ZmodemTInit(ZModem *info) ;
extern int ZmodemTFile(char *file, char *rmtname,
u_int f0, u_int f1, u_int f2, u_int f3,
int filesRem, int bytesRem, ZModem *info) ;
extern int ZmodemTFinish(ZModem *info) ;
extern int ZmodemAbort(ZModem *info) ;
extern int ZmodemRInit(ZModem *info) ;
extern int ZmodemRcv(u_char *str, int len, ZModem *info) ;
extern int ZmodemTimeout(ZModem *info) ;
extern int ZmodemAttention(ZModem *info) ;
extern int YmodemTInit(ZModem *info) ;
extern int XmodemTInit(ZModem *info) ;
extern int YmodemRInit(ZModem *info) ;
extern int XmodemRInit(ZModem *info) ;
extern u_long FileCrc(char *name) ;
extern char *sname(ZModem *) ;
extern char *sname2(ZMState) ;
#ifdef DEBUG
extern FILE *zmodemlogfile ;
extern void zmodemlog(const char *, ...) ;
#else
#define zmodemlog
#endif
/* caller-supplied functions: */
extern int ZXmitChr(u_char c, ZModem *info) ;
extern int ZXmitStr(u_char *str, int len, ZModem *info) ;
extern void ZIFlush(ZModem *info) ;
extern void ZOFlush(ZModem *info) ;
extern int ZAttn(ZModem *info) ;
extern void ZStatus(int type, int value, char *status) ;
extern FILE *ZOpenFile(char *name, u_long crc, ZModem *info) ;
/* From here on down, internal to Zmodem package */
/* ZModem character definitions */
#define ZDLE 030 /* zmodem escape is CAN */
#define ZPAD '*' /* pad */
#define ZBIN 'A' /* introduces 16-bit crc binary header */
#define ZHEX 'B' /* introduces 16-bit crc hex header */
#define ZBIN32 'C' /* introduces 32-bit crc binary header */
#define ZBINR32 'D' /* introduces RLE packed binary frame w/32-bit crc */
#define ZVBIN 'a' /* alternate ZBIN */
#define ZVHEX 'b' /* alternate ZHEX */
#define ZVBIN32 'c' /* alternate ZBIN32 */
#define ZVBINR32 'd' /* alternate ZBINR32 */
#define ZRESC 0177 /* RLE flag/escape character */
/* ZModem header type codes */
#define ZRQINIT 0 /* request receive init */
#define ZRINIT 1 /* receive init */
#define ZSINIT 2 /* send init sequence, define Attn */
#define ZACK 3 /* ACK */
#define ZFILE 4 /* file name, from sender */
#define ZSKIP 5 /* skip file command, from receiver */
#define ZNAK 6 /* last packet was garbled */
#define ZABORT 7 /* abort */
#define ZFIN 8 /* finish session */
#define ZRPOS 9 /* resume file from this position, from receiver */
#define ZDATA 10 /* data packets to follow, from sender */
#define ZEOF 11 /* end of file, from sender */
#define ZFERR 12 /* fatal i/o error, from receiver */
#define ZCRC 13 /* request for file crc, from receiver */
#define ZCHALLENGE 14 /* "send this number back to me", from receiver */
#define ZCOMPL 15 /* request is complete */
#define ZCAN 16 /* other end cancelled with CAN-CAN-CAN-CAN-CAN */
#define ZFREECNT 17 /* request for free bytes on filesystem */
#define ZCOMMAND 18 /* command, from sending program */
#define ZSTDERR 19 /* output this message to stderr */
/* ZDLE escape sequences */
#define ZCRCE 'h' /* CRC next, frame ends, header follows */
#define ZCRCG 'i' /* CRC next, frame continues nonstop */
#define ZCRCQ 'j' /* CRC next, send ZACK, frame continues nonstop */
#define ZCRCW 'k' /* CRC next, send ZACK, frame ends */
#define ZRUB0 'l' /* translate to 0177 */
#define ZRUB1 'm' /* translate to 0377 */
/* ascii definitions */
#define SOH 1 /* ^A */
#define STX 2 /* ^B */
#define EOT 4 /* ^D */
#define ACK 6 /* ^F */
#define DLE 16 /* ^P */
#define XON 17 /* ^Q */
#define XOFF 19 /* ^S */
#define NAK 21 /* ^U */
#define SYN 22 /* ^V */
#define CAN 24 /* ^X */
extern int ZXmitHdr() ;
extern int ZXmitHdrHex() ;
extern int ZXmitHdrBin() ;
extern int ZXmitHdrBin32() ;
extern u_char *putZdle( u_char *ptr, u_char c, ZModem *info ) ;
extern u_char *ZEnc4() ;
extern u_long ZDec4() ;
/* state table entry. There is one row of the table per
* possible state. Each row is a row of all reasonable
* inputs for this state. The entries are sorted so that
* the most common inputs occur first, to reduce search time
* Unexpected input is reported and ignored, as it might be
* caused by echo or something.
*
* Extra ZRINIT headers are the receiver trying to resync.
*/
typedef struct {
int type ; /* frame type */
int (*func)() ; /* transition function */
int IFlush ; /* flag: flush input first */
int OFlush ; /* flag: flush output first */
ZMState newstate ; /* new state. May be overridden by func */
} StateTable ;
#endif

582
Xmodem/zmodemdump.c Normal file
View File

@ -0,0 +1,582 @@
#ifndef lint
static const char rcsid[] = "$Id: zmodemdump.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
/* variation on serialmon companion program serialdump, which
* interprets data as a zmodem dialog
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sys/termios.h>
#include <sys/types.h>
#include <sys/time.h>
#include <assert.h>
#include "crctab.h"
#define MAXBUF 2048
#define MAXLINE 16
#define MAXHBUF 128
#define OLINELEN (MAXLINE*2)
#define CAN 030
#define XON 021
#define ZDLE 030
#define ZPAD '*'
#define ZBIN 'A'
#define ZHEX 'B'
#define ZBIN32 'C'
#define ZBINR32 'D'
#define ZVBIN 'a'
#define ZVHEX 'b'
#define ZVBIN32 'c'
#define ZVBINR32 'd'
#define ZRESC 0177
#define ZRQINIT 0 /* request receive init */
#define ZRINIT 1 /* receive init */
#define ZSINIT 2 /* send init sequence, define Attn */
#define ZACK 3 /* ACK */
#define ZFILE 4 /* file name, from sender */
#define ZSKIP 5 /* skip file command, from receiver */
#define ZNAK 6 /* last packet was garbled */
#define ZABORT 7 /* abort */
#define ZFIN 8 /* finish session */
#define ZRPOS 9 /* resume file from this position, from receiver */
#define ZDATA 10 /* data packets to follow, from sender */
#define ZEOF 11 /* end of file, from sender */
#define ZFERR 12 /* fatal i/o error, from receiver */
#define ZCRC 13 /* request for file crc, from receiver */
#define ZCHALLENGE 14 /* "send this number back to me", from receiver */
#define ZCOMPL 15 /* request is complete */
#define ZCAN 16 /* other end cancelled with CAN-CAN-CAN-CAN-CAN */
#define ZFREECNT 17 /* request for free bytes on filesystem */
#define ZCOMMAND 18 /* command, from sending program */
#define ZSTDERR 19 /* output this message to stderr */
#define ZCRCE 'h'
#define ZCRCG 'i'
#define ZCRCQ 'j'
#define ZCRCW 'k'
#define ZRUB0 'l'
#define ZRUB1 'm'
typedef enum {Idle, Padding, HexHeader, Header16, Header32,
InData, InCrc} ZState ;
typedef struct {
ZState state ;
int headertype ;
int data[4] ;
int crcBytes[4] ;
int count ;
int zdlePend ; /* ZDLE received */
int crcCmd ;
int crclen ;
u_long crc ;
} Zinfo ;
u_char buffer[MAXBUF] ;
u_char line[MAXLINE] ;
u_char hbuffer[MAXHBUF] ;
int linecnt = 0 ;
int hbufcnt = 0 ;
main( int argc, char **argv )
{
int i,j ;
int len ;
int which ;
struct timeval timestamp, oldtime ;
struct tm *tm ;
Zinfo Ainfo, Binfo ;
printf("serial log. 'A' is application, 'B' is serial port\n\n") ;
oldtime.tv_sec = 0 ;
Ainfo.state = Binfo.state = Idle ;
Ainfo.zdlePend = Binfo.zdlePend = 0 ;
while( (i=fread((char *)&which, sizeof(which), 1, stdin)) > 0 )
{
i = fread((char *)&timestamp, sizeof(timestamp), 1, stdin) ;
i = fread((char *)&len, sizeof(len), 1, stdin) ;
if( timestamp.tv_sec != oldtime.tv_sec ||
timestamp.tv_usec != oldtime.tv_usec )
{
if( linecnt > 0 )
dumpLine() ;
tm = localtime(&timestamp.tv_sec) ;
printf("%c: %2d:%2.2d:%2.2d.%2.2d\n", 'A'+which,
tm->tm_hour,tm->tm_min,tm->tm_sec, timestamp.tv_usec/10000 ) ;
oldtime = timestamp ;
}
while( len > 0 )
{
i = MAXBUF ;
if( len < i ) i = len ;
j = fread(buffer, 1, i, stdin) ;
assert(j <= MAXBUF) ;
len -= j ;
parseData(which ? &Binfo : &Ainfo, j) ;
}
while( len > 0 )
{
i = MAXLINE - linecnt ;
if( len < i ) i = len ;
assert(linecnt+i <= MAXLINE) ;
j = fread(line+linecnt, 1, i, stdin) ;
assert(linecnt+j <= MAXLINE) ;
len -= j ;
linecnt += j ;
if( linecnt >= MAXLINE )
dumpLine() ;
}
}
if( linecnt > 0 )
dumpLine() ;
exit(0) ;
}
char
toprintable(char c)
{
c &= 0177 ;
if( c >= 0x20 && c <= 0x7e )
return c ;
else
return '.' ;
}
dumpLine()
{
int i,j ;
if( linecnt <= 0 )
return ;
if( linecnt > MAXLINE ) linecnt = MAXLINE ;
printf(" ") ;
for(i=0; i<linecnt; ++i) {
assert(i <= MAXLINE) ;
printf("%2.2x ", line[i]) ;
}
for(; i<MAXLINE; ++i)
printf(" ") ;
printf("\t|") ;
for(i=0; i<linecnt; ++i) {
assert(i <= MAXLINE) ;
printf("%c",toprintable(line[i])) ;
}
printf("|\n") ;
linecnt = 0 ;
}
static u_char hexHeaderStart[] = {ZPAD,ZPAD,ZDLE,ZHEX} ;
static u_char header16Start[] = {ZPAD,ZDLE,ZBIN} ;
static u_char header32Start[] = {ZPAD,ZDLE,ZBIN32} ;
parseData( Zinfo *info, int len )
{
u_char *ptr, c ;
int idx ;
for(ptr = buffer; --len >= 0; ptr++) {
assert(ptr >= buffer && ptr < buffer+MAXBUF) ;
c = *ptr ;
if( c != XON )
switch( info->state ) {
case Idle:
if( c != ZPAD )
dataChar(c) ;
else {
info->state = Padding ;
info->count = 1 ;
hbuffer[0] = c ;
}
break ;
case Padding:
if( c == ZDLE ) {
info->zdlePend = 1 ;
}
else if( info->zdlePend ) {
info->zdlePend = 0 ;
info->count = 0 ;
switch(c) {
case ZHEX:
info->state = HexHeader ;
info->crclen=2 ;
info->crc = 0 ;
break ;
case ZBIN:
info->state = Header16 ;
info->crclen=2 ;
info->crc = 0 ;
break ;
case ZBIN32:
info->state = Header32 ;
info->crclen=4 ;
info->crc = 0xffffffff ;
break ;
default:
cancelHeader(info) ; break ;
}
}
else if( c == ZPAD )
{
if( info->count < 2 ) {
assert(info->count < MAXHBUF) ;
hbuffer[info->count++] = c ;
}
else
dataChar(c) ;
}
else
cancelHeader(info) ; break ;
break ;
case HexHeader:
if( c == ZDLE && !info->zdlePend ) {
info->zdlePend = 1 ;
break ;
}
if( info->zdlePend ) {
c = zdle(c) ;
info->zdlePend = 0 ;
}
idx = info->count++ ;
assert(idx < MAXHBUF) ;
hbuffer[idx] = c ;
if( info->count >= 16 ) { /* end of header */
info->headertype = hex2(hbuffer+0) ;
info->data[0] = hex2(hbuffer+2) ;
info->data[1] = hex2(hbuffer+4) ;
info->data[2] = hex2(hbuffer+6) ;
info->data[3] = hex2(hbuffer+8) ;
info->crcBytes[0] = hex2(hbuffer+10) ;
info->crcBytes[1] = hex2(hbuffer+12) ;
displayHeader(info) ;
}
break ;
case Header16:
if( c == ZDLE && !info->zdlePend ) {
info->zdlePend = 1 ;
break ;
}
if( info->zdlePend ) {
c = zdle(c) ;
info->zdlePend = 0 ;
}
idx = info->count++ ;
assert(idx < MAXHBUF) ;
hbuffer[idx] = c ;
if( info->count >= 7 ) { /* end of header */
info->headertype = hbuffer[0] ;
info->data[0] = hbuffer[1] ;
info->data[1] = hbuffer[2] ;
info->data[2] = hbuffer[3] ;
info->data[3] = hbuffer[4] ;
info->crcBytes[0] = hbuffer[5] ;
info->crcBytes[1] = hbuffer[6] ;
displayHeader(info) ;
}
break ;
case Header32:
if( c == ZDLE && !info->zdlePend ) {
info->zdlePend = 1 ;
break ;
}
if( info->zdlePend ) {
c = zdle(c) ;
info->zdlePend = 0 ;
}
idx = info->count++ ;
assert(idx < MAXHBUF) ;
hbuffer[idx] = c ;
if( info->count >= 9 ) { /* end of header */
info->headertype = hbuffer[0] ;
info->data[0] = hbuffer[1] ;
info->data[1] = hbuffer[2] ;
info->data[2] = hbuffer[3] ;
info->data[3] = hbuffer[4] ;
info->crcBytes[0] = hbuffer[5] ;
info->crcBytes[1] = hbuffer[6] ;
info->crcBytes[2] = hbuffer[7] ;
info->crcBytes[3] = hbuffer[8] ;
displayHeader(info) ;
}
break ;
case InData:
if( info->zdlePend )
{
info->zdlePend = 0 ;
switch( c ) {
case ZCRCE:
case ZCRCW:
case ZCRCG:
case ZCRCQ:
info->crcCmd = c ;
dumpLine() ;
info->state = InCrc ;
info->count = 0 ;
break ;
default:
c = zdle(c) ;
dataChar(c) ;
break ;
}
}
else if( c == ZDLE )
info->zdlePend = 1 ;
else
dataChar(c) ;
break ;
case InCrc:
if( info->zdlePend ) {
c = zdle(c) ;
info->zdlePend = 0 ;
}
if( c == ZDLE )
info->zdlePend = 1 ;
else
{
dataChar(c) ;
if( ++info->count >= info->crclen )
{
dumpCrc() ;
switch( info->crcCmd ) {
case ZCRCE:
printf(" ZCRCE: end of frame, header follows\n") ;
info->state = Idle ;
break ;
case ZCRCW:
printf(" ZCRCW: end of frame, send ZACK\n") ;
info->state = Idle ;
break ;
case ZCRCG:
printf(" ZCRCG: more data follows:\n") ;
info->state = InData ;
break ;
case ZCRCQ:
printf(" ZCRCQ: send ZACK, more data follows:\n") ;
info->state = InData ;
break ;
}
}
}
break ;
}
}
}
/* handle a character that's not part of the protocol */
dataChar(int c)
{
assert(linecnt < MAXLINE) ;
line[linecnt++] = c ;
if( linecnt >= MAXLINE )
dumpLine() ;
}
/* here if we thought we were in a header, but were wrong */
cancelHeader( Zinfo *info )
{
int i ;
for(i=0; i<info->count; ++i) {
assert(i < MAXHBUF) ;
dataChar(hbuffer[i]) ;
}
info->state = Idle ;
}
/* here to display a full header. CRC's not currently checked */
displayHeader( Zinfo *info )
{
int i ;
u_long crc ;
int h32 = info->state == Header32 ;
static char *names[] = {
"ZRQINIT", "ZRINIT", "ZSINIT", "ZACK", "ZFILE", "ZSKIP",
"ZNAK", "ZABORT", "ZFIN", "ZRPOS", "ZDATA", "ZEOF", "ZFERR",
"ZCRC", "ZCHALLENGE", "ZCOMPL", "ZCAN", "ZFREECNT",
"ZCOMMAND", "ZSTDERR",} ;
dumpLine() ;
printf(" ") ;
switch( info->state ) {
case HexHeader: printf("hex header") ; break ;
case Header16: printf("bin header") ; break ;
case Header32: printf("bin32 header") ; break ;
}
printf(" %d: %s: d=[%x %x %x %x]", info->headertype,
info->headertype <= ZSTDERR ? names[info->headertype] : "BAD HEADER",
info->data[0], info->data[1], info->data[2], info->data[3]) ;
switch( info->state ) {
case HexHeader:
case Header16:
printf(" crc=[%x %x]", info->crcBytes[0], info->crcBytes[1]) ;
break ;
case Header32:
printf(" crc=[%x %x %x %x]",
info->crcBytes[0], info->crcBytes[1],
info->crcBytes[2], info->crcBytes[3]) ;
break ;
}
switch( info->headertype ) {
case ZRQINIT:
case ZRINIT:
case ZACK:
case ZSKIP:
case ZNAK:
case ZABORT:
case ZFIN:
case ZRPOS:
case ZEOF:
case ZFERR:
case ZCRC:
case ZCHALLENGE:
case ZCOMPL:
case ZCAN:
case ZFREECNT:
case ZCOMMAND:
printf("\n") ;
info->state = Idle ;
break ;
case ZSINIT:
case ZFILE:
case ZDATA:
case ZSTDERR:
printf(", data follows:\n") ;
info->state = InData ;
info->count = 0 ;
break ;
}
if( !h32 )
{
crc = 0 ;
crc = updcrc(info->headertype, crc) ;
crc = updcrc(info->data[0], crc) ;
crc = updcrc(info->data[1], crc) ;
crc = updcrc(info->data[2], crc) ;
crc = updcrc(info->data[3], crc) ;
crc = updcrc(info->crcBytes[0], crc) ;
crc = updcrc(info->crcBytes[1], crc) ;
if( crc&0xffff != 0 )
printf(" CRC ERROR\n") ;
}
else
{
crc = 0xffffffff ;
crc = UPDC32(info->headertype, crc) ;
crc = UPDC32(info->data[0], crc) ;
crc = UPDC32(info->data[1], crc) ;
crc = UPDC32(info->data[2], crc) ;
crc = UPDC32(info->data[3], crc) ;
crc = UPDC32(info->crcBytes[0], crc) ;
crc = UPDC32(info->crcBytes[1], crc) ;
crc = UPDC32(info->crcBytes[2], crc) ;
crc = UPDC32(info->crcBytes[3], crc) ;
if( crc != 0xdebb20e3 )
printf(" CRC ERROR\n") ;
}
}
dumpCrc()
{
int i,j ;
if( linecnt <= 0 )
return ;
if( linecnt > MAXLINE ) linecnt = MAXLINE ;
printf(" crc: ") ;
for(i=0; i<linecnt; ++i) {
assert(i < MAXLINE) ;
printf("%2.2x ", line[i]) ;
}
printf("\n") ;
linecnt = 0 ;
}
/* return value of 2 hex digits */
int
hex2(char *chrs)
{
return (hex1(chrs[0]) << 4) + hex1(chrs[1]) ;
}
/* return value of a hex digit */
int
hex1(int chr)
{
chr -= '0' ;
if( chr > 9 )
chr -= 'A'-'0'-10 ;
if( chr > 15 )
chr -= 'a' - 'A' ;
return chr ;
}
/* apply ZDLE to chr */
int
zdle(int chr)
{
switch( chr ) {
case ZRUB0: return 0177 ;
case ZRUB1: return 0377 ;
default:
if( (chr & 0140) == 0100 )
return chr ^ 0100 ;
return -1 ;
}
}

750
Xmodem/zmodemr.c Normal file
View File

@ -0,0 +1,750 @@
#ifndef lint
static const char rcsid[] = "$Id: zmodemr.c,v 1.1.1.1 2001/03/08 00:01:48 efalk Exp $" ;
#endif
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @@@@@ @ @ @@@ @@@@ @@@@@ @ @ @@@@
* @ @@ @@ @ @ @ @ @ @@ @@ @ @
* @ @ @ @ @ @ @ @ @@@ @ @ @ @@@@
* @ @ @ @ @ @ @ @ @ @ @ @ @ @
* @@@@@ @ @ @ @@@ @@@@ @@@@@ @ @ @ @ @
*
* ZMODEMR - receive side of zmodem protocol
*
* receive side of zmodem protocol
*
* This code is designed to be called from inside a larger
* program, so it is implemented as a state machine where
* practical.
*
* functions:
*
* ZmodemRInit(ZModem *info)
* Initiate a connection
*
* ZmodemRAbort(ZModem *info)
* abort transfer
*
* all functions return 0 on success, 1 on failure
*
*
* Edward A. Falk
*
* January, 1995
*
*
*
**********/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "zmodem.h"
#include "crctab.h"
extern int errno ;
extern int ZWriteFile(u_char *buffer, int len, FILE *, ZModem *);
extern int ZCloseFile(ZModem *info) ;
extern void ZFlowControl(int onoff, ZModem *info) ;
static u_char zeros[4] = {0,0,0,0} ;
int
ZmodemRInit(ZModem *info)
{
info->packetCount = 0 ;
info->offset = 0 ;
info->errCount = 0 ;
info->escCtrl = info->escHibit = info->atSign = info->escape = 0 ;
info->InputState = Idle ;
info->canCount = info->chrCount = 0 ;
info->filename = NULL ;
info->interrupt = 0 ;
info->waitflag = 0 ;
info->attn = NULL ;
info->file = NULL ;
info->buffer = (u_char *)malloc(8192) ;
info->state = RStart ;
info->timeoutCount = 0 ;
ZIFlush(info) ;
/* Don't send ZRINIT right away, there might be a ZRQINIT in
* the input buffer. Instead, set timeout to zero and return.
* This will allow ZmodemRcv() to check the input stream first.
* If nothing found, a ZRINIT will be sent immediately.
*/
info->timeout = 0 ;
zmodemlog("ZmodemRInit[%s]: flush input, new state = RStart\n",
sname(info)) ;
return 0 ;
}
int
YmodemRInit(ZModem *info)
{
info->errCount = 0 ;
info->InputState = Yrcv ;
info->canCount = info->chrCount = 0 ;
info->noiseCount = 0 ;
info->filename = NULL ;
info->file = NULL ;
if( info->buffer == NULL )
info->buffer = (u_char *)malloc(1024) ;
info->state = YRStart ;
info->packetCount = -1 ;
info->timeoutCount = 0 ;
info->timeout = 10 ;
info->offset = 0 ;
ZIFlush(info) ;
return ZXmitStr((u_char *)"C", 1, info) ;
}
extern int ZPF() ;
extern int Ignore() ;
extern int GotCommand() ;
extern int GotStderr() ;
int SendRinit() ;
static int GotSinit() ;
static int GotFile() ;
static int GotFin() ;
static int GotData() ;
static int GotEof() ;
static int GotFreecnt() ;
static int GotFileCrc() ;
int ResendCrcReq() ;
int ResendRpos() ;
/* sent ZRINIT, waiting for ZSINIT or ZFILE */
StateTable RStartOps[] = {
{ZSINIT,GotSinit,0,1,RSinitWait}, /* SINIT, wait for attn str */
{ZFILE,GotFile,0,0,RFileName}, /* FILE, wait for filename */
{ZRQINIT,SendRinit,0,1,RStart}, /* sender confused, resend */
{ZFIN,GotFin,1,0,RFinish}, /* sender shutting down */
{ZNAK,SendRinit,1,0,RStart}, /* RINIT was bad, resend */
#ifdef TODO
{ZCOMPL,f,1,1,s},
#endif /* TODO */
{ZFREECNT,GotFreecnt,0,0,RStart}, /* sender wants free space */
{ZCOMMAND,GotCommand,0,0,CommandData}, /* sender wants command */
{ZSTDERR,GotStderr,0,0,StderrData}, /* sender wants to send msg */
{99,ZPF,0,0,RStart}, /* anything else is an error */
} ;
StateTable RSinitWaitOps[] = { /* waiting for data */
{99,ZPF,0,0,RSinitWait},
} ;
StateTable RFileNameOps[] = { /* waiting for file name */
{99,ZPF,0,0,RFileName},
} ;
StateTable RCrcOps[] = { /* waiting for CRC */
{ZCRC,GotFileCrc,0,0,RFile}, /* sender sent it */
{ZNAK,ResendCrcReq,0,0,RCrc}, /* ZCRC was bad, resend */
{ZRQINIT,SendRinit,1,1,RStart}, /* sender confused, restart */
{ZFIN,GotFin,1,1,RFinish}, /* sender signing off */
{99,ZPF,0,0,RCrc},
} ;
StateTable RFileOps[] = { /* waiting for ZDATA */
{ZDATA,GotData,0,0,RData}, /* got it */
{ZNAK,ResendRpos,0,0,RFile}, /* ZRPOS was bad, resend */
{ZEOF,GotEof,0,0,RStart}, /* end of file */
{ZRQINIT,SendRinit,1,1,RStart}, /* sender confused, restart */
{ZFILE,ResendRpos,0,0,RFile}, /* ZRPOS was bad, resend */
{ZFIN,GotFin,1,1,RFinish}, /* sender signing off */
{99,ZPF,0,0,RFile},
} ;
/* waiting for data, but a packet could possibly arrive due
* to error recovery or something
*/
StateTable RDataOps[] = {
{ZRQINIT,SendRinit,1,1,RStart}, /* sender confused, restart */
{ZFILE,GotFile,0,1,RFileName}, /* start a new file (??) */
{ZNAK,ResendRpos,1,1,RFile}, /* ZRPOS was bad, resend */
{ZFIN,GotFin,1,1,RFinish}, /* sender signing off */
{ZDATA,GotData,0,1,RData}, /* file data follows */
{ZEOF,GotEof,1,1,RStart}, /* end of file */
{99,ZPF,0,0,RData},
} ;
/* here if we've sent ZFERR or ZABORT. Waiting for ZFIN */
StateTable RFinishOps[] = {
{ZRQINIT,SendRinit,1,1,RStart}, /* sender confused, restart */
{ZFILE,GotFile,1,1,RFileName}, /* start a new file */
{ZNAK,GotFin,1,1,RFinish}, /* resend ZFIN */
{ZFIN,GotFin,1,1,RFinish}, /* sender signing off */
{99,ZPF,0,0,RFinish},
} ;
extern char *hdrnames[] ;
extern int dataSetup() ;
/* RECEIVE-RELATED STUFF BELOW HERE */
/* resend ZRINIT header in response to ZRQINIT or ZNAK header */
int
SendRinit( register ZModem *info )
{
u_char dbuf[4] ;
#ifdef COMMENT
if( info->timeoutCount >= 5 )
/* TODO: switch to Ymodem */
#endif /* COMMENT */
zmodemlog("SendRinit[%s]: send ZRINIT\n", sname(info)) ;
info->timeout = ResponseTime ;
dbuf[0] = info->bufsize&0xff ;
dbuf[1] = (info->bufsize>>8)&0xff ;
dbuf[2] = 0 ;
dbuf[3] = info->zrinitflags ;
return ZXmitHdrHex(ZRINIT, dbuf, info) ;
}
/* received a ZSINIT header in response to ZRINIT */
static int
GotSinit( register ZModem *info )
{
zmodemlog("GotSinit[%s]: call dataSetup\n", sname(info)) ;
info->zsinitflags = info->hdrData[4] ;
info->escCtrl = info->zsinitflags & TESCCTL ;
info->escHibit = info->zsinitflags & TESC8 ;
ZFlowControl(1, info) ;
return dataSetup(info) ;
}
/* received rest of ZSINIT packet */
int
GotSinitData( register ZModem *info, int crcGood )
{
info->InputState = Idle ;
info->chrCount=0 ;
info->state = RStart ;
zmodemlog("GotSinitData[%s]: crcGood=%d\n", sname(info), crcGood) ;
if( !crcGood )
return ZXmitHdrHex(ZNAK, zeros, info) ;
if( info->attn != NULL )
free(info->attn) ;
info->attn = NULL ;
if( info->buffer[0] != '\0' )
info->attn = strdup((char *)info->buffer) ;
return ZXmitHdrHex(ZACK, ZEnc4(SerialNo), info) ;
}
/* got ZFILE. Cache flags and set up to receive filename */
static int
GotFile( register ZModem *info )
{
zmodemlog("GotFile[%s]: call dataSetup\n", sname(info)) ;
info->errCount = 0 ;
info->f0 = info->hdrData[4] ;
info->f1 = info->hdrData[3] ;
info->f2 = info->hdrData[2] ;
info->f3 = info->hdrData[1] ;
return dataSetup(info) ;
}
/* utility: see if ZOpenFile wants this file, and if
* so, request it from sender.
*/
static int
requestFile( register ZModem *info, u_long crc )
{
info->file = ZOpenFile((char *)info->buffer, crc, info) ;
if( info->file == NULL ) {
zmodemlog("requestFile[%s]: send ZSKIP\n", sname(info)) ;
info->state = RStart ;
ZStatus(FileSkip, 0, info->filename) ;
return ZXmitHdrHex(ZSKIP, zeros, info) ;
}
else {
zmodemlog("requestFile[%s]: send ZRPOS(%ld)\n",
sname(info), info->offset) ;
info->offset = info->f0 == ZCRESUM ? ftell(info->file) : 0 ;
info->state = RFile ;
ZStatus(FileBegin, 0, info->filename) ;
return ZXmitHdrHex(ZRPOS, ZEnc4(info->offset), info) ;
}
}
/* parse filename info. */
static void
parseFileName( register ZModem *info, char *fileinfo )
{
char *ptr ;
int serial=0 ;
info->len = info->mode = info->filesRem =
info->bytesRem = info->fileType = 0 ;
ptr = fileinfo + strlen(fileinfo) + 1 ;
if( info->filename != NULL )
free(info->filename) ;
info->filename = strdup(fileinfo) ;
sscanf(ptr, "%d %lo %o %o %d %d %d", &info->len, &info->date,
&info->mode, &serial, &info->filesRem, &info->bytesRem,
&info->fileType) ;
}
/* got filename. Parse arguments from it and execute
* policy function ZOpenFile(), provided by caller
*/
int
GotFileName( register ZModem *info, int crcGood )
{
info->InputState = Idle ;
info->chrCount=0 ;
if( !crcGood ) {
zmodemlog("GotFileName[%s]: bad crc, send ZNAK\n", sname(info)) ;
info->state = RStart ;
return ZXmitHdrHex(ZNAK, zeros, info) ;
}
parseFileName(info, (char *)info->buffer) ;
if( (info->f1 & ZMMASK) == ZMCRC ) {
info->state = RCrc ;
return ZXmitHdrHex(ZCRC, zeros, info) ;
}
zmodemlog("GotFileName[%s]: good crc, call requestFile\n",
sname(info)) ;
info->state = RFile ;
return requestFile(info,0) ;
}
int
ResendCrcReq(ZModem *info)
{
zmodemlog("ResendCrcReq[%s]: send ZCRC\n", sname(info)) ;
return ZXmitHdrHex(ZCRC, zeros, info) ;
}
/* received file CRC, now we're ready to accept or reject */
static int
GotFileCrc( register ZModem *info )
{
zmodemlog("GotFileCrc[%s]: call requestFile\n", sname(info)) ;
return requestFile(info, ZDec4(info->hdrData+1)) ;
}
/* last ZRPOS was bad, resend it */
int
ResendRpos( register ZModem *info )
{
zmodemlog("ResendRpos[%s]: send ZRPOS(%ld)\n",
sname(info), info->offset) ;
return ZXmitHdrHex(ZRPOS, ZEnc4(info->offset), info) ;
}
/* recevied ZDATA header */
static int
GotData( register ZModem *info )
{
int err ;
zmodemlog("GotData[%s]:\n", sname(info)) ;
if( ZDec4(info->hdrData+1) != info->offset ) {
if( info->attn != NULL && (err=ZAttn(info)) != 0 )
return err ;
zmodemlog(" bad, send ZRPOS(%ld)\n", info->offset);
return ZXmitHdrHex(ZRPOS, ZEnc4(info->offset), info) ;
}
/* Let's do it! */
zmodemlog(" call dataSetup\n");
return dataSetup(info) ;
}
/* Utility: flush input, send attn, send specified header */
static int
fileError( register ZModem *info, int type, int data )
{
int err ;
info->InputState = Idle ;
info->chrCount=0 ;
if( info->attn != NULL && (err=ZAttn(info)) != 0 )
return err ;
return ZXmitHdrHex(type, ZEnc4(data), info) ;
}
/* received file data */
int
GotFileData( register ZModem *info, int crcGood )
{
/* OK, now what? Fushing the buffers and executing the
* attn sequence has likely chopped off the input stream
* mid-packet. Now we switch to idle mode and treat all
* incoming stuff like noise until we get a new valid
* packet.
*/
if( !crcGood ) { /* oh bugger, an error. */
zmodemlog(
"GotFileData[%s]: bad crc, send ZRPOS(%ld), new state = RFile\n",
sname(info), info->offset) ;
ZStatus(DataErr, ++info->errCount, NULL) ;
if( info->errCount > MaxErrs ) {
ZmodemAbort(info) ;
return ZmDataErr ;
}
else {
info->state = RFile ;
info->InputState = Idle ;
info->chrCount=0 ;
return fileError(info, ZRPOS, info->offset) ;
}
}
if( ZWriteFile(info->buffer, info->chrCount, info->file, info) )
{
/* RED ALERT! Could not write the file. */
ZStatus(FileErr, errno, NULL) ;
info->state = RFinish ;
info->InputState = Idle ;
info->chrCount=0 ;
return fileError(info, ZFERR, errno) ;
}
zmodemlog("GotFileData[%s]: %ld.%d,",
sname(info), info->offset, info->chrCount) ;
info->offset += info->chrCount ;
ZStatus(RcvByteCount, info->offset, NULL) ;
/* if this was the last data subpacket, leave data mode */
if( info->PacketType == ZCRCE || info->PacketType == ZCRCW ) {
zmodemlog(" ZCRCE|ZCRCW, new state RFile") ;
info->state = RFile ;
info->InputState = Idle ;
info->chrCount=0 ;
}
else {
zmodemlog(" call dataSetup") ;
(void) dataSetup(info) ;
}
if( info->PacketType == ZCRCQ || info->PacketType == ZCRCW ) {
zmodemlog(", send ZACK\n") ;
return ZXmitHdrHex(ZACK, ZEnc4(info->offset), info) ;
}
else
zmodemlog("\n") ;
return 0 ;
}
/* received ZEOF packet, file is now complete */
static int
GotEof( register ZModem *info )
{
zmodemlog("GotEof[%s]: offset=%ld\n", sname(info), info->offset) ;
if( ZDec4(info->hdrData+1) != info->offset ) {
zmodemlog(" bad length, state = RFile\n") ;
info->state = RFile ;
return 0 ; /* it was probably spurious */
}
/* TODO: if we can't close the file, send a ZFERR */
ZCloseFile(info) ; info->file = NULL ;
ZStatus(FileEnd, 0, info->filename) ;
if( info->filename != NULL ) {
free(info->filename) ;
info->filename = NULL ;
}
return SendRinit(info) ;
}
/* got ZFIN, respond in kind */
static int
GotFin( register ZModem *info )
{
zmodemlog("GotFin[%s]: send ZFIN\n", sname(info)) ;
info->InputState = Finish ;
info->chrCount = 0 ;
if( info->filename != NULL )
free(info->filename) ;
return ZXmitHdrHex(ZFIN, zeros, info) ;
}
static int
GotFreecnt( register ZModem *info )
{
/* TODO: how do we find free space on system? */
return ZXmitHdrHex(ZACK, ZEnc4(0xffffffff), info) ;
}
/* YMODEM */
static u_char AckStr[1] = {ACK} ;
static u_char NakStr[1] = {NAK} ;
static u_char CanStr[2] = {CAN,CAN} ;
static int ProcessPacket() ;
static int acceptPacket() ;
static int rejectPacket() ;
static int calcCrc() ;
int
YrcvChar( char c, register ZModem *info )
{
int err ;
if( info->canCount >= 2 ) {
ZStatus(RmtCancel, 0, NULL) ;
return ZmErrCancel ;
}
switch( info->state ) {
case YREOF:
if( c == EOT ) {
ZCloseFile(info) ; info->file = NULL ;
ZStatus(FileEnd, 0, info->filename) ;
if( info->filename != NULL )
free(info->filename) ;
if( (err = acceptPacket(info)) != 0 )
return err ;
info->packetCount = -1 ;
info->offset = 0 ;
info->state = YRStart ;
return ZXmitStr((u_char *)"C", 1, info) ;
}
/* else, drop through */
case YRStart:
case YRDataWait:
switch( c ) {
case SOH:
case STX:
info->pktLen = c == SOH ? (128+4) : (1024+4) ;
info->state = YRData ;
info->chrCount = 0 ;
info->timeout = 1 ;
info->noiseCount = 0 ;
info->crc = 0 ;
break ;
case EOT:
/* ignore first EOT to protect against false eot */
info->state = YREOF ;
return rejectPacket(info) ;
default:
if( ++info->noiseCount > 135 )
return ZXmitStr(NakStr, 1, info) ;
break ;
}
break ;
case YRData:
info->buffer[info->chrCount++] = c ;
if( info->chrCount >= info->pktLen )
return ProcessPacket(info) ;
break ;
default:
break ;
}
return 0 ;
}
int
YrcvTimeout( register ZModem *info )
{
switch( info->state )
{
case YRStart:
if( info->timeoutCount >= 10 ) {
(void) ZXmitStr(CanStr, 2, info) ;
return ZmErrInitTo ;
}
return ZXmitStr((u_char *)"C", 1, info) ;
case YRDataWait:
case YREOF:
case YRData:
if( info->timeoutCount >= 10 ) {
(void) ZXmitStr(CanStr, 2, info) ;
return ZmErrRcvTo ;
}
return ZXmitStr(NakStr, 1, info) ;
default: return 0 ;
}
}
static int
ProcessPacket( register ZModem *info )
{
int idx = (u_char) info->buffer[0] ;
int idxc = (u_char) info->buffer[1] ;
int crc0, crc1 ;
int err ;
info->state = YRDataWait ;
if( idxc != 255 - idx ) {
ZStatus(DataErr, ++info->errCount, NULL) ;
return rejectPacket(info) ;
}
if( idx == (info->packetCount%256) ) /* quietly ignore dup */
return acceptPacket(info) ;
if( idx != (info->packetCount+1)%256 ) { /* out of sequence */
(void) ZXmitStr(CanStr, 2, info) ;
return ZmErrSequence ;
}
crc0 = (u_char)info->buffer[info->pktLen-2] << 8 |
(u_char)info->buffer[info->pktLen-1] ;
crc1 = calcCrc(info->buffer+2, info->pktLen-4) ;
if( crc0 != crc1 ) {
ZStatus(DataErr, ++info->errCount, NULL) ;
return rejectPacket(info) ;
}
++info->packetCount ;
if( info->packetCount == 0 ) /* packet 0 is filename */
{
if( info->buffer[2] == '\0' ) { /* null filename is FIN */
(void) acceptPacket(info) ;
return ZmDone ;
}
parseFileName(info, (char *)info->buffer+2) ;
info->file = ZOpenFile(info->filename, 0, info) ;
if( info->file == NULL ) {
(void) ZXmitStr(CanStr, 2, info) ;
return ZmErrCantOpen ;
}
if( (err = acceptPacket(info)) != 0 )
return err ;
return ZXmitStr((u_char *)"C", 1, info) ;
}
if( ZWriteFile(info->buffer+2, info->pktLen-4, info->file, info) ) {
ZStatus(FileErr, errno, NULL) ;
(void) ZXmitStr(CanStr, 2, info) ;
return ZmErrSys ;
}
info->offset += info->pktLen-4 ;
ZStatus(RcvByteCount, info->offset, NULL) ;
(void) acceptPacket(info) ;
return 0 ;
}
static int
rejectPacket( register ZModem *info )
{
info->timeout = 10 ;
return ZXmitStr(NakStr, 1, info) ;
}
static int
acceptPacket( register ZModem *info )
{
info->state = YRDataWait ;
info->timeout = 10 ;
return ZXmitStr(AckStr, 1, info) ;
}
static int
calcCrc( u_char *str, int len )
{
int crc = 0 ;
while( --len >= 0 )
crc = updcrc(*str++, crc) ;
crc = updcrc(0,crc) ; crc = updcrc(0,crc) ;
return crc & 0xffff ;
}

21
Xmodem/zmodemsys.c Normal file
View File

@ -0,0 +1,21 @@
/* @(#)zmodemsys.c 1.1 95/06/28 Edward Falk */
#include <unistd.h>
/* small utilities for porting between systems */
#ifndef HAVE_STRDUP
char *
strdup( char *str )
{
char *rval ;
int len = strlen(str) + 1 ;
rval = (char *)malloc(len) ;
strcpy(rval,str) ;
return rval ;
}
#endif

1152
Xmodem/zmodemt.c Normal file

File diff suppressed because it is too large Load Diff

408
Xmodem/zmutil.c Normal file
View File

@ -0,0 +1,408 @@
#ifndef lint
static const char rcsid[] = "$Id: zmutil.c,v 1.1.1.1 2001/03/08 00:01:48 efalk Exp $" ;
#endif
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @@@@@ @ @ @ @ @@@@@ @@@ @
* @ @@ @@ @ @ @ @ @
* @ @ @ @ @ @ @ @ @
* @ @ @ @ @ @ @ @ @
* @@@@@ @ @ @ @@@ @ @@@ @@@@@
*
* ZMUTIL - utilties used by zmodem protocol.
*
* Routines provided here:
*
*
* int ZXmitHdrHex(type, data, info)
* int type ;
* u_char data[4] ;
* ZModem *info ;
*
* transmit zmodem header in hex.
*
*
* int ZXmitHdrBin(type, data, info)
* int type ;
* u_char data[4] ;
* ZModem *info ;
*
* transmit zmodem header in binary.
*
*
* int ZXmitHdrBin32(type, data, info)
* int type ;
* u_char data[4] ;
* ZModem *info ;
*
* transmit zmodem header in binary with 32-bit crc.
*
*
* int ZXmitHdr(type, format, data, info)
* int type, format ;
* u_char data[4] ;
* ZModem *info ;
*
* transmit zmodem header
*
*
* int ZXmitData(format, data, len, term, info)
* int format, len ;
* u_char term ;
* u_char *data ;
* ZModem *info ;
*
* transmit buffer of data.
*
*
* u_long FileCrc(name)
* char *name ;
*
* compute 32-bit crc for a file, returns 0 on not found
*
*
* u_char *ZEnc4(n)
* u_long n ;
*
* convert u_long to 4 bytes.
*
* u_long ZDec4(buf)
* u_char buf[4] ;
*
* convert 4 bytes to u_long
*
*
*
* Edward A. Falk
*
* January, 1995
*
*
*
**********/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/time.h>
#include "zmodem.h"
#include "crctab.h"
static char hexChars[] = "0123456789abcdef" ;
extern char *hdrnames[] ;
FILE *zmodemlogfile = NULL ;
/* put a number as two hex digits */
static u_char *
putHex( u_char *ptr, u_char c )
{
*ptr++ = hexChars[(c>>4)&0xf] ;
*ptr++ = hexChars[c&0xf] ;
return ptr ;
}
/* put a number with ZDLE escape if needed */
u_char *
putZdle( register u_char *ptr, register u_char c, register ZModem *info )
{
register u_char c2 = c & 0177 ;
if( c == ZDLE || c2 == 020 || c2 == 021 || c2 == 023 ||
c2 == 0177 || (c2 == 015 && info->atSign) ||
#ifdef COMMENT
c2 == 035 || (c2 == '~' && info->lastCR) ||
#endif /* COMMENT */
c2 == 035 ||
(c2 < 040 && info->escCtrl) )
{
*ptr++ = ZDLE ;
if( c == 0177 )
*ptr = ZRUB0 ;
else if( c == 0377 )
*ptr = ZRUB1 ;
else
*ptr = c^0100 ;
}
else
*ptr = c ;
info->atSign = c2 == '@' ;
info->lastCR = c2 == '\r' ;
return ++ptr ;
}
int
ZXmitHdrHex( int type, u_char data[4], ZModem *info )
{
u_char buffer[128] ;
register u_char *ptr = buffer ;
register u_int crc ;
int i ;
zmodemlog("sending %s: %2.2x %2.2x %2.2x %2.2x = %lx\n",
hdrnames[type], data[0], data[1], data[2], data[3],
ZDec4(data)) ;
*ptr++ = ZPAD ;
*ptr++ = ZPAD ;
*ptr++ = ZDLE ;
*ptr++ = ZHEX ;
ptr = putHex(ptr, type) ; crc = updcrc(type, 0) ;
for( i=4; --i >= 0; ++data ) {
ptr = putHex(ptr, *data) ;
crc = updcrc(*data, crc) ;
}
crc = updcrc(0,crc) ; crc = updcrc(0,crc) ;
ptr = putHex(ptr, (crc>>8)&0xff) ;
ptr = putHex(ptr, crc&0xff) ;
*ptr++ = '\r' ;
*ptr++ = '\n' ;
if( type != ZACK && type != ZFIN )
*ptr++ = XON ;
return ZXmitStr(buffer, ptr-buffer, info) ;
}
int
ZXmitHdrBin( int type, u_char data[4], register ZModem *info )
{
u_char buffer[128] ;
register u_char *ptr = buffer ;
register u_int crc ;
int len ;
zmodemlog("sending %s: %2.2x %2.2x %2.2x %2.2x = %lx\n",
hdrnames[type], data[0], data[1], data[2], data[3],
ZDec4(data)) ;
*ptr++ = ZPAD ;
*ptr++ = ZDLE ;
*ptr++ = ZBIN ;
ptr = putZdle(ptr, type, info) ; crc = updcrc(type, 0) ;
for( len=4; --len >= 0; ++data ) {
ptr = putZdle(ptr, *data, info) ;
crc = updcrc(*data, crc) ;
}
crc = updcrc(0,crc) ; crc = updcrc(0,crc) ;
ptr = putZdle(ptr, (crc>>8)&0xff, info) ;
ptr = putZdle(ptr, crc&0xff, info) ;
len = ptr-buffer ;
return ZXmitStr(buffer, len, info) ;
}
int
ZXmitHdrBin32( int type, u_char data[4], ZModem *info )
{
u_char buffer[128] ;
register u_char *ptr = buffer ;
register u_long crc ;
int len ;
zmodemlog("sending %s: %2.2x %2.2x %2.2x %2.2x = %lx\n",
hdrnames[type], data[0], data[1], data[2], data[3],
ZDec4(data)) ;
*ptr++ = ZPAD ;
*ptr++ = ZDLE ;
*ptr++ = ZBIN32 ;
ptr = putZdle(ptr, type, info) ; crc = UPDC32(type, 0xffffffffL) ;
for( len=4; --len >= 0; ++data ) {
ptr = putZdle(ptr, *data, info) ;
crc = UPDC32(*data, crc) ;
}
crc = ~crc ;
for(len=4; --len >= 0; crc >>= 8)
ptr = putZdle(ptr, crc&0xff, info) ;
len = ptr-buffer ;
return ZXmitStr(buffer, len, info) ;
}
int
ZXmitHdr( int type, int format, u_char data[4], ZModem *info)
{
if( format == ZBIN && info->crc32 )
format = ZBIN32 ;
switch( format ) {
case ZHEX:
return ZXmitHdrHex(type, data, info) ;
case ZBIN:
return ZXmitHdrBin(type, data, info) ;
case ZBIN32:
return ZXmitHdrBin32(type, data, info) ;
default:
return 0 ;
}
}
/* TODO: if input is not a file, need to keep old data
* for possible retransmission */
int
ZXmitData( int format, int len, u_char term, u_char *data, ZModem *info)
{
register u_char *ptr = info->buffer ;
register u_int crc ;
if( format == ZBIN && info->crc32 )
format = ZBIN32 ;
zmodemlog("ZXmiteData: fmt=%c, len=%d, term=%c\n", format, len, term) ;
crc = (format == ZBIN) ? 0 : 0xffffffff ;
while( --len >= 0 ) {
if( format == ZBIN )
crc = updcrc(*data, crc) ;
else
crc = UPDC32(*data, crc) ;
ptr = putZdle(ptr, *data++, info) ;
}
*ptr++ = ZDLE ;
if( format == ZBIN )
crc = updcrc(term, crc) ;
else
crc = UPDC32(term, crc) ;
*ptr++ = term ;
if( format == ZBIN ) {
crc = updcrc(0,crc) ; crc = updcrc(0,crc) ;
ptr = putZdle(ptr, (crc>>8)&0xff, info) ;
ptr = putZdle(ptr, crc&0xff, info) ;
}
else {
crc = ~crc ;
for(len=4; --len >= 0; crc >>= 8)
ptr = putZdle(ptr, crc&0xff, info) ;
}
return ZXmitStr(info->buffer, ptr-info->buffer, info) ;
}
/* compute 32-bit crc for a file, returns 0 on not found */
u_long
FileCrc( char *name )
{
u_long crc ;
FILE *ifile = fopen(name, "r") ;
int i ;
if( ifile == NULL ) /* shouldn't happen, since we did access(2) */
return 0 ;
crc = 0xffffffff ;
while( (i=fgetc(ifile)) != EOF )
crc = UPDC32(i, crc) ;
fclose(ifile) ;
return ~crc ;
}
u_char *
ZEnc4( u_long n )
{
static u_char buf[4] ;
buf[0] = n&0xff ; n >>= 8 ;
buf[1] = n&0xff ; n >>= 8 ;
buf[2] = n&0xff ; n >>= 8 ;
buf[3] = n&0xff ;
return buf ;
}
u_long
ZDec4( u_char buf[4] )
{
return buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24) ;
}
char *
sname2(ZMState state)
{
static char *names[] = {
"RStart", "RSinitWait", "RFileName", "RCrc", "RFile", "RData",
"RDataErr", "RFinish", "TStart", "TInit", "FileWait", "CrcWait",
"Sending", "SendWait", "SendDone", "SendEof", "TFinish",
"CommandData", "CommandWait", "StderrData", "Done", "YTStart",
"YTFile", "YTDataWait", "YTData", "YTEOF", "YTFin", "YRStart",
"YRDataWait", "YRData", "YREOF"} ;
return names[(int)state] ;
}
char *
sname(ZModem *info)
{
return sname2(info->state) ;
}
#ifdef DEBUG
void
zmodemlog(const char *fmt, ... )
{
va_list ap;
struct timeval tv ;
struct tm *tm ;
static int do_ts = 1 ;
if( zmodemlogfile == NULL )
return ;
if( do_ts ) {
gettimeofday(&tv, NULL) ;
tm = localtime(&tv.tv_sec) ;
fprintf(zmodemlogfile, "%2.2d:%2.2d:%2.2d.%2.2ld: ",
tm->tm_hour, tm->tm_min, tm->tm_sec,
tv.tv_usec/10000) ;
}
do_ts = strchr(fmt, '\n') != NULL ;
va_start(ap, fmt) ;
vfprintf(zmodemlogfile, fmt, ap) ;
va_end(ap) ;
}
#endif /* DEBUG */

View File

@ -0,0 +1,14 @@

ワワワワワワワ ワワ ワワ ワワワワ ワワワワワワワ ワワワワワワワワワワワ ワワワワワワワ ワワワワワワ ワワ ワ ワワ
イ゚ワワ ゚゚ ロロ イ゚ ロ゚゚゚ イ゚ワワ ゚゚ イ゚ーワ イ゚ーワ イロ イ゚ワワ ゚゚ イ゚ーワ イロ イ゚ ロ ロイ
アイ ワワロイ イイ アロワ゚ ア゚ アイワー イ゚ ーイ イ ーイ イ ア゚ アイワー イ゚ ーイ イ ア゚ ーイワ゚ イ 
ロロ ゚゚゚゚ ゚゚ ー゚゚゚゚゚゚ ゚゚゚゚゚゚ ゚゚ ゚ ゚゚ ゚ ーロ ゚゚゚゚゚゚ ゚゚ ゚ ーロ ゚゚゚゚゚゚
トトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト
}. Advance 1 Directoryウ L. List Filesウ
{. Retreat 1 Directoryウ C. Clear Tagged Listウ
]. Advance 1 Subdirectoryウ D. Download Files Taggedウ
[. Retreat 1 Subdirectoryウ U. Upload a Fileウ
I. Select Directoryウウ
S. Select Subdirectoryウ Q. Quit to Main Menuウ
ウ G. Goodbye (Log Off)ウ
トトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト

View File

@ -5,7 +5,7 @@
ßß ß ßß ß °Û ßß ß °Û ßß ßß ß °Û ßß ß ßß ß °Û ßßßßßß ßß ß °Û ßßßßßß
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
³ M. Message Areas³ L. BBS List³
ł T. File Areasł C. Chat Systemł
³ T. File Transfer Area³ C. Chat System³
³ B. Bulletins³ U. User List³
³ D. Door Games & Utilites³ 1. Last 10 Callers³
³ A. Text/ANSI File Collection ³³

7
bbs.c
View File

@ -166,6 +166,8 @@ static int file_sub_handler(void* user, const char* section, const char* name,
fd->file_subs[i]->download_sec_level = atoi(value);
} else if (strcasecmp(name, "database") == 0) {
fd->file_subs[i]->database = strdup(value);
} else if (strcasecmp(name, "upload path") == 0) {
fd->file_subs[i]->upload_path = strdup(value);
}
return 1;
}
@ -185,6 +187,8 @@ static int file_sub_handler(void* user, const char* section, const char* name,
fd->file_subs[fd->file_sub_count]->download_sec_level = atoi(value);
} else if (strcasecmp(name, "database") == 0) {
fd->file_subs[fd->file_sub_count]->database = strdup(value);
} else if (strcasecmp(name, "upload path") == 0) {
fd->file_subs[fd->file_sub_count]->upload_path = strdup(value);
}
fd->file_sub_count++;
}
@ -412,6 +416,9 @@ char s_getchar(int socket) {
len = read(socket, &c, 1);
if (len == 0) {
disconnect(socket);
} else if (c == 255) {
usertimeout = 10;
return c;
}
len = read(socket, &c, 1);
if (len == 0) {

4
bbs.h
View File

@ -64,6 +64,7 @@ struct mail_conference {
struct file_sub {
char *name;
char *database;
char *upload_path;
int upload_sec_level;
int download_sec_level;
};
@ -82,6 +83,7 @@ struct bbs_config {
char *ansi_path;
char *bbs_path;
char *default_tagline;
char *irc_server;
@ -158,4 +160,6 @@ extern void chat_system(int sock, struct user_record *user);
extern int mail_getemailcount(struct user_record *user);
extern void send_email(int socket, struct user_record *user);
extern void list_emails(int socket, struct user_record *user);
extern int file_menu(int socket, struct user_record *user);
#endif

View File

@ -5,3 +5,4 @@ Visible Sec Level = 10
Database = files_misc
Download Sec Level = 10
Upload Sec Level = 10
Upload Path = /home/andrew/MagickaBBS/files/misc

736
files.c Normal file
View File

@ -0,0 +1,736 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <unistd.h>
#include <sys/stat.h>
#include <libgen.h>
#include <ctype.h>
#include <errno.h>
#include "Xmodem/zmodem.h"
#include "bbs.h"
extern struct bbs_config conf;
static int doCancel = 0;
struct file_entry {
char *filename;
char *description;
int size;
int dlcount;
};
char **tagged_files;
int tagged_count = 0;
int ZXmitStr(u_char *str, int len, ZModem *info) {
int i;
for (i=0;i<len;i++) {
if (str[i] == 255) {
if (write(info->ofd, &str[i], 1) == 0) {
return ZmErrSys;
}
}
if (write(info->ofd, &str[i], 1) == 0) {
return ZmErrSys;
}
}
return 0;
}
void ZIFlush(ZModem *info) {
}
void ZOFlush(ZModem *info) {
}
int ZAttn(ZModem *info) {
char *ptr ;
if( info->attn == NULL )
return 0 ;
for(ptr = info->attn; *ptr != '\0'; ++ptr) {
if( *ptr == ATTNBRK ) {
} else if( *ptr == ATTNPSE ) {
sleep(1);
} else {
write(info->ifd, ptr, 1) ;
}
}
return 0;
}
void ZFlowControl(int onoff, ZModem *info) {
}
void ZStatus(int type, int value, char *status) {
}
char *upload_path;
char upload_filename[1024];
FILE *ZOpenFile(char *name, u_long crc, ZModem *info) {
FILE *fptr;
struct stat s;
snprintf(upload_filename, 1023, "%s/%s", upload_path, basename(name));
fprintf(stderr, "%s\n", upload_filename);
if (stat(upload_filename, &s) == 0) {
return NULL;
}
fptr = fopen(upload_filename, "wb");
return fptr;
}
int ZWriteFile(u_char *buffer, int len, FILE *file, ZModem *info) {
return fwrite(buffer, 1, len, file) == len ? 0 : ZmErrSys;
}
int ZCloseFile(ZModem *info) {
fclose(info->file);
return 0;
}
void ZIdleStr(u_char *buffer, int len, ZModem *info) {
}
int doIO(ZModem *zm) {
fd_set readfds;
struct timeval timeout;
u_char buffer[2048];
u_char buffer2[1024];
int len;
int pos;
int done = 0;
int i;
int j;
while(!done) {
FD_ZERO(&readfds);
FD_SET(zm->ifd, &readfds) ;
timeout.tv_sec = zm->timeout ;
timeout.tv_usec = 0 ;
i = select(zm->ifd+1, &readfds,NULL,NULL, &timeout) ;
if( i==0 ) {
done = ZmodemTimeout(zm) ;
} else if (i > 0) {
len = read(zm->ifd, buffer, 2048);
if (len == 0) {
disconnect(zm->ifd);
}
pos = 0;
for (j=0;j<len;j++) {
if (buffer[j] == 255) {
if (buffer[j+1] == 255) {
buffer2[pos] = 255;
pos++;
j++;
} else {
j++;
j++;
}
} else {
buffer2[pos] = buffer[j];
pos++;
}
}
if (pos > 0) {
done = ZmodemRcv(buffer2, pos, zm) ;
}
} else {
// SIG INT catch
if (errno != EINTR) {
printf("SELECT ERROR %s\n", strerror(errno));
}
}
}
return done;
}
void upload_zmodem(int socket, struct user_record *user) {
ZModem zm;
int done;
upload_path = conf.file_directories[user->cur_file_dir]->file_subs[user->cur_file_sub]->upload_path;
zm.attn = NULL;
zm.windowsize = 0;
zm.bufsize = 0;
zm.ifd = socket;
zm.ofd = socket;
zm.zrinitflags = 0;
zm.zsinitflags = 0;
zm.packetsize = 1024;
done = ZmodemRInit(&zm);
doIO(&zm);
}
void upload(int socket, struct user_record *user) {
char buffer[331];
char buffer2[66];
char buffer3[256];
int i;
char *create_sql = "CREATE TABLE IF NOT EXISTS files ("
"Id INTEGER PRIMARY KEY,"
"filename TEXT,"
"description TEXT,"
"size INTEGER,"
"dlcount INTEGER,"
"approved INTEGER);";
char *sql = "INSERT INTO files (filename, description, size, dlcount, approved) VALUES(?, ?, ?, 0, 0)";
sqlite3 *db;
sqlite3_stmt *res;
int rc;
struct stat s;
char *err_msg = NULL;
upload_zmodem(socket, user);
s_putstring(socket, "\r\nPlease enter a description:\r\n");
buffer[0] = '\0';
for (i=0;i<5;i++) {
sprintf(buffer2, "\r\n%d: ", i);
s_putstring(socket, buffer2);
s_readstring(socket, buffer2, 65);
if (strlen(buffer2) == 0) {
break;
}
strcat(buffer, buffer2);
strcat(buffer, "\n");
}
sprintf(buffer3, "%s/%s.sq3", conf.bbs_path, conf.file_directories[user->cur_file_dir]->file_subs[user->cur_file_sub]->database);
rc = sqlite3_open(buffer3, &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
rc = sqlite3_exec(db, create_sql, 0, 0, &err_msg);
if (rc != SQLITE_OK ) {
fprintf(stderr, "SQL error: %s\n", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
return;
}
rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
if (rc == SQLITE_OK) {
stat(upload_filename, &s);
sqlite3_bind_text(res, 1, upload_filename, -1, 0);
sqlite3_bind_text(res, 2, buffer, -1, 0);
sqlite3_bind_int(res, 3, s.st_size);
} else {
fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
return;
}
rc = sqlite3_step(res);
if (rc != SQLITE_DONE) {
printf("execution failed: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
return;
}
sqlite3_finalize(res);
sqlite3_close(db);
}
void download_zmodem(int socket, struct user_record *user, char *filename) {
ZModem zm;
int done ;
fd_set readfds;
struct timeval timeout;
int i;
int j;
int len;
int pos;
u_char buffer[2048];
u_char buffer2[1024];
printf("Attempting to upload %s\n", filename);
zm.attn = NULL;
zm.windowsize = 0;
zm.bufsize = 0;
zm.ifd = socket;
zm.ofd = socket;
zm.zrinitflags = 0;
zm.zsinitflags = 0;
zm.packetsize = 1024;
ZmodemTInit(&zm) ;
done = doIO(&zm);
if ( done != ZmDone ) {
return;
}
done = ZmodemTFile(filename, basename(filename), ZCBIN,0,0,0,0,0, &zm) ;
switch( done ) {
case 0:
break ;
case ZmErrCantOpen:
fprintf(stderr, "cannot open file \"%s\": %s\n", filename, strerror(errno)) ;
return;
case ZmFileTooLong:
fprintf(stderr, "filename \"%s\" too long, skipping...\n", filename) ;
return;
case ZmDone:
return;
default:
return;
}
if (!done) {
done = doIO(&zm);
}
if ( done != ZmDone ) {
return;
}
done = ZmodemTFinish(&zm);
if (!done) {
done = doIO(&zm);
}
}
void download(int socket, struct user_record *user) {
int i;
char *ssql = "select dlcount from files where filename like ?";
char *usql = "update files set dlcount=? where filename like ?";
char buffer[256];
int dloads;
char *err_msg = NULL;
sqlite3 *db;
sqlite3_stmt *res;
int rc;
for (i=0;i<tagged_count;i++) {
download_zmodem(socket, user, tagged_files[i]);
sprintf(buffer, "%s/%s.sq3", conf.bbs_path, conf.file_directories[user->cur_file_dir]->file_subs[user->cur_file_sub]->database);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
rc = sqlite3_prepare_v2(db, ssql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_text(res, 1, tagged_files[i], -1, 0);
} else {
fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db));
}
rc = sqlite3_step(res);
if (rc != SQLITE_ROW) {
fprintf(stderr, "Downloaded a file not in database!!!!!");
sqlite3_finalize(res);
sqlite3_close(db);
exit(1);
}
dloads = sqlite3_column_int(res, 0);
dloads++;
sqlite3_finalize(res);
rc = sqlite3_prepare_v2(db, usql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_int(res, 1, dloads);
sqlite3_bind_text(res, 2, tagged_files[i], -1, 0);
} else {
fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(db));
}
rc = sqlite3_step(res);
sqlite3_finalize(res);
sqlite3_close(db);
}
for (i=0;i<tagged_count;i++) {
free(tagged_files[i]);
}
free(tagged_files);
tagged_count = 0;
}
void list_files(int socket, struct user_record *user) {
char *sql = "select filename, description, size, dlcount from files where approved=1";
char buffer[256];
sqlite3 *db;
sqlite3_stmt *res;
int rc;
int files_c;
int file_size;
char file_unit;
int lines = 0;
char desc;
int i;
int j;
int z;
int k;
int match;
struct file_entry **files_e;
sprintf(buffer, "%s/%s.sq3", conf.bbs_path, conf.file_directories[user->cur_file_dir]->file_subs[user->cur_file_sub]->database);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
exit(1);
}
rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
if (rc != SQLITE_OK) {
sqlite3_finalize(res);
sqlite3_close(db);
s_putstring(socket, "\r\nNo files in this area!\r\n");
return;
}
files_c = 0;
while (sqlite3_step(res) == SQLITE_ROW) {
if (files_c == 0) {
files_e = (struct file_entry **)malloc(sizeof(struct file_entry *));
} else {
files_e = (struct file_entry **)realloc(files_e, sizeof(struct file_entry *) * (files_c + 1));
}
files_e[files_c] = (struct file_entry *)malloc(sizeof(struct file_entry));
files_e[files_c]->filename = strdup((char *)sqlite3_column_text(res, 0));
files_e[files_c]->description = strdup((char *)sqlite3_column_text(res, 1));
files_e[files_c]->size = sqlite3_column_int(res, 2);
files_e[files_c]->dlcount = sqlite3_column_int(res, 3);
files_c++;
}
sqlite3_finalize(res);
sqlite3_close(db);
if (files_c == 0) {
s_putstring(socket, "\r\nNo files in this area!\r\n");
return;
}
s_putstring(socket, "\r\n");
for (i=0;i<files_c;i++) {
file_size = files_e[i]->size;
if (file_size > 1024 * 1024 * 1024) {
file_size = file_size / 1024 / 1024 / 1024;
file_unit = 'G';
} else if (file_size > 1024 * 1024) {
file_size = file_size / 1024 / 1024;
file_unit = 'M';
} else if (file_size > 1024) {
file_size = file_size / 1024;
file_unit = 'K';
} else {
file_unit = 'b';
}
sprintf(buffer, "\e[1;30m[\e[1;34m%3d\e[1;30m] \e[1;33m%3ddloads \e[1;36m%4d%c \e[1;37m%-58s\r\n \e[0;32m", i, files_e[i]->dlcount, file_size, file_unit, basename(files_e[i]->filename));
s_putstring(socket, buffer);
lines++;
for (j=0;j<strlen(files_e[i]->description);j++) {
if (files_e[i]->description[j] == '\n') {
s_putstring(socket, "\r\n");
lines++;
if (lines % 22 == 0 && lines != 0) {
while (1) {
s_putstring(socket, "\r\n\e[0mEnter # to tag, Q to quit, Enter to continue: ");
s_readstring(socket, buffer, 5);
if (strlen(buffer) == 0) {
break;
} else if (tolower(buffer[0]) == 'q') {
for (z=0;z<files_c;z++) {
free(files_e[z]->filename);
free(files_e[z]->description);
free(files_e[z]);
}
free(files_e);
s_putstring(socket, "\r\n");
return;
} else {
z = atoi(buffer);
if (z >= 0 && z < files_c) {
if (conf.file_directories[user->cur_file_dir]->file_subs[user->cur_file_sub]->download_sec_level <= user->sec_level) {
match = 0;
for (k=0;k<tagged_count;k++) {
if (strcmp(tagged_files[k], files_e[z]->filename) == 0) {
match = 1;
break;
}
}
if (match == 0) {
if (tagged_count == 0) {
tagged_files = (char **)malloc(sizeof(char *));
} else {
tagged_files = (char **)realloc(tagged_files, sizeof(char *) * (tagged_count + 1));
}
tagged_files[tagged_count] = strdup(files_e[z]->filename);
tagged_count++;
sprintf(buffer, "\r\nTagged %s\r\n", basename(files_e[z]->filename));
s_putstring(socket, buffer);
} else {
s_putstring(socket, "\r\nAlready Tagged\r\n");
}
} else {
s_putstring(socket, "\r\nSorry, you don't have permission to download from this area\r\n");
}
}
}
}
} else {
s_putstring(socket, " \e[0;32m");
}
} else {
s_putchar(socket, files_e[i]->description[j]);
}
}
}
while (1) {
s_putstring(socket, "\r\n\e[0mEnter # to tag, Enter to quit: ");
s_readstring(socket, buffer, 5);
if (strlen(buffer) == 0) {
for (z=0;z<files_c;z++) {
free(files_e[z]->filename);
free(files_e[z]->description);
free(files_e[z]);
}
free(files_e);
s_putstring(socket, "\r\n");
return;
} else {
z = atoi(buffer);
if (z >= 0 && z < files_c) {
if (conf.file_directories[user->cur_file_dir]->file_subs[user->cur_file_sub]->download_sec_level <= user->sec_level) {
match = 0;
for (k=0;k<tagged_count;k++) {
if (strcmp(tagged_files[k], files_e[z]->filename) == 0) {
match = 1;
break;
}
}
if (match == 0) {
if (tagged_count == 0) {
tagged_files = (char **)malloc(sizeof(char *));
} else {
tagged_files = (char **)realloc(tagged_files, sizeof(char *) * (tagged_count + 1));
}
tagged_files[tagged_count] = strdup(files_e[z]->filename);
tagged_count++;
sprintf(buffer, "\r\nTagged %s\r\n", basename(files_e[z]->filename));
s_putstring(socket, buffer);
} else {
s_putstring(socket, "\r\nAlready Tagged\r\n");
}
} else {
s_putstring(socket, "\r\nSorry, you don't have permission to download from this area\r\n");
}
}
}
}
}
int file_menu(int socket, struct user_record *user) {
int doquit = 0;
int dofiles = 0;
char c;
int i;
int j;
char prompt[256];
while (!dofiles) {
s_displayansi(socket, "filemenu");
sprintf(prompt, "\e[0m\r\nDir: (%d) %s\r\nSub: (%d) %s\r\nTL: %dm :> ", user->cur_file_dir, conf.file_directories[user->cur_file_dir]->name, user->cur_file_sub, conf.file_directories[user->cur_file_dir]->file_subs[user->cur_file_sub]->name, user->timeleft);
s_putstring(socket, prompt);
c = s_getc(socket);
switch(tolower(c)) {
case 'i':
{
s_putstring(socket, "\r\n\r\nFile Directories:\r\n\r\n");
for (i=0;i<conf.file_directory_count;i++) {
if (conf.file_directories[i]->sec_level <= user->sec_level) {
sprintf(prompt, " %d. %s\r\n", i, conf.file_directories[i]->name);
s_putstring(socket, prompt);
}
if (i != 0 && i % 22 == 0) {
s_putstring(socket, "Press any key to continue...\r\n");
c = s_getc(socket);
}
}
s_putstring(socket, "Enter the directory number: ");
s_readstring(socket, prompt, 5);
if (tolower(prompt[0]) != 'q') {
j = atoi(prompt);
if (j < 0 || j >= conf.file_directory_count || conf.file_directories[j]->sec_level > user->sec_level) {
s_putstring(socket, "\r\nInvalid directory number!\r\n");
} else {
s_putstring(socket, "\r\n");
user->cur_file_dir = j;
user->cur_file_sub = 0;
}
}
}
break;
case 's':
{
s_putstring(socket, "\r\n\r\nFile Subdirectories:\r\n\r\n");
for (i=0;i<conf.file_directories[user->cur_file_dir]->file_sub_count;i++) {
sprintf(prompt, " %d. %s\r\n", i, conf.file_directories[user->cur_file_dir]->file_subs[i]->name);
s_putstring(socket, prompt);
if (i != 0 && i % 22 == 0) {
s_putstring(socket, "Press any key to continue...\r\n");
c = s_getc(socket);
}
}
s_putstring(socket, "Enter the sub directory number: ");
s_readstring(socket, prompt, 5);
if (tolower(prompt[0]) != 'q') {
j = atoi(prompt);
if (j < 0 || j >= conf.file_directories[user->cur_file_dir]->file_sub_count) {
s_putstring(socket, "\r\nInvalid sub directiry number!\r\n");
} else {
s_putstring(socket, "\r\n");
user->cur_file_sub = j;
}
}
}
break;
case 'l':
list_files(socket, user);
break;
case 'u':
{
if (user->sec_level >= conf.file_directories[user->cur_file_dir]->file_subs[user->cur_file_sub]->upload_sec_level) {
upload(socket, user);
} else {
s_putstring(socket, "Sorry, you don't have permission to upload in this Sub\r\n");
}
}
break;
case 'd':
download(socket, user);
break;
case 'c':
{
// Clear tagged files
if (tagged_count > 0) {
for (i=0;i<tagged_count;i++) {
free(tagged_files[i]);
}
free(tagged_files);
tagged_count = 0;
}
}
break;
case '}':
{
for (i=user->cur_file_dir;i<conf.file_directory_count;i++) {
if (i + 1 == conf.file_directory_count) {
i = -1;
}
if (conf.file_directories[i+1]->sec_level <= user->sec_level) {
user->cur_file_dir = i + 1;
user->cur_file_sub = 0;
break;
}
}
}
break;
case '{':
{
for (i=user->cur_file_dir;i>=0;i--) {
if (i - 1 == -1) {
i = conf.file_directory_count;
}
if (conf.file_directories[i-1]->sec_level <= user->sec_level) {
user->cur_file_dir = i - 1;
user->cur_file_sub = 0;
break;
}
}
}
break;
case ']':
{
i=user->cur_file_sub;
if (i + 1 == conf.file_directories[user->cur_file_dir]->file_sub_count) {
i = -1;
}
user->cur_mail_area = i + 1;
}
break;
case '[':
{
i=user->cur_file_sub;
if (i - 1 == -1) {
i = conf.file_directories[user->cur_file_dir]->file_sub_count;
}
user->cur_mail_area = i - 1;
}
break;
case 'q':
dofiles = 1;
break;
case 'g':
{
s_putstring(socket, "\r\nAre you sure you want to log off? (Y/N)");
c = s_getc(socket);
if (tolower(c) == 'y') {
dofiles = 1;
doquit = 1;
}
}
break;
}
}
return doquit;
}

View File

@ -114,7 +114,11 @@ void main_menu(int socket, struct user_record *user) {
}
}
break;
case 't':
{
doquit = file_menu(socket, user);
}
break;
}
}
}