home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / qnx2.zip / kermit.c < prev    next >
C/C++ Source or Header  |  1995-04-28  |  41KB  |  2,279 lines

  1. /*
  2.     File:        kermit.c
  3.     Purpose:    Reliable File Transfer
  4.     Author:        Frank Da Cruz, et. al
  5.     Editor:        Bill Hullsiek Hullsiek;    21-Jul-1994
  6.  
  7.     Copyright (C) 1985, 1992, Trustees of Columbia University
  8.     in the City of New York.
  9.  
  10.     Permission is granted to any individual or institution to use this
  11.     software as long as it is not sold for profit.  This copyright notice
  12.     must be retained.  This software may not be included in commercial
  13.     products without the written permission of Columbia University.
  14.  
  15.     This code is based on Kermit: A File Transfer Protocol
  16.  
  17.     Portions of this code is derived from the kermit implementation
  18.     under qcp.
  19.  
  20. */
  21.  
  22. #include    <stdio.h>
  23. #include    <stdlib.h>
  24. #include    <io.h>
  25. #include    <dev.h>
  26. #include    <lfsys.h>
  27. #include    <timer.h>
  28. #include    <magic.h>
  29. #include    <taskinfo.h>
  30. #include    <taskmsgs.h>
  31. #include    <portio.h>
  32. #include    <string.h>
  33. #include    <process.h>
  34. #include    <time.h>
  35. #include    <ctype.h>
  36. #include    <setjmp.h>
  37. #include    <signal.h>
  38.  
  39. #define SOH                    0x01
  40. #define    LF                    0x0a
  41. #define    CR                    0x0d
  42. #define    BLANK                ' '
  43.  
  44. #define    MAXSP                2048
  45. #define    MAXRP                2048
  46. #define MAXBUF                MAXRP + 100
  47. #define MAX_STD_PKT            94
  48. #define AVG_FBLKS            20
  49. #define MAX_NC                (AVG_FBLKS * FBLK_SIZE)
  50. #define    MAXTRY                5
  51.  
  52. #define tochar(ch)            (((ch) + ' ') & 0x7f )
  53. #define unchar(ch)            ((ch) - ' ')
  54. #define ctl(ch)                ((ch) ^ 64 )
  55. #define unpar(ch)            ((ch) & 127)
  56.  
  57. #define BEGIN(x)        change_state(x)
  58. #define    RESUME            if (server) { SERVE } else if (cx == 1) return (-1); else return (0)
  59. #define SERVE            tinit(); BEGIN(sserv);
  60. #define    ERR(x)            terror(x); zerror(); if (server) { SERVE } else return (-1);
  61.  
  62. /* Kermit states */
  63.  
  64. enum sttype {     stnull,
  65.                 ssini, ssfil, ssdat, sseot, sseof,
  66.                 srini, srfil, srdat, srgen,
  67.                 sserv, ssgen,
  68.                 sipkt }
  69.  
  70. state = stnull;
  71.  
  72. char    strbuf [500] = "\0";
  73.  
  74. int        spsiz    = MAXSP;
  75. int        rpsiz    = MAXRP;
  76. int        timint    = 5;
  77. int        rtimo    = 7;
  78. int        rpadn    = 0;
  79. int        spadn    = 0;
  80. int        bctr    = 3;
  81. int        bctu    = 1;
  82. int        ebq        = '&';
  83. int        ebqflg    = 0;
  84. int        rqf        = -1;
  85. int        rq        = 0;
  86. int        sq        = 'Y';
  87. int        rpt        = 0;
  88. int        rptq    = '~';
  89. int        rptflg    = 0;
  90. int        capas    = 10;
  91. int        atcapb    = 8;
  92. int        atcapr    = 0;
  93. int        atcapu    = 0;
  94. int        swcapb    = 4;
  95. int        swcapr    = 0;
  96. int        swcapu    = 0;
  97. int        lpcapb    = 2;
  98. int        lpcapr    = 1;
  99. int        lpcapu    = 0;
  100.  
  101. char    spadc    = 0;
  102. char    rpadc    = 0;
  103. char    seol    = '\r';
  104. char    reol    = '\r';
  105. char    rctlq    = '#';
  106. char    sctlq    = '#';
  107. char    ssc        = 0;
  108. char    smark    = SOH;
  109. char    rmark    = SOH;
  110.  
  111. int        seq        = 0;
  112. int        size;
  113. int        osize;
  114. int        maxsiz;
  115. int        rln;
  116. int        rsn;
  117. int        limit            = MAXTRY;
  118. int        sndpkl;
  119. char    sndpkt [MAXBUF];
  120. char    rcvpkt [MAXBUF];
  121. char    *rdatap            = NULL;
  122. char    data [MAXRP+1];
  123. char    *isp             = NULL;
  124. char    *osp             = NULL;
  125.  
  126. FILE    *ifp            = NULL;
  127. FILE    *ofp            = NULL;
  128.  
  129. char    filname        [FILENAME_MAX]    = "";
  130. char    mfilname    [FILENAME_MAX]    = "";
  131. char    ofp_name    [FILENAME_MAX]    = "";
  132. char    ifp_name    [FILENAME_MAX]    = "";
  133. int        nfils            = 0;
  134. int        cc                = 0;    /* control-c */
  135. int        cx                = 0;
  136. int        cz                = 0;
  137. int        xflag            = 0;
  138. int        xpkt            = 0;
  139. int        filcnt            = 0;
  140. int        delay            = 10;
  141. int        mfile            = 0;
  142.  
  143. int        text            = 1;
  144. int        local            = 0;
  145. int        debug            = 0;
  146. int        server            = 0;
  147. int        srv_flg            = 0;
  148. int        first            = 0;
  149. int        recno            = 0;
  150. int        keep            = 0;
  151. char    start            = 0;
  152. int        nakstate        = 0;
  153.  
  154. /* statistics */
  155.  
  156. unsigned long    nspkts    = 0;
  157. unsigned long    nrpkts    = 0;
  158. unsigned long    nnpkts    = 0;
  159. unsigned long    nfchars    = 0;
  160. unsigned long    nschars    = 0;
  161. unsigned long    npchars    = 0;
  162. unsigned long    nrchars    = 0;
  163.  
  164. /* Command Parser */
  165.  
  166. char        **xargv            = NULL;
  167. int            xargc             = 0;
  168. char        *cmarg            = NULL;
  169. char        **cmlist        = NULL;
  170. char        cmbuf [CMD_LINE_SIZE];
  171. char        action            = 0;
  172.  
  173. /* Communication Line */
  174.  
  175. FILE        *tty_ifp;
  176. FILE        *tty_ofp;
  177. unsigned    tty_ifp_opt;
  178. unsigned    tty_ofp_opt;
  179. unsigned    std_opt;
  180. int            parity = 0;
  181. char        ttname [L_tmpnam]        = "$mdm";
  182.  
  183. void usage()
  184. {
  185.     fprintf (stderr, "C-Kermit for QNX-2   21-July-1994  \n\n");
  186.     fprintf (stderr, "kermit -xfrsgtRlip123h\n\n");
  187.     fprintf (stderr, "kermit -x              <server>\n");
  188.     fprintf (stderr, "       -f              <finish>\n");
  189.     fprintf (stderr, "       -r              <receive>\n");
  190.     fprintf (stderr, "       -s filename     <send>\n");
  191.     fprintf (stderr, "       -m filename     <move>\n");
  192.     fprintf (stderr, "       -g filename     <get>\n");
  193.     fprintf (stderr, "       -t filename     <remote type>\n");
  194.     fprintf (stderr, "       -R path1 path2  <remote rename>\n");
  195.     fprintf (stderr, "       -C command      <remote command>\n");
  196.     fprintf (stderr, "       -l device       <device>\n");
  197.     fprintf (stderr, "       -i              <image binary>\n");
  198.     fprintf (stderr, "       -d              <debug mode>\n");
  199.     fprintf (stderr, "       -{1,2,3}        <block check type>\n");
  200.     fprintf (stderr, "       -p {e,o,m,s,n}  <set parity>\n");
  201.     fprintf (stderr, "       -h              <help>\n");
  202. }
  203.  
  204. void tmsg (char *s)        /* put message on the console */
  205. {
  206.     if (s != NULL)
  207.         fputs (s, stdout);
  208.  
  209.     fflush   (stdout);
  210. }
  211.  
  212. void tmsgn (int n)            /* put number on the console */
  213. {
  214.     fprintf (stdout, "%d", n);
  215.     fflush  (stdout);
  216. }
  217.  
  218. void tmsgl (char *s)        /* put message on the console */
  219. {
  220.     if (s != NULL)
  221.         fputs (s, stdout);
  222.  
  223.     fputc ('\n', stdout);
  224.     fflush   (stdout);
  225. }
  226.  
  227. void tchar (char c)            /* display a single character on the console */
  228. {
  229.     fputc (c, stdout);
  230.     fflush   (stdout);
  231. }
  232.  
  233. void tstate (enum sttype state)
  234. {
  235.     switch (state)    {
  236.         case    stnull:        tmsg ("stnull");        break;
  237.         case    ssini:        tmsg ("ssini");            break;
  238.         case    ssfil:        tmsg ("ssfil");            break;
  239.         case    ssdat:        tmsg ("ssdat");            break;
  240.         case    sseot:        tmsg ("sseot");            break;
  241.         case    sseof:        tmsg ("sseof");            break;
  242.         case    srini:        tmsg ("srini");            break;
  243.         case    srfil:        tmsg ("srfil");            break;
  244.         case    srdat:        tmsg ("srdat");            break;
  245.         case    srgen:        tmsg ("srgen");            break;
  246.         case    sserv:        tmsg ("sserv");            break;
  247.         case    ssgen:        tmsg ("ssgen");            break;
  248.         case    sipkt:        tmsg ("sipkt");            break;
  249.         default:            tmsg ("unknown state");
  250.     }
  251. }
  252.  
  253. void tstats (char *s)            /* display statistics */
  254. {
  255.     float    percent;
  256.  
  257.     if (nfchars == 0)
  258.         percent = 0.0;
  259.     else
  260.         percent = ((float) nschars / (float) nfchars) * 100;
  261.  
  262.     fprintf (stdout, "Char sent: %5U",         nschars);
  263.     fprintf (stdout, "; Pckt sent %5U",     nspkts);
  264.     fprintf (stdout, ", resent: %5U",       nrpkts);
  265.     fprintf (stdout, "; percent = %3.0f ",    percent);
  266.     if (debug)
  267.         fprintf (stdout, "\n");
  268.     else
  269.         fprintf (stdout, "%s",     s);
  270.  
  271.     fflush  (stdout);
  272. }
  273.  
  274. int    tt_is_console (FILE *tty_ifp)
  275. {
  276.     int        tty_devno;
  277.     int        std_devno;
  278.     int        tty_tid;
  279.     int        std_tid;
  280.     char    mdm_name [L_tmpnam];
  281.     char    std_name [L_tmpnam];
  282.  
  283.     tty_devno    = fdevno (tty_ifp);
  284.     std_devno    = fdevno (stdin);
  285.     tty_tid        = query_device (tty_devno, mdm_name);
  286.     std_tid        = query_device (std_devno, std_name);
  287.  
  288.     if (tty_devno != std_devno)        /* different device than standard input */
  289.         return (1);
  290.  
  291.     else if (tty_tid != std_tid)    /* different owner */ 
  292.         return (1);
  293.  
  294.     else
  295.         return (0);                    /* standard input device */
  296. }
  297.  
  298. int ttopen (char *name)            /* open communication line */
  299. {
  300.     int        local;
  301.  
  302.     local = 0;
  303.     if (strchr (name, '$') == NULL) {
  304.         tty_ifp    = stdin;
  305.         tty_ofp    = stdout;
  306.     }
  307.  
  308.     else if ((tty_ifp = fopen (name, "r")) == NULL)
  309.         error ("Invalid input device '%s'. \r\l", name);
  310.  
  311.     else if ((tty_ofp = fopen (name, "w")) == NULL) 
  312.         error ("Invalid output device '%s'. \r\l", name);
  313.  
  314.     else if (tt_is_console (tty_ifp))
  315.         local = 1;
  316.  
  317.     else {
  318.         fclose (tty_ifp);
  319.         fclose (tty_ofp);
  320.         tty_ifp = stdin;
  321.         tty_ofp = stdout;
  322.     }
  323.  
  324.     return (local);
  325. }
  326.  
  327. int ttread (int i, int max_nc, int ticks)    /* read a terminal line */
  328. {
  329.     int nc;
  330.  
  331.     iotime_set (tty_ifp, ticks);
  332.     nc = fget (&(rcvpkt[i]), max_nc, tty_ifp);
  333.     iotime_can (tty_ifp);
  334.     rcvpkt [i+nc+1] = '\0';
  335.  
  336.     return (nc);
  337. }
  338.  
  339. void ttres()            /* restore original communications */
  340. {
  341.     set_option (tty_ifp, tty_ifp_opt);
  342.     set_option (tty_ofp, tty_ofp_opt);
  343. }
  344.  
  345. void ttclos()
  346. {
  347.     fclose (tty_ifp);
  348.     fclose (tty_ofp);
  349. }
  350.  
  351. int ttpkt ()                            /* condition for packet i/o */
  352. {
  353.     unsigned    option;
  354.  
  355.     tty_ifp_opt = get_option (tty_ifp);
  356.     tty_ofp_opt = get_option (tty_ofp);
  357.  
  358.     option = tty_ifp_opt;
  359.     option = option & ~ECHO;
  360.     option = option & ~EDIT;
  361.     option = option & ~MAPCR;
  362.  
  363.     if (option & HFLOW) {
  364.         option = option | IFLOW;
  365.         option = option | OFLOW;
  366.     }
  367.  
  368.     set_option (tty_ifp, option);
  369.  
  370.     flush_input (tty_ifp);
  371.  
  372.     fflush (tty_ofp);
  373. }
  374.  
  375.  
  376.  
  377. void ttflui()        /* Flush input line */
  378. {
  379.     flush_input (tty_ifp);
  380. }
  381.  
  382. int ttol (char s[], int n)    /* output a line */
  383. {
  384.     int    m;
  385.  
  386.     m = fput (s, n, tty_ofp);
  387.     fflush (tty_ofp);
  388.     return (m);
  389. }
  390.  
  391. int ttsspd (int speed)        /* verify speed */
  392. {
  393.     if (speed == 300)
  394.         return (1);
  395.  
  396.     else if (speed = 1200)
  397.         return (1);
  398.  
  399.     else if (speed = 2400)
  400.         return (1);
  401.     
  402.     else if (speed = 4800)
  403.         return (1);
  404.  
  405.     else if (speed = 9600)
  406.         return (1);
  407.  
  408.     else if (speed = 19200)
  409.         return (1);
  410.  
  411.     else
  412.         return (0);
  413.  
  414. }
  415.  
  416. int    zgetc (text)             /* Get a character from input file */
  417. {
  418.     static int                bp    = -1;        /* push-back pointer */
  419.     static unsigned char     buf [MAX_NC];
  420.     static int                c     = 0;
  421.     static int                 i     = 0;
  422.     static int                nc    = 0;
  423.     static unsigned char    pbbuf [4];        /* push-back buffer */
  424.  
  425.     if (bp >= 0) {                /* first return any pushed-back data */
  426.         c = pbbuf [bp];
  427.         bp--;
  428.     }
  429.  
  430.     else if (cx == 1) {            /* Return error message if interrupted */
  431.         c = -1;
  432.     }
  433.  
  434.     else {
  435.         i++;
  436.         if (i >= nc) {          /* read a buffer of data */
  437.             i = 0;
  438.             nc = fget (buf, MAX_NC, ifp);
  439.             if (nc < 0) {
  440.                 cx = 1;        /* treat read error as interruption of file */
  441.                 tmsgl ("zgetc: read error -- interrupt");
  442.             }
  443.         }
  444.  
  445.         if (i >= nc) {
  446.             c = -1;
  447.         }
  448.  
  449.         else {
  450.             nschars++;
  451.             c = buf [i];
  452.  
  453.             if ((text == 1) && (c == '\n')) {
  454.                 c = CR;
  455.                 bp++;
  456.                 pbbuf [bp] = LF;
  457.             }
  458.         }
  459.     }
  460.  
  461.     if (c == -1) {
  462.         bp = -1;
  463.         nc = 0;
  464.     }
  465.  
  466.     return (c);
  467. }
  468.  
  469. int zputc (int c, int text)
  470. {
  471.     int x;
  472.  
  473.     c &= 255;
  474.     if (text && c == CR) {
  475.         return (0);
  476.     }
  477.  
  478.     else if (text && c == LF) {
  479.         nrchars++;
  480.         x = putc ('\n', ofp);
  481.         return (0);
  482.     }
  483.  
  484.     else {
  485.         nrchars++;
  486.         x = putc (c, ofp) & 255;
  487.         if (c == 255)
  488.             return (0);
  489.  
  490.         return ((x != c) ? -1 : 0);
  491.     }
  492. }
  493.  
  494. int zopeni (char *name)        /* open local file for input */
  495. {
  496.     static struct dir_entry dir;
  497.  
  498.     strcpy (ifp_name, name);
  499.  
  500.     ifp = fopen (name, "r");
  501.     if (ifp == NULL)
  502.         return (-1);
  503.  
  504.     else if (get_dir_entry (ifp, &dir) != 0) {
  505.         error ("Can't read directory entry for %s \n", name);
  506.         return (-1);
  507.     }
  508.  
  509.     else {
  510.         nschars = 0;
  511.         nfchars = (dir.fnum_blks + 1) * FBLK_SIZE;
  512.         nfchars = nfchars - (dir.fnum_xtnt * XTNT_HDR);
  513.         if (dir.fnum_chars_free & 0x400)
  514.             nfchars = nfchars - (dir.fnum_chars_free ^ 0x400);            
  515.  
  516.         return (0);
  517.     }
  518. }
  519.  
  520. int zopeno (char *name)            /* open local file for output */
  521. {
  522.     strcpy (ofp_name, name);
  523.  
  524.     nrchars    = 0;
  525.     ofp = fopen (name, "w");
  526.     if (ofp == NULL)
  527.         return (-1);
  528.     else
  529.         return (0);
  530. }
  531.  
  532. int zclosi()
  533. {
  534.     if (fclose (ifp) == EOF)
  535.         return (-1);
  536.  
  537.     else {
  538.         ifp = NULL;
  539.         return (0);
  540.     }
  541. }
  542.  
  543. int zcloso (int x)
  544. {
  545.     if (fclose (ofp) == EOF)
  546.         return (-1);
  547.  
  548.     else {
  549.         ofp = NULL;
  550.         return (0);
  551.     }
  552.  
  553.     if (x != 0)
  554.         remove (ofp_name);
  555. }
  556.  
  557. void zerror()
  558. {
  559.     if (ifp != NULL)
  560.         zclosi();
  561.  
  562.     if (ofp != NULL)
  563.         zcloso(cx | cz);
  564. }
  565.  
  566.  
  567. int zltor (char *local, char *remote)
  568. {
  569.     char    *p;
  570.     char    *np;
  571.  
  572.     p = local;
  573.     if ( *p == '[' ) {                    /* Skip over the node number    */
  574.         while (*p  &&  *p != ']')
  575.             p++;
  576.     }
  577.  
  578.     if (*p == '$')                         /* Can't prepend a device name    */
  579.         return (-1);
  580.  
  581.  
  582.     if (*p && *(p+1) == ':')             /* Skip over the drive number    */
  583.         p += 2;
  584.  
  585.     while (np = strchr (p + 1, '/')) {    /* skip over the path */
  586.         np++;
  587.         p = np;
  588.     }
  589.  
  590.     if (*p == 0)
  591.         return (-1);
  592.  
  593.     while (*p != '\0')  {
  594.         if (islower (*p) == 0)
  595.             *remote = *p;
  596.         else
  597.             *remote = toupper(*p);
  598.  
  599.         p++;
  600.         remote++;
  601.     }
  602.  
  603.     *remote = '\0';
  604.  
  605. }
  606.  
  607. int zrtol (char *remote, char *local)
  608. {
  609.     for ( ; *remote != '\0'; remote++, local++) {
  610.         *local = (isupper(*remote)) ? tolower (*remote) : * remote;
  611.     }
  612.  
  613.     *local = '\0';
  614.     if (strlen (local) > NCPFN)        /* truncate names */
  615.         local = '\0';
  616. }
  617.  
  618. /* ----------- Presentation Layer ------------ */
  619.  
  620. char *bldlen (char *str, char *dest) {
  621.     int    len;
  622.  
  623.     len = strlen(str);
  624.     *dest = len + 32;
  625.     strcpy (dest+1, str);
  626.     return (dest+len+1);
  627. }
  628.  
  629. char *setgen (char type, char *arg1, char *arg2, char *arg3)
  630. {
  631.     char    *upstr;
  632.     char    *cp;
  633.  
  634.     cp    = cmbuf;
  635.     *cp++ = type;
  636.     *cp   = '\0';
  637.     if (*arg1 != '\0') {
  638.         upstr = bldlen (arg1, cp);
  639.         if (*arg2 != '\0') {
  640.             upstr = bldlen (arg2, upstr);
  641.             if (*arg3 != '\0') {
  642.                 bldlen (arg3, upstr);
  643.             }
  644.         }
  645.     }
  646.  
  647.     return (cmbuf);
  648. }
  649.  
  650. int gnchar() 
  651. {
  652.     int    c;
  653.  
  654.     if (isp == NULL)
  655.         c = zgetc (text);
  656.  
  657.     else if (*isp == '\0')
  658.         c = -1;
  659.  
  660.     else 
  661.         c = *isp++;
  662.  
  663.     return (c);
  664. }
  665.  
  666. int pnchar (int c)
  667. {
  668.     nrchars++;
  669.  
  670.     if (xflag) {
  671.         tchar (c);
  672.         return (1);
  673.     }
  674.  
  675.     else if (osp) {
  676.         *osp++ = c;
  677.         return (1);
  678.     }
  679.  
  680.     else
  681.         return (zputc(c, text));
  682. }
  683.  
  684. void encode (int a, int next)
  685. {
  686.     int        a7, b8;
  687.  
  688.     if (rptflg) {
  689.         if (a == next) {
  690.             if (++rpt < MAX_STD_PKT) {
  691.                 return;
  692.             }
  693.             else if (rpt == MAX_STD_PKT) {
  694.                 data [size++] = rptq;
  695.                 data [size++] = tochar (rpt);
  696.                 rpt = 0;
  697.             }
  698.         }
  699.         else if (rpt == 1) {
  700.             rpt = 0;
  701.             encode (a, -1);
  702.             if (size <= maxsiz) osize = size;
  703.             rpt = 0;
  704.             encode (a, -1);
  705.             return;
  706.         }
  707.         else if (rpt > 1) {
  708.             data [size++] = rptq;
  709.             data [size++] = tochar (++rpt);
  710.             rpt = 0;
  711.         }
  712.     }
  713.  
  714.     a7 = a & 127;
  715.     b8 = a & 128;
  716.  
  717.     if (ebqflg && b8) {
  718.         data [size++] = ebq;
  719.         a = a7;
  720.     }
  721.  
  722.     if (a7 < 32 || a7 == 127) {
  723.         data [size++] = sctlq;
  724.         a = ctl (a);
  725.     }
  726.     else if (a7 == sctlq) {
  727.         data [size++] = sctlq;
  728.     }
  729.     else if (ebqflg && a7 == ebq) {
  730.         data [size++] = sctlq;
  731.     }
  732.     else if (rptflg && a7 == rptq) {
  733.         data [size++] = sctlq;
  734.     }
  735.  
  736.     data [size++] =  a;
  737.     data [size]   = '\0';
  738. }
  739.  
  740. int getpkt (int maxlen)
  741. {
  742.     int        next;
  743.     static int     c;
  744.     static int    n;
  745.     static unsigned char remain [10];
  746.  
  747.     size = 0;
  748.     data [size] = '\0';
  749.  
  750.     if (first == 1) {
  751.         n = -1;    
  752.         c = gnchar();
  753.         if (c < 0) {
  754.             first = -1;
  755.             return (size);
  756.         }
  757.         first = 0;
  758.     }
  759.     else if (first == -1) {
  760.         return (size);
  761.     }
  762.  
  763.     while (n >= 0) 
  764.         data [size++] = remain [n--];
  765.  
  766.     rpt = 0;
  767.     while (first > -1)  {
  768.         npchars++;
  769.         next = gnchar();
  770.         if (next < 0)     first = -1;
  771.  
  772.         osize = size;
  773.         encode (c, next);
  774.         c = next;
  775.  
  776.         if (size == maxlen) 
  777.             return (size);
  778.  
  779.         if (size > maxlen) {
  780.             for ( ; size > osize; size--)
  781.                 remain [++n] = data [size-1];
  782.  
  783.             size = osize;
  784.             data [size] = '\0';    
  785.             return (size);
  786.         }
  787.     }
  788.     return (size);
  789. }
  790.  
  791. int decode()
  792. {
  793.     int    a, a7, b8;
  794.  
  795.     while ((a = *rdatap++) != '\0') {
  796.         rpt = 1;
  797.         if (rptflg) {
  798.             if (a == rptq) {
  799.                 rpt = unchar (*rdatap++);
  800.                 a = *rdatap++;
  801.             }
  802.         }
  803.         b8 = 0;
  804.         if (ebqflg) {
  805.             if (a == ebq) {
  806.                 b8 = 128;
  807.                 a = *rdatap++;
  808.             }
  809.         }
  810.  
  811.         if (a == rctlq) {
  812.             a = *rdatap++;
  813.             a7 = a & 127;
  814.             if (a7 > 62 && a7 < 96)
  815.                 a = ctl (a);
  816.         }
  817.  
  818.         a |= b8;
  819.         for (; rpt > 0; rpt--)
  820.             if (pnchar(a) < 0) return (-1);
  821.     }
  822.  
  823.     return (0);
  824. }
  825.  
  826. int encstr (char *s)
  827. {
  828.     first = 1;
  829.     isp = s;
  830.     getpkt (spsiz);
  831.     isp = NULL;
  832.     return (size);
  833. }
  834.  
  835. void decstr (char *s)
  836. {
  837.     osp = s;
  838.     decode();
  839.     *osp = '\0';
  840.     osp = NULL;
  841. }
  842.  
  843. /* ----------- Tranport Layer ----------- */
  844.  
  845. int nxtpkt (int seq) 
  846. {
  847.     return ( (seq + 1) & 63 );
  848. }
  849.  
  850. void tinit()
  851. {
  852.     seq         = 0;
  853.     sndpkl        = 0;
  854.     *filname     = '\0';
  855.     *sndpkt        = '\0';
  856.     *rcvpkt        = '\0';
  857.  
  858.     ebqflg        = 0;
  859.     sq            = 'Y';
  860.     rqf            = -1;
  861.     bctu        = 1;
  862.     rptflg        = 0;
  863.  
  864.     xflag         = 0;
  865.     xpkt        = 0;
  866.     osp         = NULL;
  867.  
  868.     nspkts        = 0;
  869.     nrpkts        = 0;
  870.     nnpkts        = 0;
  871. }
  872.  
  873. int chksum (char *p)
  874. {
  875.     unsigned int m; long s;
  876.  
  877.     m = (parity)  ? 0177 : 0377;
  878.  
  879.     for (s = 0; *p != '\0'; *p++) 
  880.         s += *p & m;
  881.  
  882.     return ((int) s & 077777);
  883. }
  884.  
  885. int chkl (char *packet)
  886. {
  887.  
  888.     int        s, t;
  889.  
  890.     s = chksum (packet);
  891.     t = (((s & 192) >> 6) + s) & 63;
  892.     return (t);
  893. }
  894.  
  895. int chk3 (char *s)
  896. {
  897.  
  898. #include "ccitt.crc"
  899.  
  900.     long c, crc;
  901.  
  902.     crc = 0;
  903.     while ((c = *s++) != '\0') {
  904.         if (parity)
  905.             c &= 0x7f;
  906.  
  907.         crc = crctable [ ( c ^ crc ) & 0xff ] ^ ( crc >> 8 );
  908.     }
  909.     return ((int) crc);
  910. }
  911.  
  912. int spack (char type, int n, int len, char *data)
  913. {
  914.     int    chklen, i, j, k;
  915.  
  916.     if (type == 'S' || type == 'I')
  917.         chklen = 1;
  918.     else
  919.         chklen = bctu;
  920.  
  921.     if (debug) {
  922.         tmsg  ("spack:");
  923.         tmsg  (" type = ");    tchar (type);
  924.         tmsg  (" n = ");    tmsgn (n);
  925.         tmsg  (" len = ");    tmsgn (len);
  926.         tmsg  (" chk = ");  tmsgn (chklen);
  927.         tmsg  (" data <");    tmsg  (data);         tmsgl (">");
  928.     }
  929.  
  930.     i = 0;
  931.     while (i < spadn)
  932.         sndpkt [i++] = spadc;
  933.  
  934.     sndpkt [i++] = smark;
  935.     k = i++;
  936.     sndpkt [i++] = tochar (n); 
  937.     sndpkt [i++] = type;
  938.     j = len + chklen;
  939.  
  940.     if (j <= MAX_STD_PKT-2)
  941.         sndpkt [k] = tochar (j+2);
  942.  
  943.     else {
  944.         sndpkt [k]     = tochar (0);
  945.         sndpkt [i++] = tochar (j / 95);
  946.         sndpkt [i++] = tochar (j % 95);
  947.         sndpkt [i]   = '\0';
  948.         sndpkt [i++] = tochar (chkl(sndpkt+k));
  949.     }
  950.  
  951.     sndpkt [i] = '\0';
  952.  
  953.     if (len > 0) {
  954.         memmove (sndpkt+i, data, len);
  955.         i = i + len;
  956.     }
  957.  
  958.     sndpkt [i] = '\0';
  959.  
  960.     switch (chklen) {
  961.         case 1:
  962.             sndpkt [i++] = tochar (chkl (sndpkt+k));
  963.             break;
  964.  
  965.         case 2:
  966.             j = chksum (sndpkt+k);
  967.             sndpkt [i++] = tochar ((j >> 6)  & 077);
  968.             sndpkt [i++] = tochar ( j        & 077);
  969.             break;
  970.  
  971.         case 3:
  972.             j = chk3 (sndpkt+k);
  973.             sndpkt [i++] = tochar ((j >> 12) & 017);
  974.             sndpkt [i++] = tochar ((j >> 6)  & 077);
  975.             sndpkt [i++] = tochar ( j        & 077);
  976.             break;
  977.  
  978.         default:
  979.             error ("spack: block check type (chklen) = %d \n", chklen);
  980.     }
  981.  
  982.     sndpkt [i++] = seol;
  983.     sndpkt [i] = '\0';
  984.     sndpkl = i;
  985.  
  986.     i = ttol (sndpkt, sndpkl);
  987.  
  988.     return (i);
  989. }
  990.  
  991. int    nak()
  992. {
  993.     int    x;
  994.     x = spack ('N', seq, 0, "");
  995.     return (x);
  996. }
  997.  
  998. int resend()                        /* resend a packet */
  999. {
  1000.     int    x;
  1001.  
  1002.     if (sndpkl > 0) {
  1003.         nrpkts++;
  1004.         x = ttol (sndpkt, sndpkl);
  1005.         if (local && !xflag)
  1006.             tstats (" (resend) \r");
  1007.     }
  1008.  
  1009.     else if (nakstate == 1) {
  1010.         nnpkts++;
  1011.         x = nak();
  1012.     }
  1013.     else
  1014.         x = 0;
  1015.  
  1016.     return (x);
  1017. }
  1018.  
  1019. int serror (char *s)
  1020. {
  1021.     int    nc;
  1022.  
  1023.     nc = spack('E', seq, strlen(s), s);
  1024.  
  1025.     return (nc);
  1026.  
  1027. }
  1028.  
  1029. void terror (char *s) 
  1030. {
  1031.     if (server)
  1032.         serror (s);
  1033.  
  1034.     else if (local) {
  1035.         tmsg ("\nError: ");
  1036.         tmsgl (s);
  1037.     }
  1038.  
  1039.     return;
  1040. }
  1041.  
  1042. void trap_signal()
  1043. {
  1044.     if (local) 
  1045.         tmsgl ("\nControl-C interrupt of file transfer");
  1046.  
  1047.     cx = 1;        /* handle clean-up */
  1048.     cc = 1;
  1049. }
  1050.  
  1051. int    ack()
  1052. {
  1053.     int    x;
  1054.  
  1055.     x = spack ('Y', seq, 0, "");
  1056.     seq = nxtpkt (seq);
  1057.     return (x);
  1058. }
  1059.  
  1060. int ackl (char *s)
  1061. {
  1062.     int    x;
  1063.  
  1064.     x = spack ('Y', seq, strlen(s), s);
  1065.     seq = nxtpkt (seq);
  1066.     return (x);
  1067. }
  1068.  
  1069. int rpack ()        /* read packet and return packet type */
  1070. {
  1071.     int     chklen    = 0;
  1072.     int     g        = 0;
  1073.     char    hcheck    = '\0';
  1074.     int        lenx1    = 0;
  1075.     int        lenx2    = 0;
  1076.     int        i        = 0;
  1077.     int        j         = 0;
  1078.     int        max_nc    = 1;
  1079.     int        nc        = 0;
  1080.     char     pbc[4];
  1081.     int        rlnpos    = 0;
  1082.  
  1083. enum pkt_states { null_pkt, pkt_start, pkt_hdr, pkt_data, pkt_eol, pkt_end } 
  1084.     state = null_pkt;
  1085.  
  1086.     int        ticks    = 0;
  1087.     char    type    = 'T';
  1088.     int        x        = 0;
  1089.  
  1090.     ticks        = rtimo * 20;        /* 20 ticks per second */
  1091.     rsn         = -1;
  1092.     rln            = -1;
  1093.     rdatap         = NULL;
  1094.  
  1095.     while (state != pkt_end) {
  1096.         if (cc) {
  1097.             type = 'Q';
  1098.             state = pkt_end;
  1099.         }
  1100.  
  1101.         else if (i+max_nc > MAXBUF) {
  1102.             error ("rpack: overflow = %d characters \n", nc);
  1103.             type = 'Q';
  1104.             state = pkt_end;
  1105.         }
  1106.  
  1107.         else if ((nc = ttread (i, max_nc, ticks)) < max_nc)  {
  1108.             type = 'T';
  1109.             state = pkt_end;
  1110.         }
  1111.  
  1112.         else switch (state) {
  1113.             case null_pkt:    if (rcvpkt [i] == rmark) {
  1114.                                 state = pkt_start;    
  1115.                                 i++;
  1116.                             }
  1117.                             else
  1118.                                 g++;
  1119.                             break;
  1120.  
  1121.             case pkt_start: if (rcvpkt [i] == rmark) {
  1122.                                 /* do nothing */
  1123.                             }
  1124.                             else { 
  1125.                                 rlnpos    = i;
  1126.                                 rln        = unchar(rcvpkt[i++]);
  1127.                                 state    = pkt_hdr;
  1128.                                 if (rln == 0) 
  1129.                                     max_nc = 5;        /* extended hdr */
  1130.  
  1131.                                 else if (rln == 1) {
  1132.                                     terror ("rpack: extended hdr 1 \n");
  1133.                                     type = 'Q';
  1134.                                     state = pkt_end;
  1135.                                 }
  1136.  
  1137.                                 else if (rln == 2) {
  1138.                                     terror ("rpack: extended hdr 2 \n");
  1139.                                     type = 'Q';
  1140.                                     state = pkt_end;
  1141.                                 }
  1142.  
  1143.                                 else 
  1144.                                     max_nc = 2;        /* normal hdr */
  1145.                             }
  1146.                             break;
  1147.  
  1148.             case pkt_hdr:    rsn        = unchar(rcvpkt [i+0]);
  1149.                             type    = rcvpkt [i+1];
  1150.                             if (type == 'I' || type == 'S') 
  1151.                                 chklen = 1;
  1152.                             else
  1153.                                 chklen = bctu;
  1154.  
  1155.                             if (rln > 2)
  1156.                                 rln = rln - 2;
  1157.  
  1158.                             else {
  1159.                                 lenx1    = rcvpkt [i+2];
  1160.                                 lenx2    = rcvpkt [i+3];
  1161.                                 hcheck    = rcvpkt [i+4];
  1162.                                 rcvpkt [i+4] = '\0';
  1163.                                 if (unchar (hcheck) != chkl(rcvpkt+rlnpos)) {
  1164.                                     terror ("rpack: bad header checksum \n");
  1165.                                     type = 'Q';
  1166.                                     state = pkt_end;
  1167.                                 }
  1168.  
  1169.                                 rcvpkt [i+4] = hcheck;
  1170.  
  1171.                                 rln    = (95 * unchar(lenx1)) + unchar(lenx2);
  1172.                             }
  1173.  
  1174.                             max_nc    = rln;
  1175.                             rln        = rln - chklen;
  1176.                             i         = i + nc;
  1177.                             j        = i + rln;
  1178.                             rdatap    = rcvpkt + i;
  1179.  
  1180.                             state = pkt_data;
  1181.                             break;
  1182.  
  1183.             case pkt_data:    i = i + nc;
  1184.                             max_nc = 1;
  1185.                             if (rcvpkt[i] == reol)
  1186.                                 state = pkt_end;
  1187.                             else
  1188.                                 state = pkt_eol;
  1189.                             break;
  1190.  
  1191.             case pkt_eol:    if (rcvpkt[i] == reol)
  1192.                                 state = pkt_end;
  1193.                             else
  1194.                                 i++;
  1195.  
  1196.                             break;
  1197.  
  1198.             case pkt_end:    terror ("rpack: invalid state \n");
  1199.                             break;
  1200.         
  1201.         }
  1202.     }
  1203.  
  1204.     /* perform checksum */
  1205.                                 
  1206.     for (x = 0; x < chklen; x++)
  1207.         pbc [x] = rcvpkt [j+x];
  1208.  
  1209.     rcvpkt [j] = '\0'; 
  1210.  
  1211.     switch (chklen) {
  1212.         case 0:    break;    /* bad packet */
  1213.  
  1214.         case 1:
  1215.             if (unchar (pbc[0]) != chkl (rcvpkt+rlnpos)) {
  1216.                 if (debug)
  1217.                     tmsgl ("rpack: checksum 1 problem");
  1218.                 type = 'Q';
  1219.             }
  1220.             break;
  1221.  
  1222.         case  2:
  1223.             x = unchar (pbc[0]) << 6 | unchar (pbc[1]);
  1224.             if (x != chksum (rcvpkt+rlnpos)) {
  1225.                 if (debug)
  1226.                     tmsgl ("rpack: checksum 2 problem");
  1227.                 type = 'Q';
  1228.             }
  1229.             break;
  1230.  
  1231.         case  3:
  1232.             x = unchar (pbc[0]) << 12 | unchar (pbc[1]) << 6 | unchar (pbc[2]);
  1233.             if (x != chk3 (rcvpkt+rlnpos)) {
  1234.                 if (debug)
  1235.                     tmsgl ("rpack: checksum 3 problem");
  1236.                 type = 'Q';
  1237.             }
  1238.             break;
  1239.  
  1240.         default:
  1241.             error ("rpack: block check type (chklen) = %d \n", chklen);
  1242.     }
  1243.  
  1244.     if (debug) {
  1245.         tmsg  ("rpack:");
  1246.         tmsg  (" g = ");    tmsgn (g);
  1247.         tmsg  (" i = ");    tmsgn (i);
  1248.         tmsg  (" j = ");    tmsgn (j);
  1249.  
  1250.         if (chklen != bctu) {
  1251.             tmsg  (" chklen = ");
  1252.             tmsgn (chklen);
  1253.         }
  1254.  
  1255.         tmsg  (" rln = ");     tmsgn (rln);
  1256.         tmsg  (" type = ");    tchar (type);
  1257.         tmsg  (" rsn = ");    tmsgn (rsn);
  1258.         tmsg  (" data <");
  1259.         if (rdatap != NULL)
  1260.             tmsg (rdatap);    
  1261.  
  1262.         tmsgl (">");
  1263.     }
  1264.  
  1265.     return (type);
  1266. }
  1267.  
  1268. void spar (char *s)                /* set parameters */
  1269. {
  1270.     int    x;
  1271.  
  1272.     s--;
  1273.  
  1274.     x = (rln >= 1) ? unchar(s[1]) : 80;
  1275.     spsiz = (x < 10) ? 80 : x;
  1276.  
  1277.     x = (rln >= 2) ? unchar(s[2]) : 5;
  1278.     timint = (x < 0) ? 5 : x;
  1279.  
  1280.     spadn = 0; spadc = '\0';
  1281.     if (rln >= 3) {
  1282.         spadn = unchar (s[3]);
  1283.         if (rln >= 4)
  1284.             spadc = ctl(s[4]);
  1285.         else
  1286.             spadc = 0;
  1287.     }
  1288.  
  1289.     seol = (rln >= 5) ? unchar (s[5]) : '\r';
  1290.     if ((seol < 2) || (seol > 31))
  1291.         seol = '\r';
  1292.  
  1293.     x = (rln >= 6) ? s[6] : '#';    
  1294.     rctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
  1295.     
  1296.     rq = (rln >= 7) ? s [7] : 0;
  1297.     if (rq == 'Y')
  1298.         rqf = 1;
  1299.  
  1300.     else if ((rq > 32 && rq < 63) || (rq > 96 && rq < 127)) 
  1301.         rqf = 2;
  1302.  
  1303.     else
  1304.         rqf = 0;
  1305.  
  1306.     x = 1;
  1307.     if (rln >= 8) {
  1308.         x = s[8] - '0';
  1309.         if ((x < 1) || (x > 3)) x = 1;
  1310.     }
  1311.     bctr = x;
  1312.  
  1313.     if (bctr < 1 || bctr > 3)
  1314.         error ("spar: Received bad block check \n");
  1315.  
  1316.     if (bctu < 1 || bctu > 3)
  1317.         error ("spar: bctu out of range \n");
  1318.  
  1319.     switch (rqf) {
  1320.         case 0:        ebqflg = 0;    break;
  1321.         case 1:        if (parity) { ebqflg = 1; ebq = '&'; } break;
  1322.         case 2:        if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
  1323.     }
  1324.  
  1325.     if (rln < 9) 
  1326.         rptflg    = 0;
  1327.  
  1328.     else {
  1329.         rptq    = s [9];
  1330.         rptflg    = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
  1331.     }
  1332.  
  1333.     atcapu = lpcapu = swcapu = 0;
  1334.     if (rln >= 10) {
  1335.         x = unchar (s[10]);
  1336.         atcapu = (x & atcapb) && atcapr;
  1337.         lpcapu = (x & lpcapb) && lpcapr;
  1338.         swcapu = (x & swcapb) && swcapr;
  1339.  
  1340.         for (capas = 10; (unchar (s[capas]) & 1) && (rln >= capas); capas++) 
  1341.             ;
  1342.     }
  1343.  
  1344.     if (atcapu) {
  1345.         error ("spar: file attributes not supported \n");
  1346.     }
  1347.  
  1348.     if (swcapu) {
  1349.         error ("spar: sliding windows not supported \n");
  1350.     }
  1351.  
  1352.     if (lpcapu) {
  1353.         if (rln > capas+2) {
  1354.             spsiz = (unchar (s[capas+2]) * 95) + unchar (s[capas+3]);
  1355.             if (spsiz > MAXSP)
  1356.                 spsiz = MAXSP;
  1357.         }
  1358.     }
  1359.  
  1360.     if (spsiz > MAX_STD_PKT)
  1361.         maxsiz = spsiz - bctr - 6;
  1362.     else
  1363.         maxsiz = spsiz - bctr - 3;
  1364. }
  1365.  
  1366. int    rinit()
  1367. {
  1368.  
  1369. }
  1370.  
  1371. char *rpar ()
  1372. {
  1373.     int    x;
  1374.  
  1375.     data [1]    = tochar (MAX_STD_PKT);
  1376.     data [2]    = tochar (rtimo);
  1377.     data [3]    = tochar (rpadn);
  1378.     data [4]    = ctl (rpadc);
  1379.     data [5]    = tochar (reol);
  1380.     data [6]    = '#';
  1381.  
  1382.     switch (rqf) {
  1383.  
  1384.         case -1:
  1385.         case  1: if (parity) ebq = sq = '&'; break;
  1386.         case  0:
  1387.         case  2: break;
  1388.     }
  1389.  
  1390.     data [7]    = sq;
  1391.     data [8]    = bctr + '0';
  1392.  
  1393.     if (rptflg)
  1394.         data [9] = rptq;
  1395.     else
  1396.         data [9] = '~';
  1397.  
  1398.     x = atcapr ? atcapb : 0 | lpcapr ? lpcapb : 0 | swcapr ? swcapb : 0;
  1399.     data [10] = tochar (x);
  1400.     data [11] = tochar (0);    /* window size */
  1401.  
  1402.     data [12] = tochar (rpsiz / 95);
  1403.     data [13] = tochar (rpsiz % 95);
  1404.  
  1405.     data [14] = '\0';
  1406.  
  1407.     return (data+1);
  1408. }
  1409.  
  1410. int    sinit (char c)
  1411. {
  1412.     char    *s;
  1413.  
  1414.     s = rpar();
  1415.     if (local == 0 && c == 'S' && server == 0) {
  1416.         tmsgl ("Escape back to local system, give RECEIVE command...");
  1417.         sleep (delay);
  1418.     }
  1419.  
  1420.     return (spack (c, seq, strlen(s), s));
  1421. }
  1422.  
  1423. char sfile ()
  1424. {
  1425.  
  1426.     int    x;
  1427.     char pktnam [FILENAME_MAX];
  1428.  
  1429.     if (zopeni (filname) < 0)
  1430.         return (-1);
  1431.  
  1432.     zltor (filname, pktnam);
  1433.     x = encstr (pktnam);
  1434.  
  1435.     if (mfile) {
  1436.         strcpy (mfilname, filname);
  1437.     }
  1438.  
  1439.     if (local) {
  1440.         if (mfile)
  1441.             tmsg ("Moving ");
  1442.         else
  1443.             tmsg ("Sending ");
  1444.         tmsg (filname);
  1445.         tmsg (" as ");
  1446.         tmsg (pktnam);
  1447.         if (parity)
  1448.             tmsgl (" with parity. \n");
  1449.         else
  1450.             tmsgl (" ");
  1451.     }
  1452.     first = 1;
  1453.  
  1454.     seq = nxtpkt (seq);
  1455.  
  1456.     return (spack((xpkt ? 'X' : 'F'), seq, x, data));
  1457.  
  1458. }
  1459.  
  1460. int    sdata()
  1461. {
  1462.     int    x;
  1463.  
  1464.     x = getpkt (maxsiz);
  1465.     if (x == 0) {
  1466.         return (0);
  1467.     }
  1468.  
  1469.     if (cx) {
  1470.         return (0);
  1471.     }
  1472.  
  1473.     seq = nxtpkt (seq);
  1474.  
  1475.     x = spack ('D', seq, x, data);
  1476.  
  1477.     return  (x);
  1478. }
  1479.  
  1480. int    seof (char *s)
  1481. {
  1482.     seq = nxtpkt (seq);
  1483.     if (zclosi () < 0)
  1484.         *s = 'D';
  1485.  
  1486.     return (spack ('Z', seq, strlen(s), s));
  1487. }
  1488.  
  1489. int seot () 
  1490. {
  1491.     seq = nxtpkt (seq);
  1492.     if (local && *cmarg == '\0')
  1493.         tmsgl ("\nDone");
  1494.  
  1495.     return (spack ('B', seq, 0, ""));
  1496.  
  1497. }
  1498.  
  1499. int scmd (char t, char *s)
  1500. {
  1501.     int    x;
  1502.  
  1503.     if (local) {
  1504.         tmsg ("Remote command: ");
  1505.         tmsgl (s);
  1506.     }
  1507.  
  1508.     x = encstr (s);
  1509.     spack (t, seq, x, data);
  1510. }
  1511.  
  1512. int    gnfile()
  1513. {
  1514.     if (cz) {
  1515.         return (0);
  1516.     }
  1517.  
  1518.     else if (nfils-- <= 0) {
  1519.         return (0);
  1520.     }
  1521.  
  1522.     else if (**cmlist == '-')
  1523.         return (0);
  1524.  
  1525.     else {
  1526.         strcpy (filname, *cmlist++);
  1527.         return (1);
  1528.     }
  1529. }
  1530.  
  1531. int rcvfil()
  1532. {
  1533.     char    myname [FILENAME_MAX];
  1534.  
  1535.     decstr (filname);
  1536.     zrtol (filname, myname);
  1537.     if (zopeno (myname) < 0)
  1538.         return (-1);
  1539.  
  1540.     else {
  1541.         if (local && !xflag) {
  1542.             tmsg ("Receiving ");
  1543.             tmsg (filname);
  1544.             tmsg (" as ");
  1545.             tmsgl (myname);
  1546.         }
  1547.         return (0);
  1548.     }
  1549. }
  1550.  
  1551. int closof()
  1552. {
  1553.     int x;    
  1554.  
  1555.     if (xflag)
  1556.         return (0);
  1557.  
  1558.     decstr (strbuf);
  1559.     x = strncmp (strbuf, "D", 1) | cx | cz;
  1560.  
  1561.     if (zcloso (x) < 0)
  1562.         return (-1);
  1563.  
  1564.     return (0);
  1565. }
  1566.  
  1567. int input() 
  1568. {
  1569.     int    type, try;    
  1570.  
  1571.     if (start != 0) {
  1572.         type     = start;
  1573.         start    = 0;
  1574.         return (type);
  1575.     }
  1576.  
  1577.     type = rpack();
  1578.  
  1579.     for (try = 0; rsn != seq || strchr("TQN", type); try++) {
  1580.         if (cc) 
  1581.             return ('T');
  1582.  
  1583.         if (try > limit) 
  1584.             return ('T');
  1585.  
  1586.         if (type == 'N' && rsn == nxtpkt (seq)) 
  1587.             return ('Y');
  1588.  
  1589.         else if (type == 'T' && state == sserv) {
  1590.             /* do nothing */
  1591.         }
  1592.  
  1593.         else if (type == 'E') 
  1594.             return ('E');
  1595.  
  1596.         else 
  1597.             resend();
  1598.  
  1599.         type = rpack();
  1600.     }     
  1601.  
  1602. /*    ttflui();   */
  1603.  
  1604.     return (type);
  1605. }
  1606.  
  1607. void change_state (enum sttype new_state)
  1608. {
  1609.     state = new_state;
  1610.     if (debug) {
  1611.         tmsg ("Change state to ");
  1612.         tstate (new_state);
  1613.         tmsgl (".");
  1614.     }
  1615.  
  1616.     return;
  1617. }
  1618.  
  1619. int yylex()
  1620. {
  1621.     int ss, type, x;
  1622.  
  1623.     while (cc == 0) {
  1624.         type = input();
  1625.  
  1626.         if (debug) {
  1627.             tmsg  ("yylex:");
  1628.             tmsg  (" type = ");        tchar (type);
  1629.             tmsg  (" state = ");    tstate (state);
  1630.             tmsgl (" ");
  1631.         }
  1632.  
  1633.         if (type == 's') {                        /* send state */
  1634.             tinit();
  1635.             if (sinit('S') < 0) {
  1636.                 ERR("sinit -- Could not initialize link");
  1637.             }
  1638.  
  1639.             else {
  1640.                 nakstate = 0;
  1641.                 filcnt = 0;
  1642.                 BEGIN(ssfil);
  1643.             }
  1644.         }
  1645.  
  1646.         else if (type == 'v') {                    /* receive state */
  1647.             tinit();
  1648.             nakstate = 1;
  1649.             rinit();
  1650.             BEGIN(srini);
  1651.         }
  1652.  
  1653.         else if (type == 'r') {                    /* get */
  1654.             tinit();
  1655.             ssc = 0;
  1656.             sinit ('I');
  1657.             BEGIN(sipkt);
  1658.         }
  1659.  
  1660.         else if (type == 'c') {                    /* host */
  1661.             tinit();
  1662.             ssc = 'C';
  1663.             sinit ('I');
  1664.             BEGIN(sipkt);
  1665.         }
  1666.  
  1667.         else if (type == 'g') {                  /* generic */
  1668.             tinit();
  1669.             ssc = 'G';
  1670.             sinit('I');
  1671.             BEGIN(sipkt);
  1672.         }
  1673.  
  1674.         else if (type == 'x') {                    /* server */
  1675.             server = 1;
  1676.             SERVE;
  1677.         }
  1678.  
  1679.         else if (type == 'Y' && (state == ssfil || state == sseof))  {
  1680.  
  1681.             if (state == sseof) {
  1682.                 if (local && !xflag)
  1683.                     tstats (" (sseof)  \r");
  1684.  
  1685.                 if (cx == 1) {
  1686.                     /* do not delete file if interrupted */
  1687.                 }
  1688.  
  1689.                 else if (*cmarg != '\0') {
  1690.                     /* start a command sequence at eot */
  1691.                 }
  1692.  
  1693.                 else if (mfile == 0)  {
  1694.                     /* only delete if mfile is set */
  1695.                 }
  1696.  
  1697.                 else if (remove (mfilname) == 0) {
  1698.                     tmsg  ("\n");
  1699.                     tmsg  (mfilname);
  1700.                     tmsgl (" removed after successful transfer");
  1701.                 }
  1702.                 else {
  1703.                     tmsg  ("\nError: ");
  1704.                     tmsg  (mfilname);
  1705.                     tmsgl (" could not be removed\n");
  1706.                 }
  1707.             }
  1708.             if (filcnt++ == 0)
  1709.                 spar (rdatap);
  1710.  
  1711.             cx = 0;
  1712.             bctu = bctr;
  1713.  
  1714.             if (gnfile() > 0) {
  1715.                 if (sfile() < 0) {
  1716.                     ERR("Could not open file to send");
  1717.                 }
  1718.  
  1719.                 else {
  1720.                     BEGIN(ssdat);
  1721.                 }
  1722.             }
  1723.  
  1724.             else if (seot() < 0) {
  1725.                 ERR("seot");
  1726.             }
  1727.  
  1728.             else {
  1729.                 BEGIN(sseot);
  1730.             }
  1731.         }
  1732.  
  1733.         else if (type == 'Y' && state == ssdat) {
  1734.             nspkts++;
  1735.             if (local && !xflag) 
  1736.                 tstats (" (ssdat)  \r");
  1737.  
  1738.             decstr (strbuf);
  1739.             if (strbuf[0] == 'X') {
  1740.                 cx = 1;
  1741.                 if (local && !xflag)
  1742.                     tmsgl ("File Transfer interrupted by Ctrl-X");
  1743.             }            
  1744.             else if (strbuf[0] == 'Z') {
  1745.                 cz = 1;
  1746.                 if (local && !xflag)
  1747.                     tmsgl ("File Transfer interrupted by Ctrl-Z");
  1748.             }
  1749.  
  1750.             x = sdata();
  1751.             if (x < 0) {
  1752.                 ERR("sdata");
  1753.             }
  1754.  
  1755.             else if (x == 0) {
  1756.                 if (seof((cx | cz) ? "D" : "") < 0) {
  1757.                     ERR("seof");
  1758.                 }
  1759.  
  1760.                 else {
  1761.                     BEGIN(sseof);
  1762.                 }
  1763.             }
  1764.         }
  1765.  
  1766.         else if (type == 'Y' && state == sseot) {
  1767.             if (*cmarg != '\0') 
  1768.                 start = 'c';
  1769.             else {
  1770.                  RESUME;
  1771.             }
  1772.         }
  1773.  
  1774.         /* Receiver States */
  1775.  
  1776.         else if (type == 'S' && state == srini) {
  1777.             spar (rdatap);
  1778.             ackl (rpar());
  1779.             bctu = bctr;
  1780.             nakstate = 1;
  1781.             BEGIN(srfil);
  1782.         }
  1783.  
  1784.         else if (type == 'B' && state == srfil) {
  1785.             ack();
  1786.             RESUME;
  1787.         }
  1788.  
  1789.         else if (type == 'F' && state == srfil) {
  1790.             if (rcvfil() < 0) {
  1791.                 ERR("rcvfil");
  1792.             }
  1793.  
  1794.             else {
  1795.                 ack();
  1796.                 nakstate = 1;
  1797.                 BEGIN(srdat);
  1798.             }
  1799.         }
  1800.  
  1801.         else if (type == 'D' && state == srdat) {
  1802.             if (decode() < 0) {
  1803.                 ERR("decode");
  1804.             }
  1805.  
  1806.             else {
  1807.                 ack();
  1808.             }
  1809.         }
  1810.  
  1811.         else if (type == 'T' && state == srdat) {
  1812.             cx = 1;
  1813.             ERR("Timeout in srdat state");
  1814.         }
  1815.  
  1816.         else if (type == 'Z' && state == srdat) {
  1817.             if (closof() < 0) {
  1818.                 ERR("closof");
  1819.             }
  1820.  
  1821.             else {
  1822.                 if (cx)
  1823.                     ackl ("X");
  1824.  
  1825.                 else if (cz)
  1826.                     ackl ("Z");
  1827.  
  1828.                 else
  1829.                     ack();
  1830.  
  1831.                 state = srfil;
  1832.             }
  1833.         }
  1834.  
  1835.         /* Client states */
  1836.  
  1837.         else if (type == 'Y' && state == sipkt) {
  1838.             spar(rdatap);
  1839.             start = 'E';
  1840.         }
  1841.  
  1842.         else if (type == 'E' && state == sipkt) {
  1843.             if (ssc) {
  1844.                 if (scmd (ssc, cmarg) < 0) {
  1845.                     ERR("scmd");
  1846.                 }
  1847.  
  1848.                 else {
  1849.                     ssc = 0;
  1850.                     nakstate = 1;
  1851.                     BEGIN(srgen);
  1852.                 }
  1853.             }
  1854.             else {
  1855.                 if (scmd ('R', cmarg) < 0) {
  1856.                     ERR("scmd");
  1857.                 }
  1858.  
  1859.                 else {
  1860.                     nakstate = 1;
  1861.                     BEGIN(srini);
  1862.                 }
  1863.             }
  1864.         }
  1865.  
  1866.         else if (type == 'Y' && state == srgen) {
  1867.             xflag = 1;
  1868.             decode();
  1869.             RESUME;
  1870.         }
  1871.  
  1872.         else if (type == 'S' && state == srgen) {
  1873.             spar (rdatap);
  1874.             ackl (rpar());
  1875.             bctu = bctr;
  1876.             nakstate = 1;
  1877.             BEGIN(srfil);
  1878.  
  1879.             /* When remote command has been ack'd, check -move flag */
  1880.  
  1881.             if (mfile == 1) {
  1882.                 if (remove (mfilname) == 0) {
  1883.                     tmsg  ("\n");
  1884.                     tmsg  (mfilname);
  1885.                     tmsgl (" removed after successful transfer");
  1886.                 }
  1887.                 else {
  1888.                     tmsg  ("\nError: ");
  1889.                     tmsg  (mfilname);
  1890.                     tmsgl (" could not be deleted\n");
  1891.                 }
  1892.             }
  1893.         }
  1894.  
  1895.         /* Server states */
  1896.  
  1897.         else if (type == 'T' && state == sserv) {
  1898.             if (local)
  1899.                 tmsgl ("Kermit: waiting...");
  1900.         }
  1901.  
  1902.         else if (type == 'X' && (state == srgen || state == srfil)) {
  1903.             xflag = 1;
  1904.             ack();
  1905.             nakstate = 1;
  1906.             BEGIN(srdat);
  1907.         }
  1908.  
  1909.         else if (type == 'I' && state == sserv) {
  1910.             spar (rdatap);
  1911.             ackl (rpar());
  1912.             seq = 0;
  1913.         }
  1914.  
  1915.         else if (type == 'R' && state == sserv) {
  1916.             decstr (strbuf);
  1917.             nfils = 1;
  1918.             *cmlist = strbuf;        /* point to name for gnfile() */
  1919.             if (sinit ('S') < 0) {
  1920.                 ERR("sinit");
  1921.             }
  1922.  
  1923.             else {
  1924.                 filcnt = 0;
  1925.                 nakstate = 0;        /* now I'm the sender */
  1926.                 BEGIN(ssfil);
  1927.             }
  1928.         }
  1929.  
  1930.         else if (type == 'S' && state == sserv) {
  1931.             spar (rdatap);
  1932.             ackl (rpar());
  1933.             bctu = bctr;
  1934.             nakstate = 1;
  1935.             BEGIN(srfil);
  1936.         }
  1937.  
  1938.         else if (type == 'G' && state == sserv) {
  1939.             decstr (strbuf);
  1940.             start = *strbuf;
  1941.             xpkt  = 1;
  1942.             nakstate = 0;            /* now I'm the sender */
  1943.             BEGIN(ssgen);
  1944.         }
  1945.  
  1946.         else if (type == 'C' && state == sserv) {
  1947.             decstr (strbuf);
  1948.             ss = system(strbuf);
  1949.             if (ss == 0)
  1950.                 BEGIN(ssini);
  1951.  
  1952.             else {
  1953.                 terror("Can't do system command");
  1954.                 SERVE;
  1955.             }
  1956.         }
  1957.  
  1958.         else if (type == 'E' && state == sserv) {
  1959.             if (local && rdatap != NULL)
  1960.                 tmsgl (rdatap);
  1961.  
  1962.             SERVE;
  1963.         }
  1964.  
  1965.         else if (state == sserv) {
  1966.             ERR("Unknown server command");
  1967.             SERVE;
  1968.         }
  1969.  
  1970.         /* Generic commands */
  1971.  
  1972.         else if (type == 'F' && state == ssgen) {
  1973.             ack();
  1974.             server = 0;
  1975.             return (0);
  1976.         }
  1977.  
  1978.         else if (type == 'T' && state == ssgen) {
  1979.             decstr(strbuf);
  1980.             nfils = 1;
  1981.             *cmlist = strbuf+2;         /* setup for gnfile */
  1982.             if (sinit('S') < 0)  {
  1983.                 ERR("sinit");
  1984.             }
  1985.  
  1986.             else {
  1987.                 filcnt = 0;
  1988.                 BEGIN(ssfil);
  1989.             }
  1990.         }
  1991.  
  1992.         else if (state == ssgen) {
  1993.             serror ("Unknown command");
  1994.             SERVE;
  1995.         }
  1996.  
  1997.         else if (type == 'E') {
  1998.             if (local)
  1999.                 tmsgl (rdatap);
  2000.  
  2001.             RESUME;
  2002.         }
  2003.  
  2004.         else if (type == 'T') {
  2005.             tmsg ("Kermit--timeout in state <");
  2006.             tstate (state);
  2007.             tmsgl (">\n");
  2008.             zerror();
  2009.             if (server) {
  2010.                 tinit();
  2011.                 BEGIN(sserv);
  2012.             }
  2013.             else
  2014.                 return (-1);
  2015.         }
  2016.  
  2017.         else {
  2018.             if (local) {
  2019.                 tmsg ("Kermit--inconsistency:  state <");
  2020.                 tstate (state);
  2021.                 tmsg ("> packet type <");
  2022.                 if (isprint (type))
  2023.                     tchar (type);
  2024.                 else
  2025.                     tmsgn ((int) type);
  2026.  
  2027.                 tmsgl (">\n");
  2028.             }
  2029.  
  2030.             zerror();
  2031.             if (server) {
  2032.                 tinit();
  2033.                 BEGIN(sserv);
  2034.             }
  2035.             else
  2036.                 return (-1);
  2037.         }
  2038.     }
  2039.  
  2040.     ttres();
  2041.  
  2042.     return (-1);
  2043. }
  2044.  
  2045. void doexit (int x)
  2046. {
  2047.     ttres();
  2048.     ttclos();
  2049.     exit (x);
  2050. }
  2051.  
  2052. void fatal (char *msg)
  2053. {
  2054.     fprintf (stderr, "\r\nFatal: %s\n", msg);
  2055.     exit (-1);
  2056. }
  2057.  
  2058. void check_action()
  2059. {
  2060.     if (action)
  2061.         fatal ("conflicting actions");
  2062. }
  2063.  
  2064. void check_bundling (char *xp, char x)
  2065. {
  2066.     if (*(xp+1)) {
  2067.         fprintf (stderr, "\r\nFatal: invalid argument bundling after -%c\n", x);
  2068.         exit (-1);
  2069.     }
  2070. }
  2071.  
  2072. char *check_next_arg (char x)
  2073. {
  2074.     *xargv++;
  2075.     xargc--;
  2076.     if ((xargc == 0) || (**xargv == '-')) {
  2077.         fprintf (stderr, "\r\nFatal: missing argument after -%c\n", x);
  2078.         exit (-1);
  2079.     }
  2080.     return (*xargv);
  2081. }
  2082.  
  2083. char doarg (char x) 
  2084. {
  2085.     int        done;
  2086.     char    *xp;
  2087.     char    *fspc1;
  2088.     char    *fspc2;
  2089.  
  2090.     xp = *xargv+1;
  2091.     while (x) {
  2092.         switch (x) {
  2093.             case 'd':        /* debug switch */
  2094.                 debug = 1;
  2095.                 break;
  2096.  
  2097.             case 'x':        /* server */
  2098.                 check_action();
  2099.                 action = 'x';
  2100.                 break;
  2101.  
  2102.             case 'f':        /* generic finish */
  2103.                 check_action();
  2104.                 action = 'g';
  2105.                 cmarg = setgen ('F', "", "", "");
  2106.                 break;
  2107.  
  2108.             case 'r':        /* receive */
  2109.                 check_action();
  2110.                 action = 'v';
  2111.                 break;
  2112.  
  2113.             case 'm':        /* move */
  2114.                 mfile    = 1;
  2115.  
  2116.             case 's':        /* send */
  2117.                 check_action();
  2118.                 check_bundling (xp, x);
  2119.  
  2120.                 nfils    = 0;
  2121.                 done    = 0;
  2122.                 cmlist    = xargv+1;
  2123.  
  2124.                 while (done == 0) {
  2125.                     xargc--;
  2126.                     *xargv++;
  2127.                     if (xargc < 1)
  2128.                         done = 1;
  2129.  
  2130.                     else if (*xargv == NULL)
  2131.                         done = 1;
  2132.  
  2133.                     else if (**xargv == '-') {
  2134.                         done = 1;
  2135.                         }
  2136.                     else {
  2137.                         nfils++;
  2138.                     }
  2139.                 }
  2140.  
  2141.                 xargc++;
  2142.                 *xargv--;
  2143.  
  2144.                 if (nfils < 1)
  2145.                     fatal ("missing filename for -s");
  2146.  
  2147.                 action = 's';
  2148.                 break;
  2149.  
  2150.             case 'g':        /* get */
  2151.                 check_action();
  2152.                 check_bundling (xp, x);
  2153.                 cmarg = check_next_arg (x);
  2154.                 action = 'r';
  2155.                 break;
  2156.  
  2157.             case 't':            /* remote type */
  2158.                 check_action();
  2159.                 check_bundling (xp, x);
  2160.                 fspc1  = check_next_arg (x);                
  2161.                 cmarg  = setgen ('T', fspc1, "", "");
  2162.                 action = 'g';
  2163.                 break;
  2164.  
  2165.             case 'C':            /* Host Command */
  2166.                 cmarg = check_next_arg (x);
  2167.                 if (action == 0)
  2168.                     action = 'c';
  2169.  
  2170.                 break;
  2171.  
  2172.             case 'R':            /* rename */
  2173.                 check_bundling (xp, x);
  2174.                 fspc1  = check_next_arg (x);
  2175.                 fspc2  = check_next_arg (x);
  2176.                 cmarg  = setgen ('R', fspc1, fspc2, "");
  2177.                 if (action == 0)
  2178.                     action = 'g';
  2179.  
  2180.                 break;
  2181.  
  2182.             case 'h':            /* help */
  2183.                 usage();
  2184.                 return (-1);
  2185.  
  2186.             case 'l':            /* communication device */
  2187.                 check_bundling (xp, x);
  2188.                 fspc1 = check_next_arg (x);
  2189.                 strcpy (ttname, fspc1);
  2190.                 break;
  2191.  
  2192.             case 'i':
  2193.                 text = 0;
  2194.                 break;
  2195.  
  2196.             case 'p':
  2197.                 check_bundling (xp, x);
  2198.                 check_next_arg (x);
  2199.                 switch (x = **xargv) {
  2200.                     case    'e':
  2201.                     case    'o':
  2202.                     case    'm':
  2203.                     case    's':    parity = x; break;
  2204.                     case    'n':    parity = 0; break;
  2205.                     default:    fatal ("invalid parity");
  2206.                 }
  2207.                 break;
  2208.  
  2209.             case '1':
  2210.             case '2':
  2211.             case '3':
  2212.                 bctr = x - '0';
  2213.                 break;
  2214.  
  2215.             default:
  2216.                 fatal ("Invalid argument, type 'kermit -h'  for help");
  2217.         }
  2218.  
  2219.         x = *++xp;
  2220.     }
  2221.  
  2222.     return (0);
  2223. }
  2224.  
  2225. char cmdlin()
  2226. {
  2227.     char    x;
  2228.  
  2229.     cmarg    = "";
  2230.     action    = 0;
  2231.     cmlist    = xargv;
  2232.  
  2233.     while (--xargc > 0) {
  2234.         xargv++;
  2235.         if (**xargv == '-') { 
  2236.             x = *(*xargv+1);
  2237.             x = doarg (x);
  2238.             if (x < 0)
  2239.                 exit (x);
  2240.         }
  2241.         else {
  2242.             usage();
  2243.             exit(0);
  2244.         }
  2245.     }
  2246.  
  2247.     return (action);
  2248. }
  2249.  
  2250. void main (int argc, char **argv)
  2251. {
  2252.     xargc    = argc;
  2253.     xargv    = argv;
  2254.     start    = 0;
  2255.     seq     = 0;
  2256.  
  2257.     if (argc <= 1) 
  2258.         usage();
  2259.  
  2260.     else {
  2261.         signal (SIGINT, trap_signal);
  2262.  
  2263.         start = cmdlin();
  2264.         if (start == 0)
  2265.             fatal ("no start state");
  2266.  
  2267.         else {
  2268.             if ((local = ttopen (ttname)) < 0) 
  2269.                 fatal ("Can't open line");
  2270.  
  2271.             ttpkt();
  2272.  
  2273.             if (start) {
  2274.                 doexit (yylex());
  2275.             }
  2276.         }
  2277.     }
  2278. }
  2279.