[net.sources] PD uu clone part 1

lamb@lids.mit.edu (04/16/87)

---------------------------------PART 1 of 2 ------------------

Some time ago I wrote a "from-scratch" uucp clone for use on our DG AOS machine
(with its brain-damaged uucp, useless to us and DG being no help).
Later I ported it to MS-DOS and VAX/VMS and its been working fine for a year
(Ive also hacked up a "rmail" for use between machines.)
Recently, with the help of John Gilmore, I was able to get the "g" protocol
realy workin (window size > 1). Previously all I could figure out was a
degenerate "g" proto using 1-window.
Im not crazy enough to say its perfect, but it does work.
Although this is a two-way (master+slave) uucico clone, compared to John's
uuslave, the coding and portibility has much to be desired. (This
project started as just an internal attempt to connect our DG to the world).
In any case for what its worth, Here it is.......
Hope everyone finds it useful.
As were not a real unix site, Id appreciate all correspondence thru
mail and not NEWS. (It took me most of last week to drum up a way to
post stuf to USENET writting a NNTP program).

                        Rick Lamb
                        Lamb@lids.mit.edu
                        or ...ihnp4!mit-eddie!lids!lamb

----------------cut here------------------------
echo dcp.c
cat >dcp.c <<'@@@ Finished dcp.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* This program implements a uucico type file transfer and remote 
execution type protocol. 
*/
#include "dcp.h"
/*<FF>*/
 int              pktsize;                /* packet size for pro */
 int              flog;                   /* system log file */
 int              fw;                     /* cfile pointer */
 int              fpr,fpw;                /* comm dev pointer */
 char			  state;					/*system state*/
 char             cfile[80];              /* work file pointer */
 int              remote;                 /* -1 means we're remote*/
 int              debug;                  /* debugging level */
 int              msgtime;                /* timout setting */
 char             fromfile[132];
 char             tofile[132];
 int              fp;                     /* current disk file ptr */
 int              size;                   /* nbytes in buff */
 int              fsys;
 char             tty[20];
 char             myname[20];
 char             username[20];
 char             spooldir[80];
 char             rmtname[20];
 char             cctime[20];
 char             device[20];
 char             type[10];
 char             speed[10];
 char             proto[5];
 char             loginseq[132];
 unsigned int     checksum();

/*<FF>*/
/* usage dcp (master/slave(D)) (debug level 0=none(D)) (system name(MYNAME))*/
/* (console device)       defaults come from "userfile"                   */
main(argc,argv)
int argc;
char *argv[];
{
int ftmp;
char line[132];

flog=creat(SYSLOG,0775);
close(flog); flog=open(SYSLOG,2);

remote=TRUE;
debug=3;        
fp = -1;
fw = -1;

ftmp=open(USERFILE,0);
getline(ftmp,line);
sscanf(line,"%s %s %s",myname,username);
getline(ftmp,line);
sscanf(line,"%s %s",tty,speed);
strcpy(spooldir,".");  /* default spooldir is current dir */
/* last line of userfile is meant to be this. modify if you wish */
close(ftmp);

if(argc > 1 && strcmp(argv[1],"master") == 0) remote=FALSE;
if(argc > 2) sscanf(argv[2],"%d",&debug);
if(argc > 3) strcpy(myname,argv[3]);
if(argc > 4) strcpy(tty,argv[4]);

if(! remote) 
{
if((fsys=open(SYSTEMS,0)) ==-1) return(FALSE);
state='I';
while(TRUE)
{
if(debug>0) printmsg("Mstate = %c",state);
switch(state)
{
case 'I': state=getsystem();    break;
case 'S': state=callup();       break;
case 'P': state=startup();      break;
case 'D': state=master();       break;
case 'Y': state=sysend();       break;
case 'G': state='I';            break;
}
if(state=='A') break;
}
close(fsys);
}
else
{
if(openline(tty,speed) == -1) return(FALSE);
state='L';
while(TRUE)
{
if(debug > 0) printmsg("Sstate = %c",state);
switch(state)
{
case 'L':state=login();     break;
case 'I':state=startup();   break;
case 'R':state=slave();     break;
case 'Y':state=sysend();    break;
}
if(state=='A') break;
}
closeline();
}

if(dcxqt()) if(debug) printmsg("ERROR in DCXQT");
	/* scan and process any recieved files */


close(flog);
}

/*<FF>*/
/*
**
**
**master
**
**
*/
master()
{
state='I';
while(TRUE)
{
if(debug>1) printmsg("Top level state (master mode) %c",state);
switch(state)
{
case 'I':state=sinit();      break;
case 'B':state=scandir();    break;
case 'S':state=send();       break;
case 'Q':state=sbreak();     break;
case 'G':state=receive();    break;
case 'C':state='Y';          break;
case 'Y':state=endp();       break;
case 'P':return('Y');
case 'A':return('A');
default:return('A');
}
}
}

/*<FF>*/
/*
**
**
**slave
**
**
*/
slave()
{
state='I';
while(TRUE)
{
if(debug>1) printmsg("Top level state (slave mode) %c",state);
switch(state)
{
case 'I':state=rinit();      break;
case 'F':state=receive();    break;
case 'C':state=schkdir();    break;
case 'T':state='B';          break;
case 'B':state=scandir();    break;
case 'S':state=send();       break;
case 'Q':state=sbreak();     break;
case 'G':return('Y');
case 'Y':state=endp();       break;
case 'P':return('Y');
case 'A':return('A');
default:return('A');
}
}
}

/*<FF>*/
/*
 *  r e c e i v e
 *
 *  This is the state table switcher for receiving files.
 */

receive()
{

state = 'F';/* Receive-Init is the start state */

while(TRUE)
{
if (debug > 2) printmsg(" receive state: %c",state);
switch(state)/* Do until done */
{
case 'F':state = rfile(); break; /* Receive-File */
case 'D':state = rdata(); break; /* Receive-Data */
case 'C':return('C');/* Complete state */
case 'A':return('Y');/* "Abort" state */
default:return('Y');
}
}
}

/*<FF>*/
/*
 *  s e n d 
 *
 *  Sendsw is the state table switcher for sending files.  It loops until
 *  either it finishes, or an error is encountered.  The routines called
 *  by sendsw are responsible for changing the state.
 *
 */
send()
{
fp = -1;                /* reset file getter/opener */
state = 'F';/* Send initiate is the start state */
while(TRUE)/* Do this as long as necessary */
{
if (debug > 2) printmsg("send state: %c",state);
switch(state)
{
case 'F':state = sfile();  break; /* Send-File */
case 'D':state = sdata();  break; /* Send-Data */
case 'Z':state = seof();  break; /* Send-End-of-File */
case 'B':return ('B'); /* Complete */
case 'A':return ('Y'); /* "Abort" */
default:return ('Y'); /* Unknown, fail */
}
}
}

/*<FF>*/
/*
 *
 *      login (for slave in PC mode)
 * Real dumb login handshake
*/
login()
{
char logmsg[132];
#ifdef PC
lretry:
msgtime=9999;
rmsg(logmsg,0); /* wait for a <CR> or <NL> */
msgtime=2*MSGTIME;
wmsg("Username:",0);
rmsg(logmsg,0);
if(debug > 0) printmsg("Username = %s",logmsg);
wmsg("Password:",0);
rmsg(logmsg,0);
if(debug > 0) printmsg("Password = %s",logmsg);
if(strcmp(logmsg,"uucp") != 0) goto lretry;
#endif
return('I');
}
@@@ Finished dcp.c
echo dcpggpkt.c
cat >dcpggpkt.c <<'@@@ Finished dcpggpkt.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* second 1-window "g" protocol */
#include "dcp.h"
#define PKTSIZE	64
#define PKTSIZ2	2
#define HDRSIZE 6
#define MAXTRY	5	/* ought to be greater than RWINDOW */
#define SWINDOW	3
#define MAXERR	5

static int      pkrec,pksent,pknerr;
/*<FF>*/
/******************SUB SUB SUB PACKET HANDLER************/
gclosepk()
{
char tmp[PKTSIZE];
gspack(1,0,0,0,tmp);
gspack(1,0,0,0,tmp);
return(0);
}

gopenpk()
{
int i,j,n1,n2,len;
char tmp[PKTSIZE];
pkrec=0; pksent=1;
pktsize=PKTSIZE;
msgtime=MSGTIME;
pknerr=0;
j=7;
gsta:
if(j == 4 ) return(0); /* if ok */
for(i=0;i<MAXTRY;i++)
{gspack(j,0,0,0,tmp); if(grpack(&n1,&n2,&len,tmp)==j) {j--; goto gsta;} }
return(-1); /* fail */
}

/*
 *
 * ggetpkt
 ***** description: Gets no more than a packet's worth of data from
****               the "packet i/o state machine". May have to
****               periodically run the pkt machine to get some
****               packets.
* on input: dont care   getpkt(data,&len)  char *data int len
* on return: data+\0 and length in len. ret(0) if alls well
* ret(-1) if problems.(fail)
 */
ggetpkt(data,len)
int *len;
char *data;
{
int npkrec,npksent,i,nlen,nakflg;
char tmp[PKTSIZE];
msgtime=2*MSGTIME;
nakflg=0;
for(i=0;i<MAXTRY;i++)
{
switch(grpack(&npkrec,&npksent,&nlen,data))
{
case DATA: if(npksent != ((pkrec+1)%8)) {
                if(debug > 0) printmsg(" unexpected pkt %d ",pkrec);
                break;
        }  
        pkrec = (pkrec+1)%8;
        *len = nlen;
        if(nakflg) 	
        	gspack(NAK,pkrec,0,0,tmp);
        else
      		gspack(ACK,pkrec,0,0,tmp);
        return(0);
case ERROR: nakflg=1;
        if(debug > 0) printmsg(" checksum error pkt %d ",pkrec);
        break;  
case CLOSE:	return(-1);
default: break; /* anything else:BADHDR,LOST,PARTIAL,UNKNOWN*/
}
}
pknerr++;
if(pknerr >= MAXERR) return(-1);
return(0);
}
/*
 *
 *  sendpkt
 *
*****   description:    Put at most a packet's worth of data  in the pkt state
*****                   machine for xmission.
*****                   May have to run the pkt machine a few times to get
*****                   an available output slot.
 *
 * on input: char *data int len,flg; len=length of data in data.
 *           flg=2 just send the packet with no wait for ack.
 *           flg>0 zero out the unused part of the buffer. (for UUCP "msg"
 *                                                                   pkts)
 *           flg=0 normal data
 * return:   ret(0) if alls well ret(-1) if problems (fail)
 *
*/
gsendpkt(data,len,msg)
int len,msg;
char data[];
{
int nlen,npkrec,npksent,i;
char tmp[PKTSIZE];
msgtime=MSGTIME;
if(msg) {len=PKTSIZE; for(i=strlen(data);i<len;i++) data[i] = '\0'; }
for(i=0;i<MAXTRY;i++)
{
gspack(DATA,pkrec,pksent,len,data); if(msg == 2) return(0);
switch(grpack(&npkrec,&npksent,&nlen,tmp))
{
case ACK: /* Ignore wrong ACK's */
		if(npkrec != pksent) {
	        if(debug > 0) printmsg(" wrong RR %d (%d) ",pksent,npkrec);
			break;
        } 
        pksent = (1+pksent)%8;
        return(0);
case NAK: if(debug > 0) printmsg(" REJ %d ",npkrec);
        if(npkrec != pksent) {
        	if(debug >0) printmsg(" wrong NAK RJ %d (%d)",pksent,npkrec);
			break;
		}
		pksent=(1+pksent)%8; 
		return(0);
case CLOSE:	return(-1);
default: break;
}
}
pknerr++;
if(pknerr >= MAXERR) return(-1);
return(0);
}

/*<FF>*/
/*************** FRAMMING *****************************/
/*
 *
 *
 *      send a packet
 * nt2=type nt3=pkrec nt4=pksent len=length<=PKTSIZE cnt1= data * ret(0) always
 */
