[comp.sources.atari.st] v01i065: uupc -- UUCP clone

koreth@ssyx.ucsc.edu (Steven Grimm) (07/30/88)

Submitted-by: koreth@ssyx.ucsc.edu (Steven Grimm)
Posting-number: Volume 1, Issue 65
Archive-name: uupc/part01

This is the version of UUPC that I've been working on.  It allows you
to use your ST as a UUCP node.  Please look at the file "readme.1st"
before proceeding; it contains configuration instructions and some
caveats about the code.  It's about halfway through part03 if you
don't want to unshar before reading it.

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
# This is part 1 of a multipart archive                                    
# do not concatenate these parts, unpack them in order with /bin/sh        
#
#	Run the following text with /bin/sh to create:
#	  chekname.c
#	  dcp.c
#	  dcp.h
#	  dcpgpkt.c
#	  dcpsys.c
#	  dcpxfer.c
#	  dirsubs.c
#	  dmymath.c
#	  fgets.c
#	  genv.c
#	  genv.h
#	  getargs.c
#	  getenv.c
#	  getone.c
#	  host.c
#	  host.h
#	  inoutpth.c
#	  lib.c
#	  lmail.c
#	  mail.c
#	  mailhost.c
#	  makefile
#	  mlib.c
#	  ndir.c
#	  ndir.h
#	  pcmail.c
#	  printmsg.c
#	  readme.1st
#	  readme.dcp
#	  readme.inf
#	  readme.por
#	  readme.st
#	  readme.uup
#	  rmail.c
#	  shell.c
#	  systems
#	  time.c
#	  time.h
#	  ulib.c
#	  uuhost.c
#	  uusup.c
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
sed 's/^X//' << 'SHAR_EOF' > chekname.c &&
X#include "dcp.h"
X#include <ctype.h>
X
Xextern char s_systems[];
XFILE *FOPEN();
X
X/*
X**
X**checkname
X** Do we know the guy ?
X*/
Xcheckname(name)
Xchar	name[];
X{
X	FILE *ff;
X	char line[BUFSIZ], tmp[20]; /* can change to 8 if %8s works */
X
X	if ( ( ff = FOPEN( s_systems, "r", 't' )) == (char *)NULL )
X		return( FAILED );
X
X	while ( fgets( line, BUFSIZ, ff ) ){
X		sscanf( line, "%8s ", tmp );
X		if ( strncmp( tmp, name, 7 ) == 0 ) {
X			fclose( ff );
X			return ( OK ); /*OK I like you */
X		}
X	}
X	fclose( ff );
X	return( FAILED ); /* Who are you ? */
X
X}
X
X/*
X * Non case-sensitive string compare
X */
Xstrncom(s1, s2, n)
Xregister char *s1, *s2;
X{
X	register int t1, t2;
X
X	while ((*s1 || *s2) && n--)
X		if ((t1 = toupper(*s1++)) < (t2 = toupper(*s2++)))
X			return -1;
X		else if (t1 > t2)
X			return 1;
X
X	return 0;
X}
SHAR_EOF
chmod 0600 chekname.c || echo "restore of chekname.c fails"
sed 's/^X//' << 'SHAR_EOF' > dcp.c &&
X/*			dcp.c
X
X			Revised edition of dcp
X
X			Stuart Lynne May/87
X
X			Copyright (c) Richard H. Lamb 1985, 1986, 1987
X			Changes Copyright (c) Stuart Lynne 1987
X
X*/
X/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
X/* This program implements a uucico type file transfer and remote
Xexecution type protocol.
X*/
X#include "dcp.h"
X/**/
Xint	pktsize;                	/* packet size for pro */
XFILE	*logfile;            	/* system log file */
XFILE	*syslog;            	/* system log file */
XFILE	*fw;                 	/* cfile pointer */
Xchar	state;					/* system state*/
Xchar	cfile[80];              /* work file pointer */
Xint		remote;                 /* -1 means we're remote ..7*/
Xint		msgtime;                /* timout setting */
Xchar	fromfile[132];
Xchar	hostfile[132];		/* host version of fromfile */
Xchar	tofile[132];
Xint		fp;                     /* current disk file ptr */
Xint		size;                   /* nbytes in buff */
XFILE	*fsys;
Xchar	Rmtname[20];
Xchar	rmtname[20];
Xchar	* cctime;
Xchar	proto[5];
X/* char	loginseq[256]; */
Xchar 	sysline[BUFSIZ];
Xchar	s_systems[64];
Xchar	s_logfile[64];
Xchar	s_syslog[64];
Xchar 	*flds[60];
Xint 	kflds;
Xint		debuglevel;		/* debugging flag */
X
Xunsigned int	checksum();
X
X
X/**/
X/* new usage
X
X	dcp	[-xn] -r0		slave mode
X	dcp	[-xn] -shost 		call host
X	dcp	[-xn] -sall		call all hosts
X
X	dcp	[-xn] 		call any hosts as required by C. files
X
X*/
X
Xcomplain( s )
Xchar *s;
X{
X	fprintf( stderr, "Please set your %s environment variable.", s );
X}
X
Xstatic void cant( file )
Xchar *file;
X{
X	fprintf( stderr, "Can't open: \"%s\"\n", file );
X	exit( NULL );
X}
X
Xdcpmain( argc, argv )
Xint	argc;
Xchar*argv[];
X{
X	FILE	*ftmp;
X	char	line[132];
X
X	if ( name == NULL || *name == '\0' ) {
X		complain( NAME );
X		exit( -1 );
X	}
X	if ( nodename == NULL || *nodename == '\0' ) {
X		complain( NODENAME );
X		exit( -1 );
X	}
X
X	mkfilename( s_logfile, spooldir, LOGFILE );
X	mkfilename( s_syslog,  spooldir, SYSLOG  );
X	mkfilename( s_systems, confdir,  SYSTEMS );
X
X	if ( (logfile = FOPEN( s_logfile, "a", 't' )) == NULL )
X	   cant( s_logfile );
X	if ( (syslog  = FOPEN( s_syslog,  "a", 't' )) == NULL )
X	   cant( s_syslog );
X
X	remote = MASTER;
X	debuglevel = 1;
X	fp = -1;
X	fw = (char *)NULL;
X
X
X	remote = MASTER;
X	strcpy( Rmtname, "any" );
X
X	while ( --argc ) {
X		if ( **++argv == '-') {
X			switch(argv[0][1]) {
X			case 'x':
X				debuglevel = atoi( &argv[0][2] );
X				break;
X			case 's':
X				sprintf( Rmtname, "%.7s", &argv[0][2] );
X				break;
X			case 'r':
X				remote = atoi( &argv[0][2] );
X				break;
X
X			default:
X				break;
X			}
X		}
X	}
X
X
X	if ( remote == MASTER ) {
X 		printmsg( 0, "Calling %s, debuglevel=%d", Rmtname, debuglevel );
X		if (( fsys = FOPEN( s_systems, "r", 't' )) == (char *)NULL )
X			exit( FAILED );
X		state = 'I';
X
X		while (TRUE) {
X			printmsg( 4, "Mstate = %c", state );
X			switch (state) {
X			case 'I':
X				state = getsystem();
X				break;
X			case 'S':
X				state = callup();
X				break;
X			case 'P':
X				state = startup();
X				break;
X			case 'D':
X				state = master();
X				break;
X			case 'Y':
X				state = sysend();
X				break;
X			case 'G':
X				state = 'I';
X				break;
X			}
X			if (state == 'A')
X				break;
X		}
X		fclose( fsys );
X	} else
X	 {
X		if (openline( device, speed ) == -1)
X			return(FALSE);
X		state = 'L';
X		while (TRUE) {
X			printmsg( 4, "Sstate = %c", state );
X			switch (state) {
X			case 'L':
X				state = login();
X				break;
X			case 'I':
X				state = startup();
X				break;
X			case 'R':
X				state = slave();
X				break;
X			case 'Y':
X				state = sysend();
X				break;
X			}
X			if (state == 'A')
X				break;
X		}
X		closeline();
X	}
X
X	printmsg( 2, "calling dcxqt" );
X	if (dcxqt())
X		printmsg( 0, "ERROR in DCXQT" );
X
X	/* scan and process any recieved files */
X
X	fclose( syslog );
X	fclose( logfile );
X	return 0;
X}
X
X
X/**/
X/*
X**
X**
X**master
X**
X**
X*/
Xmaster()
X{
X	state = 'I';
X	while (TRUE) {
X		printmsg( 4, "Top level state (master mode) %c", state );
X		switch (state) {
X		case 'I':
X			state = sinit();
X			break;
X		case 'B':
X			state = scandir();
X			break;
X		case 'S':
X			state = send();
X			break;
X		case 'Q':
X			state = sbreak();
X			break;
X		case 'G':
X			state = receive();
X			break;
X		case 'C':
X			state = 'Y';
X			break;
X		case 'Y':
X			state = endp();
X			break;
X		case 'P':
X			return('Y');
X		case 'A':
X			return('A');
X		default:
X			return('A');
X		}
X	}
X}
X
X
X/**/
X/*
X**
X**
X**slave
X**
X**
X*/
Xslave()
X{
X	state = 'I';
X	while (TRUE) {
X		printmsg( 4, "Top level state (slave mode) %c", state );
X		switch (state) {
X		case 'I':
X			state = rinit();
X			break;
X		case 'F':
X			state = receive();
X			break;
X		case 'C':
X			state = schkdir();
X			break;
X		case 'T':
X			state = 'B';
X			break;
X		case 'B':
X			state = scandir();
X			break;
X		case 'S':
X			state = send();
X			break;
X		case 'Q':
X			state = sbreak();
X			break;
X		case 'G':
X			return('Y');
X		case 'Y':
X			state = endp();
X			break;
X		case 'P':
X			return('Y');
X		case 'A':
X			return('A');
X		default:
X			return('A');
X		}
X	}
X}
X
X
X/**/
X/*
X *  r e c e i v e
X *
X *  This is the state table switcher for receiving files.
X */
X
Xreceive()
X{
X
X	state = 'F';/* Receive-Init is the start state */
X
X	while (TRUE) {
X		printmsg( 4, " receive state: %c", state );
X		switch (state)/* Do until done */ {
X		case 'F':
X			state = rfile();
X			break; /* Receive-File */
X		case 'D':
X			state = rdata();
X			break; /* Receive-Data */
X		case 'C':
X			return('C');/* Complete state */
X		case 'A':
X			return('Y');/* "Abort" state */
X		default:
X			return('Y');
X		}
X	}
X}
X
X
X/**/
X/*
X *  s e n d
X *
X *  Sendsw is the state table switcher for sending files.  It loops until
X *  either it finishes, or an error is encountered.  The routines called
X *  by sendsw are responsible for changing the state.
X *
X */
Xsend()
X{
X	fp = -1;                /* reset file getter/opener */
X	state = 'F';/* Send initiate is the start state */
X	while (TRUE)/* Do this as long as necessary */ {
X		printmsg( 4, "send state: %c", state );
X		switch (state) {
X		case 'F':
X			state = sfile();
X			break; /* Send-File */
X		case 'D':
X			state = sdata();
X			break; /* Send-Data */
X		case 'Z':
X			state = seof();
X			break; /* Send-End-of-File */
X		case 'B':
X			return ('B'); /* Complete */
X		case 'A':
X			return ('Y'); /* "Abort" */
X		default:
X			return ('Y'); /* Unknown, fail */
X		}
X	}
X}
X
X
X/**/
X/* A command formatter for DCP. RH Lamb */
X/* sets up stdin and stdout on various machines */
X/* There is NO command checking so watch what you send and who you */
X/* let accsess your machine. "C rm /usr/*.*" could be executed. */
Xdcxqt()
X{
X	int	i;
X	char	command[60], input[60], output[60], line[BUFSIZ];
X	char	*cp;
X
X	rmtname[0] = '\0';
X
X	while (dscandir()) {
X		strcpy( line, cfile );
X		fw = FOPEN( line, "r", 'b' );/* imported X file */
X		strcpy(cfile, line);
X		printmsg( 2, "dcxqt:%s %ld", cfile, fw );
X		input[0]   = '\0';
X		output[0]  = '\0';
X		command[0] = '\0';
X		while ( fgets( line, BUFSIZ, fw ) ) {
X
X			cp = index( line, '\n' );
X			if ( cp != (char *)NULL )
X				*cp = '\0';
X
X			printmsg( 8, "dcxqt: %s", line );
X			switch (line[0]) {
X			case 'U':
X				break;
X			case 'I':
X				strcpy( input,   &line[2] );
X				break;
X			case 'O':
X				strcpy( output,  &line[2] );
X				break;
X			case 'C':
X				strcpy( command, &line[2] );
X				break;
X			case 'R':
X				break;
X			default :
X				break;
X			}
X		}
X		fclose( fw );
X
X		printmsg( 0, "xqt: %s\n", command );
X
X		shell( command, input, output, (char *)NULL );
X
X
X		unlink(cfile);
X 		importpath( hostfile, input );
X 		unlink(hostfile);
X		importpath( hostfile, output );
X 		unlink(hostfile);
X	}
X	return(0);
X}
X
X/**/
X/*
X *  p r i n t m s g
X *
X *  Print error message on standard output if not remote.
X */
X/*VARARGS1*/
Xprintmsg(level, fmt, a1, a2, a3, a4, a5)
Xint 	level;
Xchar	*fmt;
Xchar	*a1, *a2, *a3, *a4, *a5;
X{
X	char	msg[256];
X
X	if ( debuglevel > level ) {
X		sprintf( msg, fmt, a1, a2, a3, a4, a5 );
X		strcat( msg, "\n" );
X		if ( remote == MASTER )
X			fputs( msg, stdout );
X		fputs( msg, logfile );
X	}
X}
X
X
X
X
SHAR_EOF
chmod 0600 dcp.c || echo "restore of dcp.c fails"
sed 's/^X//' << 'SHAR_EOF' > dcp.h &&
X/* DCP a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
X#include <stdio.h>		/* Standard UNIX  definitions */
X#include "host.h"		/* Host specific definitions */
X
XFILE * FOPEN();
Xint CREAT();
X
X#define SYSTEMS		"systems"
X#define LOGFILE		"LOGFILE"
X#define SYSLOG		"SYSLOG"
X
X#define MSGTIME         20
X#define MAXPACK         256
X
X#define ACK     4       /*      general definitions     */
X#define NAK     2
X#define DATA    0
X#define CLOSE   1
X#define ERROR   10
X#define EMPTY   11
X
X
X
X#define	SLAVE	0
X#define	MASTER	1
X
X#ifndef TRUE
X#define TRUE   (-1)
X#define FALSE   0
X#endif
X
X#ifndef SAME
X#define SAME	0
X#endif
X#define FAILED	-1
X#define OK		0
X
X
X/* L.sys field defines */
X
X#define	FLD_REMOTE	0
X#define	FLD_CCTIME	1
X#define	FLD_DEVICE	2
X#define	FLD_TYPE	3
X#define	FLD_SPEED	4
X#define	FLD_PROTO	5
X#define	FLD_EXPECT	6
X#define FLD_SEND	7
X
X/**/
Xtypedef int	(*procref)();
X
Xtypedef struct {
X	char	type;
X	procref a;
X	procref b;
X	procref c;
X	procref d;
X} Proto;
X
X/* the various protocols available. Add here for others */
Xextern procref          getpkt, sendpkt, openpk, closepk;
X
Xextern int	ggetpkt(), gsendpkt(), gopenpk(), gclosepk();
X/*
Xextern int	kgetpkt(), ksendpkt(), kopenpk(), kclosepk();
Xextern int	rgetpkt(), rsendpkt(), ropenpk(), rclosepk();
Xextern int	tgetpkt(), tsendpkt(), topenpk(), tclosepk();
X*/
X
X/**/
Xextern int	pktsize;                /* packet size for this pro*/
Xextern FILE	*logfile;            	/* system log file */
Xextern FILE	*syslog;            	/* system log file */
Xextern FILE	*fw;           		/* cfile pointer */
Xextern char	cfile[80];              /* work file pointer */
Xextern int	remote;                 /* -1 means we're remote*/
Xextern int	findwork;
Xextern int	msgtime;                /* timout setting */
Xextern char	fromfile[132];
Xextern char	hostfile[132];		/* host version of fromfile */
Xextern char	tofile[132];
Xextern char	state;                  /* present state */
Xextern int	fp;                     /* current disk file ptr */
Xextern int	size;                   /* nbytes in buff */
Xextern FILE	*fsys;
Xextern char	Rmtname[20];
Xextern char	rmtname[20];
Xextern char	*cctime;
Xextern char	proto[5];
X
Xextern char sysline[BUFSIZ];
Xextern char s_systems[64];
Xextern char s_logfile[64];
Xextern char s_syslog[64];
Xextern char *flds[60];
Xextern int  kflds;
X
Xextern int	debuglevel;		/* debugging flag */
Xextern unsigned int	checksum();
Xextern char *index();
Xextern char *rindex();
X
Xextern	char *curdir;
X
X
X
SHAR_EOF
chmod 0600 dcp.h || echo "restore of dcp.h fails"
sed 's/^X//' << 'SHAR_EOF' > dcpgpkt.c &&
X/*			dcpgpkt.c
X
X			Revised edition of dcp
X
X			Stuart Lynne May/87
X
X			Copyright (c) Richard H. Lamb 1985, 1986, 1987
X			Changes Copyright (c) Stuart Lynne 1987
X
X*/
X/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
X/* 3-window "g" ptotocol */
X/* Thanks got to John Gilmore for sending me a copy of Greg Chesson's
XUUCP protocol description-- Obviously invaluable
XThanks also go to Andrew Tannenbaum for the section on Siding window
Xprotocols with a program example in his "Computer Networks" book
X*/
X#include "dcp.h"
X#define PKTSIZE         64
X#define PKTSIZ2         2
X#define HDRSIZE         6
X#define MAXTRY          4
X
X#define MAXERR  200		/* Dont want to quit in a middle of a long file*/
X#define TIMEOUT 4		/* could be longer */
X#define KPKT    1024/PKTSIZE
X#define POK      -1
X
X#define SWINDOW 3	/* fixed now, U make it variable */
X#define RWINDOW 3
X#define NBUF    8   /* always SAME as MAXSEQ ? */
X#define MAXSEQ  8
X
X#define between(a,b,c) ((a<=b && b<c) || (c<a && a<=b) || (b<c && c<a))
X
X/* packet defin */
Xstatic int	rwl, swl, swu, rwu, nerr, nbuffers, npkt, irec, timeout, GOT_SYNC, GOT_HDR;
Xstatic int	fseq[NBUF], outlen[NBUF], inlen[NBUF], arr[NBUF];
Xstatic char	outbuf[NBUF][PKTSIZE+1], inbuf[NBUF][PKTSIZE+1];
Xstatic unsigned char	grpkt[HDRSIZE+1];
Xstatic long	ftimer[NBUF], acktmr, naktmr;
X/**/
X/******************SUB SUB SUB PACKET HANDLER************/
Xgopenpk()
X{
X	int	i, j, n1, n2, len;
X	char	tmp[PKTSIZE+1];
X	pktsize = PKTSIZE; /* change it later after the init */
X	msgtime = MSGTIME; /* not sure I need this for "g" proto */
X	/* initialize proto parameters */
X	swl = nerr = nbuffers = npkt = 0;
X	swl = swu = 1;
X	rwl = 0;
X	rwu = RWINDOW - 1;
X	for (i = 0; i < NBUF; i++) {
X		ftimer[i] = 0;
X		arr[i] = FALSE;
X	}
X	GOT_SYNC = GOT_HDR = FALSE;
X	/* 3-way handshake */
X	timeout = 1; /* want some timeout capability here */
X	gspack(7, 0, 0, 0, tmp);
Xrsrt:
X	if (nerr >= MAXERR)
X		return(-1);
X	/* INIT sequence. Easy fix for variable pktsize and windows. */
X	/* I didnt since all the machines I talk to use W=3 PKTSZ=64 */
X	/* If you do this make sure to reflect the changes in "grpack" */
X	/* and "gspack" */
X	switch (grpack(&n1, &n2, &len, tmp)) {
X	case 7:
X		gspack(6, 0, 0, 0, tmp);
X		goto rsrt;
X	case 6:
X		gspack(5, 0, 0, 0, tmp);
X		goto rsrt;
X	case 5:
X		break;
X	default:
X		nerr++;
X		gspack(7, 0, 0, 0, tmp);
X		goto rsrt;
X	}
X	nerr = 0;
X	return(0);      /* channel open */
X}
X
X
Xgclosepk()
X{
X	int	i;
X	char	tmp[PKTSIZE+1];
X	timeout = 1;
X	for (i = 0; i < MAXTRY; i++) {
X		gspack(CLOSE, 0, 0, 0, tmp);
X		if (gmachine() == CLOSE)
X			break;
X	}
X	printmsg( 0, "number of errors %d and pkts xfered %d", nerr, npkt );
X	return(0);
X}
X
X
X/*
X *
X * ggetpkt
X ***** description: Gets no more than a packet's worth of data from
X****               the "packet i/o state machine". May have to
X****               periodically run the pkt machine to get some
X****               packets.
X* on input: dont care   getpkt(data,&len)  char *data int len
X* on return: data+\0 and length in len. ret(0) if alls well
X* ret(-1) if problems.(fail)
X */
Xggetpkt(cdata, len)
Xint	*len;
Xchar	cdata[];
X{
X	int	i2;
X	irec = 1;
X	timeout = 0;
X	/* WAIT FOR THE DESIRED PACKET */
X	while ((arr[rwl]) == FALSE)
X		if (gmachine() != POK)
X			return(-1);
X	/* GOT A PKT ! */
X	i2 = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
X	*len = inlen[i2];
X	strncpy(cdata, inbuf[i2], *len);
X	arr[i2] = FALSE;
X	rwu = (1 + rwu) % MAXSEQ; /* bump rec window */
X	npkt++;
X	return(0);
X}
X
X
X/*
X *
X *  sendpkt
X *
X*****   description:    Put at most a packet's worth of data  in the pkt state
X ****                   machine for xmission.
X*****                   May have to run the pkt machine a few times to get
X*****                   an available output slot.
X *
X * on input: char *data int len,flg; len=length of data in data.
X *           flg=2 just send the packet with no wait for ack.
X *           flg>0 zero out the unused part of the buffer. (for UUCP "msg"
X *                                                                   pkts)
X *           flg=0 normal data
X * return:   ret(0) if alls well ret(-1) if problems (fail)
X *
X*/
Xgsendpkt(cdata, len, flg)
Xint	len, flg;
Xchar	*cdata;
X{
X	int	i, i1;
X	long	ttmp;
X	irec = 0;
X	timeout = 0; /* non-blocking reads */
X	/* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been */
X	/* acked, wait for acks */
X	while (nbuffers >= SWINDOW)
X		if (gmachine() != POK)
X			return(-1);
X	i1 = swu;  /* <--If we ever have more than 8 seq no.s, must mod() here*/
X	/* PLACE PACKET IN TABLE AND MARK UNACKED */
X	/* fill with zeros or not */
X	if (flg) {
X		strcpy(outbuf[i1], cdata);
X		len = PKTSIZE;
X		for (i = strlen(cdata); i < len; i++)
X			outbuf[i1][i] = '\0';
X	} else {
X		strncpy(outbuf[i1], cdata, len);
X		outbuf[i1][len] = '\0';
X	}
X	/* mark packet  */
X	outlen[i1] = len;
X	ftimer[i1] = time(&ttmp);
X	fseq[i1] = swu;
X	swu = (1 + swu) % MAXSEQ;	/* bump send window */
X	nbuffers++;
X	npkt++;
X	/* send it */
X	gspack(DATA, rwl, fseq[i1], outlen[i1], outbuf[i1]);
X	/* send it once then let the pkt machine take it. wouldnt need this for */
X	/* mtasking systems */
X	/* sl gmachine(); */
X	return(0);
X}
X
X
X/************     packet machine   ****** RH Lamb 3/87 */
X/* Idealy we would like to fork this process off in an infinite loop */
X/* and send and rec pkts thru "inbuf" and "outbuf". Cant do this in MS-DOS*/
X/* so we setup "getpkt" and "sendpkt" to call this routine often and return */
X/* only when the input buffer is empty thus "blocking" the pkt-machine task. */
Xgmachine()
X{
X	int	rack, rseq, rlen, i1, i2, dflg;
X	char	rdata[PKTSIZE+1];
X	long	ttmp, itmp;
Xreply:
X	printmsg( 6, "*send %d<W<%d, rec %d<W<%d, err %d", swl, swu, rwl, rwu, nerr );
X	/* waiting for ACKs for swl to swu-1. Next pkt to send=swu */
X	/* rwl=expected pkt */
X	printmsg( 7, "Kbytes transfered %d errors %d\r", npkt / KPKT, nerr );
X	if (nerr >= MAXERR)
X		goto close;
X	dflg = 0;
X	switch (grpack(&rack, &rseq, &rlen, rdata)) {
X	case CLOSE:
X		printmsg( 5, "**got CLOSE");
X		goto close;
X	case NAK:
X		nerr++;
X		acktmr = naktmr = 0; /* stop ack/nak timer */
X		printmsg( 5, "**got NAK %d", rack );
Xnloop:
X		if (between(swl, rack, swu)) { /* resend rack->(swu-1) */
X			i1 = rack;
X			gspack(DATA, rwl, rack, outlen[i1], outbuf[i1]);
X			printmsg( 5, "***resent %d", rack );
X			ftimer[i1] = time(&ttmp);
X			rack = (1 + rack) % MAXSEQ;
X			goto nloop;
X		}
X		if (dflg)
X			return(POK);
X		goto reply; /* any other stuff ? */
X
X	case EMPTY:
X		printmsg( 5, "**got EMPTY" );
X		itmp = time(&ttmp);
X		if (acktmr)
X			if ((itmp - acktmr) >= TIMEOUT) { /* ack timed out*/
X				gspack(ACK, rwl, 0, 0, rdata);
X				acktmr = itmp;
X			}
X		if (naktmr)
X			if ((itmp - naktmr) >= TIMEOUT) { /*nak timed out*/
X				gspack(NAK, rwl, 0, 0, rdata);
X				naktmr = itmp;
X			}
X		/* resend any timed out un-acked pkts */
X		for (i2 = swl; between(swl, i2, swu); i2 = (1 + i2) % MAXSEQ)  {
X			acktmr = naktmr = 0; /* reset ack/nak */
X			i1 = i2;
X			printmsg( 5, "--->seq,elapst %d %ld", i2, (itmp - ftimer[i1]) );
X			if ((itmp - ftimer[i1]) >= TIMEOUT) {
X				printmsg( 5, "***timeout %d", i2 );
X				/* since "g" is "go-back-N", when we time out we */
X				/* must send the last N pkts in order. The generalized*/
X				/* sliding window scheme relaxes this reqirment */
X				nerr++;
X				dflg = 1;  /* same hack */
X				rack = i2;
X				goto nloop;
X			}
X		}
X		return(POK);
X	case ACK:
X		printmsg( 5, "**got ACK %d", rack );
X		acktmr = naktmr = 0; /* disable ack/nak's */
Xaloop:
X		if (between(swl, rack, swu)) {   /* S<-- -->(S+W-1)%8 */
X			printmsg( 5, "***ACK %d", swl );
X			ftimer[swl] = 0;
X			nbuffers--;
X			swl = (1 + swl) % MAXSEQ;
X			dflg = 1;  /* same hack */			/* sl */
X			goto aloop;
X		}
X		if (dflg)
X			return(POK); /* hack for non-mtask sys's */
X		/* to empty "inbuf[]" */
X		goto reply;
X	case DATA:
X		printmsg( 5, "**got DATA %d %d", rack, rseq );
X		i1 = (1 + rwl) % MAXSEQ; /* (R+1)%8 <-- -->(R+W)%8 */
X		i2 = (1 + rwu) % MAXSEQ;
X		if (between(i1, rseq, i2)) {
X			if (i1 == rseq) {
X				i1 = rseq;
X				arr[i1] = TRUE;
X				inlen[i1] = rlen;
X				strncpy(inbuf[i1], rdata, rlen);
X				rwl = (rwl + 1) % MAXSEQ;
X				printmsg( 5, "***ACK d %d", rwl );
X				gspack(ACK, rwl, 0, 0, rdata);
X				acktmr = time(&ttmp); /* enable ack/nak tmout*/
X				dflg = 1; /*return to call when finished*/
X				/* in a mtask system, unneccesary */
X			} else {
X				nerr++;
X				printmsg( 5, "***unexpect %d ne %d", rseq, rwl );
X			}
X		} else {
X			nerr++;
X			printmsg( 5, "***wrong seq %d", rseq );
X		}
X		goto aloop;
X	case ERROR:
X		nerr++;
X		printmsg( 5, "**got BAD CHK" );
X		gspack(NAK, rwl, 0, 0, rdata);
X		naktmr = time(&ttmp); /* set nak timer */
X		printmsg( 5, "***NAK d %d", rwl );
X		goto reply;
X	default:
X		printmsg( 5, "**got SCREW UP" );
X		goto reply; /* ignore it */
X	}
Xclose:
X	gspack(CLOSE, 0, 0, 0, rdata);
X	return(CLOSE);
X}
X
X
X/**/
X/*************** FRAMMING *****************************/
X/*
X *
X *
X *      send a packet
X * nt2=type nt3=pkrec nt4=pksent len=length<=PKTSIZE cnt1= data * ret(0) always
X */
Xgspack(nt2, nt3, nt4, len, cnt1)
Xint	nt2, nt3, nt4, len;
Xchar	cnt1[];
X{
X	unsigned int	check, i;
X	unsigned char	c2, pkt[HDRSIZE+1], dpkerr[10];
X	if (len > 64)
X		len = 64;
X	if (len == 0)
X		cnt1[0] = '\0';
X/**Link testing mods- create artificial errors ***/ /*
Xprintf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
Xgets(dpkerr);
X	if(dpkerr[0] == 's') { sscanf(&dpkerr[1],"%d",&nt4); } /**/
X	/** End Link testing mods ***/
X	printmsg( 5, "send packet type %d, num=%d, n=%d, len=%d", nt2, nt3, nt4, len );
X	printmsg( 5, "data =\n|%s|", cnt1 );
X	c2 = '\0';
X	pkt[0] = '\020';
X	pkt[4] = nt2 << 3;
X	nt2 &= 7;
X	switch (nt2) {
X	case 1:
X		break;                  /* stop protocol */
X	case 2:
X		pkt[4] += nt3;
X		break;   /* reject        */
X	case 3:
X		break;
X	case 4:
X		pkt[4] += nt3;
X		break;   /* ack          */
X	case 5:
X		pkt[4] += SWINDOW;
X		break;   /* 3 windows */
X	case 6:
X		pkt[4] += 1;
X		break;   /* pktsiz = 64 (1) */
X	case 7:
X		pkt[4] += SWINDOW;
X		break;   /* 3 windows */
X	case 0:
X		pkt[4] += 0x80 + nt3 + (nt4 << 3);
X		c2 = (PKTSIZE - len) & 0xff;
X		/* havnt set it up for VERY LONG pkts with a few */
X		/* bytes yet (-128) */
X		if (c2) { /* short packet handling */
X			pkt[4] += 0x40;   /* if len < PKTSIZE */
X			for (i = PKTSIZE - 1; i > 0; i--)
X				cnt1[i] = cnt1[i-1];
X			cnt1[0] = c2;
X		}
X		break;
X	}
X	pkt[4] &= 0xff;
X	if (nt2) {
X		pkt[1] = 9;             /* control packet size = 0 (9) */
X		check = (0xaaaa - pkt[4]) & 0xffff;
X	} else {
X		pkt[1] = PKTSIZ2;             /* data packet size = 64 (2) */
X		check = checksum(cnt1, PKTSIZE);
X		i = pkt[4];/* got to do this on PC for ex-or high bits */
X		i &= 0xff;
X		check = (check ^ i) & 0xffff;
X		check = (0xaaaa - check) & 0xffff;
X	}
X	pkt[2] = check & 0xff;
X	pkt[3] = (check >> 8) & 0xff;
X	pkt[5] = (pkt[1] ^ pkt[2] ^ pkt[3] ^ pkt[4]) & 0xff;
X/***More Link testing MODS ******/ /*
Xswitch(dpkerr[0]) {
Xcase 'e':   cnt1[10] = -cnt1[10];
X			break;
Xcase 'h':	pkt[5] = -pkt[5];
X			break;
Xcase 'l':	return;
Xcase 'p':	swrite(pkt,HDRSIZE);
X			if(pkt[1] != 9) swrite(cnt1,PKTSIZE-3);
X			return;
Xdefault:	break;
X	}  /**/
X	/******End Link Testing Mods **********/
X	swrite(pkt, HDRSIZE);       /* header is 6-bytes long */
X	/*      write(flog,pkt,HDRSIZE);   */
X	if (pkt[1] != 9) {
X		swrite(cnt1, PKTSIZE);     /* data is always 64
X		bytes long */
X		/*    write(flog,cnt1,PKTSIZE);   */
X	}
X}
X
X
X/**/
X/*
X *
X *      read packet
X * on return: nt3=pkrec nt4=pksent len=length <=PKTSIZE  cnt1=data *
X * ret(type) ok; ret(EMPTY) input buf empty; ret(ERROR) bad header;
X *          ret(EMPTY) lost pkt timeout; ret(ERROR) checksum error;ret(-5) ?
X****NOTE :
X***sread(buf,n,timeout)
X	while(TRUE) {
X		if(# of chars available >= n) (without dec internal counter)
X			read n chars into buf (decrenent internal char counter)
X			break
X		else
X			if(time>timeout) break
X	}
X	return(# of chars available)
X****END NOTE
X */
Xgrpack(nt3, nt4, len, cnt1)
Xint	*nt3, *nt4, *len;
Xchar	cnt1[];
X{
X	unsigned int	nt1, check, checkchk, i;
X	unsigned char	c, c2;
X	int	ii;
X	if (GOT_SYNC)
X		goto get_hdr;
X	if (GOT_HDR)
X		goto get_data;
X	c = '\0';
X	while ((c & 0x7f) != '\020')
X		if (sread(&c, 1, timeout) == 0)
X			return(EMPTY);
X	GOT_SYNC = TRUE;
Xget_hdr:
X	if (sread(&grpkt[1], HDRSIZE - 1, timeout) < (HDRSIZE - 1))
X		return(EMPTY);
X	GOT_SYNC = FALSE;
X	/*i = grpkt[1] ^ grpkt[2] ^ grpkt[3] ^ grpkt[4] ^ grpkt[5];*/
X 	i = (unsigned)grpkt[1] ^ (unsigned)grpkt[2] ^
X 	    (unsigned)grpkt[3] ^ (unsigned)grpkt[4] ^
X 	    (unsigned)grpkt[5];
X
X	i &= 0xff;
X	printmsg( 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
X				grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5],
X				i
X			);
X
X	if (i) {               /*  bad header */
X		printmsg( 0, "****bad header****" );
X		return(ERROR); /* Im not sure whether "g" considers it an empty or error */
X	}
X	GOT_HDR = TRUE;
X	if ((grpkt[1] &= 0x7f) == 9) {       /* control packet */
X		*len = 0;
X		c = grpkt[4] & 0xff;
X		nt1  = c >> 3;
X		*nt3 = c & 7;
X		*nt4 = 0;
X		check = 0;
X		checkchk = 0;
X		cnt1[*len] = '\0';
X		GOT_HDR = FALSE;
X	} else {       /* data packet */
X		if (grpkt[1] != PKTSIZ2)
X			return(-5);   /* cant handle other than 64*/
Xget_data:
X		if (sread(cnt1, PKTSIZE, timeout) < PKTSIZE)
X			return(EMPTY);
X		GOT_HDR = FALSE;
X		nt1  = 0;
X		c2 = grpkt[4] & 0xff;
X		c = c2 & 0x3f;
X		*nt4 = c >> 3;
X		*nt3 = c & 7;
X		i = grpkt[3];
X		i = (i << 8) & 0xff00;
X		check = grpkt[2];
X		check = i | (check & 0xff);
X		checkchk = checksum(cnt1, PKTSIZE);
X		i = grpkt[4] | 0x80;
X		i &= 0xff;
X		checkchk = 0xaaaa - (checkchk ^ i);
X		checkchk &= 0xffff;
X		if (checkchk != check) {
X			printmsg( 4, "***checksum error***" );
X			return(ERROR);
X		}
X		*len = PKTSIZE;
X		/* havnt set it up for very long pkts yet (>128) RH Lamb */
X		if (c2 & 0x40) {
X			ii = (cnt1[0] & 0xff);
X			*len = (*len - ii) & 0xff;
X			for (ii = 0; ii < *len; ii++)
X				cnt1[ii] = cnt1[ii+1];
X		}
X		cnt1[*len] = '\0';
X	}
X	printmsg( 5, "rec  packet type %d, num=%d, n=%d, len=%d", nt1, *nt3, *nt4, *len );
X	printmsg( 6, "  checksum rec = %x comp = %x, data=\n|%s|", check, checkchk, cnt1 );
X	ii = nt1;
X	return(ii);
X}
X
X
Xunsigned	checksum(data, len)
Xint	len;
Xchar	data[];
X{
X	unsigned int	i, j, tmp, chk1, chk2;
X	chk1 = 0xffff;
X	chk2 = 0;
X	j = len;
X	for (i = 0; i < len; i++) {
X		if (chk1 & 0x8000) {
X			chk1 <<= 1;
X			chk1++;
X		} else {
X			chk1 <<= 1;
X		}
X		tmp = chk1;
X		chk1 += (data[i] & 0xff);
X		chk2 += chk1 ^ j;
X		if ((chk1 & 0xffff) <= (tmp & 0xffff))
X			chk1 ^= chk2;
X		j--;
X	}
X	return(chk1 & 0xffff);
X}
X
X
X/* */
X/*
Xgwrmsg
X	send a null terminated string out
X*/
Xgwrmsg( typ, buf )
Xchar typ;
Xchar *buf; /* null terminated */
X{
X}
X
X/*
Xgrdmsg
X	read a null terminated string
X*/
Xgrdmsg( buf )
Xchar * buf;
X{
X
X}
X
X/*
Xgwrdata
X	read a file and send it out
X*/
Xgwrdata( f )
X{
X}
X
X/*
Xgrrdata
X	read in data and send to file
X*/
Xgrrdata( f )
X{
X}
X
X
X/*
Xgrdblk
X	read a block of data in
X*/
Xgrdblk( blk, len )
X{
X}
X
X/*
Xgwrblk
X	write out a block of data
X*/
Xgwrblk( blk, len )
X{
X}
X
SHAR_EOF
chmod 0600 dcpgpkt.c || echo "restore of dcpgpkt.c fails"
sed 's/^X//' << 'SHAR_EOF' > dcpsys.c &&
X
X/*			dcpsys.c
X
X			Revised edition of dcp
X
X			Stuart Lynne May/87
X
X			Copyright (c) Richard H. Lamb 1985, 1986, 1987
X			Changes Copyright (c) Stuart Lynne 1987
X
X*/
X/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
X/* Get the next system, and other support routines  */
X#include "dcp.h"
X/*#define PROTOS  "trkg"*/
X#define PROTOS  "g"
X#define MAXLOGTRY       3
X
XProto Protolst[] = {
X		'g', ggetpkt, gsendpkt, gopenpk, gclosepk,
X/*
X	    'k', kgetpkt, ksendpkt, kopenpk, kclosepk,
X	    'r', rgetpkt, rsendpkt, ropenpk, rclosepk,
X	    't', tgetpkt, tsendpkt, topenpk, tclosepk,
X*/
X		 '0'};
X
X#define EOTMSG "\004\r\004\r"
X
Xprocref         getpkt, sendpkt, openpk, closepk;
X
X/**/
X
X/***************************************************************/
X/***            Sub Systems             */
X/*
X**
X**getsystem
X** Process an "systems" file entry (like L.sys)
X*/
Xgetsystem()
X{
X	int	i;
X
X	do {
X		if ( ! fgets( sysline, BUFSIZ, fsys ) )
X			return( 'A' );
X		printmsg( 2, "%s", sysline );
X	} while (sysline[0] == '#');
X
X	kflds = getargs( sysline, flds );
X	strcpy( rmtname, flds[FLD_REMOTE] );
X	cctime = flds[FLD_CCTIME];
X	strcpy( device, flds[FLD_DEVICE] );
X
X	/* strcpy( type, flds[FLD_TYPE] ); */
X	strcpy( speed, flds[FLD_SPEED] );
X	strcpy( proto, flds[FLD_PROTO] );
X
X
X	if (debuglevel > 3)
X		for (i = FLD_EXPECT; i < kflds; i += 2)
X			fprintf( stderr, "expect[%02d]:\t%s\nsend  [%02d]:\t%s\n",
X				i, flds[i], i+1, flds[i+1] );
X
X	printmsg( 2, "rmt= %s ctm= %s", rmtname, flds[FLD_CCTIME] );
X	printmsg( 2, "dev= %s ", device );
X	printmsg( 2, "spd= %s pro= %s", speed, proto );
X	fw = (FILE *)NULL;
X	if (
X		/* (checktime( cctime )) || */
X		( strncom( Rmtname, "all", 4 ) == SAME ) ||
X		( strncom( Rmtname, rmtname, -1 ) == SAME ) ||
X	 	( (strncom( Rmtname, "any", 4 ) == SAME) && scandir() == 'S' )
X	 	)
X	{
X		if ( fw != (FILE *)NULL )
X		  fclose( fw );	/* in case we matched with scandir */
X		return( 'S' );  /* startup this system */
X	}
X	else
X		return('G');
X}
X
X/*
X**
X**checktime
X** check if we may make a call at this time
X**------------>to be implemented. Again. Didnt think it crucial
X*/
Xchecktime(xtime)
Xchar	xtime[];
X{
X	return(0); /* OK go to it */
X}
X
X
X
X/**/
X/*
X**
X**sysend
X** end UUCP session negotiation
X*/
Xsysend()
X{
X	char	msg[80];
X
X	msg[1] = '\0';
X	msgtime = 2 * MSGTIME;
X	/* while (msg[1] != 'O') { */
X		wmsg("OOOOOO", 2);
X		if (rmsg(msg, 2) == -1)
X			goto hang;
X	/*}*/
Xhang:
X	wmsg("OOOOOO", 2);
X	closeline();
X	if ( remote == MASTER )
X		return('I');
X	return('A');
X}
X
X
X/**/
X/*
X**
X**      delay
X**
X*/
X/*ddelay(dtime)
Xint	dtime;
X{
X	int	i, j;
X	for (i = 0; i < dtime; i++) {
X	}
X}
X*/
X
X/**/
X/*
X**
X**wmsg
X** write a ^P type msg to the remote uucp
X*/
Xwmsg(msg, syn)
Xchar	*msg;
Xint	syn;
X{
X	int	len;
X	len = strlen(msg);
X	if (syn == 2)
X		swrite("\020", 1);
X	swrite(msg, len);
X	if (syn == 2)
X		swrite("\n", 2);
X}
X
X
X/*
X**
X**rmsg
X** read a ^P msg from UUCP
X*/
Xrmsg(msg, syn)
Xint	syn;
Xchar	msg[];
X{
X	int	ii;
X	char	c, cc[5];
X	/* *msg0;*/
X	/*msg0 = msg;*/
X	c = 'a';
X	if (syn == 2) {
X		while ((c & 0x7f) != '\020') {
X			if (sread(cc, 1, msgtime) < 1)
X				return(-1);
X			c = cc[0]; /* Dont ask. MSC needs more than a byte to breathe */
X			/*		printf("Hello im in rmsg c=%x\n",c); */
X		}
X	}
X	for (ii = 0; ii < 132 && c ; ii++) {
X		if (sread(cc, 1, msgtime) < 1)
X			return(-1);
X		c = cc[0] & 0x7f;
X		if (c == '\r' || c == '\n')
X			c = '\0';
X		msg[ii] = c;
X		/*if(c == '\020') msg = msg0; */
X	}
X	return(strlen(msg));
X}
X
X
X
X/**/
X/*
X**
X**
X**startup
X**
X**
X*/
Xstartup()
X{
X	char	msg[80], tmp1[20], tmp2[20];
X	if ( remote == MASTER ) {
X		msgtime = 2 * MSGTIME;
X		if (rmsg(msg, 2) == -1)
X			return('Y');
X		printmsg( 2, "1st msg = %s", msg );
X		if (msg[5] == '=' && strncmp(&msg[6], rmtname, 7))
X			return('Y');
X
X		/*sprintf(msg, "S%.7s -Q0 -x%d", nodename, debuglevel);*/  /* -Q0 -x16 remote debuglevel set */
X		sprintf(msg, "S%.7s", nodename);
X
X		wmsg(msg, 2);
X		if (rmsg(msg, 2) == -1)
X			return('Y');
X		printmsg( 2, "2nd msg = %s", msg );
X		if (strncmp(&msg[1], "OK", 2))
X			return('Y');
X		if (rmsg(msg, 2) == -1)
X			return('Y');
X		printmsg( 2, "3rd msg = %s", msg );
X		if (msg[0] != 'P' || index(&msg[1], proto[0]) == (char *)NULL) {
X			wmsg("UN", 2);
X			return('Y');
X		}
X		sprintf(msg, "U%c", proto[0]);
X		wmsg(msg, 2);
X		setproto(proto[0]);
X		return('D');
X	} else {
X		msgtime = 2 * MSGTIME;
X		sprintf(msg, "Shere=%s", nodename);
X		wmsg(msg, 2);
X		if (rmsg(msg, 2) == -1)
X			return('Y');
X		sscanf(&msg[1], "%s %s %s", rmtname, tmp1, tmp2);
X		sscanf(tmp2, "-x%d", &debuglevel);
X		printmsg( 1, "debuglevel level = %d", debuglevel );
X		printmsg( 2, "1st msg from remote = %s", msg );
X		if (checkname(rmtname))
X			return('Y');
X		wmsg("ROK", 2);
X		sprintf(msg, "P%s", PROTOS);
X		wmsg(msg, 2);
X		if (rmsg(msg, 2) == -1)
X			return('Y');
X		if (msg[0] != 'U' || index(PROTOS, msg[1]) == (char *)NULL )
X			return('Y');
X		proto[0] = msg[1];
X		setproto(proto[0]);
X		return('R');
X	}
X}
X
X
X/******* set the protocol **********/
Xsetproto(pr)
Xchar	pr;
X{
X	int	i;
X	Proto * tproto;
X	for (tproto = Protolst; tproto->type != '\0' && pr != tproto->type; tproto++) {
X		printmsg( 3, "setproto: %c %c", pr, tproto->type );
X	}
X	if (tproto->type == '\0') {
X		printmsg( 0, "setproto:You said I had it but I cant find it" );
X		exit(1);
X	}
X	getpkt = tproto->a;
X	sendpkt = tproto->b;
X	openpk = tproto->c;
X	closepk = tproto->d;
X}
X
X
X
X/**/
Xint prefix(sh,lg)
Xchar *sh,*lg;
X{
X	return( strncmp(sh,lg,strlen(sh)) == SAME);
X}
X
Xint notin(sh,lg)
Xchar *sh,*lg;
X{
X	while (*lg) {
X		if (prefix(sh,lg++))
X			return( FALSE );
X	}
X	return( TRUE );
X}
X
X#define MAXR 300
Xint expectstr( str, timeout )
Xchar *str;
X{
X	static char rdvec[MAXR];
X	char *rp = rdvec;
X	int kr;
X	char nextch;
X
X	printmsg( 0, "wanted %s", str );
X
X	if ( strcmp(str, "\"\"") == SAME ) {
X		return( TRUE );
X	}
X	*rp = 0;
X	while ( notin( str,rdvec ) ) {
X		/* fprintf(stderr, "---------->%s<------\n", rdvec);/**/
X		kr = sread( &nextch, 1, timeout /* 40 */ );
X		/* nextch &= 0177;
X		fprintf(stderr, "kr - %2d '%c'\n", kr, nextch); */
X		if (kr <= 0) {
X			return( FALSE );
X		}
X		if ((*rp = nextch & 0177) != '\0') {
X			rp++;
X		}
X		*rp = '\0';
X		if (rp >= rdvec + MAXR) {
X			return( FALSE );
X		}
X	}
X	return( TRUE );
X}
X
Xint writestr(s)
X	register char *s;
X{
X	register char last;
X	register char * m;
X	int nocr;
X	last = '\0';
X	nocr = FALSE;
X	while (*s) {
X		if (last == '\\') {
X			switch (*s) {
X			case 'd':
X			case 'D': /* delay */
X               sleep(2);
X               break;
X            case 'c':
X            case 'C': /* end string don't output CR */
X               nocr = TRUE;
X               break;
X            case 'r':
X            case 'R': /* carriage return */
X            case 'm':
X            case 'M':
X      			swrite( "\r", 1 );
X               	break;
X            case 'n':
X            case 'N':
X      			swrite( "\n", 1 );
X               	break;
X            case 'b':
X            case 'B':
X      			swrite( "\b", 1 );
X               	break;
X            case 't':
X            case 'T':
X      			swrite( "\t", 1 );
X               	break;
X            case 's':
X            case 'S':
X      			swrite( " ", 1 );
X               	break;
X            case 'z':
X            case 'Z':
X            	SIOSpeed( ++s );
X            	while ( *s != '\0' && *s != '\\' )
X            		s++;
X            	if ( *s == '\\' )
X            		s++;
X            	break;
X            default:
X      			swrite( s, 1 );
X			}
X			last = '\0';
X		}
X		else if (*s != '\\') {
X      		swrite( s, 1 );
X			/* fputc(*s,stderr); */
X		}
X		else {
X			last = *s;
X		}
X		s++;
X	}
X	return( nocr );
X}
X
X/***
X *   void sendthem(str)   send line of login sequence
X *         char *str;
X *
X *   return codes:  none
X */
X
Xvoid sendstr(str)
Xchar *str;
X{
X	int nw, ns;
X	int nulls;
X
X	printmsg( 2, "sending %s", str );
X
X#ifdef BREAK
X	if (prefix("BREAK", str)) {
X		sscanf(&str[5], "%1d", &nulls);
X		if (nulls <= 0 || nulls > 10)
X			nulls = 3;
X		/* send break */
X		ssendbrk(nulls);
X		return;
X	}
X#endif
X
X	if ( strcmp(str, "EOT") == SAME ) {
X		swrite(EOTMSG, strlen(EOTMSG));
X		return;
X	}
X
X	if ( strcmp(str,"\"\"") == SAME )
X		*str = '\0';
X		/*fprintf(stderr,"'%s'\n",str);*/
X
X	if ( strcmp(str,"") != SAME ) {
X		if (!writestr(str)) {
X			swrite ("\r", 1);
X		}
X	}
X	else {
X		swrite("\r", 1);
X	}
X	return;
X}
X
Xint sendexpect( s, e, timeout )
Xchar * s;
Xchar * e;
X{
X	sendstr( s );
X	return( expectstr( e, timeout ) );
X}
X
Xdial()
X{
X	int	flg, kk, jj, ll, firstflg;
X	char	buf[4], *prsend;
X
X	char *exp;
X	char *alternate;
X	int	ok;
X	int	doofosity=0;
X	int i;
X
X	if ( strcmp( flds[FLD_TYPE], "HAYES" ) != SAME ) {
X		printmsg( 0, "dial: unsupported dialer %s", flds[FLD_TYPE] );
X		return( FALSE );
X	}
X
X	printmsg( 3, "calling host %s", rmtname );
X	if (openline(device, "2400" ))
X		return( FALSE );
X/*
X	printmsg( 0, "hayes: trying 2400" );
X	if ( sendexpect( "\\r\\dATZ", "OK", 4 ) != TRUE ) {
X		sendexpect( "\\d+++\\d", "OK", 2 );
X		if ( sendexpect( "ATZ", "OK", 2 ) != TRUE ) {
X			printmsg( 0, "hayes: trying 1200" );
X			SIOSpeed( "1200" );
X			if ( sendexpect( "ATZ", "OK", 2 ) != TRUE ) {
X				sendexpect( "\\d+++\\d", "OK", 2 );
X				if ( sendexpect( "ATZ", "OK", 2 ) != TRUE )
X					return( FALSE);
X				}
X		}
X	}
X	printmsg( 0, "hayes: got modem response" );
X*/
X	/*(sendstr( "\\d\\dATS7=30" );
X	expectstr( "OK", 40 );*/
X
X	sendstr( "\\dATX4\\c" );
X	sendstr( speed );
X
X	if ( sendexpect( "", "CONNECT ", 40 ) == TRUE ) {
X		printmsg( 3, "hayes: got CONNECT" );
X
X		if ( sread( buf, 4, 4 ) == 4 ) {
X			printmsg( 0, "hayes: speed select %s", buf );
X			/* set speed appropriately */
X			SIOSpeed( buf );
X		}
X		return( TRUE );
X	}
X	return( FALSE );
X}
X
X
X/*
X**
X**callup
X** script processor - nothing fancy!
X*/
Xcallup()
X{
X	int	flg, kk, jj, ll, firstflg;
X	char	*prsend;
X
X	char *exp;
X	char *alternate;
X	int	ok;
X	int i;
X
X	printmsg( 0, "calling host %s", rmtname );
X
X	if ( strcmp( flds[FLD_TYPE], "DIR" ) != SAME ) {
X		if ( dial() == FALSE )
X			return( 'G' );
X	}
X	else if (openline(device, speed))
X		return( 'G' );
X
X	for (i = 6; i < kflds; i+=2) {
X
X		exp = flds[i];
X		printmsg( 2, "callup: expect %d of %d  \"%s\"", i, kflds, exp );
X
X		ok = FALSE;
X		while (ok != TRUE) {
X			int time = 30;
X			char *timel;
X			
X			timel = index( exp, '~' );
X			if (timel != (char *)NULL)
X			{
X				time = atoi(timel+1);
X				alternate = timel+1;
X				while (isdigit(*alternate))
X					alternate++;
X				strcpy(timel, alternate);
X			}
X
X			alternate = index( exp, '-' );
X			if (alternate != (char *)NULL)
X				*alternate++ = '\0';
X
X			ok = expectstr( exp, time );
X
X			printmsg( 1, "got %s", ok != TRUE ? "?" : "that" );
X
X			if ( ok == TRUE ) {
X				printmsg( 0, "got that" );
X				break;
X			}
X
X			if ( alternate == (char *)NULL ) {
X				printmsg( 0, "LOGIN FAILED" );
X				return( 'Y' );
X			}
X
X			exp = index( alternate, '-' );
X			if ( exp != (char *)NULL )
X				*exp++ = '\0';
X
X			printmsg( 0, "send alternate" );
X
X			sendstr( alternate );
X		}
X
X	printmsg( 2, "callup: send %d of %d  \"%s\"", i+1, kflds, flds[i+1] );
X	sleep(1); /* (1)*/
X	sendstr(flds[i+1]);
X	}
X	return('P');
X
X}
X
X/**/
X/*
X**
X**      slowrite
X** comunication slow write. needed for auto-baud modems
X*/
X/*slowrite(st)
Xregister char	*st;
X{
X	int	len, j;
X	char	c;
X	len = strlen(st);
X	printmsg( 2, "sent %s", st );
X	for (j = 0; j < len; j++) {
X		swrite(&st[j], 1);
X		ddelay(80000);
X	}
X}
X*/
X
X/**/
X/*
X**
X**scandir
X**
X*/
X
X#include "ndir.h"
X
X
X/*	scandir
X
X	scan work dir for C. files matching current remote host (rmtname)
X
X	return
X
X		A	- abort
X		Y	- can't open file
X		S	- ok
X		Q	- no files
X
X*/
Xscandir()
X{
X	int	fn, len, i;
X	char	cname[40], tmp[132];
X
X	DIR *dirp;
X	struct direct *dp;
X
X	if ((dirp = opendir( spooldir )) == (DIR *)NULL ) {
X		fprintf( stderr, "couldn't open dir %s\n", spooldir );
X		return( 'A' );
X	}
X	sprintf(cname, CALLFILE, rmtname);
X	len = strlen(cname);
X	while ((dp = readdir(dirp)) != (struct direct *)NULL) {
X		printmsg( 4, "scandir: %s", dp->d_name );
X		if ( strncom( cname, dp->d_name, len ) == SAME ) {
X			printmsg( 4, "scandir: match!!" );
X			strcpy(cfile, dp->d_name);
X			closedir( dirp );
X			if ((fw = FOPEN( cfile, "r", 't' )) == (char *)NULL )
X				return('Y');
X			return('S');
X		}
X	}
X	closedir( dirp );
X	return('Q');
X
X}
X
X
X/**/
X/*
X**
X**dscandir
X** scan the directory
X*/
X
Xdscandir()
X{
X	int	fn, len, i;
X	char	cname[40], tmp[132];
X
X	DIR *dirp;
X	struct direct *dp;
X
X
X	if ((dirp = opendir( spooldir )) == (DIR *)NULL ) {
X		fprintf( stderr, "couldn't open dir %s\n", spooldir );
X		return(0);
SHAR_EOF
echo "End of part 1, continue with part 2"
echo "2" > s2_seq_.tmp
exit 0