Added Experimental File areas
This commit is contained in:
parent
955f6b6c06
commit
d2b24c8dab
5
Makefile
5
Makefile
@ -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
19
Xmodem/LICENSE
Normal 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
42
Xmodem/Makefile
Normal 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
197
Xmodem/checkcrc.c
Normal 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
182
Xmodem/crc.c
Normal 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
154
Xmodem/crctab.c
Normal 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
13
Xmodem/crctab.h
Normal 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
913
Xmodem/main.c
Normal 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
155
Xmodem/network.c
Normal 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
600
Xmodem/receive.c
Normal 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
327
Xmodem/send.c
Normal 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
86
Xmodem/seriallog.c
Normal 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 *)×tamp, 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
11
Xmodem/seriallog.h
Normal 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
133
Xmodem/utils.c
Normal 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
111
Xmodem/xmodem.h
Normal 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
417
Xmodem/xmodemr.c
Normal 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
410
Xmodem/xmodemt.c
Normal 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
900
Xmodem/zmodem.c
Normal 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
709
Xmodem/zmodem.h
Normal 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
582
Xmodem/zmodemdump.c
Normal 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 *)×tamp, 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(×tamp.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
750
Xmodem/zmodemr.c
Normal 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
21
Xmodem/zmodemsys.c
Normal 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
1152
Xmodem/zmodemt.c
Normal file
File diff suppressed because it is too large
Load Diff
408
Xmodem/zmutil.c
Normal file
408
Xmodem/zmutil.c
Normal 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 */
|
14
ansis_default/filemenu.ans
Normal file
14
ansis_default/filemenu.ans
Normal file
@ -0,0 +1,14 @@
|
||||
[0;40;37m
|
||||
[7C[1;34mワワワワワワワ ワワ ワワ [30mワワワワ [34mワワワワワワワ ワワワワワワワワワワワ ワワワワワワワ ワワワワワワ ワワ [30mワ [34mワワ
|
||||
[0m[7C[1;44;34mイ゚[0;34mワワ [1m゚゚ [44mロロ[0m [1;44;34mイ゚[0m [1;30mロ゚゚゚ [44;34mイ゚[0;34mワワ [1m゚゚ [44mイ゚[40;30mーワ [44;34mイ゚[40;30mーワ [44;34mイロ[0m [1;44;34mイ゚[0;34mワワ [1m゚゚ [44mイ゚[40;30mーワ [44;34mイロ[0m [1;44;34mイ゚[0m [1;30mロ [44;34mロイ[0m
|
||||
[7C[1;44;34mア[0;34mイ [1;30mワワロイ [44;34mイ[0;34mイ [1;44mア[0;34mロワ[1;30m゚ [44;34mア゚[0m [1;44;34mア[0;34mイワ[1;30mー [44;34mイ゚[0m [1;44;34mー[0;34mイ [1;30mイ [44;34mー[0;34mイ [1;30mイ [44;34mア゚[0m [1;44;34mア[0;34mイワ[1;30mー [44;34mイ゚[0m [1;44;34mー[0;34mイ [1;30mイ [44;34mア゚[0m [1;44;34mー[0;34mイワ[1;30m゚ [44;34mイ [0m
|
||||
[7C[34mロロ [1;30m゚゚゚゚ [0;34m゚゚ [1;30mー[0;34m゚゚゚゚゚゚ ゚゚゚゚゚゚ ゚゚ [1;30m゚ [0;34m゚゚ [1;30m゚ [44;34mー[0;34mロ ゚゚゚゚゚゚ ゚゚ [1;30m゚ [44;34mー[0;34mロ ゚゚゚゚゚゚
|
||||
[1;30mトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト
|
||||
ウ [0;36m}. [1;37mAdvance 1 Directory[0m[10C[1;30mウ [0;36mL. [1;37mList Files[0m[20C[1;30mウ
|
||||
ウ [0;36m{. [1;37mRetreat 1 Directory[0m[10C[1;30mウ [0;36mC. [1;37mClear Tagged List[0m[13C[1;30mウ
|
||||
ウ [0;36m]. [1;37mAdvance 1 Subdirectory[0m[7C[1;30mウ [0;36mD. [1;37mDownload Files Tagged[0m[9C[1;30mウ
|
||||
ウ [0;36m[. [1;37mRetreat 1 Subdirectory[0m[7C[1;30mウ [0;36mU. [1;37mUpload a File[0m[17C[1;30mウ
|
||||
ウ [0;36mI. [1;37mSelect Directory[0m[13C[1;30mウ[0m[35C[1;30mウ
|
||||
ウ [0;36mS. [1;37mSelect Subdirectory[0m[10C[1;30mウ [0;36mQ. [1;37mQuit to Main Menu[0m[13C[1;30mウ
|
||||
ウ[0m[34C[1;30mウ [0;36mG. [1;31mGoodbye [0;31m([1mLog Off[0;31m)[37m[13C[1;30mウ
|
||||
トトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト
|
@ -5,7 +5,7 @@
|
||||
[5C[32mßß [1;30mß [0;32mßß [1;30mß [42;32m°[0;32mÛ ßß [1;30mß [42;32m°[0;32mÛ ßß ßß [1;30mß [42;32m°[0;32mÛ ßß [1;30mß [0;32mßß [1;30mß [42;32m°[0;32mÛ ßßßßßß ßß [1;30mß [42;32m°[0;32mÛ ßßßßßß
|
||||
[1;30mÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
|
||||
³ [0;36mM. [1;37mMessage Areas[0m[16C[1;30m³ [0;36mL.[1;37m BBS List[0m[22C[1;30m³
|
||||
ł T. File Areas[0m[19C[1;30mł [0;36mC.[1;30m [37mChat System[0m[19C[1;30mł
|
||||
³ [0;36mT.[1;30m [37mFile Transfer Area[0m[11C[1;30m³ [0;36mC.[1;30m [37mChat System[0m[19C[1;30m³
|
||||
³ [0;36mB. [1;37mBulletins[0m[20C[1;30m³ [0;36mU. [1;37mUser List[0m[21C[1;30m³
|
||||
³ [0;36mD. [1;37mDoor Games & Utilites[0m[8C[1;30m³ [0;36m1. [1;37mLast 10 Callers[0m[15C[1;30m³
|
||||
³[0m [36mA. [1;37mText/ANSI File Collection[0m [1;30m³[0m[35C[1;30m³
|
||||
|
7
bbs.c
7
bbs.c
@ -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
4
bbs.h
@ -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
|
||||
|
@ -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
736
files.c
Normal 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;
|
||||
}
|
@ -114,7 +114,11 @@ void main_menu(int socket, struct user_record *user) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
{
|
||||
doquit = file_menu(socket, user);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user