gspack(nt2,nt3,nt4,len,cnt1)
int nt2,nt3,nt4,len;
char *cnt1;
{
unsigned int check,i;
unsigned char c2,pkt[HDRSIZE],dpkerr[10];
if(len > 64) len = 64;
if(len == 0) cnt1[0] = '\0';
/**Link testing mods***/ /*
printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
gets(dpkerr); 
if(dpkerr[0] == 's') { sscanf(&dpkerr[1],"%d",&nt4); } /**/
/** End Link testing mods ***/
if(debug > 0) {
printmsg("send packet type %d",nt2);
printmsg("  num = %d n = %d",nt3,nt4);
printmsg("  len = %d data =\n|%s|",len,cnt1);
}
c2 = '\0';
pkt[0] = '\020';
pkt[4] = nt2<<3;
nt2 &= 7;
switch(nt2)
{
case 1:      break;                  /* stop protocol */
case 2:      pkt[4] += nt3; break;   /* reject        */
case 3:      break;
case 4:      pkt[4] += nt3; break;   /* ack          */
case 5:      pkt[4] += SWINDOW;   break;   /* 3 windows */
case 6:      pkt[4] += 1;   break;   /* pktsiz = 64 (1) */
case 7:      pkt[4] += SWINDOW;   break;   /* 3 windows */
case 0:      pkt[4] += 0x80 + nt3 + (nt4<<3);
                c2 = (PKTSIZE - len)&0xff;
                if(c2)
                {
                        pkt[4] += 0x40;   /* if len < PKTSIZE */
                        for(i=PKTSIZE-1;i>0;i--) cnt1[i]=cnt1[i-1];
                        cnt1[0]=c2;
                }
                break;
}
pkt[4] &= 0xff;
if(nt2 != DATA) {
        pkt[1] = 9;             /* control packet size = 0 (9) */
		check=pkt[4];
} else {
        pkt[1] = PKTSIZ2;             /* data packet size = 64 (2) */
        check = checksum(cnt1,PKTSIZE);
		i = pkt[4];/* got to do this on PC for ex-or high bits */
		i &= 0xff;
		check = (check ^ i) & 0xffff;
}
check = (0xaaaa - check) & 0xffff;
pkt[2] = check & 0xff;
pkt[3] = (check>>8) & 0xff;
pkt[5] = (pkt[1]^pkt[2]^pkt[3]^pkt[4])&0xff;
/***More Link testing MODS ******/ /*
switch(dpkerr[0]) {
case 'e':   cnt1[10] = -cnt1[10];
			break;
case 'h':	pkt[5] = -pkt[5];
			break;
case 'l':	return;
case 'p':	swrite(pkt,HDRSIZE); 
			if(pkt[1] != 9) swrite(cnt1,PKTSIZE-3);
			return;
default:	break;
}  /**/
/******End Link Testing Mods **********/
swrite(pkt,HDRSIZE);       /* header is 6-bytes long */
if(len==0 && nt2==0) write(flog,pkt,HDRSIZE);   
if(pkt[1] != 9) { 
	swrite(cnt1,PKTSIZE);     /* data is always 64 bytes long */ 
if(len==0 && nt2==0)	write(flog,cnt1,PKTSIZE); 
}
}

/*<FF>*/
/*
 *
 *      read packet
 * on return: nt3=pkrec nt4=pksent len=length <=PKTSIZE  cnt1=data *
ret(type) ok; ret(-1) input buf empty; ret(-2) bad header;
 *              ret(-3) lost pkt timeout; ret(-4) checksum error;ret(-5) ?
 */
grpack(nt3,nt4,len,cnt1)
int *nt3,*nt4,*len;
char *cnt1;
{
unsigned int nt1,check,checkchk,i;
unsigned char c,c2,pkt[HDRSIZE];
int ii;
c = '\0';
while((c & 0x7f) != '\020') if(sread(&c,1,msgtime) < 1) return(-1);
if(sread(&pkt[1],HDRSIZE-1,msgtime) < (HDRSIZE-1)) return(-1);
/*write(flog,&c,1); write(flog,&pkt[1],HDRSIZE-1); */
/* header is 6-bytes long */
i = pkt[1]^pkt[2]^pkt[3]^pkt[4]^pkt[5];
i &= 0xff;
if(i) {                        /*  bad header */
        if(debug) printmsg("****bad header****");
        return(-2);
}
if((pkt[1] &=0x7f) == 9) {       /* control packet */
        *len = 0;
        c = pkt[4] & 0xff;
        nt1  = c>>3;
        *nt3 = c & 7;
        *nt4 = 0;
        check = 0;
        checkchk = 0;
        cnt1[*len] = '\0';
} else {       /* data packet */
        if(pkt[1] != PKTSIZ2) return(-5);   /* cant handle other than 64*/
        nt1  = 0;
        c2 = pkt[4] & 0xff;
        c = c2&0x3f;
        *nt4 = c>>3;
        *nt3 = c & 7;
        if(sread(cnt1,PKTSIZE,msgtime) < PKTSIZE) return(-3);
/*        write(flog,cnt1,PKTSIZE);     */
        /* 64 byte packets even if partial */
		i = pkt[3];
		i = (i<<8)&0xff00;
		check = pkt[2];
		check = i|(check&0xff);
        checkchk = checksum(cnt1,PKTSIZE);
		i = pkt[4]|0x80;
		i &= 0xff;
        checkchk = 0xaaaa - (checkchk^i);
        checkchk &= 0xffff;
        if(checkchk != check) {
                if(debug) printmsg("***checksum error***");
                return(ERROR);
        }
        *len = PKTSIZE;
        if(c2&0x40) {
                ii = (cnt1[0]&0xff);
                *len = (*len-ii)&0xff;
                for(ii=0;ii<*len;ii++) cnt1[ii] = cnt1[ii+1];
        }
        cnt1[*len] = '\0';
}
if(debug > 0) {
        printmsg("receive packet type %d ",nt1);
        printmsg("  num = %d n = %d",*nt3,*nt4);
        printmsg("  checksum rec = %x comp = %x",check,checkchk);
        printmsg("  len = %d data =\n|%s|",*len,cnt1);
}
ii = nt1;
return(ii);
}

unsigned checksum(data,len)
int len;
char data[];
{
unsigned int i,j,tmp,chk1,chk2;
chk1 = 0xffff;
chk2 = 0;
j = len;
for(i=0;i<len;i++)
{
        if(chk1&0x8000) { chk1 <<= 1; chk1++; }
        else { chk1 <<= 1; }
        tmp = chk1;
        chk1 += (data[i]&0xff);
        chk2 += chk1^j;
        if((chk1&0xffff) <= (tmp&0xffff)) chk1 ^= chk2;
        j--;
}
return(chk1&0xffff);
}
@@@ Finished dcpggpkt.c
echo dcpgpkt.c
cat >dcpgpkt.c <<'@@@ Finished dcpgpkt.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* 3-window "g" ptotocol */
/* Thanks got to John Gilmore for sending me a copy of Greg Chesson's 
UUCP protocol description-- Obviously invaluable
Thanks also go to Andrew Tannenbaum for the section on Siding window
protocols with a program example in his "Computer Networks" book 
*/
#include "dcp.h"
#define PKTSIZE         64
#define PKTSIZ2         2
#define HDRSIZE         6
#define MAXTRY          4

#define MAXERR  200		/* Dont want to quit in a middle of a long file*/
#define TIMEOUT 4		/* could be longer */
#define KPKT    1024/PKTSIZE
#define OK      -1

#define SWINDOW 3	/* fixed now, U make it variable */
#define RWINDOW 3
#define NBUF    8   /* always SAME as MAXSEQ ? */
#define MAXSEQ  8

#define between(a,b,c) ((a<=b && b<c) || (c<a && a<=b) || (b<c && c<a))

/* packet defin */
static int rwl,swl,swu,rwu,nerr,nbuffers,npkt,irec,timeout,GOT_SYNC,GOT_HDR;
static int fseq[NBUF],outlen[NBUF],inlen[NBUF],arr[NBUF];
static char outbuf[NBUF][PKTSIZE+1],inbuf[NBUF][PKTSIZE+1];
static unsigned char grpkt[HDRSIZE+1];
static long ftimer[NBUF],acktmr,naktmr;
/*<FF>*/
/******************SUB SUB SUB PACKET HANDLER************/
gopenpk()
{
int i,j,n1,n2,len;
char tmp[PKTSIZE+1];
pktsize=PKTSIZE; /* change it later after the init */
msgtime=MSGTIME; /* not sure I need this for "g" proto */
/* initialize proto parameters */
swl=nerr=nbuffers=npkt=0;
swl=swu=1;
rwl=0;
rwu=RWINDOW-1;
for(i=0;i<NBUF;i++) {ftimer[i]=0; arr[i]=FALSE; }
GOT_SYNC=GOT_HDR=FALSE;
/* 3-way handshake */
timeout=1; /* want some timeout capability here */
gspack(7,0,0,0,tmp);
rsrt:
if(nerr >=MAXERR) return(-1);
/* INIT sequence. Easy fix for variable pktsize and windows. */
/* I didnt since all the machines I talk to use W=3 PKTSZ=64 */
/* If you do this make sure to reflect the changes in "grpack" */
/* and "gspack" */
switch(grpack(&n1,&n2,&len,tmp)) {
case 7:	gspack(6,0,0,0,tmp);
		goto rsrt;
case 6: gspack(5,0,0,0,tmp);
		goto rsrt;
case 5: break;
default: nerr++; gspack(7,0,0,0,tmp);
		goto rsrt;
}
nerr=0;
return(0);      /* channel open */
}

gclosepk()
{
int i;
char tmp[PKTSIZE+1];
timeout=1;
for(i=0;i<MAXTRY;i++) {
        gspack(CLOSE,0,0,0,tmp);
        if(gmachine() == CLOSE) break;
}
if(debug) printmsg("number of errors %d and pkts xfered %d",nerr,npkt);
return(0);
}

/*
 *
 * ggetpkt
 ***** description: Gets no more than a packet's worth of data from
****               the "packet i/o state machine". May have to
****               periodically run the pkt machine to get some
****               packets.
* on input: dont care   getpkt(data,&len)  char *data int len
* on return: data+\0 and length in len. ret(0) if alls well
* ret(-1) if problems.(fail)
 */
ggetpkt(cdata,len)
int *len;
char cdata[];
{
int i2;
irec=1;
timeout=0;
/* WAIT FOR THE DESIRED PACKET */
while((arr[rwl]) == FALSE) if(gmachine()!=OK) return(-1);
/* GOT A PKT ! */
i2 = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
*len = inlen[i2];
strncpy(cdata,inbuf[i2],*len);
arr[i2]=FALSE;
rwu = (1+rwu)%MAXSEQ; /* bump rec window */
npkt++;
return(0);
}

/*
 *
 *  sendpkt
 *
*****   description:    Put at most a packet's worth of data  in the pkt state
 ****                   machine for xmission.
*****                   May have to run the pkt machine a few times to get
*****                   an available output slot.
 *
 * on input: char *data int len,flg; len=length of data in data.
 *           flg=2 just send the packet with no wait for ack.
 *           flg>0 zero out the unused part of the buffer. (for UUCP "msg"
 *                                                                   pkts)
 *           flg=0 normal data
 * return:   ret(0) if alls well ret(-1) if problems (fail)
 *
*/
gsendpkt(cdata,len,flg)
int len,flg;
char *cdata;
{
int i,i1;
long ttmp;
irec=0;
timeout=0; /* non-blocking reads */
/* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been */
/* acked, wait for acks */
while(nbuffers >= SWINDOW) if(gmachine()!= OK) return(-1);
i1 = swu;  /* <--If we ever have more than 8 seq no.s, must mod() here*/
/* PLACE PACKET IN TABLE AND MARK UNACKED */
/* fill with zeros or not */
if(flg) {
        strcpy(outbuf[i1],cdata);
        len=PKTSIZE;
        for(i=strlen(cdata);i<len;i++) outbuf[i1][i]='\0';
} else {
        strncpy(outbuf[i1],cdata,len);
        outbuf[i1][len]='\0';
}
/* mark packet  */
outlen[i1] = len;
ftimer[i1] = time(&ttmp);
fseq[i1]=swu;
swu = (1+swu)%MAXSEQ;	/* bump send window */
nbuffers++;
npkt++;
/* send it */
gspack(DATA,rwl,fseq[i1],outlen[i1],outbuf[i1]); 
/* send it once then let the pkt machine take it. wouldnt need this for */
/* mtasking systems */
gmachine();
return(0);
}

