Imported Upstream version 302
[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, 2011,
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, bctf, bctl, rsn, rln, maxtry;
223 extern int size, 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, speed, filcps, tfcps;
235 extern CK_OFF_T ffc, flci, flco, tlci, tlco, tfc;
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                 else                     /* JHD 20100208 */
700                   rcvtimo = timint;      /* JHD 20100208 */
701 #endif /* CK_TIMERS */
702                 debug(F101,"input rsn=winlo","",rsn);
703                 break;
704             }
705
706             /* Got a packet out of order. */
707
708             debug(F101,"input out of sequence, rsn","",rsn);
709             k = rseqtbl[rsn];           /* Get window slot of this packet. */
710             debug(F101,"input rseqtbl[rsn]","",k);
711             if (k < 0) {
712                 debug(F101,"input recv can't find index for rcvd pkt","",rsn);
713                 /* Was "Internal error 21" */
714                 /* This should not happen  */
715                 errpkt((CHAR *)"Sliding windows protocol error.");
716                 type = 'E';
717                 break;
718             }
719             y = chkwin(rsn,winlo,wslots); /* See what window it's in. */
720             debug(F101,"input recv chkwin","",y);
721             if (y == 1) {               /* From previous window. */
722 #ifdef STREAMING
723                 if (!streaming)         /* NO RESEND IF STREAMING! */
724 #endif /* STREAMING */
725                   resend(rsn);          /* Resend the ACK (might have data) */
726                 freerpkt(rsn);          /* Get rid of received packet */
727                 continue;               /* Back to wait for another packet */
728             } else {                    /* In this window or out of range */
729                 if (y < 0)              /* If out of range entirely, */
730                   freerpkt(rsn);        /* release its buffer */
731
732 #ifdef STREAMING
733                 if (streaming) {        /* Streaming (this shouldn't happen) */
734                     errpkt((CHAR *)"Sequence error on reliable link.");
735                     type = 'E';
736                     break;
737                 }
738 #endif /* STREAMING */
739
740 /* If our receive window is full, NAK window-low */
741
742                 if (rbufnum < 1) {      /* Receive window full? */
743                     if (nack(winlo) < 0) {    /* No choice, must NAK winlo. */
744                         errpkt((CHAR *)"Too many retries."); /* Too many */
745                         type = 'E';
746                         break;
747                     } else continue;
748                 }
749 /*
750   Receive window not full.  This is a packet in the current window but it is
751   not the desired packet at winlo.  So therefore there are gaps before this
752   packet.  So we find the "lowest" unNAK'd missing packet, if any, between
753   winlo and this one, and NAK it.  If there are no as-yet-unNAK'd missing
754   packets in the window, then we send nothing and go wait for another packet.
755   In theory, this could result in a timeout, but in practice it is likely that
756   the already-NAK'd missing packets are already on their way.  Note, we do not
757   NAK ahead of ourselves, as that only creates unnecessary retransmissions.
758 */
759                 for (x = winlo; x != rsn; x = (x + 1) % 64) {
760                     if (rseqtbl[x] > -1) /* Have I received packet x? */
761                       continue;          /* Yes, check next sequence number. */
762                     pi = sseqtbl[x];     /* No, have I NAK'd it yet? */
763                     if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
764                         nack(x);         /* No, NAK it now. */
765                         break;
766                     }
767                 }
768             }
769 /*!!!*/
770         } else {                        /* Otherwise file sender... */
771
772 #ifdef STREAMING
773             if (streaming && sndtyp == 'D') {
774                 debug(F101,"STREAMING input streaming","",streaming);
775                 debug(F000,"STREAMING input sndtyp","",sndtyp);
776                 rsn = winlo;
777                 type = 'Y';             /* Pretend we got an ACK */
778             }
779 #endif /* STREAMING */
780             if (!nak2ack) {             /* NAK(n+1) = ACK(n) */
781                 if (wslots > 1) {       /* Packet at winlo already ACK'd? */
782                     if (sacktbl[winlo]) { /* If so,  */
783                         sacktbl[winlo] = 0; /* Turn off the ACK'd flag */
784                         winlo = (winlo + 1) % 64; /* Rotate the window */
785                         type = 'Y';     /* And return ACK */
786                         debug(F101,
787                               "input send returning pre-stashed ACK","",
788                               winlo-1);
789                         break;
790                     }
791                 }
792 #ifdef STREAMING
793                 if (!(streaming && sndtyp == 'D')) { /* Not streaming | data */
794                     type = rpack();     /* Try to read an acknowledgement */
795                 } else {                /* Streaming and in Data phase */
796                     type = 'Y';         /* Assume all is normal */
797                     if (chkint() < 0)   /* Check for console interrupts. */
798                       type = 'z';
799                     else if (ttchk() > 4 + bctu) /* Check for return traffic */
800                       type = rpack();
801                     debug(F000,"input streaming type","",type);
802                 }
803 #endif /* STREAMING */
804                 debug(F111,"input send",(char *) rdatap,(int) type);
805                 while (type == 'e') {   /* Handle echoes */
806                     debug(F000,"echo discarded","",type);
807                     type = rpack();
808                 }
809 #ifndef OLDCHKINT
810                 if (type == 'z') {
811                     epktrcvd = 1;
812                     errpkt((CHAR *)"User cancelled.");
813                     type = 'E';
814                     break;
815                 }
816 #endif /* OLDCHKINT */
817                 if (type < -1) {
818                     xxscreen(SCR_PT,'q',0L,
819                            ((char *)((type == -2) ?
820                            "Interrupted" :
821                            "Connection lost"))
822                            );
823                     if (type != -2)
824                       dologend();
825                     return('q');        /* Ctrl-C or connection lost */
826                 }
827                 if (type == -1) {
828 #ifdef COMMENT
829                     char foo[256];
830                     ckmakxmsg(foo,256,
831                               "Receive window full (error 18): wslots=",
832                               ckitoa(wslots),
833                               " winlo=",ckitoa(winlo)," pktnum=",
834                               ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL);
835                     errpkt((CHAR *)foo);
836                     debug(F100,foo,"",0);
837 #else
838                     errpkt((CHAR *)"Receive window full"); /* was "internal */
839                     debug(F101," wslots","",wslots); /* error 18" */
840                     debug(F101," winlo","",winlo);
841                     debug(F101," pktnum","",pktnum);
842 #endif /* COMMENT */
843                     dumprbuf();
844                     type = 'E';
845                     break;
846                 }
847                 dumprbuf();             /* Debugging */
848
849 #ifdef OLDCHKINT
850                 if (chkint() < 0) {     /* Check for console interrupts. */
851                     errpkt((CHAR *)"User cancelled.");
852                     return(type = 'E');
853                 }
854 #endif /* OLDCHKINT */
855
856                 /* Got a packet */
857
858 #ifdef STREAMING
859                 if (streaming) {                /* Streaming */
860                     if (type == 'Q' || type == 'T') { /* Errors are fatal. */
861                         crunched++;     /* For statistics */
862                         errpkt((CHAR *)"Transmission error on reliable link.");
863                         type = 'E';
864                     }
865                 }
866 #endif /* STREAMING */
867                 if (type == 'E') {
868                     debug(F101,"input send got E, nakstate","",nakstate);
869                     break;              /* Error packet */
870                 }
871                 if (type == 'Q') {      /* Crunched packet */
872                     crunched++;         /* For statistics */
873                     numerrs++;          /* For packet resizing */
874                     x = resend(winlo);  /* Resend window-low */
875                     if (x < 0) {
876                         type = 'E';
877                         errpkt((CHAR *)"Too many retries");
878                         break;
879                     }
880                     continue;
881                 }
882                 if (type == 'T') {      /* Timeout waiting for ACKs. */
883                     timeouts++;         /* Count it */
884                     numerrs++;          /* Count an error too */
885                     debug(F101,"input send state timeout, winlo","",winlo);
886
887                     /* Retransmit the oldest un-ACK'd packet. */
888
889                     debug(F101,"input send resending winlo","",winlo);
890                     if (resend(winlo) < 0) { /* Check retries */
891                         debug(F101,"input send too many resends","",maxtry);
892                         errpkt((CHAR *)"Too many retries");
893                         return(type = 'E');
894                     }
895 #ifdef NEWDPL
896                     /* Reduce prevailing packet length */
897                     x = sseqtbl[winlo]; /* Get length of packet we want ACKd */
898                     if (x > -1) {       /* Only if we have a valid index */
899                         if (s_pkt[x].pk_typ == 'D') { /* only for D packets */
900                             spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */
901                             if (spsiz < 20) spsiz = 20; /* within reason */
902                             debug(F101,"input T cut packet length","",spsiz);
903                         }
904                     }
905 #endif /* NEWDPL */
906                     continue;
907                 }
908             }
909             /* Got an actual normal packet */
910
911             nak2ack = 0;                /* Unset this flag. */
912             y = chkwin(rsn,winlo,wslots); /* Is it in the window? */
913             debug(F101,"input send rsn","",rsn);
914             debug(F101,"input send winlo","",winlo);
915             debug(F101,"input send chkwin","",y);
916
917             if (type == 'Y') {          /* Got an ACK */
918                 if (y == 0) {           /* In current window */
919                     if (spackets < 4)   /* Error counter doesn't count */
920                       numerrs = 0;      /* until data phase. */
921                     sacktbl[rsn]++;     /* Mark the packet as ACK'd */
922                     x = sseqtbl[rsn];   /* Get ACK'd packet's buffer index */
923                     debug(F101,"bestlen ack x","",x);
924 #ifdef NEWDPL
925                     if (x > -1) {
926                         acktype = s_pkt[x].pk_typ; /* Get type */
927                         debug(F000,"bestlen ack type","",acktype);
928
929                         if (acktype == 'D') { /* Adjust data packet length */
930                             if (spsiz > bestlen) {
931                                 bestlen = spsiz;
932                                 debug(F101,"bestlen B","",bestlen);
933                             }
934 #ifdef DEBUG
935                             if (deblog) {
936                                 debug(F101,"bestlen retry","",s_pkt[x].pk_rtr);
937                                 debug(F101,"bestlen len","",s_pkt[x].pk_len);
938                                 debug(F101,"bestlen spackets","",spackets);
939                             }
940 #endif /* DEBUG */
941                             /* Set new best length */
942                             if (s_pkt[x].pk_rtr == 0 &&
943                                 s_pkt[x].pk_len + 8 > bestlen) {
944                                 bestlen = s_pkt[x].pk_len + 8;
945                                 if (bestlen > spmax)
946                                   bestlen = spmax;
947                                 debug(F101,"bestlen A","",bestlen);
948                             }
949 #ifdef DEBUG
950                             if (deblog) {
951                                 debug(F101,"bestlen wslots","",wslots);
952                                 debug(F101,"bestlen maxsend","",maxsend);
953                             }
954 #endif /* DEBUG */
955                             /* Slow start */
956                             if (slostart &&
957                                 (maxsend <= spmax) &&
958                                 (rpackets < 11) &&
959                                 (numerrs == 0)) {
960                                 spsiz = spsiz << 1;
961                                 debug(F101,"bestlen spsiz A","",spsiz);
962
963                             /* Creep up to best length */
964                             } else if ((spackets > 5) &&
965                                        (spsiz < bestlen - 8)) {
966                                 spsiz += (bestlen - spsiz) / 3;
967                                 debug(F101,"bestlen spsiz B","",spsiz);
968
969                             /* Push the envelope */
970                             } else if ((spackets % (wslots + 1) == 0) &&
971                                        (spackets > 6) &&
972                                        (bestlen < spmax - 8) &&
973                                        (spsiz < spmax)) {
974                                 spsiz += (spmax - bestlen) / 3;
975                                 debug(F101,"bestlen spsiz C","",spsiz);
976                             }
977                             /* But not too far */
978                             if (spsiz > spmax) {
979                                 spsiz = spmax;
980                                 debug(F101,"bestlen spsiz D","",spsiz);
981                             }
982                         }
983                     }
984 #endif /* NEWDPL */
985
986 #ifdef CK_TIMERS
987                     if (rttflg && timint) /* If doing dynamic timers */
988                       getrtt(nakstate, rsn); /* call routine to set it. */
989                     else                     /* JHD 20100208 */
990                       rcvtimo = timint;      /* JHD 20100208 */
991 #endif /* CK_TIMERS */
992 /*
993   NOTE: The following statement frees the buffer of the ACK we just got.
994   But the upper layers still need the data, like if it's the ACK to an I,
995   S, F, D, Z, or just about any kind of packet.  So for now, freerbuf()
996   deallocates the buffer, but does not erase the data or destroy the pointer
997   to it.  There's no other single place where these receive buffers can be
998   correctly freed (?) ...
999 */
1000                     freerpkt(rsn);      /* Free the ACK's buffer */
1001                     freesbuf(rsn);      /* *** Free the sent packet's buffer */
1002                     if (rsn == winlo) { /* Got the one we want */
1003                         sacktbl[winlo] = 0;
1004                         winlo = (winlo + 1) % 64;
1005                         debug(F101,"input send rotated send window","",winlo);
1006                         break;          /* Return the ACK */
1007                     } else {
1008                         debug(F101,"input send mark pkt","",rsn);
1009                         continue;       /* Otherwise go read another packet */
1010                     }
1011                 } else if (y == 1 && wslots < 2) { /* (190) ACK for previous */
1012                     numerrs++;          /* == NAK for current, count error */
1013                     debug(F101,"input send ACK for previous","",rsn);
1014                     freerpkt(rsn);      /* Free NAK's buffer */
1015                     x = resend(winlo);  /* Resend current packet */
1016                     if (x < 0) {
1017                         type = 'E';
1018                         errpkt((CHAR *)"Too many retries");
1019                         break;
1020                     } else continue;    /* Resend ok, go read another packet */
1021                 } else {                /* Other cases, just ignore */
1022                     debug(F101,"input send ACK out of window","",rsn);
1023                     freerpkt(rsn);
1024                     continue;
1025                 }
1026             }
1027             if (type == 'N') {          /* NAK */
1028                 numerrs++;              /* Count an error */
1029 #ifdef STREAMING
1030                 if (streaming) {                /* Streaming */
1031                     errpkt((CHAR *)"NAK received on reliable link.");
1032                     type = 'E';
1033                     break;
1034                 }
1035 #endif /* STREAMING */
1036
1037                 debug(F101,"input send NAK","",rsn);
1038 #ifdef NEWDPL
1039                 /* Reduce prevailing packet length */
1040                 x = sseqtbl[rsn];       /* Length of packet that was NAK'd */
1041                 if (x > -1) {           /* If it's a Data packet we've sent */
1042                     if (s_pkt[x].pk_typ == 'D') {
1043                         spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */
1044 #ifdef COMMENT
1045                         /* This might be a good idea -- haven't tried it ... */
1046                         if (bestlen > 0 && spsiz > bestlen)
1047                           spsiz = bestlen;
1048 #endif /* COMMENT */
1049                         if (spsiz < 20) spsiz = 20;
1050                         debug(F101,"input N cut packet length","",spsiz);
1051                     }
1052                 }
1053 #endif /* NEWDPL */
1054                 freerpkt(rsn);          /* Free buffer where NAK lies. */
1055                 if (y == 0) {           /* In current window */
1056                     debug(F100," in window","",0);
1057                     k = sseqtbl[rsn];   /* Get pointer to NAK'd packet. */
1058                     if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) {
1059                         x = resend(winlo); /* Packet we haven't sent yet. */
1060                     } else {
1061                         x = resend(rsn); /* Resend requested packet. */
1062                     }
1063                     if (x < 0) {        /* Resend error is fatal.  */
1064                         type = 'E';
1065                         errpkt((CHAR *)"Too many retries");
1066                         break;
1067                     } else continue;    /* Resend ok, go read another packet */
1068                 } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */
1069                     if (wslots > 1) {
1070                         debug( F101,"NAK for next packet, windowing","",rsn);
1071                         x = resend(winlo); /* Resend window-low */
1072                         if (x < 0) {
1073                             type = 'E';
1074                             errpkt((CHAR *)"Too many retries");
1075                             break;
1076                         }
1077                         continue;       /* Go back and read another pkt */
1078                     }
1079                     debug(F101,"NAK for next packet, no windowing","",rsn);
1080                     x = (rsn == 0) ? 63 : rsn - 1;
1081                     if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) {
1082                         resend(0);      /* ACK for S or I packet missing */
1083                         continue;       /* so resend the S or I */
1084                     }
1085                     rsn = x;            /* Else, treat NAK(n+1) as ACK(n) */
1086                     nak2ack = 1;        /* Go back and process the ACK */
1087                     continue;
1088                 } else if (y > 0) {     /* NAK for pkt we can't resend */
1089                     debug(F101," NAK out of window","",rsn); /* bad... */
1090                     type = 'E';
1091                     errpkt((CHAR *)"NAK out of window");
1092                     break;
1093                 } else continue;        /* Ignore other NAKs */
1094             }                           /* End of file-sender NAK handler */
1095
1096             if (rsn == winlo) {         /* Not ACK, NAK, timeout, etc. */
1097                 debug(F000,"input send unexpected type","",type);
1098                 break;
1099             }
1100         }                               /* End of file-sender section */
1101     }                                   /* End of input() while() loop */
1102 /*
1103   When the window size is 1 and we have the packet we want, there can not
1104   possibly be anything waiting for us on the connection that is useful to us.
1105   However, there might be redundant copies of a packet we already got, which
1106   would cause needless cycles of repeated packets.  Therefore we flush the
1107   communications input buffer now to try to get rid of undesired and unneeded
1108   packets that we have not read yet.
1109
1110   Actually, the first sentence above is not entirely true: there could be an
1111   Error packet waiting to be read.  Flushing an E packet is bad because it
1112   will not be resent, and we'll go into a cycle of timing out and
1113   retransmitting up to the retry limit.  - fdc 2007/03/02
1114 */
1115     if (wslotn == 1                     /* (not wslots!) */
1116 #ifdef STREAMING
1117         && !streaming                   /* But not when streaming */
1118 #endif /* STREAMING */
1119         ) {
1120         debug(F100,"input about to flush","",0);
1121         ttflui();               /* Got what we want, clear input buffer. */
1122     }
1123 #ifndef NEWDPL
1124     if (!nakstate)                      /* When sending */
1125       rcalcpsz();                       /* recalculate size every packet */
1126 #endif /* NEWDPL */
1127     if (type == 'E')
1128       xitsta |= (what ? what : 1);      /* Remember what failed. */
1129     debug(F101,"input winlo","",winlo);
1130     debug(F101,"input rsn","",rsn);
1131     debug(F000,"input returning type","",type);
1132     return(rcvtyp = type);              /* Success, return packet type. */
1133 }
1134
1135 #ifdef PARSENSE
1136 /*  P A R C H K  --  Check if Kermit packet has parity  */
1137
1138 /*
1139   Call with s = pointer to packet, start = packet start character, n = length.
1140   Returns 0 if packet has no parity, -1 on error, or, if packet has parity:
1141     'e' for even, 'o' for odd, 'm' for mark.  Space parity cannot be sensed.
1142   So a return value of 0 really means either space or none.
1143   Returns -2 if parity has already been checked during this protocol operation.
1144 */
1145 int
1146 #ifdef CK_ANSIC
1147 parchk(CHAR *s, CHAR start, int n)
1148 #else
1149 parchk(s,start,n) CHAR *s, start; int n;
1150 #endif /* CK_ANSIC */
1151 /* parchk */ {
1152     CHAR s0, s1, s2, s3;
1153
1154     debug(F101,"parchk n","",n);
1155     debug(F101,"parchk start","",start);
1156
1157     s0 = s[0] & 0x7f;                   /* Mark field (usually Ctrl-A) */
1158
1159     if (s0 != start || n < 5) return(-1); /* Not a valid packet */
1160
1161 /* Look at packet control fields, which never have 8th bit set */
1162 /* First check for no parity, most common case. */
1163
1164     if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0)
1165       return(0);                        /* No parity or space parity */
1166
1167 /* Check for mark parity */
1168
1169     if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80)
1170       return('m');                      /* Mark parity */
1171
1172 /* Packet has some kind of parity */
1173 /* Make 7-bit copies of control fields */
1174
1175     s1 = s[1] & 0x7f;                   /* LEN */
1176     s2 = s[2] & 0x7f;                   /* SEQ */
1177     s3 = s[3] & 0x7f;                   /* TYPE */
1178
1179 /* Check for even parity */
1180
1181     if ((s[0] == p_tbl[s0]) &&
1182         (s[1] == p_tbl[s1]) &&
1183         (s[2] == p_tbl[s2]) &&
1184         (s[3] == p_tbl[s3]))
1185       return('e');
1186
1187 /* Check for odd parity */
1188
1189     if ((s[0] != p_tbl[s0]) &&
1190         (s[1] != p_tbl[s1]) &&
1191         (s[2] != p_tbl[s2]) &&
1192         (s[3] != p_tbl[s3]))
1193       return('o');
1194
1195 /* Otherwise it's probably line noise.  Let checksum calculation catch it. */
1196
1197     return(-1);
1198 }
1199 #endif /* PARSENSE */
1200 \f
1201 /*
1202   Check to make sure timeout intervals are long enough to allow maximum
1203   length packets to get through before the timer goes off.  If not, the
1204   timeout interval is adjusted upwards.
1205
1206   This routine is called at the beginning of a transaction, before we
1207   know anything about the delay characteristics of the line.  It works
1208   only for serial communication devices; it trusts the speed reported by
1209   the operating system.
1210
1211   Call with a timout interval.  Returns it, adjusted if necessary.
1212 */
1213 int
1214 chktimo(timo,flag) int timo, flag; {
1215     long cps, z; int x, y;
1216 #ifdef STREAMING
1217     debug(F101,"chktimo streaming","",streaming);
1218     if (streaming)
1219       return(0);
1220 #endif /* STREAMING */
1221
1222     debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */
1223     debug(F101,"chktimo flag","",flag);
1224
1225     if (flag)                           /* Don't change timeout if user */
1226       return(timo);                     /* gave SET SEND TIMEOUT command. */
1227     debug(F101,"chktimo spmax","",spmax);
1228     debug(F101,"chktimo urpsiz","",urpsiz);
1229
1230     if (!network) {                     /* On serial connections... */
1231         speed = ttgspd();               /* Get current speed. */
1232         if (speed > 0L) {
1233             cps = speed / 10L;          /* Convert to chars per second */
1234             if (cps > 0L) {
1235                 long plen;              /* Maximum of send and rcv pkt size */
1236                 z = cps * (long) timo;  /* Chars per timeout interval */
1237                 z -= z / 10L;           /* Less 10 percent */
1238                 plen = spmax;
1239                 if (urpsiz > spmax) plen = urpsiz;
1240                 debug(F101,"chktimo plen","",plen);
1241                 if (z < plen) {         /* Compare with packet size */
1242                     x = (int) ((long) plen / cps); /* Adjust if necessary */
1243                     y = x / 10;         /* Add 10 percent for safety */
1244                     if (y < 2) y = 2;   /* Or 2 seconds, whichever is more */
1245                     x += y;
1246                     if (x > timo)       /* If this is greater than current */
1247                       timo = x;         /* timeout, change the timeout */
1248                     debug(F101,"chktimo new timo","",timo);
1249                 }
1250             }
1251         }
1252     }
1253     return(timo);
1254 }
1255 \f
1256 /*  S P A C K  --  Construct and send a packet  */
1257
1258 /*
1259   spack() sends a packet of the given type, sequence number n, with len data
1260   characters pointed to by d, in either a regular or extended- length packet,
1261   depending on len.  Returns the number of bytes actually sent, or else -1
1262   upon failure.  Uses global npad, padch, mystch, bctu, data.  Leaves packet
1263   fully built and null-terminated for later retransmission by resend().
1264   Updates global sndpktl (send-packet length).
1265
1266   NOTE: The global pointer "data" is assumed to point into the 7th position
1267   of a character array (presumably in packet buffer for the current packet).
1268   It was used by getpkt() to build the packet data field.  spack() fills in
1269   the header to the left of the data pointer (the data pointer is defined
1270   in getsbuf() in ckcfn3.c).  If the address "d" is the same as "data", then
1271   the packet's data field has been built "in place" and need not be copied.
1272 */
1273 int
1274 #ifdef CK_ANSIC
1275 spack(char pkttyp, int n, int len, CHAR *d)
1276 #else
1277 spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d;
1278 #endif /* CK_ANSIC */
1279 /* spack */ {
1280     register int i;
1281     int ix, j, k, x, lp, longpkt, copy, loglen;
1282
1283 #ifdef GFTIMER
1284     CKFLOAT t1 = 0.0, t2 = 0.0;
1285 #endif /* GFTIMER */
1286
1287     register CHAR *cp, *mydata;
1288     unsigned crc;
1289
1290     copy = (d != data);                 /* Flag whether data must be copied  */
1291
1292 #ifdef DEBUG
1293     if (deblog) {                       /* Save lots of function calls! */
1294         debug(F101,"spack n","",n);
1295 #ifdef COMMENT
1296         if (pkttyp != 'D') {            /* Data packets would be too long */
1297             debug(F111,"spack data",data,data);
1298             debug(F111,"spack d",d,d);
1299         }
1300 #endif  /* COMMENT */
1301         debug(F101,"spack len","",len);
1302         debug(F101,"spack copy","",copy);
1303     }
1304 #endif /* DEBUG */
1305
1306     longpkt = (len + bctl + 2) > 94;    /* Decide whether it's a long packet */
1307     mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */
1308     k = sseqtbl[n];                     /* Packet structure info for pkt n */
1309 #ifdef COMMENT
1310 #ifdef DEBUG
1311     if (deblog) {                       /* Save 2 more function calls... */
1312         debug(F101,"spack mydata","",mydata);
1313         debug(F101,"spack sseqtbl[n]","",k);
1314         if (k < 0) {
1315 #ifdef STREAMING
1316             if (!streaming)
1317 #endif /* STREAMING */
1318               debug(F101,"spack sending packet out of window","",n);
1319         }
1320     }
1321 #endif /* DEBUG */
1322 #endif  /* COMMENT */
1323     if (k > -1) {
1324         s_pkt[k].pk_adr = mydata;       /* Remember address of packet. */
1325         s_pkt[k].pk_seq = n;            /* Record sequence number */
1326         s_pkt[k].pk_typ = pkttyp;       /* Record packet type */
1327     }
1328     spktl = 0;                          /* Initialize length of this packet */
1329     i = 0;                              /* and position in packet. */
1330
1331 /* Now fill the packet */
1332
1333     mydata[i++] = mystch;               /* MARK */
1334     lp = i++;                           /* Position of LEN, fill in later */
1335
1336     mydata[i++] = tochar(n);            /* SEQ field */
1337     mydata[i++] = pkttyp;               /* TYPE field */
1338     j = len + bctl;                     /* Length of data + block check */
1339     if (longpkt) {                      /* Long packet? */
1340         int x;                          /* Yes, work around SCO Xenix/286 */
1341 #ifdef CKTUNING
1342         unsigned int chk;
1343 #endif /* CKTUNING */
1344         x = j / 95;                     /* compiler bug... */
1345         mydata[lp] = tochar(0);         /* Set LEN to zero */
1346         mydata[i++] = tochar(x);        /* Extended length, high byte */
1347         mydata[i++] = tochar(j % 95);   /* Extended length, low byte */
1348 #ifdef CKTUNING
1349         /* Header checksum - skip the function calls and loops */
1350           chk = (unsigned) mydata[lp]   +
1351                 (unsigned) mydata[lp+1] +
1352                 (unsigned) mydata[lp+2] +
1353                 (unsigned) mydata[lp+3] +
1354                 (unsigned) mydata[lp+4] ;
1355         mydata[i++] = tochar((CHAR) ((((chk & 0300) >> 6) + chk) & 077));
1356 #else
1357         mydata[i] = '\0';               /* Terminate for header checksum */
1358         mydata[i++] = tochar(chk1(mydata+lp,5));
1359 #endif /* CKTUNING */
1360     } else mydata[lp] = tochar(j+2);    /* Normal LEN */
1361 /*
1362   When sending a file, the data is already in the right place.  If it weren't,
1363   it might make sense to optimize this section by using memcpy or bcopy
1364   (neither of which are portable), but only if our packets were rather long.
1365   When receiving, we're only sending ACKs so it doesn't matter.  So count the
1366   following loop as a sleeping dog.
1367 */
1368     if (copy)                           /* Data field built in place? */
1369       for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */
1370     else                                /* Otherwise, */
1371       i += len;                         /* Just skip past data field. */
1372     mydata[i] = '\0';                   /* Null-terminate for checksum calc. */
1373
1374     switch (bctu) {                     /* Block check */
1375         case 1:                         /* 1 = 6-bit chksum */
1376             ix = i - lp;                /* Avoid "order of operation" error */
1377             mydata[i++] = tochar(chk1(mydata+lp,ix));
1378             break;
1379         case 2:                         /* 2 = 12-bit chksum */
1380             j = chk2(mydata+lp,i-lp);
1381             mydata[i++] = (unsigned)tochar((j >> 6) & 077);
1382             mydata[i++] = (unsigned)tochar(j & 077);
1383             break;
1384         case 3:                         /* 3 = 16-bit CRC */
1385             crc = chk3(mydata+lp,i-lp);
1386             mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12);
1387             mydata[i++] = (unsigned)tochar((crc >> 6) & 077);
1388             mydata[i++] = (unsigned)tochar(crc & 077);
1389             break;
1390         case 4:                         /* 2 = 12-bit chksum, blank-free */
1391             j = chk2(mydata+lp,i-lp);
1392             mydata[i++] =
1393               (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1)));
1394             mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1)));
1395             break;
1396     }
1397     loglen = i;
1398     mydata[i++] = seol;                 /* End of line (packet terminator) */
1399 #ifdef TCPSOCKET
1400 /*
1401   If TELNET connection and packet terminator is carriage return,
1402   we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE
1403   (tn_nlm), to meet the TELNET NVT specification, unless user said RAW.
1404
1405   If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL
1406   on a NVT connection and CR on a binary connection.
1407 */
1408     if (
1409 #ifdef STREAMING
1410         !dontsend &&
1411 #endif /* STREAMING */
1412         ((network && ttnproto == NP_TELNET) || (!local && sstelnet))
1413         && seol == CR) {
1414         switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
1415           case TNL_CR:                  /* NVT or BINARY */
1416             break;
1417           case TNL_CRNUL:
1418             mydata[i++] = NUL;
1419             break;
1420           case TNL_CRLF:
1421             mydata[i++] = LF;
1422             break;
1423         }
1424     }
1425 #endif /* TCPSOCKET */
1426     mydata[i] = '\0';                   /* Terminate string */
1427     if (
1428 #ifdef STREAMING
1429         !dontsend &&
1430 #endif /* STREAMING */
1431         pktlog
1432         )                               /* Save a function call! */
1433       logpkt('s',n,mydata,loglen);      /* Log the packet */
1434
1435     /* (PWP) add the parity quickly at the end */
1436     if (parity) {
1437         switch (parity) {
1438           case 'e':                     /* Even */
1439             for (cp = &mydata[i-1]; cp >= mydata; cp--)
1440               *cp = p_tbl[*cp];
1441             break;
1442           case 'm':                     /* Mark */
1443             for (cp = &mydata[i-1]; cp >= mydata; cp--)
1444               *cp |= 128;
1445             break;
1446           case 'o':                     /* Odd */
1447             for (cp = &mydata[i-1]; cp >= mydata; cp--)
1448               *cp = p_tbl[*cp] ^ 128;
1449             break;
1450           case 's':                     /* Space */
1451             for (cp = &mydata[i-1]; cp >= mydata; cp--)
1452               *cp &= 127;
1453             break;
1454         }
1455     }
1456     if (pktpaus) msleep(pktpaus);       /* Pause if requested */
1457     x = 0;
1458
1459     if (npad) {
1460 #ifdef STREAMING
1461         if (dontsend)
1462           x = 0;
1463         else
1464 #endif /* STREAMING */
1465           x = ttol(padbuf,npad);        /* Send any padding */
1466     }
1467     if (x > -1) {
1468 #ifdef CK_TIMERS
1469         if (timint > 0) {
1470             if (pkttyp == 'N')
1471               srttbl[n > 0 ? n-1 : 63] = gtimer();
1472             else
1473               srttbl[n] = gtimer();
1474         }
1475 #endif /* CK_TIMERS */
1476         spktl = i;                      /* Remember packet length */
1477         if (k > -1)
1478           s_pkt[k].pk_len = spktl;      /* also in packet info structure */
1479
1480 #ifdef DEBUG
1481 #ifdef GFTIMER
1482 /*
1483   This code shows (in the debug log) how long it takes write() to execute.
1484   Sometimes on a congested TCP connection, it can surprise you -- 90 seconds
1485   or more...
1486 */
1487         if (
1488 #ifdef STREAMING
1489             !dontsend &&
1490 #endif /* STREAMING */
1491             deblog
1492             )
1493           t1 = gftimer();
1494 #endif /* GFTIMER */
1495 #endif /* DEBUG */
1496
1497 #ifdef STREAMING
1498         if (dontsend) {
1499             debug(F000,"STREAMING spack skipping","",pkttyp);
1500             x = 0;
1501         } else
1502 #endif /* STREAMING */
1503         x = ttol(mydata,spktl);         /* Send the packet */
1504     }
1505 #ifdef STREAMING
1506     if (!dontsend) {
1507 #endif /* STREAMING */
1508         debug(F101,"spack spktl","",spktl);
1509         debug(F101,"spack ttol returns","",x);
1510         if (x < 0) {                    /* Failed. */
1511             if (local && x < -1) {
1512                 xxscreen(SCR_ST,ST_ERR,0L,"FAILED: Connection lost");
1513                 /* We can't send an E packet because the connection is lost. */
1514                 epktsent = 1;           /* So pretend we sent one. */
1515                 fatalio = 1;            /* Remember we got a fatal i/o error */
1516                 dologend();
1517                 ckstrncpy((char *)epktmsg,"Connection lost",PKTMSGLEN);
1518             }
1519             return(x);
1520         }
1521         if (spktl > maxsend)            /* Keep track of longest packet sent */
1522           maxsend = spktl;
1523 #ifdef DEBUG
1524 #ifdef GFTIMER
1525         if (deblog)  {                  /* Log elapsed time for write() */
1526             t2 = gftimer();
1527             debug(F101,"spack ttol msec","",(long)((t2-t1)*1000.0));
1528         }
1529 #endif /* GFTIMER */
1530 #endif /* DEBUG */
1531 #ifdef STREAMING
1532     }
1533 #endif /* STREAMING */
1534
1535     sndtyp = pkttyp;                    /* Remember packet type for echos */
1536 #ifdef STREAMING
1537     if (!dontsend) {                    /* If really sent, */
1538         spackets++;                     /* count it. */
1539         flco += spktl;                  /* Count the characters */
1540         tlco += spktl;                  /* for statistics... */
1541 #ifdef DEBUG
1542         if (deblog) {                   /* Save two function calls! */
1543             dumpsbuf();                 /* Dump send buffers to debug log */
1544             debug(F111,"spack calling screen, mydata=",mydata,n);
1545         }
1546 #endif /* DEBUG */
1547     }
1548 #endif /* STREAMING */
1549     if (local) {
1550         int x = 0;
1551         if (fdispla != XYFD_N) x = 1;
1552         if ((fdispla == XYFD_B) && (pkttyp == 'D' || pkttyp == 'Y')) x = 0;
1553         if (x)
1554           xxscreen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */
1555     }
1556     return(spktl);                      /* Return length */
1557 }
1558
1559 /*  C H K 1  --  Compute a type-1 Kermit 6-bit checksum.  */
1560
1561 int
1562 chk1(pkt,len) register CHAR *pkt; register int len; {
1563     register unsigned int chk;
1564 #ifdef CKTUNING
1565 #ifdef COMMENT
1566     register unsigned int m;            /* Avoid function call */
1567     m = (parity) ? 0177 : 0377;
1568     for (chk = 0; len-- > 0; pkt++)
1569       chk += *pkt & m;
1570 #else
1571     chk = 0;
1572     while (len-- > 0) chk += (unsigned) *pkt++;
1573 #endif /* COMMENT */
1574 #else
1575     chk = chk2(pkt,len);
1576 #endif /* CKTUNING */
1577     chk = (((chk & 0300) >> 6) + chk) & 077;
1578     debug(F101,"chk1","",chk);
1579     return((int) chk);
1580 }
1581
1582 /*  C H K 2  --  Compute the numeric sum of all the bytes in the packet.  */
1583
1584 unsigned int
1585 chk2(pkt,len) register CHAR *pkt; register int len; {
1586     register long chk;
1587 #ifdef COMMENT
1588     register unsigned int m;
1589     m = (parity) ? 0177 : 0377;
1590     for (chk = 0; len-- > 0; pkt++)
1591       chk += *pkt & m;
1592 #else
1593     /* Parity has already been stripped */
1594     chk = 0L;
1595     while (len-- > 0) chk += (unsigned) *pkt++;
1596 #endif /* COMMENT */
1597     debug(F101,"chk2","",(unsigned int) (chk & 07777));
1598     return((unsigned int) (chk & 07777));
1599 }
1600
1601 /*  C H K 3  --  Compute a type-3 Kermit block check.  */
1602 /*
1603  Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup
1604  table.  Assumes the argument string contains no embedded nulls.
1605 */
1606 #ifdef COMMENT
1607 unsigned int
1608 chk3(pkt,parity,len) register CHAR *pkt; int parity; register int len; {
1609     register long c, crc;
1610     register unsigned int m;
1611     m = (parity) ? 0177 : 0377;
1612     for (crc = 0; len-- > 0; pkt++) {
1613         c = crc ^ (long)(*pkt & m);
1614         crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
1615     }
1616     return((unsigned int) (crc & 0xFFFF));
1617 }
1618 #else
1619 unsigned int
1620 chk3(pkt,len) register CHAR *pkt; register int len; {
1621     register long c, crc;
1622     for (crc = 0; len-- > 0; pkt++) {
1623         c = crc ^ (long)(*pkt);
1624         crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
1625     }
1626     debug(F101,"chk3","",(unsigned int) (crc & 0xFFFF));
1627     return((unsigned int) (crc & 0xFFFF));
1628 }
1629 #endif /* COMMENT */
1630
1631 /*  N X T P K T  --  Next Packet  */
1632 /*
1633   Get packet number of next packet to send and allocate a buffer for it.
1634   Returns:
1635     0 on success, with global pktnum set to the packet number;
1636    -1 on failure to allocate buffer (fatal);
1637    -2 if resulting packet number is outside the current window.
1638 */
1639 int
1640 nxtpkt() {                              /* Called by file sender */
1641     int j, n, x;
1642
1643     debug(F101,"nxtpkt pktnum","",pktnum);
1644     debug(F101,"nxtpkt winlo ","",winlo);
1645     n = (pktnum + 1) % 64;              /* Increment packet number mod 64 */
1646     debug(F101,"nxtpkt n","",n);
1647 #ifdef STREAMING
1648     if (!streaming) {
1649         x = chkwin(n,winlo,wslots);     /* Don't exceed window boundary */
1650         debug(F101,"nxtpkt chkwin","",x);
1651         if (x)
1652           return(-2);
1653         j = getsbuf(n);                 /* Get a buffer for packet n */
1654         if (j < 0) {
1655             debug(F101,"nxtpkt getsbuf failure","",j);
1656             return(-1);
1657         }
1658     }
1659 #endif /* STREAMING */
1660     pktnum = n;
1661     return(0);
1662 }
1663
1664 /* Functions for sending ACKs and NAKs */
1665
1666 /* Note, we should only ACK the packet at window-low (winlo) */
1667 /* However, if an old packet arrives again (e.g. because the ACK we sent */
1668 /* earlier was lost), we ACK it again. */
1669
1670 int
1671 ack() {                                 /* Acknowledge the current packet. */
1672     return(ackns(winlo,(CHAR *)""));
1673 }
1674
1675 #ifdef STREAMING
1676 int
1677 fastack() {                             /* Acknowledge packet n */
1678     int j, k, n, x;
1679     n = winlo;
1680
1681     k = rseqtbl[n];                     /* First find received packet n. */
1682     debug(F101,"STREAMING fastack k","",k);
1683     freesbuf(n);                        /* Free current send-buffer, if any */
1684     if ((j = getsbuf(n)) < 0) {
1685         /* This can happen if we have to re-ACK an old packet that has */
1686         /* already left the window.  It does no harm. */
1687         debug(F101,"STREAMING fastack can't getsbuf","",n);
1688     }
1689     dontsend = 1;
1690     x = spack('Y',n,0,(CHAR *)"");      /* Now send it (but not really) */
1691     dontsend = 0;
1692     if (x < 0) return(x);
1693     debug(F101,"STREAMING fastack x","",x);
1694     if (k > -1)
1695       freerbuf(k);                      /* don't need it any more */
1696     if (j > -1)
1697       freesbuf(j);                      /* and don't need to keep ACK either */
1698     winlo = (winlo + 1) % 64;
1699     return(0);
1700 }
1701 #endif /* STREAMING */
1702
1703 int
1704 ackns(n,s) int n; CHAR *s; {            /* Acknowledge packet n */
1705     int j, k, x;
1706     debug(F111,"ackns",s,n);
1707
1708     k = rseqtbl[n];                     /* First find received packet n. */
1709     debug(F101,"ackns k","",k);
1710     freesbuf(n);                        /* Free current send-buffer, if any */
1711     if ((j = getsbuf(n)) < 0) {
1712         /* This can happen if we have to re-ACK an old packet that has */
1713         /* already left the window.  It does no harm. */
1714         debug(F101,"ackns can't getsbuf","",n);
1715     }
1716     x = spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */
1717     if (x < 0) return(x);
1718     debug(F101,"ackns winlo","",winlo);
1719     debug(F101,"ackns n","",n);
1720     if (n == winlo) {                   /* If we're acking winlo */
1721         if (k > -1)
1722           freerbuf(k);                  /* don't need it any more */
1723         if (j > -1)
1724           freesbuf(j);                  /* and don't need to keep ACK either */
1725         winlo = (winlo + 1) % 64;
1726     }
1727     return(0);
1728 }
1729
1730 int
1731 ackn(n) int n; {                        /* Send ACK for packet number n */
1732     return(ackns(n,(CHAR *)""));
1733 }
1734
1735 int
1736 ack1(s) CHAR *s; {                      /* Send an ACK with data. */
1737     if (!s) s = (CHAR *)"";
1738     debug(F110,"ack1",(char *)s,0);
1739     return(ackns(winlo,s));
1740 }
1741
1742 /* N A C K  --   Send a Negative ACKnowledgment. */
1743 /*
1744  Call with the packet number, n, to be NAK'd.
1745  Returns -1 if that packet has been NAK'd too many times, otherwise 0.
1746  Btw, it is not right to return 0 under error conditions.  This is
1747  done because the -1 code is used for cancelling the file transfer.
1748  More work is needed here.
1749 */
1750 int
1751 nack(n) int n; {
1752     int i, x;
1753
1754     if (n < 0 || n > 63) {
1755         debug(F101,"nack bad pkt num","",n);
1756         return(0);
1757     } else debug(F101,"nack","",n);
1758     if ((i = sseqtbl[n]) < 0) {         /* If necessary */
1759         if (getsbuf(n) < 0) {           /* get a buffer for this NAK */
1760             debug(F101,"nack can't getsbuf","",n);
1761             return(0);
1762         } else i = sseqtbl[n];          /* New slot number */
1763     }
1764     if (maxtry > 0 && s_pkt[i].pk_rtr++ > maxtry) /* How many? */
1765       return(-1);                       /* Too many... */
1766
1767 /* Note, don't free this buffer.  Eventually an ACK will come, and that */
1768 /* will set it free.  If not, well, it's back to ground zero anyway...  */
1769
1770     x = spack('N',n,0,(CHAR *) "");     /* NAKs never have data. */
1771     return(x);
1772 }
1773
1774 #ifndef NEWDPL                          /* This routine no longer used */
1775 /*
1776  * (PWP) recalculate the optimal packet length in the face of errors.
1777  * This is a modified version of the algorithm by John Chandler in Kermit/370,
1778  * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988.
1779  *
1780  * This implementation minimizes the total overhead equation, which is
1781  *
1782  *   Total chars = file_chars + (header_len * num_packs)
1783  *                            + (errors * (header_len + packet_len))
1784  *
1785  * Differentiate with respect to number of chars, solve for packet_len, get:
1786  *
1787  *   packet_len = sqrt (file_chars * header_len / errors)
1788  */
1789
1790 /*
1791  (FDC) New super-simple algorithm.  If there was an error in the most recent
1792  packet exchange, cut the send-packet size in half, down to a minimum of 20.
1793  If there was no error, increase the size by 5/4, up to the maximum negotiated
1794  length.  Seems to be much more responsive than previous algorithm, which took
1795  forever to recover the original packet length, and it also went crazy under
1796  certain conditions.
1797
1798  Here's another idea for packet length resizing that keeps a history of the
1799  last n packets.  Push a 1 into the left end of an n-bit shift register if the
1800  current packet is good, otherwise push a zero.  The current n-bit value, w, of
1801  this register is a weighted sum of the noise hits for the last n packets, with
1802  the most recent weighing the most.  The current packet length is some function
1803  of w and the negotiated packet length, like:
1804
1805    (2^n - w) / (2^n) * (negotiated length)
1806
1807  If the present resizing method causes problems, think about this one a little
1808  more.
1809 */
1810 VOID
1811 rcalcpsz() {
1812
1813 #ifdef COMMENT
1814 /* Old way */
1815     register long x, q;
1816     if (numerrs == 0) return;           /* bounds check just in case */
1817
1818     /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */
1819     /* an ACK is 5+bctr */
1820
1821     /* first set x = per packet overhead */
1822     if (wslots > 1)                     /* Sliding windows */
1823       x = (long) (npad+5+bctr);         /* packet only, don't count ack */
1824     else                                /* Stop-n-wait */
1825       x = (long) (npad+5+3+bctr+5+bctr); /* count packet and ack. */
1826
1827     /* then set x = packet length ** 2 */
1828     x = x * ( ffc / (CK_OFF_T) numerrs); /* careful of overflow */
1829
1830     /* calculate the long integer sqrt(x) quickly */
1831     q = 500;
1832     q = (q + x/q) >> 1;
1833     q = (q + x/q) >> 1;
1834     q = (q + x/q) >> 1;
1835     q = (q + x/q) >> 1;         /* should converge in about 4 steps */
1836     if ((q > 94) && (q < 130))  /* break-even point for long packets */
1837       q = 94;
1838     if (q > spmax) q = spmax;   /* maximum bounds */
1839     if (q < 10) q = 10;         /* minimum bounds */
1840     spsiz = q;                  /* set new send packet size */
1841     debug(F101,"rcalcpsiz","",q);
1842 #else
1843 /* New way */
1844     debug(F101,"rcalcpsiz numerrs","",numerrs);
1845     debug(F101,"rcalcpsiz spsiz","",spsiz);
1846     if (spackets < 3) {
1847         numerrs = 0;
1848         return;
1849     }
1850     if (numerrs)
1851       spsiz = spsiz / 2;
1852     else
1853       spsiz = (spsiz / 4) * 5;
1854     if (spsiz < 20) spsiz = 20;
1855     if (spsiz > spmax) spsiz = spmax;
1856     debug(F101,"rcalcpsiz new spsiz","",spsiz);
1857     numerrs = 0;
1858 #endif /* COMMENT */
1859 }
1860 #endif /* NEWDPL */
1861
1862 /*  R E S E N D  --  Retransmit packet n.  */
1863
1864 /*
1865   Returns 0 or positive on success (the number of retries for packet n).
1866   On failure, returns a negative number, and an error message is placed
1867   in recpkt.
1868 */
1869 int
1870 resend(n) int n; {                      /* Send packet n again. */
1871     int j, k, x;
1872 #ifdef GFTIMER
1873     CKFLOAT t1 = 0.0, t2 = 0.0;
1874 #endif /* GFTIMER */
1875
1876     debug(F101,"resend seq","",n);
1877
1878     k = chkwin(n,winlo,wslots);         /* See if packet in current window */
1879     j = -1;                             /* Assume it's lost */
1880     if (k == 0) j = sseqtbl[n];         /* See if we still have a copy of it */
1881     if (k != 0 || j < 0) {              /* If not.... */
1882         if (nakstate && k == 1) {
1883 /*
1884   Packet n is in the previous window and we are the file receiver.
1885   We already sent the ACK and deallocated its buffer so we can't just
1886   retransmit the ACK.  Rather than give up, we try some tricks...
1887 */
1888             if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */
1889 /*
1890   If the packet number is 0, and we're at the beginning of a protocol
1891   operation (spackets < 63), then we have to resend the ACK to an I or S
1892   packet, complete with parameters in the data field.  So we take a chance and
1893   send a copy of the parameters in an ACK packet with block check type 1.
1894   (Or 3 if SET BLOCK 5.)
1895 */
1896                 if (bctf) {             /* Force Type 3 on all packets? */
1897                    x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
1898                     if (x < 0) return(x);
1899                     logpkt('#',n,(CHAR *)"<reconstructed>",0); /* Log it */
1900                 } else {                /* Regular Kermit protocol */
1901                     int bctlsav;        /* Temporary storage */
1902                     int bctusav;
1903                     bctlsav = bctl;     /* Save current block check length */
1904                     bctusav = bctu;     /* and type */
1905                     bctu = bctl = 1;    /* Set block check to 1 */
1906                    x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
1907                     if (x < 0) return(x);
1908                     logpkt('#',n,(CHAR *)"<reconstructed>",0); /* Log it */
1909                     bctu = bctusav;     /* Restore block check type */
1910                     bctl = bctlsav;     /* and length */
1911                 }
1912             } else {                    /* Not the first packet */
1913 /*
1914   It's not the first packet of the protocol operation.  It's some other packet
1915   that we have already ACK'd and forgotten about.  So we take a chance and
1916   send an empty ACK using the current block-check type.  Usually this will
1917   work out OK (like when acking Data packets), and no great harm will be done
1918   if it was some other kind of packet (F, etc).  If we are requesting an
1919   interruption of the file transfer, the flags are still set, so we'll catch
1920   up on the next packet.
1921 */
1922                 x = spack('Y',n,0,(CHAR *) "");
1923                 if (x < 0) return(x);
1924             }
1925             retrans++;
1926             xxscreen(SCR_PT,'%',(long)pktnum,"Retransmission");
1927             return(0);
1928         } else {
1929 /*
1930   Packet number is not in current or previous window.  We seem to hit this
1931   code occasionally at the beginning of a transaction, for apparently no good
1932   reason.  Let's just log it for debugging, send nothing, and try to proceed
1933   with the protocol rather than killing it.
1934 */
1935             debug(F101,"resend PKT NOT IN WINDOW","",n);
1936             debug(F101,"resend k","",k);
1937             return(0);
1938         }
1939     }
1940
1941 /* OK, it's in the window and it's not lost. */
1942
1943     debug(F101,"resend pktinfo index","",k);
1944
1945     if (maxtry > 0 && s_pkt[j].pk_rtr++ > maxtry) { /* Over retry limit */
1946         xitsta |= what;
1947         return(-1);
1948     }
1949     debug(F101,"resend retry","",s_pkt[j].pk_rtr); /* OK so far */
1950     dumpsbuf();                         /* (debugging) */
1951     if (s_pkt[j].pk_typ == ' ') {       /* Incompletely formed packet */
1952         if (nakstate) {                 /* (This shouldn't happen any more) */
1953             nack(n);
1954             retrans++;
1955             xxscreen(SCR_PT,'%',(long)pktnum,"(resend)");
1956             return(s_pkt[j].pk_rtr);
1957         } else {                        /* No packet to resend! */
1958 #ifdef COMMENT
1959 /*
1960   This happened (once) while sending a file with 2 window slots and typing
1961   X to the sender to cancel the file.  But since we're cancelling anyway,
1962   there's no need to give a scary message.
1963 */
1964             sprintf((char *)epktmsg,
1965                     "resend logic error: NPS, n=%d, j=%d.",n,j);
1966             return(-2);
1967 #else
1968 /* Just ignore it. */
1969             return(0);
1970 #endif /* COMMENT */
1971         }
1972     }
1973 #ifdef DEBUG
1974 #ifdef GFTIMER
1975     if (deblog) t1 = gftimer();
1976 #endif /* GFTIMER */
1977 #endif /* DEBUG */
1978
1979     /* Everything ok, send the packet */
1980 #ifdef CK_TIMERS
1981     if (timint > 0)
1982       srttbl[n] = gtimer();             /* Update the timer */
1983 #endif /* CK_TIMERS */
1984     x = ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len);
1985
1986 #ifdef DEBUG
1987 #ifdef GFTIMER
1988     if (deblog)  {
1989         t2 = gftimer();
1990         debug(F101,"resend ttol msec","",(long)((t2-t1)*1000.0));
1991     }
1992 #endif /* GFTIMER */
1993 #endif /* DEBUG */
1994     debug(F101,"resend ttol returns","",x);
1995
1996     retrans++;                          /* Count a retransmission */
1997     xxscreen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */
1998     logpkt('S',n,s_pkt[j].pk_adr, s_pkt[j].pk_len); /* Log the resent packet */
1999     return(s_pkt[j].pk_rtr);            /* Return the number of retries. */
2000 }
2001
2002 /*  E R R P K T  --  Send an Error Packet  */
2003
2004 int
2005 errpkt(reason) CHAR *reason; {          /* ...containing the reason given */
2006     extern int rtimo, state, justone;
2007     int x, y;
2008     czseen = 1;                         /* Also cancels batch */
2009     state = 0;                          /* Reset protocol state */
2010     debug(F110,"errpkt",reason,0);
2011     tlog(F110,"Protocol Error:",(char *)reason,0L);
2012     xxscreen(SCR_EM,0,0L,reason);
2013     encstr(reason);
2014     x = spack('E',pktnum,size,data);
2015     ckstrncpy((char *)epktmsg,(char *)reason,PKTMSGLEN);
2016     y = quiet; quiet = 1; epktsent = 1; /* Close files silently. */
2017     clsif(); clsof(1);
2018     quiet = y;
2019 /*
2020   I just sent an E-packet.  I'm in local mode, I was receiving a file,
2021   I'm not a server, and sliding windows are in use.  Therefore, there are
2022   likely to be a bunch of packets already "in the pipe" on their way to me
2023   by the time the remote sender gets the E-packet.  So the next time I
2024   CONNECT or try to start another protocol operation, I am likely to become
2025   terribly confused by torrents of incoming material.  To prevent this,
2026   the following code soaks up packets from the connection until there is an
2027   error or timeout, without wasting too much time waiting.
2028
2029   Exactly the same problem occurs when I am in remote mode or if I am
2030   in server mode with the justone flag set.  In remote mode not only
2031   does the packet data potentially get echo'd back to the sender which
2032   is confusing to the user in CONNECT mode, but it also may result in the
2033   host performing bizarre actions such as suspending the process if ^Z is
2034   unprefixed, etc.
2035
2036   Furthermore, thousands of packets bytes in the data stream prevent the
2037   client from being able to process Telnet Kermit Option negotiations
2038   properly.
2039 */
2040 #ifdef STREAMING
2041     /* Because streaming sets the timeout to 0... */
2042     if (streaming) {
2043         timint = rcvtimo = rtimo;
2044         streaming = 0;
2045     }
2046 #endif /* STREAMING */
2047     if (what & W_RECV &&
2048         (!server || (server && justone)) &&
2049         (wslots > 1
2050 #ifdef STREAMING
2051          || streaming
2052 #endif /* STREAMING */
2053          )) {
2054 #ifdef GFTIMER
2055         CKFLOAT oldsec, sec = (CKFLOAT) 0.0;
2056 #else
2057         int oldsec, sec = 0;
2058 #endif /* GFTIMER */
2059         debug(F101,"errpkt draining","",wslots);
2060         xxscreen(SCR_ST,ST_MSG,0l,"Draining incoming packets, wait...");
2061         while (x > -1) {                /* Don't bother if no connection */
2062             oldsec = sec;
2063 #ifdef GFTIMER
2064             sec = gftimer();
2065             if (oldsec != (CKFLOAT) 0.0)
2066               timint = rcvtimo = (int) (sec - oldsec + 0.5);
2067 #else
2068             sec = gtimer();
2069             if (oldsec != 0)
2070               timint = rcvtimo = sec - oldsec + 1;
2071 #endif /* GFTIMER */
2072             if (timint < 1)
2073               timint = rcvtimo = 1;
2074             msleep(50);                 /* Allow a bit of slop */
2075             x = rpack();                /* Read a packet */
2076             if (x == 'T' || x == 'z')   /* Timed out means we're done */
2077               break;
2078             xxscreen(SCR_PT,x,rsn,"");  /* Let user know */
2079         }
2080         xxscreen(SCR_ST,ST_MSG,0l,"Drain complete.");
2081     }
2082     if ((x = (what & W_KERMIT)))
2083       xitsta |= x;                      /* Remember what failed. */
2084     success = 0;
2085     return(y);
2086 }
2087
2088 /* scmd()  --  Send a packet of the given type */
2089
2090 int
2091 #ifdef CK_ANSIC
2092 scmd(char t, CHAR *dat)
2093 #else
2094 scmd(t,dat) char t; CHAR *dat;
2095 #endif /* CK_ANSIC */
2096 /* scmd */ {
2097     int x;
2098     extern char * srimsg;
2099     debug(F000,"scmd",dat,t);
2100     if (encstr(dat) < 0) {              /* Encode the command string */
2101         srimsg = "String too long";
2102         return(-1);
2103     }
2104     x = spack(t,pktnum,size,data);
2105     debug(F101,"scmd spack","",x);
2106     return(x);
2107 }
2108
2109 /* Compose and Send GET packet */
2110
2111 struct opktparm {                       /* O-Packet item list */
2112     CHAR * opktitem;
2113     struct opktparm * opktnext;
2114 };
2115
2116 struct opktparm * opkthead = NULL;      /* Linked list of O-packet fields */
2117 int opktcnt = 0;                        /* O-Packet counter */
2118 char * srimsg = NULL;                   /* GET-Packet error message */
2119
2120 /* S O P K T  --  Send O-Packet */
2121 /*
2122   Sends one O-Packet each time called, using first-fit method of filling
2123   the packet from linked list of parameters pointed to by opkthead.
2124   To be called repeatedly until list is empty or there is an error.
2125   Returns:
2126    -1 on failure.
2127     0 on success and no more fields left to send.
2128     1 on success but with more fields left to be sent.
2129 */
2130
2131 int
2132 sopkt() {
2133     int n = 0;                          /* Field number in this packet */
2134     int rc = 0;                         /* Return code */
2135     int len = 0;                        /* Data field length */
2136     char c = NUL;
2137     struct opktparm * o = NULL;
2138     struct opktparm * t = NULL;
2139     struct opktparm * prev = NULL;
2140     CHAR * dsave = data;
2141     int x, ssave = spsiz;
2142
2143     srimsg = NULL;                      /* Error message */
2144     o = opkthead;                       /* Point to head of list */
2145     if (!o) {                           /* Oops, no list... */
2146         srimsg = "GET Packet Internal Error 1";
2147         debug(F100,"sopkt NULL list","",0);
2148         return(-1);
2149     }
2150     while (o) {                         /* Go thru linked list... */
2151         c = *(o->opktitem);             /* Parameter code */
2152         debug(F000,"sopkt",o->opktitem,c);
2153         x = encstr((CHAR *)o->opktitem);
2154         debug(F111,"sopkt encstr",dsave,x);
2155         if (x < 0) {                    /* Encode this item */
2156             if (n == 0) {               /* Failure, first field in packet */
2157                 debug(F100,"sopkt overflow","",0);
2158                 spsiz = ssave;          /* Restore these */
2159                 data = dsave;
2160                 o = opkthead;           /* Free linked list */
2161                 while (o) {
2162                     if (o->opktitem) free(o->opktitem);
2163                     t = o->opktnext;
2164                     free((char *)o);
2165                     o = t;
2166                 }
2167                 opkthead = NULL;
2168                 srimsg = "GET Packet Too Long for Server";
2169                 return(-1);             /* Fail */
2170             } else {                    /* Not first field in packet */
2171                 debug(F110,"sopkt leftover",o->opktitem,0);
2172                 prev = o;               /* Make this one the new previous */
2173                 o = o->opktnext;        /* Get next */
2174                 c = NUL;                /* So we know we're not done */
2175                 *data = NUL;            /* Erase any partial encoding */
2176                 continue;               /* We can try this one again later */
2177             }
2178         }
2179         n++;                            /* Encoding was successful */
2180         debug(F111,"sopkt field",data,x);
2181         len += x;                       /* Total data field length */
2182         data += x;                      /* Set up for next field... */
2183         spsiz -= x;
2184         free(o->opktitem);              /* Free item just encoded */
2185         if (o == opkthead) {            /* If head */
2186             opkthead = o->opktnext;     /* Move head to next */
2187             free((char *)o);            /* Free this list node */
2188             o = opkthead;
2189         } else {                        /* If not head */
2190             o = o->opktnext;            /* Get next */
2191             prev->opktnext = o;         /* Link previous to next */
2192         }
2193         if (c == '@')                   /* Loop exit */
2194           break;
2195         if (!o && !opkthead) {          /* Set up End Of Parameters Field */
2196             o = (struct opktparm *)malloc(sizeof(struct opktparm));
2197             if (o) {
2198                 opkthead = o;
2199                 if (!(o->opktitem = (CHAR *)malloc(3))) {
2200                     free((char *)o);
2201                     srimsg = "GET Packet Internal Error 8";
2202                     return(-1);
2203                 }
2204                 ckstrncpy((char *)(o->opktitem), "@ ", 3);
2205                 debug(F111,"sopkt o->opktitem",o->opktitem,
2206                       strlen((char *)(o->opktitem)));
2207                 o->opktnext = NULL;
2208             }
2209         }
2210     }
2211     data = dsave;                       /* Restore globals */
2212     spsiz = ssave;
2213     debug(F110,"sopkt data",data,0);
2214     debug(F101,"sopkt opktcnt","",opktcnt);
2215     if (opktcnt++ > 0) {
2216         if (nxtpkt() < 0) {             /* Get next packet number and buffer */
2217             srimsg = "GET Packet Internal Error 9";
2218             return(-1);
2219         }
2220     }
2221     debug(F101,"sopkt pktnum","",pktnum);
2222     rc = spack((char)'O',pktnum,len,data); /* Send O-Packet */
2223     debug(F101,"sopkt spack","",rc);
2224     if (rc < 0)                         /* Failed */
2225       srimsg = "Send Packet Failure";   /* Set message */
2226     else                                /* Succeeded */
2227       rc = (c == '@') ? 0 : 1;          /* 1 = come back for more, 0 = done */
2228     debug(F101,"sopkt rc","",rc);
2229     return(rc);
2230 }
2231
2232 /* S R I N I T  --  Send GET packet  */
2233 /*
2234   Sends the appropriate GET-Class packet.
2235   Returns:
2236   -1 on error
2237    0 if packet sent successfully and we can move on to the next state
2238    1 if an O-packet was sent OK but more O packets still need to be sent.
2239 */
2240 int
2241 srinit(reget, retrieve, opkt) int reget, retrieve, opkt; {
2242     int x = 0, left = 0;
2243     extern int oopts, omode;
2244     CHAR * p = NULL;
2245 #ifdef RECURSIVE
2246     extern int recursive;
2247     debug(F101,"srinit recursive","",recursive);
2248 #endif /* RECURSIVE */
2249     debug(F101,"srinit reget","",reget);
2250     debug(F101,"srinit retrieve","",retrieve);
2251     debug(F101,"srinit opkt","",opkt);
2252     debug(F101,"srinit oopts","",oopts);
2253     debug(F101,"srinit omode","",omode);
2254     debug(F110,"srinit cmarg",cmarg,0);
2255     srimsg = NULL;
2256
2257     opktcnt = 0;
2258     if (!cmarg) cmarg = "";
2259     if (!*cmarg) {
2260         srimsg = "GET with no filename";
2261         debug(F100,"srinit null cmarg","",0);
2262         return(-1);
2263     }
2264     if (opkt) {                         /* Extended GET is totally different */
2265         char buf[16];
2266         struct opktparm * o = NULL;
2267         struct opktparm * prev = NULL;
2268
2269         buf[0] = NUL;
2270
2271         /* Build O-Packet fields and send (perhaps first) O-Packet */
2272
2273         if (oopts > -1) {               /* Write Option flags */
2274             o = (struct opktparm *)malloc(sizeof(struct opktparm));
2275             if (!o) {
2276                 srimsg = "GET Packet Internal Error 2";
2277                 debug(F100,"srinit malloc fail O1","",0);
2278                 return(-1);
2279             }
2280             sprintf(buf,"Ox%d",oopts);  /* safe */
2281             x = (int) strlen(buf+2);
2282             buf[1] = tochar(x);
2283             o->opktitem = (CHAR *)malloc(x + 3);
2284             if (!o->opktitem) {
2285                 srimsg = "GET Packet Internal Error 3";
2286                 debug(F100,"srinit malloc fail O2","",0);
2287                 return(-1);
2288             }
2289             ckstrncpy((char *)(o->opktitem),buf,x+3);
2290             o->opktnext = NULL;
2291             if (!opkthead)
2292               opkthead = o;
2293             prev = o;
2294         }
2295         if (omode > -1) {               /* If Xfer Mode specified, write it */
2296             o = (struct opktparm *)malloc(sizeof(struct opktparm));
2297             if (!o) {
2298                 srimsg = "GET Packet Internal Error 4";
2299                 debug(F100,"srinit malloc fail M1","",0);
2300                 return(-1);
2301             }
2302             sprintf(buf,"Mx%d",omode);  /* safe */
2303             x = (int) strlen(buf+2);
2304             buf[1] = tochar(x);
2305             o->opktitem = (CHAR *)malloc(x + 3);
2306             if (!o->opktitem) {
2307                 srimsg = "GET Packet Internal Error 5";
2308                 debug(F100,"srinit malloc fail O2","",0);
2309                 return(-1);
2310             }
2311             ckstrncpy((char *)(o->opktitem),buf,x+3);
2312             o->opktnext = NULL;
2313             if (!opkthead)
2314               opkthead = o;
2315             else
2316               prev->opktnext = o;
2317             prev = o;
2318         }
2319
2320         /* Same deal for oname and opath eventually but not needed now... */
2321
2322         x = strlen(cmarg);              /* Now do filename */
2323         if (x > spsiz - 4) {
2324             srimsg = "GET Packet Too Long for Server";
2325             return(-1);
2326         }
2327         o = (struct opktparm *)malloc(sizeof(struct opktparm));
2328         if (!o) {
2329             srimsg = "GET Packet Internal Error 6";
2330             debug(F100,"srinit malloc fail F1","",0);
2331             return(-1);
2332         }
2333         left = x + 6;
2334         o->opktitem = (CHAR *)malloc(left + 1);
2335         if (!o->opktitem) {
2336             srimsg = "GET Packet Internal Error 7";
2337             debug(F100,"srinit malloc fail F2","",0);
2338             return(-1);
2339         }
2340         p = o->opktitem;
2341         *p++ = 'F';
2342         left--;
2343         if (x > 94) {                   /* Too long for normal length */
2344             *p++ = SYN;                 /* Escape length with Ctrl-V */
2345             *p++ = tochar(x / 95);
2346             *p++ = tochar(x % 95);
2347             left -= 3;
2348         } else {                        /* Normal encoding for 94 or less */
2349             *p++ = tochar(x);
2350             left--;
2351         }
2352         ckstrncpy((char *)p,cmarg,left); /* Copy the filename */
2353         o->opktnext = NULL;
2354         if (!opkthead)
2355           opkthead = o;
2356         else
2357           prev->opktnext = o;
2358         prev = o;
2359
2360         /* End of Parameters */
2361
2362         prev->opktnext = NULL;          /* End of list. */
2363         return(sopkt());
2364     }
2365
2366     /* Not Extended GET */
2367
2368     if (encstr((CHAR *)cmarg) < 0) {    /* Encode the filename. */
2369         srimsg = "GET Packet Too Long for Server";
2370         return(-1);
2371     }
2372     if (retrieve) {                     /* Send the packet. */
2373 #ifdef RECURSIVE
2374         if (recursive)
2375           x = spack((char)'W',pktnum,size,data); /* GET /DELETE /RECURSIVE */
2376         else
2377 #endif /* RECURSIVE */
2378           x = spack((char)'H',pktnum,size,data); /* GET /DELETE */
2379     }
2380 #ifdef RECURSIVE
2381     else if (recursive)
2382       x = spack((char)'V',pktnum,size,data); /* GET /RECURSIVE */
2383 #endif /* RECURSIVE */
2384     else
2385       x = spack((char)(reget ? 'J' : 'R'),pktnum,size,data); /* GET */
2386     if (x < 0)
2387       srimsg = "Send Packet Failure";
2388     return(x < 0 ? x : 0);
2389 }
2390
2391
2392 /*  K S T A R T  --  Checks for a Kermit packet while in terminal mode.  */
2393
2394 /*  (or command mode...)  */
2395
2396 #ifdef CK_AUTODL
2397 int
2398 #ifdef CK_ANSIC
2399 kstart(CHAR ch)
2400 #else
2401 kstart(ch) CHAR ch;
2402 #endif /* CK_ANSIC */
2403 /* kstart */ {
2404     static CHAR * p = NULL;
2405
2406 #ifdef OS2
2407     static CHAR * pk = NULL;
2408 #endif /* OS2 */
2409     ch &= 0177;                         /* Strip 8th bit */
2410
2411     /* Because we're in cooked mode at the command prompt... */
2412
2413     if (ch == LF) {
2414         debug(F110,"kstart","ch == LF",0);
2415         if ((what == W_COMMAND || what == W_INIT || what == W_NOTHING)) {
2416             if (eol == CR) {
2417                 ch = eol;
2418                 debug(F110,"kstart","ch = CR",0);
2419             }
2420         }
2421     }
2422
2423 #ifdef OS2
2424     if (adl_kmode == ADL_STR) {
2425         if (!ch)
2426           return(0);
2427         if (!pk)
2428           pk = adl_kstr;
2429
2430         if (ch == *pk) {
2431             pk++;
2432             if (*pk == '\0') {
2433                 pk = adl_kstr;
2434                 debug(F100, "kstart Kermit Start String","",0);
2435                 return(PROTO_K + 1);
2436             }
2437         } else
2438           pk = adl_kstr;
2439     }
2440 #endif /* OS2 */
2441
2442     if (ch == stchr) {                  /* Start of packet */
2443         kstartactive = 1;
2444         p = ksbuf;
2445         *p = ch;
2446         debug(F101,"kstart SOP","",ch);
2447     } else if (ch == eol) {             /* End of packet */
2448         kstartactive = 0;
2449         if (p) {
2450             debug(F101,"kstart EOL","",ch);
2451             p++;
2452             if (p - ksbuf < 94 ) {
2453                 int rc = 0;
2454                 *p++ = ch;
2455                 *p = NUL;
2456                 rc = chkspkt((char *)ksbuf);
2457                 debug(F111,"kstart EOP chkspkt", ksbuf, rc);
2458                 p = NULL;
2459                 if (!rc) return(0);
2460                 if (rc == 2) rc = -1;
2461                 debug(F111,"kstart ksbuf",ksbuf,rc);
2462                 return(rc);
2463             } else {
2464                 debug(F110,"kstart","p - ksbuf >= 94",0);
2465                 p = NULL;
2466             }
2467         }
2468     } else if (p) {
2469         if (ch < SP)
2470           kstartactive = 0;
2471         p++;
2472         if (p - ksbuf < 94) {
2473             *p = ch;
2474         } else {
2475             p = NULL;
2476             debug(F110,"kstart","p - ksbuf >= 94",0);
2477         }
2478     }
2479     return(0);
2480 }
2481
2482 #ifdef CK_XYZ
2483
2484 /*  Z S T A R T  --  Checks for a ZMODEM packet while in terminal mode.  */
2485
2486 int
2487 #ifdef CK_ANSIC
2488 zstart(CHAR ch)
2489 #else
2490 zstart(ch) CHAR ch;
2491 #endif /* CK_ANSIC */
2492 /* zstart */ {
2493     static CHAR * matchstr = (CHAR *) "\030B00";
2494     /* "rz\r**\030B00000000000000\r\033J\021"; */
2495     static CHAR * p = NULL;
2496     extern int inserver;
2497
2498     if (inserver)
2499       return(0);
2500
2501     if (!ch)
2502       return(0);
2503     if (!p) {
2504 #ifdef OS2
2505         p = adl_zmode == ADL_PACK ? matchstr : adl_zstr;
2506 #else
2507         p = matchstr;
2508 #endif /* OS2 */
2509     }
2510     if (ch == *p) {
2511         p++;
2512         if (*p == '\0') {
2513 #ifdef OS2
2514             if (adl_zmode == ADL_PACK) {
2515                 p = matchstr;
2516                 debug(F100, "zstart Zmodem SOP","",0);
2517             } else {
2518                 p = adl_zstr;
2519                 debug(F100, "zstart Zmodem Start String","",0);
2520             }
2521 #else
2522             p = matchstr;
2523             debug(F100, "zstart Zmodem SOP","",0);
2524 #endif /* OS2 */
2525             return(PROTO_Z + 1);
2526         }
2527     } else {
2528 #ifdef OS2
2529         p = adl_zmode == ADL_PACK ? matchstr : adl_zstr;
2530 #else
2531         p = matchstr;
2532 #endif /* OS2 */
2533     }
2534     return(0);
2535 }
2536 #endif /* CK_XYZ */
2537
2538 #ifndef NOICP
2539 #ifdef CK_APC
2540 /*  A U T O D O W N  */
2541
2542 #ifdef CK_ANSIC
2543 VOID
2544 autodown(int ch)
2545 #else
2546 VOID
2547 autodown(ch) int ch;
2548 #endif /* CK_ANSIC */
2549 /* autodown */ {
2550
2551 /* The Kermit and Zmodem Auto-download calls go here */
2552
2553     extern int justone;                 /* From protocol module */
2554     extern int debses, protocol, apcactive, autodl, inautodl;
2555 #ifdef DCMDBUF
2556     extern char *apcbuf;
2557 #else
2558     extern char apcbuf[];
2559 #endif /* DCMDBUF */
2560 #ifdef OS2
2561     extern int apclength, term_io;
2562 #endif /* OS2 */
2563     int k = 0;
2564
2565     if ((autodl || inautodl
2566 #ifdef IKS_OPTION
2567          || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
2568 #endif /* IKS_OPTION */
2569          ) && !debses) {
2570 #ifdef CK_XYZ
2571 #ifdef XYZ_INTERNAL
2572         extern int p_avail;
2573 #else
2574         int p_avail = 1;
2575 #endif /* XYZ_INTERNAL */
2576         if (p_avail && zstart((CHAR) ch)) {
2577             debug(F100, "Zmodem download","",0);
2578 #ifdef OS2
2579 #ifndef NOTERM
2580             apc_command(APC_LOCAL,"receive /protocol:zmodem");
2581 #endif /* NOTERM */
2582 #else /* OS2 */
2583             ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN);
2584             apcactive = APC_LOCAL;
2585 #endif /* OS2 */
2586             return;
2587         }
2588 #endif /* CK_XYZ */
2589
2590         /* First try... */
2591         k = kstart((CHAR) ch);
2592         if (
2593 #ifdef NOSERVER
2594             k > 0
2595 #else /* NOSERVER */
2596             k
2597 #endif /* NOSERVER */
2598             ) {                         /* We saw a valid S or I packet */
2599             if (k < 0) {                /* Stuff RECEIVE into APC buffer */
2600                 justone = 1;
2601                 switch (protocol) {
2602 #ifdef CK_XYZ
2603                   case PROTO_G:
2604                     ckstrncpy(apcbuf,
2605                               "set proto kermit, server, set protocol g",
2606                               APCBUFLEN
2607                               );
2608                     break;
2609                   case PROTO_X:
2610                     ckstrncpy(apcbuf,
2611                               "set proto kermit,server,set proto xmodem",
2612                               APCBUFLEN
2613                               );
2614                     break;
2615                   case PROTO_XC:
2616                     ckstrncpy(apcbuf,
2617                            "set proto kermit,server,set proto xmodem-crc",
2618                               APCBUFLEN
2619                               );
2620                       break;
2621                   case PROTO_Y:
2622                     ckstrncpy(apcbuf,
2623                               "set proto kermit,server, set protocol y",
2624                               APCBUFLEN
2625                               );
2626                     break;
2627                   case PROTO_Z:
2628                     ckstrncpy(apcbuf,
2629                               "set proto kermit,server,set proto zmodem",
2630                               APCBUFLEN
2631                               );
2632                     break;
2633 #endif /* CK_XYZ */
2634                   case PROTO_K:
2635                     ckstrncpy(apcbuf,"server",APCBUFLEN);
2636                     break;
2637                 }
2638             } else {
2639                 justone = 0;
2640                 ckstrncpy(apcbuf,"receive /protocol:kermit",APCBUFLEN);
2641             }
2642 #ifdef OS2
2643 #ifndef NOTERM
2644             apc_command(APC_LOCAL,apcbuf);
2645 #endif /* NOTERM */
2646 #else /* OS2 */
2647             ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN);
2648             apcactive = APC_LOCAL;
2649 #endif /* OS2 */
2650             return;
2651         }
2652     }
2653 }
2654 #endif /* CK_APC */
2655 #endif /* NOICP */
2656
2657 /*  C H K S P K T  --  Check if buf contains a valid S or I packet  */
2658
2659 int
2660 chkspkt(packet) char *packet; {
2661     int i;
2662     int buflen;
2663     int len = -1;
2664     CHAR chk;
2665     char type = 0;
2666     char *s = NULL;
2667     char *buf = NULL;
2668     char tmpbuf[100];                   /* Longest S/I packet is about 30 */
2669
2670     if (!packet) return(0);
2671     buflen = ckstrncpy(tmpbuf,packet,100); /* Make a pokeable copy */
2672     if (buflen < 5) return(0);          /* Too short */
2673     if (buflen > 100) return(0);        /* Too long to be an S or I packet */
2674     s = buf = tmpbuf;                   /* Point to beginning of copy */
2675
2676     if (*s++ != stchr) return(0);       /* SOH */
2677     len = xunchar(*s++);                /* Length */
2678     if (len < 0) return(0);
2679     if (*s++ != SP) return(0);          /* Sequence number */
2680     type = *s++;                        /* Type */
2681     if (type != 'S' && type != 'I')
2682       return(0);
2683     if (buflen < len + 2) return(0);
2684     s += (len - 3);                     /* Position of checksum */
2685     chk = (CHAR) (*s);                  /* Checksum */
2686     *s = NUL;                      /* Temporarily null-terminate data field */
2687     if (xunchar(chk) != chk1((CHAR *)(buf+1),buflen-2)) { /* Check it */
2688         /*
2689           In C-Kermit 9.0 and later, an S or I packet can have a 
2690           Type 3 Block check ("help set block-check" for details).
2691         */
2692         unsigned crc;                   /* Failed... Try Type 3 block check */
2693         *s = chk;                       /* Replace last byte */
2694         s -= 2;                         /* Back up two bytes */
2695         crc = (xunchar(s[0]) << 12)     /* Convert 3 bytes to numeric CRC */
2696             | (xunchar(s[1]) << 6)
2697             | (xunchar(s[2]));
2698         chk = (CHAR)(*s);               /* Copy 1st byte of 3-byte CRC */
2699         *s = NUL;                       /* Null-terminate data field */
2700         if (crc != chk3((CHAR *)(buf+1),strlen(buf+1)))
2701           return(0);
2702     }
2703     return(type == 'S' ? 1 : 2);
2704 }
2705 #endif /* CK_AUTODL */
2706
2707 /* R P A C K  --  Read a Packet */
2708
2709 /*
2710   rpack reads a packet and returns the packet type, or else Q if the
2711   packet was invalid, or T if a timeout occurred.  Upon successful return,
2712   sets the values of global rsn (received sequence number),  rln (received
2713   data length), and rdatap (pointer to null-terminated data field), and
2714   returns the packet type.  NOTE: This is an inner-loop function so must be
2715   efficient.  Protect function calls by if-tests where possible, e.g.
2716   "if (pktlog) logpkt(...);".
2717 */
2718 int
2719 rpack() {
2720     register int i, j, x, lp;           /* Local variables */
2721 #ifdef CKTUNING
2722     unsigned int chk;
2723 #endif /* CKTUNING */
2724     int k, type, chklen;
2725     unsigned crc;
2726     CHAR pbc[5];                        /* Packet block check */
2727     CHAR *sohp;                         /* Pointer to SOH */
2728     CHAR e;                             /* Packet end character */
2729
2730 #ifdef GFTIMER
2731     CKFLOAT t1 = 0.0, t2 = 0.0;
2732 #endif /* GFTIMER */
2733
2734     debug(F101,"rpack pktnum","",pktnum);
2735
2736 #ifndef OLDCHKINT
2737     if (chkint() < 0)                   /* Check for console interrupts. */
2738       return('z');
2739 #endif /* OLDCHKINT */
2740
2741     k = getrbuf();                      /* Get a new packet input buffer. */
2742     debug(F101,"rpack getrbuf","",k);
2743     if (k < 0) {                        /* Return like this if none free. */
2744         return(-1);
2745     }
2746     recpkt = r_pkt[k].bf_adr;
2747     *recpkt = '\0';                     /* Clear receive buffer. */
2748     sohp = recpkt;                      /* Initialize pointers to it. */
2749     rdatap = recpkt;
2750     rsn = rln = -1;                     /* In case of failure. */
2751     e = (turn) ? turnch : eol;          /* Use any handshake char for eol */
2752
2753 /* Try to get a "line". */
2754
2755 #ifdef CK_AUTODL
2756     debug(F110,"rpack ksbuf",ksbuf,0);
2757     if (ksbuf[0]) {                     /* Kermit packet already */
2758         int x;                          /* collected for us in CONNECT mode */
2759         CHAR *s1 = recpkt, *s2 = ksbuf;
2760         j = 0;
2761         while (*s2) {                   /* Copy and get length */
2762             *s1++ = *s2++;              /* No point optimizing this since */
2763             j++;                        /* it's never more than ~20 chars */
2764         }
2765         *s1 = NUL;
2766 #ifdef PARSENSE
2767         x = parchk(recpkt, stchr, j);   /* Check parity */
2768         debug(F000,"autodownload parity","",parity);
2769         debug(F000,"autodownload parchk","",x);
2770         if (x > 0 && parity != x) {
2771             autopar = 1;
2772             parity = x;
2773         }
2774 #endif /* PARSENSE */
2775         ksbuf[0] = NUL;                 /* Don't do this next time! */
2776
2777     } else {                            /* Normally go read a packet */
2778 #endif /* CK_AUTODL */
2779
2780 #ifdef DEBUG
2781         if (deblog) {
2782             debug(F101,"rpack timint","",timint);
2783             debug(F101,"rpack rcvtimo","",rcvtimo);
2784 #ifdef STREAMING
2785             debug(F101,"rpack streaming","",streaming);
2786 #endif /* STREAMING */
2787 #ifdef GFTIMER
2788             /* Measure how long it takes to read a packet */
2789             t1 = gftimer();
2790 #endif /* GFTIMER */
2791         }
2792 #endif /* DEBUG */
2793
2794 /* JUST IN CASE (otherwise this could clobber streaming) */
2795
2796         if ((timint == 0
2797 #ifdef STREAMING
2798              || streaming
2799 #endif /* STREAMING */
2800              ) && (rcvtimo != 0)) {
2801             debug(F101,"rpack timint 0 || streaming but rcvtimo","",rcvtimo);
2802             rcvtimo = 0;
2803         }
2804
2805 #ifdef PARSENSE
2806 #ifdef UNIX
2807 /*
2808   So far the final turn argument is only for ck[uvdl]tio.c.  Should be added
2809   to the others too.  (turn == handshake character.)
2810 */
2811         j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2812 #else
2813 #ifdef VMS
2814         j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2815 #else
2816 #ifdef datageneral
2817         j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2818 #else
2819 #ifdef STRATUS
2820         j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2821 #else
2822 #ifdef OS2
2823         j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2824 #else
2825 #ifdef OSK
2826         j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2827 #else
2828         j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr);
2829 #endif /* OSK */
2830 #endif /* OS2 */
2831 #endif /* STRATUS */
2832 #endif /* datageneral */
2833 #endif /* VMS */
2834 #endif /* UNIX */
2835         if (parity != 0 && parity != 's' && ttprty != 0) {
2836             if (parity != ttprty) autopar = 1;
2837             parity = ttprty;
2838         }
2839 #else /* !PARSENSE */
2840         j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e);
2841 #endif /* PARSENSE */
2842
2843 #ifdef DEBUG
2844         if (deblog)  {
2845             debug(F101,"rpack ttinl len","",j);
2846 #ifdef GFTIMER
2847             t2 = gftimer();
2848             debug(F101,"rpack ttinl msec","",(long)((t2-t1)*1000.0));
2849 #endif /* GFTIMER */
2850         }
2851 #endif /* DEBUG */
2852
2853 #ifdef STREAMING
2854     if (streaming && sndtyp == 'D' && j == 0)
2855         return('Y');
2856 #endif /* STREAMING */
2857
2858         if (j < 0) {
2859             /* -1 == timeout, -2 == ^C, -3 == connection lost or fatal i/o */
2860             debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */
2861             freerbuf(k);                /* Free this buffer */
2862             if (j < -1) {               /* Bail out if ^C^C typed. */
2863                 if (j == -2) {
2864                     interrupted = 1;
2865                     debug(F101,"rpack ^C server","",server);
2866                     debug(F101,"rpack ^C en_fin","",en_fin);
2867                 } else if (j == -3) {
2868                     fatalio = 1;
2869                     debug(F101,"rpack fatalio","",en_fin);
2870                 }
2871                 return(j);
2872             }
2873             if (nakstate)               /* j == -1 is a read timeout */
2874               xxscreen(SCR_PT,'T',(long)winlo,"");
2875             else
2876               xxscreen(SCR_PT,'T',(long)pktnum,"");
2877             logpkt('r',-1,(CHAR *)"<timeout>",0);
2878             if (flow == 1) ttoc(XON);   /* In case of Xoff blockage. */
2879             return('T');
2880         }
2881 #ifdef CK_AUTODL
2882     }
2883 #endif /* CK_AUTODL */
2884
2885     rpktl = j;
2886     tlci += j;                          /* All OK, Count the characters. */
2887     flci += j;
2888
2889 /* Find start of packet */
2890
2891 #ifndef PARSENSE
2892     for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
2893       sohp++;                           /* Find mark */
2894     if (i++ >= j) {                     /* Didn't find it. */
2895         logpkt('r',-1,"<timeout>",0);
2896         freerbuf(k);
2897         return('T');
2898     }
2899 #else
2900     i = 1;                              /* ttinl does this for us */
2901 #endif /* PARSENSE */
2902
2903     rpackets++;                         /* Count received packet. */
2904     lp = i;                             /* Remember LEN position. */
2905     if ((j = xunchar(recpkt[i++])) == 0) { /* Get packet length.  */
2906         if ((j = lp+5) > MAXRP) {       /* Long packet */
2907             return('Q');                /* Too long */
2908         }
2909
2910 #ifdef CKTUNING
2911         /* Save some function-call and loop overhead... */
2912 #ifdef COMMENT
2913         /* ttinl() already removed parity */
2914         if (parity)
2915 #endif /* COMMENT */
2916           chk = (unsigned) ((unsigned) recpkt[i-1] +
2917                             (unsigned) recpkt[i]   +
2918                             (unsigned) recpkt[i+1] +
2919                             (unsigned) recpkt[i+2] +
2920                             (unsigned) recpkt[i+3]
2921                             );
2922 #ifdef COMMENT
2923         else
2924           chk = (unsigned) ((unsigned) (recpkt[i-1] & 077) +
2925                             (unsigned) (recpkt[i]   & 077) +
2926                             (unsigned) (recpkt[i+1] & 077) +
2927                             (unsigned) (recpkt[i+2] & 077) +
2928                             (unsigned) (recpkt[i+3] & 077)
2929                             );
2930 #endif /* COMMENT */
2931         if (xunchar(recpkt[j]) != ((((chk & 0300) >> 6) + chk) & 077))
2932 #else
2933         x = recpkt[j];                  /* Header checksum. */
2934         recpkt[j] = '\0';               /* Calculate & compare. */
2935         if (xunchar(x) != chk1(recpkt+lp,5))
2936 #endif /* CKTUNING */
2937           {
2938               freerbuf(k);
2939               logpkt('r',-1,(CHAR *)"<crunched:hdr>",0);
2940               xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet header");
2941               return('Q');
2942           }
2943 #ifndef CKTUNING
2944         recpkt[j] = x;                  /* Checksum ok, put it back. */
2945 #endif /* CKTUNING */
2946         rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl;
2947         j = 3;                          /* Data offset. */
2948     } else if (j < 3) {
2949         debug(F101,"rpack packet length less than 3","",j);
2950         freerbuf(k);
2951         logpkt('r',-1,(CHAR *)"<crunched:len>",0);
2952         xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet length");
2953         return('Q');
2954     } else {
2955         rln = j - bctl - 2;             /* Regular packet */
2956         j = 0;                          /* No extended header */
2957     }
2958     rsn = xunchar(recpkt[i++]);         /* Sequence number */
2959     if (pktlog)                         /* Save a function call! */
2960       logpkt('r',rsn,sohp,rln+bctl+j+4);
2961     if (rsn < 0 || rsn > 63) {
2962         debug(F101,"rpack bad sequence number","",rsn);
2963         freerbuf(k);
2964         if (pktlog)
2965           logpkt('r',rsn,(CHAR *)"<crunched:seq>",0);
2966         xxscreen(SCR_PT,'%',(long)pktnum,"Bad sequence number");
2967         return('Q');
2968     }
2969 /*
2970   If this packet has the same type as the packet just sent, assume it is
2971   an echo and ignore it.  Don't even bother with the block check calculation:
2972   even if the packet is corrupted, we don't want to NAK an echoed packet.
2973   Nor must we NAK an ACK or NAK.
2974 */
2975     type = recpkt[i++];                 /* Get packet's TYPE field */
2976     if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) {
2977         debug(F000,"rpack echo","",type); /* If it's an echo */
2978         freerbuf(k);                    /* Free this buffer */
2979         logpkt('#',rsn,(CHAR *)"<echo:ignored>",0);
2980         return('e');                    /* Return special (lowercase) code */
2981     }
2982 /*
2983   Separate the data from the block check, accounting for the case where
2984   a packet was retransmitted after the block check switched.  The "Type 3
2985   Forced" business is new to C-Kermit 9.0.
2986 */
2987     if (bctf) {                         /* Type 3 forced on all packets */
2988         bctl = chklen = 3;
2989     } else if ((type == 'I' || type == 'S')) { /* Otherwise... */
2990         if (recpkt[11] == '5') {        /* Sender is forcing Type 3 */
2991             bctf = 1;                   /* So we will too */
2992             bctl = chklen = 3;
2993             debug(F100,"RECOGNIZE BLOCK CHECK TYPE 5","",0);
2994         } else {                        /* Normal case */
2995             /* I & S packets always have type 1 */
2996             chklen = 1;
2997             rln = rln + bctl - 1;
2998         }
2999     } else if (type == 'N') {           /* A NAK packet never has data */
3000         chklen = xunchar(recpkt[lp]) - 2;
3001         if (chklen < 1 || chklen > 3) { /* JHD 13 Apr 2010 */
3002             debug(F101,"rpack bad nak chklen","",chklen);
3003             freerbuf(k);
3004             logpkt('r',-1,(CHAR *)"<crunched:chklen>",0);
3005             xxscreen(SCR_PT,'%',(long)pktnum,"(bad nak)");
3006             return('Q');
3007         }
3008         rln = rln + bctl - chklen;
3009     } else chklen = bctl;
3010 #ifdef DEBUG
3011     if (deblog) {                       /* Save 2 function calls */
3012         debug(F101,"rpack bctl","",bctl);
3013         debug(F101,"rpack chklen","",chklen);
3014     }
3015 #endif /* DEBUG */
3016     i += j;                             /* Buffer index of DATA field */
3017     rdatap = recpkt+i;                  /* Pointer to DATA field */
3018     if ((j = rln + i) > r_pkt[k].bf_len) { /* Make sure it fits */
3019         debug(F101,"packet too long","",j);
3020         freerbuf(k);
3021         logpkt('r',rsn,(CHAR *)"<overflow>",0);
3022         return('Q');
3023     }
3024     for (x = 0; x < chklen; x++)        /* Copy the block check */
3025       pbc[x] = recpkt[j+x];             /* 3 bytes at most. */
3026     pbc[x] = '\0';                      /* Null-terminate block check string */
3027     recpkt[j] = '\0';                   /* and the packet Data field. */
3028
3029     if (chklen == 2 && bctu == 4) {     /* Adjust for Blank-Free-2 */
3030         chklen = 4;                     /* (chklen is now a misnomer...) */
3031         debug(F100,"rpack block check B","",0);
3032     }
3033     switch (chklen) {                   /* Check the block check */
3034       case 1:                           /* Type 1, 6-bit checksum */
3035         if (xunchar(*pbc) != chk1(recpkt+lp,j-lp)) {
3036 #ifdef DEBUG
3037             if (deblog) {
3038                 debug(F110,"checked chars",recpkt+lp,0);
3039                 debug(F101,"block check (1)","",(int) xunchar(*pbc));
3040                 debug(F101,"should be (1)","",chk1(recpkt+lp,j-lp));
3041             }
3042 #endif /* DEBUG */
3043             freerbuf(k);
3044             logpkt('r',-1,(CHAR *)"<crunched:chk1>",0);
3045             xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
3046             return('Q');
3047         }
3048         break;
3049       case 2:                           /* Type 2, 12-bit checksum */
3050         x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
3051         if (x != chk2(recpkt+lp,j-lp)) { /* No match */
3052             if (type == 'E') {          /* Allow E packets to have type 1 */
3053                 recpkt[j++] = pbc[0];
3054                 recpkt[j] = '\0';
3055                 if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp))
3056                   break;
3057                 else
3058                   recpkt[--j] = '\0';
3059             }
3060 #ifdef DEBUG
3061             if (deblog) {
3062                 debug(F110,"checked chars",recpkt+lp,0);
3063                 debug(F101,"block check (2)","", x);
3064                 debug(F101,"should be (2)","", (int) chk2(recpkt+lp,j-lp));
3065             }
3066 #endif /* DEBUG */
3067             freerbuf(k);
3068             logpkt('r',-1,(CHAR *)"<crunched:chk2>",0);
3069             xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
3070             return('Q');
3071         }
3072         break;
3073       case 3:                           /* Type 3, 16-bit CRC */
3074         crc = (xunchar(pbc[0]) << 12)
3075             | (xunchar(pbc[1]) << 6)
3076             | (xunchar(pbc[2]));
3077         if (crc != chk3(recpkt+lp,j-lp)) {
3078             if (type == 'E') {          /* Allow E packets to have type 1 */
3079                 recpkt[j++] = pbc[0];
3080                 recpkt[j++] = pbc[1];
3081                 recpkt[j] = '\0';
3082                 if (xunchar(pbc[2]) == chk1(recpkt+lp,j-lp))
3083                   break;
3084                 else { j -=2; recpkt[j] = '\0'; }
3085             }
3086 #ifdef DEBUG
3087             if (deblog) {
3088                 debug(F110,"checked chars",recpkt+lp,0);
3089                 debug(F101,"block check (3)","",crc);
3090                 debug(F101,"should be (3)","",(int) chk3(recpkt+lp,j-lp));
3091             }
3092 #endif /* DEBUG */
3093             freerbuf(k);
3094             logpkt('r',-1,(CHAR *)"<crunched:chk3>",0);
3095             xxscreen(SCR_PT,'%',(long)pktnum,"CRC error");
3096             return('Q');
3097         }
3098         break;
3099       case 4:                           /* Type 4 = Type 2, no blanks. */
3100         x = (unsigned)((xunchar(*pbc) - 1) << 6) |
3101           (unsigned)(xunchar(pbc[1]) - 1);
3102         if (x != chk2(recpkt+lp,j-lp)) {
3103             if (type == 'E') {  /* Allow E packets to have type 1 */
3104                 recpkt[j++] = pbc[0];
3105                 recpkt[j] = '\0';
3106                 if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp))
3107                   break;
3108                 else
3109                   recpkt[--j] = '\0';
3110             }
3111             debug(F101,"bad type B block check","",x);
3112             freerbuf(k);
3113             logpkt('r',-1,(CHAR *)"<crunched:chkb>",0);
3114             xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
3115             return('Q');
3116         }
3117         break;
3118       default:                  /* Shouldn't happen... */
3119         freerbuf(k);
3120         logpkt('r',-1,(CHAR *)"<crunched:chkx>",0);
3121         xxscreen(SCR_PT,'%',(long)pktnum,"(crunched)");
3122         return('Q');
3123     }
3124     debug(F101,"rpack block check OK","",rsn);
3125
3126 /* Now we can believe the sequence number, and other fields. */
3127 /* Here we violate strict principles of layering, etc, and look at the  */
3128 /* packet sequence number.  If there's already a packet with the same   */
3129 /* number in the window, we remove this one so that the window will not */
3130 /* fill up. */
3131
3132     if ((x = rseqtbl[rsn]) != -1) {     /* Already a packet with this number */
3133         retrans++;                      /* Count it for statistics */
3134         debug(F101,"rpack got dup","",rsn);
3135         logpkt('r',rsn,(CHAR *)"<duplicate>",0);
3136         freerbuf(x);                    /* Free old buffer, keep new packet. */
3137         r_pkt[k].pk_rtr++;              /* Count this as a retransmission. */
3138     }
3139
3140 /* New packet, not seen before, enter it into the receive window. */
3141
3142 #ifdef CK_TIMERS
3143     if (timint > 0)
3144       rrttbl[rsn] = gtimer();           /* Timestamp */
3145 #endif /* CK_TIMERS */
3146
3147     rseqtbl[rsn] = k;                   /* Make back pointer */
3148     r_pkt[k].pk_seq = rsn;              /* Record in packet info structure */
3149     r_pkt[k].pk_typ = type;             /* Sequence, type,... */
3150     r_pkt[k].pk_adr = rdatap;           /* pointer to data buffer */
3151     if (local) {                        /* Save a function call! */
3152         int x = 0;
3153         if (fdispla != XYFD_N) x = 1;
3154         if (fdispla == XYFD_B && (type == 'D' || sndtyp == 'D')) x = 0;
3155         if (x)                          /* Update screen */
3156           xxscreen(SCR_PT,(char)type,(long)rsn,(char *)sohp);
3157     }
3158     return(type);                       /* Return packet type */
3159 }
3160
3161 /*  L O G P K T  --  Log packet number n, pointed to by s.  */
3162
3163 /* c = 's' (send) or 'r' (receive) */
3164
3165 VOID
3166 #ifdef CK_ANSIC
3167 logpkt(char c,int n, CHAR *s, int len)
3168 #else
3169 logpkt(c,n,s,len) char c; int n; CHAR *s; int len;
3170 #endif /* CK_ANSIC */
3171 /* logpkt */ {
3172     char plog[20];
3173     if (!s) s = (CHAR *)"";
3174     if (pktlog) if (chkfn(ZPFILE) > 0) {
3175         if (n < 0)                      /* Construct entry header */
3176           sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60)); /* safe */
3177         else
3178           sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60)); /* safe */
3179         if (zsoutx(ZPFILE,plog,(int)strlen(plog)) < 0) {
3180             pktlog = 0;
3181             return;
3182         } else {
3183             if (len == 0)
3184               len = strlen((char *)s);
3185             if (len > 0) {
3186                 char * p;               /* Make SOP printable */
3187                 int x;                  /* so we can look at logs without */
3188                 p = dbchr(*s);          /* triggering autodownload. */
3189                 x = strlen(dbchr(*s));
3190                 if (*s < 32 || (*s > 127 && *s < 160)) {
3191                     if (zsoutx(ZPFILE,p,x) < 0) {
3192                         pktlog = 0;
3193                         return;
3194                     } else {
3195                         len--;
3196                         s++;
3197                     }
3198                 }
3199             }
3200             if (zsoutx(ZPFILE,(char *)s,len) < 0) {
3201                 pktlog = 0;
3202                 return;
3203             } else if (zsoutx(ZPFILE,
3204 #ifdef UNIX
3205                               "\n", 1
3206 #else
3207 #ifdef datageneral
3208                               "\n", 1
3209 #else
3210 #ifdef OSK
3211                               "\r", 1
3212 #else
3213 #ifdef MAC
3214                               "\r", 1
3215 #else
3216                               "\015\012", 2
3217 #endif /* MAC */
3218 #endif /* OSK */
3219 #endif /* datageneral */
3220 #endif /* UNIX */
3221                               ) < 0) {
3222                 pktlog = 0;
3223             }
3224         }
3225     }
3226 }
3227
3228 /*  T S T A T S  --  Record statistics in transaction log  */
3229
3230 VOID
3231 tstats() {
3232     char *tp = NULL;
3233 #ifdef GFTIMER
3234     CKFLOAT xx;                         /* Elapsed time divisor */
3235 #endif /* GFTIMER */
3236
3237     debug(F101,"tstats xfsecs","",xfsecs);
3238     debug(F101,"tstats filcnt","",filcnt);
3239     if (filcnt == 1) {                  /* Get timing for statistics */
3240         tsecs = xfsecs;                 /* Single file, we already have it */
3241 #ifdef GFTIMER
3242         debug(F101,"tstats fpxfsecs","",(int)fpxfsecs);
3243         fptsecs = fpxfsecs;
3244 #endif /* GFTIMER */
3245     } else {                            /* Multiple files */
3246         tsecs = gtimer();               /* Get current time */
3247 #ifdef GFTIMER
3248         fptsecs = gftimer();
3249 #endif /* GFTIMER */
3250     }
3251 #ifdef GFTIMER
3252     if (fptsecs <= GFMINTIME)           /* Calculate CPS */
3253       fptsecs = (CKFLOAT) GFMINTIME;
3254     debug(F101,"tstats fptsecs","",(int)fptsecs);
3255     xx = (CKFLOAT) tfc / fptsecs;
3256     if (sizeof(long) <= 4) {            /* doesn't account for 16-bit longs */
3257         if (xx  > 2147483647.0)
3258           tfcps = 2147483647L;          /* 31 bits */
3259         else
3260           tfcps = (long) xx;
3261     } else
3262       tfcps = (long) xx;
3263 #else
3264     if (tsecs < 2L)
3265       tsecs = 1L;
3266     debug(F101,"tstats tsecs","",tsecs);
3267     tfcps = tfc / tsecs;
3268 #endif /* GFTIMER */
3269
3270     ztime(&tp);                         /* Get time stamp */
3271     tlog(F100,"","",0L);                /* Leave a blank line */
3272     tlog(F110,"Transaction complete",tp,0L);  /* Record it */
3273
3274     if (filcnt < 1) return;             /* If no files, done. */
3275
3276 /* If multiple files, record character totals for all files */
3277
3278     if (filcnt > 1) {
3279         tlog(F101," files transferred       ","",filcnt - filrej);
3280         tlog(F101," total file characters   ","",tfc);
3281         tlog(F101," communication line in   ","",tlci);
3282         tlog(F101," communication line out  ","",tlco);
3283     }
3284
3285 /* Record timing info for one or more files */
3286
3287 #ifdef GFTIMER
3288     if (filcnt - filrej == 1) {
3289         tlog(F101," elapsed time (seconds)  ","",(long) fpxfsecs);
3290         tlog(F101," effective data rate     ","",filcps);
3291     } else {
3292         tlog(F101," elapsed time (seconds)  ","",(long) fptsecs);
3293         tlog(F101," effective data rate     ","",(long) xx);
3294     }
3295 #else
3296     tlog(F101," elapsed time (seconds)  ","",tsecs);
3297     if (tsecs > 0)
3298       tlog(F101," effective data rate     ","",(tfc / tsecs));
3299 #endif /* GFTIMER */
3300
3301     tlog(F100,"","",0L);                /* Leave a blank line */
3302 }
3303
3304 /*  F S T A T S  --  Record file statistics in transaction log  */
3305
3306 VOID
3307 fcps() {
3308 #ifdef GFTIMER
3309     double xx;
3310     fpxfsecs = gftimer() - fpfsecs;
3311     if (fpxfsecs <= GFMINTIME)
3312       fpxfsecs = (CKFLOAT) GFMINTIME;
3313     xx = (CKFLOAT) ffc / fpxfsecs;
3314     if (sizeof(long) <= 4) {
3315         if (xx  > 2147483647.0)
3316           tfcps = 2147483647L;          /* 31 bits */
3317         else
3318           filcps = (long) xx;
3319     } else
3320       filcps = (long) xx;
3321     if (sizeof(int) >= 4)
3322       xfsecs = (int) fpxfsecs;
3323     else if (fpxfsecs < 32768.0)
3324       xfsecs = (int) fpxfsecs;
3325     else
3326       xfsecs = 32767;
3327 #else /* GFTIMER */
3328     xfsecs = gtimer() - fsecs;
3329     if (xfsecs < 1L) xfsecs = 1L;
3330     filcps = ffc / xfsecs;
3331 #endif /* GFTIMER */
3332 }
3333
3334 VOID
3335 fstats() {
3336     tfc += ffc;
3337 #ifdef DEBUG
3338     if (deblog) {
3339         debug(F101,"fstats tfc","",tfc);
3340         debug(F101,"fstats what","",what);
3341         debug(F110,"fstats epktmsg",epktmsg,0);
3342     }
3343 #endif /* DEBUG */
3344 #ifdef TLOG
3345     if (!discard && !cxseen && !czseen && what != W_NOTHING && !*epktmsg)
3346       tlog(F101," complete, size","",ffc);
3347 #endif /* TLOG */
3348 }
3349
3350 #endif /* NOXFER */