apply 010_makefile-destdir-support
[ckermit.git] / ckcfn2.c
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, 2004,
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() */
26 extern int tn_nlm, ttnproto, tn_b_nlm;
27 #endif /* TCPSOCKET */
28
29 extern int parity, network, local, interrupted, fatalio, wasclosed;
30
31 int kstartactive = 0;                   /* Flag for kstart() in a packet */
32
33 static 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
166 CHAR
167 #ifdef CK_ANSIC
168 dopar(register CHAR ch)
169 #else
170 dopar(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
196 extern int batch;
197 #else
198 extern int backgrd;
199 #endif /* VMS */
200
201 #ifdef DYNAMIC
202 extern struct pktinfo *s_pkt;           /* array of pktinfo structures */
203 extern struct pktinfo *r_pkt;           /* array of pktinfo structures */
204 #else
205 extern struct pktinfo s_pkt[];          /* array of pktinfo structures */
206 extern struct pktinfo r_pkt[];          /* array of pktinfo structures */
207 #endif /* DYNAMIC */
208
209 extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, wslotn,
210   sbufnum, rbufnum, pktpaus, reliable;
211
212 #ifdef STREAMING
213 static int dontsend = 0;
214 extern int streaming;
215 #endif /* STREAMING */
216
217 extern int ttprty;                      /* from ck*tio.c */
218 extern int autopar;
219
220 extern int spsiz, spmax, rpsiz, timint, timef, npad, bestlen, maxsend;
221 extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, flow;
222 extern int pktnum, sndtyp, rcvtyp, bctr, bctu, bctl, rsn, rln, maxtry, size;
223 extern int osize, maxsize, spktl, rpktl, nfils, stdouf, fsecs;
224 extern int turn, turnch, displa, pktlog, seslog, xflg, mypadn;
225 extern int hcflg, server, cxseen, czseen, discard, slostart;
226 extern int nakstate, quiet, success, xitsta, what, filestatus;
227 extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz;
228 extern int carrier, fdispla, srvidl;
229
230 #ifdef GFTIMER
231 extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
232 #endif /* GFTIMER */
233
234 extern long filcnt, filrej, ffc, flci, flco, tlci, tlco, tfc, speed;
235 extern long filcps, tfcps;
236
237 extern char *cmarg, filnam[];
238
239 extern CHAR padch, mypadc, eol, seol, ctlq, sstate;
240 extern CHAR *recpkt, *data, myinit[];
241 extern CHAR *srvptr, stchr, mystch, *rdatap;
242 extern CHAR padbuf[];
243 extern CHAR * epktmsg;
244 extern int epktrcvd, epktsent;
245
246 #ifdef OS2                              /* AUTODOWNLOAD parameters */
247 extern int adl_kmode, adl_zmode;        /* Match Packet to signal download */
248 extern char * adl_kstr;                 /* KERMIT Download String */
249 extern char * adl_zstr;                 /* ZMODEM Download String */
250 #endif /* OS2 */
251
252 #ifdef CK_AUTODL
253 CHAR ksbuf[96] = { NUL, NUL };          /* Autodownload "Kermit Start" buf */
254 #endif /* CK_AUTODL */
255
256 int numerrs = 0;                        /* Number of packet errors so far */
257 int rcvtimo = 0;                        /* Timeout for receiving a packet */
258 int idletmo = 0;                        /* Flag for idle timeout */
259
260 long filcps = 0L;                       /* CPS most recent file transferred */
261 long tfcps  = 0L;                       /* CPS most recent transaction */
262 long xfsecs = 0L;                       /* Elapsed time for most recent file */
263 #ifdef GFTIMER
264 CKFLOAT fpxfsecs = 0.0;                 /* Ditto, but floating point */
265 #endif /* GFTIMER */
266
267 #ifdef CK_TIMERS
268 int rrttbl[64], srttbl[64];             /* Packet timestamp tables */
269 extern int rttflg;
270 #define RTT_SCALE 1000
271 long
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
281 long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L,
282   051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L,
283   0153215L, 0163416L, 0173617L
284 };
285
286 long 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
300 VOID
301 rttinit() {                             /* 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 */
332 int
333 getrtt(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 */
497 int
498 input() {
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 */
1136 int
1137 #ifdef CK_ANSIC
1138 parchk(CHAR *s, CHAR start, int n)
1139 #else
1140 parchk(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 \f
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 */
1204 int
1205 chktimo(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 \f
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 */
1264 int
1265 #ifdef CK_ANSIC
1266 spack(char pkttyp, int n, int len, CHAR *d)
1267 #else
1268 spack(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
1548 int
1549 chk1(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
1571 unsigned int
1572 chk2(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
1594 unsigned int
1595 chk3(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
1606 unsigned int
1607 chk3(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 */
1626 int
1627 nxtpkt() {                              /* 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
1657 int
1658 ack() {                                 /* Acknowledge the current packet. */
1659     return(ackns(winlo,(CHAR *)""));
1660 }
1661
1662 #ifdef STREAMING
1663 int
1664 fastack() {                             /* 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
1690 int
1691 ackns(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
1717 int
1718 ackn(n) int n; {                        /* Send ACK for packet number n */
1719     return(ackns(n,(CHAR *)""));
1720 }
1721
1722 int
1723 ack1(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 */
1737 int
1738 nack(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 */
1797 VOID
1798 rcalcpsz() {
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 */
1856 int
1857 resend(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
1985 int
1986 errpkt(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
2071 int
2072 #ifdef CK_ANSIC
2073 scmd(char t, CHAR *dat)
2074 #else
2075 scmd(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
2092 struct opktparm {                       /* O-Packet item list */
2093     CHAR * opktitem;
2094     struct opktparm * opktnext;
2095 };
2096
2097 struct opktparm * opkthead = NULL;      /* Linked list of O-packet fields */
2098 int opktcnt = 0;                        /* O-Packet counter */
2099 char * 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
2112 int
2113 sopkt() {
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 */
2221 int
2222 srinit(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
2378 int
2379 #ifdef CK_ANSIC
2380 kstart(CHAR ch)
2381 #else
2382 kstart(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
2467 int
2468 #ifdef CK_ANSIC
2469 zstart(CHAR ch)
2470 #else
2471 zstart(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
2524 VOID
2525 autodown(int ch)
2526 #else
2527 VOID
2528 autodown(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
2640 int
2641 chkspkt(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 */
2680 int
2681 rpack() {
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
3110 VOID
3111 #ifdef CK_ANSIC
3112 logpkt(char c,int n, CHAR *s, int len)
3113 #else
3114 logpkt(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
3175 VOID
3176 tstats() {
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
3253 VOID
3254 fcps() {
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
3281 VOID
3282 fstats() {
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 */