/************     packet machine   ****** RH Lamb 3/87 */
/* Idealy we would like to fork this process off in an infinite loop */
/* and send and rec pkts thru "inbuf" and "outbuf". Cant do this in MS-DOS*/
/* so we setup "getpkt" and "sendpkt" to call this routine often and return */
/* only when the input buffer is empty thus "blocking" the pkt-machine task. */
gmachine()
{
int rack,rseq,rlen,i1,i2,dflg;
char rdata[PKTSIZE+1];
long ttmp,itmp;
reply:
if(debug>2) printmsg("*send %d<W<%d, rec %d<W<%d, err %d",swl,swu,rwl,rwu,nerr);
/* waiting for ACKs for swl to swu-1. Next pkt to send=swu */
/* rwl=expected pkt */
if(debug>3) printmsg("Kbytes transfered %d errors %d\r",npkt/KPKT,nerr);
if(nerr >= MAXERR) goto close;
dflg=0;
switch(grpack(&rack,&rseq,&rlen,rdata))
{
case CLOSE:     if(debug>2) printmsg("**got CLOSE");
                goto close;
case NAK:       nerr++; 
				acktmr=naktmr=0; /* stop ack/nak timer */
                if(debug>2) printmsg("**got NAK %d",rack);
nloop:          if(between(swl,rack,swu)) { /* resend rack->(swu-1) */
                        i1 = rack;
                        gspack(DATA,rwl,rack,outlen[i1],outbuf[i1]);
            			if(debug>2) printmsg("***resent %d",rack);
                        ftimer[i1]=time(&ttmp);
                        rack=(1+rack)%MAXSEQ;
                        goto nloop;
                }
				if(dflg) return(OK);
                goto reply; /* any other stuff ? */
case EMPTY:     if(debug>2) printmsg("**got EMPTY");
                itmp = time(&ttmp);
				if(acktmr) if((itmp-acktmr) >= TIMEOUT) { /* ack timed out*/
					gspack(ACK,rwl,0,0,rdata);
					acktmr=itmp;
				}
				if(naktmr) if((itmp-naktmr) >= TIMEOUT) { /*nak timed out*/
					gspack(NAK,rwl,0,0,rdata);
					naktmr=itmp;
				}
				/* resend any timed out un-acked pkts */
                for(i2=swl;between(swl,i2,swu);i2=(1+i2)%MAXSEQ)  {
					acktmr=naktmr=0; /* reset ack/nak */
					i1=i2;
					if(debug > 2)
						printmsg("--->seq,elapst %d %ld",i2,(itmp-ftimer[i1]));
                    if((itmp-ftimer[i1]) >= TIMEOUT) {
						if(debug>2) printmsg("***timeout %d",i2);
						/* since "g" is "go-back-N", when we time out we */
						/* must send the last N pkts in order. The generalized*/
						/* sliding window scheme relaxes this reqirment */
                        nerr++;
						dflg=1;  /* same hack */
                        rack=i2;
						goto nloop;
                     }
                }
                return(OK);
case ACK:       if(debug>2) printmsg("**got ACK %d",rack);
				acktmr=naktmr=0; /* disable ack/nak's */
aloop:          if(between(swl,rack,swu)) {   /* S<-- -->(S+W-1)%8 */
						if(debug>2) printmsg("***ACK %d",swl);
						ftimer[swl]=0;
                        nbuffers--;
                        swl = (1+swl)%MAXSEQ;
						goto aloop;
                } 
				if(dflg) return(OK); /* hack for non-mtask sys's */
									 /* to empty "inbuf[]" */
                goto reply;
case DATA:      if(debug>2) printmsg("**got DATA %d %d",rack,rseq);
                i1=(1+rwl)%MAXSEQ; /* (R+1)%8 <-- -->(R+W)%8 */
                i2=(1+rwu)%MAXSEQ;
                if(between(i1,rseq,i2)) {
                        if(i1 == rseq) {
                                i1 = rseq;
                                arr[i1] = TRUE;
                                inlen[i1] = rlen;
                                strncpy(inbuf[i1],rdata,rlen);
                                rwl=(rwl+1)%MAXSEQ;
								if(debug>2) printmsg("***ACK d %d",rwl);
                                gspack(ACK,rwl,0,0,rdata);
								acktmr=time(&ttmp); /* enable ack/nak tmout*/
								dflg=1; /*return to call when finished*/
								/* in a mtask system, unneccesary */
                        }
                        else {nerr++; if(debug>2) printmsg("***unexpect %d ne %d",rseq,rwl);}
                } else {nerr++; if(debug>2) printmsg("***wrong seq %d",rseq);}
                goto aloop;
case ERROR:     nerr++;
                if(debug>2) printmsg("**got BAD CHK");
                gspack(NAK,rwl,0,0,rdata);
				naktmr=time(&ttmp); /* set nak timer */
				if(debug>2) printmsg("***NAK d %d",rwl);
                goto reply;
default:        if(debug>2) printmsg("**got SCREW UP");
                goto reply; /* ignore it */
}
close:          gspack(CLOSE,0,0,0,rdata);
                return(CLOSE);
}

/*<FF>*/
/*************** FRAMMING *****************************/
/*
 *
 *
 *      send a packet
 * nt2=type nt3=pkrec nt4=pksent len=length<=PKTSIZE cnt1= data * ret(0) always
 */
gspack(nt2,nt3,nt4,len,cnt1)
int nt2,nt3,nt4,len;
char cnt1[];
{
unsigned int check,i;
unsigned char c2,pkt[HDRSIZE+1],dpkerr[10];
if(len > 64) len = 64;
if(len == 0) cnt1[0] = '\0';
/**Link testing mods- create artificial errors ***/ /*
printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
gets(dpkerr); 
if(dpkerr[0] == 's') { sscanf(&dpkerr[1],"%d",&nt4); } /**/
/** End Link testing mods ***/
if(debug > 2) 
	printmsg("send packet type %d, num=%d, n=%d, len=%d",nt2,nt3,nt4,len);
if(debug > 3)
	printmsg("data =\n|%s|",cnt1);
c2 = '\0';
pkt[0] = '\020';
pkt[4] = nt2<<3;
nt2 &= 7;
switch(nt2) {
case 1:      break;                  /* stop protocol */
case 2:      pkt[4] += nt3; break;   /* reject        */
case 3:      break;
case 4:      pkt[4] += nt3; break;   /* ack          */
case 5:      pkt[4] += SWINDOW;   break;   /* 3 windows */
case 6:      pkt[4] += 1;   break;   /* pktsiz = 64 (1) */
case 7:      pkt[4] += SWINDOW;   break;   /* 3 windows */
case 0:      pkt[4] += 0x80 + nt3 + (nt4<<3);
                c2 = (PKTSIZE - len)&0xff; 
                /* havnt set it up for VERY LONG pkts with a few */
                /* bytes yet (-128) */
                if(c2) { /* short packet handling */
                        pkt[4] += 0x40;   /* if len < PKTSIZE */
                        for(i=PKTSIZE-1;i>0;i--) cnt1[i]=cnt1[i-1];
                        cnt1[0]=c2;
                }
                break;
}
pkt[4] &= 0xff;
if(nt2) {
        pkt[1] = 9;             /* control packet size = 0 (9) */
        check = (0xaaaa - pkt[4])&0xffff;
} else {
        pkt[1] = PKTSIZ2;             /* data packet size = 64 (2) */
        check = checksum(cnt1,PKTSIZE);
		i = pkt[4];/* got to do this on PC for ex-or high bits */
		i &= 0xff;
		check = (check ^ i) & 0xffff;
        check = (0xaaaa - check) & 0xffff;
}
pkt[2] = check & 0xff;
pkt[3] = (check>>8) & 0xff;
pkt[5] = (pkt[1]^pkt[2]^pkt[3]^pkt[4])&0xff;
/***More Link testing MODS ******/ /*
switch(dpkerr[0]) {
case 'e':   cnt1[10] = -cnt1[10];
			break;
case 'h':	pkt[5] = -pkt[5];
			break;
case 'l':	return;
case 'p':	swrite(pkt,HDRSIZE); 
			if(pkt[1] != 9) swrite(cnt1,PKTSIZE-3);
			return;
default:	break;
}  /**/
/******End Link Testing Mods **********/
swrite(pkt,HDRSIZE);       /* header is 6-bytes long */
/*      write(flog,pkt,HDRSIZE);   */
if(pkt[1] != 9) { swrite(cnt1,PKTSIZE);     /* data is always 64
bytes long */       /*    write(flog,cnt1,PKTSIZE);   */
}
}
/*<FF>*/
/*
 *
 *      read packet
 * on return: nt3=pkrec nt4=pksent len=length <=PKTSIZE  cnt1=data *
 * ret(type) ok; ret(EMPTY) input buf empty; ret(ERROR) bad header;
 *          ret(EMPTY) lost pkt timeout; ret(ERROR) checksum error;ret(-5) ?
****NOTE :
***sread(buf,n,timeout)
	while(TRUE) {
		if(# of chars available >= n) (without dec internal counter)
			read n chars into buf (decrenent internal char counter)
			break
		else
			if(time>timeout) break
	}
	return(# of chars available)
****END NOTE
 */
grpack(nt3,nt4,len,cnt1)
int *nt3,*nt4,*len;
char cnt1[];
{
unsigned int nt1,check,checkchk,i;
unsigned char c,c2;
int ii;
if(GOT_SYNC) goto get_hdr; 
if(GOT_HDR) goto get_data;
c = '\0';
while((c & 0x7f) != '\020') 
	if(sread(&c,1,timeout) == 0) 
		return(EMPTY);
GOT_SYNC=TRUE;
get_hdr:
if(sread(&grpkt[1],HDRSIZE-1,timeout)< (HDRSIZE-1)) return(EMPTY);
GOT_SYNC=FALSE;
i = grpkt[1]^grpkt[2]^grpkt[3]^grpkt[4]^grpkt[5];
i &= 0xff;
if(i) {               /*  bad header */
	if(debug)  printmsg("****bad header****");
    return(ERROR); /* Im not sure whether "g" considers it an empty or error */
}
GOT_HDR=TRUE;
if((grpkt[1] &=0x7f) == 9) {       /* control packet */
        *len = 0;
        c = grpkt[4] & 0xff;
        nt1  = c>>3;
        *nt3 = c & 7;
        *nt4 = 0;
        check = 0;
        checkchk = 0;
        cnt1[*len] = '\0';
		GOT_HDR=FALSE;
} else {       /* data packet */
        if(grpkt[1] != PKTSIZ2) return(-5);   /* cant handle other than 64*/
get_data:
		if(sread(cnt1,PKTSIZE,timeout) < PKTSIZE) return(EMPTY);
		GOT_HDR=FALSE;
        nt1  = 0;
        c2 = grpkt[4] & 0xff;
        c = c2&0x3f;
        *nt4 = c>>3;
        *nt3 = c & 7;
		i = grpkt[3];
		i = (i<<8)&0xff00;
		check = grpkt[2];
		check = i|(check&0xff);
        checkchk = checksum(cnt1,PKTSIZE);
		i = grpkt[4]|0x80;
		i &= 0xff;
        checkchk = 0xaaaa - (checkchk^i);
        checkchk &= 0xffff;
        if(checkchk != check) {
                if(debug>0) printmsg("***checksum error***");
                return(ERROR);
        }
        *len = PKTSIZE;
		/* havnt set it up for very long pkts yet (>128) RH Lamb */
        if(c2&0x40) {
                ii = (cnt1[0]&0xff);
                *len = (*len-ii)&0xff;
                for(ii=0;ii<*len;ii++) cnt1[ii] = cnt1[ii+1];
        }
        cnt1[*len] = '\0';
}
if(debug > 2) 
	printmsg("rec  packet type %d, num=%d, n=%d, len=%d",nt1,*nt3,*nt4,*len);
if(debug > 3)
    printmsg("  checksum rec = %x comp = %x, data=\n|%s|",check,checkchk,cnt1);
        ii = nt1;
        return(ii);
}

unsigned checksum(data,len)
int len;
char data[];
{
unsigned int i,j,tmp,chk1,chk2;
chk1 = 0xffff;
chk2 = 0;
j = len;
for(i=0;i<len;i++)
{
        if(chk1&0x8000) { chk1 <<= 1; chk1++; }
        else { chk1 <<= 1; }
        tmp = chk1;
        chk1 += (data[i]&0xff);
        chk2 += chk1^j;
        if((chk1&0xffff) <= (tmp&0xffff)) chk1 ^= chk2;
        j--;
}
return(chk1&0xffff);
}
@@@ Finished dcpgpkt.c
echo dcpio.c
cat >dcpio.c <<'@@@ Finished dcpio.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* DG and PC IO routines */
#include "dcp.h"
/*<FF>*/
/*************** BASIC I/O ***************************/
#ifdef  PC	/* Saltzers serial pkg */
/* Some notes: When pkts are flying in both directions, there seems to */
/* be some interupt handling problems as far as recieving. checksum errs*/
/* may therfore occur often even though we recover from them. This is */
/* especially true with sliding windows. Errors are very few in the VMS */
/* version. RH Lamb*/
#include "comm.h"
#define STOPBIT 1
#endif
#ifdef DG 	/* I/O routines should be re-written with sys calls */
#include <setjmp.h>
#include <signal.h>
jmp_buf env;
int     clkint();

clkint()
{longjmp(env,1);}

#include <termio.h>
#include <sys/ioctl.h>
setline(stty)
int stty;
{
int ret;
struct sgttyb ttybuf;
ret=ioctl(stty,TIOCGETP,&ttybuf);
ttybuf.sg_flags=RAW;  /* <-- faster RH Lamb */
ret=ioctl(stty,TIOCSETP,&ttybuf);/*
struct termio termbuf;
ret=ioctl(tty,TCGETA,&termbuf); printf("ret: %d ",ret);
termbuf.c_line = BELL_LD;
termbuf.c_iflag = 0;
termbuf.c_oflag = 0;
termbuf.c_lflag = 0;
ret=ioctl(tty,TCSETA,&termbuf); printf("%d\n",ret);
*/
}

receive_com()
{
int count,ret;
unsigned char c;
ret=ioctl(fpr,FIONREAD,&count);
printf("count: %d ret: %d\n",count,ret);
if(count < 1) return(-1);
read(fpr,&c,1); printf("char: %c\n",c);
return(c);
}
#endif DG

#ifdef VMS
#include <iodef.h>
#include <ttdef.h>
#include <tt2def.h>
#include <dcdef.h>
#include <ssdef.h>
#include <dvidef.h>
#include <descrip.h>
struct tt_mode {
       char class,type;
       short width;
       int basic : 24;
       char length;
       long extended;
};
struct iosb_struct {
       short status,size,terminator,termsize;
};
static struct tt_mode ttold,ttraw;
static struct iosb_struct ttiosb;
#endif VMS

swrite(data,num)
int num;
char *data;
{
int i;
#ifdef  PC
for(i=0;i<num;i++) {send_com(data[i]); }
#endif
#ifdef DG
write(fpw,data,num); i=num;
#endif
#ifdef VMS
sys$qiow(0,fpw,IO$_WRITEVBLK,0,0,0,data,num,0,0,0,0);
i=num;
#endif
return(i);
}

