[net.sources] UUSLAVE.c

simpsong@ncoast.UUCP (01/17/87)

*** Line-eater foo-d. ***

Greetings Fellow Neter's... There was a lot of talk about
UUCP for MS-DOS a week or two ago, and one thing that was
mentioned was a program called uuslave.c from a BBS in NJ.
Well, even though I am in Cleveland, I went ahead and registered
just so I could get this program...

Unfortunately, it contains very few comments, and appears to
be originally targeted for CPM, as well as having lots of stuff
hard-wired into the code...

I really don't know if it will be of any use, but it may be a 
building block from which the readers of net-land can produce
a usable uucp for msdos. (Does Minix have uucp?)

There was absolutely no documentation, and after looking at it
briefly, I really don't know where to start...

So, I ask... can anyone out there make heads or tails of this?
I will be trying to, but it really isn't my cup of tea. If anyone
can make this work, please repost your enhanced version with some
documentation.

Thanks, and Enjoy.


      Gregory R. Simpson       

UUCP: {ihnp4, seismo, decwrl, philabs, ucbvax}!decvax!cwruecmp!ncoast!simpsong
CSNET: ncoast!simpsong@case.CSNET     
ARPA:  ncoast!simpsong%case.CSNET@Csnet-Relay.ARPA

------- This is NOT a shar, or an arc, or anything... just straight code ----


/* @[$]uuslave.c	1.7 08/12/85 14:04:20 */

#include <stdio.h>
#include <fcntl.h>
#ifndef CPM
#include <termio.h>
#include <signal.h>
#endif

#define	MAGIC	0125252
#define	EOT	4

#define	CTRL	0
#define	ALTCHN	1
#define	LNGDAT	2
#define	SHTDAT	3

#define	CLOSE	1
#define	RJ	2
#define	SRJ	3
#define	RR	4
#define	INITC	5
#define	INITB	6
#define	INITA	7

extern errno;
char msgi[256],msgo[256],ttynam[32],cmnd[8],srcnam[32],dstnam[32],dskbuf[256],msgbld[256];
int fdtty,fddsk,tt,xxx,yyy,rseq,wseq;
#ifndef CPM
struct termio atermio,btermio;
#endif
#ifdef ERRLOG
FILE *file;
#endif

int wndsiz = 1;
int segsiz = 1;

char msgo0[] = "9800rcs login: ";
char msgo1[] = "Password:";
char msgo2[] = "\20Shere\0";
char msgo3[] = "\20ROK\0\20Pg\0";
char msgo4[] = "\20OOOOOO\0";
char msgo5[] = "...abort...";

char msgi0[] = "uucp\n";
char msgi1[] = "s8000\n";
char msgi2[] = "\20S*\0";
char msgi3[] = "\20Ug\0";

#ifdef CPM
extern xgetc(),xwrite();
#else
sigint()
{
	ioctl(fdtty,TCSETA,&atermio);
	close(fdtty);
	exit(0);
}

sigalrm()
{
}

xgetc()
{
	char data;

	signal(SIGALRM,sigalrm);
	alarm(10);
	if (read(fdtty,&data,1) > 0)
	{
		alarm(0);
		return(data & 0xFF);
	}
	return(EOF);
}

xwrite(fd,buf,ctr)
int fd;
char *buf;
int ctr;
{
	write(fd,buf,ctr);
}
#endif

zero(p,c)
char *p;
int c;
{
	while (c--)
		*p++ = 0;
}

ackmsg()
{
	int cksm,index;

	msgo[0] = 020;
	msgo[1] = 9;
	msgo[4] = (CTRL << 6) | (RR << 3) | rseq;
	cksm = MAGIC - msgo[4];
	msgo[2] = cksm;
	msgo[3] = cksm >> 8;
	msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];
#ifdef DEBUG
	
	printf("T ");
	for (index = 0; index < 6; index++)
		printf("%03o ",msgo[index] & 0xFF);
	putchar('\n');
#endif
	xwrite(fdtty,msgo,6);
	rseq = (rseq + 1) & 7;
}

ctlmsg(byte)
char byte;
{
	int cksm,index;

	msgo[0] = 020;
	msgo[1] = 9;
	msgo[4] = (CTRL << 6) | byte;
	cksm = MAGIC - msgo[4];
	msgo[2] = cksm;
	msgo[3] = cksm >> 8;
	msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];
#ifdef DEBUG
	printf("T ");
	for (index = 0; index < 6; index++)
		printf("%03o ",msgo[index] & 0xFF);
	putchar('\n');
#endif
	xwrite(fdtty,msgo,6);
}

lngput(s,n)
char *s;
int n;
{
	int cksm,index;

	zero(msgo,256);
	msgo[0] = 020;
	msgo[1] = segsiz + 1;
	msgo[4] = (LNGDAT << 6) + (wseq << 3) + rseq;
	for (index = 0; index < (segsiz + 1) * 32; index++)
		msgo[6+index] = 0;
	for (index = 0; index < n; index++)
		msgo[6+index] = *(s+index);
	cksm = MAGIC - (chksum(&msgo[6],(segsiz + 1) * 32) ^ (0377 & msgo[4]));
	msgo[2] = cksm;
	msgo[3] = cksm >> 8;
	msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];
#ifdef DEBUG
	printf("T ");
	for (index = 0; index < (segsiz + 1) * 32 + 6; index++)
		printf("%03o ",msgo[index] & 0xFF);
	putchar('\n');
