914 lines
18 KiB
C
914 lines
18 KiB
C
|
#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 ;
|
||
|
}
|