/* This should realy be the same as "sread" below but dont have time */
/* to look for subtlties. Workin on it though. DG,VAX using sys calls */
#ifdef DG
sread(buf,num,timeout)
int num,timeout;
unsigned char *buf;
{
int i,ii,jtime,jd; long tmp;
if(setjmp(env)) {if(debug) printmsg("ret i = %d\n",i); return(i);}
signal(SIGALRM,clkint); 
alarm(timeout+1);
for(i=0;i<num;i++) { read(fpr,&buf[i],1); }
alarm(0);
return(i);
}
#endif DG
/* non-blocking read essential to "g" protocol */
/* see "dcpgpkt.c" for description */
/* This all changes in a mtask systems. Requests for */
/* I/O should get qued and an event flag given. Then the */
/* requesting process (e.g.gmachine()) waits for the event */
/* flag to fire processing either a read or a write. */
/* Could be implemented on VAX/VMS or DG but not MS-DOS */
#ifdef PC
sread(buf,num,timeout)
char *buf;
int num,timeout;
{
long tmp,jtime;
int i,jj,jd;
jtime=time(&tmp);
while(-1) {
	jj=r_count_pending();
	if(debug > 2) printmsg("------->rcount=%d num=%d",jj,num);
	if(jj >= num ) {
		for(i=0;i<num;i++) buf[i]=receive_com();
		return(jj); }
	else {
		jd=time(&tmp)-jtime;
		if(jd>=timeout) return(jj); }
}
}
#endif PC
#ifdef VMS
sread(buf,num,timeout)
char *buf;
int num,timeout;
{
long tmp,jtime,trmmsk[2];
int i,jj,jd;
struct {
       short count;
       char c;
       char res1;
       long res2;	
       } hdcnt;
jtime=time(&tmp);
trmmsk[0]=0;
trmmsk[1]=0;
while(-1) {
	sys$qiow(0,fpr,(IO$_SENSEMODE|IO$M_TYPEAHDCNT),0,0,0,&hdcnt,sizeof(hdcnt),0,0,0,0);
	jj=hdcnt.count; 
       	if(debug > 3) printmsg("----v--->rcount=%d, num=%d",jj,num);
	if(jj >= num) {
		sys$qiow(0,fpr,IO$_READVBLK,&ttiosb,0,0,buf,num,0,trmmsk,0,0);
       		/*printf("%c",buf[0]);*/
       		return(jj); }
	else {
		jd=time(&tmp)-jtime;
		if(jd>=timeout) return(jj); }
}
}
#endif VMS


openline(name,baud)
char *name,*baud;
{
#ifdef DG
fpr=open(name,0); fpw=open(name,1); setline(fpw); setline(fpr);
if(fpr < 0) return(-1); if(fpw < 0) return(-1);
#endif
#ifdef PC
int i;
sscanf(name,"COM%d",&i); select_port(i); save_com(); install_com();
sscanf(baud,"%d",&i); open_com(i,'D','N',STOPBIT,'D');
dtr_on();
#endif
#ifdef VMS
int ii,spd,spds[] = {110,150,300,600,1200,1800,2400,4800,9600,19200,0};
static int spcodes[] = {TT$C_BAUD_110,TT$C_BAUD_150,TT$C_BAUD_300,TT$C_BAUD_600,TT$C_BAUD_1200,TT$C_BAUD_2400,TT$C_BAUD_4800,TT$C_
AUD_9600,TT$C_BAUD_19200,0};
$DESCRIPTOR(tmp,name);
tmp.dsc$w_length = strlen(name);
if((ii=sys$alloc(&tmp,0,0,0)) != 1) {
       if(debug > 3) printmsg("Alloc %d",ii);
       if(!remote) return(-1);
}
if((ii=sys$assign(&tmp,&fpr,0,0)) != 1) {
       if(debug > 3) printmsg("Assign %d",ii);
       return(-1);
}
fpw=fpr;
ii=sys$qiow(0,fpr,IO$_SENSEMODE,0,0,0,&ttold,sizeof(ttold),0,0,0,0);
if(debug && !remote) lib$signal(ii);
ttraw=ttold;
#ifdef TT2$M_PASTHRU
ttraw.extended |= TT2$M_PASTHRU;
#endif
#ifdef TT2$M_ALTYPEAHD;
ttraw.extended |= TT2$M_ALTYPEAHD;
#endif
ttraw.basic |= TT$M_PASSALL;
ttraw.basic |= TT$M_NOECHO|TT$M_EIGHTBIT;
ttraw.basic &= ~TT$M_WRAP & ~TT$M_HOSTSYNC & ~TT$M_TTSYNC;
sscanf(baud,"%d",&ii); 
for(spd=0; spds[spd] != 0 && spds[spd] != ii; spd++) ;
/*if(spds[spd]==0) err or default ?*/
if(debug) printmsg("speed code %d %d\n",spds[spd],spd);
ii=sys$qiow(0,fpr,IO$_SETMODE,0,0,0,&ttraw,sizeof(ttraw),spcodes[spd],0,0,0);
if(debug && !remote) lib$signal(ii);
#endif
return(0);
}

closeline()
{
#ifdef DG
close(fpr); close(fpw);
#endif
#ifdef PC
dtr_off();
close_com(); restore_com();
#endif
#ifdef VMS
int ii;
swrite("+++\r",4); /*helps at times */
ii=sys$qiow(0,fpr,(IO$_SETMODE|IO$M_HANGUP),0,0,0,0,0,0,0,0,0);
if(debug && !remote) lib$signal(ii);
sys$dassgn(fpr);
sys$dalloc(0,0);
#endif
}
@@@ Finished dcpio.c
echo dcpkpkt.c
cat >dcpkpkt.c <<'@@@ Finished dcpkpkt.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* Not quite the kermit proto but it works ok */
#include "dcp.h"

#define PKTSIZE 120
#define MAXSEQ  8
#define MAXERR  20
#define PKTKB   (1024/PKTSIZE)
static int nerrs,npkts,pktrec,pktsent;
kgetpkt(rdata,len)
int *len;
unsigned char *rdata;
{
int i,timeout=20;
unsigned char c,buf[5];
stpkt: if(nerrs >= MAXERR) return(-1);
c='a';
/*printmsg("kkget* 1"); */
while((c&0x7f) != '\001') if(sread(&c,1,timeout) < 1) return(-1);
/*printmsg("kkget** 2"); */
if(sread(buf,3,timeout) < 3) return(-1);
/*printmsg("kkget*** 3");       */
if(sread(rdata,PKTSIZE,timeout) < PKTSIZE) return(-1);
/*printmsg("kkget**** 4\n%s",rdata);     */
*len=buf[0]; 
if(debug > 2) {
printmsg("kget: len %d seq %d chk %d data",*len,buf[1],buf[2]);
printmsg("|%s|",rdata);
}
for(i=0;i<PKTSIZE;i++) {buf[2] ^= rdata[i]; /*printf("%x",rdata[i]);*/}
if(buf[2]) { nerrs++; swrite("\006",1); printmsg("ERR"); goto stpkt;}
swrite("\004",1);
if(buf[1] != pktrec) {nerrs++; printmsg("SEQ"); goto stpkt;}
/*printmsg("kkget***** 5");     */
pktrec=(pktrec+1)%MAXSEQ;
return(0);
}


ksendpkt(xdata,len,flg)
int len,flg;
unsigned char *xdata;
{
int i,timeout=4;
unsigned char c,kbuf[5];
if(flg) {len=PKTSIZE; for(i=strlen(xdata);i<len;i++) xdata[i]='\0';}
kbuf[0] = '\001'; kbuf[1]=len&0xff; kbuf[2]=pktsent&0xff;
kbuf[3]=0;
for(i=0;i<PKTSIZE;i++) {kbuf[3] ^= xdata[i]; /*printf("%x",xdata[i]);*/ }
sndpkt: if(nerrs >= MAXERR) return(-1);
/*printmsg("kksend****: 1\n%s",xdata); */
swrite(kbuf,4); swrite(xdata,PKTSIZE);
/*printmsg("kksend*****: 2\n%s",xdata);  */
if(debug>2) {
printmsg("ksend: len %d seq %d chk %d data",len,pktsent,kbuf[3]);
printmsg("|%s|",xdata);
}
/*printmsg("kksend******: 3");  */
if(flg==2) return(0); /* quit if flg=2 */
if(sread(&c,1,timeout) < 1) {nerrs++; printmsg("TIM"); goto sndpkt; }
if((c&0x7f) != '\004') {nerrs++; printmsg("NAK"); goto sndpkt; }
if(debug>2) printmsg("KB's xfered: %d errors %d",npkts/PKTKB,nerrs);
/*printmsg("kksend*******: 4"); */
pktsent=(pktsent+1)%MAXSEQ; npkts++;
return(0);
}

kopenpk()
{
msgtime=MSGTIME;
pktsize=PKTSIZE;
npkts=0;
nerrs=0;
pktrec=0;
pktsent=0;
return(0);
}
kclosepk()
{
return(0);
}


@@@ Finished dcpkpkt.c
echo dcppkt.c
cat >dcppkt.c <<'@@@ Finished dcppkt.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* original 1-window "g" protocol */
#include "dcp.h"
#define PKTSIZE         64
#define PKTSIZ2         2
#define HDRSIZE         6
#define MAXTRY			10

static int      pkrec,pksent;
/*<FF>*/
/******************SUB SUB SUB PACKET HANDLER************/
gclosepk()
{
char tmp[PKTSIZE];
gspack(1,0,0,0,tmp);
gspack(1,0,0,0,tmp);
return(0);
}

gopenpk()
{
int i,j,n1,n2,len;
char tmp[PKTSIZE];
pkrec=0; pksent=1;
pktsize=PKTSIZE;
msgtime=MSGTIME;
j=7;
gsta:
if(j == 4 ) return(0); /* if ok */
for(i=0;i<MAXTRY;i++)
{gspack(j,0,0,0,tmp); if(grpack(&n1,&n2,&len,tmp)==j) {j--; goto gsta;} }
return(-1); /* fail */
}

/*
 *
 * ggetpkt
 ***** description: Gets no more than a packet's worth of data from
****               the "packet i/o state machine". May have to
****               periodically run the pkt machine to get some
****               packets.
* on input: dont care   getpkt(data,&len)  char *data int len
* on return: data+\0 and length in len. ret(0) if alls well
* ret(-1) if problems.(fail)
 */
ggetpkt(data,len)
int *len;
char data[];
{
int npkrec,npksent,i,nlen;
char tmp[PKTSIZE];
for(i=0;i<MAXTRY;i++)
{
switch(grpack(&npkrec,&npksent,&nlen,data))
{
case 0: /*if(npksent != ((pkrec+1)%8)) {
                gspack(2,pkrec,0,0,tmp);
                if(debug > 0) printmsg(" send REJ %d ",pkrec);
                break;
        }    */
        pkrec = (pkrec+1)%8;
        *len = nlen;
        gspack(4,pkrec,0,0,tmp);
        return(0);
/*case 2:
        if(debug > 0) printmsg(" extra REJ %d ",npkrec);
        return(0);
case 4:
        if(debug > 0) printmsg(" extra RR %d ",npkrec);
        return(0);
case -1: gspack(4,pkrec,0,0,tmp);
        if(debug > 0) printmsg(" unknown rec packet - send ack ");
        break;
case -2: gspack(2,pkrec,0,0,tmp);
        if(debug > 0) printmsg(" send REJ %d ",pkrec);
        break;    */
default: break;
}
}
return(-1);
}
/*
 *
 *  sendpkt
 *
*****   description:    Put at most a packet's worth of data  in the pkt state
*****                   machine for xmission.
*****                   May have to run the pkt machine a few times to get
*****                   an available output slot.
 *
 * on input: char *data int len,flg; len=length of data in data.
 *           flg=2 just send the packet with no wait for ack.
 *           flg>0 zero out the unused part of the buffer. (for UUCP "msg"
 *                                                                   pkts)
 *           flg=0 normal data
 * return:   ret(0) if alls well ret(-1) if problems (fail)
 *
*/
gsendpkt(data,len,msg)
int len,msg;
char data[];
{
int nlen,npkrec,npksent,i;
char tmp[PKTSIZE];
if(msg) {len=PKTSIZE; for(i=strlen(data);i<len;i++) data[i] = '\0'; }
for(i=0;i<MAXTRY;i++)
{
gspack(0,pkrec,pksent,len,data); if(msg == 2) return(0);
switch(grpack(&npkrec,&npksent,&nlen,tmp))
{
case 4: /*if(npkrec != pksent) {
        if(debug > 0) printmsg(" wrong RR %d (%d) ",pksent,npkrec);
        break;
        }   */
        pksent = (1+pksent)%8;
        return(0);
/*case 2: if(debug > 0) printmsg(" REJ %d ",npkrec);
        break;
case 0: return(0);
case -1: break;  */
default: break;
}
}
return(-1);
}

/*<FF>*/
/*************** FRAMMING *****************************/
/*
 *
 *
 *      send a packet
 * nt2=type nt3=pkrec nt4=pksent len=length<=PKTSIZE cnt1= data * ret(0) always
 */