#endif
	do
	{
		xwrite(fdtty,msgo,(segsiz + 1) * 32 + 6);
		if (inpkt())
			return(1);
	}
	while (tt != CTRL || xxx != RR || yyy != wseq);
	wseq = (wseq + 1) & 7;
	return(0);
}

shtput(s,n)
char *s;
int n;
{
	int cksm,index;

	zero(msgo,256);
	msgo[0] = 020;
	msgo[1] = segsiz + 1;
	msgo[4] = (SHTDAT << 6) + (wseq << 3) + rseq;
	for (index = 0; index < (segsiz + 1) * 32; index++)
		msgo[6+index] = 0;
	msgo[6] = (segsiz + 1) * 32 - n;
	for (index = 0; index < n; index++)
		msgo[7+index] = *(s+index);
	cksm = MAGIC - (chksum(&msgo[6],(segsiz + 1) * 32) ^ (0377 & msgo[4]));
	msgo[2] = cksm;
	msgo[3] = cksm >> 8;
	msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];
#ifdef DEBUG
	printf("T ");
	for (index = 0; index < (segsiz + 1) * 32 + 6; index++)
		printf("%03o ",msgo[index] & 0xFF);
	putchar('\n');
#endif
	do
	{
		xwrite(fdtty,msgo,(segsiz + 1) * 32 + 6);
		if (inpkt())
			return(1);
	}
	while (tt != CTRL || xxx != RR || yyy != wseq);
	wseq = (wseq + 1) & 7;
	return(0);
}

instr(s,n)
char *s;
int n;
{
	int data,count,i,j;

	count = 0;
#ifdef DEBUG
	printf("Expecting ");
	for (i = 0; i < n; i++)
		printf("%03o ",*(s+i));
	printf("\nR ");
#endif
	while ((data = xgetc()) != EOF)
	{
		msgi[count++] = data & 0x7F;
#ifdef DEBUG
		printf("%03o ",msgi[count-1]);
#endif
		if (count >= n)
		{
			for (i = n - 1, j = count - 1; i >= 0; i--, j--)
				if (*(s+i) == '*' || *(s+i) != msgi[j])
					break;
			if (i < 0 || *(s+i) == '*')
			{
#ifdef DEBUG
				putchar('\n');
#endif
				return(0);
			}
		}
	}
#ifdef DEBUG
	putchar('\n');
#endif
	msgi[count] = 0;
	return(1);
}

inpkt()
{
	int data,count,need;

	count = 0;
#ifdef DEBUG
	printf("R ");
#endif
	while ((data = xgetc()) != EOF)
	{
#ifdef DEBUG
		printf("%03o ",data & 0xFF);
#endif
		switch (count)
		{
		case 0 :
			if (data == 020)
				msgi[count++] = 020;
			break;
		case 1 :
			msgi[count++] = data;
			if (data == 9)
				need = 4;
			else
				need = 32 * data + 4;
			break;
		case 4 :
			tt = (data >> 6) & 3;
			xxx = (data >> 3) & 7;
			yyy = data & 7;
		default :
			msgi[count++] = data;
			if (!--need)
			{
#ifdef DEBUG
				putchar('\n');
#endif
				return(0);
			}
			break;
		}
	}
#ifdef DEBUG
	putchar('\n');
#endif
	return(1);
}

chksum(s,n)
register char *s;
register n;
{
	register short sum;
	register unsigned short t;
	register short x;

	sum = -1;
	x = 0;
	do
	{
		if (sum < 0)
		{
			sum <<= 1;
			sum++;
		}
		else
			sum <<= 1;
		t = sum;
		sum += *s++ & 0377;
		x += sum ^ n;
		if ((unsigned) sum <= t)
			sum ^= x;
	}
	while (--n > 0);
	return(sum);
}

