home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / c / WINKERM.ZIP / KERMPROT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-07-31  |  28.2 KB  |  1,228 lines

  1. /*******************************************************************************
  2. **                                                                            **
  3. **                      Kermit for Microsoft Windows                          **
  4. **                      ----------------------------                          **
  5. **                               KERMPROT.C                                   **
  6. **                                                                            **
  7. **  This module contains Kermit protocol implementation.  The routines used   **
  8. **  are derived from the book by Frank daCruz and are modified for            **
  9. **  compatibility with MS Windows.                                            **
  10. **                                                                            **
  11. *******************************************************************************/
  12.  
  13. // INCLUDES -------------------------------------------------------------------
  14.  
  15. #include "kermit.h"
  16. #include "kermprot.h"
  17.  
  18. //-----------------------------------------------------------------------------
  19. void error(char *s)
  20.  
  21. //  Description of what function does.
  22.  
  23. //  Param(s):   x...............Description.
  24.  
  25. //  Returns:    Result description.
  26.  
  27. {
  28.     spack('E',seq,strlen(s),s);
  29.  
  30.     if (local) {
  31.         message("Kermit - Fatal Error", s);
  32.     }
  33. }
  34.  
  35. //-----------------------------------------------------------------------------
  36. int NEAR spack(char type, int n, int len, char *d)
  37. {
  38.     int i=0, j, k;
  39.  
  40.     for (i = 0; i < spadn; i++)
  41.         sndpkt[i] = spadc;
  42.  
  43.     sndpkt[i++] = smark;
  44.     k = i++;
  45.     sndpkt[i++] = (char)tochar(n);
  46.     sndpkt[i++] = (char)type;
  47.     j = len + bctu;
  48.     if (j > 95) {
  49.         sndpkt[k] = tochar(0);
  50.         sndpkt[i++] = (char)tochar(j / 95);
  51.         sndpkt[i++] = (char)tochar(j % 95);
  52.         sndpkt[i] = '\0';
  53.         sndpkt[i++] = (char)tochar(chk1(sndpkt + k));
  54.     }
  55.     else
  56.         sndpkt[k] = (char)tochar(j + 2);
  57.  
  58.     for (j = len; j > 0; j--)
  59.         sndpkt[i++] = *d++;
  60.  
  61.     sndpkt[i] = '\0';
  62.     switch (bctu) {
  63.         case 1:
  64.             sndpkt[i++] = tochar((char)(chk1(sndpkt+k)));
  65.             break;
  66.         case 2:
  67.             j = (int)chksum(sndpkt+k);
  68.             sndpkt[i++] = (char)tochar((j >> 6) & 077);
  69.             sndpkt[i++] = (char)tochar(j & 077);
  70.             break;
  71.         case 3:
  72.             j = chk3(sndpkt+k);
  73.             sndpkt[i++] = (char)tochar((j >> 12) & 017);
  74.             sndpkt[i++] = (char)tochar((j >> 6) & 077);
  75.             sndpkt[i++] = (char)tochar(j & 077);
  76.             break;
  77.     }
  78.     sndpkt[i++] = (char)seol;
  79.     sndpkt[i] = '\0';
  80.     sndpkl = i;
  81.  
  82.     i = ttol(sndpkt,sndpkl);
  83.     if (local && !xflag)
  84.         tmsg(".");
  85.     ShowTypeOut((char)type);
  86.     ShowPackets(++Stats.Packets);
  87.     return(i);
  88. }
  89.  
  90. //-----------------------------------------------------------------------------
  91. char NEAR rpack (void)
  92. {
  93.     int i, j, x, type, rlnpos;
  94.     char pbc[4];
  95.  
  96.     if (!(j = ttinl(rcvpkt, MAXRP, reol, timint)))
  97.         return(0);
  98.  
  99.     rsn = rln = -1;
  100.  
  101.     if (j < 0) {
  102.         ShowTypeIn('T');
  103.         return('T');
  104.     }
  105.  
  106.     if (ProtSet.DebugPacket) {
  107.         tmsg("\n\rReceived: ");
  108.         traw(rcvpkt, j);
  109.     }
  110.  
  111.     for (i = 0; rcvpkt[i] != rmark && (i < j); i++);
  112.  
  113.     if (i == j) {
  114.         ShowTypeIn('Q');
  115.         return('Q');
  116.     }
  117.  
  118.     rlnpos = ++i;
  119.     if ((j = unchar(rcvpkt[i++])) == 0) {
  120.         j = rlnpos + 5;
  121.         if (j > MAXRP) {
  122.             ShowTypeIn('Q');
  123.             return('Q');
  124.         }
  125.         x = rcvpkt[j];
  126.         rcvpkt[j] = '\0';
  127.         if (unchar(x) != chk1(rcvpkt+rlnpos)) {
  128.             ShowTypeIn('Q');
  129.             return('Q');
  130.         }
  131.         rcvpkt[j] = (char)x;
  132.         rln = unchar(rcvpkt[j - 2]) * 95 + unchar(rcvpkt[j - 1]) - bctu;
  133.         j = 3;
  134.     }
  135.     else {
  136.         rln = j - bctu - 2;
  137.         j = 0;
  138.     }
  139.     rsn = unchar(rcvpkt[i++]);
  140.     type = rcvpkt[i++];
  141.     i += j;
  142.     rdatap = rcvpkt + i;
  143.     j = rln + i;
  144.  
  145.     if (j > MAXRP) {
  146.         ShowTypeIn('Q');
  147.         return('Q');
  148.     }
  149.     for (x = 0; x < bctu; x++)
  150.         pbc[x] = rcvpkt[j+x];
  151.     rcvpkt[j] = '\0';
  152.  
  153.     switch (bctu) {
  154.         case 1:
  155.             if (unchar(*pbc) != (char)chk1(rcvpkt+rlnpos)) {
  156.                 ShowTypeIn('Q');
  157.                 return('Q');
  158.             }
  159.             break;
  160.         case 2:
  161.             x = unchar(*pbc) << 6 | unchar(pbc[1]);
  162.             if (x != (int)chksum(rcvpkt+rlnpos)) {
  163.                 ShowTypeIn('Q');
  164.                 return('Q');
  165.             }
  166.             break;
  167.         case 3:
  168.             x = unchar(*pbc) << 12 | unchar(pbc[1]) << 6 | unchar(pbc[2]);
  169.             if (x != chk3(rcvpkt+rlnpos)) {
  170.                 ShowTypeIn('Q');
  171.                 return('Q');
  172.             }
  173.             break;
  174.         default:
  175.             error("Impossible Block Check Type");
  176.     }
  177.  
  178.     ShowTypeIn((char)type);
  179.     return((char)type);
  180. }
  181.  
  182. //-----------------------------------------------------------------------------
  183. int NEAR input(void)
  184. {
  185.     static int try;
  186.            int type;
  187.  
  188.     if (start != 0) {
  189.         type = start;
  190.         start = 0;
  191.         try = 0;
  192.         return(type);
  193.     }
  194.  
  195.     if (!(type = rpack()))
  196.         return(0);
  197.  
  198.     if (ProtSet.DebugOther)
  199.         tmsg("\n\rPacket: Type %c, Sequence %i for %i, Length %i",
  200.              type, rsn, seq, rln);
  201.  
  202.     if (cc) {
  203.         message("Kermit Done", "Kermit Aborted by User");
  204.         EndKermit(-1);
  205.         return(0);
  206.     }
  207.  
  208.     if (type == 'E')
  209.         return(type);
  210.  
  211.     if (rsn != seq || strchr("TQN",type)) {
  212.         if (type == 'N' && rsn == (seq+1) & 63)
  213.             type = 'Y';
  214.         else if (try > limit)
  215.             type = 'T';
  216.         else {
  217.             try++;
  218.             resend();
  219.             return(0);
  220.         }
  221.     }
  222.  
  223.     try = 0;
  224.     ttflui();
  225.     return(type);
  226. }
  227.  
  228. //-----------------------------------------------------------------------------
  229. void NEAR nxtpkt (void)
  230. {
  231.     seq = (seq + 1) & 63;
  232. }
  233.  
  234. //-----------------------------------------------------------------------------
  235. int NEAR resend(void)
  236. {
  237.     int x;
  238.     if (*sndpkt)
  239.         x = ttol(sndpkt, sndpkl);
  240.     else
  241.         x = nak();
  242.     if (local && !xflag)
  243.         tmsg("%%");
  244.     ShowRetries(++Stats.Retries);
  245.     cr = FALSE;
  246.     return(x);
  247. }
  248.  
  249. //-----------------------------------------------------------------------------
  250. int NEAR chk3(char *s)
  251. {
  252.     unsigned int c, q;
  253.     long crc = 0;
  254.  
  255.     while ((c = *s++) != '\0') {
  256.         if (parity) c &= 0177;
  257.         q = (int)(crc ^ c) & 017;
  258.         crc = (crc >> 4) ^ (q * 010201);
  259.         q = (int)(crc ^ (c >> 4)) & 017;
  260.         crc = (crc >> 4) ^ (q * 010201);
  261.     }
  262.     return((int)crc);
  263. }
  264.  
  265.  
  266. //-----------------------------------------------------------------------------
  267. int NEAR chk1(char *packet)
  268. {
  269.     int s, t;
  270.  
  271.     s = (int)chksum(packet);
  272.     t = (((s & 192) >> 6) + s) & 63;
  273.     return(t);
  274. }
  275.  
  276. //-----------------------------------------------------------------------------
  277. long NEAR chksum(char *p)
  278. {
  279.     unsigned int m;
  280.     long s;
  281.  
  282.     m = (parity) ? 0177 : 0377;
  283.     for (s = 0; *p != '\0'; *p++)
  284.         s += *p & m;
  285.     return(s & 07777);
  286. }
  287.  
  288. //-----------------------------------------------------------------------------
  289. void NEAR tinit(void)
  290. {
  291.     spsiz = ProtSet.SendPktSize;
  292.     rpsiz = ProtSet.RecvPktSize;
  293.     timint = ProtSet.SendTimeout;
  294.     rtimo = ProtSet.RecvTimeout;
  295.     bctr = ProtSet.BlockCheck;
  296.     limit = ProtSet.RetryLimit;
  297.  
  298.     spadc = (char)PktSet.Send.PadChar;
  299.     rpadc = (char)PktSet.Recv.PadChar;
  300.     rpadn = PktSet.Recv.PadCount;
  301.     spadn = PktSet.Send.PadCount;
  302.     smark = (char)PktSet.Send.StartChar;
  303.     rmark = (char)PktSet.Recv.StartChar;
  304.     seol = (char)PktSet.Send.EndChar;
  305.     reol = (char)PktSet.Recv.EndChar;
  306.     sctlq = (char)PktSet.Send.CtlPrefix;
  307.     rctlq = (char)PktSet.Recv.CtlPrefix;
  308.  
  309.     bctu = 1;
  310.     ebq = '&';
  311.     ebqflg = 0;
  312.     rqf = -1;
  313.     rq = 0;
  314.     sq = 'Y';
  315.     rpt = 0;
  316.     rptq = '~';
  317.     rptflg = 0;
  318.     start = 0;
  319.     clrinl = 0;
  320.  
  321.     capas = 10;
  322.     atcapb = 8; atcapr = ProtSet.Attributes; atcapu = 0;
  323.     swcapb = 4; swcapr = ProtSet.Windowing; swcapu = 0;
  324.     lpcapb = 2; lpcapr = ProtSet.LongPackets; lpcapu = 0;
  325.  
  326.     seq = 0;
  327.     sndpkl = 0;
  328.  
  329.     sndpkt[0] = '\0';
  330.     rcvpkt[0] = '\0';
  331.     isp = NULL;
  332.     osp = NULL;
  333.     ssc = 0;
  334.  
  335.     filsiz = 0;
  336.  
  337.     cx = 0;
  338.     cz = 0;
  339.     cr = 0;
  340.     ce = 0;
  341.     cc = 0;
  342.     xflag = 0;
  343.     xpkt = 0;
  344.  
  345.     parity = !(CommSet.Parity == NOPARITY);
  346.     delay = 5;
  347.     local = 1;
  348.  
  349.     server = 0;
  350.     first = 0;
  351.     keep = 0;
  352.  
  353.     Stats.Packets = 0;
  354.     Stats.Bytes = 0;
  355.     Stats.Retries = 0;
  356.  
  357.     ttflui();
  358. }
  359.  
  360. //-----------------------------------------------------------------------------
  361. int NEAR ack(void)
  362. {
  363.     int x;
  364.     x = spack('Y', seq, 0, "");
  365.     nxtpkt();
  366.     return(x);
  367. }
  368.  
  369. //-----------------------------------------------------------------------------
  370. int NEAR ackl(char *s)
  371. {
  372.     int x;
  373.     x = spack('Y', seq, strlen(s), s);
  374.     nxtpkt();
  375.     return(x);
  376. }
  377.  
  378. //-----------------------------------------------------------------------------
  379. int NEAR nak(void)
  380. {
  381.     int x;
  382.     x = spack('N', seq, 0, "");
  383.     return(x);
  384. }
  385.  
  386. //-----------------------------------------------------------------------------
  387. int NEAR sinit(char c)
  388. {
  389.     char *s;
  390.  
  391.     s = rpar();
  392.     tmsg("\n\rInitializing to send");
  393.     if (local == 0 && c == 'S' && server == 0) {
  394.         tmsg("\n\rEscape back to local system, give RECEIVE command...");
  395.     /*  sleep(delay);  */
  396.     }
  397.     return(spack(c, seq, strlen(s), s));
  398. }
  399.  
  400. //-----------------------------------------------------------------------------
  401. void NEAR rinit(void)
  402. {
  403.     tmsg("\n\rInitializing to receive");
  404. }
  405.  
  406. //-----------------------------------------------------------------------------
  407. int NEAR gnfile(void)
  408. {
  409.     if (cz)
  410.         return(0);
  411.  
  412.     if (hSendList)
  413.         return(SendMessage(hSendList, LB_GETTEXT, nfils++,
  414.                (LONG)(LPSTR)filnam) != LB_ERR);
  415.  
  416.     if (nfils-- > 0)
  417.         return(1);
  418.     else
  419.         return(0);
  420. }
  421.  
  422. //-----------------------------------------------------------------------------
  423. int NEAR sfile(void)
  424. {
  425.     int x;
  426.     char pktnam[80];
  427.     char MsgBuf[100];
  428.  
  429.     if (zopeni(filnam) < 0) return(-1);
  430.     zltor(filnam, pktnam);
  431.     x = encstr(pktnam);
  432.     sprintf(MsgBuf, "Sending %s", pktnam);
  433.     SetDlgItemText(hXfrWnd, IDD_ACTION, MsgBuf);
  434.     if (local)
  435.         tmsg("\n\rSending %s as %s", filnam, pktnam);
  436.     first = 1;
  437.     maxsiz = spsiz - (bctr + 3);
  438.     nxtpkt();
  439.     return(spack((char)(xpkt ? 'X' : 'F'), seq, x, data));
  440. }
  441.  
  442. //-----------------------------------------------------------------------------
  443. int NEAR rcvfil(void)
  444. {
  445.     char myname[80];
  446.     char MsgBuf[100];
  447.  
  448.     if (xflag) {
  449.         SetDlgItemText(hXfrWnd, IDD_ACTION, "Receiving Screen Data");
  450.         tmsg("\n\rReceiving Screen Data\n\r");
  451.         return(0);
  452.     }
  453.  
  454.     zrtol(filnam,myname,TRUE);
  455.     if (zopeno(myname) < 0)
  456.         return(-1);
  457.     else {
  458.         sprintf(MsgBuf, "Receiving %s", myname);
  459.         SetDlgItemText(hXfrWnd, IDD_ACTION, MsgBuf);
  460.         if (local)
  461.             tmsg("\n\rReceiving %s as %s", filnam, myname);
  462.         strcpy(filnam, myname);
  463.         return(0);
  464.     }
  465. }
  466.  
  467. //-----------------------------------------------------------------------------
  468. int NEAR closof(void)
  469. {
  470.     if (xflag)
  471.         return(0);
  472.     if (zcloso((rln >= 1) && (rdatap[0] == 'D')) < 0)
  473.         return(-1);
  474.     tmsg("\n\rOK");
  475.     return(0);
  476. }
  477.  
  478. //-----------------------------------------------------------------------------
  479. int NEAR seot(void)
  480. {
  481.     nxtpkt();
  482.     tmsg("\n\rDone");
  483.     return(spack('B',seq,0,""));
  484. }
  485.  
  486. //-----------------------------------------------------------------------------
  487. int NEAR sdata(void)
  488. {
  489.     int x;
  490.  
  491.     if (rln >= 1)
  492.         switch (rdatap[0]) {
  493.             case 'Z':
  494.                 cz = TRUE;
  495.                 break;
  496.             case 'X':
  497.                 cx = TRUE;
  498.                 break;
  499.         }
  500.  
  501.     if (cx || cz)
  502.         return(0);
  503.  
  504.     if ((x = getpkt(maxsiz)) == 0)
  505.         return(0);
  506.     nxtpkt();
  507.     ShowBytes(Stats.Bytes);
  508.     return(spack('D', seq, x, data));
  509. }
  510.  
  511. //-----------------------------------------------------------------------------
  512. int NEAR seof(char *s)
  513. {
  514.     if (zclosi() < 0)
  515.         return(-1);
  516.     else {
  517.         if (local)
  518.             tmsg("\n\rOK");
  519.         nxtpkt();
  520.         return(spack('Z', seq, strlen(s), s));
  521.     }
  522. }
  523.  
  524. //-----------------------------------------------------------------------------
  525. int NEAR getpkt(int maxlen)
  526. {
  527.     int i, next;
  528.     static int c;
  529.     static char remain[6] = "\0\0\0\0\0\0";
  530.  
  531.     if (first == 1) {
  532.         first = 0;
  533.         *remain = '\0';
  534.         c = gnchar();
  535.         if (c < 0) {
  536.             first = -1;
  537.             return(size = 0);
  538.         }
  539.     }
  540.     else if (first == -1) {
  541.         return(size = 0);
  542.     }
  543.     for (size = 0; (data[size] = remain [size]) != '\0'; size++);
  544.     *remain = '\0';
  545.  
  546.     rpt = 0;
  547.     while (first > -1) {
  548.         next = gnchar();
  549.         if (next < 0)
  550.             first = -1;
  551.         osize = size;
  552.         encode(c, next);
  553.         c = next;
  554.  
  555.         if (size == maxlen)
  556.             return(size);
  557.  
  558.         if (size > maxlen) {
  559.             for (i = 0; (remain[i] = data[osize+i]) != '\0'; i++);
  560.             size = osize;
  561.             data[size] = '\0';
  562.             return(size);
  563.         }
  564.     }
  565.     return(size);
  566. }
  567.  
  568. //-----------------------------------------------------------------------------
  569. int NEAR gnchar (void)
  570. {
  571.     char c;
  572.  
  573.     if (isp)
  574.         return((c = *isp++) > 0 ? c : -1);
  575.     else
  576.         return(zgetc());
  577. }
  578.  
  579. //-----------------------------------------------------------------------------
  580. void NEAR encode(int a, int next)
  581. {
  582.     int a7, b8;
  583.  
  584.     if (rptflg) {
  585.         if (a == next) {
  586.             if (++rpt < 94) {
  587.                 return;
  588.             }
  589.             else if (rpt == 94) {
  590.                 data[size++] = (char)rptq;
  591.                 data[size++] = (char)tochar(rpt);
  592.                 rpt = 0;
  593.             }
  594.         }
  595.         else if (rpt == 1) {
  596.             rpt = 0;
  597.             encode(a,-1);
  598.             if (size <= maxsiz)
  599.                 osize = size;
  600.             rpt = 0;
  601.             encode(a,-1);
  602.             return;
  603.         }
  604.         else if (rpt > 1) {
  605.             data[size++] = (char)rptq;
  606.             data[size++] = (char)tochar(++rpt);
  607.             rpt = 0;
  608.         }
  609.     }
  610.     a7 = a & 127;
  611.     b8 = a & 128;
  612.  
  613.     if (ebqflg && b8) {
  614.         data[size++] = (char)ebq;
  615.         a = a7;
  616.     }
  617.  
  618.     if (a7 < 32 || a7 == 127) {
  619.         data[size++] = sctlq;
  620.         a = ctl(a);
  621.     }
  622.     else if (a7 == sctlq)
  623.         data[size++] = sctlq;
  624.     else if (ebqflg && a7 == ebq)
  625.         data[size++] = sctlq;
  626.     else if (rptflg && a7 == rptq)
  627.         data[size++] = sctlq;
  628.  
  629.     data[size++] = (char)a;
  630.     data[size] = '\0';
  631. }
  632.  
  633. //-----------------------------------------------------------------------------
  634. int NEAR decode(void)
  635. {
  636.     char a, a7, b8;
  637.  
  638.     while ((a = *rdatap++) != '\0') {
  639.         rpt = 1;
  640.         if (rptflg) {
  641.             if (a == (char)rptq) {
  642.                 rpt = unchar(*rdatap++);
  643.                 a = *rdatap++;
  644.             }
  645.         }
  646.         b8 = 0;
  647.         if (ebqflg) {
  648.             if (a == (char)ebq) {
  649.                 b8 = 128;
  650.                 a = *rdatap++;
  651.             }
  652.         }
  653.         if (a == rctlq) {
  654.             a = *rdatap++;
  655.             a7 = a & 127;
  656.             if (a7 > 62 && a7 < 96)
  657.                 a = ctl(a);
  658.         }
  659.         a |= b8;
  660.         for (; rpt > 0; rpt--)
  661.             if (pnchar(a) < 0)
  662.                 return(-1);
  663.     }
  664.     ShowBytes(Stats.Bytes);
  665.     return(0);
  666. }
  667.  
  668. //-----------------------------------------------------------------------------
  669. int NEAR pnchar (int c)
  670. {
  671.     if (xflag) {
  672.         tchar((char)c);
  673.         Stats.Bytes++;
  674.         return(1);
  675.     }
  676.     else if (osp) {
  677.         *osp++ = (char)c;
  678.         return(1);
  679.     }
  680.     else
  681.         return(zputc(c));
  682. }
  683.  
  684. //-----------------------------------------------------------------------------
  685. int NEAR encstr(char *s)
  686. {
  687.     first = 1;
  688.     isp = s;
  689.     getpkt(spsiz);
  690.     isp = NULL;
  691.     return(size);
  692. }
  693.  
  694. //-----------------------------------------------------------------------------
  695. void NEAR decstr(char *s)
  696. {
  697.     osp = s;
  698.     decode();
  699.     *osp = '\0';
  700.     osp = NULL;
  701. }
  702.  
  703. //-----------------------------------------------------------------------------
  704. void NEAR spar(char *s)
  705. {
  706.     int x;
  707.  
  708.     s--;
  709.  
  710.     x = (rln >= 1) ? unchar(s[1]) : 80;
  711.     spsiz = (x < 10) ? 80 : x;
  712.  
  713.     x = (rln >= 2) ? unchar(s[2]) : 5;
  714.     timint = (x < 0) ? 5 : x;
  715.  
  716.     spadn = 0;
  717.     spadc = '\0';
  718.     if (rln >= 3) {
  719.         spadn = unchar(s[3]);
  720.         if (rln >= 4)
  721.             spadc = ctl(s[4]);
  722.         else
  723.             spadc = 0;
  724.     }
  725.  
  726.     seol = (rln >= 5) ? unchar(s[5]) : '\r';
  727.     if ((seol < 2) || (seol > 31))
  728.         seol = '\r';
  729.  
  730.     x = (rln >= 6) ? s[6] : '#';
  731.     rctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? (char)x : '#';
  732.  
  733.     rq = (rln >= 7) ? s[7] : 0;
  734.     if (rq == 'Y')
  735.         rqf = 1;
  736.     else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127))
  737.         rqf = 2;
  738.     else
  739.         rqf = 0;
  740.     switch (rqf) {
  741.         case 0:
  742.             ebqflg = 0;
  743.             break;
  744.         case 1:
  745.             if (parity) {
  746.                 ebqflg = 1;
  747.                 ebq = '&';
  748.             }
  749.             break;
  750.         case 2:
  751.             if (ebqflg = (ebq == sq || sq == 'Y'))
  752.                 ebq = rq;
  753.     }
  754.  
  755.     x = 1;
  756.     if (rln >= 8) {
  757.         x = s[8] - '0';
  758.         if ((x < 1) || (x > 3))
  759.             x = 1;
  760.     }
  761.     bctr = x;
  762.  
  763.     if (rln >= 9) {
  764.         rptq = s[9];
  765.         rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
  766.     }
  767.     else
  768.         rptflg = 0;
  769.  
  770.     atcapu = lpcapu = swcapu = 0;
  771.     if (rln >= 10) {
  772.         x = unchar(s[10]);
  773.         atcapu = (x & atcapb) && atcapr;
  774.         lpcapu = (x & lpcapb) && lpcapr;
  775.         swcapu = (x & swcapb) && swcapr;
  776.         for (capas = 10; (unchar(s[capas]) & 1) && (rln >= capas); capas++);
  777.     }
  778.  
  779.     if (lpcapu) {
  780.         if (rln > capas + 2) {
  781.             x = unchar(s[capas + 2]) * 95 + unchar(s[capas + 3]);
  782.             spsiz = x > MAXSP ? MAXSP : x;
  783.         }
  784.     }
  785. }
  786.  
  787. //-----------------------------------------------------------------------------
  788. char NEAR *rpar(void)
  789. {
  790.     data[1] = tochar(94);
  791.     data[2] = tochar((char)rtimo);
  792.     data[3] = tochar((char)rpadn);
  793.     data[4] = ctl(rpadc);
  794.     data[5] = tochar(reol);
  795.     data[6] = '#';
  796.     switch (rqf) {
  797.         case -1:
  798.         case 1:
  799.             if (parity) ebq = sq = '&';
  800.             break;
  801.         case 0:
  802.         case 2:
  803.             break;
  804.     }
  805.     data[7] = (char)sq;
  806.     data[8] = (char)bctr + '0';
  807.     if (rptflg)
  808.         data[9] = (char)rptq;
  809.     else
  810.         data[9] = '~';
  811.  
  812.     data[10] = (char)tochar((atcapr?atcapb:0) |
  813.                             (lpcapr?lpcapb:0) |
  814.                             (swcapr?swcapb:0));
  815.     data[11] = tochar(0);
  816.     data[12] = (char)tochar(rpsiz / 95);
  817.     data[13] = (char)tochar(rpsiz % 95);
  818.     data[14] = '\0';
  819.  
  820.     return(data+1);
  821. }
  822.  
  823. int sadone;
  824.  
  825. //-----------------------------------------------------------------------------
  826. int NEAR sattr(void)
  827. {
  828.     int  fh;
  829.     char sizestr[20];
  830.     char attrstr[20];
  831.  
  832.     if (sadone)
  833.         return(0);
  834.  
  835.     fh = open(filnam, O_RDONLY);
  836.     ltoa((filsiz = filelength(fh))/1024, sizestr, 10);
  837.     close(fh);
  838.  
  839.     sadone = 1;
  840.     nxtpkt();
  841.     sprintf(attrstr, "!%c%s", tochar(strlen(sizestr)), sizestr);
  842.     return(spack('A',seq,strlen(attrstr),attrstr));
  843. }
  844.  
  845. //-----------------------------------------------------------------------------
  846. int NEAR rdattr(char *s)
  847. {
  848.     return(0);
  849. }
  850.  
  851. //-----------------------------------------------------------------------------
  852. char *NEAR setatt(char *s)
  853. {
  854.     int i;
  855.     char attrtype;
  856.     int  attrlen;
  857.     char attrstr[20];
  858.  
  859.     i = 0;
  860.     while (i < rln) {
  861.         attrtype = s[i++];
  862.         attrlen = unchar(s[i++]);
  863.         memset(attrstr, 0, sizeof(attrstr));
  864.         memcpy(attrstr, s+i, attrlen);
  865.         i += attrlen;
  866.         switch (attrtype) {
  867.             case '!':
  868.                 if (filsiz == 0)
  869.                     filsiz = atol(attrstr) * 1024;
  870.                 break;
  871.             case '1':
  872.                 filsiz = atol(attrstr);
  873.                 break;
  874.         }
  875.     }
  876.  
  877.     return("");
  878. }
  879.  
  880. //-----------------------------------------------------------------------------
  881. int NEAR scmd(char t, char *s)
  882. {
  883.     encstr(s);
  884.     return(spack(t, seq, size, data));
  885. }
  886.  
  887. //-----------------------------------------------------------------------------
  888. void DoKermit(void)
  889. {
  890.     static char state;
  891.            char type;
  892.     static int  filcnt;
  893.  
  894.     if (!(type = (char)input()))
  895.         return;
  896.  
  897.     if (ProtSet.DebugState)
  898.         tmsg("\n\rProtocol: State %i, Type: %c", state, type);
  899.  
  900.     if (ce) {
  901.         ERR("User Intervention");
  902.     }
  903.  
  904.     /******************************************************
  905.     * Kermit Send state transitions...                    *
  906.     ******************************************************/
  907.  
  908.     else if (type == 's') {
  909.         tinit();
  910.         if (sinit('S') < 0) {
  911.             ERR("sinit");
  912.         }
  913.         else {
  914.             filcnt = 0;
  915.             BEGIN(ssfil);
  916.         }
  917.     }
  918.  
  919.     else if (state == ssfil && type == 'Y') {
  920.         if (filcnt++ == 0)
  921.             spar(rdatap);
  922.         cx = 0;
  923.         Stats.Bytes = 0;
  924.         sadone = 0;
  925.         bctu = bctr;
  926.         if (gnfile() > 0) {
  927.             if (sfile() < 0) {
  928.                 ERR("sfile");
  929.             }
  930.             else if (atcapu) {
  931.                 BEGIN(ssatr);
  932.             }
  933.             else {
  934.                 BEGIN(ssdat);
  935.             }
  936.         }
  937.         else {
  938.             if (seot() < 0) {
  939.                 ERR("seot");
  940.             }
  941.             else {
  942.                 BEGIN(sseot);
  943.             }
  944.         }
  945.     }
  946.  
  947.     else if (state == ssatr && type == 'Y') {
  948.         int x;
  949.         if ((x = sattr()) < 0) {
  950.             ERR("sattr");
  951.         }
  952.         else if (x > 0)
  953.             BEGIN(ssatx);
  954.         else {
  955.             start = 'Y';
  956.             BEGIN(ssdat);
  957.         }
  958.     }
  959.  
  960.     else if (state == ssatx && type == 'Y') {
  961.         int x;
  962.         if (rdattr(rdatap) < 0) {
  963.             if (seof("D") < 0) {
  964.                 ERR("seof");
  965.             }
  966.             else
  967.                 BEGIN(sseot);
  968.         }
  969.         else if ((x = sattr()) < 0) {
  970.             ERR("sattr");
  971.         }
  972.         else if (x == 0) {
  973.             start = 'Y';
  974.             BEGIN(ssdat);
  975.         }
  976.     }
  977.  
  978.     else if (state == ssdat && type == 'Y') {
  979.         int x;
  980.         if ((x = sdata()) == 0) {
  981.             if (seof((cx | cz) ? "D" : "") < 0) {
  982.                 ERR("seof");
  983.             }
  984.             else {
  985.                 BEGIN(ssfil);
  986.             }
  987.         }
  988.         else if (x < 0) {
  989.             ERR("sdata");
  990.         }
  991.     }
  992.     else if (state == sseot && type == 'Y') {
  993.         message("Kermit Done","Transfer Completed");
  994.         RESUME(0);
  995.     }
  996.  
  997.     /******************************************************
  998.     * Kermit Receive state transitions.                   *
  999.     ******************************************************/
  1000.  
  1001.     else if (type == 'v') {
  1002.         tinit();
  1003.         rinit();
  1004.         BEGIN(srini);
  1005.     }
  1006.  
  1007.     else if (state == srini && type == 'S') {
  1008.         spar(rdatap);
  1009.         ackl(rpar());
  1010.         bctu = bctr;
  1011.         BEGIN(srfil);
  1012.     }
  1013.  
  1014.     else if (state == srfil && type == 'B') {
  1015.         tmsg("\n\rDone");
  1016.         ack();
  1017.         message("Kermit Done","Transfer Completed");
  1018.         RESUME(0);
  1019.     }
  1020.  
  1021.     else if (state == srfil && type == 'F') {
  1022.         decstr(filnam);
  1023.         ack();
  1024.         BEGIN(sratt);
  1025.     }
  1026.  
  1027.     else if (state == sratt && type == 'A') {
  1028.         ackl(setatt(rdatap));
  1029.     }
  1030.  
  1031.     else if (state == sratt && type == 'D') {
  1032.         if (rcvfil() < 0) {
  1033.             ERR("rcvfil");
  1034.         }
  1035.         else {
  1036.             cx = 0;
  1037.             Stats.Bytes = 0;
  1038.             start = type;
  1039.             BEGIN(srdat);
  1040.         }
  1041.     }
  1042.  
  1043.     else if (state == srdat && type == 'D') {
  1044.         if (decode() < 0) {
  1045.             ERR("decode");
  1046.         }
  1047.         else {
  1048.             if (cx)
  1049.                 ackl("X");
  1050.             else if (cz)
  1051.                 ackl("Z");
  1052.             else
  1053.                 ack();
  1054.         }
  1055.     }
  1056.  
  1057.     else if (state == srdat && type == 'Z') {
  1058.         if (closof() < 0) {
  1059.             ERR("closof");
  1060.         }
  1061.         else {
  1062.             ack();
  1063.             BEGIN(srfil);
  1064.         }
  1065.     }
  1066.  
  1067.     /******************************************************
  1068.     * Kermit Client state transitions.                    *
  1069.     ******************************************************/
  1070.  
  1071.     else if (type == 'r') {
  1072.         tinit();
  1073.         ssc = 0;
  1074.         sinit('I');
  1075.         BEGIN(sipkt);
  1076.     }
  1077.  
  1078.     else if (type == 'c') {
  1079.         tinit();
  1080.         ssc = 'C';
  1081.         sinit('I');
  1082.         BEGIN(sipkt);
  1083.     }
  1084.  
  1085.     else if (type == 'g') {
  1086.         tinit();
  1087.         ssc = 'G';
  1088.         sinit('I');
  1089.         BEGIN(sipkt);
  1090.     }
  1091.  
  1092.     else if (state == sipkt && type == 'Y') {
  1093.         spar(rdatap);
  1094.         start = 'E';
  1095.     }
  1096.  
  1097.     else if (state == sipkt && type == 'E') {
  1098.         if (ssc) {
  1099.             if (scmd(ssc, cmarg) < 0) {
  1100.                 ERR("scmd");
  1101.             }
  1102.             else
  1103.                 BEGIN(srgen);
  1104.         }
  1105.         else {
  1106.             if (scmd('R', cmarg) < 0) {
  1107.                 ERR("scmd");
  1108.             }
  1109.             else
  1110.                 BEGIN(srini);
  1111.         }
  1112.     }
  1113.  
  1114.     else if (state == srgen && type == 'Y') {
  1115.         xflag = 1;
  1116.         decode();
  1117.         RESUME(0);
  1118.     }
  1119.  
  1120.     else if (state == srgen && type == 'S') {
  1121.         spar(rdatap);
  1122.         ackl(rpar());
  1123.         bctu = bctr;
  1124.         BEGIN(srfil);
  1125.     }
  1126.  
  1127.     else if ((state == srgen || state == srfil) && type == 'X') {
  1128.         xflag = 1;
  1129.         ack();
  1130.         BEGIN(sratt);
  1131.     }
  1132.  
  1133.     /******************************************************
  1134.     * Kermit Server state transitions.                    *
  1135.     ******************************************************/
  1136.  
  1137.     else if (type == 'x') {
  1138.         SERVE;
  1139.     }
  1140.  
  1141.     else if (state == sserv && type == 'T') {
  1142.         SERVE;
  1143.     }
  1144.  
  1145.     else if (state == sserv && type == 'I') {
  1146.         spar(rdatap);
  1147.         ackl(rpar());
  1148.         seq = 0;
  1149.     }
  1150.  
  1151.     else if (state == sserv && type == 'R') {
  1152.         decstr(strbuf);
  1153.         nfils = 1;
  1154.         strcpy(filnam, strbuf);
  1155.         if (sinit('S') < 0) {
  1156.             ERR("sinit");
  1157.         }
  1158.         else {
  1159.             filcnt = 0;
  1160.             BEGIN(ssfil);
  1161.         }
  1162.     }
  1163.  
  1164.     else if (state == sserv && type == 'S') {
  1165.         spar(rdatap);
  1166.         ackl(rpar());
  1167.         bctu = bctr;
  1168.         BEGIN(srfil);
  1169.     }
  1170.  
  1171.     else if (state == sserv && type == 'G') {
  1172.         decstr(strbuf);
  1173.         start = *strbuf;
  1174.         xpkt = 1;
  1175.         BEGIN(ssgen);
  1176.     }
  1177.  
  1178.     else if (state == sserv && type == 'E') {
  1179.         SERVE;
  1180.     }
  1181.  
  1182.     else if (state == sserv) {
  1183.         ERR("Unknown Server Command");
  1184.         SERVE;
  1185.     }
  1186.  
  1187.     else if (state == ssgen && type == 'F') {
  1188.         ack();
  1189.         server = 0;
  1190.         RESUME(0);
  1191.     }
  1192.  
  1193.     else if (state == ssgen && type == 'T') {
  1194.         decstr(strbuf);
  1195.         nfils = 1;
  1196.         strcpy(filnam, strbuf + 2);
  1197.         if (sinit('S') < 0) {
  1198.             ERR("sinit");
  1199.         }
  1200.         else {
  1201.             filcnt = 0;
  1202.             BEGIN(ssfil);
  1203.         }
  1204.     }
  1205.  
  1206.     else if (state == ssgen) {
  1207.         ERR("Unknown Generic Command");
  1208.         SERVE;
  1209.     }
  1210.  
  1211.     /******************************************************
  1212.     * Error state transitions...                          *
  1213.     ******************************************************/
  1214.  
  1215.     else if (type == 'E') {
  1216.         message("Kermit - Remote Error",rdatap);
  1217.         RESUME(-1);
  1218.     }
  1219.  
  1220.     else if (type == 'T') {
  1221.         ERR("Remote Kermit Not Responding");
  1222.     }
  1223.  
  1224.     else {
  1225.         ERR("Unexpected Packet Type");
  1226.     }
  1227. }
  1228.