This is tipsz.c in view mode; [Download] [Up]
char *numeric_revision = "tipsz 1.00";
#define BUFFERED_WRITE
/*+-------------------------------------------------------------------------
tipsz.c - X/Y/ZMODEM send program
Derived from public domain source by Chuck Forsberg, Omen Technologies
wht%n4hgf@emory.mathcs.emory.edu
Usage: tipsz [-X -Y -Z] [-12+abdefkLlNnquvwy] [-] file ...
(Y) = Option applies to YMODEM only
(Z) = Option applies to ZMODEM only
a (ASCII) change NL to CR/LF
b Binary file transfer override
f send Full pathname (Y/Z)
k Send 1024 byte packets (Y)
L N Limit subpacket length to N bytes (Z)
l N Limit frame length to N bytes (l>=L) (Z)
n send file if source newer (Z)
N send file if source newer or longer (Z)
o Use 16 bit CRC instead of 32 bit CRC (Z)
p Protect existing destination file (Z)
r Resume/Recover interrupted file transfer (Z)
q Quiet (no progress reports)
u Unlink file after transmission
w N Window is N bytes (Z)
y Yes,overwrite existing file (Z)
@file reads a list of filenames from 'file'
Defined functions:
SIGALRM_handler()
bye_bye(sig)
cancel_transaction(sig)
determine_transaction_time()
flushline()
get_file_list_name(namep)
getinsync(flag)
getnak()
getzrxinit()
log_packet_buffer(buf,len)
main(argc,argv)
onintr()
purgeline()
readline(n)
readock(timeout,count)
report_rcvr_cancelled(place_happened)
report_rcvr_skipped()
report_send_stats(filepos)
report_send_transaction()
rewind_file_list()
saybibi()
send_cancel()
sendline(ch)
sendzsinit()
set_file_list(pathc,pathv)
substr(s,t)
usage()
wcputsec(buf,sectnum,cseclen)
wcs(oname)
wcsend()
wctx(flen)
wctxpn(name)
xbuf_build(buf,count)
xsendline(ch)
zbuf_build(buf,count)
zsendfdata()
zsendfile(buf,blen)
--------------------------------------------------------------------------*/
/*+:EDITS:*/
/*:05-21-1990-16:00-wht@tridom-adapt ecu xfer protocols for tipwht */
/*
Error return conditions
255: usage
254: protocol failed (bad line conditions,brain dead remote)
253: could not open any files
128-192: process terminated with signal==code-128 (64 signals allowed for)
signal 0 == program logic error (see cancel_transaction)
127: 127 or more files not transmitted (see ~/.tip/log)
1-126: count of files not transmitted (see ~/.tip/log)
0: file transfer completely successful
*/
char *substr(),*getenv();
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <ctype.h>
#include <fcntl.h>
#ifdef NeXT
#include <sys/stat.h>
#endif /* NeXT */
#include "zmodem.h"
#include "zlint.h"
#if defined(__STDC__) || defined(__cplusplus)
# define P_A(s) s
#else
# define P_A(s) ()
#endif
void log_packet_buffer P_A((unsigned char *buf, int len));
void rewind_file_list P_A((void));
void set_file_list P_A((int pathc, char **pathv));
int get_file_list_name P_A((char **namep));
void bye_bye P_A((int sig));
void cancel_transaction P_A((int sig));
int onintr P_A((void));
void report_send_transaction P_A((void));
void report_send_stats P_A((long filepos));
void report_rcvr_cancelled P_A((char *place_happened));
void report_rcvr_skipped P_A((void));
int xsendline P_A((int ch));
int sendline P_A((int ch));
int flushline P_A((void));
int main P_A((int argc, char *argv[]));
int wcsend P_A((void));
int wcs P_A((char *oname));
int wctxpn P_A((char *name));
int getnak P_A((void));
int wctx P_A((long flen));
int wcputsec P_A((unsigned char *buf, int sectnum, int cseclen));
int xbuf_build P_A((char *buf, int count));
int zbuf_build P_A((char *buf, int count));
int SIGALRM_handler P_A((void));
int readock P_A((int timeout, int count));
int readline P_A((int n));
int purgeline P_A((void));
int send_cancel P_A((void));
char *substr P_A((char *str, char *substr));
int usage P_A((void));
int getzrxinit P_A((void));
int sendzsinit P_A((void));
int zsendfile P_A((char *buf, int blen));
int zsendfdata P_A((void));
int getinsync P_A((int flag));
int saybibi P_A((void));
void determine_transaction_time P_A((void));
#undef P_A
extern char *sys_errlist[];
extern unsigned short crctab[]; /* wht */
extern unsigned long total_data_chars_xfered; /* zcurses.c */
extern int errno;
extern int show_window;
extern int Rxtimeout; /* Tenths of seconds to wait for something */
extern char Rxhdr[4]; /* Received header */
extern char Txhdr[4]; /* Transmitted header */
extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */
extern long Rxpos; /* Received file position */
extern long Txpos; /* Transmitted file position */
extern char *frametypes[];
extern char Attn[]; /* Attention string rx sends to tx on err */
extern char s256[];
#define RETRYMAX 10 /* non-zmodem retry count on block send */
#define VMIN_COUNT 2 /* must not exceed 255 */
unsigned char vmin_count = VMIN_COUNT;
int iofd = 0; /* line io fd */
#ifdef BUFFERED_WRITE
FILE *iofp;
char iofpbuf[256];
#endif
/*
* Attention string to be extipted by receiver to interrupt streaming data
* when an error is detected. A pause (0336) may be needed before the
* ^C (03) or after it.
*/
#if defined(READCHECK)
char Myattn[] = { 0 };
#else
#if defined(M_SYS5)
char Myattn[] = { 03,0336,0 };
#else
char Myattn[] = { 0 };
#endif
#endif
FILE *in;
char *Cmdstr; /* Pointer to the command string */
char *bottom_label = (char *)0;
char Crcflg;
char Lastrx;
char Lzconv; /* Local ZMODEM file conversion request */
char Lzmanag; /* Local ZMODEM file management request */
char Lztrans;
char Pathname[PATHLEN];
char curr_dir[256];
char s128[128];
char txbuf[1024];
char zconv; /* ZMODEM file conversion request */
char zmanag; /* ZMODEM file management request */
char ztrans; /* ZMODEM file transport request */
int Ascii=0; /* Add CR's for brain damaged programs */
int Cmdack1; /* Rx ACKs command,then do it */
int Cmdtries = 11;
int Command = 0; /* Send a command,then exit. */
int Dontread; /* Don't read the buffer,it's still there */
int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */
int Exitcode = 0;
int Filcnt=0; /* count of number of files opened */
int FilesTotal;
int Filesleft;
int Fullname=0; /* transmit full pathname */
int Lastn; /* Count of last buffer read or -1 */
int Lfseen=0;
int Noeofseen;
int Nozmodem = 0;
int Optiong; /* no wait for block ACK's */
int Quiet=0; /* overrides logic that would otherwise set verbose */
int Rxflags = 0;
int SameZrposAgain=0; /* How many times we've been ZRPOS'd same place (wht) */
int Tframlen = 0; /* Override for tx frame length */
int Totsecs; /* total number of blocks this file */
int Twostop = 0; /* use two stop bits */
int Unlinkafter=0; /* Unlink file after it is sent */
int Wantfcs32 = TRUE; /* want to send 32 bit FCS */
int Xmodem=0; /* XMODEM Protocol - don't send pathnames */
int Zctlesc; /* Encode control characters */
int Zmodem=0; /* ZMODEM protocol requested by receiver */
int Zrwindow = 1400; /* RX window size (controls garbage count) */
int blklen=128; /* length of transmitted records */
int blklen_original;
int blkopt=0; /* Override value for zmodem blklen */
int tipsz_flag = 1;
int skip_count = 0; /* skipped files */
int errors;
int firstsec;
int log_packets = 0;
int no_files = 0;
int npats = 0;
long Lastread; /* Beginning offset of last buffer read */
long Lastsync; /* Last offset to which we got a ZRPOS */
long Lrxpos; /* Receiver's last reported offset */
long TotalLeft;
long TotalToSend;
long bytcnt;
long rx_char_count = 0L;
long this_file_length;
long tx_char_count = 0L;
unsigned Baudrate;
unsigned Rxbuflen = 16384; /* Receiver's max buffer length */
unsigned Txwcnt; /* Counter used to space ack requests */
unsigned Txwindow; /* Control the size of the transmitted window */
unsigned Txwspac; /* Spacing between zcrcq requests */
unsigned int bad_condx_blklen = 0; /* if <>0,blklen has been reduced (wht) */
unsigned int bad_condx_frame_count = 0; /* frame # last SameZrposAgain (wht) */
unsigned int this_file_frame_count; /* count of frames sent this file (wht) */
#define MAX_PATHS 512
char *paths[MAX_PATHS];
jmp_buf tohere; /* For the interrupt on RX timeout */
jmp_buf intrjmp; /* For the interrupt on RX CAN */
int file_list_pathc;
int file_list_path_current;
char **file_list_pathv;
int required_type = 0;
FILE *fpflst = (FILE *)0;
/*+-------------------------------------------------------------------------
log_packet_buffer(buf,len)
--------------------------------------------------------------------------*/
void
log_packet_buffer(buf,len)
register unsigned char *buf;
register int len;
{
char xbuf[32];
while(len--)
{
sprintf(xbuf,"%02x ",*buf++);
write(log_packets,xbuf,strlen(xbuf));
}
write(log_packets,"\n",1);
} /* end of log_packet_buffer */
/*+-------------------------------------------------------------------------
rewind_file_list()
--------------------------------------------------------------------------*/
void
rewind_file_list()
{
file_list_path_current = 0;
if(fpflst)
{
fclose(fpflst);
fpflst = (FILE *)0;
}
} /* end of rewind_file_list */
/*+-------------------------------------------------------------------------
set_file_list(pathc,pathv)
--------------------------------------------------------------------------*/
void
set_file_list(pathc,pathv)
int pathc;
char **pathv;
{
file_list_pathc = pathc;
file_list_pathv = pathv;
rewind_file_list();
} /* end of set_file_list */
/*+-------------------------------------------------------------------------
get_file_list_name(namep)
--------------------------------------------------------------------------*/
get_file_list_name(namep)
char **namep;
{
register char *cptr;
static char name[256];
try_fpflst:
if(fpflst)
{
if(fgets(name,sizeof(name),fpflst) != NULL)
{
name[strlen(name) - 1] = 0;
*namep = name;
return(1);
}
fclose(fpflst);
fpflst = (FILE *)0;
}
next_arg:
if(file_list_path_current == file_list_pathc)
return(0);
cptr = file_list_pathv[file_list_path_current++];
if(*cptr != '@')
{
*namep = cptr;
return(1);
}
cptr++;
if((fpflst = fopen(cptr,"r")) == NULL)
goto next_arg;
goto try_fpflst;
} /* end of get_file_list_name */
/*+-------------------------------------------------------------------------
bye_bye(sig)
--------------------------------------------------------------------------*/
void
bye_bye(sig)
int sig;
{
exit(sig+128);
} /* end of bye_bye */
/*+-------------------------------------------------------------------------
cancel_transaction(sig)
called by signal interrupt or terminate to clean things up
--------------------------------------------------------------------------*/
void
cancel_transaction(sig)
{
if(Zmodem)
zmputs(Attn);
send_cancel();
mode(0);
if(sig >= 0)
{
sprintf(s128,"tipsz aborted (signal %d)",sig);
report_str(s128,0);
}
report_tx_ind(0);
report_rx_ind(0);
report_uninit(0);
bye_bye(sig);
} /* end of cancel_transaction */
/* Called when ZMODEM gets an interrupt (^X) */
onintr()
{
signal(SIGINT,SIG_IGN);
#if defined(M_SYS5)
report_rx_ind(0);
report_tx_ind(0);
#endif
longjmp(intrjmp,-1);
}
/*+-------------------------------------------------------------------------
report_send_transaction()
--------------------------------------------------------------------------*/
void
report_send_transaction()
{
if(Xmodem)
{
long blocks = (TotalToSend >> 7) + ((TotalToSend % 128) != 0);
long secs = 7 /* slightly worse than average first nak delay */
+ (blocks / 5L) /* assume .2 sec ack time */
+ ((blocks * (128L + 16L)) / (Baudrate / 10));
if(!secs)
secs = 10L;
sprintf(s128,"Sending %ld blocks time ~= %ld:%02ld",
blocks,secs/60,secs % 60);
}
else
{
long min_100 =
(FilesTotal * 2L) + (((TotalToSend * 11L)) * 10L) / (Baudrate * 6L);
if(!min_100)
min_100 = 4L;
#if defined(M_I286) /* slower */
else if(Baudrate > 4800)
{
min_100 *= 13;
min_100 /= 9; /* yech ... empirical */
}
#endif
sprintf(s128,"Sending %ld bytes total time ~= %2lu:%02lu",
TotalToSend,min_100 / 100,((min_100 % 100) * 60L) / 100L);
}
report_transaction(s128);
} /* end of report_send_transaction */
/*+-------------------------------------------------------------------------
report_send_stats(filepos)
--------------------------------------------------------------------------*/
void
report_send_stats(filepos)
long filepos;
{
if(Xmodem)
sprintf(s128,"File %d%% complete",
(this_file_length == 0) ? (int)100 :
(int)((filepos * 100L) / this_file_length));
else
sprintf(s128,"This file %d%%, transaction %d%% complete",
(this_file_length == 0) ? (int)100 :
(int)((filepos * 100L)/this_file_length),
(TotalToSend == 0) ? (int)100 :
(int)(((total_data_chars_xfered + filepos) * 100L)
/ TotalToSend));
report_str(s128,0);
report_txpos(filepos);
} /* end of report_send_stats */
/*+-------------------------------------------------------------------------
report_rcvr_cancelled(place_happened)
--------------------------------------------------------------------------*/
void
report_rcvr_cancelled(place_happened)
char *place_happened;
{
strcpy(s128,"SEND CANCELLED");
report_str(s128 + 5,1);
skip_count++;
report_error_count();
} /* end of report_rcvr_cancelled */
/*+-------------------------------------------------------------------------
report_rcvr_skipped()
--------------------------------------------------------------------------*/
void
report_rcvr_skipped()
{
sprintf(s128,"SEND skipped: %s",Pathname);
report_str(s128 + 5,-1);
skip_count++;
report_error_count();
TotalToSend -= this_file_length;
report_send_transaction();
} /* end of report_rcvr_skipped */
/*+-------------------------------------------------------------------------
xsendline(ch)
--------------------------------------------------------------------------*/
xsendline(ch)
char ch;
{
#ifdef BUFFERED_WRITE
fputc(ch,iofp);
#else
write(iofd,&ch,1);
#endif
++tx_char_count;
} /* end of xsendline */
/*+-------------------------------------------------------------------------
sendline(ch)
--------------------------------------------------------------------------*/
sendline(ch)
char ch;
{
xsendline(ch);
} /* end of sendline */
flushline()
{
#ifdef BUFFERED_WRITE
fflush(iofp);
#endif
}
main(argc,argv)
char *argv[];
{
register char *cp;
long min_100;
char **patts = paths;
char **gargv = argv;
int gargc = argc;
signal(SIGINT,bye_bye);
signal(SIGTERM,bye_bye);
get_curr_dir(curr_dir,sizeof(curr_dir));
Rxtimeout = 600;
npats=0;
if(argc<2)
usage();
while(--argc)
{
cp = *++argv;
if(*cp == '-')
{
cp++;
switch(*cp++)
{
case 'X':
required_type = 1;
Xmodem = TRUE;
break;
case 'Y':
required_type = 1;
Nozmodem = TRUE;
blklen=1024;
break;
case 'Z':
show_window = 1;
required_type = 1;
break;
case '+':
Lzmanag = ZMAPND;
break;
case 'a':
Lzconv = ZCNL;
Ascii = TRUE;
break;
case 'b':
Lzconv = ZCBIN;
break;
case 'd':
++Dottoslash;
/* **** FALL THROUGH TO **** */
case 'f':
Fullname=TRUE;
break;
case ',':
log_packets = 1;
break;
case '/':
if(--argc < 1)
usage();
strcpy(curr_dir,*++argv);
break;
case '.':
if(--argc < 1)
usage();
iofd = atoi(*++argv);
break;
#ifdef HAYES
case ':':
if(--argc < 1)
usage();
Baudrate = atoi(*++argv);
break;
#endif
case 'C':
if(--argc < 1)
/* usage("no label after -C"); */
usage();
bottom_label = *++argv;
break;
case 'e':
Zctlesc = 1;
break;
case 'k':
blklen=1024;
break;
case 'L':
if(--argc < 1)
{
usage();
}
blkopt = atoi(*++argv);
if(blkopt<24 || blkopt>1024)
usage();
break;
case 'l':
if(--argc < 1)
{
usage();
}
Tframlen = atoi(*++argv);
if(Tframlen<32 || Tframlen>1024)
usage();
break;
case 'N':
Lzmanag = ZMNEWL;
break;
case 'n':
Lzmanag = ZMNEW;
break;
case 'o':
Wantfcs32 = FALSE;
break;
case 'p':
Lzmanag = ZMPROT;
break;
case 'r':
Lzconv = ZCRESUM;
case 't':
if(--argc < 1)
{
usage();
}
Rxtimeout = atoi(*++argv);
if(Rxtimeout<10 || Rxtimeout>1000)
usage();
break;
case 'u':
++Unlinkafter;
break;
case 'w':
if(--argc < 1)
{
usage();
}
Txwindow = atoi(*++argv);
if(Txwindow < 256)
Txwindow = 256;
Txwindow = (Txwindow/64) * 64;
Txwspac = Txwindow/4;
if(blkopt > Txwspac || (!blkopt && Txwspac < 1024))
blkopt = Txwspac;
break;
case 'y':
Lzmanag = ZMCLOB;
break;
case 'z':
Lztrans = ZTRLE;
break;
default:
usage();
}
}
else if(argc > 0)
{
if(npats < MAX_PATHS)
{
npats++;
*patts++ = cp;
}
else
{
printf("too many filenames to send\n");
exit(255);
}
}
}
if(!required_type || !iofd)
{
printf("can only be run by tip\n");
exit(255);
}
if(npats < 1 && !Command)
usage();
set_file_list(npats,paths);
sprintf(s128,"%s",numeric_revision);
if(log_packets)
{
char log_packets_name[64];
FILE *ftmp;
int iargv;
sprintf(log_packets_name,"/tmp/sz%05d.plog",getpid());
unlink(log_packets_name);
ftmp = fopen(log_packets_name,"w");
fclose(ftmp);
log_packets = open(log_packets_name,O_WRONLY,0644);
if(log_packets < 0)
log_packets = 0;
else
{
write(log_packets,"exec: ",6);
for(iargv = 0; iargv < gargc; iargv++)
{
write(log_packets,gargv[iargv],strlen(gargv[iargv]));
write(log_packets," ",1);
}
write(log_packets,"\n",1);
}
}
report_init(s128);
mode(1);
if(signal(SIGINT,cancel_transaction) == SIG_IGN)
signal(SIGINT,SIG_IGN);
else
signal(SIGINT,cancel_transaction);
signal(SIGTERM,cancel_transaction);
report_str("calculating transaction time",-1);
determine_transaction_time();
#ifdef BUFFERED_WRITE
iofp = fdopen(iofd,"w");
setbuffer(iofp,iofpbuf,sizeof(iofpbuf));
#endif
if(!Xmodem)
{
TotalToSend = TotalLeft;
report_send_transaction();
report_str("starting remote receiver",-1);
if(!Nozmodem)
write(iofd,"rz\r",3);
else /* wht -- why not? */
write(iofd,"rb\r",3); /* wht */
sleep(2);
report_str("beginning transfer",-1);
if(!Nozmodem)
{
stohdr(0L);
zshhdr(4,ZRQINIT,Txhdr);
}
}
else
report_str("beginning transfer",-1);
if(wcsend()==ERROR)
{
Exitcode=254; /*wht was 0200 */
send_cancel();
}
mode(0);
report_uninit(0);
if(no_files)
Exitcode = 253;
exit(Exitcode ? Exitcode : (skip_count > 127) ? 127 : skip_count);
/*NOTREACHED*/
}
/*+-------------------------------------------------------------------------
wcsend(argc,argp) -- send group of files
--------------------------------------------------------------------------*/
wcsend()
{
register n;
char *name;
Crcflg=FALSE;
firstsec=TRUE;
bytcnt = -1;
rewind_file_list();
while(get_file_list_name(&name))
{
Totsecs = 0;
if(wcs(name)==ERROR)
return(ERROR);
}
Totsecs = 0;
if(Filcnt==0)
{ /* bitch if we couldn't open ANY files */
send_cancel();
strcpy(s128,"SEND cannot open any requested files");
report_str(s128 + 5,1);
sleep(2); /* allow time for other rz to get ready */
no_files = 1;
return(ERROR); /* ... then cancel */
}
if(Zmodem)
saybibi();
else if(!Xmodem)
wctxpn("");
return(OK);
}
/*+-------------------------------------------------------------------------
wcs(oname) -- send a file
--------------------------------------------------------------------------*/
wcs(oname)
char *oname;
{
register c;
register char *p;
struct stat f;
strcpy(Pathname,oname); /* global copy of name */
if((in=fopen(oname,"r"))==NULL)
{
sprintf(s128,"SEND %s: %s",sys_errlist[errno],oname);
report_str(s128 + 5,1);
skip_count++;
report_error_count();
return(OK); /* pass over it,there may be others */
}
++Noeofseen;
Lastread = 0;
Lastn = -1;
Dontread = FALSE;
/* Check for directory or block special files */
fstat(fileno(in),&f);
c = f.st_mode & S_IFMT;
if(c == S_IFDIR || c == S_IFBLK)
{
sprintf(s128,"SEND %s: %s",
(c == S_IFDIR) ? "directory" : "block device",oname);
report_str(s128 + 5,1);
skip_count++;
report_error_count();
fclose(in);
return(OK);
}
f.st_mode &= ~(S_ISUID | S_ISGID);
Filcnt++;
report_file_send_open(oname,&f);
this_file_length = f.st_size;
report_send_stats(0L);
switch(wctxpn(Pathname))
{
case ERROR:
sprintf(s128,"SEND protocol failure: %s",oname);
report_str(s128 + 5,1);
skip_count++;
report_error_count();
report_file_close();
fclose(in);
return(ERROR);
case ZSKIP:
report_rcvr_skipped();
return(OK);
}
if(!Zmodem && wctx(f.st_size)==ERROR)
return(ERROR);
if(Unlinkafter)
unlink(oname);
return(0);
}
/*
* generate and transmit pathname block consisting of
* pathname (null terminated),
* file length,mode time and file mode in octal
* as provided by the Unix fstat call.
* N.B.: modifies the passed name,may extend it!
*/
wctxpn(name)
char *name;
{
register char *p,*q;
char name2[PATHLEN];
struct stat f;
if(Xmodem)
{
if((in!=stdin) && *name && fstat(fileno(in),&f)!= -1)
{
TotalToSend = f.st_size;
report_protocol_type("XMODEM");
report_send_transaction();
report_xfer_mode((Ascii) ? "ASCII" : "BINARY");
report_last_txhdr("Waiting on NAK",0);
}
return(OK);
}
if(!Zmodem)
{
report_last_txhdr("START PENDING",0);
if(getnak())
{
report_str("Timeout on pathname nak",1);
return(ERROR);
}
}
q = (char *) 0;
if(Dottoslash)
{ /* change . to . */
for(p=name; *p; ++p)
{
if(*p == '/')
q = p;
else if(*p == '.')
*(q=p) = '/';
}
if(q && strlen(++q) > 8)
{ /* If name>8 chars */
q += 8; /* make it .ext */
strcpy(name2,q); /* save excess of name */
*q = '.';
strcpy(++q,name2); /* add it back */
}
}
for(p=name,q=txbuf ; *p; )
if((*q++ = *p++) == '/' && !Fullname)
q = txbuf;
*q++ = 0;
p=q;
while(q < (txbuf + 1024))
*q++ = 0;
if(!Ascii && (in != stdin) && *name && !fstat(fileno(in),&f))
sprintf(p,"%lu %lo %o 0 %d %ld",f.st_size,f.st_mtime,
f.st_mode &= ~(S_ISUID | S_ISGID),
Filesleft,TotalLeft);
report_xfer_mode((Lzconv == ZCNL) ? "ASCII" : "BINARY");
TotalLeft -= f.st_size;
if(--Filesleft <= 0)
TotalLeft = 0;
if(TotalLeft < 0)
TotalLeft = 0;
/* force 1k blocks if name won't fit in 128 byte block */
if(txbuf[125])
blklen=1024;
else
{ /* A little goodie for IMP/KMD */
txbuf[127] = (f.st_size + 127) >>7;
txbuf[126] = (f.st_size + 127) >>15;
}
if(Zmodem)
return(zsendfile(txbuf,1+strlen(p)+(p-txbuf)));
report_protocol_type("YMODEM");
if(wcputsec(txbuf,0,128)==ERROR)
return(ERROR);
return(OK);
}
getnak()
{
register firstch;
Lastrx = 0;
for(;;)
{
switch(firstch = readock(50,1)) /* 50 was 800 (80 secs!!) wht */
{
case ZPAD:
if(getzrxinit())
return(ERROR);
Ascii = 0; /* Receiver does the conversion */
return(FALSE);
case TIMEOUT:
report_str("Timeout",1);
return(TRUE);
case WANTG:
#if defined(MODE2OK)
mode(2); /* Set cbreak,XON/XOFF,etc. */
#endif
Optiong = TRUE;
blklen=1024;
case WANTCRC:
Crcflg = TRUE;
case NAK:
return(FALSE);
case CAN:
if((firstch = readock(20,1)) == CAN && Lastrx == CAN)
return(TRUE);
default:
break;
}
Lastrx = firstch;
}
}
/*+-------------------------------------------------------------------------
wctx(flen)
--------------------------------------------------------------------------*/
wctx(flen)
long flen;
{
register int thisblklen;
register int firstch;
register int sectnum;
register int attempts;
long charssent;
charssent = 0;
firstsec=TRUE;
thisblklen = blklen;
report_txblklen(blklen);
attempts = 8;
while(((firstch = readock(Rxtimeout,2)) != NAK) &&
(firstch != WANTCRC) && (firstch != WANTG) &&
(firstch != TIMEOUT) && (firstch != CAN))
{
if(!--attempts)
{
report_str("bad start stimulus",1);
send_cancel();
return(ERROR);
}
}
if(firstch==CAN)
{
report_str("receiver CAN",1);
return(ERROR);
}
if((firstch==WANTCRC) || (firstch==WANTG))
Crcflg=TRUE;
report_protocol_crc_type((Crcflg)
? ((firstch== WANTG) ? "/CRC-g" : "/CRC")
: "/CHK");
sectnum=0;
for(;;)
{
if(flen <= (charssent + 896L))
{
thisblklen = 128;
report_txblklen(thisblklen);
}
if(!xbuf_build(txbuf,thisblklen))
break;
if(wcputsec(txbuf,++sectnum,thisblklen)==ERROR)
return(ERROR);
charssent += thisblklen;
}
/* file transfer completed */
report_file_byte_io(this_file_length);
report_file_close();
fclose(in);
attempts=0;
do
{
purgeline();
sendline(EOT);
flushline();
report_last_txhdr("EOT",0);
++attempts;
} while((firstch=(readock(Rxtimeout,1)) != ACK) && attempts < RETRYMAX);
if(attempts == RETRYMAX)
{
report_str("No ACK on EOT",1);
return(ERROR);
}
else
return(OK);
}
wcputsec(buf,sectnum,cseclen)
unsigned char *buf;
int sectnum;
int cseclen; /* data length of this block to send */
{
register int checksum;
register int wcj;
register unsigned char *cp;
unsigned short oldcrc;
int firstch;
int attempts;
firstch=0; /* part of logic to detect CAN CAN */
sprintf(s128,"Sending block %d",sectnum);
report_last_txhdr(s128,0);
if(log_packets)
{
log_packet_buffer(buf,cseclen);
}
for(attempts=0; attempts <= RETRYMAX; attempts++)
{
Lastrx= firstch;
sendline(cseclen == 1024 ? STX : SOH);
sendline(sectnum);
sendline(-sectnum - 1);
oldcrc=checksum=0;
for(wcj = cseclen,cp = buf; --wcj >= 0; )
{
sendline(*cp);
oldcrc=updcrc(*cp,oldcrc);
checksum += *cp++;
}
if(Crcflg)
{
oldcrc=updcrc(0,updcrc(0,oldcrc));
sendline((int)(oldcrc >> 8));
sendline((int)(oldcrc & 0xFF));
}
else
sendline(checksum);
flushline();
if(Optiong)
{
firstsec = FALSE;
return(OK);
}
firstch = readock(Rxtimeout,(Noeofseen&§num) ? 2:1);
gotnak:
switch(firstch)
{
case CAN:
if(Lastrx == CAN)
{
cancan:
report_last_rxhdr("CAN",1);
return(ERROR);
}
break;
case TIMEOUT:
report_last_rxhdr("Timeout",1);
continue;
case WANTCRC:
if(firstsec)
Crcflg = TRUE;
case NAK:
report_last_rxhdr("NAK",1);
continue;
case ACK:
report_last_rxhdr("ACK",0);
firstsec=FALSE;
Totsecs += (cseclen>>7);
return(OK);
case ERROR:
report_last_rxhdr("Noise",0);
break;
default:
sprintf(s128,"0x%02x ???",firstch);
report_last_rxhdr(s128,1);
break;
}
for(;;)
{
Lastrx = firstch;
if((firstch = readock(Rxtimeout,2)) == TIMEOUT)
break;
if(firstch == NAK || firstch == WANTCRC)
goto gotnak;
if(firstch == CAN && Lastrx == CAN)
goto cancan;
}
}
report_str("retry count exceeded",1);
return(ERROR);
}
/* fill buf with count chars padding with ^Z for CPM */
xbuf_build(buf,count)
register char *buf;
{
register c,m;
long lseek();
long X_txpos = lseek(fileno(in),0L,1);
char diag_str[64];
report_send_stats(X_txpos);
if( !Ascii)
{
m = read(fileno(in),buf,count);
if(log_packets)
{
sprintf(diag_str,"read rtnd %d of %d",m,count);
report_str(diag_str,1);
}
if(m <= 0)
return(0);
while(m < count)
buf[m++] = 032;
return(count);
}
m=count;
if(Lfseen)
{
*buf++ = 012;
--m;
Lfseen = 0;
}
while((c=getc(in))!=EOF)
{
if(c == 012)
{
*buf++ = 015;
if(--m == 0)
{
Lfseen = TRUE;
break;
}
}
*buf++ =c;
if(--m == 0)
break;
}
if(m==count)
return(0);
else
while(--m>=0)
*buf++ = CPMEOF;
return(count);
}
/*+-------------------------------------------------------------------------
zbuf_build(buf,count) - fill buf with count chars
--------------------------------------------------------------------------*/
zbuf_build(buf,count)
register char *buf;
int count;
{
register c,m;
m=count;
while((c=getc(in))!=EOF)
{
*buf++ =c;
if(--m == 0)
break;
}
return(count - m);
} /* end of zbuf_build */
/*+-------------------------------------------------------------------------
SIGALRM_handler()
--------------------------------------------------------------------------*/
SIGALRM_handler()
{
#if defined(M_SYS5)
report_rx_ind(0);
report_tx_ind(0);
#endif
longjmp(tohere,-1);
} /* end of SIGALRM_handler */
/*+-------------------------------------------------------------------------
readock(timeout,count)
timeout is in tenths of seconds reads character(s) from file
descriptor 'fd' read 'count' characters, (1 <= count <= 3) if more than
one received, return ERROR unless all are CAN normal response is NAK,
ACK, CAN, G or C
--------------------------------------------------------------------------*/
readock(timeout,count)
int timeout;
int count;
{
register int c;
static char byt[5];
if(setjmp(tohere))
{
report_str("TIMEOUT",1);
return(TIMEOUT);
}
c = timeout/10;
if(c<2)
c = 2;
signal(SIGALRM,SIGALRM_handler);
alarm(c);
#if defined(ONEREAD)
c=read(iofd,byt,1); /* regulus raw read is unique */
#else
c=read(iofd,byt,count);
#endif
rx_char_count += c;
alarm(0);
if(c<1)
return(TIMEOUT);
if(c==1)
return(byt[0]&0377);
else
while(c)
if(byt[--c] != CAN)
return(ERROR);
return(CAN);
} /* end of readock */
/*+-------------------------------------------------------------------------
readline(n)
--------------------------------------------------------------------------*/
readline(n)
int n;
{
return(readock(n,1));
} /* end of readline */
/*+-------------------------------------------------------------------------
purgeline()
--------------------------------------------------------------------------*/
purgeline()
{
#if defined(M_SYS5)
ioctl(iofd,TCFLSH,0);
#else
lseek(iofd,0L,2);
#endif
} /* end of purgeline */
/*+-------------------------------------------------------------------------
send_cancel() - send cancel to remote
--------------------------------------------------------------------------*/
send_cancel()
{
static char canistr[] =
{
24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
};
register char *cptr = canistr;
report_last_txhdr("^X CAN",1);
while(*cptr)
sendline(*cptr++);
flushline();
} /* end of send_cancel */
/*+-------------------------------------------------------------------------
substr(str,substr) - searches for substr in string str
--------------------------------------------------------------------------*/
char *
substr(str,substr)
register char *str,*substr;
{
register char *sptr;
register char *ssptr;
for(sptr = str; *str; str++)
{
if(*str == *substr)
{
sptr = str;
ssptr = substr;
while(1)
{
if(*ssptr == 0)
return(str);
if(*sptr++ != *ssptr++)
break;
}
}
}
return(NULL);
} /* end of substr */
/*+-------------------------------------------------------------------------
usage()
--------------------------------------------------------------------------*/
usage()
{
exit(255);
} /* end of usage */
/*+-------------------------------------------------------------------------
getzrxinit() - Get the receiver's init parameters
--------------------------------------------------------------------------*/
getzrxinit()
{
register n;
struct stat f;
for(n=10; --n>=0; )
{
switch(zgethdr(Rxhdr,1))
{
case ZCHALLENGE: /* Echo receiver's challenge numbr */
stohdr(Rxpos);
zshhdr(4,ZACK,Txhdr);
continue;
case ZCOMMAND: /* They didn't see out ZRQINIT */
stohdr(0L);
zshhdr(4,ZRQINIT,Txhdr);
continue;
case ZRINIT:
Rxflags = 0377 & Rxhdr[ZF0];
Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
report_protocol_type("ZMODEM");
report_protocol_crc_type((Txfcs32) ? "/CRC32" : "/CRC16");
Zctlesc |= Rxflags & TESCCTL;
Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
if( !(Rxflags & CANFDX))
Txwindow = 0;
#if defined(MODE2OK)
mode(2); /* Set cbreak,XON/XOFF,etc. */
#endif
#if !defined(READCHECK)
#if !defined(M_SYS5)
/* Use 1024 byte frames if no sample/interrupt */
if(Rxbuflen < 32 || Rxbuflen > 1024)
{
Rxbuflen = 1024;
}
#endif
#endif
/* Override to force shorter frame length */
if(Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
Rxbuflen = Tframlen;
if( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
Rxbuflen = Tframlen;
/* If using a pipe for testing set lower buf len */
fstat(iofd,&f);
if((f.st_mode & S_IFMT) != S_IFCHR
&& (Rxbuflen == 0 || Rxbuflen > 4096))
Rxbuflen = 4096;
sprintf(s128,"Remote: CRC32 %c duplex %c",
(Rxflags & CANFC32) ? 'y' : 'n',
(Rxflags & CANFDX) ? 'y' : 'n');
if(Rxbuflen)
sprintf(&s128[strlen(s128)]," buflen %u",Rxbuflen);
else
strcat(s128," continuous stream y");
report_str(s128,2);
/*
* If input is not a regular file,force ACK's each 1024
* (A smarter strategey could be used here ...)
*/
if( !Command)
{
fstat(fileno(in),&f);
if(((f.st_mode & S_IFMT) != S_IFREG)
&& (Rxbuflen == 0 || Rxbuflen > 1024))
Rxbuflen = 1024;
}
if(Baudrate > 300) /* Set initial subpacket len */
blklen = 256;
if(Baudrate > 1200)
blklen = 512;
if(Baudrate >= 2400) /* original code had > 2400 here ****/
blklen = 1024;
if(Rxbuflen && blklen>Rxbuflen)
blklen = Rxbuflen;
if(blkopt && blklen > blkopt)
blklen = blkopt;
blklen_original = blklen;
report_txblklen(blklen);
return(sendzsinit());
case ZCAN:
case TIMEOUT:
return(ERROR);
case ZRQINIT:
if(Rxhdr[ZF0] == ZCOMMAND)
continue;
default:
zshhdr(4,ZNAK,Txhdr);
continue;
}
}
return(ERROR);
} /* end of getzrxinit */
/*+-------------------------------------------------------------------------
sendzsinit() - send send-init information
--------------------------------------------------------------------------*/
sendzsinit()
{
register c;
if(Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
return(OK);
errors = 0;
for(;;)
{
stohdr(0L);
if(Zctlesc)
{
Txhdr[ZF0] |= TESCCTL;
zshhdr(4,ZSINIT,Txhdr);
}
else
zsbhdr(4, ZSINIT, Txhdr);
zsdata(Myattn,1+strlen(Myattn),ZCRCW);
c = zgethdr(Rxhdr,1);
switch(c)
{
case ZCAN:
return(ERROR);
case ZACK:
return(OK);
default:
if(++errors > 19)
return(ERROR);
continue;
}
}
} /* end of sendzsinit */
/*+-------------------------------------------------------------------------
zsendfile(buf,blen) - send file name & info
--------------------------------------------------------------------------*/
zsendfile(buf,blen)
char *buf;
int blen;
{
register c;
for(;;)
{
blklen = blklen_original;
report_txblklen(blklen);
Txhdr[ZF0] = Lzconv; /* file conversion request */
Txhdr[ZF1] = Lzmanag; /* file management request */
Txhdr[ZF2] = Lztrans; /* file transport request */
Txhdr[ZF3] = 0;
zsbhdr(4, ZFILE, Txhdr);
zsdata(buf,blen,ZCRCW);
again:
c = zgethdr(Rxhdr,1);
switch(c)
{
case ZRINIT:
while((c = readline(50)) > 0)
if(c == ZPAD)
{
goto again;
}
/* **** FALL THRU TO **** */
default:
continue;
case ZCAN:
case TIMEOUT:
case ZABORT:
case ZFIN:
return(ERROR);
case ZSKIP:
report_file_close();
fclose(in);
return(c);
case ZRPOS:
/*
* Suppress zcrcw request otherwise triggered by
* lastyunc==bytcnt
*/
Lastsync = (bytcnt = Txpos = Rxpos) -1;
fseek(in,Rxpos,0);
Dontread = FALSE;
report_send_stats(Txpos);
return(zsendfdata());
}
}
} /* end of zsendfile */
/*+-------------------------------------------------------------------------
zsendfdata() - send data in the file
--------------------------------------------------------------------------*/
zsendfdata()
{
register c,e,n;
register newcnt;
register long tcount = 0;
int junkcount; /* Counts garbage chars received by TX */
static int tleft = 6; /* Counter for test mode */
int err;
Lrxpos = 0;
junkcount = 0;
SameZrposAgain = FALSE; /* variable was named Beenhereb4 (wht) */
this_file_frame_count = 0; /* we've sent no frames (wht) */
somemore:
if(setjmp(intrjmp))
{
waitack:
junkcount = 0;
c = getinsync(0);
gotack:
switch(c)
{
default:
case ZCAN:
report_rcvr_cancelled("zfdata-1");
report_file_close();
fclose(in);
return(ERROR);
case ZSKIP:
report_file_close();
fclose(in);
return(c);
case ZACK:
case ZRPOS:
break;
case ZRINIT:
return(OK);
}
#if defined(READCHECK)
/*
* If the reverse channel can be tested for data,
* this logic may be used to detect error packets
* sent by the receiver,in place of setjmp/longjmp
* rdchk(fdes) returns non 0 if a character is available
*/
while(rdchk(iofd))
{
switch(readline(1))
{
case CAN:
case ZPAD:
c = getinsync(1);
goto gotack;
case XOFF: /* Wait a while for an XON */
case XOFF|0200:
readline(100);
}
}
#endif
}
newcnt = Rxbuflen;
Txwcnt = 0;
stohdr(Txpos);
zsbhdr(4,ZDATA,Txhdr);
do
{
if(Dontread)
{
n = Lastn;
} else
{
n = zbuf_build(txbuf,blklen);
Lastread = Txpos;
Lastn = n;
}
Dontread = FALSE;
if(n < blklen)
e = ZCRCE;
else if(junkcount > 3)
e = ZCRCW;
else if(bytcnt == Lastsync)
e = ZCRCW;
else if(Rxbuflen && (newcnt -= n) <= 0)
e = ZCRCW;
else if(Txwindow && (Txwcnt += n) >= Txwspac)
{
Txwcnt = 0;
e = ZCRCQ;
}
else
e = ZCRCG;
zsdata(txbuf,n,e);
this_file_frame_count++; /* wht */
if(bad_condx_blklen) /* wht */
{
/* if we have sent four frames since last ZRPOS to same pos (wht)*/
if((this_file_frame_count - bad_condx_frame_count) > 4) /*wht*/
{
if(blklen == bad_condx_blklen)
bad_condx_blklen = 0;
else
{
blklen *= 2;
report_txblklen(blklen);
}
SameZrposAgain = 0;
}
}
bytcnt = Txpos += n;
report_send_stats(Txpos);
if(e == ZCRCW)
goto waitack;
#if defined(READCHECK)
/*
* If the reverse channel can be tested for data,
* this logic may be used to detect error packets
* sent by the receiver,in place of setjmp/longjmp
* rdchk(fdes) returns non 0 if a character is available
*/
while(rdchk(iofd))
{
switch(readline(1))
{
case CAN:
case ZPAD:
c = getinsync(1);
if(c == ZACK)
break;
#if defined(TCFLSH)
ioctl(iofd,TCFLSH,1);
#endif
/* zcrce - dinna wanna starta ping-pong game */
zsdata(txbuf,0,ZCRCE);
goto gotack;
case XOFF: /* Wait a while for an XON */
case XOFF|0200:
readline(100);
default:
++junkcount;
}
}
#endif /* READCHECK */
if(Txwindow)
{
while((tcount = Txpos - Lrxpos) >= Txwindow)
{
if(e != ZCRCQ)
zsdata(txbuf,0,e = ZCRCQ);
c = getinsync(1);
if(c != ZACK)
{
#if defined(TCFLSH)
ioctl(iofd,TCFLSH,1);
#endif
zsdata(txbuf,0,ZCRCE);
goto gotack;
}
}
}
} while(n == blklen);
for(;;)
{
stohdr(Txpos);
zsbhdr(4,ZEOF,Txhdr);
switch(err = getinsync(0))
{
case ZACK:
continue;
case ZRPOS:
goto somemore;
case ZRINIT:
return(OK);
case ZSKIP:
report_file_close();
fclose(in);
return(c);
default:
sprintf(s128,"SEND protocol sync error 0x%04x: %s",err,Pathname);
report_str(s128 + 5,1);
skip_count++;
report_error_count();
report_file_byte_io(this_file_length);
report_file_close();
fclose(in);
return(ERROR);
}
}
} /* end of zsendfdata */
/*+-------------------------------------------------------------------------
getinsync(flag) - get back in sync with receiver
--------------------------------------------------------------------------*/
getinsync(flag)
{
register c;
for(;;)
{
switch(c = zgethdr(Rxhdr,0))
{
case ZCAN:
case ZABORT:
case ZFIN:
case TIMEOUT:
sprintf(s128,"Receiver %s",frametypes[c+FTOFFSET]);
report_str(s128,1);
return(ERROR);
case ZRPOS:
report_str("Receiver ZRPOS",1);
/* ************************************* */
/* If sending to a modem buffer,you */
/* might send a break at this point to */
/* dump the modem's buffer. */
/* ************************************* */
if(Lastn >= 0 && Lastread == Rxpos)
{
Dontread = TRUE;
} else
{
clearerr(in); /* In case file EOF seen */
fseek(in,Rxpos,0);
}
bytcnt = Lrxpos = Txpos = Rxpos;
if(Lastsync == Rxpos) /* wht - original code */
{ /* wht - original code */
/* save frame count at time of each occurrence (wht) */
bad_condx_frame_count = this_file_frame_count; /* wht */
/* save block length at time of error (wht) */
if(++SameZrposAgain > 4) /* wht - original code */
{ /* wht */
if(bad_condx_blklen == 0) /* wht */
bad_condx_blklen = blklen; /* wht */
if(blklen > 256) /* wht - 32->256 */
{
blklen /= 2; /* wht - original code */
report_txblklen(blklen);
}
} /* wht */
} /* wht - original code */
Lastsync = Rxpos;
report_send_stats(Txpos);
return(c);
case ZACK:
Lrxpos = Rxpos;
if(flag || Txpos == Rxpos)
return(ZACK);
continue;
case ZRINIT:
case ZSKIP:
report_file_byte_io(this_file_length);
report_file_close();
fclose(in);
return(c);
case ERROR:
default:
report_str("Sending ZNAK",1);
zsbhdr(4,ZNAK,Txhdr);
continue;
}
}
} /* end of getinsync */
/*+-------------------------------------------------------------------------
saybibi() - Say "bibi" to the receiver, try to do it cleanly
--------------------------------------------------------------------------*/
saybibi()
{
for(;;)
{
stohdr(0L); /* CAF Was zsbhdr - minor change */
zshhdr(4,ZFIN,Txhdr); /* to make debugging easier */
switch(zgethdr(Rxhdr,0))
{
case ZFIN:
sendline('O');
sendline('O');
flushline();
case ZCAN:
case TIMEOUT:
return;
}
}
} /* end of saybibi */
/*+-------------------------------------------------------------------------
determine_transaction_time()
--------------------------------------------------------------------------*/
void
determine_transaction_time()
{
register c;
struct stat f;
char *name;
rewind_file_list();
TotalLeft = 0;
Filesleft = 0;
while(get_file_list_name(&name))
{
f.st_size = -1;
if((access(name,04) >= 0) && (stat(name,&f) >= 0))
{
c = f.st_mode & S_IFMT;
if(c != S_IFDIR && c != S_IFBLK)
{
++Filesleft;
TotalLeft += f.st_size;
}
}
}
FilesTotal = Filesleft;
rewind_file_list();
} /* end of determine_transaction_time */
/* vi: set tabstop=4 shiftwidth=4: */
/* end of tipsz.c */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.