main(argc,argv)
int argc;
char *argv[];
{
	char *p;
	int data,count;

#ifdef CPM
	sioinit();
#else
	if (argc > 1)
		strcpy(ttynam,argv[1]);
	else
		strcpy(ttynam,"/dev/tty12");
	if ((fdtty = open(ttynam,O_RDWR)) < 0)
	{
		printf("Cannot open %s for read/write %d\n",ttynam,errno);
		exit(1);
	}
	ioctl(fdtty,TCGETA,&atermio);
	btermio = atermio;
	btermio.c_iflag = btermio.c_oflag = btermio.c_lflag = 0;
	btermio.c_cc[VMIN] = 1;
	btermio.c_cc[VTIME] = 0;
	btermio.c_cflag = (btermio.c_cflag & ~CBAUD) | B1200;
	ioctl(fdtty,TCSETA,&btermio);
	signal(SIGINT,sigint);
#endif
	while (1)
	{
#ifdef DEBUG
		puts("restarting");
#endif
		rseq = 0;
		wseq = 1;

/* wait for EOT */

		while ((data = xgetc()) == EOF || (data &= 0x7F) != EOT);

/* output login request, verify uucp */

		xwrite(fdtty,msgo0,sizeof(msgo0)-1);
		if (instr(msgi0,sizeof(msgi0)-1))
			goto abort;

/* output password request, verify s8000 */

		xwrite(fdtty,msgo1,sizeof(msgo1)-1);
		if (instr(msgi1,sizeof(msgi1)-1))
			goto abort;

/* output here message, wait for response */

		xwrite(fdtty,msgo2,sizeof(msgo2)-1);
		if (instr(msgi2,sizeof(msgi2)-1))
			goto abort;

/* output ok message, output protocol request, wait for response */

		xwrite(fdtty,msgo3,sizeof(msgo3)-1);
		if (instr(msgi3,sizeof(msgi3)-1))
			goto abort;

/* output inita message, wait for response */

		ctlmsg((INITA << 3) | wndsiz);
		if (inpkt() || tt != CTRL || xxx != INITA)
			goto abort;

/* output initb message, wait for response */

		ctlmsg((INITB << 3) | segsiz);
		if (inpkt() || tt != CTRL || xxx != INITB)
			goto abort;

/* output initc message, wait for response */

		ctlmsg((INITC << 3) | wndsiz);
		if (inpkt() || tt != CTRL || xxx != INITC)
			goto abort;

/* output initial acknowledge, wait for command */

		ackmsg();
		while (1)
		{
			if (inpkt() || tt != LNGDAT)
			{
				intf("OVER EIGHT");
				goto abort;
			}
			strcpy(msgbld,&msgi[6]);
			while (strlen(&msgi[6]) == (segsiz + 1) * 32)
			{
				ackmsg();
				if (inpkt() || tt != LNGDAT)
				{
					intf("OVER ABORT SEVEN");
					goto abort;
				}
				strcat(msgbld,&msgi[6]);
			}
			switch (msgbld[0])
			{
			case 'S' :
				sscanf(msgbld,"%s %s %s",cmnd,srcnam,dstnam);
#ifdef CPM
				for (p = dstnam + strlen(dstnam); p != dstnam && *(p-1) != '/'; p--);
#else
				p = dstnam;
#endif
				if ((fddsk = creat(p,0644)) >= 0)
				{
					ackmsg();
					if (lngput("SY",2))
					{
						intf("OVER NINE");
						goto abort;
					}
					do
						if (inpkt())
						{
							intf("OVER TEN");	
							goto abort;
						}	
						else
							switch (tt)
							{
							case LNGDAT :
								write(fddsk,&msgi[6],(segsiz + 1) * 32);
								ackmsg();
								break;
							case SHTDAT :
								if (msgi[6] & 0x80)
								{
									intf("OVER ELEVEN");
#ifdef DEBUG
									puts("short packet error");
#endif
									goto abort;
								}
								else
								{
									if (msgi[6] != (segsiz + 1) * 32)
										write(fddsk,&msgi[7],(segsiz + 1) * 32 - msgi[6]);
									ackmsg();
								}
								break;
							default :
								intf("OVER TWELVE");
								goto abort;
							}
					while (tt != SHTDAT || msgi[6] != (segsiz + 1) * 32);
					close(fddsk);
					if (lngput("CY",2))
						goto abort;
				}
				else
				{
					ackmsg();
#ifdef ERRLOG
					if (file = fopen("uuslave.log","a+"))
					{
						fprintf(file,"Cannot open file=%s for writing errno=%d\n",p,errno);
						fclose(file);
					}
#endif
					sprintf(dskbuf,"SN%d",errno);
					if (lngput(dskbuf,strlen(dskbuf)))
						goto abort;
				}
				break;
			case 'R' :
				sscanf(msgbld,"%s %s %s",cmnd,srcnam,dstnam);
#ifdef CPM
				for (p = srcnam + strlen(srcnam); p != srcnam && *(p-1) != '/'; p--);
#else
				p = srcnam;
#endif
				if ((fddsk = open(p,O_RDONLY)) >= 0)
				{
					ackmsg();
					if (lngput("RY",2))
						goto abort;
					do
						if ((count = read(fddsk,dskbuf,(segsiz + 1) * 32)) == (segsiz + 1) * 32)
							if (lngput(dskbuf,(segsiz + 1) * 32))
								goto abort;
							else;
						else
							if (shtput(dskbuf,count))
								goto abort;
					while (count);
					close(fddsk);
					do
						if (inpkt())
							goto abort;
					while (tt != LNGDAT);
					ackmsg();
				}
				else
				{
					ackmsg();
#ifdef ERRLOG
					if (file = fopen("uuslave.log","a+"))
					{
						fprintf(file,"Cannot open file=%s for reading errno=%d\n",p,errno);
						fclose(file);
					}
#endif
					sprintf(dskbuf,"RN%d",errno);
					if (lngput(dskbuf,strlen(dskbuf)))
						goto abort;
				}
				break;
			case 'H' :
				intf("IN H CASE");
				if (lngput("HY",2))
				{
					intf("OVER ABORT ONE");	
					goto abort;
				}
				if (inpkt() || tt != LNGDAT)
				{
					intf("OVER ABORT TWO");		
					goto abort;
				}
				if (!strcmp(&msgi[6],"HY"))
				{
					ctlmsg(CLOSE << 3);
					do
						if (inpkt())
						{
							intf("OVER ABORT THREE");
							goto abort;
						}
					while (tt != CTRL && xxx != CLOSE);
					xwrite(fdtty,msgo4,sizeof(msgo4)-1);
					instr(msgo4,sizeof(msgo4)-1);
				}
				intf("OVER ABORT FIVE");
				break;
				/*goto abort;*/
			}
		}
abort:;
		xwrite(fdtty,msgo5,sizeof(msgo5)-1);
	}
}
intf(buffer)
register char *buffer;
{
	int fd;
	fd = open("UUCP.DAT",O_RDWR + O_CREAT);
	lseek(fd,0L,2);
	write(fd,buffer,strlen(buffer));
	close(fd);
}
-- 
      Gregory R. Simpson       