gspack(nt2,nt3,nt4,len,cnt1)
int nt2,nt3,nt4,len;
char cnt1[];
{
unsigned int check,i;
unsigned char c2,pkt[HDRSIZE];
if(len > 64) len = 64;
if(len == 0) cnt1[0] = '\0';
if(debug > 0) {
printmsg("send packet type %d",nt2);
printmsg("  num = %d n = %d",nt3,nt4);
printmsg("  len = %d data =\n|%s|",len,cnt1);
}
c2 = '\0';
pkt[0] = '\020';
pkt[4] = nt2<<3;
nt2 &= 7;
switch(nt2)
{
case 1:      break;                  /* stop protocol */
case 2:      pkt[4] += nt3; break;   /* reject        */
case 3:      break;
case 4:      pkt[4] += nt3; break;   /* ack          */
case 5:      pkt[4] += 3;   break;   /* 3 windows */
case 6:      pkt[4] += 1;   break;   /* pktsiz = 64 (1) */
case 7:      pkt[4] += 3;   break;   /* 3 windows */
case 0:      pkt[4] += 0x80 + nt3 + (nt4<<3);
                c2 = (PKTSIZE - len)&0xff;
                if(c2)
                {
                        pkt[4] += 0x40;   /* if len < PKTSIZE */
                        for(i=PKTSIZE-1;i>0;i--) cnt1[i]=cnt1[i-1];
                        cnt1[0]=c2;
                }
                break;
}
pkt[4] &= 0xff;
if(nt2)
{
        pkt[1] = 9;             /* control packet size = 0 (9) */
        check = (0xaaaa - pkt[4])&0xffff;
}
else
{
        pkt[1] = PKTSIZ2;             /* data packet size = 64 (2) */
        check = checksum(cnt1,PKTSIZE);
i = pkt[4];/* got to do this on PC for ex-or high bits */
i &= 0xff;
check = (check ^ i) & 0xffff;
        check = (0xaaaa - check) & 0xffff;
}
        pkt[2] = check & 0xff;
        pkt[3] = (check>>8) & 0xff;
        pkt[5] = (pkt[1]^pkt[2]^pkt[3]^pkt[4])&0xff;
        swrite(pkt,HDRSIZE);       /* header is 6-bytes long */
/*      write(flog,pkt,HDRSIZE);   */
        if(pkt[1] != 9) { swrite(cnt1,PKTSIZE);     /* data is always 64
bytes long */       /*    write(flog,cnt1,PKTSIZE);   */
}
}

/*<FF>*/
/*
 *
 *      read packet
 * on return: nt3=pkrec nt4=pksent len=length <=PKTSIZE  cnt1=data *
ret(type) ok; ret(-1) input buf empty; ret(-2) bad header;
 *              ret(-3) lost pkt timeout; ret(-4) checksum error;ret(-5) ?
 */
grpack(nt3,nt4,len,cnt1)
int *nt3,*nt4,*len;
char cnt1[];
{
unsigned int nt1,check,checkchk,i;
unsigned char c,c2,pkt[HDRSIZE];
int ii;
c = '\0';
while((c & 0x7f) != '\020') if(sread(&c,1,msgtime) < 1) return(-1);

if(sread(&pkt[1],HDRSIZE-1,msgtime) < (HDRSIZE-1)) return(-1);
/*write(flog,&c,1); write(flog,&pkt[1],HDRSIZE-1); */
/* header is 6-bytes long */
i = pkt[1]^pkt[2]^pkt[3]^pkt[4]^pkt[5];
i &= 0xff;
if(i)
{                        /*  bad header */
        printmsg("****bad header****");
      return(-2);
}
if((pkt[1] &=0x7f) == 9)
{       /* control packet */
        *len = 0;
        c = pkt[4] & 0xff;
        nt1  = c>>3;
        *nt3 = c & 7;
        *nt4 = 0;
        check = 0;
        checkchk = 0;
        cnt1[*len] = '\0';
}
else
{       /* data packet */
        if(pkt[1] != PKTSIZ2) return(-5);   /* cant handle other than 64*/
        nt1  = 0;
        c2 = pkt[4] & 0xff;
        c = c2&0x3f;
        *nt4 = c>>3;
        *nt3 = c & 7;
        if(sread(cnt1,PKTSIZE,msgtime) < PKTSIZE) return(-3);
/*        write(flog,cnt1,PKTSIZE);     */
        /* 64 byte packets even if partial */
i = pkt[3];
i = (i<<8)&0xff00;
check = pkt[2];
check = i|(check&0xff);
        checkchk = checksum(cnt1,PKTSIZE);
i = pkt[4]|0x80;
i &= 0xff;
        checkchk = 0xaaaa - (checkchk^i);
        checkchk &= 0xffff;
        if(checkchk != check) {
                printmsg("***checksum error***");
                return(-4);
        }
        *len = PKTSIZE;
        if(c2&0x40)
        {
                ii = (cnt1[0]&0xff);
                *len = (*len-ii)&0xff;
                for(ii=0;ii<*len;ii++) cnt1[ii] = cnt1[ii+1];
        }
        cnt1[*len] = '\0';
}
if(debug > 0) {
        printmsg("receive packet type %d ",nt1);
        printmsg("  num = %d n = %d",*nt3,*nt4);
        printmsg("  checksum rec = %x comp = %x",check,checkchk);
        printmsg("  len = %d data =\n|%s|",*len,cnt1);
}
        ii = nt1;
        return(ii);
}

unsigned checksum(data,len)
int len;
char data[];
{
unsigned int i,j,tmp,chk1,chk2;
chk1 = 0xffff;
chk2 = 0;
j = len;
for(i=0;i<len;i++)
{
        if(chk1&0x8000) { chk1 <<= 1; chk1++; }
        else { chk1 <<= 1; }
        tmp = chk1;
        chk1 += (data[i]&0xff);
        chk2 += chk1^j;
        if((chk1&0xffff) <= (tmp&0xffff)) chk1 ^= chk2;
        j--;
}
return(chk1&0xffff);
}
@@@ Finished dcppkt.c
echo dcprec.c
cat >dcprec.c <<'@@@ Finished dcprec.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* file recieve routines */
#include "dcp.h"
static unsigned char rpacket[MAXPACK];
/*<FF>*/
/*********************** MISC SUB SUB PROTOCOL *************************/
/*
**
**schkdir
** scan the dir
*/
schkdir()
{
char c;
c = scandir();
if(c =='Q')
{
return('Y');
}
if(c =='S')
{
sprintf(rpacket,"HN");
if((*sendpkt)(rpacket,0,1)) return(0);
}
return('B');
}

/*<FF>*/
/*
 *
 *      endp() end protocol
 *
*/
endp()
{
sprintf(rpacket,"HY");
(*sendpkt)(rpacket,0,2); /* dont wait for ACK */
(*closepk)();
return('P');
}

/*<FF>*/
/***********************RECIEVE PROTOCOL**********************/
/*
 *  r d a t a
 *
 *  Receive Data
 */
rdata()
{
        int len;
        if((*getpkt)(rpacket,&len)) return(0);
        if(len == 0)
        {
        close(fp);
        sprintf(rpacket,"CY");
        if((*sendpkt)(rpacket,0,1)) return(0);
		if(debug) printmsg("transfer complete");
        return('F');
        }
    write(fp,rpacket,len);/* Write the data to the file */
    return('D');/* Remain in data state */
}


/*<FF>*/
/*
 *  r f i l e
 *
 *  Receive File Header
 */
rfile()
{
        int len,i;
        char *nptr,filenam1[132]; /*Holds the converted file name */
        char *fromptr,*toptr;
        toptr=tofile; fromptr=fromfile; nptr=filenam1;
        if((*getpkt)(rpacket,&len)) return(0);
        if((rpacket[0]&0x7f) == 'H') { return('C');}
        strncpy(filenam1,rpacket,len);

/* Convert upper case to lower */
for (nptr=filenam1; *nptr != '\0'; nptr++)
if (*nptr >= 'A' && *nptr <= 'Z')  *nptr |= 040;
nptr = filenam1;

toptr=tofile; nptr=filenam1; sscanf(&nptr[2],"%s %s ",fromptr,toptr);

toptr = tofile;
#ifndef DG
if((i=mindex(toptr,'.')) > 0) {nptr=filenam1; len=strlen(toptr);
/* MASH the file for PC and VMS */
sprintf(nptr,"%.1s%.4s%.3s",toptr,&toptr[i+1],&toptr[len-3]); }
#else
sprintf(nptr,"%s",toptr);
#endif

if ((fp=creat(nptr,0775)) == -1) { /* Try to open a new file */
  if(debug) printmsg("cannot create %s",nptr); /* Give up if can't */
  return('A'); }

if(debug) printmsg("Receiving %s as %s",fromptr,nptr);
sprintf(rpacket,"SY");
if((*sendpkt)(rpacket,0,1)) return(0);
return('D'); /* Switch to data state */
}

/*<FF>*/
/*
 *  r i n i t
 *
 *  Receive Initialization
 */
rinit()
{
if((*openpk)()) return(0);
return('F');
}
@@@ Finished dcprec.c
echo dcprpkt.c
cat >dcprpkt.c <<'@@@ Finished dcprpkt.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* General sliding window program. Under developement. Has advanteges */
/* over "got-back-N". Was used initially as a vehicle to decypher  */
/* the "g: protocol. Modify dcp.h,dcp.c,dcpstart.c and leave out if desired*/
#include "dcp.h"

#define PKTSIZE 64      /*      framming data   */
#define HDRSIZ  5
#define SYNC    '\020'

#define MAXSEQ  8       /*      protocol data   */
#define NBUF    4    /*MAXSEQ/2 give explicitly! so type is integer*/
#define MAXERR  20
#define KPKT    1024/PKTSIZE
#define TIMEOUT 10     /* should be 4sec */
#define MAXTRY  10

#define between(a,b,c) ((a<=b && b<c) || (c<a && a<=b) || (b<c && c<a))

/* packet defin */
static int head,rwl,swl,swu,rwu,nerr,nbuffers,nonak,npkt;
static int ftimer[NBUF],fseq[NBUF],outlen[NBUF],inlen[NBUF],arr[NBUF];
static char outbuf[NBUF][PKTSIZE],inbuf[NBUF][PKTSIZE];

/***************************************************/
ropenpk()
{
int i,j,n1,n2,len;
char tmp[PKTSIZE];
msgtime=MSGTIME;
pktsize=PKTSIZE;
head=rwl=swl=swu=nerr=nbuffers=npkt=0;
rwu=NBUF; nonak=TRUE;
for(i=0;i<NBUF;i++) {ftimer[i]=0; arr[i]=FALSE; }
j=7;
ropkt:
if(j==4) return(0); /* ok */
for(i=0;i<MAXTRY;i++)
{rspack(j,0,0,0,tmp); if(rrpack(&n1,&n2,&len,tmp)==j) {j--; goto ropkt;}}
return(-1); /* no good */
}

rclosepk()
{
char tmp[PKTSIZE];
rspack(CLOSE,0,0,0,tmp);
rspack(CLOSE,0,0,0,tmp);
return(0);
}

/*************** rsendpkt *****************/
/*
*****   description:    Put at most a packet's worth of data  in the pkt state
*****                   machine for xmission.
*****                   May have to run the pkt machine a few times to get
*****                   an available output slot.
 *
 * on input: char *data int len,flg; len=length of data in data.
 *           flg=2 just send the packet with no wait for ack.
 *           flg>0 zero out the unused part of the buffer. (for UUCP "msg"
 *                                                                   pkts)
 *           flg=0 normal data
 * return:   ret(0) if alls well ret(-1) if problems (fail)
 *
*/
rsendpkt(data,len,flg)
int len,flg;
char data[];
{
int i,i1;
long tmp;
if(debug>2) printmsg("\nSendpkt");
machine();
while(nbuffers >= NBUF) machine();
i1 = swu % NBUF;
if(flg) {strcpy(outbuf[i1],data); len=PKTSIZE; for(i=strlen(data);i<len;i++)
outbuf[i1][i]='\0';}
else { strncpy(outbuf[i1],data,len); }
outlen[i1] = len;
rspack(DATA,rwl,swu,outlen[i1],outbuf[i1]); ftimer[i1] = time(&tmp);
fseq[i1]=swu; npkt++;
nbuffers++;
swu = (1+swu)%MAXSEQ;
return(0);
}


/*************** rgetpkt **********/
/*
**** description: Gets no more than a packet's worth of data from
****               the "packet i/o state machine". May have to
****               periodically run the pkt machine to get some
****               packets.
* on input: dont care   getpkt(data,&len)  char *data int len
* on return: data+\0 and length in len. ret(0) if alls well
* ret(-1) if problems.(fail)
 */
rgetpkt(data,len)
int *len;
char data[];
{
int i2;
if(debug>2) printmsg("\nGetpkt");
machine();
while((arr[rwl%NBUF]) == 0) machine();
{
        if(debug>2) printmsg("ACK %d",rwl);
        rspack(ACK,rwl,0,0,0);
        i2 = rwl%NBUF;
        *len = inlen[i2];
        strncpy(data,inbuf[i2],*len);
        nonak = TRUE;
        arr[i2] = FALSE;
        rwl = (1+rwl)%MAXSEQ;
        rwu = (1+rwu)%MAXSEQ;
}
return(0);
}


