home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d9xx / d995 / xprkermit.lha / XprKermit / source.lha / ckxtio.c < prev    next >
C/C++ Source or Header  |  1993-05-17  |  23KB  |  830 lines

  1. char *ckxv = "XPR tty I/O, 5A(001), 23 Apr 92";
  2.  
  3. /*
  4.  * C K X T I O
  5.  *
  6.  * Terminal I/O functions for the Amiga External Protocol (XPR) version
  7.  * of C Kermit.
  8.  */
  9.  
  10. #include "ckcdeb.h"
  11. #include "ckcker.h"
  12. #include "ckxker.h"
  13. #include "ckxtim.h"
  14.  
  15. extern int local, what, spackets, fsecs, rpktl, spktl, bctu, numerrs, timeouts;
  16.  
  17. extern long ffc, tsecs;
  18.  
  19. extern long (*xupdate) (), (*xswrite) (), (*xfopen) (), (*xfclose) (),
  20.   (*xfread) (), (*xsread) (), (*xchkabort) (void), (*xfnext) (), (*xffirst) (),
  21.   (*xsflush) (void), (*xfwrite) (), (*xgets) (), (*xfinfo) (), (*xunlink)() ,
  22.   (*xsquery) (void), (*xchkmisc) (void), (*xsetserial)();
  23.  
  24. int
  25. ttchk() {
  26.    if (xsquery != NULL)
  27.       return((*xsquery)());
  28.    else
  29.       return 0;
  30. }
  31.  
  32. int
  33. ttclos(int ignore) {
  34.    return 0;
  35. }
  36.  
  37. int
  38. ttfluo(void) {
  39.    return((*xsflush)());
  40. }
  41.  
  42. int
  43. ttgmdm(void) {
  44.    return -3;
  45. }
  46.  
  47. long
  48. ttgspd(void) {
  49.    int x;
  50.  
  51.    x = ((calld(xsetserial, -1L) >> 16) & 255);
  52.    switch(x) {
  53.       case 0:
  54.          return(110L);
  55.       case 1:
  56.          return(300L);
  57.       case 2:
  58.          return(1200L);
  59.       case 3:
  60.          return(2400L);
  61.       case 4:
  62.          return(4800L);
  63.       case 5:
  64.          return(9600L);
  65.       case 6:
  66.          return(19200L);
  67.       case 8:
  68.          return(38400L);
  69.       case 9:
  70.          return(57600L);
  71.       case 10:
  72.          return(76800L);
  73.       case 11:
  74.          return(115200L);
  75.       default:
  76.          return -1;
  77.    }
  78. }
  79.  
  80. int
  81. tthang(void) {
  82.    return 0;
  83. }
  84.  
  85. void
  86. ttimoff(void) {
  87. }
  88.  
  89. #ifdef MYREAD
  90.  
  91. /* Private buffer for myread() and its companions.  Not for use by anything
  92.  * else.  ttflui() is allowed to reset them to initial values.  ttchk() is
  93.  * allowed to read my_count.
  94.  *
  95.  * my_item is an index into mybuf[].  Increment it *before* reading mybuf[].
  96.  *
  97.  * A global parity mask variable could be useful too.  We could use it to
  98.  * let myread() strip the parity on its own, instead of stripping sign
  99.  * bits as it does now.
  100.  */
  101. #define MYBUFLEN 256
  102. static CHAR mybuf[MYBUFLEN];
  103.  
  104. static int my_count = 0;        /* Number of chars still in mybuf */
  105. static int my_item = -1;        /* Last index read from mybuf[] */
  106.  
  107. /* myread() -- Efficient read of one character from communications line.
  108.  *
  109.  * Uses a private buffer to minimize the number of expensive read() system
  110.  * calls.  Essentially performs the equivalent of read() of 1 character, which
  111.  * is then returned.  By reading all available input from the system buffers
  112.  * to the private buffer in one chunk, and then working from this buffer, the
  113.  * number of system calls is reduced in any case where more than one character
  114.  * arrives during the processing of the previous chunk, for instance high
  115.  * baud rates or network type connections where input arrives in packets.
  116.  * If the time needed for a read() system call approaches the time for more
  117.  * than one character to arrive, then this mechanism automatically compensates
  118.  * for that by performing bigger read()s less frequently.  If the system load
  119.  * is high, the same mechanism compensates for that too.
  120.  *
  121.  * myread() is a macro that returns the next character from the buffer.  If the
  122.  * buffer is empty, mygetbuf() is called.  See mygetbuf() for possible error
  123.  * returns.
  124.  *
  125.  * This should be efficient enough for any one-character-at-a-time loops.
  126.  * For even better efficiency you might use memcpy()/bcopy() or such between
  127.  * buffers (since they are often better optimized for copying), but it may not
  128.  * be worth it if you have to take an extra pass over the buffer to strip
  129.  * parity and check for CTRL-C anyway.
  130.  *
  131.  * Note that if you have been using myread() from another program module, you
  132.  * may have some trouble accessing this macro version and the private variables
  133.  * it uses.  In that case, just add a function in this module, that invokes the
  134.  * macro.
  135.  */
  136. #define myread()  (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
  137.  
  138. /* Specification: Push back up to one character onto myread()'s queue.
  139.  *
  140.  * This implementation: Push back characters into mybuf. At least one character
  141.  * must have been read through myread() before myunrd() may be used.  After
  142.  * EOF or read error, again, myunrd() can not be used.  Sometimes more than
  143.  * one character can be pushed back, but only one character is guaranteed.
  144.  * Since a previous myread() must have read its character out of mybuf[],
  145.  * that guarantees that there is space for at least one character.  If push
  146.  * back was really needed after EOF, a small addition could provide that.
  147.  *
  148.  * myunrd() is currently not called from anywhere inside kermit...
  149.  */
  150. #ifdef NOTUSED
  151. myunrd(ch) CHAR ch; {
  152.     if (my_item >= 0) {
  153.     mybuf[my_item--] = ch;
  154.     ++my_count;
  155.     }
  156. }
  157. #endif
  158.  
  159. /* mygetbuf() -- Fill buffer for myread() and return first character.
  160.  *
  161.  * This function is what myread() uses when it can't get the next character
  162.  * directly from its buffer.  First, it calls a system dependent myfillbuf()
  163.  * to read at least one new character into the buffer, and then it returns
  164.  * the first character just as myread() would have done.  This function also
  165.  * is responsible for all error conditions that myread() can indicate.
  166.  *
  167.  * Returns: When OK    => a positive character, 0 or greater.
  168.  *        When EOF    => -2.
  169.  *        When error    => -3, error code in errno.
  170.  *
  171.  * Older myread()s additionally returned -1 to indicate that there was nothing
  172.  * to read, upon which the caller would call myread() again until it got
  173.  * something.  The new myread()/mygetbuf() always gets something.  If it 
  174.  * doesn't, then make it do so!  Any program that actually depends on the old
  175.  * behaviour will break.
  176.  *
  177.  * The older version also used to return -2 both for EOF and other errors,
  178.  * and used to set errno to 9999 on EOF.  The errno stuff is gone, EOF and
  179.  * other errors now return different results, although Kermit currently never
  180.  * checks to see which it was.  It just disconnects in both cases.
  181.  *
  182.  * Kermit lets the user use the quit key to perform some special commands
  183.  * during file transfer.  This causes read(), and thus also mygetbuf(), to
  184.  * finish without reading anything and return the EINTR error.  This should
  185.  * be checked by the caller.  Mygetbuf() could retry the read() on EINTR,
  186.  * but if there is nothing to read, this could delay Kermit's reaction to
  187.  * the command, and make Kermit appear unresponsive.
  188.  *
  189.  * The debug() call should be removed for optimum performance.
  190.  */
  191. int myfillbuf(void);
  192.  
  193. int
  194. mygetbuf(void) {
  195.     my_count = myfillbuf();
  196.     debug(F101, "myfillbuf read", "", my_count);
  197.     if (my_count <= 0)
  198.       return(my_count < 0 ? -3 : -2);
  199.     --my_count;
  200.     return(255 & (int)mybuf[my_item = 0]);
  201. }
  202.  
  203. /* myfillbuf():
  204.  * System-dependent read() into mybuf[], as many characters as possible.
  205.  *
  206.  * Returns: OK => number of characters read, always more than zero.
  207.  *          EOF => 0
  208.  *          Error => -1, error code in errno.
  209.  *
  210.  * If there is input available in the system's buffers, all of it should be
  211.  * read into mybuf[] and the function return immediately.  If no input is
  212.  * available, it should wait for a character to arrive, and return with that
  213.  * one in mybuf[] as soon as possible.  It may wait somewhat past the first
  214.  * character, but be aware that any such delay lengthens the packet turnaround
  215.  * time during kermit file transfers.  Should never return with zero characters
  216.  * unless EOF or irrecoverable read error.
  217.  *
  218.  * Correct functioning depends on the correct tty parameters being used.
  219.  * Better control of current parameters is required than may have been the
  220.  * case in older Kermit releases.  For instance, O_NDELAY (or equivalent) can 
  221.  * no longer be sometimes off and sometimes on like it used to, unless a 
  222.  * special myfillbuf() is written to handle that.  Otherwise the ordinary 
  223.  * myfillbuf()s may think they have come to EOF.
  224.  *
  225.  * If your system has a facility to directly perform the functioning of
  226.  * myfillbuf(), then use it.  If the system can tell you how many characters
  227.  * are available in its buffers, then read that amount (but not less than 1).
  228.  * If the system can return a special indication when you try to read without
  229.  * anything to read, while allowing you to read all there is when there is
  230.  * something, you may loop until there is something to read, but probably that
  231.  * is not good for the system load.
  232.  */
  233.  
  234. /*
  235.  * Following the example of the Unix code, I have chosen to write the XPR
  236.  * version as follows:  if the xpr_squery exists, then it is called.
  237.  * If it does not exist, or returns 0, then we call xsread of 1 character
  238.  * with a one-second timeout.  Thus, we simply return 0 if no characters
  239.  * arrive in one second, at which point we recheck our overall timeout.
  240.  */
  241.  
  242. int
  243. myfillbuf(void) {
  244.     long avail;
  245.     int x;
  246.  
  247.     if (xsquery)
  248.         avail = (*xsquery)();
  249.     if (!xsquery || avail == 0)
  250.       avail = 1;
  251.  
  252.     if (avail > MYBUFLEN)
  253.       avail = MYBUFLEN;
  254.  
  255.     return(calladd(xsread, mybuf, avail, 1000000L));
  256. }
  257.  
  258.  
  259. #endif /* MYREAD */
  260.  
  261. /*  T T F L U I  --  Flush tty input buffer */
  262.  
  263. int
  264. ttflui() {
  265.  
  266. #ifdef MYREAD
  267. /*
  268.   Flush internal MYREAD buffer *FIRST*, in all cases.
  269. */
  270.     my_count = 0;            /* Reset count to zero */
  271.     my_item = -1;            /* And buffer index to -1 */
  272. #endif /* MYREAD */
  273.  
  274.     if (xsflush)
  275.         (void) (*xsflush)();
  276.     return(0);
  277. }
  278.  
  279. /*
  280.  * T T I N L
  281.  *
  282.  * Return a line in the buffer pointed to by s from the serial line.
  283.  * The line must end with eol and be no longer than max characters.
  284.  * timeout is a timeout interval in seconds.
  285.  *
  286.  * Returns
  287.  *    > 0    Success--number of characters read
  288.  *    = 0    Shouldn't happen!
  289.  *     -1    Timeout
  290.  *    -2    Error of some other kind
  291.  *
  292.  * This version for XPR Kermit.  We ignore negative returns from
  293.  * the xpr_sread() function, preferring to take care of these
  294.  * via the timeout mechanism.
  295.  */
  296. int ttinl(CHAR *s, int max, int timeout, CHAR eol)
  297. {
  298.    int x = 0;
  299.    long i;
  300.    struct timerequest *Timereq;
  301.    unsigned mask;
  302.    extern int parity;
  303.  
  304.    if (xchkmisc)
  305.       (void) (*xchkmisc)();
  306.    *s = '\0';
  307.    mask = (parity ? 0177 : 0377);
  308.    /*
  309.     * Set up and post timer request for overall timeout.
  310.     * As a compromise between correct and efficient, I only check
  311.     * the overall timeout if a one-character read with a one second
  312.     * timeout fails first.
  313.     */
  314.    if (!(Timereq = CreateTimer(UNIT_VBLANK)))
  315.            return -1;
  316.    Timereq->tr_time.tv_secs = timeout;
  317.    Timereq->tr_time.tv_micro = 0;
  318.    Timereq->tr_node.io_Command = TR_ADDREQUEST;
  319.    SendIO((struct IORequest *) Timereq);
  320. #ifndef MYREAD
  321.    /*
  322.     * Willy Langeveld assures me that, since serial.device does its
  323.     * own buffering, calling xsread once for each character isn't
  324.     * going to take too long.
  325.     *
  326.     */
  327.    for (x = 0; x < max; ) {
  328.       if ((i = calladd(xsread, s, 1L, 1000000L)) < 0) {
  329.          if (chkint() < 0) {
  330.             x =  -2;
  331.             goto leave;
  332.          }
  333.       } else if (i == 1) {
  334.          x++;
  335.          if ((*s++ &= mask) == eol)
  336.             break;
  337.       } else if (CheckIO((struct IORequest *) Timereq)) { /* timeout */
  338.          x = -1;                 /* Flag timeout abort */
  339.          goto leave;
  340.       }
  341.    }
  342.    *s = '\0';                              /* Normal termination */
  343. leave:                                     /* Common cleanup code */
  344.    AbortIO((struct IORequest *) Timereq);
  345.    WaitIO((struct IORequest *) Timereq);
  346.    DeleteTimer(Timereq);
  347.    return(x);
  348. #else
  349.    /*
  350.     * Despite the comment above, the myread() macro significantly improves
  351.     * performance on terminal emulators whose xpr_sread() is not as finely
  352.     * tuned, apparently as VLT's.  Term 3.n comes to mind...
  353.     */
  354.  
  355.    for (x = 0; x < max; ) {
  356.       if ((i = myread()) < -1) {
  357.          /*
  358.           * The following code deals with the case that
  359.           * xsread() returns a negative value if the
  360.           * user has clicked on the "Cancel File" or
  361.           * "Cancel Batch" gadgets.  However, we don't
  362.           * want to abort receiving the current packet
  363.           * in this case;  calling chkint() now sets
  364.           * the global cx and/or cz flags, but in the
  365.           * case of a complete abort, chkint() returns
  366.           * a negative value.
  367.           */
  368.          if (chkint() < 0) {
  369.             x = -2;         /* Error */
  370.             goto leave;
  371.          } else if (CheckIO((struct IORequest *) Timereq)) { /* timeout */
  372.             x = -1;                 /* Flag timeout abort */
  373.             goto leave;
  374.          }
  375.       } else if (i >= 0) {           /* Successful get of character */
  376.          x++;
  377.          *s = i;
  378.          if ((*s++ &= mask) == eol)
  379.             break;
  380.       }
  381.    }
  382.    *s = '\0';                /* Normal termination */
  383. leave:                    /* Common cleanup code */
  384.    AbortIO((struct IORequest *) Timereq);
  385.    WaitIO((struct IORequest *) Timereq);
  386.    DeleteTimer(Timereq);
  387.    if (chkint() < 0)
  388.        return -2;
  389.    return(x);
  390. #endif /*MYREAD*/
  391. }
  392.  
  393. int
  394. ttinc(int ttimo) {
  395. #ifndef MYREAD
  396.    unsigned char ch;
  397. #else
  398.    int n;
  399. #endif /*MYREAD*/
  400.  
  401. #ifdef MYREAD
  402.    n = myread();
  403.    return (n < 0 ? n : n & 0377);
  404. #else
  405.    if (calladd(xsread, &ch, 1, ttimo*1000000L) <= 0)
  406.       return -1;
  407.    return(ch);
  408. #endif /*MYREAD*/
  409. }
  410.  
  411. int
  412. ttoc(char c) {
  413.    if (callad(xswrite, &c, 1) == 0L)
  414.       return 1;
  415.    else
  416.       return -1;
  417. }
  418.  
  419. int
  420. ttol(CHAR *s, int n) {
  421.    if (callad(xswrite, s, n) == 0L)
  422.       return n;
  423.    else
  424.       return -1;
  425. }
  426.  
  427. int
  428. ttopen(char *ttname, int *lcl, int modem, int timo) {
  429.    return 0;
  430. }
  431.  
  432. int
  433. ttpkt(long speed, int flow, int parity) {
  434.    return 0;
  435. }
  436.  
  437. int
  438. ttres(void) {
  439.    return 0;
  440. }
  441.  
  442. int
  443. ttscarr(int carrier) {
  444.    return carrier;
  445. }
  446.  
  447. int
  448. ttsndb(void) {
  449.    return 0;
  450. }
  451.  
  452. int
  453. ttsndlb(void) {
  454.    return 0;
  455. }
  456.  
  457. int
  458. ttsspd(int cps) {
  459.    return 0;
  460. }
  461.  
  462. int
  463. ttvt(long speed, int flow) {
  464.    return 0;
  465. }
  466.  
  467. int
  468. ttwmdm(int mdmsig, int timo) {
  469.    return -3;
  470. }
  471.  
  472. int
  473. ttxin(int n, CHAR *buf) {
  474. #ifdef MYREAD
  475.    int c, i;
  476. #endif
  477.  
  478. #ifdef MYREAD
  479.    for (i = 0; i < n; i++) {
  480.       c = myread();
  481.       if (c < 0)
  482.          return i;
  483.       *buf++ = c & 0377;
  484.    }
  485.    return n;
  486. #else
  487.    return(calladd(xsread, buf, n, 0L));
  488. #endif /*MYREAD*/
  489. }
  490.  
  491. void
  492. ztime(char **s) {
  493.    *s = "Ddd Mmm 00 00:00:00 0000\n";    /* Return dummy in asctime() format */
  494. }
  495.  
  496. int
  497. msleep(int m) {
  498.    struct timeval tv;
  499.  
  500.    tv.tv_secs = m/1000;
  501.    tv.tv_micro = (m % 1000)*1000;
  502.    return(MyDelay(&tv, 0L));
  503. }
  504.  
  505. int
  506. sleep(int m) {
  507.    return(msleep(1000*m));
  508. }
  509.  
  510. static struct timeval now, elapsed;
  511.  
  512. void
  513. rtimer(void) {
  514.    GetSysTime(&now);
  515. }
  516.  
  517. int
  518. gtimer(void) {
  519.    GetSysTime(&elapsed);
  520.    return((((1000000L*elapsed.tv_secs + elapsed.tv_micro) - 
  521.         (1000000L*now.tv_secs + now.tv_micro)) + 500000L)/1000000L);
  522. }
  523.  
  524. int
  525. sysinit(void) {
  526.    return 0;
  527. }
  528.  
  529. int
  530. syscleanup(void) {
  531.    return 0;
  532. }
  533.  
  534. void
  535. connoi(void) {
  536. }
  537.  
  538. int
  539. conoll(char *s) {
  540.    return 0;
  541. }
  542.  
  543. int
  544. conol(char *s) {
  545.    return 0;
  546. }
  547.  
  548. int
  549. conoc(char c) {
  550.    return 1;
  551. }
  552.  
  553. static int oldtyp = 0, olderrs = -1, oldlen = -1, oldffc = 0L, oldtimes = -1;
  554.  
  555. char *                    /* Convert seconds to hh:mm:ss */
  556. hhmmss(long x)
  557. {
  558.     static char buf[10];
  559.     long s, h, m;
  560.     h = x / 3600L;            /* Hours */
  561.     x = x % 3600L;
  562.     m = x / 60L;            /* Minutes */
  563.     s = x % 60L;            /* Seconds */
  564.     if (x > -1L)
  565.       sprintf(buf,"%02ld:%02ld:%02ld",h,m,s);
  566.     else buf[0] = '\0';
  567.     return((char *)buf);
  568. }
  569.  
  570. /*
  571.  * S C R E E N
  572.  *
  573.  * Display status on the screen.  This version is the go-between from
  574.  * what C Kermit needs and what XPR provides.
  575.  */
  576. void
  577. screen(int f, char c, long n, char *s) {
  578.    static struct XPR_UPDATE update;
  579.    static char string[51], time1[15], time2[15];
  580.    static long fsiz = -1L;              /* Copy of file size */
  581.    static long fcnt = 0L;               /* File count */
  582.    static long fbyt = 0L;               /* Total file bytes */
  583.    static char fn[257];            /* Local copy of file name */
  584.  
  585.    update.xpru_updatemask = 0;
  586.    debug(F101,"screen f = ","",f);    /* Handle our function code */
  587.    if (n) debug(F101, "screen n = ", "", n);
  588.    if (s) debug(F110, "screen s = ", s, n);
  589.    switch(f) {
  590.       case SCR_FN:
  591.          if (what == W_SEND)
  592.        sprintf(string, "Sending: %s", s);
  593.      else
  594.        sprintf(string, "Receiving: %s", s);
  595.          update.xpru_filename = string;
  596.          update.xpru_updatemask = XPRU_FILENAME;
  597.          fsiz = -1L;            /* Invalidate file size */
  598.          strncpy(fn, s, 256);
  599.          break;
  600.       case SCR_AN:
  601.          if (what == W_SEND)
  602.        sprintf(string, "Sending: %s as %s", fn, s);
  603.      else
  604.        sprintf(string, "Receiving: %s as %s", fn, s);
  605.          update.xpru_filename = string;
  606.          update.xpru_updatemask = XPRU_FILENAME;
  607.          break;
  608.       case SCR_FS:
  609.          fsiz = update.xpru_filesize = n;
  610.          update.xpru_updatemask = XPRU_FILESIZE;
  611.          break;
  612.       case SCR_ST:
  613.          switch (c) {                   /* Print new status message */
  614.             case ST_OK:                 /* Transfer OK */
  615.                fcnt++;                  /* Count this file */
  616.                if (ffc > 0)             /* For some reason ffc is off by 1 */
  617.                   fbyt += ffc - 1L;     /* Count its bytes */
  618.                strcpy(string, "Transfer OK");
  619.                break;
  620.             case ST_DISC:
  621.                strcpy(string, "File discarded");
  622.                break;
  623.             case ST_INT:
  624.                strcpy(string, "Transfer interrupted");
  625.                break;
  626.             case ST_SKIP:
  627.                strcpy(string, "File skipped");
  628.                break;
  629.             case ST_ERR:
  630.                sprintf(string, "%.50s", s);
  631.                break;
  632.             case ST_REFU:
  633.                strcpy(string, "File refused");
  634.                break;
  635.             case ST_INC:
  636.                strcpy(string, "Incompletely received");
  637.                break;
  638.             default:
  639.                strcpy(string, "screen() called with bad status");
  640.                break;
  641.             }
  642.          if (c == ST_OK) {
  643.             update.xpru_updatemask = XPRU_MSG;
  644.             update.xpru_msg = string;
  645.          } else {
  646.             update.xpru_updatemask = XPRU_ERRORMSG;
  647.             update.xpru_errormsg = string;
  648.          }
  649.          break;
  650.       case SCR_PN:
  651.          update.xpru_blocks = n;
  652.          update.xpru_updatemask = XPRU_BLOCKS;
  653.          break;
  654.       case SCR_PT:
  655.          /*
  656.           * Following the Unix version, we check everything and only
  657.           * update what's actually changed since last time.  The intent
  658.           * is to prevent the screen updates from slowing the file
  659.           * transfers.
  660.           */
  661.          update.xpru_updatemask = 0;
  662.          if (spackets < 5) {
  663.             switch (bctu) {
  664.                case 1:
  665.                   update.xpru_blockcheck = "Sum-6";
  666.                   break;
  667.                case 2:
  668.                   update.xpru_blockcheck = "Sum-12";
  669.                   break;
  670.                case 3:
  671.                   update.xpru_blockcheck = "CRC-16";
  672.                   break;
  673.             }
  674.             update.xpru_updatemask |= XPRU_BLOCKCHECK;
  675.          }
  676.      if ((update.xpru_blocksize = (what == W_RECV) ? rpktl + 1 : spktl +
  677.                1) != oldlen) {
  678.             update.xpru_updatemask |= XPRU_BLOCKSIZE;
  679.             oldlen = update.xpru_blocksize;
  680.          }
  681.      update.xpru_blocks = spackets;
  682.      update.xpru_updatemask |= XPRU_BLOCKS;
  683.      if (c != oldtyp && c != 'Y' && c != 'N' && c != '%') {
  684.         oldtyp = update.xpru_packettype = c;
  685.         update.xpru_updatemask |= XPRU_PACKETTYPE;
  686.      }
  687.      if (numerrs != olderrs) {
  688.         olderrs = update.xpru_errors = numerrs;
  689.         update.xpru_updatemask |= XPRU_ERRORS;
  690.      }
  691.      if (ffc != oldffc) {
  692.         oldffc = update.xpru_bytes = ffc;
  693.         update.xpru_updatemask |= XPRU_BYTES;
  694.      }
  695.      switch (c) {            /* Now handle specific packet types */
  696.         long x, y;
  697.         case 'S':            /* Beginning of transfer */
  698.            fcnt = fbyt = 0L;    /* Clear counters */
  699.            break;
  700.         case 'D':                     /* Data packet */
  701.            /* fsecs is the time from gtimer() this file started at */
  702.            y = ((unsigned) gtimer() - fsecs); /* Secs so far */
  703.            strcpy(time1, hhmmss(y));
  704.            update.xpru_elapsedtime = time1;
  705.            update.xpru_updatemask |= XPRU_ELAPSEDTIME;
  706.            if (y > 0) {
  707.               update.xpru_datarate = ((10L * ffc)/y)/10L;
  708.               update.xpru_updatemask |= XPRU_DATARATE;
  709.            }
  710.            if (y > 0L && fsiz > 0L && ffc > 0L) {    /* Update expected time so on */
  711.               x = (y*fsiz)/ffc;
  712.               strcpy(time2, hhmmss(x));
  713.               update.xpru_expecttime = time2;
  714.               update.xpru_updatemask |= XPRU_EXPECTTIME;
  715.            }
  716.            break;
  717.         case 'E':                /* Error packet */
  718.            if (*s) {                        /* Print its data field */
  719.                   update.xpru_errormsg = s;
  720.               update.xpru_updatemask |= XPRU_ERRORMSG;
  721.            }
  722.            fcnt = fbyt = 0;                 /* No bytes for this file */
  723.            break;
  724.         case 'Q':
  725.            update.xpru_errormsg = "Damaged packet";
  726.            update.xpru_updatemask |= XPRU_ERRORMSG;
  727.            break;
  728.         case 'T':
  729.            update.xpru_errormsg = "Timeout";
  730.            update.xpru_updatemask |= XPRU_ERRORMSG;
  731.            if ((update.xpru_timeouts = timeouts) != oldtimes) {
  732.               update.xpru_updatemask |= XPRU_TIMEOUTS;
  733.               oldtimes = timeouts;
  734.            }
  735.            break;
  736.         default:
  737.            break;
  738.         }
  739.      break;
  740.       case SCR_TC:
  741.          if (tsecs > 0)
  742.             sprintf(string, "Files: %ld, Total Bytes: %ld, %ld cps",
  743.                     fcnt, fbyt, ((fbyt * 10L) / (long) tsecs) / 10L);
  744.          else
  745.             sprintf(string, "Files: %ld, Total Bytes: %ld", fcnt, fbyt);
  746.          update.xpru_msg = string;
  747.          update.xpru_updatemask = XPRU_MSG;
  748.          break;
  749.       case SCR_EM:
  750.          update.xpru_errormsg = s;
  751.          update.xpru_updatemask = XPRU_ERRORMSG;
  752.          break;
  753.       case SCR_QE:                      /* Quantity equals */
  754.       case SCR_TU:                      /* Undelmited text */
  755.       case SCR_TN:                      /* Text delimited at start */
  756.       case SCR_TZ:                      /* Text delimited at end */
  757.          break;
  758.       case SCR_XD:                      /* X packet data */
  759.          update.xpru_filename = s;
  760.          update.xpru_updatemask = XPRU_FILENAME;
  761.          break;
  762.       case SCR_CW:                      /* Close window */
  763.          oldtyp = 0;                    /* Reset these counters for next time */
  764.          olderrs = oldtimes = oldlen = -1;
  765.          oldffc = 0;
  766.          break;
  767.       default:
  768.          break;
  769.    }
  770.    if (update.xpru_updatemask) (void) calla(xupdate, &update);
  771.    return;
  772. }
  773.  
  774. /*
  775.  * This is the XPR Kermit version of chkint.  We allow multiple levels
  776.  * of interrupt, if available.
  777.  */
  778. int
  779. chkint(void) {            /* Check for console interrupts. */
  780.    int x;
  781.    extern int cxseen, czseen;
  782.  
  783.    x = (*xchkabort)();
  784.    switch (x) {
  785.       case 0:                 /* No abort pending */
  786.          return 0;
  787.       case 1:                 /* Abort file only. */
  788.          screen(SCR_TN,0,0l,"Cancelling File ");
  789.          cxseen = 1;
  790.          break;
  791.       case 2:                 /* Abort file and batch. */
  792.          screen(SCR_TN,0,0l,"Cancelling Batch ");
  793.          czseen = 1;
  794.          break;
  795.       case -1:                /* Emergency escape -- kill all */
  796.          return -1;
  797.       default:
  798.          ;
  799. }
  800.    return 1;
  801. }
  802.  
  803. void
  804. intmsg(long n) {
  805.    screen(SCR_TN, 0, 0L, "Interrupt using mouse or keyboard");
  806. }
  807.  
  808. void
  809. ermsg(msg) char *msg; {            /* Print error message */
  810.    if (local)
  811.       screen(SCR_EM,0,0L,msg);
  812.    tlog(F110,"Protocol Error:",msg,0L);
  813. }
  814.  
  815. void
  816. fatal(char *msg) {
  817.    if (local)
  818.       screen(SCR_EM,0,0L,msg);
  819.    tlog(F110,"Fatal Error:",msg,0L);
  820. }
  821.  
  822. void
  823. doclean(void) {
  824. }
  825.  
  826. int
  827. psuspend(int x) {
  828.    return 0;
  829. }
  830.