Annotation of coherent/e/bin/ckermit/ckcfn2.c, revision 1.1

1.1     ! root        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 ([email protected], [email protected]),
        !             7:   Columbia University Center for Computing Activities.
        !             8:   First released January 1985.
        !             9:   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
        !            10:   York.  Permission is granted to any individual or institution to use this
        !            11:   software as long as it is not sold for profit.  This copyright notice must be
        !            12:   retained.  This software may not be included in commercial products without
        !            13:   written permission of Columbia University.
        !            14: */
        !            15: /*
        !            16:  Note -- if you change this file, please amend the version number and date at
        !            17:  the top of ckcfns.c accordingly.
        !            18: */
        !            19: 
        !            20: #include "ckcsym.h"                    /* Compilation options */
        !            21: #include "ckcdeb.h"                    /* Debugging and other symbols */
        !            22: #include "ckcasc.h"                    /* ASCII symbols */
        !            23: #include "ckcker.h"                    /* Kermit symbols */
        !            24: #include "ckcxla.h"                    /* Translation */
        !            25: 
        !            26: #ifdef TCPSOCKET                       /* For TELNET business in spack() */
        !            27: #ifndef NP_TELNET
        !            28: #define NP_TELNET 1
        !            29: extern int tn_nlm, ttnproto;
        !            30: #endif /* NP_TELNET */
        !            31: #endif /* TCPSOCKET */
        !            32: 
        !            33: #ifdef DYNAMIC
        !            34: extern struct pktinfo *s_pkt;          /* array of pktinfo structures */
        !            35: extern struct pktinfo *r_pkt;          /* array of pktinfo structures */
        !            36: #else
        !            37: extern struct pktinfo s_pkt[];         /* array of pktinfo structures */
        !            38: extern struct pktinfo r_pkt[];         /* array of pktinfo structures */
        !            39: #endif /* DYNAMIC */
        !            40: 
        !            41: extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, sbufnum;
        !            42: 
        !            43: extern int ttprty;                     /* from ckutio.c */
        !            44: extern int autopar;
        !            45: 
        !            46: extern int spsiz, spmax, rpsiz, timint, timef, npad, ebq, ebqflg;
        !            47: extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, network, flow;
        !            48: extern int pktnum, sndtyp, bctr, bctu, bctl, rsn, rln, maxtry, size;
        !            49: extern int osize, maxsize, spktl, rpktl, nfils, stdouf, warn, parity;
        !            50: extern int turn, turnch,  delay, displa, pktlog, tralog, seslog, xflg, mypadn;
        !            51: extern int hcflg, local, server, cxseen, czseen;
        !            52: extern int nakstate, quiet, success, xitsta, what;
        !            53: extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz;
        !            54: 
        !            55: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, speed;
        !            56: 
        !            57: extern char *cmarg, *cmarg2, filnam[], *hlptxt;
        !            58: 
        !            59: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate;
        !            60: extern CHAR *recpkt, *data, encbuf[], myinit[];
        !            61: extern CHAR *srvptr, stchr, mystch, *rdatap;
        !            62: extern CHAR padbuf[];
        !            63: #ifdef DYNAMIC
        !            64:   extern CHAR *srvcmd;
        !            65: #else
        !            66:   extern CHAR srvcmd[];
        !            67: #endif /* DYNAMIC */
        !            68: 
        !            69: int numerrs = 0;               /* (PWP) total number packet errors so far */
        !            70: 
        !            71: static CHAR partab[] = {               /* Even parity table for dopar(). */
        !            72:     (CHAR) '\000',                     /* ANSI C casts '\ooo' constants  */
        !            73:     (CHAR) '\201',                     /* to signed char, so we have to  */
        !            74:     (CHAR) '\202',                     /* cast back to unsigned char...  */
        !            75:     (CHAR) '\003',
        !            76:     (CHAR) '\204',
        !            77:     (CHAR) '\005',
        !            78:     (CHAR) '\006',
        !            79:     (CHAR) '\207',
        !            80:     (CHAR) '\210',
        !            81:     (CHAR) '\011',
        !            82:     (CHAR) '\012',
        !            83:     (CHAR) '\213',
        !            84:     (CHAR) '\014',
        !            85:     (CHAR) '\215',
        !            86:     (CHAR) '\216',
        !            87:     (CHAR) '\017',
        !            88:     (CHAR) '\220',
        !            89:     (CHAR) '\021',
        !            90:     (CHAR) '\022',
        !            91:     (CHAR) '\223',
        !            92:     (CHAR) '\024',
        !            93:     (CHAR) '\225',
        !            94:     (CHAR) '\226',
        !            95:     (CHAR) '\027',
        !            96:     (CHAR) '\030',
        !            97:     (CHAR) '\231',
        !            98:     (CHAR) '\232',
        !            99:     (CHAR) '\033',
        !           100:     (CHAR) '\234',
        !           101:     (CHAR) '\035',
        !           102:     (CHAR) '\036',
        !           103:     (CHAR) '\237',
        !           104:     (CHAR) '\240',
        !           105:     (CHAR) '\041',
        !           106:     (CHAR) '\042',
        !           107:     (CHAR) '\243',
        !           108:     (CHAR) '\044',
        !           109:     (CHAR) '\245',
        !           110:     (CHAR) '\246',
        !           111:     (CHAR) '\047',
        !           112:     (CHAR) '\050',
        !           113:     (CHAR) '\251',
        !           114:     (CHAR) '\252',
        !           115:     (CHAR) '\053',
        !           116:     (CHAR) '\254',
        !           117:     (CHAR) '\055',
        !           118:     (CHAR) '\056',
        !           119:     (CHAR) '\257',
        !           120:     (CHAR) '\060',
        !           121:     (CHAR) '\261',
        !           122:     (CHAR) '\262',
        !           123:     (CHAR) '\063',
        !           124:     (CHAR) '\264',
        !           125:     (CHAR) '\065',
        !           126:     (CHAR) '\066',
        !           127:     (CHAR) '\267',
        !           128:     (CHAR) '\270',
        !           129:     (CHAR) '\071',
        !           130:     (CHAR) '\072',
        !           131:     (CHAR) '\273',
        !           132:     (CHAR) '\074',
        !           133:     (CHAR) '\275',
        !           134:     (CHAR) '\276',
        !           135:     (CHAR) '\077',
        !           136:     (CHAR) '\300',
        !           137:     (CHAR) '\101',
        !           138:     (CHAR) '\102',
        !           139:     (CHAR) '\303',
        !           140:     (CHAR) '\104',
        !           141:     (CHAR) '\305',
        !           142:     (CHAR) '\306',
        !           143:     (CHAR) '\107',
        !           144:     (CHAR) '\110',
        !           145:     (CHAR) '\311',
        !           146:     (CHAR) '\312',
        !           147:     (CHAR) '\113',
        !           148:     (CHAR) '\314',
        !           149:     (CHAR) '\115',
        !           150:     (CHAR) '\116',
        !           151:     (CHAR) '\317',
        !           152:     (CHAR) '\120',
        !           153:     (CHAR) '\321',
        !           154:     (CHAR) '\322',
        !           155:     (CHAR) '\123',
        !           156:     (CHAR) '\324',
        !           157:     (CHAR) '\125',
        !           158:     (CHAR) '\126',
        !           159:     (CHAR) '\327',
        !           160:     (CHAR) '\330',
        !           161:     (CHAR) '\131',
        !           162:     (CHAR) '\132',
        !           163:     (CHAR) '\333',
        !           164:     (CHAR) '\134',
        !           165:     (CHAR) '\335',
        !           166:     (CHAR) '\336',
        !           167:     (CHAR) '\137',
        !           168:     (CHAR) '\140',
        !           169:     (CHAR) '\341',
        !           170:     (CHAR) '\342',
        !           171:     (CHAR) '\143',
        !           172:     (CHAR) '\344',
        !           173:     (CHAR) '\145',
        !           174:     (CHAR) '\146',
        !           175:     (CHAR) '\347',
        !           176:     (CHAR) '\350',
        !           177:     (CHAR) '\151',
        !           178:     (CHAR) '\152',
        !           179:     (CHAR) '\353',
        !           180:     (CHAR) '\154',
        !           181:     (CHAR) '\355',
        !           182:     (CHAR) '\356',
        !           183:     (CHAR) '\157',
        !           184:     (CHAR) '\360',
        !           185:     (CHAR) '\161',
        !           186:     (CHAR) '\162',
        !           187:     (CHAR) '\363',
        !           188:     (CHAR) '\164',
        !           189:     (CHAR) '\365',
        !           190:     (CHAR) '\366',
        !           191:     (CHAR) '\167',
        !           192:     (CHAR) '\170',
        !           193:     (CHAR) '\371',
        !           194:     (CHAR) '\372',
        !           195:     (CHAR) '\173',
        !           196:     (CHAR) '\374',
        !           197:     (CHAR) '\175',
        !           198:     (CHAR) '\176',
        !           199:     (CHAR) '\377'
        !           200: };
        !           201: 
        !           202: /* CRC generation tables */
        !           203: 
        !           204: static long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L,
        !           205:   051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L,
        !           206:   0153215L, 0163416L, 0173617L };
        !           207: 
        !           208: static long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L,
        !           209:   053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L,
        !           210:   0155745L, 0164576L, 0174367L };
        !           211: 
        !           212: 
        !           213: /*  I N P U T  --  Attempt to read packet number 'pktnum'.  */
        !           214: 
        !           215: /*
        !           216:  This is the function that feeds input to Kermit's finite state machine,
        !           217:  in the form of a character in the range 32-126, normally a packet type
        !           218:  (uppercase letter) or pseudo-packet-type (lowercase letter).
        !           219: 
        !           220:  If a special start state is in effect, that state is returned as if it were
        !           221:  the type of an incoming packet.  Otherwise:
        !           222: 
        !           223:  (fill in...)
        !           224: */
        !           225: 
        !           226: int
        !           227: input() {
        !           228:     int type;
        !           229:     int x = 0, y, k;
        !           230: 
        !           231:     debug(F101,"input sstate","",sstate);
        !           232:     debug(F101," nakstate","",nakstate);
        !           233:     debug(F000," sndtyp","",sndtyp);
        !           234: 
        !           235:     while (1) {                                /* Big loop... */
        !           236: 
        !           237:        if (sstate != 0) {              /* If a start state is in effect, */
        !           238:            type = sstate;              /* return it like a packet type, */
        !           239:            sstate = 0;                 /* and then nullify it. */
        !           240:            numerrs = 0;                /* (PWP) no errors so far */
        !           241:            return(type);
        !           242:        }
        !           243:        
        !           244:        if (nakstate) {                 /* This section for file receiver. */
        !           245: 
        !           246:            if (wslots > 1) {           /* If we're doing windows, */
        !           247:                x = rseqtbl[winlo];     /* see if desired packet already in. */
        !           248:                debug(F101," winlo","",winlo);
        !           249:                debug(F101," rseqtbl[winlo]","",rseqtbl[winlo]);
        !           250:                if (x > -1) {           /* Already there? */
        !           251:                    if (r_pkt[x].pk_seq == winlo) { /* (double check) */
        !           252:                        rsn = winlo;                /* Yes, return its info */
        !           253:                        debug(F101,"input return pre-stashed packet","",rsn);
        !           254:                        dumprbuf();
        !           255:                        rdatap = r_pkt[x].pk_adr;   /* like rpack would do. */
        !           256:                        rln = (int)strlen((char *) rdatap);
        !           257:                        type = r_pkt[x].pk_typ;
        !           258:                        break;
        !           259:                    }
        !           260:                }
        !           261:            }
        !           262:            type = rpack();             /* Try to read a packet. */
        !           263:            debug(F111,"input recv",(char *) rdatap,(int) type);
        !           264:            while (type == 'e') {       /* Handle echoes */
        !           265:                debug(F000,"echo discarded","",type);
        !           266:                type = rpack(); 
        !           267:            }           
        !           268:            if (type < -1) return('q'); /* Ctrl-C */
        !           269:            if (type < 0) {             /* Receive window full */
        !           270:                /* Another thing to do here would be to delete */
        !           271:                /* the highest packet and NAK winlo.  But that */
        !           272:                /* shouldn't be necessary since the other Kermit */
        !           273:                /* should not have sent a packet outside the window. */
        !           274:                debug(F101,"rpack receive window full","",0);
        !           275:                dumprbuf();
        !           276:                errpkt((CHAR *)"Receive window full.");
        !           277:                strcpy((char *)recpkt,"Receive window full.");
        !           278:                type = 'E';
        !           279:                break;
        !           280:            }
        !           281:            dumprbuf();
        !           282: 
        !           283:            if (chkint() < 0) {         /* Check for console interrupts. */
        !           284:                errpkt((CHAR *)"User cancelled.");
        !           285:                strcpy((char *)recpkt,"User cancelled.");
        !           286:                type = 'E';
        !           287:                break;
        !           288:            }
        !           289:            if (type == 'E') {
        !           290:                debug(F101,"input got E, nakstate","",nakstate);
        !           291:                break;                  /* Error packet */
        !           292:            }
        !           293:            if (type == 'Q') {          /* Crunched packet. */
        !           294:                crunched++;
        !           295:                numerrs++;
        !           296:                if (nack(winlo) < 0) {  /* Request resend of window-low.. */
        !           297:                    debug(F101,"input sent too many naks","",winlo);
        !           298:                    errpkt((CHAR *)"Too many retries.");
        !           299:                    strcpy((char *)recpkt,"Sent too many NAKs.");
        !           300:                    type = 'E';
        !           301:                    break;
        !           302:                } else continue;
        !           303:            }           
        !           304:            if (type == 'T') {          /* Timeout */
        !           305: #ifdef BULKNAKS
        !           306:                int z;
        !           307: #endif
        !           308:                timeouts++;
        !           309:                debug(F101,"input receive-state timeout, winlo","",winlo);
        !           310: #ifdef BULKNAKS
        !           311:                z = winlo + wslots;     /* NAK all unACK'd packets */
        !           312:                if (z > 63) z -= 64;
        !           313:                debug(F101,"input sending bulk NAKs, winlo","",winlo);
        !           314:                for (x = winlo; (x != z) && ttchk() == 0; x++) {
        !           315:                    if (x < 0 || x > 63) break;
        !           316:                    if (rseqtbl[x] < 0) {
        !           317:                        if (nack(x) < 0) {
        !           318:                            debug(F101,"input sent too many naks","",winlo);
        !           319:                            errpkt((CHAR *)"Too many retries.");
        !           320:                            strcpy(recpkt,"Sent too many NAKs.");
        !           321:                            type = 'E';
        !           322:                            break;
        !           323:                        }
        !           324:                    }
        !           325:                }
        !           326: #else          /* NAK only the packet at window-low */
        !           327:                debug(F101,"input sending NAK for winlo","",winlo);
        !           328:                if (nack(winlo) < 0) {
        !           329:                    debug(F101,"input sent too many naks","",winlo);
        !           330:                    errpkt((CHAR *)"Too many retries.");
        !           331:                    strcpy((char *)recpkt,"Sent too many NAKs.");
        !           332:                    type = 'E';
        !           333:                    break;
        !           334:                }
        !           335: #endif /* BULKNAKS */
        !           336:                continue;
        !           337:            }
        !           338: 
        !           339:            /* Got the packet we want, done. */
        !           340: 
        !           341:            if (rsn == winlo) {
        !           342:                debug(F101,"input rsn=winlo","",rsn);
        !           343:                break;
        !           344:            }
        !           345: 
        !           346:            /* Got a packet out of order. */
        !           347: 
        !           348:            debug(F101,"input recv got packet out of order","",rsn);
        !           349:            k = rseqtbl[rsn];           /* Get window slot of this packet. */
        !           350:            debug(F101,"input recv rseqtbl[rsn]","",k);
        !           351:            if (k < 0) {
        !           352:                debug(F101,"input recv can't find index for rcvd pkt","",rsn);
        !           353:                errpkt((CHAR *)"internal error number 21");
        !           354:                strcpy((char *)recpkt,"Sliding windows protocol error.");
        !           355:                type = 'E';
        !           356:                break;
        !           357:            }           
        !           358:            y = chkwin(rsn,winlo,wslots); /* See what window it's in. */
        !           359:            debug(F101,"input recv chkwin","",y);
        !           360:            if (y == 1) {               /* Previous window. */
        !           361: #ifdef COMMENT
        !           362:                ackn(rsn);              /* Send empty ACK */
        !           363: #else
        !           364:                resend(rsn);
        !           365: #endif /* COMMENT */
        !           366:                freerpkt(rsn);          /* Get rid of received packet */
        !           367:                continue;
        !           368:            } else {                    /* In this window or out of range */
        !           369:                if (y < 0)              /* If out of range entirely, */
        !           370:                  freerpkt(rsn);        /* release its buffer */
        !           371: /*
        !           372:   We have received a packet, but not the one we want.  If we do nothing,
        !           373:   we could be in for a lengthy timeout/retry cycle.  It would seem to
        !           374:   make sense to send a NAK for the most desired packet (winlo).  But
        !           375:   consider this scenario: a packet arrived damaged so we NAK'd it above;
        !           376:   then packets winlo+1, winlo+2, ... winlo+n arrive, each one making us
        !           377:   send a NAK for winlo, so the other Kermit gets n NAKs for winlo, and
        !           378:   either would have to resend it n times, or if n > retry limit, give up
        !           379:   because of too many retries.  So we compromise: If a packet arrives
        !           380:   that is not the most desired packet (winlo), we NAK winlo, BUT ONLY IF
        !           381:   it has not been NAK'd before.
        !           382: */
        !           383:                if (s_pkt[k].pk_rtr == 0) {     /* Have we been here before? */
        !           384:                    if (nack(winlo) < 0) {      /* No, NAK winlo. */
        !           385:                        errpkt((CHAR *)"Too many retries."); /* Too many */
        !           386:                        strcpy((char *)recpkt,"Timed out."); /* Give up */
        !           387:                        type = 'E';
        !           388:                        break;
        !           389:                    } else continue;
        !           390:                } else continue;
        !           391:            }
        !           392: /*!!!*/
        !           393:        } else {                        /* Otherwise file sender... */
        !           394: 
        !           395:            if (wslots > 1) {           /* Packet at winlo already ACK'd? */
        !           396:                if (sacktbl[winlo]) {   /* If so,  */
        !           397:                    sacktbl[winlo] = 0;       /* Turn off the ACK'd flag */
        !           398:                    winlo = (winlo + 1) % 64; /* Rotate the window */
        !           399:                    type = 'Y';         /* And return ACK */
        !           400:                    debug(F101,
        !           401:                          "input send returning pre-stashed ACK","",
        !           402:                          winlo-1);
        !           403:                    break;
        !           404:                }
        !           405:            }
        !           406:            type = rpack();             /* Try to read an acknowledgement */
        !           407:            debug(F111,"input send",(char *) rdatap,(int) type);
        !           408:            while (type == 'e') {       /* Handle echoes */
        !           409:                debug(F000,"echo discarded","",type);
        !           410:                type = rpack(); 
        !           411:            }           
        !           412:            if (type == -2) return('q');
        !           413:            if (type == -1) {
        !           414:                errpkt((CHAR *)"Internal error number 18");
        !           415:                debug(F101," wslots","",wslots);
        !           416:                debug(F101," winlo","",winlo);
        !           417:                debug(F101," pktnum","",pktnum);
        !           418:                dumprbuf();
        !           419:                strcpy((char *)recpkt,"Can't allocate receive buffer");
        !           420:                type = 'E';
        !           421:                break;
        !           422:            }
        !           423:            dumprbuf();                 /* debugging */
        !           424: 
        !           425:            if (chkint() < 0) {         /* Check for console interrupts. */
        !           426:                errpkt((CHAR *)"User cancelled.");
        !           427:                strcpy((char *)recpkt,"User cancelled.");
        !           428:                return(type = 'E');
        !           429:            }
        !           430: 
        !           431:            /* got a packet */
        !           432: 
        !           433:            if (type == 'E') {
        !           434:                debug(F101,"input send got E, nakstate","",nakstate);
        !           435:                break;                  /* Error packet */
        !           436:            }
        !           437:            if (type == 'Q') {          /* Crunched packet */ 
        !           438:                crunched++;             /* For statistics */
        !           439:                numerrs++;              /* For packet resizing */
        !           440:                x = resend(winlo);      /* Resend window-low */
        !           441:                if (x < 0) {
        !           442:                    type = 'E';
        !           443:                    errpkt(recpkt);
        !           444:                    break;
        !           445:                }
        !           446:                continue;
        !           447:            }
        !           448:            if (type == 'T') {          /* Timeout waiting for ACKs. */
        !           449:                timeouts++;             /* Count it */
        !           450:                numerrs++;              /* Count an error too */
        !           451:                debug(F101,"input send state timeout, winlo","",winlo);
        !           452: 
        !           453:                /* Retransmit the oldest un-ACK'd packet. */
        !           454: 
        !           455:                debug(F101,"input send resending winlo","",winlo);
        !           456:                if (resend(winlo) < 0) { /* Check retries */
        !           457:                    debug(F101,"input send too many resends","",maxtry);
        !           458:                    errpkt(recpkt);
        !           459:                    return(type = 'E');
        !           460:                }
        !           461:                continue;
        !           462:            }
        !           463: 
        !           464:            /* Got an actual normal packet */
        !           465: 
        !           466:            y = chkwin(rsn,winlo,wslots); /* Is it in the window? */
        !           467:            debug(F101,"input send rsn","",rsn);
        !           468:            debug(F101,"input send winlo","",winlo);
        !           469:            debug(F101,"input send chkwin","",y);
        !           470:            if (type == 'Y') {          /* Got an ACK */
        !           471:                if (y == 0) {           /* In current window */
        !           472:                    x = sseqtbl[rsn];   /* Mark the packet as ACK'd */
        !           473:                    if (x > -1) s_pkt[x].pk_flg++;  /* (old way) */
        !           474:                    sacktbl[rsn]++;                 /* (new way) */
        !           475: /*
        !           476:   NOTE: The following statement frees the buffer of the ACK we just got.
        !           477:   But the upper layers still need the data, like if it's the ACK to an I,
        !           478:   S, F, D, Z, or just about any kind of packet.  So for now, freerbuf()
        !           479:   deallocates the buffer, but does not erase the data or destroy the pointer
        !           480:   to it.  There's no other single place where these receive buffers can be
        !           481:   correctly freed (?) ...
        !           482: */
        !           483:                    freerpkt(rsn);      /* Free the ACK's buffer */
        !           484:                    freesbuf(rsn);      /* *** Free the sent packet's buffer */
        !           485:                    if (rsn == winlo) { /* Got the one we want */
        !           486:                        sacktbl[winlo] = 0;
        !           487:                        winlo = (winlo + 1) % 64;
        !           488:                        debug(F101,"input send rotated send window","",winlo);
        !           489:                        break;          /* Return the ACK */
        !           490:                    } else {
        !           491:                        debug(F101,"input send mark pkt","",rsn);
        !           492:                        continue;       /* Otherwise go read another packet */
        !           493:                    }
        !           494:                } else {                /* ACK not in window, ignore */
        !           495:                    debug(F101,"input send ACK out of window","",rsn);
        !           496:                    freerpkt(rsn);
        !           497:                    continue;
        !           498:                }
        !           499:            }
        !           500:            if (type == 'N') {          /* NAK */
        !           501:                numerrs++;              /* Count an error */
        !           502:                debug(F101,"input send NAK","",rsn);
        !           503:                freerpkt(rsn);          /* Free buffer where NAK lies. */
        !           504:                if (y == 0) {           /* In current window */         
        !           505:                    debug(F100," in window","",0);
        !           506:                    k = sseqtbl[rsn];   /* Get pointer to NAK'd packet. */
        !           507:                    x = 0;
        !           508:                    if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) {
        !           509:                        x = resend(winlo); /* Packet we haven't sent yet. */
        !           510:                    } else {
        !           511:                        x = resend(rsn); /* Resend requested packet. */
        !           512:                    }
        !           513:                    if (x < 0) {        /* Resend error is fatal.  */
        !           514:                        type = 'E';
        !           515:                        errpkt(recpkt);
        !           516:                        break;
        !           517:                    } else continue;    /* Resend ok, go read another packet */
        !           518:                } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */
        !           519:                    if (wslots > 1) {
        !           520:                        debug( F101,"NAK for next packet, windowing","",rsn);
        !           521:                        x = resend(winlo); /* Resend window-low */
        !           522:                        if (x < 0) {
        !           523:                            type = 'E';
        !           524:                            errpkt(recpkt);
        !           525:                            break;
        !           526:                        }
        !           527:                        continue;       /* Go back and read another pkt */
        !           528:                    }
        !           529:                    debug(F101,"NAK for next packet, no windowing","",rsn);
        !           530:                    x = (rsn == 0) ? 63 : rsn - 1;
        !           531:                    if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) {
        !           532:                        resend(0);      /* ACK for S or I packet missing */
        !           533:                        continue;       /* so resend it. */
        !           534:                    }                   /* Else, treat NAK(n+1) as ACK(n) */
        !           535:                    if ((x = sseqtbl[x]) > -1) {
        !           536:                        sacktbl[x]++;      /* (new way) */
        !           537:                        s_pkt[x].pk_flg++; /* (old way) */
        !           538:                    }
        !           539:                    type = 'Y';         /* Treat it as ACK for last pkt */
        !           540:                    break;
        !           541:                } else if (y > 0) {     /* NAK for pkt we can't resend */
        !           542:                    debug(F101," NAK out of window","",rsn); /* bad... */
        !           543:                    type = 'E';
        !           544:                    errpkt((CHAR *)"NAK out of window");
        !           545:                    strcpy((char *)recpkt,"NAK out of window.");
        !           546:                    break;
        !           547:                } else continue;        /* Ignore other NAKs */
        !           548:            }                           /* End of file-sender NAK handler */
        !           549: 
        !           550:             if (rsn == winlo) {                /* Not ACK, NAK, timeout, etc. */
        !           551:                debug(F000,"input send unexpected type","",type);
        !           552:                break;
        !           553:            }
        !           554:        }                               /* End of file-sender section */
        !           555:     }                                  /* End of input() loop */
        !           556:     if (wslots == 1) {
        !           557:        debug(F100,"input about to flush","",0);
        !           558:        ttflui();               /* Got what we want, clear input buffer. */
        !           559:     }
        !           560:     if (!nakstate)             /* When sending */
        !           561:       rcalcpsz();              /* recalculate size every packet */
        !           562:     debug(F000,"input returning type","",type);
        !           563:     return(type);              /* Success, return packet type. */
        !           564: }
        !           565: 
        !           566: /*  D O P A R  --  Add an appropriate parity bit to a character  */
        !           567: 
        !           568: /*
        !           569:   (PWP) this is still used in the Mac terminal emulator, so we have to keep it
        !           570: */
        !           571: CHAR
        !           572: #ifdef CK_ANSIC
        !           573: dopar(register CHAR ch)
        !           574: #else
        !           575: dopar(ch) register CHAR ch;
        !           576: #endif /* CK_ANSIC */
        !           577:     {
        !           578:     register unsigned int a;
        !           579:     if (!parity) return((CHAR) (ch & 255)); else a = ch & 127;
        !           580:     switch (parity) {
        !           581:        case 'e':  return(partab[a]);                /* Even */
        !           582:        case 'm':  return((CHAR) (a | 128));         /* Mark */
        !           583:        case 'o':  return((CHAR) (partab[a] ^ 128)); /* Odd */
        !           584:        case 's':  return((CHAR) a);                 /* Space */
        !           585:        default:   return((CHAR) a);                 /* Something illegal */
        !           586:     }
        !           587: }
        !           588: 
        !           589: #ifdef PARSENSE
        !           590: /*  P A R C H K  --  Check if Kermit packet has parity  */
        !           591: 
        !           592: /*
        !           593:   Call with s = pointer to packet, start = packet start character, n = length.
        !           594:   Returns 0 if packet has no parity, -1 on error, or, if packet has parity:
        !           595:     'e' for even, 'o' for odd, 'm' for mark.  Space parity cannot be sensed.
        !           596:   So a return value of 0 really means either space or none.
        !           597:   Returns -2 if parity has already been checked during this protocol operation.
        !           598: */
        !           599: int
        !           600: #ifdef CK_ANSIC
        !           601: parchk(CHAR *s, CHAR start, int n)
        !           602: #else
        !           603: parchk(s,start,n) CHAR *s, start; int n;
        !           604: #endif /* CK_ANSIC */
        !           605: /* parchk */ {
        !           606:     CHAR s0, s1, s2, s3;
        !           607: 
        !           608:     debug(F101,"parchk n","",n);
        !           609:     debug(F101,"parchk start","",start);
        !           610: 
        !           611:     s0 = s[0] & 0x7f;                  /* Mark field (usually Ctrl-A) */
        !           612: 
        !           613:     if (s0 != start || n < 5) return(-1); /* Not a valid packet */
        !           614: 
        !           615: /* Look at packet control fields, which never have 8th bit set */
        !           616: /* First check for no parity, most common case. */
        !           617: 
        !           618:     if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0)
        !           619:       return(0);                       /* No parity or space parity */
        !           620: 
        !           621: /* Check for mark parity */
        !           622: 
        !           623:     if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80)
        !           624:       return('m');                     /* Mark parity */
        !           625: 
        !           626: /* Packet has some kind of parity */
        !           627: /* Make 7-bit copies of control fields */
        !           628: 
        !           629:     s1 = s[1] & 0x7f;                  /* LEN */
        !           630:     s2 = s[2] & 0x7f;                  /* SEQ */
        !           631:     s3 = s[3] & 0x7f;                  /* TYPE */
        !           632: 
        !           633: /* Check for even parity */
        !           634: 
        !           635:     if ((s[0] == partab[s0]) &&
        !           636:         (s[1] == partab[s1]) &&
        !           637:         (s[2] == partab[s2]) &&
        !           638:        (s[3] == partab[s3]))
        !           639:       return('e');
        !           640: 
        !           641: /* Check for odd parity */
        !           642: 
        !           643:     if ((s[0] != partab[s0]) &&
        !           644:         (s[1] != partab[s1]) &&
        !           645:         (s[2] != partab[s2]) &&
        !           646:        (s[3] != partab[s3]))
        !           647:       return('o');
        !           648: 
        !           649: /* Otherwise it's probably line noise.  Let checksum calculation catch it. */
        !           650: 
        !           651:     return(-1);
        !           652: }
        !           653: #endif /* PARSENSE */
        !           654: 
        !           655: /*
        !           656:   Check to make sure timeout intervals are long enough to allow maximum
        !           657:   length packets to get through before the timer goes off.  If not, the
        !           658:   timeout interval is adjusted upwards.
        !           659: 
        !           660:   This routine is called at the beginning of a transaction, before we
        !           661:   know anything about the delay characteristics of the line.  It works
        !           662:   only for serial communication devices; it trusts the speed reported by
        !           663:   the operating system.
        !           664: 
        !           665:   Call with a timout interval.  Returns it, adjusted if necessary.
        !           666: */  
        !           667: int
        !           668: chktimo(timo,flag) int timo, flag; {
        !           669:     long cps, z; int x, y;
        !           670:     debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */
        !           671:     debug(F101,"chktimo flag","",flag);
        !           672: 
        !           673:     if (flag)                          /* Don't change timeout if user */
        !           674:       return(timo);                    /* gave SET SEND TIMEOUT command. */
        !           675:     debug(F101,"chktimo spmax","",spmax);
        !           676:     debug(F101,"chktimo urpsiz","",urpsiz);
        !           677: 
        !           678:     speed = ttgspd();                  /* Get current speed. */
        !           679:     if (speed > 0L && !network) {
        !           680:        cps = speed / 10L;              /* Convert to chars per second */
        !           681:        if (cps > 0L) {
        !           682:            long plen;                  /* Maximum of send and rcv pkt size */
        !           683:            z = cps * (long) timo;      /* Chars per timeout interval */
        !           684:            z -= z / 10L;               /* Less 10 percent */
        !           685:            plen = spmax;
        !           686:            if (urpsiz > spmax) plen = urpsiz;
        !           687:            debug(F101,"chktimo plen","",plen);
        !           688:            if (z < plen) {             /* Compare with packet size */
        !           689:                x = (int) ((long) plen / cps); /* Adjust if necessary */
        !           690:                y = x / 10;             /* Add 10 percent for safety */
        !           691:                if (y < 2) y = 2;       /* Or 2 seconds, whichever is more */
        !           692:                x += y;
        !           693:                if (x > timo)           /* If this is greater than current */
        !           694:                  timo = x;             /* timeout, change the timeout */
        !           695:                debug(F101,"chktimo new timo","",timo);
        !           696:            }
        !           697:        }
        !           698:     }
        !           699:     return(timo);
        !           700: }
        !           701: 
        !           702: /*  S P A C K  --  Construct and send a packet  */
        !           703: 
        !           704: /*
        !           705:   spack() sends a packet of the given type, sequence number n, with len data
        !           706:   characters pointed to by d, in either a regular or extended- length packet,
        !           707:   depending on len.  Returns the number of bytes actually sent, or else -1
        !           708:   upon failure.  Uses global npad, padch, mystch, bctu, data.  Leaves packet 
        !           709:   fully built and null-terminated for later retransmission by resend().
        !           710:   Updates global sndpktl (send-packet length).
        !           711: 
        !           712:   NOTE: The global pointer "data" is assumed to point into the 7th position
        !           713:   of a character array (presumably in packet buffer for the current packet).
        !           714:   It was used by getpkt() to build the packet data field.  spack() fills in
        !           715:   the header to the left of the data pointer (the data pointer is defined
        !           716:   in getsbuf() in ckcfn3.c).  If the address "d" is the same as "data", then
        !           717:   the packet's data field has been built "in place" and need not be copied.
        !           718: */
        !           719: int
        !           720: #ifdef CK_ANSIC
        !           721: spack(char pkttyp, int n, int len, CHAR *d)
        !           722: #else
        !           723: spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d;
        !           724: #endif /* CK_ANSIC */
        !           725: /* spack */ {
        !           726:     register int i;
        !           727:     int j, k, lp, longpkt, copy;
        !           728:     register CHAR *cp, *mydata;
        !           729:     unsigned crc;
        !           730: 
        !           731:     debug(F101,"spack n","",n);
        !           732:     debug(F111," data",data,data);
        !           733:     debug(F101," d","",d);
        !           734:     debug(F101," len","",len);
        !           735: 
        !           736:     copy = (d != data);                        /* Flag whether data must be copied  */
        !           737:     longpkt = (len + bctl + 2) > 94;   /* Decide whether it's a long packet */
        !           738:     mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */
        !           739:     debug(F101," mydata","",mydata);
        !           740: 
        !           741:     k = sseqtbl[n];                    /* Packet structure info for pkt n */ 
        !           742:     debug(F101," sseqtbl[n]","",k);
        !           743:     if (k < 0) {
        !           744:        debug(F101,"spack sending packet out of window","",n);
        !           745:     } else {                           /* Record packet info */
        !           746:        s_pkt[k].pk_adr = mydata;       /* Remember address of packet. */
        !           747:        s_pkt[k].pk_seq = n;            /* Record sequence number */
        !           748:        s_pkt[k].pk_typ = pkttyp;       /* Record packet type */
        !           749:     }
        !           750: 
        !           751:     spktl = 0;                         /* Initialize length of this packet */
        !           752:     i = 0;                             /* and position in packet. */
        !           753: 
        !           754: /* Now fill the packet */
        !           755: 
        !           756:     mydata[i++] = mystch;              /* MARK */
        !           757:     lp = i++;                          /* Position of LEN, fill in later */
        !           758: 
        !           759:     mydata[i++] = tochar(n);           /* SEQ field */
        !           760:     mydata[i++] = pkttyp;              /* TYPE field */
        !           761:     j = len + bctl;                    /* Length of data + block check */
        !           762:     if (longpkt) {                     /* Long packet? */
        !           763:        int x;                          /* Work around SCO Xenix/286 */
        !           764:        x = 95;                         /* compiler bug... */
        !           765:        x = j / 95;
        !           766:         mydata[lp] = tochar(0);                /* Yes, set LEN to zero */
        !           767:         mydata[i++] = tochar(x);       /* High part */
        !           768:         mydata[i++] = tochar(j % 95);  /* Low part */
        !           769:         mydata[i] = '\0';              /* Header checksum */
        !           770:         mydata[i++] = tochar(chk1(mydata+lp));
        !           771:     } else mydata[lp] = tochar(j+2);   /* Normal LEN */
        !           772: 
        !           773:     if (copy)                          /* Data field built in place? */
        !           774:       for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */
        !           775:     else                               /* Otherwise, */
        !           776:       i += len;                                /* Just skip past data field. */
        !           777:     mydata[i] = '\0';                  /* Null-terminate for checksum calc. */
        !           778: 
        !           779:     switch (bctu) {                    /* Block check */
        !           780:        case 1:                         /* 1 = 6-bit chksum */
        !           781:            mydata[i++] = tochar(chk1(mydata+lp));
        !           782:            break;
        !           783:        case 2:                         /* 2 = 12-bit chksum */
        !           784:            j = chk2(mydata+lp);
        !           785:            mydata[i++] = (unsigned)tochar((j >> 6) & 077);
        !           786:            mydata[i++] = (unsigned)tochar(j & 077);
        !           787:            break;
        !           788:         case 3:                                /* 3 = 16-bit CRC */
        !           789:            crc = chk3(mydata+lp);
        !           790:            mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12);
        !           791:            mydata[i++] = (unsigned)tochar((crc >> 6) & 077);
        !           792:            mydata[i++] = (unsigned)tochar(crc & 077);
        !           793:            break;
        !           794:        case 4:                         /* 2 = 12-bit chksum, blank-free */
        !           795:            j = chk2(mydata+lp);        
        !           796:            mydata[i++] =
        !           797:              (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1)));
        !           798:            mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1)));
        !           799:            break;
        !           800:     }
        !           801:     mydata[i++] = seol;                        /* End of line (packet terminator) */
        !           802: #ifdef TCPSOCKET
        !           803: /*
        !           804:   If TELNET connection and packet terminator is carriage return,
        !           805:   we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE
        !           806:   (tn_nlm), to meet the TELNET specification.
        !           807: */
        !           808:     if (network && ttnproto == NP_TELNET && seol == CR)
        !           809:       mydata[i++] = tn_nlm ? LF : NUL;
        !           810: #endif /* TCPSOCKET */
        !           811:     mydata[i] = '\0';                  /* Terminate string */
        !           812:     logpkt('s',n,mydata);              /* Log packet */
        !           813: 
        !           814:     /* (PWP) add the parity quickly at the end */
        !           815:     switch (parity) {
        !           816:       case 'e':                                /* Even */
        !           817:        for (cp = &mydata[i-1]; cp >= mydata; cp--)
        !           818:          *cp = partab[*cp];
        !           819:        break;
        !           820:       case 'm':                                /* Mark */
        !           821:        for (cp = &mydata[i-1]; cp >= mydata; cp--)
        !           822:          *cp |= 128;
        !           823:        break;
        !           824:       case 'o':                                /* Odd */
        !           825:        for (cp = &mydata[i-1]; cp >= mydata; cp--)
        !           826:          *cp = partab[*cp] ^ 128;
        !           827:        break;
        !           828:       case 's':                                /* Space */
        !           829:        for (cp = &mydata[i-1]; cp >= mydata; cp--)
        !           830:          *cp &= 127;
        !           831:        break;
        !           832:     }
        !           833:     if (npad) ttol(padbuf,npad);       /* Send any padding */
        !           834:     spktl = i;                         /* Remember packet length */
        !           835:     s_pkt[k].pk_len = spktl;           /* also in packet info structure */
        !           836:     if (ttol(mydata,spktl) < 0) return(-1); /* Send the packet */
        !           837:     sndtyp = pkttyp;                   /* Remember packet type for echos */
        !           838:     spackets++;                                /* Count it. */
        !           839:     flco += spktl;                     /* Count the characters */
        !           840:     tlco += spktl;                     /* for statistics... */
        !           841:     dumpsbuf();                                /* Dump send buffers to debug log */
        !           842:     screen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */
        !           843:     return(spktl);                     /* Return length */
        !           844: }
        !           845: 
        !           846: /*  C H K 1  --  Compute a type-1 Kermit 6-bit checksum.  */
        !           847: 
        !           848: int
        !           849: chk1(pkt) register CHAR *pkt; {
        !           850:     register unsigned int chk;
        !           851:     chk = chk2(pkt);
        !           852:     chk = (((chk & 0300) >> 6) + chk) & 077;
        !           853:     return((int) chk);
        !           854: }
        !           855: 
        !           856: /*  C H K 2  --  Compute the numeric sum of all the bytes in the packet.  */
        !           857: 
        !           858: unsigned int
        !           859: chk2(pkt) register CHAR *pkt; {
        !           860:     register long chk; register unsigned int m;
        !           861:     m = (parity) ? 0177 : 0377;
        !           862:     for (chk = 0; *pkt != '\0'; pkt++)
        !           863:       chk += *pkt & m;
        !           864:     return((unsigned int) (chk & 07777));
        !           865: }
        !           866: 
        !           867: 
        !           868: /*  C H K 3  --  Compute a type-3 Kermit block check.  */
        !           869: /*
        !           870:  Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup 
        !           871:  table.  Assumes the argument string contains no embedded nulls.
        !           872: */
        !           873: unsigned int
        !           874: chk3(pkt) register CHAR *pkt; {
        !           875:     register long c, crc;
        !           876:     register unsigned int m;
        !           877:     m = (parity) ? 0177 : 0377;
        !           878:     for (crc = 0; *pkt != '\0'; pkt++) {
        !           879:        c = crc ^ (long)(*pkt & m);
        !           880:        crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
        !           881:     }
        !           882:     return((unsigned int) (crc & 0xFFFF));
        !           883: }
        !           884: 
        !           885: int
        !           886: nxtpkt() {                             /* Called by file sender */
        !           887:     int j, n;
        !           888: 
        !           889:     debug(F101,"nxtpkt pktnum","",pktnum);
        !           890:     debug(F101,"nxtpkt winlo ","",winlo);
        !           891:     n = (pktnum + 1) % 64;             /* Increment packet number mod 64 */
        !           892: #ifdef COMMENT 
        !           893: /*
        !           894:   Suggested by Alan Grieg.  A packet can be sent out of window in 
        !           895:   circumstances involving acks received out of order, ...  Have to think
        !           896:   about this...
        !           897: */
        !           898:     if (chkwin(n,winlo,wslots)) {
        !           899:        debug(F101,"nxtpkt n not in window","",n);
        !           900:        return(-1);
        !           901:     }
        !           902: #endif
        !           903:     j = getsbuf(n);                    /* Get a buffer for packet n */
        !           904:     if (j < 0) {
        !           905:        debug(F101,"nxtpkt can't getsbuf","",j);
        !           906:        return(-1);
        !           907:     }
        !           908:     pktnum = n;              
        !           909:     debug(F101,"nxtpkt bumped pktnum to","",pktnum);
        !           910:     return(0);
        !           911: }
        !           912: 
        !           913: /* Functions for sending ACKs and NAKs */
        !           914: 
        !           915: /* Note, we should only ACK the packet at window-low (winlo) */
        !           916: /* However, if an old packet arrives again (e.g. because the ACK we sent */
        !           917: /* earlier was lost), we ACK it again. */
        !           918: 
        !           919: int
        !           920: ack() {                                        /* Acknowledge the current packet. */
        !           921:     return(ackns(winlo,(CHAR *)""));
        !           922: }
        !           923: 
        !           924: int
        !           925: ackns(n,s) int n; CHAR *s; {           /* Acknowledge packet n */
        !           926:     int j, k;
        !           927:     debug(F111,"ackns",s,n);
        !           928: 
        !           929:     k = rseqtbl[n];                    /* First find received packet n. */
        !           930:     debug(F101,"ackns k","",k);
        !           931: #ifdef COMMENT
        !           932: /* No need to set ACK'd bit, because we're gonna free the buffer now */
        !           933:     if (k > -1)                                /* If in window */
        !           934:       s_pkt[k].pk_flg++;               /* mark the ack'd bit. */
        !           935:     else
        !           936:       debug(F101,"ackns can't set ack'd bit","",k);
        !           937: #endif
        !           938:     freesbuf(n);                       /* Free current send-buffer, if any */
        !           939:     if ((j = getsbuf(n)) < 0) {
        !           940:        /* This can happen if we have to re-ACK an old packet that has */
        !           941:         /* already left the window.  It does no harm. */
        !           942:        debug(F101,"ackns can't getsbuf","",n);
        !           943:     }
        !           944:     spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */
        !           945:     debug(F101,"ackns winlo","",winlo);
        !           946:     debug(F101,"ackns n","",n);
        !           947:     if (n == winlo) {                  /* If we're acking winlo */
        !           948:        if (k > -1)
        !           949:          freerbuf(k);                  /* don't need it any more */
        !           950:        if (j > -1)
        !           951:          freesbuf(j);                  /* and don't need to keep ACK either */
        !           952:        winlo = (winlo + 1) % 64;
        !           953:     }
        !           954:     return(0);
        !           955: }
        !           956: 
        !           957: int
        !           958: ackn(n) int n; {                       /* Send ACK for packet number n */
        !           959:     return(ackns(n,(CHAR *)""));
        !           960: }
        !           961: 
        !           962: int
        !           963: ack1(s) CHAR *s; {                     /* Send an ACK with data. */
        !           964:     debug(F110,"ack1",(char *) s,0);
        !           965:     return(ackns(winlo, s));
        !           966: }
        !           967: 
        !           968: /* N A C K  --   Send a Negative ACKnowledgment. */
        !           969: /*
        !           970:  Call with the packet number, n, to be NAK'd.
        !           971:  Returns -1 if that packet has been NAK'd too many times, otherwise 0.
        !           972:  Btw, it is not right to return 0 under error conditions.  This is
        !           973:  done because the -1 code is used for cancelling the file transfer.
        !           974:  More work is needed here.
        !           975: */
        !           976: int
        !           977: nack(n) int n; {
        !           978:     int i;
        !           979: 
        !           980:     if (n < 0 || n > 63) {
        !           981:        debug(F101,"nack bad pkt num","",n);
        !           982:        return(0);
        !           983:     } else debug(F101,"nack","",n);
        !           984:     if ((i = sseqtbl[n]) < 0) {                /* If necessary */
        !           985:        if (getsbuf(n) < 0) {           /* get a buffer for this NAK */
        !           986:            debug(F101,"nack can't getsbuf","",n);
        !           987:            return(0);
        !           988:        } else i = sseqtbl[n];          /* New slot number */
        !           989:     }
        !           990:     if (s_pkt[i].pk_rtr++ > maxtry)    /* How many times have we done this? */
        !           991:       return(-1);                      /* Too many... */
        !           992: 
        !           993: /* Note, don't free this buffer.  Eventually an ACK will come, and that */
        !           994: /* will set it free.  If not, well, it's back to ground zero anyway...  */
        !           995: 
        !           996:     spack('N',n,0,(CHAR *) "");                /* NAKs never have data. */
        !           997:     return(0);
        !           998: }
        !           999: 
        !          1000: /*
        !          1001:  * (PWP) recalculate the optimal packet length in the face of errors.
        !          1002:  * This is a modified version of the algorithm by John Chandler in Kermit/370, 
        !          1003:  * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988.
        !          1004:  *
        !          1005:  * This implementation minimizes the total overhead equation, which is
        !          1006:  *
        !          1007:  *   Total chars = file_chars + (header_len * num_packs)
        !          1008:  *                            + (errors * (header_len + packet_len))
        !          1009:  *
        !          1010:  * Differentiate with respect to number of chars, solve for packet_len, get:
        !          1011:  *
        !          1012:  *   packet_len = sqrt (file_chars * header_len / errors)
        !          1013:  */
        !          1014: 
        !          1015: /*
        !          1016:  (FDC) New super-simple algorithm.  If there was an error in the most recent
        !          1017:  packet exchange, cut the send-packet size in half, down to a minimum of 20.
        !          1018:  If there was no error, increase the size by 5/4, up to the maximum negotiated
        !          1019:  length.  Seems to be much more responsive than previous algorithm, which took
        !          1020:  forever to recover the original packet length, and it also went crazy under
        !          1021:  certain conditions.
        !          1022: 
        !          1023:  Here's another idea for packet length resizing that keeps a history of the
        !          1024:  last n packets.  Push a 1 into the left end of an n-bit shift register if the
        !          1025:  current packet is good, otherwise push a zero.  The current n-bit value, w, of
        !          1026:  this register is a weighted sum of the noise hits for the last n packets, with
        !          1027:  the most recent weighing the most.  The current packet length is some function
        !          1028:  of w and the negotiated packet length, like:
        !          1029: 
        !          1030:    (2^n - w) / (2^n) * (negotiated length)
        !          1031: 
        !          1032:  If the present resizing method causes problems, think about this one a little
        !          1033:  more.
        !          1034: */
        !          1035: VOID
        !          1036: rcalcpsz() {
        !          1037: 
        !          1038: #ifdef COMMENT
        !          1039: /* Old way */
        !          1040:     register long x, q;
        !          1041:     if (numerrs == 0) return;  /* bounds check just in case */
        !          1042: 
        !          1043:     /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */
        !          1044:     /* an ACK is 5+bctr */
        !          1045: 
        !          1046:     /* first set x = per packet overhead */
        !          1047:     if (wslots > 1)
        !          1048:        x = (long) (npad+5+bctr);    /* only the packet, don't count the ack */
        !          1049:     else
        !          1050:        x = (long) (npad+5+3+bctr+5+bctr);
        !          1051: 
        !          1052:     /* then set x = packet length ** 2 */
        !          1053:     x = x * ( ffc / (long) numerrs);   /* careful of overflow */
        !          1054:     
        !          1055:     /* calculate the long integer sqrt(x) quickly */
        !          1056:     q = 500;
        !          1057:     q = (q + x/q) >> 1;
        !          1058:     q = (q + x/q) >> 1;
        !          1059:     q = (q + x/q) >> 1;
        !          1060:     q = (q + x/q) >> 1;                /* should converge in about 4 steps */
        !          1061:     if ((q > 94) && (q < 130)) /* break-even point for long packets */
        !          1062:        q = 94;
        !          1063:     if (q > spmax) q = spmax;  /* maximum bounds */
        !          1064:     if (q < 10) q = 10;                /* minimum bounds */
        !          1065:     spsiz = q;                 /* set new send packet size */
        !          1066:     debug(F101,"rcalcpsiz","",q);
        !          1067: #else
        !          1068: /* New way */
        !          1069:     if (spackets < 3) return;
        !          1070:     debug(F101,"rcalcpsiz numerrs","",numerrs);
        !          1071:     debug(F101,"rcalcpsiz spsiz","",spsiz);
        !          1072:     if (numerrs)
        !          1073:       spsiz = spsiz / 2;
        !          1074:     else
        !          1075:       spsiz = (spsiz / 4) * 5;
        !          1076:     if (spsiz < 20) spsiz = 20;
        !          1077:     if (spsiz > spmax) spsiz = spmax;
        !          1078:     debug(F101,"rcalcpsiz new spsiz","",spsiz);
        !          1079:     numerrs = 0;
        !          1080:     return;
        !          1081: #endif
        !          1082: }
        !          1083: 
        !          1084: /*  R E S E N D  --  Retransmit packet n.  */
        !          1085: 
        !          1086: /*
        !          1087:   Returns 0 or positive on success (the number of retries for packet n).
        !          1088:   On failure, returns a negative number, and an error message is placed
        !          1089:   in recpkt.
        !          1090: */
        !          1091: int
        !          1092: resend(n) int n; {                     /* Send packet n again. */
        !          1093:     int j, k;
        !          1094: 
        !          1095:     debug(F101,"resend seq","",n);
        !          1096: 
        !          1097:     k = chkwin(n,winlo,wslots);                /* See if packet in current window */
        !          1098:     j = -1;                            /* Assume it's lost */
        !          1099:     if (k == 0) j = sseqtbl[n];                /* See if we still have a copy of it */
        !          1100:     if (k != 0 || j < 0) {             /* If not.... */
        !          1101:        if (nakstate && k == 1) {
        !          1102: /*
        !          1103:   Packet n is in the previous window and we are the file receiver.
        !          1104:   We already sent the ACK and deallocated its buffer so we can't just 
        !          1105:   retransmit the ACK.  Rather than give up, we try some tricks...
        !          1106: */
        !          1107:            if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */
        !          1108: /*
        !          1109:   If the packet number is 0, and we're at the beginning of a protocol
        !          1110:   operation (spackets < 63), then we have to resend the ACK to an I or S
        !          1111:   packet, complete with parameters in the data field.  So we take a chance and
        !          1112:   send a copy of the parameters in an ACK packet with block check type 1.
        !          1113: */
        !          1114:                int bctlsav;            /* Temporary storage */
        !          1115:                int bctusav;
        !          1116:                bctlsav = bctl;         /* Save current block check length */
        !          1117:                bctusav = bctu;         /* and type */
        !          1118:                bctu = bctl = 1;        /* Set block check to 1 */
        !          1119:                spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
        !          1120:                logpkt('#',n,(CHAR *)"<reconstructed>"); /* Log it */
        !          1121:                bctu = bctusav;         /* Restore block check type */
        !          1122:                bctl = bctlsav;         /* and length */
        !          1123: 
        !          1124:            } else {                    /* Not the first packet */
        !          1125: /*
        !          1126:   It's not the first packet of the protocol operation.  It's some other packet
        !          1127:   that we have already ACK'd and forgotten about.  So we take a chance and
        !          1128:   send an empty ACK using the current block-check type.  Usually this will
        !          1129:   work out OK (like when acking Data packets), and no great harm will be done
        !          1130:   if it was some other kind of packet (F, etc).  If we are requesting an
        !          1131:   interruption of the file transfer, the flags are still set, so we'll catch
        !          1132:   up on the next packet.
        !          1133: */
        !          1134:                spack('Y',n,0,(CHAR *) "");
        !          1135:                logpkt('#',n,(CHAR *)"<faith>"); /* Log it */
        !          1136:            }
        !          1137:            retrans++;
        !          1138:            screen(SCR_PT,'%',(long)pktnum,"(resend)");
        !          1139:            return(0);
        !          1140:        } else {
        !          1141: /*
        !          1142:   Packet number is not in current or previous window.  We seem to hit this
        !          1143:   code occasionally at the beginning of a transaction, for apparently no good
        !          1144:   reason.  Let's just log it for debugging, send nothing, and try to proceed
        !          1145:   with the protocol rather than killing it.
        !          1146: */
        !          1147:            debug(F101,"RESEND PKT NOT IN WINDOW","",n);
        !          1148:            debug(F101,"RESEND k","",k);
        !          1149: #ifdef COMMENT
        !          1150:            sprintf((char *)recpkt,
        !          1151:                    "   resend error: NIW, n=%d, k=%d.",n,k);
        !          1152:            return(-2);
        !          1153: #else
        !          1154:            return(0);
        !          1155: #endif /* COMMENT */
        !          1156:        }
        !          1157:     }
        !          1158: 
        !          1159: /* OK, it's in the window and it's not lost. */
        !          1160: 
        !          1161:     debug(F101,"resend pktinfo index","",k);
        !          1162: 
        !          1163:     if (s_pkt[j].pk_rtr++ > maxtry) {  /* Found it but over retry limit */
        !          1164:        strcpy((char *)recpkt,"Too many retries.");
        !          1165:        return(-1);
        !          1166:     }
        !          1167:     debug(F101," retry","",s_pkt[j].pk_rtr); /* OK so far */
        !          1168:     dumpsbuf();                                /* (debugging) */
        !          1169:     if (s_pkt[j].pk_typ == ' ') {      /* Incompletely formed packet */
        !          1170:        if (nakstate) {                 /* (This shouldn't happen any more) */
        !          1171:            nack(n);
        !          1172:            retrans++;
        !          1173:            screen(SCR_PT,'%',(long)pktnum,"(resend)");
        !          1174:            return(s_pkt[j].pk_rtr);
        !          1175:        } else {                        /* No packet to resend! */
        !          1176: #ifdef COMMENT
        !          1177: /*
        !          1178:   This happened (once) while sending a file with 2 window slots and typing
        !          1179:   X to the sender to cancel the file.  But since we're cancelling anyway,
        !          1180:   no need to give a scary message.
        !          1181: */
        !          1182:            sprintf((char *)recpkt,
        !          1183:                    "resend logic error: NPS, n=%d, j=%d.",n,j); 
        !          1184:            return(-2);
        !          1185: #else
        !          1186: /* Just ignore it. */
        !          1187:            return(0);
        !          1188: #endif /* COMMENT */
        !          1189:        }
        !          1190:     }
        !          1191:     ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len); /* Everything ok, send the packet */
        !          1192:     retrans++;                         /* Count a retransmission */
        !          1193:     screen(SCR_PT,'%',(long)pktnum,"(resend)");        /* Tell user about resend */
        !          1194:     logpkt('S',n,s_pkt[j].pk_adr);     /* Log the resent packet */
        !          1195:     return(s_pkt[j].pk_rtr);           /* Return the number of retries. */
        !          1196: }
        !          1197: 
        !          1198: int
        !          1199: errpkt(reason) CHAR *reason; {         /* Send an error packet. */
        !          1200:     int x, y;
        !          1201:     encstr(reason);
        !          1202:     y = spack('E',pktnum,size,encbuf+7);
        !          1203:     x = quiet; quiet = 1;              /* Close files silently. */
        !          1204:     clsif(); clsof(1);
        !          1205:     quiet = x;
        !          1206: #ifdef COMMENT
        !          1207:     screen(SCR_TC,0,0l,"");
        !          1208: #endif /* COMMENT */
        !          1209:     if (what < W_CONNECT)
        !          1210:       xitsta |= what;                  /* Remember what failed. */
        !          1211:     success = 0;
        !          1212:     return(y);
        !          1213: }
        !          1214: 
        !          1215: /* scmd()  --  Send a packet of the given type */
        !          1216: 
        !          1217: int
        !          1218: #ifdef CK_ANSIC
        !          1219: scmd(char t, CHAR *dat)
        !          1220: #else
        !          1221: scmd(t,dat) char t; CHAR *dat;
        !          1222: #endif /* CK_ANSIC */
        !          1223: /* scmd */ {
        !          1224:     encstr(dat);                       /* Encode the command string */
        !          1225:     spack(t,pktnum,size,(CHAR *)(encbuf+7));
        !          1226:     return(0);
        !          1227: }
        !          1228: 
        !          1229: VOID
        !          1230: srinit() {                             /* Send R (GET) packet */
        !          1231:     encstr((CHAR *)cmarg);             /* Encode the filename. */
        !          1232:     spack('R',pktnum,size,encbuf+7);   /* Send the packet. */
        !          1233: }
        !          1234: 
        !          1235: /* R P A C K  --  Read a Packet */
        !          1236: 
        !          1237: /*
        !          1238:  rpack reads a packet and returns the packet type, or else Q if the
        !          1239:  packet was invalid, or T if a timeout occurred.  Upon successful return, sets
        !          1240:  the values of global rsn (received sequence number),  rln (received
        !          1241:  data length), and rdatap (pointer to null-terminated data field).
        !          1242: */
        !          1243: int
        !          1244: rpack() {
        !          1245:     register int i, j, x, lp;          /* Local variables */
        !          1246:     int k, type, chklen;
        !          1247:     unsigned crc;
        !          1248:     CHAR pbc[4];                       /* Packet block check */
        !          1249:     CHAR *sohp;                                /* Pointer to SOH */
        !          1250:     CHAR e;                            /* Packet end character */
        !          1251: 
        !          1252:     debug(F101,"entering rpack, pktnum","",pktnum);
        !          1253:     k = getrbuf();                     /* Get a new packet input buffer. */
        !          1254:     debug(F101,"rpack getrbuf","",k);
        !          1255:     if (k < 0) return(-1);             /* Return like this if none free. */
        !          1256:     recpkt = r_pkt[k].bf_adr;
        !          1257:     *recpkt = '\0';                    /* Clear receive buffer. */
        !          1258:     sohp = recpkt;                     /* Initialize pointers to it. */
        !          1259:     rdatap = recpkt;
        !          1260:     rsn = rln = -1;                    /* In case of failure. */
        !          1261:     e = (turn) ? turnch : eol;         /* Use any handshake char for eol */
        !          1262: 
        !          1263: /* Try to get a "line". */
        !          1264: 
        !          1265: #ifdef PARSENSE
        !          1266: #ifdef UNIX
        !          1267: /*
        !          1268:   So far the final turn argument is only for ck[uvd]tio.c.  Should be added
        !          1269:   to the others too.  (turn == handshake character.)
        !          1270: */
        !          1271:     j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn);
        !          1272: #else
        !          1273: #ifdef VMS
        !          1274:     j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn);
        !          1275: #else
        !          1276: #ifdef datageneral
        !          1277:     j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn);
        !          1278: #else
        !          1279:     j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr);
        !          1280: #endif /* datageneral */
        !          1281: #endif /* VMS */
        !          1282: #endif /* UNIX */
        !          1283:     if (parity != ttprty) autopar = 1;
        !          1284:     parity = ttprty; 
        !          1285: #else
        !          1286:     j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e);
        !          1287: #endif /* PARSENSE */
        !          1288:     if (j < 0) {
        !          1289:        debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */
        !          1290:        freerbuf(k);                    /* Free this buffer */
        !          1291:        if (j < -1) {                   /* Bail out if ^C^C typed. */
        !          1292:            debug(F101,"rpack ^C server","",server);
        !          1293:            debug(F101,"rpack ^C en_fin","",en_fin);
        !          1294:            if (server == 0) return(j); /* But not if in server mode */
        !          1295:            else if (en_fin) return(j); /* with DISABLE FINISH */
        !          1296:        }
        !          1297:        if (nakstate)                          /* call it a timeout. */
        !          1298:          screen(SCR_PT,'T',(long)winlo,"");
        !          1299:        else
        !          1300:          screen(SCR_PT,'T',(long)pktnum,"");
        !          1301:        logpkt('r',-1,(CHAR *)"<timeout>");
        !          1302:        if (flow == 1) ttoc(XON);       /* In case of Xoff blockage. */
        !          1303:        return('T');
        !          1304:     }
        !          1305:     rpktl = j;
        !          1306:     tlci += j;                         /* All OK, Count the characters. */
        !          1307:     flci += j;
        !          1308: 
        !          1309: #ifndef PARSENSE
        !          1310: /* THEN eliminate this loop... */
        !          1311:     for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
        !          1312:       sohp++;                          /* Find mark */
        !          1313:     if (i++ >= j) {                    /* Didn't find it. */
        !          1314:        logpkt('r',-1,"<timeout>");
        !          1315:        freerbuf(k);
        !          1316:        return('T');
        !          1317:     }    
        !          1318: #else
        !          1319:     i = 1;
        !          1320: #endif /* PARSENSE */
        !          1321: 
        !          1322:     rpackets++;
        !          1323:     lp = i;                            /* Remember LEN position. */
        !          1324:     if ((j = xunchar(recpkt[i++])) == 0) {
        !          1325:         if ((j = lp+5) > MAXRP) return('Q'); /* Long packet */
        !          1326:        x = recpkt[j];                  /* Header checksum. */
        !          1327:        recpkt[j] = '\0';               /* Calculate & compare. */
        !          1328:        if (xunchar(x) != chk1(recpkt+lp)) {
        !          1329:            freerbuf(k);
        !          1330:            logpkt('r',-1,(CHAR *)"<crunched:hdr>");
        !          1331:            return('Q');
        !          1332:        }
        !          1333:        recpkt[j] = x;                  /* Checksum ok, put it back. */
        !          1334:        rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl;
        !          1335:        j = 3;                          /* Data offset. */
        !          1336:     } else if (j < 3) {
        !          1337:        debug(F101,"rpack packet length less than 3","",j);
        !          1338:        freerbuf(k);
        !          1339:        logpkt('r',-1,(CHAR *)"<crunched:len>");
        !          1340:        return('Q');
        !          1341:     } else {
        !          1342:        rln = j - bctl - 2;             /* Regular packet */
        !          1343:        j = 0;                          /* No extended header */
        !          1344:     }
        !          1345:     rsn = xunchar(recpkt[i++]);                /* Sequence number */
        !          1346:     logpkt('r',rsn,sohp);
        !          1347:     if (rsn < 0 || rsn > 63) {
        !          1348:        debug(F101,"rpack bad sequence number","",rsn);
        !          1349:        freerbuf(k);
        !          1350:        logpkt('r',rsn,(CHAR *)"<crunched:seq>");
        !          1351:        return('Q');
        !          1352:     }
        !          1353: /*
        !          1354:   If this packet has the same type as the packet just sent, assume it is
        !          1355:   an echo and ignore it.  Don't even bother with the block check calculation:
        !          1356:   even if the packet is corrupted, we don't want to NAK an echoed packet.
        !          1357:   (And we certainly don't want to NAK an ACK or NAK!)
        !          1358: */
        !          1359:     type = recpkt[i++];                        /* Get packet's TYPE field */
        !          1360:     if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) {
        !          1361:        debug(F000,"rpack echo","",type); /* If it's an echo */
        !          1362:        freerbuf(k);                    /* Free this buffer */
        !          1363:        logpkt('#',rsn,(CHAR *)"<echo:ignored>");
        !          1364:        return('e');                    /* return special (lowercase) code */
        !          1365:     }
        !          1366: /*
        !          1367:   Separate the data from the block check, accounting for the case where    
        !          1368:   a packet was retransmitted after the block check switched.
        !          1369: */
        !          1370:     if (type == 'I' || type == 'S') {  /* I & S packets always have type 1 */
        !          1371:        chklen = 1;
        !          1372:        rln = rln + bctl - 1;
        !          1373:     } else if (type == 'N') {          /* A NAK packet never has data */
        !          1374:        chklen = xunchar(recpkt[lp]) - 2;
        !          1375:        rln = rln + bctl - chklen;
        !          1376:     } else chklen = bctl;
        !          1377:     debug(F101,"rpack bctl","",bctl);
        !          1378:     debug(F101,"rpack chklen","",chklen);
        !          1379: 
        !          1380:     i += j;                            /* Buffer index of DATA field */
        !          1381:     rdatap = recpkt+i;                 /* Pointer to DATA field */
        !          1382:     if ((j = rln + i) > r_pkt[k].bf_len ) { /* Make sure it fits */
        !          1383:        debug(F101,"packet sticks out too far","",j);
        !          1384:        freerbuf(k);
        !          1385:        logpkt('r',rsn,(CHAR *)"<overflow>");
        !          1386:        return('Q');
        !          1387:     }
        !          1388: 
        !          1389:     for (x = 0; x < chklen; x++)       /* Copy the block check */
        !          1390:       pbc[x] = recpkt[j+x];
        !          1391:     pbc[x] = '\0';                     /* Null-terminate block check string */
        !          1392:     recpkt[j] = '\0';                  /*  and the packet DATA field. */
        !          1393:     
        !          1394:     if (chklen == 2 && bctu == 4) {    /* Adjust for Blank-Free-2 */
        !          1395:        chklen = 4;                     /* (chklen is now a misnomer...) */
        !          1396:        debug(F100,"rpack block check B","",0);
        !          1397:     }
        !          1398:     switch (chklen) {                  /* Check the block check */
        !          1399:        case 1:                         /* Type 1, 6-bit checksum */
        !          1400:            if (xunchar(*pbc) != chk1(recpkt+lp)) {
        !          1401:                debug(F110,"checked chars",recpkt+lp,0);
        !          1402:                debug(F101,"block check","",(int) xunchar(*pbc));
        !          1403:                debug(F101,"should be","",chk1(recpkt+lp));
        !          1404:                freerbuf(k);
        !          1405:                logpkt('r',-1,(CHAR *)"<crunched:chk1>");
        !          1406:                return('Q');
        !          1407:            }
        !          1408:            break;
        !          1409:        case 2:                         /* Type 2, 12-bit checksum */
        !          1410:            x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
        !          1411:            if (x != chk2(recpkt+lp)) { /* No match */
        !          1412:                if (type == 'E') {      /* Allow E packets to have type 1 */
        !          1413:                    recpkt[j++] = pbc[0];    
        !          1414:                    recpkt[j] = '\0';
        !          1415:                    if (xunchar(pbc[1]) == chk1(recpkt+lp))
        !          1416:                      break;
        !          1417:                    else
        !          1418:                      recpkt[--j] = '\0';
        !          1419:                }
        !          1420:                debug(F110,"checked chars",recpkt+lp,0);
        !          1421:                debug(F101,"block check","", x);
        !          1422:                debug(F101,"should be","", (int) chk2(recpkt+lp));
        !          1423:                freerbuf(k);
        !          1424:                logpkt('r',-1,(CHAR *)"<crunched:chk2>");
        !          1425:                return('Q');
        !          1426:            }
        !          1427:            break;
        !          1428:        case 3:                         /* Type 3, 16-bit CRC */
        !          1429:            crc = (xunchar(pbc[0]) << 12)
        !          1430:                | (xunchar(pbc[1]) << 6)
        !          1431:                | (xunchar(pbc[2]));
        !          1432:            if (crc != chk3(recpkt+lp)) {
        !          1433:                if (type == 'E') {      /* Allow E packets to have type 1 */
        !          1434:                    recpkt[j++] = pbc[0];    
        !          1435:                    recpkt[j++] = pbc[1];
        !          1436:                    recpkt[j] = '\0';
        !          1437:                    if (xunchar(pbc[2]) == chk1(recpkt+lp))
        !          1438:                      break;
        !          1439:                    else { j -=2; recpkt[j] = '\0'; }
        !          1440:                }
        !          1441:                debug(F110,"checked chars",recpkt+lp,0);
        !          1442:                debug(F101,"block check","",xunchar(*pbc));
        !          1443:                debug(F101,"should be","",(int) chk3(recpkt+lp));
        !          1444:                freerbuf(k);
        !          1445:                logpkt('r',-1,(CHAR *)"<crunched:chk3>");
        !          1446:                return('Q');
        !          1447:            }
        !          1448:            break;
        !          1449:        case 4:                         /* Type 4 = Type 2, no blanks. */
        !          1450:            x = (unsigned)((xunchar(*pbc) - 1) << 6) |
        !          1451:                (unsigned)(xunchar(pbc[1]) - 1);
        !          1452:            if (x != chk2(recpkt+lp)) {
        !          1453:                if (type == 'E') {      /* Allow E packets to have type 1 */
        !          1454:                    recpkt[j++] = pbc[0];    
        !          1455:                    recpkt[j] = '\0';
        !          1456:                    if (xunchar(pbc[1]) == chk1(recpkt+lp))
        !          1457:                      break;
        !          1458:                    else
        !          1459:                      recpkt[--j] = '\0';
        !          1460:                }
        !          1461:                debug(F101,"bad type B block check","",x);
        !          1462:                freerbuf(k);
        !          1463:                logpkt('r',-1,(CHAR *)"<crunched:chkb>");
        !          1464:                return('Q');
        !          1465:            }
        !          1466:            break;
        !          1467:        default:                        /* Shouldn't happen... */
        !          1468:            freerbuf(k);
        !          1469:            logpkt('r',-1,(CHAR *)"<crunched:chkx>");
        !          1470:            return('Q');
        !          1471:     }
        !          1472:     debug(F101,"rpack block check OK","",rsn);
        !          1473: 
        !          1474: /* Now we can believe the sequence number, and other fields. */
        !          1475: /* Here we violate strict principles of layering, etc, and look at the  */
        !          1476: /* packet sequence number.  If there's already a packet with the same   */
        !          1477: /* number in the window, we remove this one so that the window will not */
        !          1478: /* fill up. */
        !          1479: 
        !          1480:     if ((x = rseqtbl[rsn]) != -1) {    /* Already a packet with this number */
        !          1481:        retrans++;                      /* Count it for statistics */
        !          1482:        debug(F101,"rpack got dup","",rsn);
        !          1483:        logpkt('r',rsn,(CHAR *)"<duplicate>");
        !          1484:        freerbuf(x);                    /* Free old buffer, keep new packet. */
        !          1485:        r_pkt[k].pk_rtr++;              /* Count this as a retransmission. */
        !          1486:     }
        !          1487: 
        !          1488: /* New packet, not seen before, enter it into the receive window. */
        !          1489: 
        !          1490:     rseqtbl[rsn] = k;                  /* Make back pointer */
        !          1491:     r_pkt[k].pk_seq = rsn;             /* Record in packet info structure */
        !          1492:     r_pkt[k].pk_typ = type;            /* Sequence, type,... */
        !          1493:     r_pkt[k].pk_adr = rdatap;          /* pointer to data buffer */
        !          1494:     screen(SCR_PT,(char)type,(long)rsn,(char *)sohp); /* Update screen */
        !          1495:     return(type);                      /* Return packet type */
        !          1496: }
        !          1497: 
        !          1498: /*  L O G P K T  --  Log packet number n, pointed to by s.  */
        !          1499: 
        !          1500: /* c = 's' (send) or 'r' (receive) */
        !          1501: 
        !          1502: VOID
        !          1503: #ifdef CK_ANSIC
        !          1504: logpkt(char c,int n, CHAR *s)
        !          1505: #else
        !          1506: logpkt(c,n,s) char c; int n; CHAR *s;
        !          1507: #endif /* CK_ANSIC */
        !          1508: /* logpkt */ {
        !          1509:     char plog[20];
        !          1510:     if (pktlog && *s) {
        !          1511:        if (n < 0)
        !          1512:          sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60));
        !          1513:        else
        !          1514:          sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60));
        !          1515:        if (zsout(ZPFILE,plog) < 0) pktlog = 0;
        !          1516:        else if (zsoutl(ZPFILE,(char *)s) < 0) pktlog = 0;
        !          1517:     }
        !          1518: }
        !          1519: 
        !          1520: #ifdef TLOG
        !          1521: 
        !          1522: /*  T S T A T S  --  Record statistics in transaction log  */
        !          1523: 
        !          1524: VOID
        !          1525: tstats() {
        !          1526:     char *tp;
        !          1527:     ztime(&tp);                                /* Get time stamp */
        !          1528:     tlog(F110,"End of transaction",tp,0L);  /* Record it */
        !          1529: 
        !          1530:     if (filcnt < 1) return;            /* If no files, done. */
        !          1531: 
        !          1532: /* If multiple files, record character totals for all files */
        !          1533: 
        !          1534:     if (filcnt > 1) {
        !          1535:        tlog(F101," files","",filcnt);
        !          1536:        tlog(F101," total file characters   ","",tfc);
        !          1537:        tlog(F101," communication line in   ","",tlci);
        !          1538:        tlog(F101," communication line out  ","",tlco);
        !          1539:     }
        !          1540: 
        !          1541: /* Record timing info for one or more files */
        !          1542: 
        !          1543:     tlog(F101," elapsed time (seconds)  ","",(long) tsecs);
        !          1544:     if (tsecs > 0) {
        !          1545:        long lx;
        !          1546:        lx = (tfc * 10L) / (long) tsecs;
        !          1547:        tlog(F101," effective data rate     ","",lx/10L);
        !          1548:        if (speed <= 0L) speed = ttgspd();
        !          1549:        if (speed > 0L && speed != 8880L && network == 0) {
        !          1550:            lx = (lx * 100L) / speed;
        !          1551:            tlog(F101," efficiency (percent)    ","",lx);
        !          1552:        }
        !          1553:     }
        !          1554:     tlog(F100,"","",0L);               /* Leave a blank line */
        !          1555: }
        !          1556: 
        !          1557: /*  F S T A T S  --  Record file statistics in transaction log  */
        !          1558: 
        !          1559: VOID
        !          1560: fstats() {
        !          1561:     tfc += ffc;
        !          1562:     tlog(F100," end of file","",0L);
        !          1563:     tlog(F101,"  file characters        ","",ffc);
        !          1564:     tlog(F101,"  communication line in  ","",flci);
        !          1565:     tlog(F101,"  communication line out ","",flco);
        !          1566: }
        !          1567: #else /* NOTLOG */
        !          1568: VOID
        !          1569: tstats() {}
        !          1570: 
        !          1571: VOID
        !          1572: fstats() {
        !          1573:     tfc += ffc;
        !          1574: }
        !          1575: #endif /* TLOG */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.