home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / HEATH / HMSRC20.LBR / HM8.CZ / HM8.C
Text File  |  2000-06-30  |  16KB  |  786 lines

  1. /************************* START OF MODULE 8 ********************************/
  2.  
  3. /* rz.c By Chuck Forsberg modified for cp/m by Hal Maney */
  4.  
  5. #define  C80
  6.  
  7. #include "hmodem80.h"
  8. #include "zmodem.h"
  9.  
  10. int Tryzhdrtype;       /* Header type to send corresponding to Last rx close */
  11.  
  12. wcreceive(filename)
  13. char *filename;
  14. {
  15.    char *grabmem();
  16.     static int c;
  17.  
  18.    rlabel();
  19.    QuitFlag = FALSE;
  20.    Zctlesc = 0;
  21.    Baudrate = Baudtable[Current.cbaudindex];
  22.    Tryzhdrtype = ZRINIT;
  23.    Secbuf = alloc(KSIZE + 1);
  24.    if (allocerror(Secbuf))
  25.       return NERROR;
  26.    Cpmbuf = grabmem(&Cpbufsize);
  27.    if (allocerror(Cpmbuf))
  28.       return NERROR;
  29.    Cpindex = 0;                        /* just in case */
  30.     Rxtimeout = 100;           /* 10 seconds */
  31.    Errors = 0;
  32. #ifdef   DEBUG
  33.    printf("\nbuffer size = %u\n",Cpbufsize);
  34. #endif
  35.    savecurs();
  36.    hidecurs();
  37.    box();
  38.     if (filename==0) {                  /* batch transfer */
  39.         Crcflag=(Wcsmask==0377);
  40.         if (c=tryz()) {                  /* zmodem transfer */
  41.          report(PROTOCOL,"ZMODEM Receive");
  42.             if (c == ZCOMPL)
  43.                 goto good;
  44.             if (c == NERROR)
  45.                 goto fubar;
  46.             c = rzmfile();
  47.             if (c)
  48.                 goto fubar;
  49.         } 
  50.         else {                            /* ymodem batch transfer */
  51.          report(PROTOCOL,"YMODEM Receive");
  52.          report(BLKCHECK,Crcflag?"CRC":"Checksum");
  53.             for (;;) {
  54.             if (opabort())
  55.                goto fubar;
  56.                 if (wcrxpn(Secbuf)== NERROR)
  57.                     goto fubar;
  58.                 if (Secbuf[0]==0)
  59.                     goto good;
  60.                 if (procheader(Secbuf) == NERROR)
  61.                     goto fubar;
  62.                 if (wcrx()==NERROR)
  63.                     goto fubar;
  64.             }
  65.         }
  66.     } 
  67.     else {
  68.       report(PROTOCOL,"XMODEM Receive");
  69.       strcpy(Pathname,filename);
  70.         checkpath(Pathname);
  71.         Fd=fopen(Pathname, "wb");
  72.       if (openerror(Fd,Pathname))
  73.          goto fubar1;
  74.         if (wcrx()==NERROR)                   /* xmodem */
  75.             goto fubar;
  76.     }
  77. good:
  78.    free(Cpmbuf);
  79.    free(Secbuf);
  80.    showcurs();
  81.    restcurs();
  82.    return OK;
  83.  
  84. fubar:
  85.     canit();
  86.     if (Fd)
  87.         fclose(Fd);
  88. fubar1:
  89.    free(Cpmbuf);
  90.    free(Secbuf);
  91.    showcurs();
  92.    restcurs();
  93.     return NERROR;
  94. }
  95.  
  96. /*
  97.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  98.  * Length is indeterminate as long as less than Blklen
  99.  * A null string represents no more files (YMODEM)
  100.  */
  101.  
  102. wcrxpn(rpn)
  103. char *rpn;    /* receive a pathname */
  104. {
  105.     static int c;
  106.  
  107.     purgeline();
  108.  
  109. et_tu:
  110.     Firstsec=TRUE;  
  111.     Eofseen=FALSE;
  112.     mcharout(Crcflag?WANTCRC:NAK);
  113.     while ((c = wcgetsec(rpn, 100)) != 0) {
  114.       if (QuitFlag)
  115.          return NERROR;
  116.         if (c == WCEOT) {
  117.             mcharout(ACK);
  118.             readline(INTRATIME);
  119.             goto et_tu;
  120.         }
  121.         return NERROR;
  122.     }
  123.     mcharout(ACK);
  124.     return OK;
  125. }
  126.  
  127. /*
  128.  * Adapted from CMODEM13.C, written by
  129.  * Jack M. Wierda and Roderick W. Hart
  130.  */
  131.  
  132. wcrx()
  133. {
  134.     static int sectnum, sectcurr;
  135.     static char sendchar;
  136.     static char *p;
  137.     static int cblklen;            /* bytes to dump this block */
  138.  
  139.     Firstsec=TRUE;
  140.     sectnum=0; 
  141.     Eofseen=FALSE;
  142.     sendchar=Crcflag?WANTCRC:NAK;
  143.    report(BLKCHECK,Crcflag?"CRC":"Checksum");
  144.  
  145.     for (;;) {
  146.       if (opabort())
  147.          return NERROR;
  148.         mcharout(sendchar);                /* send it now, we're ready! */
  149.         sectcurr = wcgetsec(Secbuf,Firstsec||(sectnum&0177)?50:130);
  150.         if (sectcurr==(sectnum+1 &Wcsmask)) {
  151.            sreport(++sectnum);
  152.             cblklen = Blklen;
  153.             if (putsec(Secbuf, cblklen)==NERROR)
  154.                 return NERROR;
  155.             sendchar=ACK;
  156.         }
  157.         else if (sectcurr==(sectnum&Wcsmask)) {
  158.             zperr("Duplicate Sector",TRUE);
  159.             sendchar=ACK;
  160.         }
  161.         else if (sectcurr==WCEOT) {
  162.          if (closeit())
  163.                 return NERROR;
  164.             mcharout(ACK);
  165.             return OK;
  166.         }
  167.         else if (sectcurr==NERROR)
  168.             return NERROR;
  169.         else {
  170.             zperr( "Sync Error",TRUE);
  171.             return NERROR;
  172.         }
  173.     }
  174. }
  175.  
  176. /*
  177.  * Wcgetsec fetches a Ward Christensen type sector.
  178.  * Returns sector number encountered or NERROR if valid sector not received,
  179.  * or CAN CAN received
  180.  * or WCEOT if eot sector
  181.  * time is timeout for first char, set to 4 seconds thereafter
  182.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  183.  *    (Caller must do that when he is good and ready to get next sector)
  184.  */
  185.  
  186. wcgetsec(rxbuf, maxtime)
  187. char *rxbuf;
  188. int maxtime;
  189. {
  190.     static int checksum, wcj, firstch;
  191.     static unsigned oldcrc;
  192.     static char *p;
  193.     static int sectcurr;
  194.    static int tries;
  195.  
  196.     for (Lastrx=Errors=0; Errors < RETRYMAX; ) {  /* errors incr by zperr */
  197.       if (opabort())
  198.          return NERROR;
  199.         if ((firstch=readline(maxtime))==STX) {
  200.             Blklen=KSIZE; 
  201.             goto get2;
  202.         }
  203.         if (firstch==SOH) {
  204.             Blklen=SECSIZ;
  205. get2:
  206.             sectcurr=readline(INTRATIME);
  207.             if ((sectcurr+(oldcrc=readline(INTRATIME)))==Wcsmask) {
  208.                 oldcrc=checksum=0;
  209.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  210.                     if ((firstch=readline(INTRATIME)) < 0)
  211.                         goto bilge;
  212.                     oldcrc=updcrc(firstch, oldcrc);
  213.                     checksum += (*p++ = firstch);
  214.                 }
  215.                 if ((firstch=readline(INTRATIME)) < 0)
  216.                     goto bilge;
  217.                 if (Crcflag) {
  218.                     oldcrc=updcrc(firstch, oldcrc);
  219.                     if ((firstch=readline(INTRATIME)) < 0)
  220.                         goto bilge;
  221.                     oldcrc=updcrc(firstch, oldcrc);
  222.                     if (oldcrc & 0xFFFF)
  223.                         zperr( "CRC Error",TRUE);
  224.                     else {
  225.                         Firstsec=FALSE;
  226.                         return sectcurr;
  227.                     }
  228.                 }
  229.                 else if (((checksum-firstch)&Wcsmask)==0) {
  230.                     Firstsec=FALSE;
  231.                     return sectcurr;
  232.                 }
  233.                 else
  234.                     zperr("Checksum error",TRUE);
  235.             }
  236.             else
  237.                 zperr("Block nr garbled",TRUE);
  238.         }
  239.         /* make sure eot really is eot and not just mixmash */
  240.         else if (firstch==EOT && readline(10)==TIMEOUT)
  241.             return WCEOT;
  242.         else if (firstch==CAN) {
  243.             if (Lastrx==CAN) {
  244.                 zperr( "Sender CANcelled",TRUE);
  245.                 return NERROR;
  246.             } 
  247.             else {
  248.                 Lastrx=CAN;
  249.                 continue;
  250.             }
  251.         }
  252.         else if (firstch==TIMEOUT) {
  253.             if (Firstsec) {
  254.                zperr( "TIMEOUT",TRUE);
  255.                 goto humbug;
  256.          }
  257. bilge:
  258.             zperr( "TIMEOUT",TRUE);
  259.         }
  260.         else
  261.             zperr( "Bad header",TRUE);
  262.  
  263. humbug:
  264.         Lastrx=0;
  265.         while(readline(50) != TIMEOUT)
  266.          if (QuitFlag)
  267.             return NERROR;
  268.         if (Firstsec) {
  269.          if (Xmodem && (Errors == RETRYMAX/2))
  270.             Crcflag = !Crcflag;           
  271.          report(BLKCHECK,Crcflag?"CRC":"Checksum");
  272.             mcharout(Crcflag?WANTCRC:NAK);
  273.         } 
  274.         else {
  275.             maxtime=40; 
  276.             mcharout(NAK);
  277.         }
  278.     }
  279.     /* try to stop the bubble machine. */
  280.     canit();
  281.     return NERROR;
  282. }
  283.  
  284. /*
  285.  * Process incoming file information header
  286.  */
  287. procheader(name)
  288. char *name;
  289. {
  290.    long atol();
  291.     static char *p, *ap;
  292.     
  293.     /*
  294.      *  Process YMODEM,ZMODEM remote file management requests
  295.      */
  296.  
  297.    clrreports();
  298.     p = name + 1 + strlen(name);
  299.     if (*p) {    /* file coming from Unix or DOS system */
  300.       ap = p;
  301.       while (*p != ' ')     /* find first space */
  302.          ++p;
  303.       *p = '\0';            /* ap now points to a long integer in ascii */
  304.       report(FILESIZE,ap);
  305.       report(SENDTIME,ttime(atol(ap)));
  306.    }
  307.     strcpy(Pathname, name);
  308.     checkpath(Pathname);
  309.    Fd=fopen(Pathname, "wb");
  310.    if (openerror(Fd,Pathname))
  311.       return NERROR;
  312.     return OK;
  313. }
  314.  
  315. /*
  316.  * Putsec writes the n characters of buf to receive file Fd.
  317.  */
  318. putsec(buf, n)
  319. char *buf;
  320. int n;
  321. {
  322.    static int status;
  323.  
  324.    status = 0xff;
  325.    while (n--) {
  326.       Cpmbuf[Cpindex++] = *buf++;
  327.       if (Cpindex >= Cpbufsize) {
  328.          status = write(Fd,Cpmbuf,Cpbufsize);
  329.          if (!status)
  330.             zperr("Disk write error",TRUE);
  331.          Cpindex = 0;
  332.       }
  333.    }
  334.    return status ? 0 : NERROR;
  335. }
  336.  
  337. /*
  338.  * substr(string, token) searches for token in string s
  339.  * returns pointer to token within string if found, NULL otherwise
  340.  */
  341. char *
  342. substr(s, t)
  343. char *s,*t;
  344. {
  345.    static int i;
  346.  
  347.    if ((i=index(s,t)) != -1)
  348.       return s+i;
  349.    else
  350.       return NULL;
  351. }
  352.  
  353. /* send cancel string to get the other end to shut up */
  354. canit()
  355. {
  356.     static char canistr[] = {
  357.         24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  358.     };
  359.  
  360.     mstrout(canistr,FALSE);
  361.    purgeline();
  362. }
  363.  
  364. clrreports()
  365. {
  366.    static int i;
  367.  
  368.    for (i=4; i<13; i++)
  369.       clrline(i);
  370. }
  371.  
  372.  
  373. zperr(string,incrflag)
  374. char *string;
  375. int incrflag;
  376. {
  377.    clrline(MESSAGE);
  378.    report(MESSAGE,string);
  379.    if (incrflag)
  380.       dreport(ERRORS,++Errors);
  381. }
  382.  
  383. report(row,string)
  384. int row;
  385. char *string;
  386. {
  387.    locate(row,61);
  388.    printf(string);
  389. }
  390.  
  391. dreport(row,value)
  392. int row, value;
  393. {
  394.    static char buf[7];
  395.    
  396.    report(row,itoa(value,buf));
  397. }
  398.  
  399. lreport(row,value)
  400. int row;
  401. long value;
  402. {
  403.    static char buf[20];
  404.  
  405.    report(row,ltoa(value,buf));
  406. }
  407.  
  408. sreport(sct)
  409. int sct;
  410. {  
  411.    static long bytes;
  412.  
  413.    bytes = (long)Blklen;
  414.    bytes *= sct;
  415.    dreport(BLOCKS,sct);
  416.    lreport(KBYTES,bytes);
  417. }
  418.  
  419. clrline(line)
  420. int line;
  421. {
  422.    report(line,"                ");
  423. }
  424.  
  425. checkpath(name)  /* eliminate bad paths */
  426. char *name;
  427. {
  428.    static char *p;
  429.    static int i;
  430.  
  431.    for (p=name; *p; p++) {             /* dump strange characters */
  432.       if (!isalpha(*p) && !isdigit(*p) && (*p != '.')) {
  433.          *p = '\0';
  434.          strcat(name,p+1);
  435.       }
  436.    }
  437.    if ((i=index(name,".")) > 8) {
  438.       p = name + i;
  439.       name[8] = '.';
  440.       name[9] = '\0';
  441.       p[3] = '\0';
  442.       strcat(name,p);
  443.    }
  444.    name[12] = '\0';
  445.    addatadrive(name);
  446.    report(PATHNAME,name);
  447. }
  448.  
  449. /*
  450.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  451.  *  Handles ZSINIT frame
  452.  *  Return ZFILE if Zmodem filename received, -1 on error,
  453.  *   ZCOMPL if transaction finished,  else 0
  454.  */
  455. tryz()
  456. {
  457.     static int c, n, *ip;
  458.     static int cmdzack1flg;
  459.  
  460.     if (Nozmodem)        /* ymodem has been forced */
  461.         return 0;
  462.  
  463.     for (n=Zmodem?15:5; --n>=0; ) {
  464.       if (opabort())
  465.          return NERROR;
  466.         /* Set buffer length (0) and capability flags */
  467.         stohdr(0L);
  468.         Txhdr[ZF0] = CANFC32 | CANFDX;
  469.         if (Zctlesc)
  470.             Txhdr[ZF0] |= TESCCTL;
  471.       ip = (int *)&Txhdr[ZP0];
  472.       *ip = Cpbufsize;
  473.         zshhdr(Tryzhdrtype, Txhdr);
  474.         if (Tryzhdrtype == ZSKIP)    /* Don't skip too far */
  475.             Tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  476. again:
  477.         switch (zgethdr(Rxhdr, 0)) {
  478.         case ZRQINIT:
  479.             continue;
  480.         case ZEOF:
  481.             continue;
  482.         case TIMEOUT:
  483.             continue;
  484.         case ZFILE:
  485.             Zconv = Rxhdr[ZF0];
  486.             Zmanag = Rxhdr[ZF1];
  487.             Ztrans = Rxhdr[ZF2];
  488.             Tryzhdrtype = ZRINIT;
  489.             c = zrdata(Secbuf, KSIZE);
  490.             if (c == GOTCRCW)
  491.                 return ZFILE;
  492.             zshhdr(ZNAK, Txhdr);
  493.             goto again;
  494.         case ZSINIT:
  495.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  496.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  497.                 zshhdr(ZACK, Txhdr);
  498.                 goto again;
  499.             }
  500.             zshhdr(ZNAK, Txhdr);
  501.             goto again;
  502.         case ZFREECNT:
  503.             stohdr(0L);
  504.             zshhdr(ZACK, Txhdr);
  505.             goto again;
  506.         case ZCOMMAND:
  507.             cmdzack1flg = Rxhdr[ZF0];
  508.             if (zrdata(Secbuf, KSIZE) == GOTCRCW) {
  509.                stohdr(0L);
  510.                 purgeline();    /* dump impatient questions */
  511.                 do {
  512.                     zshhdr(ZCOMPL, Txhdr);
  513.                zperr("Waiting for ZFIN",FALSE);
  514.                if (opabort())
  515.                   return NERROR;
  516.                 }
  517.                 while (++Errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  518.                 ackbibi();
  519.                 return ZCOMPL;
  520.             }
  521.             zshhdr(ZNAK, Txhdr); 
  522.             goto again;
  523.         case ZCOMPL:
  524.             goto again;
  525.         default:
  526.             continue;
  527.         case ZFIN:
  528.             ackbibi(); 
  529.             return ZCOMPL;
  530.         case ZCAN:
  531.             return NERROR;
  532.         }
  533.     }
  534.     return 0;
  535. }
  536.  
  537. /*
  538.  * Receive 1 or more files with ZMODEM protocol
  539.  */
  540.  
  541. rzmfile()
  542. {
  543.     static int c;
  544.  
  545.     for (;;) {
  546.       if (opabort())
  547.          return NERROR;
  548.         switch (c = rzfile()) {
  549.         case ZEOF:
  550.         case ZSKIP:
  551.             switch (tryz()) {
  552.             case ZCOMPL:
  553.                 return OK;
  554.             default:
  555.                 return NERROR;
  556.             case ZFILE:
  557.                 break;
  558.             }
  559.             continue;
  560.         default:
  561.             return c;
  562.         case NERROR:
  563.             return NERROR;
  564.         }
  565.     }
  566. }
  567.  
  568. /*
  569.  * Receive a file with ZMODEM protocol
  570.  *  Assumes file name frame is in Secbuf
  571.  */
  572. rzfile()
  573. {
  574.     static int c, n;
  575.     static long rxbytes;
  576.  
  577.     Eofseen=FALSE;
  578.     if (procheader(Secbuf) == NERROR) {
  579.         return (Tryzhdrtype = ZSKIP);
  580.     }
  581.  
  582.     n = 20; 
  583.     rxbytes = 0L;
  584.  
  585.     for (;;) {
  586.       if (opabort())
  587.          return NERROR;
  588.         stohdr(rxbytes);
  589.         zshhdr(ZRPOS, Txhdr);
  590. nxthdr:
  591.         switch (c = zgethdr(Rxhdr, 0)) {
  592.         default:
  593.             return NERROR;
  594.         case ZNAK:
  595.         case TIMEOUT:
  596.             if ( --n < 0) {
  597.                 return NERROR;
  598.             }
  599.         case ZFILE:
  600.             zrdata(Secbuf, KSIZE);
  601.             continue;
  602.         case ZEOF:
  603.             if (rclhdr(Rxhdr) != rxbytes) {
  604.                 /*
  605.                  * Ignore eof if it's at wrong place - force
  606.                  *  a timeout because the eof might have gone
  607.                  *  out before we sent our zrpos.
  608.                  */
  609.                 Errors = 0;  
  610.                 goto nxthdr;
  611.             }
  612.             if (closeit()) {
  613.                 Tryzhdrtype = ZFERR;
  614.                 return NERROR;
  615.             }
  616.          lreport(KBYTES,rxbytes);
  617.          report(BLKCHECK,Crc32?"CRC-32":"CRC-16");
  618.             return c;
  619.         case NERROR:    /* Too much garbage in header search error */
  620.             if ( --n < 0) {
  621.                 return NERROR;
  622.             }
  623.             zmputs(Attn);
  624.             continue;
  625.         case ZDATA:
  626.             if (rclhdr(Rxhdr) != rxbytes) {
  627.                 if ( --n < 0) {
  628.                     return NERROR;
  629.                 }
  630.                 zmputs(Attn);  
  631.                 continue;
  632.             }
  633. moredata:
  634.          lreport(KBYTES,rxbytes);
  635.          report(BLKCHECK,Crc32?"CRC-32":"CRC-16");
  636.             switch (c = zrdata(Secbuf, KSIZE)) {
  637.             case ZCAN:
  638.                 return NERROR;
  639.             case NERROR:    /* CRC error */
  640.                 if ( --n < 0) {
  641.                     return NERROR;
  642.                 }
  643.                 zmputs(Attn);
  644.                 continue;
  645.             case TIMEOUT:
  646.                 if ( --n < 0) {
  647.                     return NERROR;
  648.                 }
  649.                 continue;
  650.             case GOTCRCW:
  651.                 n = 20;
  652.                 putsec(Secbuf, Rxcount);
  653.                 rxbytes += Rxcount;
  654.                 stohdr(rxbytes);
  655. #ifdef   DEBUG
  656.             lreport(BLOCKS,rxbytes);     /* put it any old place */
  657. #endif;
  658.                 zshhdr(ZACK, Txhdr);
  659.                 mcharout(XON);
  660.                 goto nxthdr;
  661.             case GOTCRCQ:
  662.                 n = 20;
  663.                 putsec(Secbuf, Rxcount);
  664.                 rxbytes += Rxcount;
  665.                 stohdr(rxbytes);
  666.                 zshhdr(ZACK, Txhdr);
  667.                 goto moredata;
  668.             case GOTCRCG:
  669.                 n = 20;
  670.                 putsec(Secbuf, Rxcount);
  671.                 rxbytes += Rxcount;
  672.                 goto moredata;
  673.             case GOTCRCE:
  674.                 n = 20;
  675.                 putsec(Secbuf, Rxcount);
  676.                 rxbytes += Rxcount;
  677.                 goto nxthdr;
  678.             }
  679.         }
  680.     }
  681. }
  682.  
  683. /*
  684.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  685.  *   and \335 (break signal)
  686.  */
  687. zmputs(s)
  688. char *s;
  689. {
  690.     static int c;
  691.  
  692.     while (*s) {
  693.       if (opabort())
  694.          return NERROR;
  695.         switch (c = *s++) {
  696.         case '\336':
  697.             wait(1); 
  698.             continue;
  699.         case '\335':
  700.             sendbrk(); 
  701.             continue;
  702.         default:
  703.             mcharout(c);
  704.         }
  705.     }
  706. }
  707.  
  708. sendbrk(){}  /* do later */
  709.  
  710. /*
  711.  * Close the receive dataset, return OK or NERROR
  712.  */
  713. closeit()
  714. {  
  715.    static int status;
  716.  
  717.    status = OK;
  718.    if (Cpindex) {
  719.       status = write(Fd,Cpmbuf,128*roundup(Cpindex,128)) ? OK : NERROR;
  720.       Cpindex = 0;
  721.    }
  722.    if (status == NERROR)
  723.       zperr("Disk write error",TRUE);
  724.     if (fclose(Fd)==NERROR) {
  725.       Fd = 0;
  726.         zperr("File close error",TRUE);
  727.         return NERROR;
  728.     }
  729.     return status;
  730. }
  731.  
  732. /*
  733.  * Ack a ZFIN packet, let byegones be byegones
  734.  */
  735.  
  736. ackbibi()
  737. {
  738.     static int n;
  739.  
  740.     stohdr(0L);
  741.     for (n=3; --n>=0; ) {
  742.         purgeline();
  743.         zshhdr(ZFIN, Txhdr);
  744.         switch (readline(100)) {
  745.         case 'O':
  746.             readline(INTRATIME);    /* Discard 2nd 'O' */
  747.             return;
  748.         case RCDO:
  749.             return;
  750.         case TIMEOUT:
  751.         default:
  752.             break;
  753.         }
  754.     }
  755. }
  756.  
  757. opabort()
  758. {
  759.    Lastkey = getch() & 0xff;
  760.    if (Lastkey == ESC) {
  761.       flush();
  762.       if (!Inhost && !Dialing)
  763.          report(MESSAGE,"Operator abort");
  764.       QuitFlag = TRUE;
  765.    }
  766.    return QuitFlag;
  767. }
  768.    
  769. long
  770. atol(string)
  771. char *string;
  772. {
  773.    static long value, lv;
  774.    static char *p;
  775.    
  776.    value = 0L;
  777.    p = string + strlen(string);     /* end of string */
  778.    while (!isdigit(*p))
  779.       p--;
  780.    for (lv = 1L; isdigit(*p) && p >= string; lv *= 10)
  781.       value += ((*p--) - '0') * lv;
  782.    return value;
  783. }
  784.  
  785. /************************** END OF MODULE 8 *********************************/
  786.