home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckv192.zip / ckcfn2.c < prev    next >
C/C++ Source or Header  |  1996-12-28  |  68KB  |  2,174 lines

  1. #define NEWDPL
  2.  
  3. /*  C K C F N 2  --  System-independent Kermit protocol support functions... */
  4.  
  5. /*  ...Part 2 (continued from ckcfns.c)  */
  6.  
  7. /*
  8.   Author: Frank da Cruz <fdc@columbia.edu>,
  9.   Columbia University Academic Information Systems, New York City.
  10.  
  11.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  12.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  13.   sold for profit as a software product itself, nor may it be included in or
  14.   distributed with commercial products or otherwise distributed by commercial
  15.   concerns to their clients or customers without written permission of the
  16.   Office of Kermit Development and Distribution, Columbia University.  This
  17.   copyright notice must not be removed, altered, or obscured.
  18. */
  19. /*
  20.  Note -- if you change this file, please amend the version number and date at
  21.  the top of ckcfns.c accordingly.
  22. */
  23.  
  24. #include "ckcsym.h"            /* Compilation options */
  25. #include "ckcdeb.h"            /* Debugging and other symbols */
  26. #include "ckcasc.h"            /* ASCII symbols */
  27. #include "ckcker.h"            /* Kermit symbols */
  28. #include "ckcxla.h"            /* Translation */
  29.  
  30. #ifdef TCPSOCKET            /* For TELNET business in spack() */
  31. #ifndef NP_TELNET            /* Avoid dragging in ckcnet.h */
  32. #define NP_TELNET  1
  33. #define TNL_CR     0            /* CR sends bare carriage return */
  34. #define TNL_CRNUL  1            /* CR and NUL */
  35. #define TNL_CRLF   2            /* CR and LF */
  36. #define TNL_LF     3            /* LF instead of CR */
  37. #endif /* NP_TELNET */
  38. extern int tn_nlm, ttnproto;
  39. extern int me_binary, tn_b_nlm;
  40. #endif /* TCPSOCKET */
  41.  
  42. #ifdef DYNAMIC
  43. extern struct pktinfo *s_pkt;        /* array of pktinfo structures */
  44. extern struct pktinfo *r_pkt;        /* array of pktinfo structures */
  45. #else
  46. extern struct pktinfo s_pkt[];        /* array of pktinfo structures */
  47. extern struct pktinfo r_pkt[];        /* array of pktinfo structures */
  48. #endif /* DYNAMIC */
  49.  
  50. extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo,
  51.   sbufnum, rbufnum, pktpaus;
  52.  
  53. extern int ttprty;            /* from ck*tio.c */
  54. extern int autopar;
  55.  
  56. extern int spsiz, spmax, rpsiz, timint, timef, npad, bestlen, maxsend;
  57. extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, network, flow;
  58. extern int pktnum, sndtyp, rcvtyp, bctr, bctu, bctl, rsn, rln, maxtry, size;
  59. extern int osize, maxsize, spktl, rpktl, nfils, stdouf, warn, parity;
  60. extern int turn, turnch,  delay, displa, pktlog, tralog, seslog, xflg, mypadn;
  61. extern int hcflg, local, server, cxseen, czseen, discard, slostart;
  62. extern int nakstate, quiet, success, xitsta, what;
  63. extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz;
  64.  
  65. extern long filcnt, filrej, ffc, flci, flco, tlci, tlco, tfc, speed;
  66.  
  67. extern char *cmarg, filnam[], *hlptxt;
  68.  
  69. extern CHAR padch, mypadc, eol, seol, ctlq, sstate;
  70. extern CHAR *recpkt, *data, myinit[];
  71. extern CHAR *srvptr, stchr, mystch, *rdatap;
  72. extern CHAR padbuf[];
  73. #ifdef pdp11
  74.   extern CHAR srvcmd[];
  75.   extern CHAR *pktmsg;
  76. #else
  77. #ifdef DYNAMIC
  78.   extern CHAR *srvcmd;
  79.   extern CHAR *pktmsg;
  80. #else
  81.   extern CHAR srvcmd[];
  82.   extern CHAR pktmsg[];
  83. #endif /* DYNAMIC */
  84. #endif /* pdp11 */
  85.  
  86. int numerrs = 0;            /* Number of packet errors so far */
  87. int rcvtimo = 0;            /* Timeout for receiving a packet */
  88.  
  89. #ifdef CK_TIMERS
  90. int rrttbl[64], srttbl[64];        /* Packet timestamp tables */
  91. extern int rttflg;
  92. #define RTT_SCALE 1000
  93. long
  94.   rttsamples,                /* Round trip time samples */
  95.   rttdelay,                /* RTT delay */
  96.   pktintvl,                /* Interpacket arrival time */
  97.   rttvariance,                /* RTT variance */
  98.   rttstddev;                /* RTT standard deviation */
  99. #endif /* CK_TIMERS */
  100.  
  101. static CHAR p_tbl[] = {            /* Even parity table for dopar(). */
  102.     (CHAR) '\000',            /* ANSI C casts '\ooo' constants  */
  103.     (CHAR) '\201',            /* to signed char, so we have to  */
  104.     (CHAR) '\202',            /* cast back to unsigned char...  */
  105.     (CHAR) '\003',
  106.     (CHAR) '\204',
  107.     (CHAR) '\005',
  108.     (CHAR) '\006',
  109.     (CHAR) '\207',
  110.     (CHAR) '\210',
  111.     (CHAR) '\011',
  112.     (CHAR) '\012',
  113.     (CHAR) '\213',
  114.     (CHAR) '\014',
  115.     (CHAR) '\215',
  116.     (CHAR) '\216',
  117.     (CHAR) '\017',
  118.     (CHAR) '\220',
  119.     (CHAR) '\021',
  120.     (CHAR) '\022',
  121.     (CHAR) '\223',
  122.     (CHAR) '\024',
  123.     (CHAR) '\225',
  124.     (CHAR) '\226',
  125.     (CHAR) '\027',
  126.     (CHAR) '\030',
  127.     (CHAR) '\231',
  128.     (CHAR) '\232',
  129.     (CHAR) '\033',
  130.     (CHAR) '\234',
  131.     (CHAR) '\035',
  132.     (CHAR) '\036',
  133.     (CHAR) '\237',
  134.     (CHAR) '\240',
  135.     (CHAR) '\041',
  136.     (CHAR) '\042',
  137.     (CHAR) '\243',
  138.     (CHAR) '\044',
  139.     (CHAR) '\245',
  140.     (CHAR) '\246',
  141.     (CHAR) '\047',
  142.     (CHAR) '\050',
  143.     (CHAR) '\251',
  144.     (CHAR) '\252',
  145.     (CHAR) '\053',
  146.     (CHAR) '\254',
  147.     (CHAR) '\055',
  148.     (CHAR) '\056',
  149.     (CHAR) '\257',
  150.     (CHAR) '\060',
  151.     (CHAR) '\261',
  152.     (CHAR) '\262',
  153.     (CHAR) '\063',
  154.     (CHAR) '\264',
  155.     (CHAR) '\065',
  156.     (CHAR) '\066',
  157.     (CHAR) '\267',
  158.     (CHAR) '\270',
  159.     (CHAR) '\071',
  160.     (CHAR) '\072',
  161.     (CHAR) '\273',
  162.     (CHAR) '\074',
  163.     (CHAR) '\275',
  164.     (CHAR) '\276',
  165.     (CHAR) '\077',
  166.     (CHAR) '\300',
  167.     (CHAR) '\101',
  168.     (CHAR) '\102',
  169.     (CHAR) '\303',
  170.     (CHAR) '\104',
  171.     (CHAR) '\305',
  172.     (CHAR) '\306',
  173.     (CHAR) '\107',
  174.     (CHAR) '\110',
  175.     (CHAR) '\311',
  176.     (CHAR) '\312',
  177.     (CHAR) '\113',
  178.     (CHAR) '\314',
  179.     (CHAR) '\115',
  180.     (CHAR) '\116',
  181.     (CHAR) '\317',
  182.     (CHAR) '\120',
  183.     (CHAR) '\321',
  184.     (CHAR) '\322',
  185.     (CHAR) '\123',
  186.     (CHAR) '\324',
  187.     (CHAR) '\125',
  188.     (CHAR) '\126',
  189.     (CHAR) '\327',
  190.     (CHAR) '\330',
  191.     (CHAR) '\131',
  192.     (CHAR) '\132',
  193.     (CHAR) '\333',
  194.     (CHAR) '\134',
  195.     (CHAR) '\335',
  196.     (CHAR) '\336',
  197.     (CHAR) '\137',
  198.     (CHAR) '\140',
  199.     (CHAR) '\341',
  200.     (CHAR) '\342',
  201.     (CHAR) '\143',
  202.     (CHAR) '\344',
  203.     (CHAR) '\145',
  204.     (CHAR) '\146',
  205.     (CHAR) '\347',
  206.     (CHAR) '\350',
  207.     (CHAR) '\151',
  208.     (CHAR) '\152',
  209.     (CHAR) '\353',
  210.     (CHAR) '\154',
  211.     (CHAR) '\355',
  212.     (CHAR) '\356',
  213.     (CHAR) '\157',
  214.     (CHAR) '\360',
  215.     (CHAR) '\161',
  216.     (CHAR) '\162',
  217.     (CHAR) '\363',
  218.     (CHAR) '\164',
  219.     (CHAR) '\365',
  220.     (CHAR) '\366',
  221.     (CHAR) '\167',
  222.     (CHAR) '\170',
  223.     (CHAR) '\371',
  224.     (CHAR) '\372',
  225.     (CHAR) '\173',
  226.     (CHAR) '\374',
  227.     (CHAR) '\175',
  228.     (CHAR) '\176',
  229.     (CHAR) '\377'
  230. };
  231.  
  232. /* CRC generation tables */
  233.  
  234. long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L,
  235.   051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L,
  236.   0153215L, 0163416L, 0173617L
  237. };
  238.  
  239. long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L,
  240.   053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L,
  241.   0155745L, 0164576L, 0174367L
  242. };
  243.  
  244. #ifdef CK_TIMERS
  245. /*
  246.   Round-trip timer calculations adapted from Tim Kientzle's article,
  247.   "Improving Kermit Performance", Dr Dobb's Journal, February 1996.
  248. */
  249.  
  250. /*  R T T I N I T  --  Initialize timers at start of transaction  */
  251.  
  252. VOID
  253. rttinit() {                /* Initialize round-trip timing */
  254.     int i;
  255.  
  256.     rttsamples  = 0L;            /* Samples (packets) */
  257.     rttvariance = 0L;            /* Variance in delay */
  258.     rttdelay    = (long) timint * RTT_SCALE; /* Delay */
  259.     pktintvl    = (long) timint * RTT_SCALE; /* Delay */
  260.     rttstddev   = (long) timint * RTT_SCALE; /* Standard deviation of delay */
  261.  
  262.     /* Tables of timestamps indexed by packet sequence number */
  263.  
  264.     for (i = 0; i < 64; i++) {        
  265.     rrttbl[i] = -1;            /* Time each packet was received */
  266.     srttbl[i] = -1;            /* Time each packet was sent */
  267.     }
  268.     rcvtimo = timint;            /* Initial timeout is what user said */
  269. }
  270.  
  271. /*  G E T R T T  --  Get packet round trip time  */
  272. /*
  273.   Call with nakstate == 0 if file sender, nonzero if receiver,
  274.   and n == packet sequence number of the packet we just received.
  275.  
  276.   Returns:
  277.   -1 on failure with rcvtimo set to timint (what the user said), or:
  278.    0 on success with rcvtimo set to dynamically calculated value:
  279.      1 <= rcvtimo <= timint * 3.
  280. */
  281. int
  282. getrtt(nakstate, n) int nakstate, n; {
  283.     long rttdiff;
  284.     extern int mintime, maxtime;
  285.  
  286.     int x, y, yy, z = 0, zz = 0;    /* How long did it take to get here? */
  287.  
  288.     rcvtimo = timint;            /* Default timeout is what user said */
  289.  
  290.     if (timint == 0)            /* We're not timing out. */
  291.       return(0);
  292.  
  293.     if (!rttflg)            /* Not supposed to be doing this? */
  294.       return(-1);            /*  So don't */
  295.  
  296.     if (!RTT_SCALE)            /* Paranoia... */
  297.       return(-1);
  298.  
  299.     /* rtimer() (reset timer) is not called until 1st data packet */
  300.     /* S (F [ A ] D* Z)* B */
  301.  
  302.     /* NOTE: we calculate both the round-trip time AND the packet */
  303.     /* arrival rate.  We don't use the RTT for anything, we just display it. */
  304.     /* Timeouts are based on the packet arrival rate. */
  305.  
  306.     if (spackets > 3) {            /* Don't start till 4th packet */
  307.     if (nakstate) {            /* File receiver */
  308.         x = rrttbl[n];             /* Time when I got packet n */
  309.         y = rrttbl[n > 0 ? n - 1 : 63];  /* Time when I got packet n-1 */
  310.         yy = srttbl[n > 0 ? n - 1 : 63]; /* Time when I sent ACK(n-1) */
  311.         if (x > -1 && y > -1) {    /* Be careful */
  312.         z = x - y;        /* Packet rate */
  313.         zz = x - yy;        /* Round trip time */
  314.         debug(F101,"RTT RECV","",z);
  315.         } else {            /* This shouldn't happen */
  316.         debug(F101,"RTT RECV ERROR spackets","",spackets);
  317.         debug(F101,"RTT RECV ERROR sequence","",n);
  318.         return(-1);
  319.         }
  320.     } else {            /* File sender */
  321.         x = rrttbl[n];        /* Time when I got ACK(n) */
  322.         y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */
  323.         yy = srttbl[n];        /* Time when I sent n */
  324.         if (x > -1 && y > -1) {
  325.         z = x - y;        /* Packet rate */
  326.         zz = x - yy;        /* Round trip time */
  327.         debug(F101,"RTT SEND","",z);
  328.         } else {
  329.         debug(F100,"RTT SEND ERROR","",0);
  330.         return(-1);
  331.         }
  332.     }
  333.     if (z < 1)            /* For fast connections */
  334.       z = RTT_SCALE / 2;        /* Convert to scale... */
  335.     else
  336.       z *= RTT_SCALE;
  337.  
  338.     if (zz < 1)            /* For fast connections */
  339.       zz = RTT_SCALE / 2;        /* Convert to scale... */
  340.     else
  341.       zz *= RTT_SCALE;
  342.  
  343.     rttdelay = zz;            /* Round trip time of this packet */
  344.     if (rttsamples++ == 0L) {    /* First sample */
  345.         pktintvl = z;
  346.         rttdiff = 0;
  347.     } else {            /* Subsequent samples */
  348.         long oldavg = pktintvl;
  349.         long rttdiffsq;
  350.  
  351.         if (rttsamples > 30)    /* Use real average for first 30 */
  352.           rttsamples = 30;        /*  then decaying average. */
  353.  
  354.         /* Average delay, difference squared, variance, std deviation */
  355.  
  356.         pktintvl += (z - pktintvl) / rttsamples;
  357.         rttdiffsq = (z - oldavg) * (z - oldavg);
  358.         rttvariance += (rttdiffsq - rttvariance) / rttsamples;
  359.         debug(F101,"RTT stddev1","",rttstddev);
  360.         if (rttstddev < 1L)        /* It can be zero, in which case */
  361.           rttstddev = RTT_SCALE / 3; /* set it to something small... */
  362.         rttstddev = (rttstddev + rttvariance / rttstddev) / 2;
  363.     }
  364.     debug(F101,"RTT stddev2","",rttstddev);
  365.     debug(F101,"RTT delay  ","",pktintvl);
  366.     rcvtimo = (pktintvl + (3L * rttstddev)) / RTT_SCALE + 1;
  367.     if (rpackets < 32)        /* Allow for slow start */
  368.       rcvtimo += rcvtimo + 2;
  369.     else if (rpackets < 64)
  370.       rcvtimo += rcvtimo / 2 + 1;
  371.     if (rcvtimo < mintime)        /* Lower bound */
  372.       rcvtimo = mintime;
  373.     if (maxtime > 0) {        /* User specified an upper bound */
  374.         if (rcvtimo > maxtime)
  375.           rcvtimo = maxtime;
  376.     } else if (maxtime == 0) {    /* User didn't specify */
  377.         if (rcvtimo > timint * 6)
  378.           rcvtimo = timint * 6;
  379.     }
  380.     debug(F101,"RTT rcvtimo","",rcvtimo);
  381.     }
  382.     return(0);
  383. }
  384. #endif /* CK_TIMERS */
  385.  
  386. /*  I N P U T  --  Attempt to read packet number 'pktnum'.  */
  387.  
  388. /*
  389.  This is the function that feeds input to Kermit's finite state machine,
  390.  in the form of a character in the range 32-126, normally a packet type
  391.  (uppercase letter) or pseudo-packet-type (lowercase letter).
  392.  
  393.  If a special start state is in effect, that state is returned as if it were
  394.  the type of an incoming packet.
  395. */
  396. int
  397. input() {
  398.     int type, acktype;            /* Received packet type */
  399.     int x, y, k;            /* Workers */
  400.     int z, pi, nf;            /* Worker, packet index, NAK flag */
  401.     int nak2ack = 0;
  402.  
  403.     debug(F101,"input sstate","",sstate);
  404.     debug(F101," nakstate","",nakstate);
  405.     debug(F000," sndtyp","",sndtyp);
  406.  
  407.     while (1) {                /* Big loop... */
  408.  
  409.     if (sstate != 0) {        /* If a start state is in effect, */
  410.         type = sstate;        /* return it like a packet type, */
  411.         sstate = 0;            /* and then nullify it. */
  412.         numerrs = 0;        /* (PWP) no errors so far */
  413.         return(type);
  414.     }
  415.     
  416.     if (nakstate) {            /* This section for file receiver. */
  417.  
  418.         if (wslots > 1) {        /* If we're doing windows, */
  419.         x = rseqtbl[winlo];    /* see if desired packet already in. */
  420.         debug(F101," winlo","",winlo);
  421.         debug(F101," rseqtbl[winlo]","",rseqtbl[winlo]);
  422.         if (x > -1) {        /* Already there? */
  423.             if (r_pkt[x].pk_seq == winlo) { /* (double check) */
  424.             rsn = winlo;                /* Yes, return its info */
  425.             debug(F101,"input return pre-stashed packet","",rsn);
  426.             dumprbuf();
  427.             rdatap = r_pkt[x].pk_adr;   /* like rpack would do. */
  428.             rln = (int)strlen((char *) rdatap);
  429.             type = r_pkt[x].pk_typ;
  430.             break;
  431.             }
  432.         }
  433.         }
  434.         type = rpack();            /* Try to read a packet. */
  435.         debug(F111,"input recv",(char *) rdatap,(int) type);
  436.         while (type == 'e') {    /* Handle echoes */
  437.         debug(F000,"echo discarded","",type);
  438.         type = rpack();    
  439.         }        
  440. #ifndef OLDCHKINT
  441.         if (type == 'z') {
  442.         errpkt((CHAR *)"User cancelled.");
  443.         strcpy((char *)pktmsg,"User cancelled.");
  444.         type = 'E';
  445.         break;
  446.         }
  447. #endif /* OLDCHKINT */
  448.         if (type < -1) return('q'); /* Ctrl-C or connection lost */
  449.         if (type < 0) {        /* Receive window full */
  450.         /* Another thing to do here would be to delete */
  451.         /* the highest packet and NAK winlo.  But that */
  452.         /* shouldn't be necessary since the other Kermit */
  453.         /* should not have sent a packet outside the window. */
  454.         debug(F101,"rpack receive window full","",0);
  455.         dumprbuf();
  456.         errpkt((CHAR *)"Receive window full.");
  457.         strcpy((char *)pktmsg,"Receive window full.");
  458.         type = 'E';
  459.         break;
  460.         }
  461.         dumprbuf();
  462.  
  463. #ifdef OLDCHKINT
  464.         if (chkint() < 0) {        /* Check for console interrupts. */
  465.         errpkt((CHAR *)"User cancelled.");
  466.         strcpy((char *)pktmsg,"User cancelled.");
  467.         type = 'E';
  468.         break;
  469.         }
  470. #endif /* OLDCHKINT */
  471.  
  472.         if (type == 'E') {
  473.         debug(F101,"input got E, nakstate","",nakstate);
  474.         break;            /* Error packet */
  475.         }
  476.         if (type == 'Q') {        /* Crunched packet. */
  477.         crunched++;
  478.         numerrs++;
  479. /*
  480.   Packet arrived damaged.  It was most likely the packet we were expecting
  481.   next, so we send a NAK for that packet.  Prior to 5A(189), we always
  482.   NAK'd winlo here, but that was bad because if two (or more) different
  483.   packets were damaged, we would keep NAKing the first one and never NAK the
  484.   other ones, which could result in a lengthy series of timeouts.  Now we
  485.   NAK the oldest as-yet-unNAK'd missing packet.
  486. */
  487. #ifdef CK_TIMERS
  488.         rcvtimo++;        /* Stretch the timeout a little */
  489. #endif /* CK_TIMERS */
  490.         z = (winlo + wslots) % 64;  /* Search from winlo to z */
  491.         debug(F101,"ZZZ crunched z","",z);
  492.         nf = 0;                /* NAK flag not set yet */
  493.         for (x = winlo; x != z; x = (x + 1) % 64) {
  494.             debug(F101,"ZZZ x","",x);
  495.             if (rseqtbl[x] > -1) /* Have I received packet x? */
  496.               continue;         /* Yes, go on. */
  497.             debug(F101,"ZZZ x not recd yet","",x);
  498.             pi = sseqtbl[x];     /* No, have I NAK'd it yet? */
  499.             if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
  500.             debug(F101,"ZZZ x not NAK'd yet","",x);
  501.             nack(x);     /* No, NAK it now. */
  502.             nf = 1;         /* Flag that I did. */
  503.             break;
  504.             }
  505.         }
  506.         if (!nf) {        /* If we didn't NAK anything above, */
  507.             debug(F101,"ZZZ NAKing winlo","",winlo);
  508.             if (nack(winlo) < 0) { /* we have to NAK winlo (again) */
  509.             errpkt((CHAR *)"Too many retries."); /* Too many */
  510.             strcpy((char *)pktmsg,"Timed out."); /* Give up */
  511.             type = 'E';
  512.             break;
  513.             }
  514.         } 
  515.         continue;
  516.         }
  517.  
  518.         if (type == 'T') {        /* Timeout */
  519. #ifdef CK_TIMERS
  520.         rcvtimo++;        /* Stretch the timeout a little */
  521. #endif /* CK_TIMERS */
  522.         timeouts++;
  523.         debug(F101,"input receive-state timeout, winlo","",winlo);
  524.         /* NAK only the packet at window-low */
  525.         debug(F101,"input sending NAK for winlo","",winlo);
  526.         if (ttchk() > 0)    /* Don't give up if there is still */
  527.           continue;        /* something to read. */
  528.         if (nack(winlo) < 0) {
  529.             debug(F101,"input sent too many naks","",winlo);
  530.             errpkt((CHAR *)"Too many retries.");
  531.             strcpy((char *)pktmsg,"Sent too many NAKs.");
  532.             type = 'E';
  533.             break;
  534.         } else continue;
  535.         }
  536.  
  537.         if (rsn == winlo) {        /* Got the packet we want, done. */
  538. #ifdef CK_TIMERS
  539.         if (rttflg)        /* Dynamic round trip timers? */
  540.           getrtt(nakstate, rsn); /* yes, do it. */
  541. #endif /* CK_TIMERS */
  542.         debug(F101,"input rsn=winlo","",rsn);
  543.         break;
  544.         }
  545.  
  546.         /* Got a packet out of order. */
  547.  
  548.         debug(F101,"input recv got packet out of order","",rsn);
  549.         k = rseqtbl[rsn];        /* Get window slot of this packet. */
  550.         debug(F101,"input recv rseqtbl[rsn]","",k);
  551.         if (k < 0) {
  552.         debug(F101,"input recv can't find index for rcvd pkt","",rsn);
  553.         /* Was "Internal error 21" */
  554.         errpkt((CHAR *)"Sliding windows protocol error.");
  555.         strcpy((char *)pktmsg,"Sliding windows protocol error.");
  556.         type = 'E';
  557.         break;
  558.         }        
  559.         y = chkwin(rsn,winlo,wslots); /* See what window it's in. */
  560.         debug(F101,"input recv chkwin","",y);
  561.         if (y == 1) {        /* From previous window. */
  562.         resend(rsn);        /* Resend the ACK (might have data) */
  563.         freerpkt(rsn);        /* Get rid of received packet */
  564.         continue;
  565.         } else {            /* In this window or out of range */
  566.         if (y < 0)        /* If out of range entirely, */
  567.           freerpkt(rsn);    /* release its buffer */
  568.  
  569. #ifdef COMMENT /* Ignore this and read what comes afterwards... */
  570. /*
  571.   We have received a packet, but not the one we want.  It would seem to
  572.   make sense to always send a NAK for the most desired packet (winlo).  But
  573.   consider this scenario: a packet arrived damaged so we NAK'd it above;
  574.   then packets winlo+1, winlo+2, ... winlo+n arrive, each one making us
  575.   send another NAK for winlo, so the other Kermit gets n NAKs for winlo, and
  576.   either would have to resend it n times, or if n > retry limit, give up
  577.   because of too many retries.  So we compromise: If a packet arrives
  578.   that is not the most desired packet (winlo), we NAK winlo, BUT ONLY IF
  579.   it has not been NAK'd before.
  580. */
  581.         x = sseqtbl[winlo];    /* Get index of most desired packet */
  582.         if (s_pkt[x].pk_rtr == 0 ||   /* Not NAK'd before? */
  583.             rbufnum < 1) {          /* Or receive window full? */
  584.             if (nack(winlo) < 0) {    /* One or both, so NAK it now. */
  585.             errpkt((CHAR *)"Too many retries."); /* Too many */
  586.             strcpy((char *)pktmsg,"Timed out."); /* Give up */
  587.             type = 'E';
  588.             break;
  589.             } else continue;
  590.         } else continue;
  591. #endif /* COMMENT */
  592.  
  593. /*
  594.   In version 5A(189), the strategy was revised to send NAKs for the oldest
  595.   missing packet that had not been NAK'd before, which requires a search.
  596.   Thus, if winlo was already NAK'd, instead of doing nothing, we send a NAK
  597.   for the "lowest" as-yet-unNAK'd missing packet.
  598.  
  599.   If our receive window is full, however, we have no choice but to NAK winlo:
  600. */
  601.         debug(F101,"XXX checking rbufnum","",rbufnum);
  602.         if (rbufnum < 1) {    /* Receive window full? */
  603.             debug(F101,"XXX out of buffers","",rbufnum); /* Yes */
  604.             if (nack(winlo) < 0) {    /* No choice, must NAK winlo. */
  605.             errpkt((CHAR *)"Too many retries."); /* Too many */
  606.             strcpy((char *)pktmsg,"Timed out."); /* Give up */
  607.             type = 'E';
  608.             break;
  609.             } else continue;
  610.         }
  611. /*
  612.   Receive window not full.  This is a packet in the current window but it is
  613.   not the desired packet at winlo.  So therefore there are gaps before this
  614.   packet.  So we find the "lowest" unNAK'd missing packet, if any, between
  615.   winlo and this one, and NAK it.  If there are no as-yet-unNAK'd missing
  616.   packets in the window, then we send nothing and go wait for another packet.
  617.   In theory, this could result in a timeout, but in practice it is likely that
  618.   the already-NAK'd missing packets are already on their way.  Note, we do not
  619.   NAK ahead of ourselves, as that only creates unnecessary retransmissions.
  620. */
  621.         debug(F101,"XXX winlo","",winlo);
  622.         for (x = winlo; x != rsn; x = (x + 1) % 64) {
  623.             debug(F101,"XXX x","",x);
  624.             if (rseqtbl[x] > -1) /* Have I received packet x? */
  625.               continue;         /* Yes, check next sequence number. */
  626.             debug(F101,"XXX missing pkt","",x);
  627.             pi = sseqtbl[x];     /* No, have I NAK'd it yet? */
  628.             if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
  629.             nack(x);     /* No, NAK it now. */
  630.             debug(F101,"XXX nak","",x);
  631.             break;
  632.             }
  633.         }
  634.         }
  635. /*!!!*/
  636.     } else {            /* Otherwise file sender... */
  637.  
  638.         if (!nak2ack) {        /* NAK(n+1) = ACK(n) */
  639.  
  640.         if (wslots > 1) {    /* Packet at winlo already ACK'd? */
  641.             if (sacktbl[winlo]) { /* If so,  */
  642.             sacktbl[winlo] = 0; /* Turn off the ACK'd flag */
  643.             winlo = (winlo + 1) % 64; /* Rotate the window */
  644.             type = 'Y';    /* And return ACK */
  645.             debug(F101,
  646.                   "input send returning pre-stashed ACK","",
  647.                   winlo-1);
  648.             break;
  649.             }
  650.         }
  651.         type = rpack();        /* Try to read an acknowledgement */
  652.         debug(F111,"input send",(char *) rdatap,(int) type);
  653.         while (type == 'e') {    /* Handle echoes */
  654.             debug(F000,"echo discarded","",type);
  655.             type = rpack();    
  656.         }        
  657. #ifndef OLDCHKINT
  658.         if (type == 'z') {
  659.             errpkt((CHAR *)"User cancelled.");
  660.             strcpy((char *)pktmsg,"User cancelled.");
  661.             type = 'E';
  662.             break;
  663.         }
  664. #endif /* OLDCHKINT */
  665.         if (type == -2) return('q');
  666.         if (type == -1) {
  667.             errpkt((CHAR *)"Receive window full"); /* was "internal */
  668.             debug(F101," wslots","",wslots); /* error 18" */
  669.             debug(F101," winlo","",winlo);
  670.             debug(F101," pktnum","",pktnum);
  671.             dumprbuf();
  672.             strcpy((char *)pktmsg,"Can't allocate receive buffer");
  673.             type = 'E';
  674.             break;
  675.         }
  676.         dumprbuf();        /* Debugging */
  677.  
  678. #ifdef OLDCHKINT
  679.         if (chkint() < 0) {    /* Check for console interrupts. */
  680.             errpkt((CHAR *)"User cancelled.");
  681.             strcpy((char *)pktmsg,"User cancelled.");
  682.             return(type = 'E');
  683.         }
  684. #endif /* OLDCHKINT */
  685.  
  686.         /* Got a packet */
  687.  
  688.         if (type == 'E') {
  689.             debug(F101,"input send got E, nakstate","",nakstate);
  690.             break;        /* Error packet */
  691.         }
  692.         if (type == 'Q') {    /* Crunched packet */ 
  693.             crunched++;        /* For statistics */
  694.             numerrs++;        /* For packet resizing */
  695.             x = resend(winlo);    /* Resend window-low */
  696.             if (x < 0) {
  697.             type = 'E';
  698.             errpkt(pktmsg);
  699.             break;
  700.             }
  701.             continue;
  702.         }
  703.         if (type == 'T') {    /* Timeout waiting for ACKs. */
  704.             timeouts++;        /* Count it */
  705.             numerrs++;        /* Count an error too */
  706.             debug(F101,"input send state timeout, winlo","",winlo);
  707.  
  708.             /* Retransmit the oldest un-ACK'd packet. */
  709.  
  710.             debug(F101,"input send resending winlo","",winlo);
  711.             if (resend(winlo) < 0) { /* Check retries */
  712.             debug(F101,"input send too many resends","",maxtry);
  713.             errpkt(pktmsg);
  714.             return(type = 'E');
  715.             }
  716. #ifdef NEWDPL
  717.             /* Reduce prevailing packet length */
  718.             x = sseqtbl[winlo];    /* Get length of packet we want ACKd */
  719.             if (x > -1) {    /* Only if we have a valid index */
  720.             if (s_pkt[x].pk_typ == 'D') { /* only for D packets */
  721.                 spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */
  722.                 if (spsiz < 20) spsiz = 20; /* within reason */
  723.                 debug(F101,"input T cut packet length","",spsiz);
  724.             }
  725.             }
  726. #endif /* NEWDPL */
  727.             continue;
  728.         }
  729.         }
  730.         /* Got an actual normal packet */
  731.  
  732.         nak2ack = 0;        /* Unset this flag. */
  733.         y = chkwin(rsn,winlo,wslots); /* Is it in the window? */
  734.         debug(F101,"input send rsn","",rsn);
  735.         debug(F101,"input send winlo","",winlo);
  736.         debug(F101,"input send chkwin","",y);
  737.  
  738.         if (type == 'Y') {        /* Got an ACK */
  739.         if (y == 0) {        /* In current window */
  740.             if (spackets < 4)    /* Error counter doesn't count */
  741.               numerrs = 0;    /* until data phase. */
  742.             sacktbl[rsn]++;    /* Mark the packet as ACK'd */
  743.             x = sseqtbl[rsn];    /* Get ACK'd packet's buffer index */
  744.             debug(F101,"bestlen ack x","",x);
  745. #ifdef NEWDPL
  746.             if (x > -1) {
  747.             acktype = s_pkt[x].pk_typ; /* Get type */
  748.             debug(F000,"bestlen ack type","",acktype);
  749.  
  750.             if (acktype == 'D') { /* Adjust data packet length */
  751.                 if (spsiz > bestlen) {
  752.                 bestlen = spsiz;
  753.                 debug(F101,"bestlen B","",bestlen);
  754.                 }
  755. #ifdef DEBUG            
  756.                 if (deblog) {
  757.                 debug(F101,"bestlen retry","",s_pkt[x].pk_rtr);
  758.                 debug(F101,"bestlen len","",s_pkt[x].pk_len);
  759.                 debug(F101,"bestlen spackets","",spackets);
  760.                 }
  761. #endif /* DEBUG */
  762.                 /* Set new best length */
  763.                 if (s_pkt[x].pk_rtr == 0 &&
  764.                 s_pkt[x].pk_len + 8 > bestlen) {
  765.                 bestlen = s_pkt[x].pk_len + 8;
  766.                 if (bestlen > spmax)
  767.                   bestlen = spmax;
  768.                 debug(F101,"bestlen A","",bestlen);
  769.                 }
  770. #ifdef DEBUG            
  771.                 if (deblog) {
  772.                 debug(F101,"bestlen wslots","",wslots);
  773.                 debug(F101,"bestlen maxsend","",maxsend);
  774.                 }
  775. #endif /* DEBUG */
  776.                 /* Slow start */
  777.                 if (slostart &&
  778.                 (maxsend <= spmax) &&
  779.                 (rpackets < 11) &&
  780.                 (numerrs == 0)) {
  781.                 spsiz = spsiz << 1;
  782.                 debug(F101,"bestlen spsiz A","",spsiz);
  783.  
  784.                 /* Creep up to best length */
  785.                 } else if ((spackets > 5) &&
  786.                        (spsiz < bestlen - 8)) {
  787.                 spsiz += (bestlen - spsiz) / 3;
  788.                 debug(F101,"bestlen spsiz B","",spsiz);
  789.  
  790.                 /* Push the envelope */
  791.                 } else if ((spackets % (wslots + 1) == 0) &&
  792.                        (spackets > 6) &&
  793.                        (bestlen < spmax - 8) &&
  794.                        (spsiz < spmax)) {
  795.                 spsiz += (spmax - bestlen) / 3;
  796.                 debug(F101,"bestlen spsiz C","",spsiz);
  797.                 }
  798.                 /* But not too far */
  799.                 if (spsiz > spmax) {
  800.                 spsiz = spmax;
  801.                 debug(F101,"bestlen spsiz D","",spsiz);
  802.                 }
  803.             }
  804.             }
  805. #endif /* NEWDPL */
  806.  
  807. #ifdef CK_TIMERS
  808.             if (rttflg)        /* If doing dynamic timers */
  809.               getrtt(nakstate, rsn); /* call routine to set it. */
  810. #endif /* CK_TIMERS */
  811. /*
  812.   NOTE: The following statement frees the buffer of the ACK we just got.
  813.   But the upper layers still need the data, like if it's the ACK to an I,
  814.   S, F, D, Z, or just about any kind of packet.  So for now, freerbuf()
  815.   deallocates the buffer, but does not erase the data or destroy the pointer
  816.   to it.  There's no other single place where these receive buffers can be
  817.   correctly freed (?) ...
  818. */
  819.             freerpkt(rsn);    /* Free the ACK's buffer */
  820.             freesbuf(rsn);    /* *** Free the sent packet's buffer */
  821.             if (rsn == winlo) {    /* Got the one we want */
  822.             sacktbl[winlo] = 0;
  823.             winlo = (winlo + 1) % 64;
  824.             debug(F101,"input send rotated send window","",winlo);
  825.             break;        /* Return the ACK */
  826.             } else {
  827.             debug(F101,"input send mark pkt","",rsn);
  828.             continue;    /* Otherwise go read another packet */
  829.             }
  830.         } else if (y == 1 && wslots < 2) { /* (190) ACK for previous */
  831.             numerrs++;        /* == NAK for current, count error */
  832.             debug(F101,"input send ACK for previous","",rsn);
  833.             freerpkt(rsn);    /* Free NAK's buffer */
  834.             x = resend(winlo);    /* Resend current packet */
  835.             if (x < 0) {
  836.             type = 'E';
  837.             errpkt(pktmsg);
  838.             break;
  839.             } else continue;    /* Resend ok, go read another packet */
  840.         } else {        /* Other cases, just ignore */
  841.             debug(F101,"input send ACK out of window","",rsn);
  842.             freerpkt(rsn);
  843.             continue;
  844.         }
  845.         }
  846.         if (type == 'N') {        /* NAK */
  847.         numerrs++;        /* Count an error */
  848.         debug(F101,"input send NAK","",rsn);
  849. #ifdef NEWDPL
  850.         /* Reduce prevailing packet length */
  851.         x = sseqtbl[rsn];    /* Length of packet that was NAK'd */
  852.         if (x > -1) {        /* If it's a Data packet we've sent */
  853.             if (s_pkt[x].pk_typ == 'D') {
  854.             spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */
  855. #ifdef COMMENT
  856.             /* This might be a good idea -- haven't tried it ... */
  857.             if (bestlen > 0 && spsiz > bestlen)
  858.               spsiz = bestlen;
  859. #endif /* COMMENT */
  860.             if (spsiz < 20) spsiz = 20;
  861.             debug(F101,"input N cut packet length","",spsiz);
  862.             }
  863.         }
  864. #endif /* NEWDPL */
  865.         freerpkt(rsn);        /* Free buffer where NAK lies. */
  866.         if (y == 0) {        /* In current window */        
  867.             debug(F100," in window","",0);
  868.             k = sseqtbl[rsn];    /* Get pointer to NAK'd packet. */
  869.             if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) {
  870.             x = resend(winlo); /* Packet we haven't sent yet. */
  871.             } else {
  872.             x = resend(rsn); /* Resend requested packet. */
  873.             }
  874.             if (x < 0) {    /* Resend error is fatal.  */
  875.             type = 'E';
  876.             errpkt(pktmsg);
  877.             break;
  878.             } else continue;    /* Resend ok, go read another packet */
  879.         } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */
  880.             if (wslots > 1) {
  881.             debug( F101,"NAK for next packet, windowing","",rsn);
  882.             x = resend(winlo); /* Resend window-low */
  883.             if (x < 0) {
  884.                 type = 'E';
  885.                 errpkt(pktmsg);
  886.                 break;
  887.             }
  888.             continue;    /* Go back and read another pkt */
  889.             }
  890.             debug(F101,"NAK for next packet, no windowing","",rsn);
  891.             x = (rsn == 0) ? 63 : rsn - 1;
  892.             if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) {
  893.             resend(0);    /* ACK for S or I packet missing */
  894.             continue;    /* so resend the S or I */
  895.             }        
  896.             rsn = x;        /* Else, treat NAK(n+1) as ACK(n) */
  897.             nak2ack = 1;    /* Go back and process the ACK */
  898.             continue;
  899.         } else if (y > 0) {    /* NAK for pkt we can't resend */
  900.             debug(F101," NAK out of window","",rsn); /* bad... */
  901.             type = 'E';
  902.             errpkt((CHAR *)"NAK out of window");
  903.             strcpy((char *)pktmsg,"NAK out of window.");
  904.             break;
  905.         } else continue;    /* Ignore other NAKs */
  906.         }                /* End of file-sender NAK handler */
  907.  
  908.             if (rsn == winlo) {        /* Not ACK, NAK, timeout, etc. */
  909.         debug(F000,"input send unexpected type","",type);
  910.         break;
  911.         }
  912.     }                /* End of file-sender section */
  913.     }                    /* End of input() while() loop */
  914.     if (wslots == 1) {
  915.     debug(F100,"input about to flush","",0);
  916.     ttflui();        /* Got what we want, clear input buffer. */
  917.     }
  918. #ifndef NEWDPL
  919.     if (!nakstate)        /* When sending */
  920.       rcalcpsz();        /* recalculate size every packet */
  921. #endif /* NEWDPL */
  922.     debug(F000,"input returning type","",type);
  923.     return(rcvtyp = type);    /* Success, return packet type. */
  924. }
  925.  
  926. /*  D O P A R  --  Add an appropriate parity bit to a character  */
  927.  
  928. /*
  929.   (PWP) this is still used in the Mac terminal emulator, so we have to keep it
  930. */
  931. CHAR
  932. #ifdef CK_ANSIC
  933. dopar(register CHAR ch)
  934. #else
  935. dopar(ch) register CHAR ch;
  936. #endif /* CK_ANSIC */
  937.     {
  938.     register unsigned int a;
  939.     if (!parity
  940. #ifdef TCPSOCKET        
  941.         || (network &&        /* TELNET BINARY MODE */
  942.         (ttnproto == NP_TELNET) && (me_binary) )
  943. #endif /* TCPSOCKET */
  944.         ) return((CHAR) (ch & 255)); else a = ch & 127;
  945.     switch (parity) {
  946.     case 'e':  return(p_tbl[a]);                 /* Even */
  947.     case 'm':  return((CHAR) (a | 128));         /* Mark */
  948.     case 'o':  return((CHAR) (p_tbl[a] ^ 128));  /* Odd */
  949.     case 's':  return((CHAR) a);                 /* Space */
  950.     default:   return((CHAR) a);                 /* Something illegal */
  951.     }
  952. }
  953.  
  954. #ifdef PARSENSE
  955. /*  P A R C H K  --  Check if Kermit packet has parity  */
  956.  
  957. /*
  958.   Call with s = pointer to packet, start = packet start character, n = length.
  959.   Returns 0 if packet has no parity, -1 on error, or, if packet has parity:
  960.     'e' for even, 'o' for odd, 'm' for mark.  Space parity cannot be sensed.
  961.   So a return value of 0 really means either space or none.
  962.   Returns -2 if parity has already been checked during this protocol operation.
  963. */
  964. int
  965. #ifdef CK_ANSIC
  966. parchk(CHAR *s, CHAR start, int n)
  967. #else
  968. parchk(s,start,n) CHAR *s, start; int n;
  969. #endif /* CK_ANSIC */
  970. /* parchk */ {
  971.     CHAR s0, s1, s2, s3;
  972.  
  973.     debug(F101,"parchk n","",n);
  974.     debug(F101,"parchk start","",start);
  975.  
  976.     s0 = s[0] & 0x7f;            /* Mark field (usually Ctrl-A) */
  977.  
  978.     if (s0 != start || n < 5) return(-1); /* Not a valid packet */
  979.  
  980. /* Look at packet control fields, which never have 8th bit set */
  981. /* First check for no parity, most common case. */
  982.  
  983.     if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0)
  984.       return(0);            /* No parity or space parity */
  985.  
  986. /* Check for mark parity */
  987.  
  988.     if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80)
  989.       return('m');            /* Mark parity */
  990.  
  991. /* Packet has some kind of parity */
  992. /* Make 7-bit copies of control fields */
  993.  
  994.     s1 = s[1] & 0x7f;            /* LEN */
  995.     s2 = s[2] & 0x7f;            /* SEQ */
  996.     s3 = s[3] & 0x7f;            /* TYPE */
  997.  
  998. /* Check for even parity */
  999.  
  1000.     if ((s[0] == p_tbl[s0]) &&
  1001.         (s[1] == p_tbl[s1]) &&
  1002.         (s[2] == p_tbl[s2]) &&
  1003.     (s[3] == p_tbl[s3]))
  1004.       return('e');
  1005.  
  1006. /* Check for odd parity */
  1007.  
  1008.     if ((s[0] != p_tbl[s0]) &&
  1009.         (s[1] != p_tbl[s1]) &&
  1010.         (s[2] != p_tbl[s2]) &&
  1011.     (s[3] != p_tbl[s3]))
  1012.       return('o');
  1013.  
  1014. /* Otherwise it's probably line noise.  Let checksum calculation catch it. */
  1015.  
  1016.     return(-1);
  1017. }
  1018. #endif /* PARSENSE */
  1019.  
  1020. /*
  1021.   Check to make sure timeout intervals are long enough to allow maximum
  1022.   length packets to get through before the timer goes off.  If not, the
  1023.   timeout interval is adjusted upwards.
  1024.  
  1025.   This routine is called at the beginning of a transaction, before we
  1026.   know anything about the delay characteristics of the line.  It works
  1027.   only for serial communication devices; it trusts the speed reported by
  1028.   the operating system.
  1029.  
  1030.   Call with a timout interval.  Returns it, adjusted if necessary.
  1031. */  
  1032. int
  1033. chktimo(timo,flag) int timo, flag; {
  1034.     long cps, z; int x, y;
  1035.     debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */
  1036.     debug(F101,"chktimo flag","",flag);
  1037.  
  1038.     if (flag)                /* Don't change timeout if user */
  1039.       return(timo);            /* gave SET SEND TIMEOUT command. */
  1040.     debug(F101,"chktimo spmax","",spmax);
  1041.     debug(F101,"chktimo urpsiz","",urpsiz);
  1042.  
  1043.     speed = ttgspd();            /* Get current speed. */
  1044.     if (speed > 0L && !network) {
  1045.     cps = speed / 10L;        /* Convert to chars per second */
  1046.     if (cps > 0L) {
  1047.         long plen;            /* Maximum of send and rcv pkt size */
  1048.         z = cps * (long) timo;    /* Chars per timeout interval */
  1049.         z -= z / 10L;        /* Less 10 percent */
  1050.         plen = spmax;
  1051.         if (urpsiz > spmax) plen = urpsiz;
  1052.         debug(F101,"chktimo plen","",plen);
  1053.         if (z < plen) {        /* Compare with packet size */
  1054.         x = (int) ((long) plen / cps); /* Adjust if necessary */
  1055.         y = x / 10;        /* Add 10 percent for safety */
  1056.         if (y < 2) y = 2;    /* Or 2 seconds, whichever is more */
  1057.         x += y;
  1058.         if (x > timo)        /* If this is greater than current */
  1059.           timo = x;        /* timeout, change the timeout */
  1060.         debug(F101,"chktimo new timo","",timo);
  1061.         }
  1062.     }
  1063.     }
  1064.     return(timo);
  1065. }
  1066.  
  1067. /*  S P A C K  --  Construct and send a packet  */
  1068.  
  1069. /*
  1070.   spack() sends a packet of the given type, sequence number n, with len data
  1071.   characters pointed to by d, in either a regular or extended- length packet,
  1072.   depending on len.  Returns the number of bytes actually sent, or else -1
  1073.   upon failure.  Uses global npad, padch, mystch, bctu, data.  Leaves packet 
  1074.   fully built and null-terminated for later retransmission by resend().
  1075.   Updates global sndpktl (send-packet length).
  1076.  
  1077.   NOTE: The global pointer "data" is assumed to point into the 7th position
  1078.   of a character array (presumably in packet buffer for the current packet).
  1079.   It was used by getpkt() to build the packet data field.  spack() fills in
  1080.   the header to the left of the data pointer (the data pointer is defined
  1081.   in getsbuf() in ckcfn3.c).  If the address "d" is the same as "data", then
  1082.   the packet's data field has been built "in place" and need not be copied.
  1083. */
  1084. int
  1085. #ifdef CK_ANSIC
  1086. spack(char pkttyp, int n, int len, CHAR *d)
  1087. #else
  1088. spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d;
  1089. #endif /* CK_ANSIC */
  1090. /* spack */ {
  1091.     register int i;
  1092.     int j, k, x, lp, longpkt, copy;
  1093.  
  1094. #ifdef GETMSEC
  1095.     long t1, t2;
  1096. #endif /* GETMSEC */
  1097.  
  1098.     register CHAR *cp, *mydata;
  1099.     unsigned crc;
  1100.  
  1101.     debug(F101,"spack n","",n);
  1102.     debug(F111,"spack data",data,data);
  1103.     /* debug(F101,"spack d","",d); */
  1104.     debug(F101,"spack len","",len);
  1105.  
  1106.     copy = (d != data);            /* Flag whether data must be copied  */
  1107.     longpkt = (len + bctl + 2) > 94;    /* Decide whether it's a long packet */
  1108.     mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */
  1109.     debug(F101," mydata","",mydata);
  1110.  
  1111.     k = sseqtbl[n];            /* Packet structure info for pkt n */ 
  1112.     debug(F101," sseqtbl[n]","",k);
  1113.     if (k < 0) {
  1114.     debug(F101,"spack sending packet out of window","",n);
  1115.     } else {                /* Record packet info */
  1116.     s_pkt[k].pk_adr = mydata;    /* Remember address of packet. */
  1117.     s_pkt[k].pk_seq = n;        /* Record sequence number */
  1118.     s_pkt[k].pk_typ = pkttyp;    /* Record packet type */
  1119.     }
  1120.     spktl = 0;                /* Initialize length of this packet */
  1121.     i = 0;                /* and position in packet. */
  1122.  
  1123. /* Now fill the packet */
  1124.  
  1125.     mydata[i++] = mystch;        /* MARK */
  1126.     lp = i++;                /* Position of LEN, fill in later */
  1127.  
  1128.     mydata[i++] = tochar(n);        /* SEQ field */
  1129.     mydata[i++] = pkttyp;        /* TYPE field */
  1130.     j = len + bctl;            /* Length of data + block check */
  1131.     if (longpkt) {            /* Long packet? */
  1132.     int x;                /* Work around SCO Xenix/286 */
  1133.     x = j / 95;            /* compiler bug... */
  1134.         mydata[lp] = tochar(0);        /* Yes, set LEN to zero */
  1135.         mydata[i++] = tochar(x);    /* High part */
  1136.         mydata[i++] = tochar(j % 95);    /* Low part */
  1137.         mydata[i] = '\0';        /* Header checksum */
  1138.         mydata[i++] = tochar(chk1(mydata+lp));
  1139.     } else mydata[lp] = tochar(j+2);    /* Normal LEN */
  1140.  
  1141.     if (copy)                /* Data field built in place? */
  1142.       for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */
  1143.     else                /* Otherwise, */
  1144.       i += len;                /* Just skip past data field. */
  1145.     mydata[i] = '\0';            /* Null-terminate for checksum calc. */
  1146.  
  1147.     switch (bctu) {            /* Block check */
  1148.     case 1:                /* 1 = 6-bit chksum */
  1149.         mydata[i++] = tochar(chk1(mydata+lp));
  1150.         break;
  1151.     case 2:                /* 2 = 12-bit chksum */
  1152.         j = chk2(mydata+lp);
  1153.         mydata[i++] = (unsigned)tochar((j >> 6) & 077);
  1154.            mydata[i++] = (unsigned)tochar(j & 077);
  1155.         break;
  1156.         case 3:                /* 3 = 16-bit CRC */
  1157.         crc = chk3(mydata+lp,parity);
  1158.         mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12);
  1159.         mydata[i++] = (unsigned)tochar((crc >> 6) & 077);
  1160.         mydata[i++] = (unsigned)tochar(crc & 077);
  1161.         break;
  1162.     case 4:                /* 2 = 12-bit chksum, blank-free */
  1163.         j = chk2(mydata+lp);    
  1164.         mydata[i++] =
  1165.           (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1)));
  1166.            mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1)));
  1167.         break;
  1168.     }
  1169.     mydata[i++] = seol;            /* End of line (packet terminator) */
  1170. #ifdef TCPSOCKET
  1171. /*
  1172.   If TELNET connection and packet terminator is carriage return,
  1173.   we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE
  1174.   (tn_nlm), to meet the TELNET specification, unless user said RAW.
  1175.  
  1176.   If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL
  1177.   on a NVT connection and CR on a binary connection.
  1178. */
  1179.     if (seol == CR && network && ttnproto == NP_TELNET) {
  1180.         switch (me_binary ? tn_b_nlm : tn_nlm) { /* NVT or BINARY */
  1181.             case TNL_CR:
  1182.                 break;
  1183.             case TNL_CRNUL:
  1184.                 mydata[i++] = NUL ;
  1185.                 break;
  1186.             case TNL_CRLF:
  1187.                 mydata[i++] = LF ;
  1188.                 break;
  1189.             }
  1190.       }
  1191. #endif /* TCPSOCKET */
  1192.     mydata[i] = '\0';            /* Terminate string */
  1193.     logpkt('s',n,mydata);        /* Log packet */
  1194.  
  1195.     /* (PWP) add the parity quickly at the end */
  1196.     switch (parity) {
  1197.       case 'e':                /* Even */
  1198.     for (cp = &mydata[i-1]; cp >= mydata; cp--)
  1199.       *cp = p_tbl[*cp];
  1200.     break;
  1201.       case 'm':                /* Mark */
  1202.     for (cp = &mydata[i-1]; cp >= mydata; cp--)
  1203.       *cp |= 128;
  1204.     break;
  1205.       case 'o':                /* Odd */
  1206.     for (cp = &mydata[i-1]; cp >= mydata; cp--)
  1207.       *cp = p_tbl[*cp] ^ 128;
  1208.     break;
  1209.       case 's':                /* Space */
  1210.     for (cp = &mydata[i-1]; cp >= mydata; cp--)
  1211.       *cp &= 127;
  1212.     break;
  1213.     }
  1214.     if (pktpaus) msleep(pktpaus);    /* Pause if requested */
  1215.     if (npad) ttol(padbuf,npad);    /* Send any padding */
  1216. #ifdef CK_TIMERS
  1217.     if (pkttyp == 'N')
  1218.       srttbl[n > 0 ? n-1 : 63] = gtimer();
  1219.     else
  1220.       srttbl[n] = gtimer();
  1221. #endif /* CK_TIMERS */
  1222.     spktl = i;                /* Remember packet length */
  1223.     if (k > -1)
  1224.       s_pkt[k].pk_len = spktl;        /* also in packet info structure */
  1225.  
  1226. #ifdef GETMSEC
  1227.     if (deblog) t1 = getmsec();
  1228. #endif /* GETMSEC */
  1229.  
  1230.     x = ttol(mydata,spktl);
  1231.     if (spktl > maxsend) maxsend = spktl;
  1232.  
  1233. #ifdef GETMSEC
  1234.     if (deblog)  {
  1235.     t2 = getmsec();
  1236.     if (t2 > -1L && t1 > -1L)
  1237.       debug(F101,"spack ttol time","",t2-t1);
  1238.     else
  1239.       debug(F100,"spack ttol time error","",0);
  1240.     }
  1241. #endif /* GETMSEC */
  1242.  
  1243.     debug(F101,"spack ttol returns","",x);
  1244.     if (x < 0)
  1245.       return(x);
  1246.     sndtyp = pkttyp;            /* Remember packet type for echos */
  1247.     spackets++;                /* Count it. */
  1248.     flco += spktl;            /* Count the characters */
  1249.     tlco += spktl;            /* for statistics... */
  1250.     dumpsbuf();                /* Dump send buffers to debug log */
  1251.     debug(F100,"spack about to call screen","",0);
  1252.     debug(F111," with mydata=",mydata,n);
  1253.     screen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */
  1254.     return(spktl);            /* Return length */
  1255. }
  1256.  
  1257. /*  C H K 1  --  Compute a type-1 Kermit 6-bit checksum.  */
  1258.  
  1259. int
  1260. chk1(pkt) register CHAR *pkt; {
  1261.     register unsigned int chk;
  1262.     chk = chk2(pkt);
  1263.     chk = (((chk & 0300) >> 6) + chk) & 077;
  1264.     return((int) chk);
  1265. }
  1266.  
  1267. /*  C H K 2  --  Compute the numeric sum of all the bytes in the packet.  */
  1268.  
  1269. unsigned int
  1270. chk2(pkt) register CHAR *pkt; {
  1271.     register long chk; register unsigned int m;
  1272.     m = (parity) ? 0177 : 0377;
  1273.     for (chk = 0; *pkt != '\0'; pkt++)
  1274.       chk += *pkt & m;
  1275.     return((unsigned int) (chk & 07777));
  1276. }
  1277.  
  1278.  
  1279. /*  C H K 3  --  Compute a type-3 Kermit block check.  */
  1280. /*
  1281.  Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup 
  1282.  table.  Assumes the argument string contains no embedded nulls.
  1283. */
  1284. unsigned int
  1285. chk3(pkt,parity) register CHAR *pkt; int parity; {
  1286.     register long c, crc;
  1287.     register unsigned int m;
  1288.     m = (parity) ? 0177 : 0377;
  1289.     for (crc = 0; *pkt != '\0'; pkt++) {
  1290.     c = crc ^ (long)(*pkt & m);
  1291.     crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
  1292.     }
  1293.     return((unsigned int) (crc & 0xFFFF));
  1294. }
  1295.  
  1296. int
  1297. nxtpkt() {                /* Called by file sender */
  1298.     int j, n;
  1299.  
  1300.     debug(F101,"nxtpkt pktnum","",pktnum);
  1301.     debug(F101,"nxtpkt winlo ","",winlo);
  1302.     n = (pktnum + 1) % 64;        /* Increment packet number mod 64 */
  1303. #ifdef COMMENT 
  1304. /*
  1305.   Suggested by Alan Grieg.  A packet can be sent out of window in 
  1306.   circumstances involving acks received out of order, ...  Have to think
  1307.   about this...
  1308. */
  1309.     if (chkwin(n,winlo,wslots)) {
  1310.     debug(F101,"nxtpkt n not in window","",n);
  1311.     return(-1);
  1312.     }
  1313. #endif
  1314.     j = getsbuf(n);            /* Get a buffer for packet n */
  1315.     if (j < 0) {
  1316.     debug(F101,"nxtpkt can't getsbuf","",j);
  1317.     return(-1);
  1318.     }
  1319.     pktnum = n;          
  1320.     debug(F101,"nxtpkt bumped pktnum to","",pktnum);
  1321.     return(0);
  1322. }
  1323.  
  1324. /* Functions for sending ACKs and NAKs */
  1325.  
  1326. /* Note, we should only ACK the packet at window-low (winlo) */
  1327. /* However, if an old packet arrives again (e.g. because the ACK we sent */
  1328. /* earlier was lost), we ACK it again. */
  1329.  
  1330. int
  1331. ack() {                    /* Acknowledge the current packet. */
  1332.     return(ackns(winlo,(CHAR *)""));
  1333. }
  1334.  
  1335. int
  1336. ackns(n,s) int n; CHAR *s; {        /* Acknowledge packet n */
  1337.     int j, k;
  1338.     debug(F111,"ackns",s,n);
  1339.  
  1340.     k = rseqtbl[n];            /* First find received packet n. */
  1341.     debug(F101,"ackns k","",k);
  1342.     freesbuf(n);            /* Free current send-buffer, if any */
  1343.     if ((j = getsbuf(n)) < 0) {
  1344.     /* This can happen if we have to re-ACK an old packet that has */
  1345.         /* already left the window.  It does no harm. */
  1346.     debug(F101,"ackns can't getsbuf","",n);
  1347.     }
  1348.     spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */
  1349.     debug(F101,"ackns winlo","",winlo);
  1350.     debug(F101,"ackns n","",n);
  1351.     if (n == winlo) {            /* If we're acking winlo */
  1352.     if (k > -1)
  1353.       freerbuf(k);            /* don't need it any more */
  1354.     if (j > -1)
  1355.       freesbuf(j);            /* and don't need to keep ACK either */
  1356.     winlo = (winlo + 1) % 64;
  1357.     }
  1358.     return(0);
  1359. }
  1360.  
  1361. int
  1362. ackn(n) int n; {            /* Send ACK for packet number n */
  1363.     return(ackns(n,(CHAR *)""));
  1364. }
  1365.  
  1366. int
  1367. ack1(s) CHAR *s; {            /* Send an ACK with data. */
  1368.     debug(F110,"ack1",(char *) s,0);
  1369.     return(ackns(winlo, s));
  1370. }
  1371.  
  1372. /* N A C K  --   Send a Negative ACKnowledgment. */
  1373. /*
  1374.  Call with the packet number, n, to be NAK'd.
  1375.  Returns -1 if that packet has been NAK'd too many times, otherwise 0.
  1376.  Btw, it is not right to return 0 under error conditions.  This is
  1377.  done because the -1 code is used for cancelling the file transfer.
  1378.  More work is needed here.
  1379. */
  1380. int
  1381. nack(n) int n; {
  1382.     int i;
  1383.  
  1384.     if (n < 0 || n > 63) {
  1385.     debug(F101,"nack bad pkt num","",n);
  1386.     return(0);
  1387.     } else debug(F101,"nack","",n);
  1388.     if ((i = sseqtbl[n]) < 0) {        /* If necessary */
  1389.     if (getsbuf(n) < 0) {        /* get a buffer for this NAK */
  1390.         debug(F101,"nack can't getsbuf","",n);
  1391.         return(0);
  1392.     } else i = sseqtbl[n];        /* New slot number */
  1393.     }
  1394.     if (s_pkt[i].pk_rtr++ > maxtry)    /* How many times have we done this? */
  1395.       return(-1);            /* Too many... */
  1396.  
  1397. /* Note, don't free this buffer.  Eventually an ACK will come, and that */
  1398. /* will set it free.  If not, well, it's back to ground zero anyway...  */
  1399.  
  1400.     spack('N',n,0,(CHAR *) "");        /* NAKs never have data. */
  1401.     return(0);
  1402. }
  1403.  
  1404. #ifndef NEWDPL                /* This routine no longer used */
  1405. /*
  1406.  * (PWP) recalculate the optimal packet length in the face of errors.
  1407.  * This is a modified version of the algorithm by John Chandler in Kermit/370, 
  1408.  * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988.
  1409.  *
  1410.  * This implementation minimizes the total overhead equation, which is
  1411.  *
  1412.  *   Total chars = file_chars + (header_len * num_packs)
  1413.  *                            + (errors * (header_len + packet_len))
  1414.  *
  1415.  * Differentiate with respect to number of chars, solve for packet_len, get:
  1416.  *
  1417.  *   packet_len = sqrt (file_chars * header_len / errors)
  1418.  */
  1419.  
  1420. /*
  1421.  (FDC) New super-simple algorithm.  If there was an error in the most recent
  1422.  packet exchange, cut the send-packet size in half, down to a minimum of 20.
  1423.  If there was no error, increase the size by 5/4, up to the maximum negotiated
  1424.  length.  Seems to be much more responsive than previous algorithm, which took
  1425.  forever to recover the original packet length, and it also went crazy under
  1426.  certain conditions.
  1427.  
  1428.  Here's another idea for packet length resizing that keeps a history of the
  1429.  last n packets.  Push a 1 into the left end of an n-bit shift register if the
  1430.  current packet is good, otherwise push a zero.  The current n-bit value, w, of
  1431.  this register is a weighted sum of the noise hits for the last n packets, with
  1432.  the most recent weighing the most.  The current packet length is some function
  1433.  of w and the negotiated packet length, like:
  1434.  
  1435.    (2^n - w) / (2^n) * (negotiated length)
  1436.  
  1437.  If the present resizing method causes problems, think about this one a little
  1438.  more.
  1439. */
  1440. VOID
  1441. rcalcpsz() {
  1442.  
  1443. #ifdef COMMENT
  1444. /* Old way */
  1445.     register long x, q;
  1446.     if (numerrs == 0) return;        /* bounds check just in case */
  1447.  
  1448.     /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */
  1449.     /* an ACK is 5+bctr */
  1450.  
  1451.     /* first set x = per packet overhead */
  1452.     if (wslots > 1)            /* Sliding windows */
  1453.       x = (long) (npad+5+bctr);        /* packet only, don't count ack */
  1454.     else                /* Stop-n-wait */
  1455.       x = (long) (npad+5+3+bctr+5+bctr); /* count packet and ack. */
  1456.  
  1457.     /* then set x = packet length ** 2 */
  1458.     x = x * ( ffc / (long) numerrs);    /* careful of overflow */
  1459.     
  1460.     /* calculate the long integer sqrt(x) quickly */
  1461.     q = 500;
  1462.     q = (q + x/q) >> 1;
  1463.     q = (q + x/q) >> 1;
  1464.     q = (q + x/q) >> 1;
  1465.     q = (q + x/q) >> 1;        /* should converge in about 4 steps */
  1466.     if ((q > 94) && (q < 130))    /* break-even point for long packets */
  1467.       q = 94;
  1468.     if (q > spmax) q = spmax;    /* maximum bounds */
  1469.     if (q < 10) q = 10;        /* minimum bounds */
  1470.     spsiz = q;            /* set new send packet size */
  1471.     debug(F101,"rcalcpsiz","",q);
  1472. #else
  1473. /* New way */
  1474.     debug(F101,"rcalcpsiz numerrs","",numerrs);
  1475.     debug(F101,"rcalcpsiz spsiz","",spsiz);
  1476.     if (spackets < 3) {
  1477.     numerrs = 0;
  1478.     return;
  1479.     }
  1480.     if (numerrs)
  1481.       spsiz = spsiz / 2;
  1482.     else
  1483.       spsiz = (spsiz / 4) * 5;
  1484.     if (spsiz < 20) spsiz = 20;
  1485.     if (spsiz > spmax) spsiz = spmax;
  1486.     debug(F101,"rcalcpsiz new spsiz","",spsiz);
  1487.     numerrs = 0;
  1488. #endif /* COMMENT */
  1489. }
  1490. #endif /* NEWDPL */
  1491.  
  1492. /*  R E S E N D  --  Retransmit packet n.  */
  1493.  
  1494. /*
  1495.   Returns 0 or positive on success (the number of retries for packet n).
  1496.   On failure, returns a negative number, and an error message is placed
  1497.   in recpkt.
  1498. */
  1499. int
  1500. resend(n) int n; {            /* Send packet n again. */
  1501.     int j, k, x;
  1502. #ifdef GETMSEC
  1503.     long t1, t2;
  1504. #endif /* GETMSEC */
  1505.  
  1506.     debug(F101,"resend seq","",n);
  1507.  
  1508.     k = chkwin(n,winlo,wslots);        /* See if packet in current window */
  1509.     j = -1;                /* Assume it's lost */
  1510.     if (k == 0) j = sseqtbl[n];        /* See if we still have a copy of it */
  1511.     if (k != 0 || j < 0) {        /* If not.... */
  1512.     if (nakstate && k == 1) {
  1513. /*
  1514.   Packet n is in the previous window and we are the file receiver.
  1515.   We already sent the ACK and deallocated its buffer so we can't just 
  1516.   retransmit the ACK.  Rather than give up, we try some tricks...
  1517. */
  1518.         if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */
  1519. /*
  1520.   If the packet number is 0, and we're at the beginning of a protocol
  1521.   operation (spackets < 63), then we have to resend the ACK to an I or S
  1522.   packet, complete with parameters in the data field.  So we take a chance and
  1523.   send a copy of the parameters in an ACK packet with block check type 1.
  1524. */
  1525.         int bctlsav;        /* Temporary storage */
  1526.         int bctusav;
  1527.         bctlsav = bctl;        /* Save current block check length */
  1528.         bctusav = bctu;        /* and type */
  1529.         bctu = bctl = 1;    /* Set block check to 1 */
  1530.         spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
  1531.         logpkt('#',n,(CHAR *)"<reconstructed>"); /* Log it */
  1532.         bctu = bctusav;        /* Restore block check type */
  1533.         bctl = bctlsav;        /* and length */
  1534.  
  1535.         } else {            /* Not the first packet */
  1536. /*
  1537.   It's not the first packet of the protocol operation.  It's some other packet
  1538.   that we have already ACK'd and forgotten about.  So we take a chance and
  1539.   send an empty ACK using the current block-check type.  Usually this will
  1540.   work out OK (like when acking Data packets), and no great harm will be done
  1541.   if it was some other kind of packet (F, etc).  If we are requesting an
  1542.   interruption of the file transfer, the flags are still set, so we'll catch
  1543.   up on the next packet.
  1544. */
  1545.         spack('Y',n,0,(CHAR *) "");
  1546.         }
  1547.         retrans++;
  1548.         screen(SCR_PT,'%',(long)pktnum,"Retransmission");
  1549.         return(0);
  1550.     } else {
  1551. /*
  1552.   Packet number is not in current or previous window.  We seem to hit this
  1553.   code occasionally at the beginning of a transaction, for apparently no good
  1554.   reason.  Let's just log it for debugging, send nothing, and try to proceed
  1555.   with the protocol rather than killing it.
  1556. */
  1557.         debug(F101,"RESEND PKT NOT IN WINDOW","",n);
  1558.         debug(F101,"RESEND k","",k);
  1559. #ifdef COMMENT
  1560.         sprintf((char *)pktmsg,
  1561.             "   resend error: NIW, n=%d, k=%d.",n,k);
  1562.         return(-2);
  1563. #else
  1564.         return(0);
  1565. #endif /* COMMENT */
  1566.     }
  1567.     }
  1568.  
  1569. /* OK, it's in the window and it's not lost. */
  1570.  
  1571.     debug(F101,"resend pktinfo index","",k);
  1572.  
  1573.     if (s_pkt[j].pk_rtr++ > maxtry) {    /* Found it but over retry limit */
  1574.     strcpy((char *)pktmsg,"Too many retries.");
  1575.     return(-1);
  1576.     }
  1577.     debug(F101," retry","",s_pkt[j].pk_rtr); /* OK so far */
  1578.     dumpsbuf();                /* (debugging) */
  1579.     if (s_pkt[j].pk_typ == ' ') {    /* Incompletely formed packet */
  1580.     if (nakstate) {            /* (This shouldn't happen any more) */
  1581.         nack(n);
  1582.         retrans++;
  1583.         screen(SCR_PT,'%',(long)pktnum,"(resend)");
  1584.         return(s_pkt[j].pk_rtr);
  1585.     } else {            /* No packet to resend! */
  1586. #ifdef COMMENT
  1587. /*
  1588.   This happened (once) while sending a file with 2 window slots and typing
  1589.   X to the sender to cancel the file.  But since we're cancelling anyway,
  1590.   there's no need to give a scary message.
  1591. */
  1592.         sprintf((char *)pktmsg,
  1593.             "resend logic error: NPS, n=%d, j=%d.",n,j); 
  1594.         return(-2);
  1595. #else
  1596. /* Just ignore it. */
  1597.         return(0);
  1598. #endif /* COMMENT */
  1599.     }
  1600.     }
  1601. #ifdef GETMSEC
  1602.     if (deblog) t1 = getmsec();
  1603. #endif /* GETMSEC */
  1604.  
  1605.     /* Everything ok, send the packet */
  1606. #ifdef CK_TIMERS
  1607.     srttbl[n] = gtimer();        /* Update the timer */
  1608. #endif /* CK_TIMERS */
  1609.     x = ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len);
  1610.  
  1611. #ifdef GETMSEC
  1612.     if (deblog)  {
  1613.     t2 = getmsec();
  1614.     if (t2 > -1L && t1 > -1L)
  1615.       debug(F101,"resend ttol time","",t2-t1);
  1616.     else
  1617.       debug(F100,"resend ttol time error","",0);
  1618.     }
  1619. #endif /* GETMSEC */
  1620.     debug(F101,"resend ttol returns","",x);
  1621.  
  1622.     retrans++;                /* Count a retransmission */
  1623.     screen(SCR_PT,'%',(long)pktnum,"(resend)");    /* Tell user about resend */
  1624.     logpkt('S',n,s_pkt[j].pk_adr);    /* Log the resent packet */
  1625.     return(s_pkt[j].pk_rtr);        /* Return the number of retries. */
  1626. }
  1627.  
  1628. int
  1629. errpkt(reason) CHAR *reason; {        /* Send an error packet. */
  1630.     int x, y;
  1631.     encstr(reason);
  1632.     y = spack('E',pktnum,size,data);
  1633.     x = quiet; quiet = 1;         /* Close files silently. */
  1634.     clsif(); clsof(1);
  1635.     quiet = x;
  1636. #ifdef COMMENT
  1637.     screen(SCR_TC,0,0l,"");
  1638. #endif /* COMMENT */
  1639.     if (what < W_CONNECT)
  1640.       xitsta |= what;            /* Remember what failed. */
  1641.     success = 0;
  1642.     return(y);
  1643. }
  1644.  
  1645. /* scmd()  --  Send a packet of the given type */
  1646.  
  1647. int
  1648. #ifdef CK_ANSIC
  1649. scmd(char t, CHAR *dat)
  1650. #else
  1651. scmd(t,dat) char t; CHAR *dat;
  1652. #endif /* CK_ANSIC */
  1653. /* scmd */ {
  1654.     if (encstr(dat) < 0)        /* Encode the command string */
  1655.       return(-1);
  1656.     spack(t,pktnum,size,data);
  1657.     return(0);
  1658. }
  1659.  
  1660. int
  1661. srinit(reget, retrieve) int reget, retrieve; { /* Send R, H, or J packet */
  1662.     if (encstr((CHAR *)cmarg) < 0)    /* Encode the filename. */
  1663.       return(-1);
  1664.     if (retrieve)
  1665.       spack((char)'H',pktnum,size,data); /* Send the packet. */
  1666.     else
  1667.       spack((char)(reget ? 'J' : 'R'),pktnum,size,data); /* Send the packet. */
  1668.     return(0);
  1669. }
  1670.  
  1671. /*  K S T A R T  --  Checks for a Kermit packet while in terminal mode.  */
  1672.  
  1673. #ifdef CK_APC
  1674. int 
  1675. #ifdef CK_ANSIC
  1676. kstart(CHAR ch)
  1677. #else
  1678. kstart(ch) CHAR ch;
  1679. #endif /* CK_ANSIC */
  1680. /* kstart */ {
  1681.     static int buflen = 94;
  1682.     static CHAR buf[95];
  1683.     static CHAR * p = NULL;
  1684.     extern CHAR stchr, eol;
  1685.  
  1686.     if (ch == stchr) {            /* Start of packet */
  1687.     p = buf;
  1688.     *p = ch;
  1689.     debug(F101,"kstart SOP","",ch);
  1690.     } else if (ch == eol) {        /* End of packet */
  1691.     if (p) {
  1692.         p++;
  1693.         if (p - buf < 94 ) { 
  1694.         int rc = 0;
  1695.         *p = ch;
  1696.         p++;
  1697.         *p = NUL;
  1698.         if (rc = chkspkt((char *)buf))
  1699.           debug(F111,"kstart EOP", buf, ch);
  1700.         p = NULL;
  1701.         if (!rc) return(0);
  1702.         return(rc == 1 ? PROTO_K + 1 : 0 - (PROTO_K + 1));
  1703.         } else {
  1704.         p = NULL;
  1705.         }
  1706.     } 
  1707.     } else if (p) {
  1708.     p++;
  1709.     if (p - buf < 94)
  1710.       *p = ch;
  1711.     else 
  1712.       p = NULL;
  1713.     }
  1714.     return(0);
  1715. }
  1716.  
  1717. #ifdef CK_XYZ
  1718.  
  1719. /*  Z S T A R T  --  Checks for a ZMODEM packet while in terminal mode.  */
  1720.  
  1721. int 
  1722. #ifdef CK_ANSIC
  1723. zstart(CHAR ch)
  1724. #else
  1725. zstart(ch) CHAR ch;
  1726. #endif /* CK_ANSIC */
  1727. /* zstart */ {
  1728.     static CHAR * matchstr = (CHAR *) "\030B00";
  1729.     /* "rz\r**\030B00000000000000\r\033J\021"; */
  1730.     static CHAR * p = NULL;
  1731.  
  1732.     if (!ch)
  1733.       return(0);
  1734.     if (!p)
  1735.       p = matchstr;
  1736.  
  1737.     if (ch == *p) {
  1738.     p++;
  1739.     if (*p == '\0') {
  1740.         p = matchstr;
  1741.         debug(F100, "zstart Zmodem SOP","",0);
  1742.         return(PROTO_Z + 1);
  1743.     }
  1744.     } else 
  1745.       p = matchstr;
  1746.     return(0);
  1747. }
  1748. #endif /* CK_XYZ */
  1749.  
  1750. /*  C H K S P K T  --  Check if buf contains a valid S or I packet  */
  1751.  
  1752. int
  1753. chkspkt(buf) char *buf; {
  1754.     int buflen;
  1755.     int len = -1;
  1756.     CHAR chk;
  1757.     char type = 0;
  1758.     char *s = buf;
  1759.  
  1760.     if (!buf) return(0);
  1761.     buflen = strlen(buf);
  1762.     if (buflen < 5) return(0);        /* Too short */
  1763.     if (*s++ != stchr) return(0);    /* SOH */
  1764.     len = xunchar(*s++);        /* Length */
  1765.     if (len < 0) return(0);
  1766.     if (*s++ != SP) return(0);        /* Sequence number */
  1767.     type = *s++;            /* Type */
  1768.     if (type != 'S' && type != 'I')
  1769.       return(0);
  1770.     if (buflen < len + 2) return(0);
  1771.     s += (len - 3);            /* Position of checksum */
  1772.     chk = (CHAR) (*s);            /* Checksum */
  1773.     *s = NUL;
  1774.     if (xunchar(chk) != chk1((CHAR *) (buf+1))) return(0); /* Check it */
  1775.     *s = chk;
  1776.     return(type == 'S' ? 1 : 2);
  1777. }
  1778. #endif /* CK_APC */
  1779.  
  1780. /* R P A C K  --  Read a Packet */
  1781.  
  1782. /*
  1783.  rpack reads a packet and returns the packet type, or else Q if the
  1784.  packet was invalid, or T if a timeout occurred.  Upon successful return, sets
  1785.  the values of global rsn (received sequence number),  rln (received
  1786.  data length), and rdatap (pointer to null-terminated data field), and
  1787.  returns the packet type.
  1788. */
  1789. int
  1790. rpack() {
  1791.     register int i, j, x, lp;        /* Local variables */
  1792.     int k, type, chklen;
  1793.     unsigned crc;
  1794.     CHAR pbc[4];            /* Packet block check */
  1795.     CHAR *sohp;                /* Pointer to SOH */
  1796.     CHAR e;                /* Packet end character */
  1797.  
  1798. #ifdef GETMSEC
  1799.     long t1, t2;
  1800. #endif /* GETMSEC */
  1801.  
  1802.     debug(F101,"entering rpack, pktnum","",pktnum);
  1803.  
  1804. #ifndef OLDCHKINT
  1805.     if (chkint() < 0)            /* Check for console interrupts. */
  1806.       return('z');
  1807. #endif /* OLDCHKINT */
  1808.  
  1809.     k = getrbuf();            /* Get a new packet input buffer. */
  1810.     debug(F101,"rpack getrbuf","",k);
  1811.     if (k < 0) return(-1);        /* Return like this if none free. */
  1812.     if (pktmsg) *pktmsg = NUL;
  1813.     recpkt = r_pkt[k].bf_adr;
  1814.     *recpkt = '\0';            /* Clear receive buffer. */
  1815.     sohp = recpkt;            /* Initialize pointers to it. */
  1816.     rdatap = recpkt;
  1817.     rsn = rln = -1;            /* In case of failure. */
  1818.     e = (turn) ? turnch : eol;        /* Use any handshake char for eol */
  1819.  
  1820. /* Try to get a "line". */
  1821.  
  1822. #ifdef GETMSEC
  1823.     if (deblog) t1 = getmsec();
  1824. #endif /* GETMSEC */
  1825.  
  1826. #ifdef PARSENSE
  1827. #ifdef UNIX
  1828. /*
  1829.   So far the final turn argument is only for ck[uvdl]tio.c.  Should be added
  1830.   to the others too.  (turn == handshake character.)
  1831. */
  1832.     j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
  1833. #else
  1834. #ifdef VMS
  1835.     j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
  1836. #else
  1837. #ifdef datageneral
  1838.     j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
  1839. #else
  1840. #ifdef STRATUS
  1841.     j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
  1842. #else
  1843. #ifdef OS2
  1844.     j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
  1845. #else
  1846. #ifdef OSK
  1847.     j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
  1848. #else
  1849.     j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr);
  1850. #endif /* OSK */
  1851. #endif /* OS2 */
  1852. #endif /* STRATUS */
  1853. #endif /* datageneral */
  1854. #endif /* VMS */
  1855. #endif /* UNIX */
  1856.     if (parity != ttprty) autopar = 1;
  1857.     parity = ttprty; 
  1858. #else /* !PARSENSE */
  1859.     j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e);
  1860. #endif /* PARSENSE */
  1861.  
  1862. #ifdef GETMSEC
  1863.     if (deblog)  {
  1864.     t2 = getmsec();
  1865.     if (t2 > -1L && t1 > -1L)
  1866.       debug(F101,"rpack ttinl time","",t2-t1);
  1867.     else
  1868.       debug(F100,"rpack ttinl time error","",0);
  1869.     }
  1870. #endif /* GETMSEC */
  1871.  
  1872.     if (j < 0) {
  1873.     debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */
  1874.     freerbuf(k);            /* Free this buffer */
  1875.     if (j < -1) {            /* Bail out if ^C^C typed. */
  1876.         debug(F101,"rpack ^C server","",server);
  1877.         debug(F101,"rpack ^C en_fin","",en_fin);
  1878.         if (server == 0) return(j);    /* But not if in server mode */
  1879.         else if (en_fin) return(j);    /* with DISABLE FINISH */
  1880.         else return(-2);
  1881.     }
  1882.     if (nakstate)            /* Call it a timeout. */
  1883.       screen(SCR_PT,'T',(long)winlo,"");
  1884.     else
  1885.       screen(SCR_PT,'T',(long)pktnum,"");
  1886.     logpkt('r',-1,(CHAR *)"<timeout>");
  1887.     if (flow == 1) ttoc(XON);    /* In case of Xoff blockage. */
  1888.     return('T');
  1889.     }
  1890.     rpktl = j;
  1891.     tlci += j;                /* All OK, Count the characters. */
  1892.     flci += j;
  1893.  
  1894. #ifndef PARSENSE
  1895. /* THEN eliminate this loop... */
  1896.     for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
  1897.       sohp++;                /* Find mark */
  1898.     if (i++ >= j) {            /* Didn't find it. */
  1899.     logpkt('r',-1,"<timeout>");
  1900.     freerbuf(k);
  1901.     return('T');
  1902.     }    
  1903. #else
  1904.     i = 1;
  1905. #endif /* PARSENSE */
  1906.  
  1907.     rpackets++;
  1908.     lp = i;                /* Remember LEN position. */
  1909.     if ((j = xunchar(recpkt[i++])) == 0) {
  1910.         if ((j = lp+5) > MAXRP) return('Q'); /* Long packet */
  1911.     x = recpkt[j];            /* Header checksum. */
  1912.     recpkt[j] = '\0';        /* Calculate & compare. */
  1913.     if (xunchar(x) != chk1(recpkt+lp)) {
  1914.         freerbuf(k);
  1915.         logpkt('r',-1,(CHAR *)"<crunched:hdr>");
  1916.         screen(SCR_PT,'%',(long)pktnum,"Bad packet header");
  1917.         return('Q');
  1918.     }
  1919.     recpkt[j] = x;            /* Checksum ok, put it back. */
  1920.     rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl;
  1921.     j = 3;                /* Data offset. */
  1922.     } else if (j < 3) {
  1923.     debug(F101,"rpack packet length less than 3","",j);
  1924.     freerbuf(k);
  1925.     logpkt('r',-1,(CHAR *)"<crunched:len>");
  1926.     screen(SCR_PT,'%',(long)pktnum,"Bad packet length");
  1927.     return('Q');
  1928.     } else {
  1929.     rln = j - bctl - 2;        /* Regular packet */
  1930.     j = 0;                /* No extended header */
  1931.     }
  1932.     rsn = xunchar(recpkt[i++]);        /* Sequence number */
  1933.     logpkt('r',rsn,sohp);
  1934.     if (rsn < 0 || rsn > 63) {
  1935.     debug(F101,"rpack bad sequence number","",rsn);
  1936.     freerbuf(k);
  1937.     logpkt('r',rsn,(CHAR *)"<crunched:seq>");
  1938.     screen(SCR_PT,'%',(long)pktnum,"Bad sequence number");
  1939.     return('Q');
  1940.     }
  1941. /*
  1942.   If this packet has the same type as the packet just sent, assume it is
  1943.   an echo and ignore it.  Don't even bother with the block check calculation:
  1944.   even if the packet is corrupted, we don't want to NAK an echoed packet.
  1945.   (And we certainly don't want to NAK an ACK or NAK!)
  1946. */
  1947.     type = recpkt[i++];            /* Get packet's TYPE field */
  1948.     if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) {
  1949.     debug(F000,"rpack echo","",type); /* If it's an echo */
  1950.     freerbuf(k);            /* Free this buffer */
  1951.     logpkt('#',rsn,(CHAR *)"<echo:ignored>");
  1952.     return('e');            /* return special (lowercase) code */
  1953.     }
  1954. /*
  1955.   Separate the data from the block check, accounting for the case where    
  1956.   a packet was retransmitted after the block check switched.
  1957. */
  1958.     if (type == 'I' || type == 'S') {    /* I & S packets always have type 1 */
  1959.     chklen = 1;
  1960.     rln = rln + bctl - 1;
  1961.     } else if (type == 'N') {        /* A NAK packet never has data */
  1962.     chklen = xunchar(recpkt[lp]) - 2;
  1963.     rln = rln + bctl - chklen;
  1964.     } else chklen = bctl;
  1965.     debug(F101,"rpack bctl","",bctl);
  1966.     debug(F101,"rpack chklen","",chklen);
  1967.  
  1968.     i += j;                /* Buffer index of DATA field */
  1969.     rdatap = recpkt+i;            /* Pointer to DATA field */
  1970.     if ((j = rln + i) > r_pkt[k].bf_len ) { /* Make sure it fits */
  1971.     debug(F101,"packet sticks out too far","",j);
  1972.     freerbuf(k);
  1973.     logpkt('r',rsn,(CHAR *)"<overflow>");
  1974.     return('Q');
  1975.     }
  1976.  
  1977.     for (x = 0; x < chklen; x++)    /* Copy the block check */
  1978.       pbc[x] = recpkt[j+x];
  1979.     pbc[x] = '\0';            /* Null-terminate block check string */
  1980.     recpkt[j] = '\0';            /*  and the packet DATA field. */
  1981.     
  1982.     if (chklen == 2 && bctu == 4) {    /* Adjust for Blank-Free-2 */
  1983.     chklen = 4;            /* (chklen is now a misnomer...) */
  1984.     debug(F100,"rpack block check B","",0);
  1985.     }
  1986.     switch (chklen) {            /* Check the block check */
  1987.     case 1:                /* Type 1, 6-bit checksum */
  1988.         if (xunchar(*pbc) != chk1(recpkt+lp)) {
  1989.         debug(F110,"checked chars",recpkt+lp,0);
  1990.             debug(F101,"block check","",(int) xunchar(*pbc));
  1991.         debug(F101,"should be","",chk1(recpkt+lp));
  1992.         freerbuf(k);
  1993.         logpkt('r',-1,(CHAR *)"<crunched:chk1>");
  1994.         screen(SCR_PT,'%',(long)pktnum,"Checksum error");
  1995.         return('Q');
  1996.          }
  1997.         break;
  1998.     case 2:                /* Type 2, 12-bit checksum */
  1999.         x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
  2000.         if (x != chk2(recpkt+lp)) {    /* No match */
  2001.         if (type == 'E') {    /* Allow E packets to have type 1 */
  2002.             recpkt[j++] = pbc[0];    
  2003.             recpkt[j] = '\0';
  2004.             if (xunchar(pbc[1]) == chk1(recpkt+lp))
  2005.               break;
  2006.             else
  2007.               recpkt[--j] = '\0';
  2008.         }
  2009.         debug(F110,"checked chars",recpkt+lp,0);
  2010.             debug(F101,"block check","", x);
  2011.         debug(F101,"should be","", (int) chk2(recpkt+lp));
  2012.         freerbuf(k);
  2013.         logpkt('r',-1,(CHAR *)"<crunched:chk2>");
  2014.         screen(SCR_PT,'%',(long)pktnum,"Checksum error");
  2015.         return('Q');
  2016.         }
  2017.         break;
  2018.     case 3:                /* Type 3, 16-bit CRC */
  2019.         crc = (xunchar(pbc[0]) << 12)
  2020.             | (xunchar(pbc[1]) << 6)
  2021.         | (xunchar(pbc[2]));
  2022.         if (crc != chk3(recpkt+lp,parity)) {
  2023.         if (type == 'E') {    /* Allow E packets to have type 1 */
  2024.             recpkt[j++] = pbc[0];    
  2025.             recpkt[j++] = pbc[1];
  2026.             recpkt[j] = '\0';
  2027.             if (xunchar(pbc[2]) == chk1(recpkt+lp))
  2028.               break;
  2029.             else { j -=2; recpkt[j] = '\0'; }
  2030.         }
  2031.         debug(F110,"checked chars",recpkt+lp,0);
  2032.             debug(F101,"block check","",xunchar(*pbc));
  2033.         debug(F101,"should be","",(int) chk3(recpkt+lp,parity));
  2034.         freerbuf(k);
  2035.         logpkt('r',-1,(CHAR *)"<crunched:chk3>");
  2036.         screen(SCR_PT,'%',(long)pktnum,"CRC error");
  2037.         return('Q');
  2038.         }
  2039.         break;
  2040.     case 4:                /* Type 4 = Type 2, no blanks. */
  2041.         x = (unsigned)((xunchar(*pbc) - 1) << 6) |
  2042.             (unsigned)(xunchar(pbc[1]) - 1);
  2043.         if (x != chk2(recpkt+lp)) {
  2044.         if (type == 'E') {    /* Allow E packets to have type 1 */
  2045.             recpkt[j++] = pbc[0];    
  2046.             recpkt[j] = '\0';
  2047.             if (xunchar(pbc[1]) == chk1(recpkt+lp))
  2048.               break;
  2049.             else
  2050.               recpkt[--j] = '\0';
  2051.         }
  2052.         debug(F101,"bad type B block check","",x);
  2053.         freerbuf(k);
  2054.         logpkt('r',-1,(CHAR *)"<crunched:chkb>");
  2055.         screen(SCR_PT,'%',(long)pktnum,"Checksum error");
  2056.         return('Q');
  2057.         }
  2058.         break;
  2059.     default:            /* Shouldn't happen... */
  2060.         freerbuf(k);
  2061.         logpkt('r',-1,(CHAR *)"<crunched:chkx>");
  2062.         screen(SCR_PT,'%',(long)pktnum,"(crunched)");
  2063.         return('Q');
  2064.     }
  2065.     debug(F101,"rpack block check OK","",rsn);
  2066.  
  2067. /* Now we can believe the sequence number, and other fields. */
  2068. /* Here we violate strict principles of layering, etc, and look at the  */
  2069. /* packet sequence number.  If there's already a packet with the same   */
  2070. /* number in the window, we remove this one so that the window will not */
  2071. /* fill up. */
  2072.  
  2073.     if ((x = rseqtbl[rsn]) != -1) {    /* Already a packet with this number */
  2074.     retrans++;            /* Count it for statistics */
  2075.     debug(F101,"rpack got dup","",rsn);
  2076.     logpkt('r',rsn,(CHAR *)"<duplicate>");
  2077.     freerbuf(x);            /* Free old buffer, keep new packet. */
  2078.     r_pkt[k].pk_rtr++;        /* Count this as a retransmission. */
  2079.     }
  2080.  
  2081. /* New packet, not seen before, enter it into the receive window. */
  2082.  
  2083. #ifdef CK_TIMERS
  2084.     rrttbl[rsn] = gtimer();        /* Timestamp */
  2085. #endif /* CK_TIMERS */
  2086.  
  2087.     rseqtbl[rsn] = k;            /* Make back pointer */
  2088.     r_pkt[k].pk_seq = rsn;        /* Record in packet info structure */
  2089.     r_pkt[k].pk_typ = type;        /* Sequence, type,... */
  2090.     r_pkt[k].pk_adr = rdatap;        /* pointer to data buffer */
  2091.     screen(SCR_PT,(char)type,(long)rsn,(char *)sohp); /* Update screen */
  2092.     return(type);            /* Return packet type */
  2093. }
  2094.  
  2095. /*  L O G P K T  --  Log packet number n, pointed to by s.  */
  2096.  
  2097. /* c = 's' (send) or 'r' (receive) */
  2098.  
  2099. VOID
  2100. #ifdef CK_ANSIC
  2101. logpkt(char c,int n, CHAR *s)
  2102. #else
  2103. logpkt(c,n,s) char c; int n; CHAR *s;
  2104. #endif /* CK_ANSIC */
  2105. /* logpkt */ {
  2106.     char plog[20];
  2107.     if (pktlog && *s) {
  2108.     if (n < 0)
  2109.       sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60));
  2110.     else
  2111.       sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60));
  2112.     if (zsout(ZPFILE,plog) < 0) pktlog = 0;
  2113.     else if (zsoutl(ZPFILE,(char *)s) < 0) pktlog = 0;
  2114.     }
  2115. }
  2116.  
  2117. #ifdef TLOG
  2118.  
  2119. /*  T S T A T S  --  Record statistics in transaction log  */
  2120.  
  2121. VOID
  2122. tstats() {
  2123.     char *tp;
  2124.     ztime(&tp);                /* Get time stamp */
  2125.     tlog(F100,"","",0L);        /* Leave a blank line */
  2126.     tlog(F110,"Transaction complete",tp,0L);  /* Record it */
  2127.  
  2128.     if (filcnt < 1) return;        /* If no files, done. */
  2129.  
  2130. /* If multiple files, record character totals for all files */
  2131.  
  2132.     if (filcnt > 1) {
  2133.     tlog(F101," files transferred       ","",filcnt - filrej);
  2134.     tlog(F101," total file characters   ","",tfc);
  2135.     tlog(F101," communication line in   ","",tlci);
  2136.     tlog(F101," communication line out  ","",tlco);
  2137.     }
  2138.  
  2139. /* Record timing info for one or more files */
  2140.  
  2141.     tlog(F101," elapsed time (seconds)  ","",(long) tsecs);
  2142.     if (tsecs > 0) {
  2143.     long lx;
  2144.     lx = (tfc * 10L) / (long) tsecs;
  2145.     tlog(F101," effective data rate     ","",lx/10L);
  2146.     if (speed <= 0L) speed = ttgspd();
  2147. #ifdef COMMENT
  2148.     if (speed > 0L && speed != 8880L && network == 0) {
  2149.         lx = (lx * 100L) / speed;
  2150.         tlog(F101," efficiency (percent)    ","",lx);
  2151.     }
  2152. #endif /* COMMENT */
  2153.     }
  2154.     tlog(F100,"","",0L);        /* Leave a blank line */
  2155. }
  2156.  
  2157. /*  F S T A T S  --  Record file statistics in transaction log  */
  2158.  
  2159. VOID
  2160. fstats() {
  2161.     tfc += ffc;
  2162.     if (!discard && !cxseen && !czseen && what != W_NOTHING)
  2163.       tlog(F101," complete, size","",ffc);
  2164. }
  2165. #else /* NOTLOG */
  2166. VOID
  2167. tstats() {}
  2168.  
  2169. VOID
  2170. fstats() {
  2171.     tfc += ffc;
  2172. }
  2173. #endif /* TLOG */
  2174.