UUCP: {ihnp4, seismo, decwrl, philabs, ucbvax}!decvax!cwruecmp!ncoast!simpsong
CSNET: ncoast!simpsong@case.CSNET     
ARPA:  ncoast!simpsong%case.CSNET@Csnet-Relay.ARPA

pozar@hoptoad.UUCP (01/24/87)

    Sorry to post this, my mailer upchucked on ncoast.UUCP.

    I picked off the uuslave code.  Could you point me the direction of where
you got it from?   There seems to be some header files that I'm unfamiler
with and weren't included with the code.  Mucho functions I don't fully
know what they need, etc...
       Thanks

-- 
        Tim Pozar
UUCP    pozar@hoptoad.UUCP
Fido    125/406
USNail  KLOK-FM
	77 Maiden Lane
	San Francisco CA 94108
terrorist cryptography DES drugs cipher secret decode NSA CIA NRO IRS
coke crack pot LSD russian missile atom nuclear assassinate libyan RSA
(Thanks to Robert Bickford for the suggestion for the NSA line eater)

allbery@ncoast.UUCP (01/26/87)

As quoted from <1683@hoptoad.uucp> by pozar@hoptoad.uucp (Tim Pozar):
+---------------
|     Sorry to post this, my mailer upchucked on ncoast.UUCP.
| 
|     I picked off the uuslave code.  Could you point me the direction of where
| you got it from?   There seems to be some header files that I'm unfamiler
| with and weren't included with the code.  Mucho functions I don't fully
| know what they need, etc...
+---------------

I can't tell you what BBS it came from, but I'm pretty sure it's legit; I
was given a copy somewhat earlier on another machine (tdi2.uucp).

The posting mentioned the fact that we're all pretty well stumped by it.  (I
don't have a C compiler, so I can't translate it to C on my PC; and while I
could conceivably translate to Turbo Pascal (I have done so in the past with
C programs), pointer problems usually result and reasonable COMn: I/O seems
to choke at anything over 1200 baud (and is somewhat flaky at 1200).)

It *does* seem to be written for CP/M, as opposed to MS-DOS.  This might mean
Aztec or BDS C, the two most common for CP/M.

++Brandon
-- 
 ____   ______________
/    \ / __   __   __ \   Brandon S. Allbery	    <backbone>!ncoast!allbery
 ___  | /__> /  \ /  \    aXcess Co., Consulting    ncoast!allbery@Case.CSNET
/   \ | |    `--, `--,    6615 Center St. #A1-105 	   (...@relay.CS.NET)
|     | \__/ \__/ \__/    Mentor, OH 44060-4101     
\____/ \______________/   +1 216 781 6201

turner@imagen.UUCP (01/28/87)

in article <1943@ncoast.UUCP>, allbery@ncoast.UUCP (Brandon Allbery) says:

> As quoted from <1683@hoptoad.uucp> by pozar@hoptoad.uucp (Tim Pozar):
......where does uuslave.c come from 
> I can't tell you what BBS it came from, but I'm pretty sure it's legit; I
> was given a copy somewhat earlier on another machine (tdi2.uucp).
> 
it came from the acg BBS in new jersey, they're number is

201 753-9758









-- 
---------------
C'est la vie, C'est le guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400

shapiro@oucs.UUCP (01/28/87)

What is uuslave.c? What is it supposed to do?
 
Thanks.
 
Brian Shapiro
Ohio University Computing and Learning Services
Athens Ohio  45710
 
UUCP:    !inhp4!cbatt!oucs!shapiro
Fido:    126/110
BITNET:  SHAPIROB@OUACCVMA

bruceb@telesoft.UUCP (01/28/87)

> As quoted from <1683@hoptoad.uucp> by pozar@hoptoad.uucp (Tim Pozar):
> | 
> |     I picked off the uuslave code.  Could you point me the direction of ...
> +---------------
> 
> The posting mentioned the fact that we're all pretty well stumped by it.  (I
> don't have a C compiler, so I can't translate it to C on my PC ...
> 
> ++Brandon

Hmmm.  I also got a copy of uuslave.c and have had time to investigate it in
depth.  If you have not bothered to find out the guts of uucp, no, you
probably will not make sense of it at all.  Fortunately, in past, I did try to
recreate uucp (similar to what lauren weinstien did), however the protocol
level of uucp is not documented.  Those who know the info aren't willing to
share it, so if you want to rewrite uucp, you are on your own.

