source: trunk/third/kermit/ckcfn2.c @ 20081

Revision 20081, 95.5 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20080, which included commits to RCS files with non-trunk default branches.
Line 
1/*  C K C F N 2  --  System-independent Kermit protocol support functions... */
2
3/*  ...Part 2 (continued from ckcfns.c)  */
4
5/*
6  Author: Frank da Cruz <fdc@columbia.edu>,
7  Columbia University Academic Information Systems, New York City.
8
9  Copyright (C) 1985, 2002,
10    Trustees of Columbia University in the City of New York.
11    All rights reserved.  See the C-Kermit COPYING.TXT file or the
12    copyright text in the ckcmai.c module for disclaimer and permissions.
13*/
14/*
15 Note -- if you change this file, please amend the version number and date at
16 the top of ckcfns.c accordingly.
17*/
18
19#include "ckcsym.h"                     /* Compilation options */
20#include "ckcdeb.h"                     /* Debugging and other symbols */
21#include "ckcasc.h"                     /* ASCII symbols */
22#include "ckcker.h"                     /* Kermit symbols */
23#include "ckcxla.h"                     /* Translation */
24#include "ckcnet.h"                     /* IKS and VMS #define TCPSOCKET */
25#ifdef TCPSOCKET                        /* For TELNET business in spack() */
26extern int tn_nlm, ttnproto, tn_b_nlm;
27#endif /* TCPSOCKET */
28
29extern int parity, network, local, interrupted, fatalio, wasclosed;
30
31int kstartactive = 0;                   /* Flag for kstart() in a packet */
32
33static CHAR p_tbl[] = {                 /* Even parity table for dopar(). */
34    (CHAR) '\000',                      /* ANSI C casts '\ooo' constants  */
35    (CHAR) '\201',                      /* to signed char, so we have to  */
36    (CHAR) '\202',                      /* cast back to unsigned char...  */
37    (CHAR) '\003',
38    (CHAR) '\204',
39    (CHAR) '\005',
40    (CHAR) '\006',
41    (CHAR) '\207',
42    (CHAR) '\210',
43    (CHAR) '\011',
44    (CHAR) '\012',
45    (CHAR) '\213',
46    (CHAR) '\014',
47    (CHAR) '\215',
48    (CHAR) '\216',
49    (CHAR) '\017',
50    (CHAR) '\220',
51    (CHAR) '\021',
52    (CHAR) '\022',
53    (CHAR) '\223',
54    (CHAR) '\024',
55    (CHAR) '\225',
56    (CHAR) '\226',
57    (CHAR) '\027',
58    (CHAR) '\030',
59    (CHAR) '\231',
60    (CHAR) '\232',
61    (CHAR) '\033',
62    (CHAR) '\234',
63    (CHAR) '\035',
64    (CHAR) '\036',
65    (CHAR) '\237',
66    (CHAR) '\240',
67    (CHAR) '\041',
68    (CHAR) '\042',
69    (CHAR) '\243',
70    (CHAR) '\044',
71    (CHAR) '\245',
72    (CHAR) '\246',
73    (CHAR) '\047',
74    (CHAR) '\050',
75    (CHAR) '\251',
76    (CHAR) '\252',
77    (CHAR) '\053',
78    (CHAR) '\254',
79    (CHAR) '\055',
80    (CHAR) '\056',
81    (CHAR) '\257',
82    (CHAR) '\060',
83    (CHAR) '\261',
84    (CHAR) '\262',
85    (CHAR) '\063',
86    (CHAR) '\264',
87    (CHAR) '\065',
88    (CHAR) '\066',
89    (CHAR) '\267',
90    (CHAR) '\270',
91    (CHAR) '\071',
92    (CHAR) '\072',
93    (CHAR) '\273',
94    (CHAR) '\074',
95    (CHAR) '\275',
96    (CHAR) '\276',
97    (CHAR) '\077',
98    (CHAR) '\300',
99    (CHAR) '\101',
100    (CHAR) '\102',
101    (CHAR) '\303',
102    (CHAR) '\104',
103    (CHAR) '\305',
104    (CHAR) '\306',
105    (CHAR) '\107',
106    (CHAR) '\110',
107    (CHAR) '\311',
108    (CHAR) '\312',
109    (CHAR) '\113',
110    (CHAR) '\314',
111    (CHAR) '\115',
112    (CHAR) '\116',
113    (CHAR) '\317',
114    (CHAR) '\120',
115    (CHAR) '\321',
116    (CHAR) '\322',
117    (CHAR) '\123',
118    (CHAR) '\324',
119    (CHAR) '\125',
120    (CHAR) '\126',
121    (CHAR) '\327',
122    (CHAR) '\330',
123    (CHAR) '\131',
124    (CHAR) '\132',
125    (CHAR) '\333',
126    (CHAR) '\134',
127    (CHAR) '\335',
128    (CHAR) '\336',
129    (CHAR) '\137',
130    (CHAR) '\140',
131    (CHAR) '\341',
132    (CHAR) '\342',
133    (CHAR) '\143',
134    (CHAR) '\344',
135    (CHAR) '\145',
136    (CHAR) '\146',
137    (CHAR) '\347',
138    (CHAR) '\350',
139    (CHAR) '\151',
140    (CHAR) '\152',
141    (CHAR) '\353',
142    (CHAR) '\154',
143    (CHAR) '\355',
144    (CHAR) '\356',
145    (CHAR) '\157',
146    (CHAR) '\360',
147    (CHAR) '\161',
148    (CHAR) '\162',
149    (CHAR) '\363',
150    (CHAR) '\164',
151    (CHAR) '\365',
152    (CHAR) '\366',
153    (CHAR) '\167',
154    (CHAR) '\170',
155    (CHAR) '\371',
156    (CHAR) '\372',
157    (CHAR) '\173',
158    (CHAR) '\374',
159    (CHAR) '\175',
160    (CHAR) '\176',
161    (CHAR) '\377'
162};
163
164/*  D O P A R  --  Add an appropriate parity bit to a character  */
165
166CHAR
167#ifdef CK_ANSIC
168dopar(register CHAR ch)
169#else
170dopar(ch) register CHAR ch;
171#endif /* CK_ANSIC */
172    {
173    register unsigned int a;
174    if (!parity
175#ifdef TCPSOCKET
176        || (network && (ttnproto == NP_TELNET) && (TELOPT_ME(TELOPT_BINARY)))
177#ifndef NOXFER
178        || (!local && sstelnet)         /* TELNET BINARY MODE */
179#endif /* NOXFER */
180#endif /* TCPSOCKET */
181        ) return((CHAR) (ch & 255)); else a = ch & 127;
182    switch (parity) {
183        case 'e':  return(p_tbl[a]);                 /* Even */
184        case 'm':  return((CHAR) (a | 128));         /* Mark */
185        case 'o':  return((CHAR) (p_tbl[a] ^ 128));  /* Odd */
186        case 's':  return((CHAR) a);                 /* Space */
187        default:   return((CHAR) a);                 /* Something illegal */
188    }
189}
190
191#ifndef NOXFER                          /* Rest of this file... */
192
193#define NEWDPL                          /* New dynamic packet length method */
194
195#ifdef VMS
196extern int batch;
197#else
198extern int backgrd;
199#endif /* VMS */
200
201#ifdef DYNAMIC
202extern struct pktinfo *s_pkt;           /* array of pktinfo structures */
203extern struct pktinfo *r_pkt;           /* array of pktinfo structures */
204#else
205extern struct pktinfo s_pkt[];          /* array of pktinfo structures */
206extern struct pktinfo r_pkt[];          /* array of pktinfo structures */
207#endif /* DYNAMIC */
208
209extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, wslotn,
210  sbufnum, rbufnum, pktpaus, reliable;
211
212#ifdef STREAMING
213static int dontsend = 0;
214extern int streaming;
215#endif /* STREAMING */
216
217extern int ttprty;                      /* from ck*tio.c */
218extern int autopar;
219
220extern int spsiz, spmax, rpsiz, timint, timef, npad, bestlen, maxsend;
221extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, flow;
222extern int pktnum, sndtyp, rcvtyp, bctr, bctu, bctl, rsn, rln, maxtry, size;
223extern int osize, maxsize, spktl, rpktl, nfils, stdouf, fsecs;
224extern int turn, turnch, displa, pktlog, seslog, xflg, mypadn;
225extern int hcflg, server, cxseen, czseen, discard, slostart;
226extern int nakstate, quiet, success, xitsta, what, filestatus;
227extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz;
228extern int carrier, fdispla, srvidl;
229
230#ifdef GFTIMER
231extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
232#endif /* GFTIMER */
233
234extern long filcnt, filrej, ffc, flci, flco, tlci, tlco, tfc, speed;
235extern long filcps, tfcps;
236
237extern char *cmarg, filnam[];
238
239extern CHAR padch, mypadc, eol, seol, ctlq, sstate;
240extern CHAR *recpkt, *data, myinit[];
241extern CHAR *srvptr, stchr, mystch, *rdatap;
242extern CHAR padbuf[];
243extern CHAR * epktmsg;
244extern int epktrcvd, epktsent;
245
246#ifdef OS2                              /* AUTODOWNLOAD parameters */
247extern int adl_kmode, adl_zmode;        /* Match Packet to signal download */
248extern char * adl_kstr;                 /* KERMIT Download String */
249extern char * adl_zstr;                 /* ZMODEM Download String */
250#endif /* OS2 */
251
252#ifdef CK_AUTODL
253CHAR ksbuf[96] = { NUL, NUL };          /* Autodownload "Kermit Start" buf */
254#endif /* CK_AUTODL */
255
256int numerrs = 0;                        /* Number of packet errors so far */
257int rcvtimo = 0;                        /* Timeout for receiving a packet */
258int idletmo = 0;                        /* Flag for idle timeout */
259
260long filcps = 0L;                       /* CPS most recent file transferred */
261long tfcps  = 0L;                       /* CPS most recent transaction */
262long xfsecs = 0L;                       /* Elapsed time for most recent file */
263#ifdef GFTIMER
264CKFLOAT fpxfsecs = 0.0;                 /* Ditto, but floating point */
265#endif /* GFTIMER */
266
267#ifdef CK_TIMERS
268int rrttbl[64], srttbl[64];             /* Packet timestamp tables */
269extern int rttflg;
270#define RTT_SCALE 1000
271long
272  rttsamples,                           /* Round trip time samples */
273  rttdelay,                             /* RTT delay */
274  pktintvl,                             /* Interpacket arrival time */
275  rttvariance,                          /* RTT variance */
276  rttstddev;                            /* RTT standard deviation */
277#endif /* CK_TIMERS */
278
279/* CRC generation tables */
280
281long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L,
282  051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L,
283  0153215L, 0163416L, 0173617L
284};
285
286long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L,
287  053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L,
288  0155745L, 0164576L, 0174367L
289};
290
291#ifdef CK_TIMERS
292/*
293  Round-trip timer calculations adapted from Tim Kientzle's article,
294  "Improving Kermit Performance", Dr Dobb's Journal, February 1996.
295*/
296
297
298/*  R T T I N I T  --  Initialize timers at start of transaction  */
299
300VOID
301rttinit() {                             /* Initialize round-trip timing */
302    int i;
303
304    if (timint == 0)
305      return;
306
307    rttsamples  = 0L;                   /* Samples (packets) */
308    rttvariance = 0L;                   /* Variance in delay */
309    rttdelay    = (long) timint * RTT_SCALE; /* Delay */
310    pktintvl    = (long) timint * RTT_SCALE; /* Delay */
311    rttstddev   = (long) timint * RTT_SCALE; /* Standard deviation of delay */
312
313    /* Tables of timestamps indexed by packet sequence number */
314
315    for (i = 0; i < 64; i++) {
316        rrttbl[i] = -1;                 /* Time each packet was received */
317        srttbl[i] = -1;                 /* Time each packet was sent */
318    }
319    rcvtimo = timint;                   /* Initial timeout is what user said */
320}
321
322/*  G E T R T T  --  Get packet round trip time  */
323/*
324  Call with nakstate == 0 if file sender, nonzero if receiver,
325  and n == packet sequence number of the packet we just received.
326
327  Returns:
328  -1 on failure with rcvtimo set to timint (what the user said), or:
329   0 on success with rcvtimo set to dynamically calculated value:
330     1 <= rcvtimo <= timint * 3.
331*/
332int
333getrtt(nakstate, n) int nakstate, n; {
334    extern int mintime, maxtime;
335    static int prevz = 0, prevr = 0;
336    int x, y, yy, z = 0, zz = 0;        /* How long did it take to get here? */
337
338    rcvtimo = timint;                   /* Default timeout is what user said */
339
340    if (timint == 0)                    /* We're not timing out. */
341      return(0);
342
343    if (!rttflg)                        /* Not supposed to be doing this? */
344      return(-1);                       /*  So don't */
345
346    if (!RTT_SCALE)                     /* Paranoia... */
347      return(-1);
348
349    /* rtimer() (reset timer) is not called until 1st data packet */
350#ifdef GFTIMER
351    /* rftimer(); */
352#endif /* GFTIMER */
353    /* S (F [ A ] D* Z)* B */
354
355    /* NOTE: we calculate both the round-trip time AND the packet */
356    /* arrival rate.  We don't use the RTT for anything, we just display it. */
357    /* Timeouts are based on the packet arrival rate. */
358
359    if (spackets > 3) {                 /* Don't start till 4th packet */
360        if (nakstate) {                 /* File receiver */
361            x = rrttbl[n];                   /* Time when I got packet n */
362            y = rrttbl[n > 0 ? n - 1 : 63];  /* Time when I got packet n-1 */
363            yy = srttbl[n > 0 ? n - 1 : 63]; /* Time when I sent ACK(n-1) */
364            if (x > -1 && y > -1) {     /* Be careful */
365                z = x - y;              /* Packet rate */
366                zz = x - yy;            /* Round trip time */
367                z++;                    /* So sender & receiver differ */
368                debug(F101,"RTT RECV","",z);
369            } else {                    /* This shouldn't happen */
370                debug(F101,"RTT RECV ERROR spackets","",spackets);
371                debug(F101,"RTT RECV ERROR sequence","",n);
372                return(-1);
373            }
374        } else {                        /* File sender */
375            x = rrttbl[n];              /* Time when I got ACK(n) */
376            y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */
377            yy = srttbl[n];             /* Time when I sent n */
378            if (x > -1 && y > -1) {
379                z = x - y;              /* Packet rate */
380                zz = x - yy;            /* Round trip time */
381                debug(F101,"RTT SEND","",z);
382            } else {
383                debug(F100,"RTT SEND ERROR","",0);
384                return(-1);
385            }
386        }
387        if (z < 1)                      /* For fast connections */
388          z = RTT_SCALE / 2;            /* Convert to scale... */
389        else
390          z *= RTT_SCALE;
391        debug(F101,"RTT z scaled","",z);
392
393        if (zz < 1)                     /* For fast connections */
394          zz = RTT_SCALE / 2;           /* Convert to scale... */
395        else
396          zz *= RTT_SCALE;
397
398        rttdelay = zz;                  /* Round trip time of this packet */
399#ifdef COMMENT
400/*
401  This was used in C-Kermit 7.0 (and 6.0?) but not only is it overkill,
402  it also can produce ridiculously long timeouts under certain conditions.
403  Replaced in 8.0 by a far simpler and more aggressive strategy.
404*/
405        if (rttsamples++ == 0L) {       /* First sample */
406            pktintvl = z;
407        } else {                        /* Subsequent samples */
408            long oldavg = pktintvl;
409            long rttdiffsq;
410
411            if (rttsamples > 30)        /* Use real average for first 30 */
412              rttsamples = 30;          /*  then decaying average. */
413
414            /* Average delay, difference squared, variance, std deviation */
415
416            pktintvl += (z - pktintvl) / rttsamples;
417            rttdiffsq = (z - oldavg) * (z - oldavg);
418            rttvariance += (rttdiffsq - rttvariance) / rttsamples;
419            debug(F101,"RTT stddev1","",rttstddev);
420            if (rttstddev < 1L)         /* It can be zero, in which case */
421              rttstddev = RTT_SCALE / 3; /* set it to something small... */
422            rttstddev = (rttstddev + rttvariance / rttstddev) / 2;
423        }
424        debug(F101,"RTT stddev2","",rttstddev);
425        debug(F101,"RTT delay  ","",pktintvl);
426        rcvtimo = (pktintvl + (3L * rttstddev)) / RTT_SCALE + 1;
427        if (rpackets < 32)              /* Allow for slow start */
428          rcvtimo += rcvtimo + 2;
429        else if (rpackets < 64)
430          rcvtimo += rcvtimo / 2 + 1;
431        /* On a reliable link, don't try too hard to time out. */
432        /* Especially on fast local network connections. */
433        if (server && what == W_NOTHING) /* Server command wait */
434          rcvtimo = rcvtimo;            /* == srvtim */
435        else if (reliable == SET_ON && rcvtimo > 0) /* Reliable */
436          rcvtimo = rcvtimo +15;        /* and not server command wait */
437        else                            /* Not reliable or server cmd wait */
438          rcvtimo = rcvtimo;
439        if (rcvtimo < mintime)          /* Lower bound */
440          rcvtimo = mintime;
441        if (maxtime > 0) {              /* User specified an upper bound */
442            if (rcvtimo > maxtime)
443              rcvtimo = maxtime;
444        } else if (maxtime == 0) {      /* User didn't specify */
445            if (rcvtimo > timint * 6)
446              rcvtimo = timint * 6;
447        }
448#else  /* COMMENT */
449#ifdef CKFLOAT
450        {
451            CKFLOAT x;
452            x = (CKFLOAT)(prevz + z + z) / 3.0;
453            rcvtimo = (int)((((CKFLOAT)x * 2.66) / RTT_SCALE) + 0.5);
454            debug(F101,"RTT rcvtimo (float)","",rcvtimo);
455        }
456#else
457        rcvtimo = (prevz + z + z) / RTT_SCALE;
458        debug(F101,"RTT rcvtimo (int)","",rcvtimo);
459#endif /* CKFLOAT */
460#endif /* COMMENT */
461
462        zz = (rttdelay + 500) / 1000;
463        if (rcvtimo > (zz * 3))
464          rcvtimo = zz * 3;
465
466        if (rcvtimo < 1)
467          rcvtimo = 1;
468        if (mintime > 0) {
469            if (rcvtimo < mintime)      /* Lower bound */
470              rcvtimo = mintime;
471        }
472        if (maxtime > 0) {              /* Upper bound */
473            if (rcvtimo > maxtime)
474              rcvtimo = maxtime;
475        }
476        if (rcvtimo == (prevr - 1))
477          rcvtimo++;
478
479        debug(F101,"RTT final rcvtimo","",rcvtimo);
480    }
481    prevz = z;
482    prevr = rcvtimo;
483    return(0);
484}
485#endif /* CK_TIMERS */
486
487/*  I N P U T  --  Attempt to read packet number 'pktnum'.  */
488
489/*
490 This is the function that feeds input to Kermit's finite state machine,
491 in the form of a character in the range 32-126, normally a packet type
492 (uppercase letter) or pseudo-packet-type (lowercase letter).
493
494 If a special start state is in effect, that state is returned as if it were
495 the type of an incoming packet.
496*/
497int
498input() {
499    int type = 0, acktype;              /* Received packet type */
500    int x, y, k;                        /* Workers */
501    int z, pi, nf;                      /* Worker, packet index, NAK flag */
502    int nak2ack = 0;
503
504    debug(F000,"input sstate","",sstate);
505    debug(F101,"input nakstate","",nakstate);
506    debug(F000,"input sndtyp","",sndtyp);
507    debug(F101,"input xitsta","",xitsta);
508    debug(F101,"input what","",what);
509
510    while (1) {                         /* Big loop... */
511/*
512  It is ttchk()'s responsibility to tell us if the connection is broken,
513  and to do so instantly and nondestructively -- no blocking, etc, that would
514  slow down file transfer.
515*/
516        if (ttchk() < 0) {
517            debug(F100,"input CONNECTION BROKEN","",0);
518            fatalio = 1;
519            return('q');
520        }
521        if (sstate != 0) {              /* If a start state is in effect, */
522            type = sstate;              /* return it like a packet type, */
523            sstate = 0;                 /* and then nullify it. */
524            numerrs = 0;                /* (PWP) no errors so far */
525            return(type);
526        }
527        if (nakstate) {                 /* This section for file receiver. */
528            if (wslots > 1) {           /* If we're doing windows, */
529                x = rseqtbl[winlo];     /* see if desired packet already in. */
530                debug(F101,"input winlo","",winlo);
531                debug(F101,"input rseqtbl[winlo]","",rseqtbl[winlo]);
532                if (x > -1) {           /* Already there? */
533                    if (r_pkt[x].pk_seq == winlo) { /* (double check) */
534                        rsn = winlo;                /* Yes, return its info */
535                        debug(F101,"input return pre-stashed packet","",rsn);
536                        dumprbuf();
537                        rdatap = r_pkt[x].pk_adr;   /* like rpack would do. */
538                        rln = (int)strlen((char *) rdatap);
539                        type = r_pkt[x].pk_typ;
540                        break;
541                    }
542                }
543            }
544            type = rpack();             /* Try to read a packet. */
545            debug(F101,"input rpack","",type);
546
547            while (type == 'e') {       /* Handle echoes */
548                debug(F101,"input echo discarded","",type);
549                type = rpack();
550            }
551#ifdef DEBUG
552            if (deblog) {
553                if (type == 'D')
554                  debug(F011,"input type D=",(char *)rdatap,39);
555                else
556                  debug(F000,"input type",(char *)rdatap,type);
557            }
558#endif /* DEBUG */
559#ifndef OLDCHKINT
560            if (type == 'z') {
561                epktrcvd = 1;
562                errpkt((CHAR *)"User cancelled.");
563                type = 'E';
564                break;
565            }
566#endif /* OLDCHKINT */
567            if (type < -1) {
568                char * s;
569                s = (type == -2) ?
570                  "FAILED - Interrupted" :
571                    "FAILED - Connection lost";
572
573                xxscreen(SCR_PT,'q',0L,s);
574                dologend();
575                return('q');            /* Ctrl-C or connection lost */
576            }
577            if (type < 0) {             /* Receive window full */
578                /* Another thing to do here would be to delete */
579                /* the highest packet and NAK winlo.  But that */
580                /* shouldn't be necessary since the other Kermit */
581                /* should not have sent a packet outside the window. */
582#ifdef COMMENT
583                char foo[256];
584                ckmakxmsg(foo,256,"Receive window full (rpack): wslots=",
585                          ckitoa(wslots)," winlo=",ckitoa(winlo)," pktnum=",
586                          ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL);
587                errpkt((CHAR *)foo);
588                debug(F100,foo,"",0);
589#else
590                errpkt((CHAR *)"Receive window full");
591                debug(F101,"rpack receive window full","",0);
592                debug(F101," wslots","",wslots);
593                debug(F101," winlo","",winlo);
594                debug(F101," pktnum","",pktnum);
595#endif
596                dumprbuf();
597                type = 'E';
598                break;
599            }
600            dumprbuf();
601
602#ifdef OLDCHKINT
603            if (chkint() < 0) {         /* Check for console interrupts. */
604                errpkt((CHAR *)"User cancelled."); /* (old way) */
605                type = 'E';
606                break;
607            }
608#endif /* OLDCHKINT */
609
610#ifdef STREAMING
611            if (streaming) {            /* Streaming */
612                if (type == 'Q' || type == 'T') { /* Errors are fatal. */
613                    crunched++;         /* For statistics */
614                    errpkt((CHAR *)"Transmission error on reliable link.");
615                    type = 'E';
616                }
617            }
618#endif /* STREAMING */
619            if (type == 'E') {
620                debug(F101,"input got E, nakstate","",nakstate);
621                break;                  /* Error packet */
622            }
623            if (type == 'Q') {          /* Crunched packet. */
624                crunched++;
625                numerrs++;
626/*
627  Packet arrived damaged.  It was most likely the packet we were expecting
628  next, so we send a NAK for that packet.  Prior to 5A(189), we always
629  NAK'd winlo here, but that was bad because if two (or more) different
630  packets were damaged, we would keep NAKing the first one and never NAK the
631  other ones, which could result in a lengthy series of timeouts.  Now we
632  NAK the oldest as-yet-unNAK'd missing packet.
633*/
634#ifdef CK_TIMERS
635                rcvtimo++;              /* Stretch the timeout a little */
636#endif /* CK_TIMERS */
637                z = (winlo + wslots) % 64;  /* Search from winlo to z */
638                debug(F101,"ZZZ crunched z","",z);
639                nf = 0;                     /* NAK flag not set yet */
640                for (x = winlo; x != z; x = (x + 1) % 64) {
641                    debug(F101,"ZZZ x","",x);
642                    if (rseqtbl[x] > -1) /* Have I received packet x? */
643                      continue;          /* Yes, go on. */
644                    debug(F101,"ZZZ x not recd yet","",x);
645                    pi = sseqtbl[x];     /* No, have I NAK'd it yet? */
646                    if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
647                        debug(F101,"ZZZ x not NAK'd yet","",x);
648                        nack(x);         /* No, NAK it now. */
649                        nf = 1;          /* Flag that I did. */
650                        break;
651                    }
652                }
653                if (!nf) {              /* If we didn't NAK anything above, */
654                    debug(F101,"ZZZ NAKing winlo","",winlo);
655                    if (nack(winlo) < 0) { /* we have to NAK winlo (again) */
656                        errpkt((CHAR *)"Too many retries."); /* Too many */
657                        type = 'E';
658                        break;
659                    }
660                }
661                continue;
662            }
663
664            if (type == 'T') {          /* Timeout */
665#ifndef OS2
666                /* K95 does this its own way */
667                if (server && srvidl) {
668                    idletmo = 1;
669                    debug(F101,"SERVER IDLE TIMEOUT","",srvidl);
670                    return('q');
671                }
672#endif /* OS2 */
673#ifdef CK_TIMERS
674                rcvtimo++;              /* Stretch the timeout a little */
675#endif /* CK_TIMERS */
676                timeouts++;
677                debug(F101,"input receive-state timeout, winlo","",winlo);
678                /* NAK only the packet at window-low */
679                debug(F101,"input sending NAK for winlo","",winlo);
680                x = ttchk();
681                if (x > 0)              /* Don't give up if there is still */
682                  continue;             /* something to read. */
683                else if (x < 0) {
684                    dologend();
685                    fatalio = 1;
686                    return('q');        /* Connection Lost */
687                }
688                if (nack(winlo) < 0) {
689                    debug(F101,"input sent too many naks","",winlo);
690                    errpkt((CHAR *)"Too many retries.");
691                    type = 'E';
692                    break;
693                } else continue;
694            }
695            if (rsn == winlo) {         /* Got the packet we want, done. */
696#ifdef CK_TIMERS
697                if (rttflg && timint)   /* Dynamic round trip timers? */
698                  getrtt(nakstate, rsn); /* yes, do it. */
699#endif /* CK_TIMERS */
700                debug(F101,"input rsn=winlo","",rsn);
701                break;
702            }
703
704            /* Got a packet out of order. */
705
706            debug(F101,"input out of sequence, rsn","",rsn);
707            k = rseqtbl[rsn];           /* Get window slot of this packet. */
708            debug(F101,"input rseqtbl[rsn]","",k);
709            if (k < 0) {
710                debug(F101,"input recv can't find index for rcvd pkt","",rsn);
711                /* Was "Internal error 21" */
712                /* This should not happen  */
713                errpkt((CHAR *)"Sliding windows protocol error.");
714                type = 'E';
715                break;
716            }
717            y = chkwin(rsn,winlo,wslots); /* See what window it's in. */
718            debug(F101,"input recv chkwin","",y);
719            if (y == 1) {               /* From previous window. */
720#ifdef STREAMING
721                if (!streaming)         /* NO RESEND IF STREAMING! */
722#endif /* STREAMING */
723                  resend(rsn);          /* Resend the ACK (might have data) */
724                freerpkt(rsn);          /* Get rid of received packet */
725                continue;               /* Back to wait for another packet */
726            } else {                    /* In this window or out of range */
727                if (y < 0)              /* If out of range entirely, */
728                  freerpkt(rsn);        /* release its buffer */
729
730#ifdef STREAMING
731                if (streaming) {        /* Streaming (this shouldn't happen) */
732                    errpkt((CHAR *)"Sequence error on reliable link.");
733                    type = 'E';
734                    break;
735                }
736#endif /* STREAMING */
737
738/* If our receive window is full, NAK window-low */
739
740                if (rbufnum < 1) {      /* Receive window full? */
741                    if (nack(winlo) < 0) {    /* No choice, must NAK winlo. */
742                        errpkt((CHAR *)"Too many retries."); /* Too many */
743                        type = 'E';
744                        break;
745                    } else continue;
746                }
747/*
748  Receive window not full.  This is a packet in the current window but it is
749  not the desired packet at winlo.  So therefore there are gaps before this
750  packet.  So we find the "lowest" unNAK'd missing packet, if any, between
751  winlo and this one, and NAK it.  If there are no as-yet-unNAK'd missing
752  packets in the window, then we send nothing and go wait for another packet.
753  In theory, this could result in a timeout, but in practice it is likely that
754  the already-NAK'd missing packets are already on their way.  Note, we do not
755  NAK ahead of ourselves, as that only creates unnecessary retransmissions.
756*/
757                for (x = winlo; x != rsn; x = (x + 1) % 64) {
758                    if (rseqtbl[x] > -1) /* Have I received packet x? */
759                      continue;          /* Yes, check next sequence number. */
760                    pi = sseqtbl[x];     /* No, have I NAK'd it yet? */
761                    if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
762                        nack(x);         /* No, NAK it now. */
763                        break;
764                    }
765                }
766            }
767/*!!!*/
768        } else {                        /* Otherwise file sender... */
769
770#ifdef STREAMING
771            if (streaming && sndtyp == 'D') {
772                debug(F101,"STREAMING input streaming","",streaming);
773                debug(F000,"STREAMING input sndtyp","",sndtyp);
774                rsn = winlo;
775                type = 'Y';             /* Pretend we got an ACK */
776            }
777#endif /* STREAMING */
778            if (!nak2ack) {             /* NAK(n+1) = ACK(n) */
779                if (wslots > 1) {       /* Packet at winlo already ACK'd? */
780                    if (sacktbl[winlo]) { /* If so,  */
781                        sacktbl[winlo] = 0; /* Turn off the ACK'd flag */
782                        winlo = (winlo + 1) % 64; /* Rotate the window */
783                        type = 'Y';     /* And return ACK */
784                        debug(F101,
785                              "input send returning pre-stashed ACK","",
786                              winlo-1);
787                        break;
788                    }
789                }
790#ifdef STREAMING
791                if (!(streaming && sndtyp == 'D')) { /* Not streaming | data */
792                    type = rpack();     /* Try to read an acknowledgement */
793                } else {                /* Streaming and in Data phase */
794                    type = 'Y';         /* Assume all is normal */
795                    if (chkint() < 0)   /* Check for console interrupts. */
796                      type = 'z';
797                    else if (ttchk() > 4 + bctu) /* Check for return traffic */
798                      type = rpack();
799                    debug(F000,"input streaming type","",type);
800                }
801#endif /* STREAMING */
802                debug(F111,"input send",(char *) rdatap,(int) type);
803                while (type == 'e') {   /* Handle echoes */
804                    debug(F000,"echo discarded","",type);
805                    type = rpack();
806                }
807#ifndef OLDCHKINT
808                if (type == 'z') {
809                    epktrcvd = 1;
810                    errpkt((CHAR *)"User cancelled.");
811                    type = 'E';
812                    break;
813                }
814#endif /* OLDCHKINT */
815                if (type < -1) {
816                    xxscreen(SCR_PT,'q',0L,
817                           ((char *)((type == -2) ?
818                           "Interrupted" :
819                           "Connection lost"))
820                           );
821                    if (type != -2)
822                      dologend();
823                    return('q');        /* Ctrl-C or connection lost */
824                }
825                if (type == -1) {
826#ifdef COMMENT
827                    char foo[256];
828                    ckmakxmsg(foo,256,
829                              "Receive window full (error 18): wslots=",
830                              ckitoa(wslots),
831                              " winlo=",ckitoa(winlo)," pktnum=",
832                              ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL);
833                    errpkt((CHAR *)foo);
834                    debug(F100,foo,"",0);
835#else
836                    errpkt((CHAR *)"Receive window full"); /* was "internal */
837                    debug(F101," wslots","",wslots); /* error 18" */
838                    debug(F101," winlo","",winlo);
839                    debug(F101," pktnum","",pktnum);
840#endif /* COMMENT */
841                    dumprbuf();
842                    type = 'E';
843                    break;
844                }
845                dumprbuf();             /* Debugging */
846
847#ifdef OLDCHKINT
848                if (chkint() < 0) {     /* Check for console interrupts. */
849                    errpkt((CHAR *)"User cancelled.");
850                    return(type = 'E');
851                }
852#endif /* OLDCHKINT */
853
854                /* Got a packet */
855
856#ifdef STREAMING
857                if (streaming) {                /* Streaming */
858                    if (type == 'Q' || type == 'T') { /* Errors are fatal. */
859                        crunched++;     /* For statistics */
860                        errpkt((CHAR *)"Transmission error on reliable link.");
861                        type = 'E';
862                    }
863                }
864#endif /* STREAMING */
865                if (type == 'E') {
866                    debug(F101,"input send got E, nakstate","",nakstate);
867                    break;              /* Error packet */
868                }
869                if (type == 'Q') {      /* Crunched packet */
870                    crunched++;         /* For statistics */
871                    numerrs++;          /* For packet resizing */
872                    x = resend(winlo);  /* Resend window-low */
873                    if (x < 0) {
874                        type = 'E';
875                        errpkt((CHAR *)"Too many retries");
876                        break;
877                    }
878                    continue;
879                }
880                if (type == 'T') {      /* Timeout waiting for ACKs. */
881                    timeouts++;         /* Count it */
882                    numerrs++;          /* Count an error too */
883                    debug(F101,"input send state timeout, winlo","",winlo);
884
885                    /* Retransmit the oldest un-ACK'd packet. */
886
887                    debug(F101,"input send resending winlo","",winlo);
888                    if (resend(winlo) < 0) { /* Check retries */
889                        debug(F101,"input send too many resends","",maxtry);
890                        errpkt((CHAR *)"Too many retries");
891                        return(type = 'E');
892                    }
893#ifdef NEWDPL
894                    /* Reduce prevailing packet length */
895                    x = sseqtbl[winlo]; /* Get length of packet we want ACKd */
896                    if (x > -1) {       /* Only if we have a valid index */
897                        if (s_pkt[x].pk_typ == 'D') { /* only for D packets */
898                            spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */
899                            if (spsiz < 20) spsiz = 20; /* within reason */
900                            debug(F101,"input T cut packet length","",spsiz);
901                        }
902                    }
903#endif /* NEWDPL */
904                    continue;
905                }
906            }
907            /* Got an actual normal packet */
908
909            nak2ack = 0;                /* Unset this flag. */
910            y = chkwin(rsn,winlo,wslots); /* Is it in the window? */
911            debug(F101,"input send rsn","",rsn);
912            debug(F101,"input send winlo","",winlo);
913            debug(F101,"input send chkwin","",y);
914
915            if (type == 'Y') {          /* Got an ACK */
916                if (y == 0) {           /* In current window */
917                    if (spackets < 4)   /* Error counter doesn't count */
918                      numerrs = 0;      /* until data phase. */
919                    sacktbl[rsn]++;     /* Mark the packet as ACK'd */
920                    x = sseqtbl[rsn];   /* Get ACK'd packet's buffer index */
921                    debug(F101,"bestlen ack x","",x);
922#ifdef NEWDPL
923                    if (x > -1) {
924                        acktype = s_pkt[x].pk_typ; /* Get type */
925                        debug(F000,"bestlen ack type","",acktype);
926
927                        if (acktype == 'D') { /* Adjust data packet length */
928                            if (spsiz > bestlen) {
929                                bestlen = spsiz;
930                                debug(F101,"bestlen B","",bestlen);
931                            }
932#ifdef DEBUG
933                            if (deblog) {
934                                debug(F101,"bestlen retry","",s_pkt[x].pk_rtr);
935                                debug(F101,"bestlen len","",s_pkt[x].pk_len);
936                                debug(F101,"bestlen spackets","",spackets);
937                            }
938#endif /* DEBUG */
939                            /* Set new best length */
940                            if (s_pkt[x].pk_rtr == 0 &&
941                                s_pkt[x].pk_len + 8 > bestlen) {
942                                bestlen = s_pkt[x].pk_len + 8;
943                                if (bestlen > spmax)
944                                  bestlen = spmax;
945                                debug(F101,"bestlen A","",bestlen);
946                            }
947#ifdef DEBUG
948                            if (deblog) {
949                                debug(F101,"bestlen wslots","",wslots);
950                                debug(F101,"bestlen maxsend","",maxsend);
951                            }
952#endif /* DEBUG */
953                            /* Slow start */
954                            if (slostart &&
955                                (maxsend <= spmax) &&
956                                (rpackets < 11) &&
957                                (numerrs == 0)) {
958                                spsiz = spsiz << 1;
959                                debug(F101,"bestlen spsiz A","",spsiz);
960
961                            /* Creep up to best length */
962                            } else if ((spackets > 5) &&
963                                       (spsiz < bestlen - 8)) {
964                                spsiz += (bestlen - spsiz) / 3;
965                                debug(F101,"bestlen spsiz B","",spsiz);
966
967                            /* Push the envelope */
968                            } else if ((spackets % (wslots + 1) == 0) &&
969                                       (spackets > 6) &&
970                                       (bestlen < spmax - 8) &&
971                                       (spsiz < spmax)) {
972                                spsiz += (spmax - bestlen) / 3;
973                                debug(F101,"bestlen spsiz C","",spsiz);
974                            }
975                            /* But not too far */
976                            if (spsiz > spmax) {
977                                spsiz = spmax;
978                                debug(F101,"bestlen spsiz D","",spsiz);
979                            }
980                        }
981                    }
982#endif /* NEWDPL */
983
984#ifdef CK_TIMERS
985                    if (rttflg && timint) /* If doing dynamic timers */
986                      getrtt(nakstate, rsn); /* call routine to set it. */
987#endif /* CK_TIMERS */
988/*
989  NOTE: The following statement frees the buffer of the ACK we just got.
990  But the upper layers still need the data, like if it's the ACK to an I,
991  S, F, D, Z, or just about any kind of packet.  So for now, freerbuf()
992  deallocates the buffer, but does not erase the data or destroy the pointer
993  to it.  There's no other single place where these receive buffers can be
994  correctly freed (?) ...
995*/
996                    freerpkt(rsn);      /* Free the ACK's buffer */
997                    freesbuf(rsn);      /* *** Free the sent packet's buffer */
998                    if (rsn == winlo) { /* Got the one we want */
999                        sacktbl[winlo] = 0;
1000                        winlo = (winlo + 1) % 64;
1001                        debug(F101,"input send rotated send window","",winlo);
1002                        break;          /* Return the ACK */
1003                    } else {
1004                        debug(F101,"input send mark pkt","",rsn);
1005                        continue;       /* Otherwise go read another packet */
1006                    }
1007                } else if (y == 1 && wslots < 2) { /* (190) ACK for previous */
1008                    numerrs++;          /* == NAK for current, count error */
1009                    debug(F101,"input send ACK for previous","",rsn);
1010                    freerpkt(rsn);      /* Free NAK's buffer */
1011                    x = resend(winlo);  /* Resend current packet */
1012                    if (x < 0) {
1013                        type = 'E';
1014                        errpkt((CHAR *)"Too many retries");
1015                        break;
1016                    } else continue;    /* Resend ok, go read another packet */
1017                } else {                /* Other cases, just ignore */
1018                    debug(F101,"input send ACK out of window","",rsn);
1019                    freerpkt(rsn);
1020                    continue;
1021                }
1022            }
1023            if (type == 'N') {          /* NAK */
1024                numerrs++;              /* Count an error */
1025#ifdef STREAMING
1026                if (streaming) {                /* Streaming */
1027                    errpkt((CHAR *)"NAK received on reliable link.");
1028                    type = 'E';
1029                    break;
1030                }
1031#endif /* STREAMING */
1032
1033                debug(F101,"input send NAK","",rsn);
1034#ifdef NEWDPL
1035                /* Reduce prevailing packet length */
1036                x = sseqtbl[rsn];       /* Length of packet that was NAK'd */
1037                if (x > -1) {           /* If it's a Data packet we've sent */
1038                    if (s_pkt[x].pk_typ == 'D') {
1039                        spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */
1040#ifdef COMMENT
1041                        /* This might be a good idea -- haven't tried it ... */
1042                        if (bestlen > 0 && spsiz > bestlen)
1043                          spsiz = bestlen;
1044#endif /* COMMENT */
1045                        if (spsiz < 20) spsiz = 20;
1046                        debug(F101,"input N cut packet length","",spsiz);
1047                    }
1048                }
1049#endif /* NEWDPL */
1050                freerpkt(rsn);          /* Free buffer where NAK lies. */
1051                if (y == 0) {           /* In current window */
1052                    debug(F100," in window","",0);
1053                    k = sseqtbl[rsn];   /* Get pointer to NAK'd packet. */
1054                    if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) {
1055                        x = resend(winlo); /* Packet we haven't sent yet. */
1056                    } else {
1057                        x = resend(rsn); /* Resend requested packet. */
1058                    }
1059                    if (x < 0) {        /* Resend error is fatal.  */
1060                        type = 'E';
1061                        errpkt((CHAR *)"Too many retries");
1062                        break;
1063                    } else continue;    /* Resend ok, go read another packet */
1064                } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */
1065                    if (wslots > 1) {
1066                        debug( F101,"NAK for next packet, windowing","",rsn);
1067                        x = resend(winlo); /* Resend window-low */
1068                        if (x < 0) {
1069                            type = 'E';
1070                            errpkt((CHAR *)"Too many retries");
1071                            break;
1072                        }
1073                        continue;       /* Go back and read another pkt */
1074                    }
1075                    debug(F101,"NAK for next packet, no windowing","",rsn);
1076                    x = (rsn == 0) ? 63 : rsn - 1;
1077                    if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) {
1078                        resend(0);      /* ACK for S or I packet missing */
1079                        continue;       /* so resend the S or I */
1080                    }
1081                    rsn = x;            /* Else, treat NAK(n+1) as ACK(n) */
1082                    nak2ack = 1;        /* Go back and process the ACK */
1083                    continue;
1084                } else if (y > 0) {     /* NAK for pkt we can't resend */
1085                    debug(F101," NAK out of window","",rsn); /* bad... */
1086                    type = 'E';
1087                    errpkt((CHAR *)"NAK out of window");
1088                    break;
1089                } else continue;        /* Ignore other NAKs */
1090            }                           /* End of file-sender NAK handler */
1091
1092            if (rsn == winlo) {         /* Not ACK, NAK, timeout, etc. */
1093                debug(F000,"input send unexpected type","",type);
1094                break;
1095            }
1096        }                               /* End of file-sender section */
1097    }                                   /* End of input() while() loop */
1098/*
1099  When the window size is 1 and we have the packet we want, there can not
1100  possibly be anything waiting for us on the connection that is useful to us.
1101  However, there might be redundant copies of a packet we already got, which
1102  would cause needless cycles of repeated packets.  Therefore we flush the
1103  communications input buffer now to try to get rid of undesired and unneeded
1104  packets that we have not read yet.
1105*/
1106    if (wslotn == 1                     /* (not wslots!) */
1107#ifdef STREAMING
1108        && !streaming                   /* But not when streaming */
1109#endif /* STREAMING */
1110        ) {
1111        debug(F100,"input about to flush","",0);
1112        ttflui();               /* Got what we want, clear input buffer. */
1113    }
1114#ifndef NEWDPL
1115    if (!nakstate)                      /* When sending */
1116      rcalcpsz();                       /* recalculate size every packet */
1117#endif /* NEWDPL */
1118    if (type == 'E')
1119      xitsta |= (what ? what : 1);      /* Remember what failed. */
1120    debug(F101,"input winlo","",winlo);
1121    debug(F101,"input rsn","",rsn);
1122    debug(F000,"input returning type","",type);
1123    return(rcvtyp = type);              /* Success, return packet type. */
1124}
1125
1126#ifdef PARSENSE
1127/*  P A R C H K  --  Check if Kermit packet has parity  */
1128
1129/*
1130  Call with s = pointer to packet, start = packet start character, n = length.
1131  Returns 0 if packet has no parity, -1 on error, or, if packet has parity:
1132    'e' for even, 'o' for odd, 'm' for mark.  Space parity cannot be sensed.
1133  So a return value of 0 really means either space or none.
1134  Returns -2 if parity has already been checked during this protocol operation.
1135*/
1136int
1137#ifdef CK_ANSIC
1138parchk(CHAR *s, CHAR start, int n)
1139#else
1140parchk(s,start,n) CHAR *s, start; int n;
1141#endif /* CK_ANSIC */
1142/* parchk */ {
1143    CHAR s0, s1, s2, s3;
1144
1145    debug(F101,"parchk n","",n);
1146    debug(F101,"parchk start","",start);
1147
1148    s0 = s[0] & 0x7f;                   /* Mark field (usually Ctrl-A) */
1149
1150    if (s0 != start || n < 5) return(-1); /* Not a valid packet */
1151
1152/* Look at packet control fields, which never have 8th bit set */
1153/* First check for no parity, most common case. */
1154
1155    if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0)
1156      return(0);                        /* No parity or space parity */
1157
1158/* Check for mark parity */
1159
1160    if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80)
1161      return('m');                      /* Mark parity */
1162
1163/* Packet has some kind of parity */
1164/* Make 7-bit copies of control fields */
1165
1166    s1 = s[1] & 0x7f;                   /* LEN */
1167    s2 = s[2] & 0x7f;                   /* SEQ */
1168    s3 = s[3] & 0x7f;                   /* TYPE */
1169
1170/* Check for even parity */
1171
1172    if ((s[0] == p_tbl[s0]) &&
1173        (s[1] == p_tbl[s1]) &&
1174        (s[2] == p_tbl[s2]) &&
1175        (s[3] == p_tbl[s3]))
1176      return('e');
1177
1178/* Check for odd parity */
1179
1180    if ((s[0] != p_tbl[s0]) &&
1181        (s[1] != p_tbl[s1]) &&
1182        (s[2] != p_tbl[s2]) &&
1183        (s[3] != p_tbl[s3]))
1184      return('o');
1185
1186/* Otherwise it's probably line noise.  Let checksum calculation catch it. */
1187
1188    return(-1);
1189}
1190#endif /* PARSENSE */
1191
1192/*
1193  Check to make sure timeout intervals are long enough to allow maximum
1194  length packets to get through before the timer goes off.  If not, the
1195  timeout interval is adjusted upwards.
1196
1197  This routine is called at the beginning of a transaction, before we
1198  know anything about the delay characteristics of the line.  It works
1199  only for serial communication devices; it trusts the speed reported by
1200  the operating system.
1201
1202  Call with a timout interval.  Returns it, adjusted if necessary.
1203*/
1204int
1205chktimo(timo,flag) int timo, flag; {
1206    long cps, z; int x, y;
1207#ifdef STREAMING
1208    debug(F101,"chktimo streaming","",streaming);
1209    if (streaming)
1210      return(0);
1211#endif /* STREAMING */
1212
1213    debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */
1214    debug(F101,"chktimo flag","",flag);
1215
1216    if (flag)                           /* Don't change timeout if user */
1217      return(timo);                     /* gave SET SEND TIMEOUT command. */
1218    debug(F101,"chktimo spmax","",spmax);
1219    debug(F101,"chktimo urpsiz","",urpsiz);
1220
1221    if (!network) {                     /* On serial connections... */
1222        speed = ttgspd();               /* Get current speed. */
1223        if (speed > 0L) {
1224            cps = speed / 10L;          /* Convert to chars per second */
1225            if (cps > 0L) {
1226                long plen;              /* Maximum of send and rcv pkt size */
1227                z = cps * (long) timo;  /* Chars per timeout interval */
1228                z -= z / 10L;           /* Less 10 percent */
1229                plen = spmax;
1230                if (urpsiz > spmax) plen = urpsiz;
1231                debug(F101,"chktimo plen","",plen);
1232                if (z < plen) {         /* Compare with packet size */
1233                    x = (int) ((long) plen / cps); /* Adjust if necessary */
1234                    y = x / 10;         /* Add 10 percent for safety */
1235                    if (y < 2) y = 2;   /* Or 2 seconds, whichever is more */
1236                    x += y;
1237                    if (x > timo)       /* If this is greater than current */
1238                      timo = x;         /* timeout, change the timeout */
1239                    debug(F101,"chktimo new timo","",timo);
1240                }
1241            }
1242        }
1243    }
1244    return(timo);
1245}
1246
1247/*  S P A C K  --  Construct and send a packet  */
1248
1249/*
1250  spack() sends a packet of the given type, sequence number n, with len data
1251  characters pointed to by d, in either a regular or extended- length packet,
1252  depending on len.  Returns the number of bytes actually sent, or else -1
1253  upon failure.  Uses global npad, padch, mystch, bctu, data.  Leaves packet
1254  fully built and null-terminated for later retransmission by resend().
1255  Updates global sndpktl (send-packet length).
1256
1257  NOTE: The global pointer "data" is assumed to point into the 7th position
1258  of a character array (presumably in packet buffer for the current packet).
1259  It was used by getpkt() to build the packet data field.  spack() fills in
1260  the header to the left of the data pointer (the data pointer is defined
1261  in getsbuf() in ckcfn3.c).  If the address "d" is the same as "data", then
1262  the packet's data field has been built "in place" and need not be copied.
1263*/
1264int
1265#ifdef CK_ANSIC
1266spack(char pkttyp, int n, int len, CHAR *d)
1267#else
1268spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d;
1269#endif /* CK_ANSIC */
1270/* spack */ {
1271    register int i;
1272    int ix, j, k, x, lp, longpkt, copy, loglen;
1273
1274#ifdef GFTIMER
1275    CKFLOAT t1 = 0.0, t2 = 0.0;
1276#endif /* GFTIMER */
1277
1278    register CHAR *cp, *mydata;
1279    unsigned crc;
1280
1281    copy = (d != data);                 /* Flag whether data must be copied  */
1282
1283#ifdef DEBUG
1284    if (deblog) {                       /* Save lots of function calls! */
1285        debug(F101,"spack n","",n);
1286        if (pkttyp != 'D') {            /* Data packets would be too long */
1287            debug(F111,"spack data",data,data);
1288            debug(F111,"spack d",d,d);
1289        }
1290        debug(F101,"spack len","",len);
1291        debug(F101,"spack copy","",copy);
1292    }
1293#endif /* DEBUG */
1294
1295    longpkt = (len + bctl + 2) > 94;    /* Decide whether it's a long packet */
1296    mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */
1297    k = sseqtbl[n];                     /* Packet structure info for pkt n */
1298#ifdef DEBUG
1299    if (deblog) {                       /* Save 2 more function calls... */
1300        debug(F101,"spack mydata","",mydata);
1301        debug(F101,"spack sseqtbl[n]","",k);
1302        if (k < 0) {
1303#ifdef STREAMING
1304            if (!streaming)
1305#endif /* STREAMING */
1306              debug(F101,"spack sending packet out of window","",n);
1307        }
1308    }
1309#endif /* DEBUG */
1310    if (k > -1) {
1311        s_pkt[k].pk_adr = mydata;       /* Remember address of packet. */
1312        s_pkt[k].pk_seq = n;            /* Record sequence number */
1313        s_pkt[k].pk_typ = pkttyp;       /* Record packet type */
1314    }
1315    spktl = 0;                          /* Initialize length of this packet */
1316    i = 0;                              /* and position in packet. */
1317
1318/* Now fill the packet */
1319
1320    mydata[i++] = mystch;               /* MARK */
1321    lp = i++;                           /* Position of LEN, fill in later */
1322
1323    mydata[i++] = tochar(n);            /* SEQ field */
1324    mydata[i++] = pkttyp;               /* TYPE field */
1325    j = len + bctl;                     /* Length of data + block check */
1326    if (longpkt) {                      /* Long packet? */
1327        int x;                          /* Yes, work around SCO Xenix/286 */
1328#ifdef CKTUNING
1329        unsigned int chk;
1330#endif /* CKTUNING */
1331        x = j / 95;                     /* compiler bug... */
1332        mydata[lp] = tochar(0);         /* Set LEN to zero */
1333        mydata[i++] = tochar(x);        /* Extended length, high byte */
1334        mydata[i++] = tochar(j % 95);   /* Extended length, low byte */
1335#ifdef CKTUNING
1336        /* Header checksum - skip the function calls and loops */
1337          chk = (unsigned) mydata[lp]   +
1338                (unsigned) mydata[lp+1] +
1339                (unsigned) mydata[lp+2] +
1340                (unsigned) mydata[lp+3] +
1341                (unsigned) mydata[lp+4] ;
1342        mydata[i++] = tochar((CHAR) ((((chk & 0300) >> 6) + chk) & 077));
1343#else
1344        mydata[i] = '\0';               /* Terminate for header checksum */
1345        mydata[i++] = tochar(chk1(mydata+lp,5));
1346#endif /* CKTUNING */
1347    } else mydata[lp] = tochar(j+2);    /* Normal LEN */
1348/*
1349  When sending a file, the data is already in the right place.  If it weren't,
1350  it might make sense to optimize this section by using memcpy or bcopy
1351  (neither of which are portable), but only if our packets were rather long.
1352  When receiving, we're only sending ACKs so it doesn't matter.  So count the
1353  following loop as a sleeping dog.
1354*/
1355    if (copy)                           /* Data field built in place? */
1356      for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */
1357    else                                /* Otherwise, */
1358      i += len;                         /* Just skip past data field. */
1359    mydata[i] = '\0';                   /* Null-terminate for checksum calc. */
1360
1361    switch (bctu) {                     /* Block check */
1362        case 1:                         /* 1 = 6-bit chksum */
1363            ix = i - lp;                /* Avoid "order of operation" error */
1364            mydata[i++] = tochar(chk1(mydata+lp,ix));
1365            break;
1366        case 2:                         /* 2 = 12-bit chksum */
1367            j = chk2(mydata+lp,i-lp);
1368            mydata[i++] = (unsigned)tochar((j >> 6) & 077);
1369            mydata[i++] = (unsigned)tochar(j & 077);
1370            break;
1371        case 3:                         /* 3 = 16-bit CRC */
1372            crc = chk3(mydata+lp,i-lp);
1373            mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12);
1374            mydata[i++] = (unsigned)tochar((crc >> 6) & 077);
1375            mydata[i++] = (unsigned)tochar(crc & 077);
1376            break;
1377        case 4:                         /* 2 = 12-bit chksum, blank-free */
1378            j = chk2(mydata+lp,i-lp);
1379            mydata[i++] =
1380              (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1)));
1381            mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1)));
1382            break;
1383    }
1384    loglen = i;
1385    mydata[i++] = seol;                 /* End of line (packet terminator) */
1386#ifdef TCPSOCKET
1387/*
1388  If TELNET connection and packet terminator is carriage return,
1389  we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE
1390  (tn_nlm), to meet the TELNET NVT specification, unless user said RAW.
1391
1392  If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL
1393  on a NVT connection and CR on a binary connection.
1394*/
1395    if (
1396#ifdef STREAMING
1397        !dontsend &&
1398#endif /* STREAMING */
1399        ((network && ttnproto == NP_TELNET) || (!local && sstelnet))
1400        && seol == CR) {
1401        switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
1402          case TNL_CR:                  /* NVT or BINARY */
1403            break;
1404          case TNL_CRNUL:
1405            mydata[i++] = NUL;
1406            break;
1407          case TNL_CRLF:
1408            mydata[i++] = LF;
1409            break;
1410        }
1411    }
1412#endif /* TCPSOCKET */
1413    mydata[i] = '\0';                   /* Terminate string */
1414    if (
1415#ifdef STREAMING
1416        !dontsend &&
1417#endif /* STREAMING */
1418        pktlog
1419        )                               /* Save a function call! */
1420      logpkt('s',n,mydata,loglen);      /* Log the packet */
1421
1422    /* (PWP) add the parity quickly at the end */
1423    if (parity) {
1424        switch (parity) {
1425          case 'e':                     /* Even */
1426            for (cp = &mydata[i-1]; cp >= mydata; cp--)
1427              *cp = p_tbl[*cp];
1428            break;
1429          case 'm':                     /* Mark */
1430            for (cp = &mydata[i-1]; cp >= mydata; cp--)
1431              *cp |= 128;
1432            break;
1433          case 'o':                     /* Odd */
1434            for (cp = &mydata[i-1]; cp >= mydata; cp--)
1435              *cp = p_tbl[*cp] ^ 128;
1436            break;
1437          case 's':                     /* Space */
1438            for (cp = &mydata[i-1]; cp >= mydata; cp--)
1439              *cp &= 127;
1440            break;
1441        }
1442    }
1443    if (pktpaus) msleep(pktpaus);       /* Pause if requested */
1444    x = 0;
1445
1446    if (npad) {
1447#ifdef STREAMING
1448        if (dontsend)
1449          x = 0;
1450        else
1451#endif /* STREAMING */
1452          x = ttol(padbuf,npad);        /* Send any padding */
1453    }
1454    if (x > -1) {
1455#ifdef CK_TIMERS
1456        if (timint > 0) {
1457            if (pkttyp == 'N')
1458              srttbl[n > 0 ? n-1 : 63] = gtimer();
1459            else
1460              srttbl[n] = gtimer();
1461        }
1462#endif /* CK_TIMERS */
1463        spktl = i;                      /* Remember packet length */
1464        if (k > -1)
1465          s_pkt[k].pk_len = spktl;      /* also in packet info structure */
1466
1467#ifdef DEBUG
1468#ifdef GFTIMER
1469/*
1470  This code shows (in the debug log) how long it takes write() to execute.
1471  Sometimes on a congested TCP connection, it can surprise you -- 90 seconds
1472  or more...
1473*/
1474        if (
1475#ifdef STREAMING
1476            !dontsend &&
1477#endif /* STREAMING */
1478            deblog
1479            )
1480          t1 = gftimer();
1481#endif /* GFTIMER */
1482#endif /* DEBUG */
1483
1484#ifdef STREAMING
1485        if (dontsend) {
1486            debug(F000,"STREAMING spack skipping","",pkttyp);
1487            x = 0;
1488        } else
1489#endif /* STREAMING */
1490        x = ttol(mydata,spktl);         /* Send the packet */
1491    }
1492#ifdef STREAMING
1493    if (!dontsend) {
1494#endif /* STREAMING */
1495        debug(F101,"spack spktl","",spktl);
1496        debug(F101,"spack ttol returns","",x);
1497        if (x < 0) {                    /* Failed. */
1498            if (local && x < -1) {
1499                xxscreen(SCR_ST,ST_ERR,0L,"FAILED: Connection lost");
1500                /* We can't send an E packet because the connection is lost. */
1501                epktsent = 1;           /* So pretend we sent one. */
1502                fatalio = 1;            /* Remember we got a fatal i/o error */
1503                dologend();
1504                ckstrncpy((char *)epktmsg,"Connection lost",PKTMSGLEN);
1505            }
1506            return(x);
1507        }
1508        if (spktl > maxsend)            /* Keep track of longest packet sent */
1509          maxsend = spktl;
1510#ifdef DEBUG
1511#ifdef GFTIMER
1512        if (deblog)  {                  /* Log elapsed time for write() */
1513            t2 = gftimer();
1514            debug(F101,"spack ttol msec","",(long)((t2-t1)*1000.0));
1515        }
1516#endif /* GFTIMER */
1517#endif /* DEBUG */
1518#ifdef STREAMING
1519    }
1520#endif /* STREAMING */
1521
1522    sndtyp = pkttyp;                    /* Remember packet type for echos */
1523#ifdef STREAMING
1524    if (!dontsend) {                    /* If really sent, */
1525        spackets++;                     /* count it. */
1526        flco += spktl;                  /* Count the characters */
1527        tlco += spktl;                  /* for statistics... */
1528#ifdef DEBUG
1529        if (deblog) {                   /* Save two function calls! */
1530            dumpsbuf();                 /* Dump send buffers to debug log */
1531            debug(F111,"spack calling screen, mydata=",mydata,n);
1532        }
1533#endif /* DEBUG */
1534    }
1535#endif /* STREAMING */
1536    if (local) {
1537        int x = 0;
1538        if (fdispla != XYFD_N) x = 1;
1539        if ((fdispla == XYFD_B) && (pkttyp == 'D' || pkttyp == 'Y')) x = 0;
1540        if (x)
1541          xxscreen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */
1542    }
1543    return(spktl);                      /* Return length */
1544}
1545
1546/*  C H K 1  --  Compute a type-1 Kermit 6-bit checksum.  */
1547
1548int
1549chk1(pkt,len) register CHAR *pkt; register int len; {
1550    register unsigned int chk;
1551#ifdef CKTUNING
1552#ifdef COMMENT
1553    register unsigned int m;            /* Avoid function call */
1554    m = (parity) ? 0177 : 0377;
1555    for (chk = 0; len-- > 0; pkt++)
1556      chk += *pkt & m;
1557#else
1558    chk = 0;
1559    while (len-- > 0) chk += (unsigned) *pkt++;
1560#endif /* COMMENT */
1561#else
1562    chk = chk2(pkt,len);
1563#endif /* CKTUNING */
1564    chk = (((chk & 0300) >> 6) + chk) & 077;
1565    debug(F101,"chk1","",chk);
1566    return((int) chk);
1567}
1568
1569/*  C H K 2  --  Compute the numeric sum of all the bytes in the packet.  */
1570
1571unsigned int
1572chk2(pkt,len) register CHAR *pkt; register int len; {
1573    register long chk;
1574#ifdef COMMENT
1575    register unsigned int m;
1576    m = (parity) ? 0177 : 0377;
1577    for (chk = 0; len-- > 0; pkt++)
1578      chk += *pkt & m;
1579#else
1580    /* Parity has already been stripped */
1581    chk = 0L;
1582    while (len-- > 0) chk += (unsigned) *pkt++;
1583#endif /* COMMENT */
1584    debug(F101,"chk2","",(unsigned int) (chk & 07777));
1585    return((unsigned int) (chk & 07777));
1586}
1587
1588/*  C H K 3  --  Compute a type-3 Kermit block check.  */
1589/*
1590 Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup
1591 table.  Assumes the argument string contains no embedded nulls.
1592*/
1593#ifdef COMMENT
1594unsigned int
1595chk3(pkt,parity,len) register CHAR *pkt; int parity; register int len; {
1596    register long c, crc;
1597    register unsigned int m;
1598    m = (parity) ? 0177 : 0377;
1599    for (crc = 0; len-- > 0; pkt++) {
1600        c = crc ^ (long)(*pkt & m);
1601        crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
1602    }
1603    return((unsigned int) (crc & 0xFFFF));
1604}
1605#else
1606unsigned int
1607chk3(pkt,len) register CHAR *pkt; register int len; {
1608    register long c, crc;
1609    for (crc = 0; len-- > 0; pkt++) {
1610        c = crc ^ (long)(*pkt);
1611        crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
1612    }
1613    debug(F101,"chk3","",(unsigned int) (crc & 0xFFFF));
1614    return((unsigned int) (crc & 0xFFFF));
1615}
1616#endif /* COMMENT */
1617
1618/*  N X T P K T  --  Next Packet  */
1619/*
1620  Get packet number of next packet to send and allocate a buffer for it.
1621  Returns:
1622    0 on success, with global pktnum set to the packet number;
1623   -1 on failure to allocate buffer (fatal);
1624   -2 if resulting packet number is outside the current window.
1625*/
1626int
1627nxtpkt() {                              /* Called by file sender */
1628    int j, n, x;
1629
1630    debug(F101,"nxtpkt pktnum","",pktnum);
1631    debug(F101,"nxtpkt winlo ","",winlo);
1632    n = (pktnum + 1) % 64;              /* Increment packet number mod 64 */
1633    debug(F101,"nxtpkt n","",n);
1634#ifdef STREAMING
1635    if (!streaming) {
1636        x = chkwin(n,winlo,wslots);     /* Don't exceed window boundary */
1637        debug(F101,"nxtpkt chkwin","",x);
1638        if (x)
1639          return(-2);
1640        j = getsbuf(n);                 /* Get a buffer for packet n */
1641        if (j < 0) {
1642            debug(F101,"nxtpkt getsbuf failure","",j);
1643            return(-1);
1644        }
1645    }
1646#endif /* STREAMING */
1647    pktnum = n;
1648    return(0);
1649}
1650
1651/* Functions for sending ACKs and NAKs */
1652
1653/* Note, we should only ACK the packet at window-low (winlo) */
1654/* However, if an old packet arrives again (e.g. because the ACK we sent */
1655/* earlier was lost), we ACK it again. */
1656
1657int
1658ack() {                                 /* Acknowledge the current packet. */
1659    return(ackns(winlo,(CHAR *)""));
1660}
1661
1662#ifdef STREAMING
1663int
1664fastack() {                             /* Acknowledge packet n */
1665    int j, k, n, x;
1666    n = winlo;
1667
1668    k = rseqtbl[n];                     /* First find received packet n. */
1669    debug(F101,"STREAMING fastack k","",k);
1670    freesbuf(n);                        /* Free current send-buffer, if any */
1671    if ((j = getsbuf(n)) < 0) {
1672        /* This can happen if we have to re-ACK an old packet that has */
1673        /* already left the window.  It does no harm. */
1674        debug(F101,"STREAMING fastack can't getsbuf","",n);
1675    }
1676    dontsend = 1;
1677    x = spack('Y',n,0,(CHAR *)"");      /* Now send it (but not really) */
1678    dontsend = 0;
1679    if (x < 0) return(x);
1680    debug(F101,"STREAMING fastack x","",x);
1681    if (k > -1)
1682      freerbuf(k);                      /* don't need it any more */
1683    if (j > -1)
1684      freesbuf(j);                      /* and don't need to keep ACK either */
1685    winlo = (winlo + 1) % 64;
1686    return(0);
1687}
1688#endif /* STREAMING */
1689
1690int
1691ackns(n,s) int n; CHAR *s; {            /* Acknowledge packet n */
1692    int j, k, x;
1693    debug(F111,"ackns",s,n);
1694
1695    k = rseqtbl[n];                     /* First find received packet n. */
1696    debug(F101,"ackns k","",k);
1697    freesbuf(n);                        /* Free current send-buffer, if any */
1698    if ((j = getsbuf(n)) < 0) {
1699        /* This can happen if we have to re-ACK an old packet that has */
1700        /* already left the window.  It does no harm. */
1701        debug(F101,"ackns can't getsbuf","",n);
1702    }
1703    x = spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */
1704    if (x < 0) return(x);
1705    debug(F101,"ackns winlo","",winlo);
1706    debug(F101,"ackns n","",n);
1707    if (n == winlo) {                   /* If we're acking winlo */
1708        if (k > -1)
1709          freerbuf(k);                  /* don't need it any more */
1710        if (j > -1)
1711          freesbuf(j);                  /* and don't need to keep ACK either */
1712        winlo = (winlo + 1) % 64;
1713    }
1714    return(0);
1715}
1716
1717int
1718ackn(n) int n; {                        /* Send ACK for packet number n */
1719    return(ackns(n,(CHAR *)""));
1720}
1721
1722int
1723ack1(s) CHAR *s; {                      /* Send an ACK with data. */
1724    if (!s) s = (CHAR *)"";
1725    debug(F110,"ack1",(char *)s,0);
1726    return(ackns(winlo,s));
1727}
1728
1729/* N A C K  --   Send a Negative ACKnowledgment. */
1730/*
1731 Call with the packet number, n, to be NAK'd.
1732 Returns -1 if that packet has been NAK'd too many times, otherwise 0.
1733 Btw, it is not right to return 0 under error conditions.  This is
1734 done because the -1 code is used for cancelling the file transfer.
1735 More work is needed here.
1736*/
1737int
1738nack(n) int n; {
1739    int i, x;
1740
1741    if (n < 0 || n > 63) {
1742        debug(F101,"nack bad pkt num","",n);
1743        return(0);
1744    } else debug(F101,"nack","",n);
1745    if ((i = sseqtbl[n]) < 0) {         /* If necessary */
1746        if (getsbuf(n) < 0) {           /* get a buffer for this NAK */
1747            debug(F101,"nack can't getsbuf","",n);
1748            return(0);
1749        } else i = sseqtbl[n];          /* New slot number */
1750    }
1751    if (maxtry > 0 && s_pkt[i].pk_rtr++ > maxtry) /* How many? */
1752      return(-1);                       /* Too many... */
1753
1754/* Note, don't free this buffer.  Eventually an ACK will come, and that */
1755/* will set it free.  If not, well, it's back to ground zero anyway...  */
1756
1757    x = spack('N',n,0,(CHAR *) "");     /* NAKs never have data. */
1758    return(x);
1759}
1760
1761#ifndef NEWDPL                          /* This routine no longer used */
1762/*
1763 * (PWP) recalculate the optimal packet length in the face of errors.
1764 * This is a modified version of the algorithm by John Chandler in Kermit/370,
1765 * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988.
1766 *
1767 * This implementation minimizes the total overhead equation, which is
1768 *
1769 *   Total chars = file_chars + (header_len * num_packs)
1770 *                            + (errors * (header_len + packet_len))
1771 *
1772 * Differentiate with respect to number of chars, solve for packet_len, get:
1773 *
1774 *   packet_len = sqrt (file_chars * header_len / errors)
1775 */
1776
1777/*
1778 (FDC) New super-simple algorithm.  If there was an error in the most recent
1779 packet exchange, cut the send-packet size in half, down to a minimum of 20.
1780 If there was no error, increase the size by 5/4, up to the maximum negotiated
1781 length.  Seems to be much more responsive than previous algorithm, which took
1782 forever to recover the original packet length, and it also went crazy under
1783 certain conditions.
1784
1785 Here's another idea for packet length resizing that keeps a history of the
1786 last n packets.  Push a 1 into the left end of an n-bit shift register if the
1787 current packet is good, otherwise push a zero.  The current n-bit value, w, of
1788 this register is a weighted sum of the noise hits for the last n packets, with
1789 the most recent weighing the most.  The current packet length is some function
1790 of w and the negotiated packet length, like:
1791
1792   (2^n - w) / (2^n) * (negotiated length)
1793
1794 If the present resizing method causes problems, think about this one a little
1795 more.
1796*/
1797VOID
1798rcalcpsz() {
1799
1800#ifdef COMMENT
1801/* Old way */
1802    register long x, q;
1803    if (numerrs == 0) return;           /* bounds check just in case */
1804
1805    /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */
1806    /* an ACK is 5+bctr */
1807
1808    /* first set x = per packet overhead */
1809    if (wslots > 1)                     /* Sliding windows */
1810      x = (long) (npad+5+bctr);         /* packet only, don't count ack */
1811    else                                /* Stop-n-wait */
1812      x = (long) (npad+5+3+bctr+5+bctr); /* count packet and ack. */
1813
1814    /* then set x = packet length ** 2 */
1815    x = x * ( ffc / (long) numerrs);    /* careful of overflow */
1816
1817    /* calculate the long integer sqrt(x) quickly */
1818    q = 500;
1819    q = (q + x/q) >> 1;
1820    q = (q + x/q) >> 1;
1821    q = (q + x/q) >> 1;
1822    q = (q + x/q) >> 1;         /* should converge in about 4 steps */
1823    if ((q > 94) && (q < 130))  /* break-even point for long packets */
1824      q = 94;
1825    if (q > spmax) q = spmax;   /* maximum bounds */
1826    if (q < 10) q = 10;         /* minimum bounds */
1827    spsiz = q;                  /* set new send packet size */
1828    debug(F101,"rcalcpsiz","",q);
1829#else
1830/* New way */
1831    debug(F101,"rcalcpsiz numerrs","",numerrs);
1832    debug(F101,"rcalcpsiz spsiz","",spsiz);
1833    if (spackets < 3) {
1834        numerrs = 0;
1835        return;
1836    }
1837    if (numerrs)
1838      spsiz = spsiz / 2;
1839    else
1840      spsiz = (spsiz / 4) * 5;
1841    if (spsiz < 20) spsiz = 20;
1842    if (spsiz > spmax) spsiz = spmax;
1843    debug(F101,"rcalcpsiz new spsiz","",spsiz);
1844    numerrs = 0;
1845#endif /* COMMENT */
1846}
1847#endif /* NEWDPL */
1848
1849/*  R E S E N D  --  Retransmit packet n.  */
1850
1851/*
1852  Returns 0 or positive on success (the number of retries for packet n).
1853  On failure, returns a negative number, and an error message is placed
1854  in recpkt.
1855*/
1856int
1857resend(n) int n; {                      /* Send packet n again. */
1858    int j, k, x;
1859#ifdef GFTIMER
1860    CKFLOAT t1 = 0.0, t2 = 0.0;
1861#endif /* GFTIMER */
1862
1863    debug(F101,"resend seq","",n);
1864
1865    k = chkwin(n,winlo,wslots);         /* See if packet in current window */
1866    j = -1;                             /* Assume it's lost */
1867    if (k == 0) j = sseqtbl[n];         /* See if we still have a copy of it */
1868    if (k != 0 || j < 0) {              /* If not.... */
1869        if (nakstate && k == 1) {
1870/*
1871  Packet n is in the previous window and we are the file receiver.
1872  We already sent the ACK and deallocated its buffer so we can't just
1873  retransmit the ACK.  Rather than give up, we try some tricks...
1874*/
1875            if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */
1876/*
1877  If the packet number is 0, and we're at the beginning of a protocol
1878  operation (spackets < 63), then we have to resend the ACK to an I or S
1879  packet, complete with parameters in the data field.  So we take a chance and
1880  send a copy of the parameters in an ACK packet with block check type 1.
1881*/
1882                int bctlsav;            /* Temporary storage */
1883                int bctusav;
1884                bctlsav = bctl;         /* Save current block check length */
1885                bctusav = bctu;         /* and type */
1886                bctu = bctl = 1;        /* Set block check to 1 */
1887                x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
1888                if (x < 0) return(x);
1889                logpkt('#',n,(CHAR *)"<reconstructed>",0); /* Log it */
1890                bctu = bctusav;         /* Restore block check type */
1891                bctl = bctlsav;         /* and length */
1892
1893            } else {                    /* Not the first packet */
1894/*
1895  It's not the first packet of the protocol operation.  It's some other packet
1896  that we have already ACK'd and forgotten about.  So we take a chance and
1897  send an empty ACK using the current block-check type.  Usually this will
1898  work out OK (like when acking Data packets), and no great harm will be done
1899  if it was some other kind of packet (F, etc).  If we are requesting an
1900  interruption of the file transfer, the flags are still set, so we'll catch
1901  up on the next packet.
1902*/
1903                x = spack('Y',n,0,(CHAR *) "");
1904                if (x < 0) return(x);
1905            }
1906            retrans++;
1907            xxscreen(SCR_PT,'%',(long)pktnum,"Retransmission");
1908            return(0);
1909        } else {
1910/*
1911  Packet number is not in current or previous window.  We seem to hit this
1912  code occasionally at the beginning of a transaction, for apparently no good
1913  reason.  Let's just log it for debugging, send nothing, and try to proceed
1914  with the protocol rather than killing it.
1915*/
1916            debug(F101,"resend PKT NOT IN WINDOW","",n);
1917            debug(F101,"resend k","",k);
1918            return(0);
1919        }
1920    }
1921
1922/* OK, it's in the window and it's not lost. */
1923
1924    debug(F101,"resend pktinfo index","",k);
1925
1926    if (maxtry > 0 && s_pkt[j].pk_rtr++ > maxtry) { /* Over retry limit */
1927        xitsta |= what;
1928        return(-1);
1929    }
1930    debug(F101,"resend retry","",s_pkt[j].pk_rtr); /* OK so far */
1931    dumpsbuf();                         /* (debugging) */
1932    if (s_pkt[j].pk_typ == ' ') {       /* Incompletely formed packet */
1933        if (nakstate) {                 /* (This shouldn't happen any more) */
1934            nack(n);
1935            retrans++;
1936            xxscreen(SCR_PT,'%',(long)pktnum,"(resend)");
1937            return(s_pkt[j].pk_rtr);
1938        } else {                        /* No packet to resend! */
1939#ifdef COMMENT
1940/*
1941  This happened (once) while sending a file with 2 window slots and typing
1942  X to the sender to cancel the file.  But since we're cancelling anyway,
1943  there's no need to give a scary message.
1944*/
1945            sprintf((char *)epktmsg,
1946                    "resend logic error: NPS, n=%d, j=%d.",n,j);
1947            return(-2);
1948#else
1949/* Just ignore it. */
1950            return(0);
1951#endif /* COMMENT */
1952        }
1953    }
1954#ifdef DEBUG
1955#ifdef GFTIMER
1956    if (deblog) t1 = gftimer();
1957#endif /* GFTIMER */
1958#endif /* DEBUG */
1959
1960    /* Everything ok, send the packet */
1961#ifdef CK_TIMERS
1962    if (timint > 0)
1963      srttbl[n] = gtimer();             /* Update the timer */
1964#endif /* CK_TIMERS */
1965    x = ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len);
1966
1967#ifdef DEBUG
1968#ifdef GFTIMER
1969    if (deblog)  {
1970        t2 = gftimer();
1971        debug(F101,"resend ttol msec","",(long)((t2-t1)*1000.0));
1972    }
1973#endif /* GFTIMER */
1974#endif /* DEBUG */
1975    debug(F101,"resend ttol returns","",x);
1976
1977    retrans++;                          /* Count a retransmission */
1978    xxscreen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */
1979    logpkt('S',n,s_pkt[j].pk_adr, s_pkt[j].pk_len); /* Log the resent packet */
1980    return(s_pkt[j].pk_rtr);            /* Return the number of retries. */
1981}
1982
1983/*  E R R P K T  --  Send an Error Packet  */
1984
1985int
1986errpkt(reason) CHAR *reason; {          /* ...containing the reason given */
1987    extern int rtimo, state, justone;
1988    int x, y;
1989    czseen = 1;                         /* Also cancels batch */
1990    state = 0;                          /* Reset protocol state */
1991    debug(F110,"errpkt",reason,0);
1992    tlog(F110,"Protocol Error:",(char *)reason,0L);
1993    xxscreen(SCR_EM,0,0L,reason);
1994    encstr(reason);
1995    x = spack('E',pktnum,size,data);
1996    ckstrncpy((char *)epktmsg,(char *)reason,PKTMSGLEN);
1997    y = quiet; quiet = 1; epktsent = 1; /* Close files silently. */
1998    clsif(); clsof(1);
1999    quiet = y;
2000/*
2001  I just sent an E-packet.  I'm in local mode, I was receiving a file,
2002  I'm not a server, and sliding windows are in use.  Therefore, there are
2003  likely to be a bunch of packets already "in the pipe" on their way to me
2004  by the time the remote sender gets the E-packet.  So the next time I
2005  CONNECT or try to start another protocol operation, I am likely to become
2006  terribly confused by torrents of incoming material.  To prevent this,
2007  the following code soaks up packets from the connection until there is an
2008  error or timeout, without wasting too much time waiting.
2009
2010  Exactly the same problem occurs when I am in remote mode or if I am
2011  in server mode with the justone flag set.  In remote mode not only
2012  does the packet data potentially get echo'd back to the sender which
2013  is confusing to the user in CONNECT mode, but it also may result in the
2014  host performing bizarre actions such as suspending the process if ^Z is
2015  unprefixed, etc.
2016
2017  Furthermore, thousands of packets bytes in the data stream prevent the
2018  client from being able to process Telnet Kermit Option negotiations
2019  properly.
2020*/
2021#ifdef STREAMING
2022    /* Because streaming sets the timeout to 0... */
2023    if (streaming) {
2024        timint = rcvtimo = rtimo;
2025        streaming = 0;
2026    }
2027#endif /* STREAMING */
2028    if (what & W_RECV &&
2029        (!server || (server && justone)) &&
2030        (wslots > 1
2031#ifdef STREAMING
2032         || streaming
2033#endif /* STREAMING */
2034         )) {
2035#ifdef GFTIMER
2036        CKFLOAT oldsec, sec = (CKFLOAT) 0.0;
2037#else
2038        int oldsec, sec = 0;
2039#endif /* GFTIMER */
2040        debug(F101,"errpkt draining","",wslots);
2041        xxscreen(SCR_ST,ST_MSG,0l,"Draining incoming packets, wait...");
2042        while (x > -1) {                /* Don't bother if no connection */
2043            oldsec = sec;
2044#ifdef GFTIMER
2045            sec = gftimer();
2046            if (oldsec != (CKFLOAT) 0.0)
2047              timint = rcvtimo = (int) (sec - oldsec + 0.5);
2048#else
2049            sec = gtimer();
2050            if (oldsec != 0)
2051              timint = rcvtimo = sec - oldsec + 1;
2052#endif /* GFTIMER */
2053            if (timint < 1)
2054              timint = rcvtimo = 1;
2055            msleep(50);                 /* Allow a bit of slop */
2056            x = rpack();                /* Read a packet */
2057            if (x == 'T' || x == 'z')   /* Timed out means we're done */
2058              break;
2059            xxscreen(SCR_PT,x,rsn,"");  /* Let user know */
2060        }
2061        xxscreen(SCR_ST,ST_MSG,0l,"Drain complete.");
2062    }
2063    if ((x = (what & W_KERMIT)))
2064      xitsta |= x;                      /* Remember what failed. */
2065    success = 0;
2066    return(y);
2067}
2068
2069/* scmd()  --  Send a packet of the given type */
2070
2071int
2072#ifdef CK_ANSIC
2073scmd(char t, CHAR *dat)
2074#else
2075scmd(t,dat) char t; CHAR *dat;
2076#endif /* CK_ANSIC */
2077/* scmd */ {
2078    int x;
2079    extern char * srimsg;
2080    debug(F000,"scmd",dat,t);
2081    if (encstr(dat) < 0) {              /* Encode the command string */
2082        srimsg = "String too long";
2083        return(-1);
2084    }
2085    x = spack(t,pktnum,size,data);
2086    debug(F101,"scmd spack","",x);
2087    return(x);
2088}
2089
2090/* Compose and Send GET packet */
2091
2092struct opktparm {                       /* O-Packet item list */
2093    CHAR * opktitem;
2094    struct opktparm * opktnext;
2095};
2096
2097struct opktparm * opkthead = NULL;      /* Linked list of O-packet fields */
2098int opktcnt = 0;                        /* O-Packet counter */
2099char * srimsg = NULL;                   /* GET-Packet error message */
2100
2101/* S O P K T  --  Send O-Packet */
2102/*
2103  Sends one O-Packet each time called, using first-fit method of filling
2104  the packet from linked list of parameters pointed to by opkthead.
2105  To be called repeatedly until list is empty or there is an error.
2106  Returns:
2107   -1 on failure.
2108    0 on success and no more fields left to send.
2109    1 on success but with more fields left to be sent.
2110*/
2111
2112int
2113sopkt() {
2114    int n = 0;                          /* Field number in this packet */
2115    int rc = 0;                         /* Return code */
2116    int len = 0;                        /* Data field length */
2117    char c = NUL;
2118    struct opktparm * o = NULL;
2119    struct opktparm * t = NULL;
2120    struct opktparm * prev = NULL;
2121    CHAR * dsave = data;
2122    int x, ssave = spsiz;
2123
2124    srimsg = NULL;                      /* Error message */
2125    o = opkthead;                       /* Point to head of list */
2126    if (!o) {                           /* Oops, no list... */
2127        srimsg = "GET Packet Internal Error 1";
2128        debug(F100,"sopkt NULL list","",0);
2129        return(-1);
2130    }
2131    while (o) {                         /* Go thru linked list... */
2132        c = *(o->opktitem);             /* Parameter code */
2133        debug(F000,"sopkt",o->opktitem,c);
2134        x = encstr((CHAR *)o->opktitem);
2135        debug(F111,"sopkt encstr",dsave,x);
2136        if (x < 0) {                    /* Encode this item */
2137            if (n == 0) {               /* Failure, first field in packet */
2138                debug(F100,"sopkt overflow","",0);
2139                spsiz = ssave;          /* Restore these */
2140                data = dsave;
2141                o = opkthead;           /* Free linked list */
2142                while (o) {
2143                    if (o->opktitem) free(o->opktitem);
2144                    t = o->opktnext;
2145                    free((char *)o);
2146                    o = t;
2147                }
2148                opkthead = NULL;
2149                srimsg = "GET Packet Too Long for Server";
2150                return(-1);             /* Fail */
2151            } else {                    /* Not first field in packet */
2152                debug(F110,"sopkt leftover",o->opktitem,0);
2153                prev = o;               /* Make this one the new previous */
2154                o = o->opktnext;        /* Get next */
2155                c = NUL;                /* So we know we're not done */
2156                *data = NUL;            /* Erase any partial encoding */
2157                continue;               /* We can try this one again later */
2158            }
2159        }
2160        n++;                            /* Encoding was successful */
2161        debug(F111,"sopkt field",data,x);
2162        len += x;                       /* Total data field length */
2163        data += x;                      /* Set up for next field... */
2164        spsiz -= x;
2165        free(o->opktitem);              /* Free item just encoded */
2166        if (o == opkthead) {            /* If head */
2167            opkthead = o->opktnext;     /* Move head to next */
2168            free((char *)o);            /* Free this list node */
2169            o = opkthead;
2170        } else {                        /* If not head */
2171            o = o->opktnext;            /* Get next */
2172            prev->opktnext = o;         /* Link previous to next */
2173        }
2174        if (c == '@')                   /* Loop exit */
2175          break;
2176        if (!o && !opkthead) {          /* Set up End Of Parameters Field */
2177            o = (struct opktparm *)malloc(sizeof(struct opktparm));
2178            if (o) {
2179                opkthead = o;
2180                if (!(o->opktitem = (CHAR *)malloc(3))) {
2181                    free((char *)o);
2182                    srimsg = "GET Packet Internal Error 8";
2183                    return(-1);
2184                }
2185                ckstrncpy((char *)(o->opktitem), "@ ", 3);
2186                debug(F111,"sopkt o->opktitem",o->opktitem,
2187                      strlen((char *)(o->opktitem)));
2188                o->opktnext = NULL;
2189            }
2190        }
2191    }
2192    data = dsave;                       /* Restore globals */
2193    spsiz = ssave;
2194    debug(F110,"sopkt data",data,0);
2195    debug(F101,"sopkt opktcnt","",opktcnt);
2196    if (opktcnt++ > 0) {
2197        if (nxtpkt() < 0) {             /* Get next packet number and buffer */
2198            srimsg = "GET Packet Internal Error 9";
2199            return(-1);
2200        }
2201    }
2202    debug(F101,"sopkt pktnum","",pktnum);
2203    rc = spack((char)'O',pktnum,len,data); /* Send O-Packet */
2204    debug(F101,"sopkt spack","",rc);
2205    if (rc < 0)                         /* Failed */
2206      srimsg = "Send Packet Failure";   /* Set message */
2207    else                                /* Succeeded */
2208      rc = (c == '@') ? 0 : 1;          /* 1 = come back for more, 0 = done */
2209    debug(F101,"sopkt rc","",rc);
2210    return(rc);
2211}
2212
2213/* S R I N I T  --  Send GET packet  */
2214/*
2215  Sends the appropriate GET-Class packet.
2216  Returns:
2217  -1 on error
2218   0 if packet sent successfully and we can move on to the next state
2219   1 if an O-packet was sent OK but more O packets still need to be sent.
2220*/
2221int
2222srinit(reget, retrieve, opkt) int reget, retrieve, opkt; {
2223    int x = 0, left = 0;
2224    extern int oopts, omode;
2225    CHAR * p = NULL;
2226#ifdef RECURSIVE
2227    extern int recursive;
2228    debug(F101,"srinit recursive","",recursive);
2229#endif /* RECURSIVE */
2230    debug(F101,"srinit reget","",reget);
2231    debug(F101,"srinit retrieve","",retrieve);
2232    debug(F101,"srinit opkt","",opkt);
2233    debug(F101,"srinit oopts","",oopts);
2234    debug(F101,"srinit omode","",omode);
2235    debug(F110,"srinit cmarg",cmarg,0);
2236    srimsg = NULL;
2237
2238    opktcnt = 0;
2239    if (!cmarg) cmarg = "";
2240    if (!*cmarg) {
2241        srimsg = "GET with no filename";
2242        debug(F100,"srinit null cmarg","",0);
2243        return(-1);
2244    }
2245    if (opkt) {                         /* Extended GET is totally different */
2246        char buf[16];
2247        struct opktparm * o = NULL;
2248        struct opktparm * prev = NULL;
2249
2250        buf[0] = NUL;
2251
2252        /* Build O-Packet fields and send (perhaps first) O-Packet */
2253
2254        if (oopts > -1) {               /* Write Option flags */
2255            o = (struct opktparm *)malloc(sizeof(struct opktparm));
2256            if (!o) {
2257                srimsg = "GET Packet Internal Error 2";
2258                debug(F100,"srinit malloc fail O1","",0);
2259                return(-1);
2260            }
2261            sprintf(buf,"Ox%d",oopts);  /* safe */
2262            x = (int) strlen(buf+2);
2263            buf[1] = tochar(x);
2264            o->opktitem = (CHAR *)malloc(x + 3);
2265            if (!o->opktitem) {
2266                srimsg = "GET Packet Internal Error 3";
2267                debug(F100,"srinit malloc fail O2","",0);
2268                return(-1);
2269            }
2270            ckstrncpy((char *)(o->opktitem),buf,x+3);
2271            o->opktnext = NULL;
2272            if (!opkthead)
2273              opkthead = o;
2274            prev = o;
2275        }
2276        if (omode > -1) {               /* If Xfer Mode specified, write it */
2277            o = (struct opktparm *)malloc(sizeof(struct opktparm));
2278            if (!o) {
2279                srimsg = "GET Packet Internal Error 4";
2280                debug(F100,"srinit malloc fail M1","",0);
2281                return(-1);
2282            }
2283            sprintf(buf,"Mx%d",omode);  /* safe */
2284            x = (int) strlen(buf+2);
2285            buf[1] = tochar(x);
2286            o->opktitem = (CHAR *)malloc(x + 3);
2287            if (!o->opktitem) {
2288                srimsg = "GET Packet Internal Error 5";
2289                debug(F100,"srinit malloc fail O2","",0);
2290                return(-1);
2291            }
2292            ckstrncpy((char *)(o->opktitem),buf,x+3);
2293            o->opktnext = NULL;
2294            if (!opkthead)
2295              opkthead = o;
2296            else
2297              prev->opktnext = o;
2298            prev = o;
2299        }
2300
2301        /* Same deal for oname and opath eventually but not needed now... */
2302
2303        x = strlen(cmarg);              /* Now do filename */
2304        if (x > spsiz - 4) {
2305            srimsg = "GET Packet Too Long for Server";
2306            return(-1);
2307        }
2308        o = (struct opktparm *)malloc(sizeof(struct opktparm));
2309        if (!o) {
2310            srimsg = "GET Packet Internal Error 6";
2311            debug(F100,"srinit malloc fail F1","",0);
2312            return(-1);
2313        }
2314        left = x + 6;
2315        o->opktitem = (CHAR *)malloc(left + 1);
2316        if (!o->opktitem) {
2317            srimsg = "GET Packet Internal Error 7";
2318            debug(F100,"srinit malloc fail F2","",0);
2319            return(-1);
2320        }
2321        p = o->opktitem;
2322        *p++ = 'F';
2323        left--;
2324        if (x > 94) {                   /* Too long for normal length */
2325            *p++ = SYN;                 /* Escape length with Ctrl-V */
2326            *p++ = tochar(x / 95);
2327            *p++ = tochar(x % 95);
2328            left -= 3;
2329        } else {                        /* Normal encoding for 94 or less */
2330            *p++ = tochar(x);
2331            left--;
2332        }
2333        ckstrncpy((char *)p,cmarg,left); /* Copy the filename */
2334        o->opktnext = NULL;
2335        if (!opkthead)
2336          opkthead = o;
2337        else
2338          prev->opktnext = o;
2339        prev = o;
2340
2341        /* End of Parameters */
2342
2343        prev->opktnext = NULL;          /* End of list. */
2344        return(sopkt());
2345    }
2346
2347    /* Not Extended GET */
2348
2349    if (encstr((CHAR *)cmarg) < 0) {    /* Encode the filename. */
2350        srimsg = "GET Packet Too Long for Server";
2351        return(-1);
2352    }
2353    if (retrieve) {                     /* Send the packet. */
2354#ifdef RECURSIVE
2355        if (recursive)
2356          x = spack((char)'W',pktnum,size,data); /* GET /DELETE /RECURSIVE */
2357        else
2358#endif /* RECURSIVE */
2359          x = spack((char)'H',pktnum,size,data); /* GET /DELETE */
2360    }
2361#ifdef RECURSIVE
2362    else if (recursive)
2363      x = spack((char)'V',pktnum,size,data); /* GET /RECURSIVE */
2364#endif /* RECURSIVE */
2365    else
2366      x = spack((char)(reget ? 'J' : 'R'),pktnum,size,data); /* GET */
2367    if (x < 0)
2368      srimsg = "Send Packet Failure";
2369    return(x < 0 ? x : 0);
2370}
2371
2372
2373/*  K S T A R T  --  Checks for a Kermit packet while in terminal mode.  */
2374
2375/*  (or command mode...)  */
2376
2377#ifdef CK_AUTODL
2378int
2379#ifdef CK_ANSIC
2380kstart(CHAR ch)
2381#else
2382kstart(ch) CHAR ch;
2383#endif /* CK_ANSIC */
2384/* kstart */ {
2385    static CHAR * p = NULL;
2386
2387#ifdef OS2
2388    static CHAR * pk = NULL;
2389#endif /* OS2 */
2390    ch &= 0177;                         /* Strip 8th bit */
2391
2392    /* Because we're in cooked mode at the command prompt... */
2393
2394    if (ch == LF) {
2395        debug(F110,"kstart","ch == LF",0);
2396        if ((what == W_COMMAND || what == W_INIT || what == W_NOTHING)) {
2397            if (eol == CR) {
2398                ch = eol;
2399                debug(F110,"kstart","ch = CR",0);
2400            }
2401        }
2402    }
2403
2404#ifdef OS2
2405    if (adl_kmode == ADL_STR) {
2406        if (!ch)
2407          return(0);
2408        if (!pk)
2409          pk = adl_kstr;
2410
2411        if (ch == *pk) {
2412            pk++;
2413            if (*pk == '\0') {
2414                pk = adl_kstr;
2415                debug(F100, "kstart Kermit Start String","",0);
2416                return(PROTO_K + 1);
2417            }
2418        } else
2419          pk = adl_kstr;
2420    }
2421#endif /* OS2 */
2422
2423    if (ch == stchr) {                  /* Start of packet */
2424        kstartactive = 1;
2425        p = ksbuf;
2426        *p = ch;
2427        debug(F101,"kstart SOP","",ch);
2428    } else if (ch == eol) {             /* End of packet */
2429        kstartactive = 0;
2430        if (p) {
2431            debug(F101,"kstart EOL","",ch);
2432            p++;
2433            if (p - ksbuf < 94 ) {
2434                int rc = 0;
2435                *p++ = ch;
2436                *p = NUL;
2437                rc = chkspkt((char *)ksbuf);
2438                debug(F111,"kstart EOP chkspkt", ksbuf, rc);
2439                p = NULL;
2440                if (!rc) return(0);
2441                if (rc == 2) rc = -1;
2442                debug(F111,"kstart ksbuf",ksbuf,rc);
2443                return(rc);
2444            } else {
2445                debug(F110,"kstart","p - ksbuf >= 94",0);
2446                p = NULL;
2447            }
2448        }
2449    } else if (p) {
2450        if (ch < SP)
2451          kstartactive = 0;
2452        p++;
2453        if (p - ksbuf < 94) {
2454            *p = ch;
2455        } else {
2456            p = NULL;
2457            debug(F110,"kstart","p - ksbuf >= 94",0);
2458        }
2459    }
2460    return(0);
2461}
2462
2463#ifdef CK_XYZ
2464
2465/*  Z S T A R T  --  Checks for a ZMODEM packet while in terminal mode.  */
2466
2467int
2468#ifdef CK_ANSIC
2469zstart(CHAR ch)
2470#else
2471zstart(ch) CHAR ch;
2472#endif /* CK_ANSIC */
2473/* zstart */ {
2474    static CHAR * matchstr = (CHAR *) "\030B00";
2475    /* "rz\r**\030B00000000000000\r\033J\021"; */
2476    static CHAR * p = NULL;
2477    extern int inserver;
2478
2479    if (inserver)
2480      return(0);
2481
2482    if (!ch)
2483      return(0);
2484    if (!p) {
2485#ifdef OS2
2486        p = adl_zmode == ADL_PACK ? matchstr : adl_zstr;
2487#else
2488        p = matchstr;
2489#endif /* OS2 */
2490    }
2491    if (ch == *p) {
2492        p++;
2493        if (*p == '\0') {
2494#ifdef OS2
2495            if (adl_zmode == ADL_PACK) {
2496                p = matchstr;
2497                debug(F100, "zstart Zmodem SOP","",0);
2498            } else {
2499                p = adl_zstr;
2500                debug(F100, "zstart Zmodem Start String","",0);
2501            }
2502#else
2503            p = matchstr;
2504            debug(F100, "zstart Zmodem SOP","",0);
2505#endif /* OS2 */
2506            return(PROTO_Z + 1);
2507        }
2508    } else {
2509#ifdef OS2
2510        p = adl_zmode == ADL_PACK ? matchstr : adl_zstr;
2511#else
2512        p = matchstr;
2513#endif /* OS2 */
2514    }
2515    return(0);
2516}
2517#endif /* CK_XYZ */
2518
2519#ifndef NOICP
2520#ifdef CK_APC
2521/*  A U T O D O W N  */
2522
2523#ifdef CK_ANSIC
2524VOID
2525autodown(int ch)
2526#else
2527VOID
2528autodown(ch) int ch;
2529#endif /* CK_ANSIC */
2530/* autodown */ {
2531
2532/* The Kermit and Zmodem Auto-download calls go here */
2533
2534    extern int justone;                 /* From protocol module */
2535    extern int debses, protocol, apcactive, autodl, inautodl;
2536#ifdef DCMDBUF
2537    extern char *apcbuf;
2538#else
2539    extern char apcbuf[];
2540#endif /* DCMDBUF */
2541#ifdef OS2
2542    extern int apclength, term_io;
2543#endif /* OS2 */
2544    int k = 0;
2545
2546    if ((autodl || inautodl
2547#ifdef IKS_OPTION
2548         || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
2549#endif /* IKS_OPTION */
2550         ) && !debses) {
2551#ifdef CK_XYZ
2552#ifdef XYZ_INTERNAL
2553        extern int p_avail;
2554#else
2555        int p_avail = 1;
2556#endif /* XYZ_INTERNAL */
2557        if (p_avail && zstart((CHAR) ch)) {
2558            debug(F100, "Zmodem download","",0);
2559#ifdef OS2
2560#ifndef NOTERM
2561            apc_command(APC_LOCAL,"receive /protocol:zmodem");
2562#endif /* NOTERM */
2563#else /* OS2 */
2564            ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN);
2565            apcactive = APC_LOCAL;
2566#endif /* OS2 */
2567            return;
2568        }
2569#endif /* CK_XYZ */
2570
2571        /* First try... */
2572        k = kstart((CHAR) ch);
2573        if (
2574#ifdef NOSERVER
2575            k > 0
2576#else /* NOSERVER */
2577            k
2578#endif /* NOSERVER */
2579            ) {                         /* We saw a valid S or I packet */
2580            if (k < 0) {                /* Stuff RECEIVE into APC buffer */
2581                justone = 1;
2582                switch (protocol) {
2583#ifdef CK_XYZ
2584                  case PROTO_G:
2585                    ckstrncpy(apcbuf,
2586                              "set proto kermit, server, set protocol g",
2587                              APCBUFLEN
2588                              );
2589                    break;
2590                  case PROTO_X:
2591                    ckstrncpy(apcbuf,
2592                              "set proto kermit,server,set proto xmodem",
2593                              APCBUFLEN
2594                              );
2595                    break;
2596                  case PROTO_XC:
2597                    ckstrncpy(apcbuf,
2598                           "set proto kermit,server,set proto xmodem-crc",
2599                              APCBUFLEN
2600                              );
2601                      break;
2602                  case PROTO_Y:
2603                    ckstrncpy(apcbuf,
2604                              "set proto kermit,server, set protocol y",
2605                              APCBUFLEN
2606                              );
2607                    break;
2608                  case PROTO_Z:
2609                    ckstrncpy(apcbuf,
2610                              "set proto kermit,server,set proto zmodem",
2611                              APCBUFLEN
2612                              );
2613                    break;
2614#endif /* CK_XYZ */
2615                  case PROTO_K:
2616                    ckstrncpy(apcbuf,"server",APCBUFLEN);
2617                    break;
2618                }
2619            } else {
2620                justone = 0;
2621                ckstrncpy(apcbuf,"receive /protocol:kermit",APCBUFLEN);
2622            }
2623#ifdef OS2
2624#ifndef NOTERM
2625            apc_command(APC_LOCAL,apcbuf);
2626#endif /* NOTERM */
2627#else /* OS2 */
2628            ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN);
2629            apcactive = APC_LOCAL;
2630#endif /* OS2 */
2631            return;
2632        }
2633    }
2634}
2635#endif /* CK_APC */
2636#endif /* NOICP */
2637
2638/*  C H K S P K T  --  Check if buf contains a valid S or I packet  */
2639
2640int
2641chkspkt(buf) char *buf; {
2642    int buflen;
2643    int len = -1;
2644    CHAR chk;
2645    char type = 0;
2646    char *s = buf;
2647
2648    if (!buf) return(0);
2649    buflen = strlen(buf);
2650    if (buflen < 5) return(0);          /* Too short */
2651    if (*s++ != stchr) return(0);       /* SOH */
2652    len = xunchar(*s++);                /* Length */
2653    if (len < 0) return(0);
2654    if (*s++ != SP) return(0);          /* Sequence number */
2655    type = *s++;                        /* Type */
2656    if (type != 'S' && type != 'I')
2657      return(0);
2658    if (buflen < len + 2) return(0);
2659    s += (len - 3);                     /* Position of checksum */
2660    chk = (CHAR) (*s);                  /* Checksum */
2661    *s = NUL;
2662    if (xunchar(chk) != chk1((CHAR *)(buf+1),buflen-2)) /* Check it */
2663      return(0);
2664    *s = chk;
2665    return(type == 'S' ? 1 : 2);
2666}
2667#endif /* CK_AUTODL */
2668
2669/* R P A C K  --  Read a Packet */
2670
2671/*
2672  rpack reads a packet and returns the packet type, or else Q if the
2673  packet was invalid, or T if a timeout occurred.  Upon successful return,
2674  sets the values of global rsn (received sequence number),  rln (received
2675  data length), and rdatap (pointer to null-terminated data field), and
2676  returns the packet type.  NOTE: This is an inner-loop function so must be
2677  efficient.  Protect function calls by if-tests where possible, e.g.
2678  "if (pktlog) logpkt(...);".
2679*/
2680int
2681rpack() {
2682    register int i, j, x, lp;           /* Local variables */
2683#ifdef CKTUNING
2684    unsigned int chk;
2685#endif /* CKTUNING */
2686    int k, type, chklen;
2687    unsigned crc;
2688    CHAR pbc[5];                        /* Packet block check */
2689    CHAR *sohp;                         /* Pointer to SOH */
2690    CHAR e;                             /* Packet end character */
2691
2692#ifdef GFTIMER
2693    CKFLOAT t1 = 0.0, t2 = 0.0;
2694#endif /* GFTIMER */
2695
2696    debug(F101,"rpack pktnum","",pktnum);
2697
2698#ifndef OLDCHKINT
2699    if (chkint() < 0)                   /* Check for console interrupts. */
2700      return('z');
2701#endif /* OLDCHKINT */
2702
2703    k = getrbuf();                      /* Get a new packet input buffer. */
2704    debug(F101,"rpack getrbuf","",k);
2705    if (k < 0) {                        /* Return like this if none free. */
2706        return(-1);
2707    }
2708    recpkt = r_pkt[k].bf_adr;
2709    *recpkt = '\0';                     /* Clear receive buffer. */
2710    sohp = recpkt;                      /* Initialize pointers to it. */
2711    rdatap = recpkt;
2712    rsn = rln = -1;                     /* In case of failure. */
2713    e = (turn) ? turnch : eol;          /* Use any handshake char for eol */
2714
2715/* Try to get a "line". */
2716
2717#ifdef CK_AUTODL
2718    debug(F110,"rpack ksbuf",ksbuf,0);
2719    if (ksbuf[0]) {                     /* Kermit packet already */
2720        int x;                          /* collected for us in CONNECT mode */
2721        CHAR *s1 = recpkt, *s2 = ksbuf;
2722        j = 0;
2723        while (*s2) {                   /* Copy and get length */
2724            *s1++ = *s2++;              /* No point optimizing this since */
2725            j++;                        /* it's never more than ~20 chars */
2726        }
2727        *s1 = NUL;
2728#ifdef PARSENSE
2729        x = parchk(recpkt, stchr, j);   /* Check parity */
2730        debug(F000,"autodownload parity","",parity);
2731        debug(F000,"autodownload parchk","",x);
2732        if (x > -1 && parity != x) {
2733            autopar = 1;
2734            parity = x;
2735        }
2736#endif /* PARSENSE */
2737        ksbuf[0] = NUL;                 /* Don't do this next time! */
2738
2739    } else {                            /* Normally go read a packet */
2740#endif /* CK_AUTODL */
2741
2742#ifdef DEBUG
2743        if (deblog) {
2744            debug(F101,"rpack timint","",timint);
2745            debug(F101,"rpack rcvtimo","",rcvtimo);
2746#ifdef STREAMING
2747            debug(F101,"rpack streaming","",streaming);
2748#endif /* STREAMING */
2749#ifdef GFTIMER
2750            /* Measure how long it takes to read a packet */
2751            t1 = gftimer();
2752#endif /* GFTIMER */
2753        }
2754#endif /* DEBUG */
2755
2756/* JUST IN CASE (otherwise this could clobber streaming) */
2757
2758        if ((timint == 0
2759#ifdef STREAMING
2760             || streaming
2761#endif /* STREAMING */
2762             ) && (rcvtimo != 0)) {
2763            debug(F101,"rpack timint 0 || streaming but rcvtimo","",rcvtimo);
2764            rcvtimo = 0;
2765        }
2766
2767#ifdef PARSENSE
2768#ifdef UNIX
2769/*
2770  So far the final turn argument is only for ck[uvdl]tio.c.  Should be added
2771  to the others too.  (turn == handshake character.)
2772*/
2773        j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2774#else
2775#ifdef VMS
2776        j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2777#else
2778#ifdef datageneral
2779        j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2780#else
2781#ifdef STRATUS
2782        j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2783#else
2784#ifdef OS2
2785        j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2786#else
2787#ifdef OSK
2788        j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2789#else
2790        j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr);
2791#endif /* OSK */
2792#endif /* OS2 */
2793#endif /* STRATUS */
2794#endif /* datageneral */
2795#endif /* VMS */
2796#endif /* UNIX */
2797        if (parity != 0 && parity != 's' && ttprty != 0) {
2798            if (parity != ttprty) autopar = 1;
2799            parity = ttprty;
2800        }
2801#else /* !PARSENSE */
2802        j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e);
2803#endif /* PARSENSE */
2804
2805#ifdef DEBUG
2806        if (deblog)  {
2807            debug(F101,"rpack ttinl len","",j);
2808#ifdef GFTIMER
2809            t2 = gftimer();
2810            debug(F101,"rpack ttinl msec","",(long)((t2-t1)*1000.0));
2811#endif /* GFTIMER */
2812        }
2813#endif /* DEBUG */
2814
2815#ifdef STREAMING
2816    if (streaming && sndtyp == 'D' && j == 0)
2817        return('Y');
2818#endif /* STREAMING */
2819
2820        if (j < 0) {
2821            /* -1 == timeout, -2 == ^C, -3 == connection lost or fatal i/o */
2822            debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */
2823            freerbuf(k);                /* Free this buffer */
2824            if (j < -1) {               /* Bail out if ^C^C typed. */
2825                if (j == -2) {
2826                    interrupted = 1;
2827                    debug(F101,"rpack ^C server","",server);
2828                    debug(F101,"rpack ^C en_fin","",en_fin);
2829                } else if (j == -3) {
2830                    fatalio = 1;
2831                    debug(F101,"rpack fatalio","",en_fin);
2832                }
2833                return(j);
2834            }
2835            if (nakstate)               /* j == -1 is a read timeout */
2836              xxscreen(SCR_PT,'T',(long)winlo,"");
2837            else
2838              xxscreen(SCR_PT,'T',(long)pktnum,"");
2839            logpkt('r',-1,(CHAR *)"<timeout>",0);
2840            if (flow == 1) ttoc(XON);   /* In case of Xoff blockage. */
2841            return('T');
2842        }
2843#ifdef CK_AUTODL
2844    }
2845#endif /* CK_AUTODL */
2846
2847    rpktl = j;
2848    tlci += j;                          /* All OK, Count the characters. */
2849    flci += j;
2850
2851/* Find start of packet */
2852
2853#ifndef PARSENSE
2854    for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
2855      sohp++;                           /* Find mark */
2856    if (i++ >= j) {                     /* Didn't find it. */
2857        logpkt('r',-1,"<timeout>",0);
2858        freerbuf(k);
2859        return('T');
2860    }
2861#else
2862    i = 1;                              /* ttinl does this for us */
2863#endif /* PARSENSE */
2864
2865    rpackets++;                         /* Count received packet. */
2866    lp = i;                             /* Remember LEN position. */
2867    if ((j = xunchar(recpkt[i++])) == 0) { /* Get packet length.  */
2868        if ((j = lp+5) > MAXRP) {       /* Long packet */
2869            return('Q');                /* Too long */
2870        }
2871
2872#ifdef CKTUNING
2873        /* Save some function-call and loop overhead... */
2874#ifdef COMMENT
2875        /* ttinl() already removed parity */
2876        if (parity)
2877#endif /* COMMENT */
2878          chk = (unsigned) ((unsigned) recpkt[i-1] +
2879                            (unsigned) recpkt[i]   +
2880                            (unsigned) recpkt[i+1] +
2881                            (unsigned) recpkt[i+2] +
2882                            (unsigned) recpkt[i+3]
2883                            );
2884#ifdef COMMENT
2885        else
2886          chk = (unsigned) ((unsigned) (recpkt[i-1] & 077) +
2887                            (unsigned) (recpkt[i]   & 077) +
2888                            (unsigned) (recpkt[i+1] & 077) +
2889                            (unsigned) (recpkt[i+2] & 077) +
2890                            (unsigned) (recpkt[i+3] & 077)
2891                            );
2892#endif /* COMMENT */
2893        if (xunchar(recpkt[j]) != ((((chk & 0300) >> 6) + chk) & 077))
2894#else
2895        x = recpkt[j];                  /* Header checksum. */
2896        recpkt[j] = '\0';               /* Calculate & compare. */
2897        if (xunchar(x) != chk1(recpkt+lp,5))
2898#endif /* CKTUNING */
2899          {
2900              freerbuf(k);
2901              logpkt('r',-1,(CHAR *)"<crunched:hdr>",0);
2902              xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet header");
2903              return('Q');
2904          }
2905#ifndef CKTUNING
2906        recpkt[j] = x;                  /* Checksum ok, put it back. */
2907#endif /* CKTUNING */
2908        rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl;
2909        j = 3;                          /* Data offset. */
2910    } else if (j < 3) {
2911        debug(F101,"rpack packet length less than 3","",j);
2912        freerbuf(k);
2913        logpkt('r',-1,(CHAR *)"<crunched:len>",0);
2914        xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet length");
2915        return('Q');
2916    } else {
2917        rln = j - bctl - 2;             /* Regular packet */
2918        j = 0;                          /* No extended header */
2919    }
2920    rsn = xunchar(recpkt[i++]);         /* Sequence number */
2921    if (pktlog)                         /* Save a function call! */
2922      logpkt('r',rsn,sohp,rln+bctl+j+4);
2923    if (rsn < 0 || rsn > 63) {
2924        debug(F101,"rpack bad sequence number","",rsn);
2925        freerbuf(k);
2926        if (pktlog)
2927          logpkt('r',rsn,(CHAR *)"<crunched:seq>",0);
2928        xxscreen(SCR_PT,'%',(long)pktnum,"Bad sequence number");
2929        return('Q');
2930    }
2931/*
2932  If this packet has the same type as the packet just sent, assume it is
2933  an echo and ignore it.  Don't even bother with the block check calculation:
2934  even if the packet is corrupted, we don't want to NAK an echoed packet.
2935  Nor must we NAK an ACK or NAK.
2936*/
2937    type = recpkt[i++];                 /* Get packet's TYPE field */
2938    if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) {
2939        debug(F000,"rpack echo","",type); /* If it's an echo */
2940        freerbuf(k);                    /* Free this buffer */
2941        logpkt('#',rsn,(CHAR *)"<echo:ignored>",0);
2942        return('e');                    /* Return special (lowercase) code */
2943    }
2944/*
2945  Separate the data from the block check, accounting for the case where
2946  a packet was retransmitted after the block check switched.
2947*/
2948    if (type == 'I' || type == 'S') {   /* I & S packets always have type 1 */
2949        chklen = 1;
2950        rln = rln + bctl - 1;
2951    } else if (type == 'N') {           /* A NAK packet never has data */
2952        chklen = xunchar(recpkt[lp]) - 2;
2953        rln = rln + bctl - chklen;
2954    } else chklen = bctl;
2955#ifdef DEBUG
2956    if (deblog) {                       /* Save 2 function calls */
2957        debug(F101,"rpack bctl","",bctl);
2958        debug(F101,"rpack chklen","",chklen);
2959    }
2960#endif /* DEBUG */
2961    i += j;                             /* Buffer index of DATA field */
2962    rdatap = recpkt+i;                  /* Pointer to DATA field */
2963    if ((j = rln + i) > r_pkt[k].bf_len) { /* Make sure it fits */
2964        debug(F101,"packet too long","",j);
2965        freerbuf(k);
2966        logpkt('r',rsn,(CHAR *)"<overflow>",0);
2967        return('Q');
2968    }
2969    for (x = 0; x < chklen; x++)        /* Copy the block check */
2970      pbc[x] = recpkt[j+x];             /* 3 bytes at most. */
2971    pbc[x] = '\0';                      /* Null-terminate block check string */
2972    recpkt[j] = '\0';                   /* and the packet Data field. */
2973
2974    if (chklen == 2 && bctu == 4) {     /* Adjust for Blank-Free-2 */
2975        chklen = 4;                     /* (chklen is now a misnomer...) */
2976        debug(F100,"rpack block check B","",0);
2977    }
2978    switch (chklen) {                   /* Check the block check */
2979      case 1:                           /* Type 1, 6-bit checksum */
2980        if (xunchar(*pbc) != chk1(recpkt+lp,j-lp)) {
2981#ifdef DEBUG
2982            if (deblog) {
2983                debug(F110,"checked chars",recpkt+lp,0);
2984                debug(F101,"block check (1)","",(int) xunchar(*pbc));
2985                debug(F101,"should be (1)","",chk1(recpkt+lp,j-lp));
2986            }
2987#endif /* DEBUG */
2988            freerbuf(k);
2989            logpkt('r',-1,(CHAR *)"<crunched:chk1>",0);
2990            xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
2991            return('Q');
2992        }
2993        break;
2994      case 2:                           /* Type 2, 12-bit checksum */
2995        x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
2996        if (x != chk2(recpkt+lp,j-lp)) { /* No match */
2997            if (type == 'E') {          /* Allow E packets to have type 1 */
2998                recpkt[j++] = pbc[0];
2999                recpkt[j] = '\0';
3000                if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp))
3001                  break;
3002                else
3003                  recpkt[--j] = '\0';
3004            }
3005#ifdef DEBUG
3006            if (deblog) {
3007                debug(F110,"checked chars",recpkt+lp,0);
3008                debug(F101,"block check (2)","", x);
3009                debug(F101,"should be (2)","", (int) chk2(recpkt+lp,j-lp));
3010            }
3011#endif /* DEBUG */
3012            freerbuf(k);
3013            logpkt('r',-1,(CHAR *)"<crunched:chk2>",0);
3014            xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
3015            return('Q');
3016        }
3017        break;
3018      case 3:                           /* Type 3, 16-bit CRC */
3019        crc = (xunchar(pbc[0]) << 12)
3020            | (xunchar(pbc[1]) << 6)
3021            | (xunchar(pbc[2]));
3022        if (crc != chk3(recpkt+lp,j-lp)) {
3023            if (type == 'E') {          /* Allow E packets to have type 1 */
3024                recpkt[j++] = pbc[0];
3025                recpkt[j++] = pbc[1];
3026                recpkt[j] = '\0';
3027                if (xunchar(pbc[2]) == chk1(recpkt+lp,j-lp))
3028                  break;
3029                else { j -=2; recpkt[j] = '\0'; }
3030            }
3031#ifdef DEBUG
3032            if (deblog) {
3033                debug(F110,"checked chars",recpkt+lp,0);
3034                debug(F101,"block check (3)","",crc);
3035                debug(F101,"should be (3)","",(int) chk3(recpkt+lp,j-lp));
3036            }
3037#endif /* DEBUG */
3038            freerbuf(k);
3039            logpkt('r',-1,(CHAR *)"<crunched:chk3>",0);
3040            xxscreen(SCR_PT,'%',(long)pktnum,"CRC error");
3041            return('Q');
3042        }
3043        break;
3044      case 4:                           /* Type 4 = Type 2, no blanks. */
3045        x = (unsigned)((xunchar(*pbc) - 1) << 6) |
3046          (unsigned)(xunchar(pbc[1]) - 1);
3047        if (x != chk2(recpkt+lp,j-lp)) {
3048            if (type == 'E') {  /* Allow E packets to have type 1 */
3049                recpkt[j++] = pbc[0];
3050                recpkt[j] = '\0';
3051                if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp))
3052                  break;
3053                else
3054                  recpkt[--j] = '\0';
3055            }
3056            debug(F101,"bad type B block check","",x);
3057            freerbuf(k);
3058            logpkt('r',-1,(CHAR *)"<crunched:chkb>",0);
3059            xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
3060            return('Q');
3061        }
3062        break;
3063      default:                  /* Shouldn't happen... */
3064        freerbuf(k);
3065        logpkt('r',-1,(CHAR *)"<crunched:chkx>",0);
3066        xxscreen(SCR_PT,'%',(long)pktnum,"(crunched)");
3067        return('Q');
3068    }
3069    debug(F101,"rpack block check OK","",rsn);
3070
3071/* Now we can believe the sequence number, and other fields. */
3072/* Here we violate strict principles of layering, etc, and look at the  */
3073/* packet sequence number.  If there's already a packet with the same   */
3074/* number in the window, we remove this one so that the window will not */
3075/* fill up. */
3076
3077    if ((x = rseqtbl[rsn]) != -1) {     /* Already a packet with this number */
3078        retrans++;                      /* Count it for statistics */
3079        debug(F101,"rpack got dup","",rsn);
3080        logpkt('r',rsn,(CHAR *)"<duplicate>",0);
3081        freerbuf(x);                    /* Free old buffer, keep new packet. */
3082        r_pkt[k].pk_rtr++;              /* Count this as a retransmission. */
3083    }
3084
3085/* New packet, not seen before, enter it into the receive window. */
3086
3087#ifdef CK_TIMERS
3088    if (timint > 0)
3089      rrttbl[rsn] = gtimer();           /* Timestamp */
3090#endif /* CK_TIMERS */
3091
3092    rseqtbl[rsn] = k;                   /* Make back pointer */
3093    r_pkt[k].pk_seq = rsn;              /* Record in packet info structure */
3094    r_pkt[k].pk_typ = type;             /* Sequence, type,... */
3095    r_pkt[k].pk_adr = rdatap;           /* pointer to data buffer */
3096    if (local) {                        /* Save a function call! */
3097        int x = 0;
3098        if (fdispla != XYFD_N) x = 1;
3099        if (fdispla == XYFD_B && (type == 'D' || sndtyp == 'D')) x = 0;
3100        if (x)                          /* Update screen */
3101          xxscreen(SCR_PT,(char)type,(long)rsn,(char *)sohp);
3102    }
3103    return(type);                       /* Return packet type */
3104}
3105
3106/*  L O G P K T  --  Log packet number n, pointed to by s.  */
3107
3108/* c = 's' (send) or 'r' (receive) */
3109
3110VOID
3111#ifdef CK_ANSIC
3112logpkt(char c,int n, CHAR *s, int len)
3113#else
3114logpkt(c,n,s,len) char c; int n; CHAR *s; int len;
3115#endif /* CK_ANSIC */
3116/* logpkt */ {
3117    char plog[20];
3118    if (!s) s = (CHAR *)"";
3119    if (pktlog) if (chkfn(ZPFILE) > 0) {
3120        if (n < 0)                      /* Construct entry header */
3121          sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60)); /* safe */
3122        else
3123          sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60)); /* safe */
3124        if (zsoutx(ZPFILE,plog,(int)strlen(plog)) < 0) {
3125            pktlog = 0;
3126            return;
3127        } else {
3128            if (len == 0)
3129              len = strlen((char *)s);
3130            if (len > 0) {
3131                char * p;               /* Make SOP printable */
3132                int x;                  /* so we can look at logs without */
3133                p = dbchr(*s);          /* triggering autodownload. */
3134                x = strlen(dbchr(*s));
3135                if (*s < 32 || (*s > 127 && *s < 160)) {
3136                    if (zsoutx(ZPFILE,p,x) < 0) {
3137                        pktlog = 0;
3138                        return;
3139                    } else {
3140                        len--;
3141                        s++;
3142                    }
3143                }
3144            }
3145            if (zsoutx(ZPFILE,(char *)s,len) < 0) {
3146                pktlog = 0;
3147                return;
3148            } else if (zsoutx(ZPFILE,
3149#ifdef UNIX
3150                              "\n", 1
3151#else
3152#ifdef datageneral
3153                              "\n", 1
3154#else
3155#ifdef OSK
3156                              "\r", 1
3157#else
3158#ifdef MAC
3159                              "\r", 1
3160#else
3161                              "\015\012", 2
3162#endif /* MAC */
3163#endif /* OSK */
3164#endif /* datageneral */
3165#endif /* UNIX */
3166                              ) < 0) {
3167                pktlog = 0;
3168            }
3169        }
3170    }
3171}
3172
3173/*  T S T A T S  --  Record statistics in transaction log  */
3174
3175VOID
3176tstats() {
3177    char *tp = NULL;
3178#ifdef GFTIMER
3179    CKFLOAT xx;                         /* Elapsed time divisor */
3180#endif /* GFTIMER */
3181
3182    debug(F101,"tstats xfsecs","",xfsecs);
3183    debug(F101,"tstats filcnt","",filcnt);
3184    if (filcnt == 1) {                  /* Get timing for statistics */
3185        tsecs = xfsecs;                 /* Single file, we already have it */
3186#ifdef GFTIMER
3187        debug(F101,"tstats fpxfsecs","",(int)fpxfsecs);
3188        fptsecs = fpxfsecs;
3189#endif /* GFTIMER */
3190    } else {                            /* Multiple files */
3191        tsecs = gtimer();               /* Get current time */
3192#ifdef GFTIMER
3193        fptsecs = gftimer();
3194#endif /* GFTIMER */
3195    }
3196#ifdef GFTIMER
3197    if (fptsecs <= GFMINTIME)           /* Calculate CPS */
3198      fptsecs = (CKFLOAT) GFMINTIME;
3199    debug(F101,"tstats fptsecs","",(int)fptsecs);
3200    xx = (CKFLOAT) tfc / fptsecs;
3201    if (sizeof(long) <= 4) {            /* doesn't account for 16-bit longs */
3202        if (xx  > 2147483647.0)
3203          tfcps = 2147483647L;          /* 31 bits */
3204        else
3205          tfcps = (long) xx;
3206    } else
3207      tfcps = (long) xx;
3208#else
3209    if (tsecs < 2L)
3210      tsecs = 1L;
3211    debug(F101,"tstats tsecs","",tsecs);
3212    tfcps = tfc / tsecs;
3213#endif /* GFTIMER */
3214
3215    ztime(&tp);                         /* Get time stamp */
3216    tlog(F100,"","",0L);                /* Leave a blank line */
3217    tlog(F110,"Transaction complete",tp,0L);  /* Record it */
3218
3219    if (filcnt < 1) return;             /* If no files, done. */
3220
3221/* If multiple files, record character totals for all files */
3222
3223    if (filcnt > 1) {
3224        tlog(F101," files transferred       ","",filcnt - filrej);
3225        tlog(F101," total file characters   ","",tfc);
3226        tlog(F101," communication line in   ","",tlci);
3227        tlog(F101," communication line out  ","",tlco);
3228    }
3229
3230/* Record timing info for one or more files */
3231
3232#ifdef GFTIMER
3233    if (filcnt - filrej == 1) {
3234        tlog(F101," elapsed time (seconds)  ","",(long) fpxfsecs);
3235        tlog(F101," effective data rate     ","",filcps);
3236    } else {
3237        tlog(F101," elapsed time (seconds)  ","",(long) fptsecs);
3238        tlog(F101," effective data rate     ","",(long) xx);
3239    }
3240#else
3241    tlog(F101," elapsed time (seconds)  ","",(long) tsecs);
3242    if (tsecs > 0) {
3243        long lx;
3244        lx = (tfc * 10L) / (long) tsecs;
3245        tlog(F101," effective data rate     ","",lx/10L);
3246    }
3247#endif /* GFTIMER */
3248    tlog(F100,"","",0L);                /* Leave a blank line */
3249}
3250
3251/*  F S T A T S  --  Record file statistics in transaction log  */
3252
3253VOID
3254fcps() {
3255#ifdef GFTIMER
3256    double xx;
3257    fpxfsecs = gftimer() - fpfsecs;
3258    if (fpxfsecs <= GFMINTIME)
3259      fpxfsecs = (CKFLOAT) GFMINTIME;
3260    xx = (CKFLOAT) ffc / fpxfsecs;
3261    if (sizeof(long) <= 4) {
3262        if (xx  > 2147483647.0)
3263          tfcps = 2147483647L;          /* 31 bits */
3264        else
3265          filcps = (long) xx;
3266    } else
3267      filcps = (long) xx;
3268    if (sizeof(int) >= 4)
3269      xfsecs = (int) fpxfsecs;
3270    else if (fpxfsecs < 32768.0)
3271      xfsecs = (int) fpxfsecs;
3272    else
3273      xfsecs = 32767;
3274#else /* GFTIMER */
3275    xfsecs = gtimer() - fsecs;
3276    if (xfsecs < 1L) xfsecs = 1L;
3277    filcps = ffc / xfsecs;
3278#endif /* GFTIMER */
3279}
3280
3281VOID
3282fstats() {
3283    tfc += ffc;
3284#ifdef DEBUG
3285    if (deblog) {
3286        debug(F101,"fstats tfc","",tfc);
3287        debug(F101,"fstats what","",what);
3288        debug(F110,"fstats epktmsg",epktmsg,0);
3289    }
3290#endif /* DEBUG */
3291#ifdef TLOG
3292    if (!discard && !cxseen && !czseen && what != W_NOTHING && !*epktmsg)
3293      tlog(F101," complete, size","",ffc);
3294#endif /* TLOG */
3295}
3296
3297#endif /* NOXFER */
Note: See TracBrowser for help on using the repository browser.