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!