Anyhow, with the advent of uuslave.c, the gaps have filled in.  With about 3
exceptions, I think I have what I need to do what I want.  In any case, I am
already engaged in creating a Modula-2 version of uuslave.c.  If this is
successful (no reason why it shouldn't be), I will take the time to redo
uuslave.c for MS-DOS.  The Modula-2 version (for MS-DOS) should be available
in a short while.

If anyone is interested in the Modula-2 or C versions of uuslave.c for MS-DOS,
please send me a note.  I'll be porting it as we speak, in any case.  Source
code will be included, of course.  Also, if you are interested in a discussion
of how uucp communicates (including the information in uuslave.c), please
send me a note also.  If I get sufficient response, I may consider posting
what I have.

bruce
-- 
                 bang!-
allegra!\              \
gould9!  \      crash!--\
ihnp4!    \              \
           >--sdcsvax!---->--telesoft!bruceb  (Bruce Bergman N7HAW)
noscvax!  /              /
scgvaxd! /   sdencore!--/
ucbvax! /              /
              talaris!-

allbery@ncoast.UUCP (02/01/87)

As quoted from <378@telesoft.UUCP> by bruceb@telesoft.UUCP (Bruce Bergman @spot):
+---------------
| > As quoted from <1683@hoptoad.uucp> by pozar@hoptoad.uucp (Tim Pozar):
| > | 
| > |     I picked off the uuslave code.  Could you point me the direction of ...
| > +---------------
| > 
| > The posting mentioned the fact that we're all pretty well stumped by it.  (I
| > don't have a C compiler, so I can't translate it to C on my PC ...
| > 
| > ++Brandon
| 
| Hmmm.  I also got a copy of uuslave.c and have had time to investigate it in
| depth.  If you have not bothered to find out the guts of uucp, no, you
| probably will not make sense of it at all.  Fortunately, in past, I did try to
+---------------

Actually, I meant the I/O code; specifically, how to duplicate it using UNIX
system calls or the I/O routines of MSC 4.0, etc.  I don't grok CP/M-80 C
I/O calls.

++Brandon
-- 
++Brandon (Resident Elf @ ncoast.UUCP)
 ____   ______________
/    \ / __   __   __ \   Brandon S. Allbery	    <backbone>!ncoast!allbery
 ___  | /__> /  \ /  \    aXcess Co., Consulting    ncoast!allbery@Case.CSNET
/   \ | |    `--, `--,    6615 Center St. #A1-105 	   (...@relay.CS.NET)
|     | \__/ \__/ \__/    Mentor, OH 44060-4101     
\____/ \______________/   +1 216 781 6201

mjranum@osiris.UUCP (02/06/87)

This is the mangled version of uuslave. I've fixed some parts, and
done my best to provide machine independence. The job is probably
not complete, but it will compile OK on a PC with Lattice C, as 
well as a SUN workstation. (from the ridiculous to the sublime, eh ?)

Anyhow, this is code "as is". It may need some work. If I was a 
dummy anywhere, flame me personally, don't E-mail to the net.
--mjr;

-------------fold here-------------

/* uuslave.c - client uucp(R) connection */
/* 	(uucp is copyright AT&T)	 */
/* this is designed to run on IBM PCs w/ */
/* a modem or direct connection to UNIX  */
/* no guarantees of functionality...     */

/* original author ?   */
/* very extensive and brutal hacks by Marcus J Ranum */

/* I take no responsibility for the working code here. */
/* all the comments (for what they're worth) are mine) */
/* I added all the incremental debug information stuff */

#include "stdio.h"
#include "signal.h"
/* if your system does not support signal, comment all */
/* references to signal out and it may still work.     */

#define	O_RDONLY	000	/* open for reading */
#define	O_WRONLY	001	/* open for writing */
#define	O_RDWR		002	/* open for read & write */

/* mysterious numbers that are possibly CP/M specific. */
/* they are used as masks for file I/O */
#define	CLOSE	1
#define	CTRL	0
#define LNGDAT	2
#define SHTDAT	3
#define	MAGIC	0125252
#define	EOT	4
#define	RR	4
#define	INITC	5
#define	INITB	6
#define	INITA	7

int     sigint ();
int     abort ();
char   *strcat ();
char   *strcpy ();
long    lseek ();
extern  errno;


int     wndsiz = 1;
int     segsiz = 1;

/* these are used later as buffers for ttynames, etc, etc, etc. */
char    msgi[256],
        msgo[256],
        cmnd[8],
        srcnam[32];
char    dstnam[32],
        dskbuf[256],
        msgbld[256];

/* fdtty is terminal file descriptor */
/* fddsk is disk file descriptor */
int     fdtty,
        fddsk;

/* I believe these are the message sequence numbers */
int     tt,
        xxx,
        yyy,
        rseq,
        wseq;

/* this is the communications device/port/whatever */
char   *ttynam;

/* error log file name, debug flags, etc.*/
FILE * errfile;
char   *errlog;
int     errflg;
int     debugmode = 0;

/* these next few strings are strings uucp expects to see. */
/* they shouldn't need changing */
/* messages that get sent out */
char   *msgo0;
char    msgo1[] = "Password:";
char    msgo2[] = "\20Shere\0";
char    msgo3[] = "\20ROK\0\20Pg\0";
char    msgo4[] = "\20OOOOOO\0";
char    msgo5[] = "...abort...";

/* messages that are read in */
char    msgi0[] = "uucp\n";
char    msgi1[] = "s8000\n";
char    msgi2[] = "\20S*\0";
char   *msgi3;

main (argc, argv)
int     argc;
char   *argv[];
{
    char   *p;
    int     data,
            ttisflg,
            unamflg,
            themflg,
            count;

    errflg = ttisflg = 0;
    unamflg = themflg = 0;
    errlog = "uuerr.log";

 /* mjr - this part completely mine. original version did not */
 /* give a damn about arguments */
/* we try to remove compiled-in dependencies (ugh) */

    for (count = 1; count <= argc; count++) {
	if (argv[count][0] == '-') {
	    switch (argv[count][1]) {
		/* line name */
		case 'l': 
		case 'L': 
		    if (strlen (argv[count]) > 2) {
			ttynam = &argv[count][2];
			ttisflg++;
		    }
		    break;

		/* error log file (default is uuerr.log) */
		case 'e': 
		case 'E': 
		    if (strlen (argv[count]) > 2) {
			errlog = &argv[count][2];
		    }
		    break;

		/* this system's name */
		case 'h': 
		case 'H': 
		    if (strlen (argv[count]) > 2) {
			unamflg++;
			msgo0 = &argv[count][2];
		    }
		    break;

		/* the other systems name */
		case 's': 
		case 'S': 
		    if (strlen (argv[count]) > 2) {
			themflg++;
			msgi3 = &argv[count][2];
		    }
		    break;

		/* turn on debug */
		case 'x': 
		case 'X': 
		    debugmode = atoi (&argv[count][2]);
		    if (!debugmode)
			debugmode++;
		    break;

		/* options */
		case 'o': 
		case 'O': 
		    fprintf (stderr, "uuslave options: \n");
		    fprintf (stderr, "(mandatory) -ldevicename\n");
		    fprintf (stderr, "(mandatory) -hhostname\n");
		    fprintf (stderr, "(mandatory) -stheirname\n");
		    fprintf (stderr, "errlog      -efilename\n");
		    fprintf (stderr, "debug       -x#\n");
		    fprintf (stderr, "options     -o\n");
		    exit (-9);

		default: 
		    fprintf (stderr, "uuslave:invalid option %s\n", &argv[count][1]);
		    exit (-1);
	    }
	}
    }

    if (!ttisflg) {
	fprintf (stderr, "uuslave: ");
	fprintf (stderr, "MUST specify line with -l<line> flag\n");
	exit (-1);
    }

    if (!themflg) {
	fprintf (stderr, "uuslave: ");
	fprintf (stderr, "MUST name other system with -s<name> flag\n");
	fprintf (stderr, "(use the name they will try to login as)\n");
	exit (-1);
    }

    if (!unamflg) {
	fprintf (stderr, "uuslave: ");
	fprintf (stderr, "MUST specify this system name with -h<name> flag\n");
	fprintf (stderr, "(use the name they are trying to log in to)\n");
	exit (-1);
    }
    if (debugmode) {
	fprintf (stderr, "using line %s to communicate.\n", ttynam);
	fprintf (stderr, "expecting them to log in as %s.\n", msgi3);
	fprintf (stderr, "this system name is expected to be %s.\n", msgo0);
	fprintf (stderr, "error log file is %s.\n", errlog);
    }

 /* open the communications device/tty for read/write */
    if ((fdtty = open (ttynam, O_RDWR)) < 0) {
	printf ("Cannot open %s for read/write %d\n", ttynam, errno);
	exit (1);
    }
    if (debugmode > 3) {
	printf ("opened %s read/write\n", ttynam);
    }

 /* trap interrupt to close communications line */
    signal (SIGINT, sigint);

    while (1) {
	if (debugmode) {
	    puts ("restarting\n");
	}
	rseq = 0;
	wseq = 1;

    /* wait for EOT */
	while ((data = xgetc ()) == EOF || (data &= 0x7F) != EOT);
	if (debugmode > 6) {
	    puts ("got EOT\n");
	}

    /* output login request, verify uucp */
	write (fdtty, msgo0, sizeof (msgo0) - 1);
	if (instr (msgi0, sizeof (msgi0) - 1))
	    abort ();
	if (debugmode > 3) {
	    puts ("requested and got login\n");
	}

    /* output password request */
	write (fdtty, msgo1, sizeof (msgo1) - 1);
	if (instr (msgi1, sizeof (msgi1) - 1))
	    abort ();
	if (debugmode > 4) {
	    puts ("requested and got password\n");
	}

    /* output system here message, wait for response */
	write (fdtty, msgo2, sizeof (msgo2) - 1);
	if (instr (msgi2, sizeof (msgi2) - 1))
	    abort ();
	if (debugmode > 6) {
	    puts ("sent and got system here name\n");
	}

    /* output ok message, protocol request, wait for response */
	write (fdtty, msgo3, sizeof (msgo3) - 1);
	if (instr (msgi3, sizeof (msgi3) - 1))
	    abort ();
	if (debugmode > 6) {
	    puts ("sent OK\n");
	}

    /* output inital message, wait for response */
	ctlmsg ((INITA << 3) | wndsiz);
	if (inpkt () || tt != CTRL || xxx != INITA)
	    abort ();
	if (debugmode > 6) {
	    puts ("sent initial message\n");
	}

    /* output initb message, wait for response */
	ctlmsg ((INITB << 3) | segsiz);
	if (inpkt () || tt != CTRL || xxx != INITB)
	    abort ();
	if (debugmode > 6) {
	    puts ("sent initb message\n");
	}

    /* output initc message, wait for response */
	ctlmsg ((INITC << 3) | wndsiz);
	if (inpkt () || tt != CTRL || xxx != INITC)
	    abort ();
	if (debugmode > 6) {
	    puts ("sent initc message\n");
	}

    /* output initial acknowledge, wait for command */
	ackmsg ();
	while (1) {
	    if (inpkt () || tt != LNGDAT) {
		intf ("OVER EIGHT");
		abort ();
	    }
	    strcpy (msgbld, &msgi[6]);
	    while (strlen (&msgi[6]) == (segsiz + 1) * 32) {
		ackmsg ();
		if (inpkt () || tt != LNGDAT) {
		    intf ("OVER ABORT SEVEN");
		    abort ();
		}
		strcat (msgbld, &msgi[6]);
	    }
	    switch (msgbld[0]) {
		case 'S': 
		    sscanf (msgbld, "%s %s %s", cmnd, srcnam, dstnam);
		    p = dstnam;
		    if ((fddsk = creat (p, 0644)) >= 0) {
			ackmsg ();
			if (lngput ("SY", 2)) {
			    intf ("OVER NINE");
			    abort ();
			}
			do
			    if (inpkt ()) {
				intf ("OVER TEN");
				abort ();
			    }
			    else
				switch (tt) {
				    case LNGDAT: 
					write (fddsk, &msgi[6], ((segsiz + 1) * 32));
					ackmsg ();
					break;
				    case SHTDAT: 
					if (msgi[6] & 0x80) {
					    intf ("OVER ELEVEN");
					    if (debugmode) {
						puts ("short packet error");
					    }
					    abort ();
					}
					else {
					    if (msgi[6] != (segsiz + 1) * 32)
						write (fddsk, &msgi[7], (segsiz + 1) * 32 - msgi[6]);
					    ackmsg ();
					}
					break;
				    default: 
					intf ("OVER TWELVE");
					abort ();
				}
			while (tt != SHTDAT || msgi[6] != (segsiz + 1) * 32);
			close (fddsk);
			if (lngput ("CY", 2))
			    abort ();
		    }
		    else {
			ackmsg ();
			if (errflg) {
			    if (errfile = fopen (errlog, "a+")) {
				fprintf (errfile, "Cannot write %s errno%d\n", p, errno);
				fclose (errfile);
			    }
			}
			sprintf (dskbuf, "SN%d", errno);
			if (lngput (dskbuf, strlen (dskbuf)))
			    abort ();
		    }
		    break;
		case 'R': 
		    sscanf (msgbld, "%s %s %s", cmnd, srcnam, dstnam);
		    p = srcnam;
		    if ((fddsk = open (p, O_RDONLY)) >= 0) {
			ackmsg ();
			if (lngput ("RY", 2))
			    abort ();
			do
			    if ((count = read (fddsk, dskbuf, ((segsiz + 1) * 32))) == (segsiz + 1) * 32)
				if (lngput (dskbuf, (segsiz + 1) * 32))
				    abort ();
				else;
			    else
				if (shtput (dskbuf, count))
				    abort ();
			while (count);
			close (fddsk);
			do
			    if (inpkt ())
				abort ();
			while (tt != LNGDAT);
			ackmsg ();
		    }
		    else {
			ackmsg ();
			if (errflg) {
			    if (errfile = fopen (errlog, "a+")) {
				fprintf (errfile, "Cannot read file %s errno:%d\n", p, errno);
				fclose (errfile);
			    }
			}
			sprintf (dskbuf, "RN%d", errno);
			if (lngput (dskbuf, strlen (dskbuf)))
			    abort ();
		    }
		    break;
		case 'H': 
		    intf ("IN H CASE");
		    if (lngput ("HY", 2)) {
			intf ("OVER ABORT ONE");
			abort ();
		    }
		    if (inpkt () || tt != LNGDAT) {
			intf ("OVER ABORT TWO");
			abort ();
		    }
		    if (!strcmp (&msgi[6], "HY")) {
			ctlmsg (CLOSE << 3);
			do
			    if (inpkt ()) {
				intf ("OVER ABORT THREE");
				abort ();
			    }
			while (tt != CTRL && xxx != CLOSE);
			write (fdtty, msgo4, sizeof (msgo4) - 1);
			instr (msgo4, sizeof (msgo4) - 1);
		    }
		    intf ("OVER ABORT FIVE");
		    break;
	    }
	}
    }
}

intf (buffer)
register char  *buffer;
{
    int     fd;

 /* make entry in UUCP.DAT file */
    fd = open ("UUCP.DAT", O_RDWR);
    lseek (fd, (long) 0, 2);
    write (fd, buffer, strlen (buffer));
    close (fd);
}

xgetc () {

    char    data;

 /* get some stuff from acu/tty line */
    if (read (fdtty, &data, 1) > 0)
	return (data & 0xFF);
    return (EOF);
}

sigint () {
 /* interrupt - close acu/tty line */
    if (debugmode) {
	fprintf (stderr, "...interrupt...\n");
    }
    close (fdtty);
    exit (0);
}

zero (p, c)
char   *p;
int     c;
{
 /* zero a string */
    while (c--)
	*p++ = 0;
}

ackmsg () {
    int     cksm,
            index;

 /* looks like this writes a UUCp format ack message */
    msgo[0] = 020;
    msgo[1] = 9;
    msgo[4] = (CTRL << 6) | (RR << 3) | rseq;
    cksm = MAGIC - msgo[4];
    msgo[2] = cksm;
    msgo[3] = cksm >> 8;
    msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];

    if (debugmode > 6) {
	printf ("T ");
	for (index = 0; index < 6; index++)
	    printf ("%03o ", msgo[index] & 0xFF);
	putchar ('\n');
    }

    write (fdtty, msgo, 6);
    rseq = (rseq + 1) & 7;
}