/************     packet machine   *************/
machine()
{
int rack,rseq,rlen,i1,i2;
char rdata[PKTSIZE];
long tmp;
reply:
if(debug>3) printmsg("Kbytes transfered %d errors %d\r",npkt/KPKT,nerr);
if(nerr >= MAXERR) {return(ERROR);}
switch(rrpack(&rack,&rseq,&rlen,rdata))
{
case CLOSE: if(debug>2) printmsg("got CLOSE"); return(CLOSE);
case NAK: if(debug>2) printmsg("got NAK"); if(between(swl,rack,swu))
          {
             i1 = (i2 = rack)%NBUF;
             rspack(DATA,rwl,i2,outlen[i1],outbuf[i1]);ftimer[i1]=time(&tmp);
             nerr++; if(debug>2) printmsg("got NAK %d",rack);
          }
          goto reply;
case EMPTY:   if(debug>2) printmsg("got EMPTY");
            i1 = time(&tmp);
            for(i2=0;i2<NBUF;i2++)  {
                 if(ftimer[i2]) {if((i1-ftimer[i2]) >= TIMEOUT)
                 {
                        rspack(DATA,rwl,fseq[i2],outlen[i2],outbuf[i2]);
                        ftimer[i2]=time(&tmp);
                        nerr++; if(debug>2)
                                printmsg("timeout on %d",fseq[i2]);
            }    } }
            goto ssend;
case ACK: if(debug>2) printmsg("got ACK"); while(between(swl,rack,swu))
          {
                if(debug>2) printmsg("got ACK %d",rack);
                nbuffers--;
                ftimer[swl % NBUF] = 0;
                swl = (1+swl)%MAXSEQ;
          }
          goto reply;
case DATA: if(debug>2) printmsg("got DATA");
          if(rseq != rwl && nonak)
                {
                        /* can comment this out without loss in perfom*/
                        /*rspack(NAK,rwl,0,0,0);nonak=FALSE;*/
                        nerr++;   if(debug>2)
                                   printmsg("out of sequence %d",rseq);
                }
                if(between(rwl,rseq,rwu) && arr[rseq%NBUF] == FALSE)
                {
                        if(debug>2) printmsg("data pass %d",rseq);
                        i1 = rseq%NBUF;
                        arr[i1] = TRUE;
                        inlen[i1] = rlen;
                        strncpy(inbuf[i1],rdata,rlen);
                }
                goto reply;
case ERROR: nerr++; if(debug>2) printmsg("checksum error %d",rseq);
                if(nonak) {rspack(NAK,rwl,0,0,0);nonak=FALSE;}
                goto reply;
default: goto ssend;
}
ssend: {}
}
/*      framming        */
/********************
 *      read packet
 * on return: nt3=pkrec nt4=pksent len=length <=PKTSIZE  cnt1=data
 * ret(type) ok; ret(-1) input buf empty; ret(-2) bad header;
 *              ret(-3) lost pkt timeout; ret(-4) checksum error;ret(-5) ?
 rpack(nt3,nt4,len,cnt1)
 int *nt3,*nt4,*len;
 char cnt1[];
 *********************
 *      send a packet
 * nt2=type nt3=pkrec nt4=pksent len=length<=PKTSIZE cnt1= data
 * ret(0) always
 *
gspack(nt2,nt3,nt4,len,cnt1)
int nt2,nt3,nt4,len;
char cnt1[];
************************/
/******************** rspack *****************/
rspack(ttype,ack,seq,len,data)
int ttype,ack,seq,len;
char *data;
{
int i;
char msg[HDRSIZ];
msg[0] = SYNC; msg[1] = ttype;  msg[2] = ((ack<<4)&0xf0)|(seq&0x0f);
msg[3] = len;      msg[4] = msg[1]^msg[2]^msg[3];
if(ttype == DATA) for(i=0;i<PKTSIZE;i++) msg[4] ^= data[i];
swrite(msg,HDRSIZ);
if(ttype == DATA) swrite(data,PKTSIZE);
if(debug>2) {printmsg("rspack: ");
printmsg("type=%d seq=%d ack=%d len=%d chk=%d",ttype,seq,ack,len,msg[4]);
if(ttype==DATA)
        {data[len]='\0';  printmsg("|%s|",data); }
else    {printmsg("||"); }
}
}

/*********** rrpack **********************/
static unsigned char sbuf[512];
rrpack(ack,seq,len,data)
int *ack,*seq,*len;
char *data;
{
int i1,timeout=0;
/* ideally we only want to check the input buffer */
/* if its empty return(EMPTY) else get the rest of the packet */
if(sread(sbuf,1,timeout)<1) return(EMPTY);
i1=HDRSIZ-1;
if(sread(&sbuf[1],i1,1)<i1) return(ERROR);
if(sbuf[1]==DATA) if(sread(data,PKTSIZE,1)<PKTSIZE) return(ERROR);
/* deeeeeeeeeeee  all this que stuff just complicates stuff
*len = 0;
if(head>=HDRSIZ) goto rp2;
if(head>0) goto rp1;
sbuf[0] = (!SYNC);
while(sbuf[0] != SYNC) 
   {if(sread(&sbuf[0],1,timeout)<1) return(EMPTY);} head = 1;
rp1: i1=HDRSIZ;
if((head += sread(&sbuf[head],i1-head,timeout))<i1) return(EMPTY);
rp2: i1=HDRSIZ+PKTSIZE;
if(sbuf[1]==DATA)
if((head += sread(&sbuf[head],i1-head,timeout))<i1) return(EMPTY);
head=0; deeeeeeeeee  end de-complification */
*ack = (sbuf[2]>>4)&0x0f; *seq = sbuf[2]&0x0f; *len = sbuf[3];
sbuf[4] = sbuf[4]^sbuf[3]^sbuf[2]^sbuf[1];
if(sbuf[1] == DATA) for(i1=0;i1<PKTSIZE;i1++)
                        sbuf[4] ^=(data[i1]);/*=sbuf[HDRSIZ+i1]);*/
if(sbuf[4]&0xff) return(ERROR);
if(debug>2) {printmsg("rrpack: ");
printmsg("type=%d seq=%d ack=%d len=%d chk=%d",sbuf[1],*seq,*ack,*len,sbuf[4]);
data[*len]='\0'; printmsg("|%s|",data); }
return(sbuf[1]);
}
@@@ Finished dcprpkt.c
echo dcpscan.c
cat >dcpscan.c <<'@@@ Finished dcpscan.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* Directory scanner for DOS and DG and some unix systems */
#include "dcp.h"
/*<FF>*/
/*
**
**scandir
**
*/
#ifdef PC
int near dir_open();
#endif
#ifdef DG
#include <sys/types.h>
#include <sys/dir.h>
#endif

scandir()
{
int fn,len,i;
char cname[40],tmp[132];
#ifndef DG
sprintf(cname,"c%.4s*",rmtname);
if(dir_open(cname,tmp) != 0) return('Q');/* asm DOS call for dir */
#ifdef PC
strcpy(cfile,&tmp[30]); /* PC filename starts at DTA+30 */
#else VMS
if(debug > 3) printmsg("workfile: %s",tmp);
strcpy(cfile,tmp);  /* Normal for VMS */
#endif PC
if(fw== -1)
if((fw=open(cfile,0))==-1) return('Y');
return('S');
#else
struct direct dirbuf;
sprintf(cname,"c.%.6s",rmtname); /* sprintf(cname,"c%.4s",rmtname); */
if((i=mindex(cname,'-')) != -1) cname[i] = '?';
len=strlen(cname);
if((fn=open(spooldir,0)) <= 0) return('A');
while(read(fn,(char *)&dirbuf,sizeof(dirbuf))>0) {
        if(debug > 4) printmsg("dir file = %s cfile = %s",dirbuf.d_name,cname);
        if(strncmp(dirbuf.d_name,cname,len)==0) {
                strcpy(cfile,dirbuf.d_name);
                close(fn);
                if(fw==-1)
                        if((fw=open(cfile,0))==-1) return('Y');
                return('S');
        }
}
close(fn);
return('Q');
#endif
}
@@@ Finished dcpscan.c
echo dcpsend.c
cat >dcpsend.c <<'@@@ Finished dcpsend.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* file send routines */
#include "dcp.h"
static unsigned char spacket[MAXPACK];
/*<FF>*/
/***************SEND PROTOCOL***************************/
/*
 *  s d a t a
 *
 *  Send File Data
 */
sdata()
{
        if((*sendpkt)(spacket,size,0)) return(0);     /* send data */
        if ((size = bufill(spacket)) == -1) /* Get data from file */
             return('Z');/* If EOF set state to that */
        return('D');/* Got data, stay in state D */

}

/*<FF>*/
/*
 *  b u f i l l
 *
 *  Get a bufferful of data from the file that's being sent.
 *  Only control-quoting is done; 8-bit & repeat count prefixes are
 *  not handled.
 */
bufill(buffer)
char buffer[];/* Buffer */
{
    int i;/* Loop index */
    char t;/* Char read from file */
    i = 0;/* Init data buffer pointer */
        while(read(fp,&t,1) ==1)
        {
            buffer[i++] = t;/* Deposit the character itself */
            if(i >= pktsize) return(i);
        }
        if(i==0) return(-1);
    return(i);/* Handle partial buffer */
}


/*<FF>*/
/*
 *  s b r e a k
 *
 *  Send Break (EOT)
 */
sbreak()
{
        int len,i;
        sprintf(spacket,"H");
        if((*sendpkt)(spacket,0,1)) return(0);
        if((*getpkt)(spacket,&len)) return(0);
		if(debug) printmsg("Switch modes");
        if(spacket[1] == 'N') return('G');
        return('Y');
}

/*<FF>*/
/*
 *  s e o f
 *
 *  Send End-Of-File.
 */
seof()
{
        int len,i;
		if((*sendpkt)(spacket,0,0)) return(0);
		if((*getpkt)(spacket,&len)) return(0); /* rec CY or CN */
	    if(strncmp(spacket,"CY",2)) return(0); /* cant send file */
		close(fp);
		fp = (-1);
		unlink(fromfile);
		if(debug) printmsg("transfer %s complete,%d",fromfile,fp);
        return('F');                    /* go get the next file to send */
}

/*<FF>*/
/*
 *  s f i l e
 *
 *  Send File Header.
 */
sfile()
{
int i,len;
if (fp == -1) {/* If not already open, */
       if (debug > 1) printmsg("looking for next file...");
       if(getfile()) {/* get next file from current work*/
              close(fw);
              unlink(cfile);/* close and delete completed workfile */
              fw = -1;
              return('B'); /* end sending session */
       } 
#ifdef DG /* brain damaged MV/UX on DG */
       if((i=mindex(fromfile,'-')) != -1) fromfile[i] = '?';
#endif DG
       if (debug > 1) printmsg("  New file is %s", fromfile);
       if (debug) printmsg("   Opening %s for sending.", fromfile);
       fp = open(fromfile,0);/* open the file to be sent */
       if (fp == -1) {/* If bad file pointer, give up */
       	 if(debug) printmsg("Cannot open file %s", fromfile);
         return('A');
       }
} else return('A'); /* If somethings already open. were in trouble*/
if(debug > 1) printmsg("Sending %s as %s",fromfile,tofile);
strcpy(spacket,tofile);
if((*sendpkt)(spacket,0,1)) return(0);       /* send S fromfile tofile */
if((*getpkt)(spacket,&len)) return(0);       /* user - tofile 0666. */
if(spacket[1] != 'Y') return('A'); 			/* If otherside says no-quit*/
size = bufill(spacket);
return('D');
}

/*<FF>*/
/*
 *  s i n i t
 *
 *  Send Initiate: send this host's parameters and get other side's back.
 */
sinit()
{
        if((*openpk)()) return('A');
        return('B');
}

/*<FF>*/
/*
 *
 *
 *  getfile
 *
 *  getfile reads the next line from the presently open workfile
 *  (cfile) and determines from this the next file to be sent
 *  (file). If there are no more TRUE is returned.
 *  --A fix for "R from to 0666" should be done here to recieve files
 *  --in addition to sending them. The appropriate "state letter"
 *  --i.e. "R" should be returned to the send "master" or "slave"
 *  --state switching table in "dcp.c"
 *  --I did not implement this since the majority of uucp transactions
 *  --appear to be "S from to 0666" type. RHLamb 1/87
 *
 */
getfile()
{
int i;
char line[132];
if(getline(fw,line)) return(TRUE);
sscanf(&line[2],"%s ",fromfile);
for(i=0;line[i];i++) {if(strncmp(&line[i],"0666",4) == 0) break;}
line[i+4] = '\0';
strcpy(tofile,line);
return(FALSE);
}

@@@ Finished dcpsend.c
echo dcpstart.c
cat >dcpstart.c <<'@@@ Finished dcpstart.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* Dialer,Proto negotiator,identify routines */
#include "dcp.h"
#define PROTOS  "trkg"
#define MAXLOGTRY       3

Proto Protolst[] = {  'g',ggetpkt,gsendpkt,gopenpk,gclosepk,
                      'k',kgetpkt,ksendpkt,kopenpk,kclosepk,
                      'r',rgetpkt,rsendpkt,ropenpk,rclosepk,
                      't',tgetpkt,tsendpkt,topenpk,tclosepk,'0'};

procref         getpkt,sendpkt,openpk,closepk;

/*<FF>*/
/*
**
**
**startup
**
**
*/
startup()
{
char msg[80],tmp1[20],tmp2[20];
if(! remote) 
{
msgtime = 2*MSGTIME;
if(rmsg(msg,2)== -1) return('Y');
if(debug > 1) printmsg("1st msg = %s",msg);
if(strncmp(&msg[6],rmtname,7)) return('Y');
sprintf(msg,"S%.7s -Q0 -x%d",myname,debug);  /* -Q0 -x16 remote debug set */
wmsg(msg,2);
if(rmsg(msg,2)== -1) return('Y');
if(debug > 1) printmsg("2nd msg = %s",msg);
if(strncmp(&msg[1],"OK",2)) return('Y');
if(rmsg(msg,2)== -1) return('Y');
if(debug > 1) printmsg("3rd msg = %s",msg);
if(msg[0] != 'P' || mindex(&msg[1],proto[0]) == -1)
{
wmsg("UN",2);
return('Y');
}
sprintf(msg,"U%c",proto[0]);
wmsg(msg,2);
setproto(proto[0]);
return('D');
}
else 
{
msgtime = 2*MSGTIME;
sprintf(msg,"Shere=%s",myname);
wmsg(msg,2);
if(rmsg(msg,2)== -1) return('Y');
sscanf(&msg[1],"%s %s %s",rmtname,tmp1,tmp2);
sscanf(tmp2,"-x%d",&debug);
if(debug > 0) printmsg("debug level = %d",debug);
if(debug > 1) printmsg("1st msg from remote = %s",msg);
if(checkname(rmtname)) return('Y');
wmsg("ROK",2);
sprintf(msg,"P%s",PROTOS);
wmsg(msg,2);
if(rmsg(msg,2)== -1) return('Y');
if(msg[0] != 'U' || mindex(PROTOS,msg[1]) == -1) return('Y');
proto[0] = msg[1];
setproto(proto[0]);
return('R');
}
}


