/* >>:yam2.c 10-15-81 * Ward Christensen Protocol handler for sending and receiving * ascii and binary files. Modified for choice of checksum or crc. */ #include "yam.h" #define WCEOT (-10) wcsend(argc, argp) char **argp; { int wcs(); Crcflg=FALSE; firstsec=TRUE; if(Batch) { #ifdef XMODEM printf("Sending in Batch Mode\n"); #endif if(expand(wcs, argc, argp)==ERROR) goto fubar; if(wctxpn("")==ERROR) goto fubar; } else { for(; --argc>=0;) { if(opentx(*argp++)==ERROR) goto fubar; #ifdef XMODEM printf("'%s' FILE OPEN\n", Tname); #endif if(wctx()==ERROR) goto fubar; } } return OK; fubar: closetx(TRUE); sendline(CAN);sendline(CAN);sendline(CAN); return ERROR; } wcs(name) char *name; { if(opentx(name)==ERROR) return ERROR; if(wctxpn(name)!= ERROR) return wctx(); else { return ERROR; } } wcreceive(argc, argp) char **argp; { char rpn[SECSIZ]; /* rx path name */ if(Batch || argc==0) { printf("Receiving in Batch Mode\n"); for(;;) { if(wcrxpn(rpn)== ERROR) goto fubar; if(*rpn==0) return OK; if(wcrx(rpn)==ERROR) goto fubar; } } else for(; --argc>=0;) { #ifdef XMODEM printf("Receive:'%s' FILE OPEN\n", *argp); #endif if(wcrx(*argp++)==ERROR) goto fubar; } return OK; fubar: sendline(CAN);sendline(CAN);sendline(CAN); closerx(TRUE); return ERROR; } /* * Fetch a pathname from the other end as a C ctyle ASCIZ string. * Length is indeterminate as long as less than SECSIZ * a null string represents no more files */ wcrxpn(rpn) char *rpn; /* receive a pathname */ { char rname[SECSIZ]; purgeline(); sendline(Crcflg?WANTCRC:NAK); if(wcgetsec(rname, 100)==ERROR) { printf("Pathname fetch failed\n"); return ERROR; } strcpy(rpn, rname); sendline(ACK); return OK; } wctxpn(name) char *name; { char *p; lpstat("Awaiting initial pathname NAK"); if((firstch=readline(400))==TIMEOUT) return ERROR; if(firstch==WANTCRC) { printf("CRC Mode requested\n"); Crcflg=TRUE; } /* don't send drive specification */ if(p=index(':', name)) name= ++p; if(wcputsec(name, 0)==ERROR) { printf("Can't send pathname %s\n", name); return ERROR; } return OK; } /* * Adapted from CMODEM13.C, written by * Jack M. Wierda and Roderick W. Hart */ wcrx(name) char *name; { int sectnum, sectcurr, sectcomp; char rxbuf[128], sendchar; if(openrx(name)==ERROR) return ERROR; firstsec=TRUE;sectnum=0; sendchar=Crcflg?WANTCRC:NAK; for(;;) { if(!Quiet #ifdef STATLINE ) lpstat("Sector %3d", sectnum+1); #else && !View) lprintf("%s", (sectnum+1 &63)?"*":"*\n"); #endif purgeline(); sendline(sendchar); /* send it now, we're ready! */ sectcurr=wcgetsec(rxbuf, (sectnum&0177)?50:130); if(sectcurr==(sectnum+1 &0377)) { sectnum++; for(cp=rxbuf,wcj=128; --wcj>=0; ) if(putc(*cp++, fout)==ERROR) { printf("\nDisk Full\n"); return ERROR; } #ifndef XMODEM if(View) for(cp=rxbuf,wcj=128;--wcj>=0;) putchar(*cp++); #endif sendchar=ACK; } else if(sectcurr==sectnum) { pstat("Received dup Sector %d",sectcurr); sendchar=ACK; } else if(sectcurr==WCEOT) { sendline(ACK); /* don't pad the file any more than it already is */ closerx(FALSE); return OK; } else if(sectcurr==ERROR) return ERROR; else { printf(" Sync Error\n"); return ERROR; } } } /* * wcgetsec fetches a Ward Christensen type sector. * Returns sector number encountered or ERROR if valid sector not received, * or CAN CAN received * or WCEOT if eot sector * time is timeout for first char, set to 4 seconds thereafter ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** * (Caller must do that when he is good and ready to get next sector) */ wcgetsec(rxbuf, time) char *rxbuf; int time; { /* BDSC register checksum, wcj, firstch; */ int sectcurr,errors; for(Lastrx=errors=0; errors=0; ) { if((firstch=readline(1)) < 0) goto bilge; oldcrc=updcrc(firstch, oldcrc); checksum += (*cp++ = firstch); } if((firstch=readline(1)) < 0) goto bilge; if(Crcflg) { oldcrc=updcrc(firstch, oldcrc); if((firstch=readline(1)) < 0) goto bilge; oldcrc=updcrc(firstch, oldcrc); if(oldcrc) pstat("CRC=0%o Error #%d", oldcrc, errors); else { firstsec=FALSE; return sectcurr; } } else if(((checksum-firstch)&0377)==0) { firstsec=FALSE; return sectcurr; } else pstat("Checksum Error #%d", errors); } else pstat("Sector number garbled #%d", errors); } /* make sure eot really is eot and not just mixmash */ else if(firstch==EOT && readline(1)==TIMEOUT) return WCEOT; else if(firstch==CAN) { if(Lastrx==CAN) { printf("Sender CANcelled\n"); return ERROR; } else { Lastrx=CAN; continue; } } else if(firstch==TIMEOUT) pstat("Timeout #%d", errors); else if(firstch==ERROR) { bilge: pstat("Modem error #%d SR=%0o", errors, Mstatus); } else pstat("Got 0%o sector header", firstch); Lastrx=0; while(readline(1)!=TIMEOUT) ; time=40; sendline(Crcflg&&firstsec?WANTCRC:NAK); } /* try to stop the bubble machine. */ sendline(CAN);sendline(CAN);sendline(CAN); return ERROR; } wctx() { int sectnum, attempts; char txbuf[SECSIZ]; firstsec=TRUE; lpstat("Awaiting initial NAK"); while((firstch=readline(400))!=NAK && firstch != WANTCRC && firstch!=TIMEOUT && firstch!=CAN) lprintf("%c", firstch); /* let user see it if strange char */ if(firstch==CAN) return ERROR; if(firstch==WANTCRC) { printf("CRC Mode requested\n"); Crcflg=TRUE; } sectnum=1; while(filbuf(txbuf, SECSIZ)) { if(!Quiet #ifdef STATLINE ) lpstat("Sector %3d", sectnum); #else && !View) lprintf("%s", (sectnum&63)?"*":"*\n"); #endif if(wcputsec(txbuf, sectnum)==ERROR) { return ERROR; } else { if(View) /* View can't be set in xyam */ for(cp=txbuf,wcj=128;--wcj>=0;) putchar(*cp++); sectnum++; } } closetx(FALSE); attempts=0; do { sendline(EOT); purgeline(); attempts++; } while((firstch=(readline(100)) != ACK) && attempts < RETRYMAX); if(attempts == RETRYMAX) { printf("No ACK on EOT\n"); return ERROR; } else return OK; } wcputsec(txbuf, sectnum) char *txbuf; { /* BDSC register checksum, wcj, firstch; */ int attempts; firstch=0; /* part of logic to detect CAN CAN */ for(attempts=0; attempts <= RETRYMAX; attempts++) { Lastrx= firstch; sendline(SOH); sendline(sectnum); sendline(-sectnum-1); oldcrc=checksum=0; for(wcj=SECSIZ,cp=txbuf; --wcj>=0; ) { sendline(*cp); oldcrc=updcrc(*cp, oldcrc); checksum += *cp++; } if(Crcflg) { oldcrc=updcrc(0,updcrc(0,oldcrc)); sendline(oldcrc>>8);sendline(oldcrc); } else sendline(checksum); purgeline(); firstch=readline(100); if(firstch==CAN && Lastrx==CAN) { cancan: printf("\nReceiver CANcelled transmission "); return ERROR; } else if(firstch==ACK) { firstsec=FALSE; return OK; } else if(firstch==TIMEOUT) pstat("Timeout on sector ack attempt %d", attempts); else { if(firstsec && firstch==WANTCRC) { printf("CRC Mode requested\n"); Crcflg=TRUE; } pstat("Got 0%o for sector ACK attempt %d", firstch, attempts); for(;;) { Lastrx=firstch; /* let user see it if strange char */ lprintf("%c", firstch); if((firstch=readline(1))==TIMEOUT) break; if(firstch==CAN && Lastrx==CAN) goto cancan; } } } printf("No ACK on sector; Abort "); return ERROR; }