ctlmsg (byte)
char    byte;
{
    int     cksm,
            index;

    msgo[0] = 020;
    msgo[1] = 9;
    msgo[4] = (CTRL << 6) | byte;
    cksm = MAGIC - msgo[4];
    msgo[2] = cksm;
    msgo[3] = cksm >> 8;
    msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];

    if (debugmode > 6) {
	printf ("T ");
	for (index = 0; index < 6; index++)
	    printf ("%03o ", msgo[index] & 0xFF);
	putchar ('\n');
    }

    write (fdtty, msgo, 6);
}

lngput (s, n)
char   *s;
int     n;
{
    int     cksm,
            index;

    zero (msgo, 256);
    msgo[0] = 020;
    msgo[1] = segsiz + 1;
    msgo[4] = (LNGDAT << 6) + (wseq << 3) + rseq;
    for (index = 0; index < (segsiz + 1) * 32; index++)
	msgo[6 + index] = 0;
    for (index = 0; index < n; index++)
	msgo[6 + index] = *(s + index);
    cksm = MAGIC - (chksum (&msgo[6], (segsiz + 1) * 32) ^ (0377 & msgo[4]));
    msgo[2] = cksm;
    msgo[3] = cksm >> 8;
    msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];

    if (debugmode > 6) {
	printf ("T ");
	for (index = 0; index < (segsiz + 1) * 32 + 6; index++)
	    printf ("%03o ", msgo[index] & 0xFF);
	putchar ('\n');
    }

    do {
	write (fdtty, msgo, (segsiz + 1) * 32 + 6);
	if (inpkt ())
	    return (1);
    }
    while (tt != CTRL || xxx != RR || yyy != wseq);
    wseq = (wseq + 1) & 7;
    return (0);
}