/******* set the protocol **********/
setproto(pr)
char pr;
{
int i;
Proto *tproto;
for(tproto=Protolst;tproto->type != '\0' && pr != tproto->type; tproto++)
{if(debug>2) printmsg("setproto: %c %c",pr,tproto->type); }
if(tproto->type =='\0') {
                  printmsg("setproto:You said I had it but I cant find it");
                        exit(1); }
getpkt = tproto->a; sendpkt = tproto->b;
openpk =tproto->c;  closepk =tproto->d;
}



/*<FF>*/
/*
**
**callup
** script processor - nothing fancy! 
*/
callup()
{
int flg,kk,jj,ll,firstflg;
char buf2[132],*prsend;
if(openline(device,speed)) return('G');
jj=0;
kk=0;
while(TRUE)
{
        if(loginseq[jj] == 0x5c && loginseq[jj+1] == 'n')
        {
                buf2[kk] = '\n';
                kk++;
                jj += 2;
                continue;
        }
        if(loginseq[jj] == 0x5c && loginseq[jj+1] == 'r')
        {
                buf2[kk] = '\r';
                kk++;
                jj += 2;
                continue;
        }
        buf2[kk] = loginseq[jj];
        if(buf2[kk] == '\0') break;
        kk++;
        jj++;
}
flg = -1;       /* start by sending */
firstflg = -1;
jj=0;
prsend = &buf2[jj];
msgtime = 2*MSGTIME;
while(buf2[jj])
{
        kk=jj;
        while(buf2[kk] != '-' && buf2[kk] != '\0')
                kk++;
        if(buf2[kk]=='\0') buf2[kk+1]='\0';
        buf2[kk] = '\0';
        if(flg)
        {
                prsend = &buf2[jj];
                if(firstflg) {
                slowrite(&buf2[jj]);
                } else {
                wmsg(&buf2[jj],0);
                }
                flg = 0;
                firstflg = -1; /* change this to 0 for normal use */
        }
        else
        {
                ll = 1;
                while(getstring(&buf2[jj]))
                {
                      if(ll++ >= MAXLOGTRY ) return('Y');
                      wmsg(prsend,0);
                      /* try resending before giving up */
                }
                flg = -1;
        }
        jj = kk + 1;
}
return('P');
}


/*<FF>*/
/*
**
**      slowrite
** comunication slow write. needed for auto-baud modems
*/
slowrite(st)
register char *st;
{
int len,j;
char c;
len=strlen(st);
if(debug>2) printmsg("sent %s",st);
for(j=0;j<len;j++) {
        swrite(&st[j],1);
        ddelay(80000);
        }
}
@@@ Finished dcpstart.c
echo dcpsys.c
cat >dcpsys.c <<'@@@ Finished dcpsys.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* Get the next system, and other support routines  */
#include "dcp.h"
/*<FF>*/
/***************************************************************/
/***            Sub Systems             */
/*
**
**getsystem
** Process an "systems" file entry (like L.sys)
*/
getsystem()
{
int i;
char line[132];
if(getline(fsys,line)) return('A');
sscanf(line,"%s %s %s %s %s %s %s",rmtname,cctime,device,type,speed,proto,loginseq);
if(debug > 2) printmsg("rmt= %s ctm= %s dev= %s",rmtname,cctime,device);
if(debug > 2) printmsg("typ= %s spd= %s pro= %s",type,speed,proto);
if(debug > 2) printmsg("logseq= %s",loginseq);
if(strcmp(cctime,"Slave")==0) return('G');        /*skip this system*/
if(checktime(cctime)) return('G');/* "" wrong time */
return('S');    /*startup this system*/
}

/*<FF>*/
/*
**
**checkname
** Do we know the guy ?
*/
checkname(name)
char name[];
{
int ffd;
char line[132],tmp[20];
if((ffd=open(SYSTEMS,0))== -1) return(-1);
while(getline(ffd,line)==FALSE)
{
        sscanf(line,"%s ",tmp);
        if(debug > 3) printmsg("rmt= %s sys= %s",name,tmp);
        if(strncmp(name,tmp,7)==0) 
                               {
                      close(ffd);
                     return(0); /*OK I like you */
         }
}
close(ffd);
return(-1); /* Who are you ? */
}

/*<FF>*/
/*
**
**checktime
** check if we may make a call at this time 
**------------>to be implemented. Again. Didnt think it crucial
*/
checktime(xtime)
char xtime[];
{
return(0); /* OK go to it */
}

/*<FF>*/
/*
 *
 *      mindex() True if c is in st
 *
*/
mindex(st,c)
char c,st[];
{
int i;
i=0;
for(;;)
{
if(st[i] == '\0') return(-1);
if(st[i] == c) return(i);
i++;
}
}

/*<FF>*/
/*
**
**sysend
** end UUCP session negotiation
*/
sysend()
{
char msg[80];
msg[1] = '\0';
msgtime = 2*MSGTIME;
while(msg[1] != 'O')
{
wmsg("OOOOOO",2);
if(rmsg(msg,2)== -1) goto hang;
}
hang:
        wmsg("OOOOOO",2);
        closeline();
if(! remote) return('I');
return('A');
}


/*<FF>*/
/*
**
**      delay
**
*/
ddelay(dtime)
int dtime;
{
int i,j;
for(i=0;i<dtime;i++) { }
}

/*<FF>*/
/*
**
**      getstring
** Look for a string - useful for send-expect operation
*/
getstring(st)
char *st;
{
int len,j;
char c[40];
len=strlen(st);
c[len]='\0';
len--;
if(debug > 2) printmsg("wanted %s",st);
while(strcmp(st,c) !=0) {
        for(j=0;j<len;j++) c[j]=c[j+1];
        if(sread(&c[len],1,msgtime) < 1) return(-1);
        c[len] &= 0x7f;
        }
if(debug >2) printmsg("got that ","");
return 0;
}


/*<FF>*/
/*
**
**wmsg
** write a ^P type msg to the remote uucp
*/
wmsg(msg,syn)
int syn;
char msg[];
{
int len;
len=strlen(msg);
if(syn==2) swrite("\0\020",2);
swrite(msg,len);
if(syn==2) swrite("\0",1);
}

/*<FF>*/
/*
**
**rmsg
** read a ^P msg from UUCP
*/
rmsg(msg,syn)
int syn;
char msg[];
{
int ii;
char c,cc[5];
/* *msg0;*/
/*msg0 = msg;*/
c = 'a';
if(syn==2) {
	while((c & 0x7f) != '\020') {
		if(sread(cc,1,msgtime) < 1) return(-1); 
		c=cc[0]; /* Dont ask. MSC needs more than a byte to breathe */
/*		printf("Hello im in rmsg c=%x\n",c); */
	}
}
for(ii=0;ii<132 && c ;ii++) {
	if(sread(cc,1,msgtime) < 1) return(-1);
	c = cc[0] & 0x7f;
	if(c == '\r' || c == '\n') c = '\0';
	msg[ii]=c;
	/*if(c == '\020') msg = msg0; */
}
return(strlen(msg));
}


/*<FF>*/
/*
**
**      getline
** get a \n terminated string from whatever
*/
getline(lfp,line)
int lfp;
char line[];
{
int ii;
char c;
c = 'a';
for(ii=0;ii<132 && c;ii++) {
	if(read(lfp,&c,1) == 0) return(TRUE);
	c &= 0xff;
    if(c == '\n') c = '\0';
	line[ii] = c;
}
return(FALSE);
}

/*<FF>*/
/*
 *  p r i n t m s g
 *
 *  Print error message on standard output if not remote.
 */
/*VARARGS1*/
printmsg(fmt, a1, a2, a3, a4, a5)
char * fmt;
{
        int len;
		char msg[256];
        sprintf(msg,fmt, a1, a2, a3, a4, a5);
		msg[256]='\0';
		len=strlen(msg);
		msg[len]='\n'; len++;
		msg[len]='\0';
	    if (! remote) printf("%s",msg);
	    write(flog,msg,len);
}

@@@ Finished dcpsys.c
echo dcptpkt.c
cat >dcptpkt.c <<'@@@ Finished dcptpkt.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* NO error checking protocol. Good for UUCP over virtual circuits */
/* such as TCPIP or X.25. Also a good starting place to write your */
/* own protocols */
#include "dcp.h"
#define PKTSIZE 120

topenpk()
{
msgtime=MSGTIME;
pktsize=PKTSIZE;
return(0);
}

tclosepk()
{
return(0);
}

tgetpkt(data,len)
int *len;
char *data;
{
int nt1,nt2;
trpack(len,data);
swrite("2",1);
return(0);
}

tsendpkt(data,len,msg)
int len,msg;
char *data;
{
int i;
char c;
if(msg) { len=PKTSIZE; for(i=strlen(data);i<len;i++) data[i]='\0'; }
tspack(DATA,len,data);
sread(&c,1,30);
return(0);
}

tspack(nt1,len,data)
int nt1,len;
unsigned char *data;
{
unsigned char c;
if(debug>2) {printmsg("spack: type=%d len=%d",nt1,len);
if(nt1==DATA) {data[len]='\0'; printmsg("|%s|",data); }}
c=nt1; swrite(&c,1); c=len; swrite(&c,1);
swrite(data,len);
}

trpack(len,data)
int *len;
unsigned char *data;
{
unsigned char c,ct;
int timeout=30;
sread(&c,1,timeout); ct=c; sread(&c,1,timeout); *len=c;
sread(data,*len,timeout); data[*len]='\0';
if(debug>2) {printmsg("rpack: type=%d len=%d",ct,*len);
if(*len > 0) printmsg("data=|%s|",data);}
return(ct);
}
@@@ Finished dcptpkt.c
echo dcpvms.c
cat >dcpvms.c <<'@@@ Finished dcpvms.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* VAX/VMS support. */
#include "dcp.h"
#ifdef VMS
#include <descrip.h>
dir_open(tplt,f21)
char *tplt,*f21;
{
int len1,cont1,ii1;
char lbuf[80],*strchr();
$DESCRIPTOR(tmp11,tplt);
$DESCRIPTOR(tmp21,lbuf);
tmp11.dsc$w_length = strlen(tplt);
tmp21.dsc$w_length = sizeof(lbuf);
cont1=0;
ii1=lib$find_file(&tmp11,&tmp21,&cont1);
/*lib$signal(ii1);*/
len1=strchr(lbuf,' ') - lbuf;
lbuf[len1]='\0';
strcpy(f21,lbuf);
if(ii1==65537) return(0);
return(-1);
}

unlink(name)
char *name;
{
/* strange how VAX C does things */
delete(name);
}

spawn(command,input,output)
char *command,*input,*output;
{
int ret;
$DESCRIPTOR(tmp1,command);
$DESCRIPTOR(tmp2,input);
$DESCRIPTOR(tmp3,output);
tmp1.dsc$w_length = strlen(command);
tmp2.dsc$w_length = strlen(input);
tmp3.dsc$w_length = strlen(output);
ret=lib$spawn(&tmp1,&tmp2,&tmp3,0,0,0,0,0,0,0);
if(debug && !remote) lib$signal(ret);
}
#endif VMS

@@@ Finished dcpvms.c
echo dcxqt.c
cat >dcxqt.c <<'@@@ Finished dcxqt.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
#include "dcp.h"

