/* >>:yam4.c 11-4-83 * * Support for Compuserve CIS A protocol * file-upload and file-download functions * called from term() when ascii SI is received. * * It seems that the CIS protocol isn't quite as simple as YAM4.C * was lead to beleive! 1) The SI and SO may have the high-order * bit on, as SI and SO without the high order bit on are used to * control external network echoing. 2) If you R FILTRN, then a * "redundant" SI is issued when FILTRN transfers control to * XFTRAN without sending an SO. 3) Sometimes CIS ends a transfer * without any SO at all, just starts sending (with a blank). * 5) The fixes therein allow downloading from Micro-quote * via TymNet. DAVID WELCH */ #include "yam.h" FLAG CISasc; /* CIS xfer is in ascii mode */ char ciscursec; /* Sector number just received by cisgetsec() */ cispa() { register char *p; for(;;) { switch( firstch=readline(400)) { case ESC: switch(firstch=readline(400)) { case 'I': /* pstat("CIS-IDENT"); */ p = MYSYSTEM; while( *p) sendline( *p++); continue; case 'A': if(cisxfer() != ERROR) { sayterm(); continue; } sendline(NAK); sayterm(); return ERROR; default: break; } default: lprintf("Bad CIS request 0%o\n", firstch); sayterm(); return ERROR; case '\n': case SO: case (SO | 0x80): case ' ': return OK; case SI: case (SI | 0x80): break; } } } /* * get file request from host and perform the transfer */ cisxfer() { char *p; CISasc = FALSE; if(cisgetsec(Utility.ubuf, (PATHLEN+3)) <= 0) return ERROR; if(p=index('\r', Utility.ubuf)) *p = 0; CISasc = (Utility.ubuf[1] == 'A'); if(Utility.ubuf[0] == 'U') { if(opentx( &Utility.ubuf[2]) == ERROR) return ERROR; sendline('.'); if(readline(400) != '.' || sendcis() == ERROR) { closetx(FALSE); return ERROR; } closetx(TRUE); return OK; } else if(Utility.ubuf[0] == 'D') { if(openrx( &Utility.ubuf[2]) == ERROR) { return ERROR; } sendline('.'); return getcis(); } else return ERROR; } sendcis() { unsigned nchars; nchars=0; while((wcj=filbcis(Utility.ubuf)) > 0) { pstat("Char %u", nchars); if(scisrec(Utility.ubuf, wcj)==ERROR) return ERROR; nchars += wcj; } return scisrec(0,0); /* send special EOT record */ } /* * fill p with at most 256 chars not incl EOF * returns number of chars fetched, 0 for end of file */ filbcis(p) char *p; { int c; int count; for( count=0; count< 256; ++count) { if((c=getc(fin)) == EOF) break; if(CISasc && c == CPMEOF) { ungetc(CPMEOF, fin); break; } *p++ =c; } return count; } /* * send a record at buf with length len to CIS * return ERROR if unsuccessful * Special case: len==0 causes EOT record to be sent * instead of buffer contents */ scisrec( buf, len) char *buf; { char *p; int count; int retry; if( ++ciscursec > '9') ciscursec = '0'; for(retry = 5; --retry; ++toterrs) { p = buf; sendline(SOH); sendline(oldcrc=ciscursec); if(len==0) { sendline(firstch=EOT); ucksum(); } else for(count=len; --count >=0;) { firstch = *p++ & 0377; ucksum(); sendmsk(firstch); if(CISasc) putcty(firstch); } sendline(ETX); sendmsk(oldcrc); if((firstch=readline(400)) == '.') return OK; lprintf("\nGot 0%o for record ACK\n", firstch); if(firstch < 0) return ERROR; } return ERROR; } /* * send most control charsacters as DLE sequence * except for BEL to CR inclusive */ sendmsk(c) unsigned c; { c &= 0377; /* in case of sign extension */ if( c < 7 || (c < 0x20 && c > 0x0D)) { sendline(DLE); sendline(c | 0x40); } else sendline(c); } /* * get (download) a file with CIS A protocol */ getcis() { char cursec; char *p; unsigned nchars; cursec = '1'; nchars=0; for(;;) { pstat("Char %u", nchars); doagain: if((wcj=cisgetsec(Utility.ubuf, KSIZE)) <= 0) break; if(ciscursec==EOT) break; if(ciscursec == cursec) { sendline('.'); goto doagain; } if(ciscursec == cursec+1 || (cursec == '9' && ciscursec == '0') ) { nchars += wcj; for(p=Utility.ubuf; --wcj >= 0; ) putc( *p++, fout); if( ++cursec > '9') cursec = '0'; sendline('.'); } else { lprintf("\nGot record 0%o expecting 0%o\n", ciscursec, cursec); break; } } if(ciscursec != EOT) { lprintf("Error: Transfer Aborted: %u Characters Received ", nchars); closerx(TRUE); printdfr(); return ERROR; } #ifndef BYTEFLENGTH if(CISasc) putc(CPMEOF, fout); #endif closerx(FALSE); sendline('.'); lprintf("%u Characters Received ", nchars); printdfr(); return OK; } /* * gets a CIS A protocol record into buf. Record number returned in global * ciscursec, which equals EOT for EOT record (end of file). Returns number * of characters read. Returns ERROR if too many chars received. * no retry count; it is assumed that sender will send NAK to abort * (will abort on timeout) * The acknowledge is NOT sent by cisgetsec; the caller must send a '.' * when it is ready to proceed. */ cisgetsec(buf, maxcount) char *buf; { char *p; int count; reread: for(;;) { if((firstch=readline(400)) == SOH) break; if(firstch==TIMEOUT) goto timedout; if(firstch==NAK) return ERROR; } ciscursec = oldcrc = readline(400); for(p=buf, count=0; ;) { switch(firstch=readline(400)) { timedout: case TIMEOUT: lprintf("\nTimeout waiting for Host\n"); return ERROR; case NAK: return ERROR; case ETX: if((firstch=readline(400))==TIMEOUT) goto timedout; if(firstch==DLE) { if((firstch=readline(400))==TIMEOUT) goto timedout; firstch &= 037; } if(firstch == oldcrc) return count; lprintf("\nError Checksum=0%o Got 0%o \n", oldcrc, firstch); ++toterrs; sendline('/'); goto reread; case EOT: ciscursec = EOT; break; case DLE: if((firstch=readline(400))==TIMEOUT) goto timedout; firstch &= 037; } if(++count > maxcount) return ERROR; *p++ = firstch; if(CISasc) putcty(firstch); ucksum(); } } /* * ucksum updates oldcrc with firstch * CIS uses rotate left, NOT shift left as per protocol.cis */ ucksum() { oldcrc += oldcrc; if(oldcrc & 0400) ++oldcrc; if( (oldcrc = (oldcrc & 0377) + firstch) & 0400) ++oldcrc; oldcrc &= 0377; }