shtput (s, n)
char   *s;
int     n;
{
    int     cksm,
            index;

    zero (msgo, 256);
    msgo[0] = 020;
    msgo[1] = segsiz + 1;
    msgo[4] = (SHTDAT << 6) + (wseq << 3) + rseq;
    for (index = 0; index < (segsiz + 1) * 32; index++)
	msgo[6 + index] = 0;
    msgo[6] = (segsiz + 1) * 32 - n;
    for (index = 0; index < n; index++)
	msgo[7 + index] = *(s + index);
    cksm = MAGIC - (chksum (&msgo[6], (segsiz + 1) * 32) ^ (0377 & msgo[4]));
    msgo[2] = cksm;
    msgo[3] = cksm >> 8;
    msgo[5] = msgo[1] ^ msgo[2] ^ msgo[3] ^ msgo[4];

    if (debugmode > 4) {
	printf ("T ");
	for (index = 0; index < (segsiz + 1) * 32 + 6; index++)
	    printf ("%03o ", msgo[index] & 0xFF);
	putchar ('\n');
    }

    do {
	write (fdtty, msgo, (segsiz + 1) * 32 + 6);
	if (inpkt ())
	    return (1);
    }
    while (tt != CTRL || xxx != RR || yyy != wseq);
    wseq = (wseq + 1) & 7;
    return (0);
}