/* A command formatter for DCP. RH Lamb */
/* sets up stdin and stdout on various machines */
/* There is NO command checking so watch what you send and who you */
/* let accsess your machine. "C rm /usr/*.*" could be executed. */
dcxqt()
{
int i;
char command[60],input[60],output[60],line[132];
while(dscandir())
{
sprintf(line,"%s",cfile);
fw=open(line,0);
strcpy(cfile,line);
if(debug > 2) printmsg("dcxqt:%s %d",cfile,fw);
input[0] = '\0';
output[0] = '\0';
while(getline(fw,line)==FALSE)
{
if(debug > 2) printmsg("dcxqt:%s",line); 
switch(line[0])
{
        case 'U':       break;
        case 'I':       sprintf(input,"%s",&line[2]); break;
        case 'O':       sprintf(output,"%s",&line[2]); break;
        case 'C':       strcpy(command,&line[2]); break;
        case 'R':       break;
        default :       break;
}
}
#ifndef DG
nodot(input); nodot(output); 
#endif
#ifdef PC
i=strlen(command); strcpy(line,command);
if(strlen(input)==0 && strlen(output)==0) goto syskp;
if(strlen(input)==0) {sprintf(&line[i]," >%s",output); goto syskp;}
if(strlen(output)==0) {sprintf(&line[i]," <%s",input); goto syskp;}
sprintf(&line[i]," <%s >%s",input,output);
syskp: { }
#endif PC
#ifdef DG
if(strlen(input)==0) strcpy(input,"@null");
if(strlen(output)==0) strcpy(output,"@null");
sprintf(line,"proc/def/block/inp=%s/out=%s ",input,output);
i=strlen(line);
strcpy(&line[i],command);
#endif
#ifndef VMS
if(debug > 1) printmsg("dcxqt:%s",line);
if(system(line)) return(-1);
#endif 
#ifdef VMS
/* hacks to make VMS recognize files */
if((i=strlen(input))==0) strcpy(input,"nl:");
else {input[i]='.'; input[i+1]=';'; input[i+2]='\0'; }
/* Change file record format here. MUST have a var.fdl file in this dir  */
unlink("tmp.tmp");
sprintf(line,"CONVERT/FDL=VAR %s tmp.tmp",input);
if(debug > 3) printmsg("dcxqt: %s",line);
spawn(line,"nl:","nl:");
sprintf(input,"tmp.tmp");
/* END record format conversion hack. Please fix */
if((i=strlen(output))==0) strcpy(output,"nl:");
else {output[i]='.'; output[i+1]=';'; output[i+2]='\0';}
/* hack to make VMS ignore "!" bye quoting "mit-eddie!lids" */
i=mindex(command,' '); strncpy(line,command,i+1);
line[i+1]='"'; strcpy(&line[i+2],&command[i+1]); i=strlen(line);
line[i]='"'; line[i+1]='\0';
if(debug > 1) printmsg("dcxqt:%s in:%s out:%s",line,input,output);
/* the "spawn" function seems to lose blocks of a file from time to time*/
/* The full file is transfered ok but its lost here. please FIX */
/* Cause: Incorrect file attributes. rmail wants stream_LF, spawn wants
Varable. Current hack is to user "CONVERT/FDL=VAR". */
spawn(line,input,output);
#endif
close(fw);
unlink(cfile);
unlink(input);
unlink(output);
}
return(0);
}

#ifndef DG
/* remove dots for PC or VAX file names */
nodot(string)
char *string;
{
int i,len;
char msg[80];
len=strlen(string); if((i=mindex(string,'.'))== -1) return(0);
sprintf(msg,"%.1s%.4s%.3s",string,&string[i+1],&string[len-3]);
strcpy(string,msg);
return(1);
}
#endif

/*<FF>*/
/*
**
**dscandir
** scan the directory
*/
#ifdef PC
int near dir_open();
#endif
#ifdef DG
#include <sys/types.h>
#include <sys/dir.h>
#endif

dscandir()
{
int fn,len,i;
char cname[40],tmp[132];
#ifndef DG
sprintf(cname,"x*");
if(dir_open(cname,tmp) != 0) return(0);/* asm DOS call for dir */
#ifdef PC
strcpy(cfile,&tmp[30]); /* filename starts at DTA+30 */
#else
strcpy(cfile,tmp); /*VMS */
#endif
return(-1);
#else
struct direct dirbuf;
sprintf(cname,"x."); 
len=strlen(cname);
if((fn=open(spooldir,0)) <= 0) return(0);
while(read(fn,(char *)&dirbuf,sizeof(dirbuf))>0) {
if(debug>4) printmsg("dcxqt:dir file = %s cfile = %s",dirbuf.d_name,cname);
        if(strncmp(dirbuf.d_name,cname,len)==0) {
                strcpy(cfile,dirbuf.d_name);
                close(fn);
                return(-1);
        }
}
close(fn);
return(0);
#endif
}



@@@ Finished dcxqt.c
echo rmail.c
cat >rmail.c <<'@@@ Finished rmail.c'
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/* mail handler like unix "rmail".  */
#include <stdio.h>
#include "dcps.h"
/*#define LCLMAILER /**/   /* define it if you have a local mail handler */
/* high modified 8/5/86 for fixed spool directory usage */
/* 8/5/86 mod for PC */
/* usage: rmail remotesystem!remoteuser user mysystem   */
/* rmail a!b <NL> takes user,mysystem from "userfile" */
/* rmail<NL> reads the local file "mboxuser", <NL> to see next msg */
/* This obviously can be improved upon easily. RH Lamb */
/* rmail looks for "From " lines in mbox for delimiting */
/*#define DATETIME        "dow mo day time year"        */
#ifndef DG		/* PC VMS file munging */
#define FPATTERN 		"%c%.4s%03d"
#else			/* unix type files */
#define FPATTERN		"%c.%.7s%03d"
#endif
#define PC_CREAT (0775)
main(argc,argv)
int argc;
char *argv[];
{
int i,ii,seq,fcfile,fxfile,fdfile,flg,fpip;
char cfile[40],dfile[40],xfile[40],rmtname[40],rmtuser[80],myname[40];
char rmtdfile[40],rmtxfile[40],user[40],tmp[132],spooldir[132],datetime[50];
long temptime;
flg = 0;
fcfile=open(USERFILE,0);
rmsg(fcfile,tmp);
sscanf(tmp,"%s %s ",myname,user);
rmsg(fcfile,tmp);
rmsg(fcfile,tmp);
sscanf(tmp,"%s ",spooldir);
close(fcfile);
if(argc <= 1 ) goto readmbox;
if(argc > 2 ) strcpy(user,argv[2]);
if(argc > 3 ) strcpy(myname,argv[3]);
if((i=mindex(argv[1],'!')) < 0) flg = 1;
/*if(mindex(argv[1],'@') > -1) flg=2; */
/*un-comment it if you want ARPANET to handle ALL "@" recipients */
/* else "!"'s will be processed first.*/
/* till we figure out the rest of the message format do !'s first */
time(&temptime);
sprintf(datetime,"%s",ctime(&temptime)); ii=strlen(datetime);
datetime[ii-1] = '\0'; sprintf(&datetime[ii-1]," EDT");
seq=random(); /* pick the time as a random file seq num and take our chances*/
if(flg==0)  /* has only !'s in it --->UUCP */
{
strncpy(rmtname,argv[1],i);
rmtname[i] = '\0';
strcpy(rmtuser,&argv[1][i+1]);
sprintf(dfile,FPATTERN,'D',rmtname,seq);
sprintf(rmtdfile,"D.%.7s%03d",rmtname,seq);
fdfile=creat(dfile,PC_CREAT);
}
if(flg)    /* else pass it along to --->ARPANET,and Local mailer */
{
/********* MAKE the data file for your local mail handler *****/
#ifdef  LCLMAILER   /** pass it thru **/ 
/*set up a local file with the right header info for local mailer */
sprintf(dfile,":udd:uucp:mail:uucp%03d",seq);
fdfile=creat(dfile,PC_CREAT);
sprintf(tmp,"To:%s\n\n",argv[1]);
wmsg(fdfile,tmp);
#else    /** final destination **/ /*put it in an mbox */
sprintf(dfile,"Mbox%.4s",user);
if((fdfile=open(dfile,1)) < 0) fdfile=creat(dfile,PC_CREAT);
lseek(fdfile,0L,2);
sprintf(tmp,"From %s %s remote from %s\n",user,datetime,myname);
wmsg(fdfile,tmp);
#endif
/***************************************************************/
}
sprintf(tmp,"Received: by %s on %s\n",myname,datetime);
wmsg(fdfile,tmp);
while(-1)
{
        if(rmsg(0,tmp) == 0) break;     /* EOF */
#ifndef VMS
        if(tmp[0] == 0x1a ) break;      /* ctrl-Z */
#endif
        if(tmp[0] == '.' && tmp[1] == '\n')  break;
        if(strncmp(tmp,"From ",5) == 0) wmsg(fdfile,">");
        wmsg(fdfile,tmp);
}
/*wmsg(fdfile,"\n\n");*/
close(fdfile);
if(flg) {
#ifdef  LCLMAILER
/******* PUT your local mail handler here *****/
sprintf(tmp,"control :util:smile:mailer:mail$ uucp%03d uucp",seq);
system(tmp); /* this ones for our DG mailer */
/***********************************************/
#endif
}
if(flg) return(0); /* if ARPA or Local or final dest Im finised */
/***************************************/
sprintf(xfile,FPATTERN,'B',myname,seq);
fxfile=creat(xfile,PC_CREAT);
sprintf(tmp,"U %s %s\n",user,myname);
wmsg(fxfile,tmp);
sprintf(tmp,"F %s\n",rmtdfile);
wmsg(fxfile,tmp);
sprintf(tmp,"I %s\n",rmtdfile);
wmsg(fxfile,tmp);
sprintf(tmp,"C rmail %s\n",rmtuser);
wmsg(fxfile,tmp);
close(fxfile);
/***************************************/
sprintf(cfile,FPATTERN,'C',rmtname,seq);
fcfile=creat(cfile,PC_CREAT);
sprintf(rmtxfile,"X.%.7s%03d",myname,seq);
sprintf(tmp,"S %s %s %s - %s 0666\n",dfile,rmtdfile,user,dfile);
wmsg(fcfile,tmp);
sprintf(tmp,"S %s %s %s - %s 0666\n",xfile,rmtxfile,user,xfile);
wmsg(fcfile,tmp);
close(fcfile);
/****************************************/
return(0);
/*****************************************/
readmbox:
sprintf(cfile,"Mbox%.4s",user);
if((fcfile=open(cfile,0)) < 0) fcfile=creat(cfile,PC_CREAT);
while(-1)
{
        if(rmsg(fcfile,tmp) == 0) break;        if(strncmp(tmp,"From ",5)==0)
rmsg(0,dfile);
        wmsg(1,tmp);
}
close(fcfile);
return(0);
/***************************************/
}

random()
{ /* get a random number for names and other stuff */
int it;
long tmp;
it = time(&tmp);
it &= 0xff;
return(it);
}

rmsg(fp,msg)
int fp;
char msg[];
{
char c;
c = 'a';
while(c)
{
        if(read(fp,&c,1) == 0) return(0);
        c &= 0x7f;
        *msg = c;
        msg++;
        if(c == '\r' || c == '\n') {*msg = '\0'; c = '\0';}
}
return(-1);
}


wmsg(fp,msg)
int fp;
char msg[];
{
int len;
len=strlen(msg);
write(fp,msg,len);
}

mindex(st,c)
char c,st[];
{
int i;
for(i=0;st[i] != '\0';i++)
{
if(st[i] == c) return(i);
}
return(-1);
}
@@@ Finished rmail.c
echo spawn.c
cat >spawn.c <<'@@@ Finished spawn.c'
#include <descrip.h>

main(argc,argv)
int argc;
char *argv[];
{
char input[32],output[32];
if(argc < 3) strcpy(output,"nl:"); else strcpy(output,argv[3]);
if(argc < 2) strcpy(input,"nl:"); else strcpy(input,argv[2]);
printf("cmd:%s in:%s out:%s\n",argv[1],input,output);
spawn(argv[1],input,output);
}

spawn(command,input,output)
char *command,*input,*output;
{
int ret;
$DESCRIPTOR(tmp1,command);
$DESCRIPTOR(tmp2,input);
$DESCRIPTOR(tmp3,output);
tmp1.dsc$w_length = strlen(command);
tmp2.dsc$w_length = strlen(input);
tmp3.dsc$w_length = strlen(output);
ret=lib$spawn(&tmp1,&tmp2,&tmp3,0,0,0,0,0,0,0);
lib$signal(ret);
}

@@@ Finished spawn.c
exit 0
End of Listing

ddl@husc6.UUCP (Dan Lanciani) (04/17/87)

In article <531@lids.mit.edu>, lamb@lids.mit.edu writes:
> /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */

	I know this has been said before, but it is getting very frustrating.
Public domain and copyright are mutually exclusive.  I appreciate that
people want to share their sources with us, and I understand if they
would prefer to protect them.  But placing two conflicting statements of
status in a program makes it useless to anyone who cares about such things.
We have no way of knowing what we may or may not do with this "PD uu clone;"
the copyright doesn't even include the usual "copy but not for profit
clause."  We have to assume that we can't even print it out...

In article <4269@hi.uucp>, josh@hi.uucp writes:
> XX  Copyright 1987, Josh Siegel
> XX  All rights reserved.

	In the cases of the "network library," there is no ambiguity,
but there is also no permission to use, modify, or otherwise enjoy the
code.  Why post it?

	Further examples may be found in the "public domain" curses,
grep, and many others in the mod.sources archive.  So please (pretty
please with sugar on it?) if you want to make something public domain,
don't copyright it.  If you have something about non-profit use in mind,
spell it out so we know what we can use it for.  If you actually want
to reserve all rights, avoid posting since it is an invitation to have
those rights violated by, e.g., someone's reading the article on a
printing terminal and leaving the terminal room without destroying the
copy...

					Dan Lanciani
					ddl@harvard.*

josh@hi.UUCP (04/18/87)

 >In article <531@lids.mit.edu>, lamb@lids.mit.edu writes:
 >
 >In article <4269@hi.uucp>, josh@hi.uucp writes:
 >> XX  Copyright 1987, Josh Siegel
 >> XX  All rights reserved.
 >
 >	In the cases of the "network library," there is no ambiguity,
 >but there is also no permission to use, modify, or otherwise enjoy the
 >code.  Why post it?
 >

Just so I can get HUNDREDS of letters asking for express permission
 to use the code.... :-)

				--Josh Siegel
-- 
Josh Siegel		(siegel@hc.dspo.gov)
                        (505) 277-2497  (Home)
		I'm a mathematician, not a programmer!