home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol158 / yam4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1984-04-29  |  6.0 KB  |  304 lines

  1. /*
  2. >>:yam4.c 9-6-83
  3.  *
  4.  * Support for Compuserve CIS A protocol
  5.  * file-upload and file-download functions
  6.  * called from term() when ascii SI is received.
  7.  *
  8.  * It seems that the CIS protocol isn't quite as simple as YAM4.C
  9.  * was lead to beleive! 1) The SI and SO may have the high-order
  10.  * bit on, as SI and SO without the high order bit on are used to
  11.  * control external network echoing. 2) If you R FILTRN, then a
  12.  * "redundant" SI is issued when FILTRN transfers control to
  13.  * XFTRAN without sending an SO. 3) Sometimes CIS ends a transfer
  14.  * without any SO at all, just starts sending (with a blank).
  15.  * 5) The fixes therein allow downloading from Micro-quote
  16.  * via TymNet.  DAVID WELCH
  17.  */
  18.  
  19. #define EXTERN extern
  20. #include "yamc86.h"
  21.  
  22. FLAG CISasc;            /* CIS xfer is in ascii mode */
  23. char ciscursec;        /* Sector number just received by cisgetsec() */
  24.  
  25. cispa()
  26. {
  27.     register char *p;
  28.  
  29.     for(;;) {
  30.         switch( firstch=readline(400)) {
  31.           case ESC:
  32.             switch(firstch=readline(400)) {
  33.             case 'I':
  34.                 pstat("CIS-IDENT");
  35.                 p = MYSYSTEM;
  36.                 while( *p)
  37.                     sendline( *p++);
  38.                 continue;
  39.             case 'A':
  40.                 if(cisxfer() != ERROR)
  41.                     continue;
  42.                 sendline(NAK); return ERROR;
  43.             default:
  44.                 break;
  45.             }
  46.         default:
  47.             lprintf("Bad CIS request 0%o\n", firstch);
  48.             return ERROR;
  49.         case '\n':
  50.         case SO:
  51.         case (SO | 0x80):
  52.         case ' ':
  53.             return OK;
  54.         case SI:
  55.         case (SI | 0x80):
  56.             break;
  57.         }
  58.     }
  59. }
  60.  
  61. /*
  62.  * get file request from host and perform the transfer
  63.  */
  64. cisxfer()
  65. {
  66.     char *p;
  67.     CISasc = FALSE;
  68.     if(cisgetsec(Utility.ubuf, (PATHLEN+3)) <= 0)
  69.         return ERROR;
  70.     if(p=index('\r', Utility.ubuf))
  71.         *p = 0;
  72.     CISasc = (Utility.ubuf[1] == 'A');
  73.  
  74.     if(Utility.ubuf[0] == 'U') {
  75.         if(opentx( &Utility.ubuf[2]) == ERROR)
  76.             return ERROR;
  77.         sendline('.');
  78.         if(readline(400) != '.'  ||  sendcis() == ERROR) {
  79.             closetx(FALSE); return ERROR;
  80.         }
  81.         closetx(TRUE); return OK;
  82.     }
  83.     else if(Utility.ubuf[0] == 'D') {
  84.         if(openrx( &Utility.ubuf[2]) == ERROR) {
  85.             return ERROR;
  86.         }
  87.         sendline('.');
  88.         return getcis();
  89.     }
  90.     else
  91.         return ERROR;
  92. }
  93.  
  94. sendcis()
  95. {
  96.     unsigned nchars;
  97.  
  98.     nchars=0;
  99.     while((wcj=filbcis(Utility.ubuf)) > 0) {
  100.         pstat("Char %u", nchars);
  101.         if(scisrec(Utility.ubuf, wcj)==ERROR)
  102.             return ERROR;
  103.         nchars += wcj;
  104.     }
  105.     return scisrec(0,0);    /* send special EOT record */
  106. }
  107.  
  108. /*
  109.  * fill p with at most 256 chars not incl EOF
  110.  * returns number of chars fetched, 0 for end of file
  111.  */
  112. filbcis(p)
  113. char *p;
  114. {
  115.     int c;
  116.     int count;
  117.     for( count=0; count< 256; ++count) {
  118.         if((c=getc(fin)) == EOF)
  119.             break;
  120.         if(CISasc && c == CPMEOF) {
  121.             ungetc(CPMEOF, fin); break;
  122.         }
  123.         *p++ =c;
  124.     }
  125.     return count;
  126. }
  127. /*
  128.  * send a record at buf with length len to CIS
  129.  * return ERROR if unsuccessful
  130.  * Special case: len==0 causes EOT record to be sent
  131.  *          instead of buffer contents
  132.  */
  133. scisrec( buf, len)
  134. char *buf;
  135. {
  136.     char *p;
  137.     int count;
  138.     int retry;
  139.     if( ++ciscursec > '9')
  140.         ciscursec = '0';
  141.     for(retry = 5; --retry; ++toterrs) {
  142.         p = buf; sendline(SOH);
  143.         sendline(oldcrc=ciscursec);
  144.         if(len==0) {
  145.             sendline(firstch=EOT);
  146.             ucksum();
  147.         } else
  148.             for(count=len; --count >=0;) {
  149.                 firstch = *p++ & 0377;
  150.                 ucksum();
  151.                 sendmsk(firstch);
  152.                 if(CISasc)
  153.                     putcty(firstch);
  154.             }
  155.         sendline(ETX);
  156.         sendmsk(oldcrc);
  157.         if((firstch=readline(400)) == '.')
  158.             return OK;
  159.         if (CISasc)
  160.             lprintf("\n");
  161.         lprintf("Got 0%o for record ACK\n", firstch);
  162.         if(firstch < 0)
  163.             return ERROR;
  164.     }
  165.     return ERROR;
  166. }
  167.  
  168. /*
  169.  * send most control charsacters as DLE sequence
  170.  * except for BEL to CR inclusive
  171.  */
  172. sendmsk(c)
  173. unsigned c;
  174. {
  175.     c &= 0377;        /* in case of sign extension */
  176.     if( c < 7 || (c < 0x20 && c > 0x0D)) {
  177.         sendline(DLE);
  178.         sendline(c | 0x40);
  179.     }
  180.     else
  181.         sendline(c);
  182. }
  183.  
  184. /*
  185.  * get (download) a file with CIS A protocol
  186.  */
  187. getcis()
  188. {
  189.     char cursec;
  190.     char *p;
  191.     unsigned nchars;
  192.  
  193.     cursec = '1'; nchars=0;
  194.     for(;;) {
  195.         pstat("Char %u", nchars);
  196. doagain:
  197.         if((wcj=cisgetsec(Utility.ubuf, KSIZE)) <= 0)
  198.             break;
  199.         if(ciscursec==EOT)
  200.             break;
  201.         if(ciscursec == cursec) {
  202.             sendline('.');
  203.             goto doagain;
  204.         }
  205.         if(ciscursec == cursec+1 ||
  206.           (cursec == '9' && ciscursec == '0') ) {
  207.             nchars += wcj;
  208.             for(p=Utility.ubuf; --wcj >= 0; )
  209.                 fputc( *p++, fout);
  210.             if( ++cursec > '9')
  211.                 cursec = '0';
  212.             sendline('.');
  213.         }
  214.         else {
  215.             if (CISasc)
  216.                 lprintf("\n");
  217.             lprintf("Got record 0%o expecting 0%o\n",
  218.               ciscursec, cursec);
  219.             break;
  220.         }
  221.     }
  222.     lprintf("%u Characters Received ", nchars);
  223.     if(ciscursec != EOT) {
  224.         closerx(TRUE);    return ERROR;
  225.     }
  226.     if(CISasc)
  227.         fputc(CPMEOF, fout);
  228.     closerx(FALSE); sendline('.'); return OK;
  229. }
  230. /*
  231.  * gets a CIS A protocol record into buf.  Record number returned in global
  232.  * ciscursec, which equals EOT for EOT record (end of file).  Returns number
  233.  * of characters read.  Returns ERROR if too many chars received.
  234.  * no retry count; it is assumed that sender will send NAK to abort
  235.  * (will abort on timeout)
  236.  * The acknowledge is NOT sent by cisgetsec; the caller must send a '.'
  237.  * when it is ready to proceed.
  238.  */
  239. cisgetsec(buf, maxcount)
  240. char *buf;
  241. {
  242.     char *p;
  243.     int count;
  244.  
  245. reread:
  246.     for(;;) {
  247.         if((firstch=readline(400)) == SOH)
  248.             break;
  249.         if(firstch==TIMEOUT)
  250.             return ERROR;
  251.         if(firstch==NAK)
  252.             return ERROR;
  253.     }
  254.     ciscursec = oldcrc = readline(400);
  255.     for(p=buf, count=0; ;) {
  256.         switch(firstch=readline(400)) {
  257.         case TIMEOUT:
  258.               return ERROR;
  259.         case NAK:
  260.             return ERROR;
  261.         case ETX:
  262.             if((firstch=readline(400))==TIMEOUT)
  263.                 return ERROR;
  264.             if(firstch==DLE) {
  265.                 if((firstch=readline(400))==TIMEOUT)
  266.                     return ERROR;
  267.                 firstch &= 037;
  268.             }
  269.             if(firstch == oldcrc)
  270.                 return count;
  271.             if (CISasc)
  272.                 lprintf("\n");
  273.             lprintf("Error Checksum=0%o Got 0%o \n",
  274.               oldcrc, firstch);
  275.             ++toterrs; sendline('/'); goto reread;
  276.         case EOT:
  277.             ciscursec = EOT; break;
  278.         case DLE:
  279.             if((firstch=readline(400))==TIMEOUT)
  280.                 return ERROR;
  281.             firstch &= 037;
  282.         }
  283.         if(++count > maxcount)
  284.             return ERROR;
  285.         *p++ = firstch;
  286.         if(CISasc)
  287.             putcty(firstch);
  288.         ucksum();
  289.     }
  290. }
  291. /*
  292.  * ucksum updates oldcrc with firstch
  293.  * CIS uses rotate left, NOT shift left as per protocol.cis
  294.  */
  295. ucksum()
  296. {
  297.     oldcrc += oldcrc;
  298.     if(oldcrc & 0400)
  299.         ++oldcrc;
  300.     if( (oldcrc = (oldcrc & 0377) + firstch) & 0400)
  301.         ++oldcrc;
  302.     oldcrc &= 0377;
  303. }
  304.