instr (s, n)
char   *s;
int     n;
{
    int     data,
            count,
            i,
            j;

    count = 0;

    if (debugmode > 4) {
	printf ("Expecting ");
	for (i = 0; i < n; i++)
	    printf ("%03o ", *(s + i));
	printf ("\nR ");
    }

    while ((data = xgetc ()) != EOF) {
	msgi[count++] = data & 0x7F;

	if (debugmode > 4) {
	    printf ("%03o ", msgi[count - 1]);
	}

	if (count >= n) {
	    for (i = n - 1, j = count - 1; i >= 0; i--, j--)
		if (*(s + i) == '*' || *(s + i) != msgi[j])
		    break;
	    if (i < 0 || *(s + i) == '*') {

		if (debugmode > 4) {
		    putchar ('\n');
		}

		return (0);
	    }
	}
    }

    if (debugmode > 4) {
	putchar ('\n');
    }

    msgi[count] = 0;
    return (1);
}

inpkt () {
    int     data,
            count,
            need;

    count = 0;

    if (debugmode > 4) {
	printf ("R ");
    }

    while ((data = xgetc ()) != EOF) {

	if (debugmode > 4) {
	    printf ("%03o ", data & 0xFF);
	}

	switch (count) {
	    case 0: 
		if (data == 020)
		    msgi[count++] = 020;
		break;
	    case 1: 
		msgi[count++] = data;
		if (data == 9)
		    need = 4;
		else
		    need = 32 * data + 4;
		break;
	    case 4: 
		tt = (data >> 6) & 3;
		xxx = (data >> 3) & 7;
		yyy = data & 7;
	    default: 
		msgi[count++] = data;
		if (!--need) {
		    if (debugmode > 4) {
			putchar ('\n');
		    }
		    return (0);
		}
		break;
	}
    }
    if (debugmode > 4) {
	putchar ('\n');
    }
    return (1);
}

chksum (s, n)
register char  *s;
register int    n;
{
    register short  sum;
    register unsigned short t;
    register short  x;

    sum = -1;
    x = 0;
    do {
	if (sum < 0) {
	    sum <<= 1;
	    sum++;
	}
	else
	    sum <<= 1;
	t = sum;
	sum += *s++ & 0377;
	x += sum ^ n;
	if ((unsigned) sum <= t)
	    sum ^= x;
    }
    while (--n > 0);
    return (sum);
}

int
        abort () {
            write (fdtty, msgo5, sizeof (msgo5) - 1);
    if (debugmode) {
	fprintf (stderr, "%s\n", msgo5);
    }
    exit (-1);
}
-- 
{decuac}!gouldsd!mjranum || {decuac}!osiris!mjranum

"It is better to shred the bugger than to bugger the shredder."
					-ancient doltic proverb.