ftp.nice.ch/pub/next/unix/communication/zm_tip_modified.NI.bs.tar.gz#/zm_tip/xfer/tipsz.c

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 <stdlib.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <time.h>
#include <sys/types.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


int write(int fd, char *buf, int nbytes);
int read(int fd, char *buf, int nbytes);
off_t lseek(int fd, off_t offset, int whence);
unsigned int alarm();
int open(const char *path, int flags, ...);
int getpid(void);
int utime();
int chmod();
int unlink(const char *path);
int sleep();
void setbuffer();
int access(const char *path, int mode);


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));
void 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));
void xsendline P_A((int ch));
void sendline P_A((int ch));
void 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));
void SIGALRM_handler ();
int readock P_A((int timeout, int count));
int readline P_A((int n));
void purgeline P_A((void));
void send_cancel P_A((void));
char *substr P_A((char *str, char *substr));
void 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));
void 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)
--------------------------------------------------------------------------*/
int 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(int 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) */
void onintr(void)
{
	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(void)
{
	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)
--------------------------------------------------------------------------*/
void xsendline(ch)
char ch;
{
#ifdef BUFFERED_WRITE
	fputc(ch,iofp);
#else
	write(iofd,&ch,1);
#endif
	++tx_char_count;
}	/* end of xsendline */

/*+-------------------------------------------------------------------------
	sendline(ch)
--------------------------------------------------------------------------*/
void sendline(ch)
char ch;
{
	xsendline(ch);
}	/* end of sendline */

void flushline(void)
{
#ifdef BUFFERED_WRITE
	fflush(iofp);
#endif
}

int main(argc,argv)
int argc;
char *argv[];
{
register char *cp;
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
--------------------------------------------------------------------------*/
int wcsend(void)
{
	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
--------------------------------------------------------------------------*/
int wcs(oname)
char *oname;
{
register c;
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!
 */
int 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);
}

int getnak(void)
{
	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)
--------------------------------------------------------------------------*/
int 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);
}

int 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&&sectnum) ? 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 */
int xbuf_build(buf,count)
register char *buf;
int count;
{
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 
--------------------------------------------------------------------------*/
int 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()
--------------------------------------------------------------------------*/
void 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
--------------------------------------------------------------------------*/
int 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)
--------------------------------------------------------------------------*/
int readline(n)
int n;
{
	return(readock(n,1));
}	/* end of readline */



/*+-------------------------------------------------------------------------
	purgeline()
--------------------------------------------------------------------------*/
void purgeline(void)
{
#if defined(M_SYS5)
	ioctl(iofd,TCFLSH,0);
#else
	lseek(iofd,0L,2);
#endif
}	/* end of purgeline */


/*+-------------------------------------------------------------------------
	send_cancel() - send cancel to remote
--------------------------------------------------------------------------*/
void send_cancel(void)
{
	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()
--------------------------------------------------------------------------*/
void usage(void)
{
	exit(255);
}	/* end of usage */

/*+-------------------------------------------------------------------------
	getzrxinit() - Get the receiver's init parameters
--------------------------------------------------------------------------*/
int getzrxinit(void)
{
	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
--------------------------------------------------------------------------*/
int sendzsinit(void)
{
	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
--------------------------------------------------------------------------*/
int 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
--------------------------------------------------------------------------*/
int zsendfdata(void)
{
int 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
--------------------------------------------------------------------------*/
int getinsync(int 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
--------------------------------------------------------------------------*/
void saybibi(void)
{
	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(void)
{
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.