Annotation of coherent/g/usr/bin/ckermit/ckcfns.c, revision 1.1.1.1

1.1       root        1: char *fnsv = "C-Kermit functions, 5A(079) 23 Nov 92";
                      2: 
                      3: /*  C K C F N S  --  System-independent Kermit protocol support functions.  */
                      4: 
                      5: /*  ...Part 1 (others moved to ckcfn2,3 to make this module small enough) */
                      6: 
                      7: /*
                      8:   Author: Frank da Cruz ([email protected], [email protected]),
                      9:   Columbia University Center for Computing Activities.
                     10:   First released January 1985.
                     11:   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
                     12:   York.  Permission is granted to any individual or institution to use this
                     13:   software as long as it is not sold for profit.  This copyright notice must be
                     14:   retained.  This software may not be included in commercial products without
                     15:   written permission of Columbia University.
                     16: */
                     17: /*
                     18:  System-dependent primitives defined in:
                     19: 
                     20:    ck?tio.c -- terminal i/o
                     21:    cx?fio.c -- file i/o, directory structure
                     22: */
                     23: #include "ckcsym.h"                    /* Once needed this for Mac... */
                     24: #include "ckcasc.h"                    /* ASCII symbols */
                     25: #include "ckcdeb.h"                    /* Debug formats, typedefs, etc. */
                     26: #include "ckcker.h"                    /* Symbol definitions for Kermit */
                     27: #include "ckcxla.h"                    /* Character set symbols */
                     28: 
                     29: /* Externals from ckcmai.c */
                     30: extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
                     31:  rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr;
                     32: extern int pktnum, bctr, bctu, bctl, fmask, clfils, sbufnum,
                     33:  size, osize, spktl, nfils, warn, timef, spsizf, sndtyp, success;
                     34: extern int parity, turn, network, what, fsecs,
                     35:  delay, displa, xflg, mypadn;
                     36: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize, speed;
                     37: extern int fblksiz, frecl, frecfm, forg, fcctrl;
                     38: extern int spackets, rpackets, timeouts, retrans, crunched, wmax;
                     39: extern int hcflg, binary, savmod, fncnv, local, server, cxseen, czseen;
                     40: extern int nakstate, discard;
                     41: extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
                     42: extern int atcapr, atcapb, atcapu;
                     43: extern int lpcapr, lpcapb, lpcapu;
                     44: extern int swcapr, swcapb, swcapu;
                     45: extern int lscapr, lscapb, lscapu;
                     46: extern int bsave, bsavef;
                     47: extern int sseqtbl[];
                     48: extern int numerrs;
                     49: extern long rptn;
                     50: extern int maxtry;
                     51: 
                     52: #ifndef NOCSETS
                     53: extern int tcharset, fcharset;
                     54: extern int ntcsets;
                     55: extern struct csinfo tcsinfo[], fcsinfo[];
                     56: #endif /* NOCSETS */
                     57: 
                     58: extern int
                     59:   atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
                     60:   attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; 
                     61: 
                     62: extern int bigsbsiz, bigrbsiz;
                     63: 
                     64: #ifdef DYNAMIC
                     65:   extern CHAR *srvcmd;
                     66: #else
                     67:   extern CHAR srvcmd[];
                     68: #endif /* DYNAMIC */
                     69: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate;
                     70: extern CHAR *recpkt, *data, padbuf[], stchr, mystch;
                     71: extern CHAR *srvptr;
                     72: extern CHAR *rdatap;
                     73: extern char *cmarg, *cmarg2, *hlptxt, **cmlist, filnam[], fspec[];
                     74: 
                     75: _PROTOTYP( CHAR *rpar, (void) );
                     76: _PROTOTYP( int lslook, (unsigned int b) );     /* Locking Shift Lookahead */
                     77: _PROTOTYP( int szeof, (CHAR *s) );
                     78: 
                     79: /* International character sets */
                     80: 
                     81: #ifndef NOCSETS
                     82: /* Pointers to translation functions */
                     83: #ifdef CK_ANSIC
                     84: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
                     85: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
                     86: #else
                     87: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();        /* Character set */
                     88: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();        /* translation functions. */
                     89: #endif /* CK_ANSIC */
                     90: _PROTOTYP( CHAR (*rx), (CHAR) );       /* Input translation function */
                     91: _PROTOTYP( CHAR (*sx), (CHAR) );       /* Output translation function */
                     92: _PROTOTYP( CHAR ident, (CHAR) );       /* Identity translation function */
                     93: #endif /* NOCSETS */
                     94: 
                     95: /* Windowing things */
                     96: 
                     97: extern int rseqtbl[];                  /* Rec'd-packet sequence # table */
                     98: 
                     99: /* (PWP) external def. of things used in buffered file input and output */
                    100: 
                    101: #ifdef DYNAMIC
                    102: extern char *zinbuffer, *zoutbuffer;
                    103: #else
                    104: extern char zinbuffer[], zoutbuffer[];
                    105: #endif
                    106: extern char *zinptr, *zoutptr;
                    107: extern int zincnt, zoutcnt;
                    108: 
                    109: /* Variables defined in this module, but shared by ckcfn3, to which */
                    110: /* several functions have been moved... */
                    111: 
                    112: int sndsrc;            /* Flag for where to get names of files to send: */
                    113:                                        /* -1: znext() function */
                    114:                                        /*  0: stdin */
                    115:                                        /* >0: list in cmlist */
                    116: 
                    117: int  memstr;                           /* Flag for input from memory string */
                    118: 
                    119: #ifdef pdp11
                    120: CHAR myinit[25];                       /* Copy of my Send-Init data */
                    121: #else
                    122: CHAR myinit[100];                      /* Copy of my Send-Init data */
                    123: #endif /* pdp11 */
                    124: 
                    125: /* Variables local to this module */
                    126: 
                    127: static char *memptr;                   /* Pointer for memory strings */
                    128: 
                    129: #ifdef pdp11
                    130: static char cmdstr[50];                        /* System command string. */
                    131: #else
                    132: static char cmdstr[100];
                    133: #endif /* pdp11 */
                    134: 
                    135: static int drain;                      /* For draining stacked-up ACKs. */
                    136: 
                    137: static int first;                      /* Flag for first char from input */
                    138: static CHAR t,                         /* Current character */
                    139:     next;                              /* Next character */
                    140: 
                    141: static int lsstate = 0;                        /* Locking shift state */
                    142: static int lsquote = 0;                        /* Locking shift quote */
                    143: 
                    144: #ifdef datageneral
                    145: extern int quiet;
                    146: #endif
                    147: 
                    148: /*  E N C S T R  --  Encode a string from memory. */
                    149: 
                    150: /*
                    151:   Call this instead of getpkt() if source is a string, rather than a file.
                    152:   Note: Character set translation is never done in this case.
                    153: */
                    154: 
                    155: #ifdef pdp11
                    156: #define ENCBUFL 100
                    157: #else
                    158: #define ENCBUFL 200
                    159: #endif /* pdp11 */
                    160: CHAR encbuf[ENCBUFL];
                    161: 
                    162: int
                    163: encstr(s) CHAR* s; {
                    164:     int m; char *p;
                    165:     CHAR *dsave;
                    166: 
                    167:     if ((m = (int)strlen((char *)s)) > ENCBUFL) {
                    168:        debug(F111,"encstr string too long for buffer",s,ENCBUFL);
                    169:        s[ENCBUFL] = '\0';
                    170:     }
                    171:     if (m > spsiz-bctl-3) {
                    172:        debug(F111,"encstr string too long for packet",s,spsiz-bctl-3);
                    173:        s[spsiz-bctl-3] = '\0';
                    174:     }
                    175:     m = memstr; p = memptr;            /* Save these. */
                    176: 
                    177:     memptr = (char *)s;                        /* Point to the string. */
                    178:     memstr = 1;                                /* Flag memory string as source. */
                    179:     first = 1;                         /* Initialize character lookahead. */
                    180:     dsave = data;                      /* Boy is this ugly... */
                    181:     data = encbuf + 7;                 /* Why + 7?  See spack()... */
                    182: #ifdef COMMENT
                    183:     getpkt(spsiz-bctl-3,0);            /* Fill a packet from the string. */
                    184: #else
                    185:     getpkt(spsiz,0);
                    186: #endif /* COMMENT */
                    187:     data = dsave;                      /* (sorry...) */
                    188:     memstr = m;                                /* Restore memory string flag */
                    189:     memptr = p;                                /* and pointer */
                    190:     first = 1;                         /* Put this back as we found it. */
                    191:     return(0);
                    192: }
                    193: 
                    194: #ifdef COMMENT
                    195: /*
                    196:   We don't use this routine any more -- the code has been incorporated
                    197:   directly into getpkt() to reduce per-character function call overhead.
                    198:   Also, watch out: it hasn't been updated since it was commented out a
                    199:   long time ago.
                    200: */
                    201: /* E N C O D E - Kermit packet encoding procedure */
                    202: 
                    203: VOID
                    204: encode(a) CHAR a; {                    /* The current character */
                    205:     int a7;                            /* Low order 7 bits of character */
                    206:     int b8;                            /* 8th bit of character */
                    207:  
                    208: #ifndef NOCSETS
                    209:     if (!binary && sx) a = (*sx)(a);   /* Translate. */
                    210: #endif /* NOCSETS */
                    211: 
                    212:     if (rptflg)        {                       /* Repeat processing? */
                    213:         if (a == next && (first == 0)) { /* Got a run... */
                    214:            if (++rpt < 94)             /* Below max, just count */
                    215:                 return;
                    216:            else if (rpt == 94) {       /* Reached max, must dump */
                    217:                 data[size++] = rptq;
                    218:                 data[size++] = tochar(rpt);
                    219:                rptn += rpt;            /* Count, for stats */
                    220:                 rpt = 0;
                    221:            }
                    222:         } else if (rpt == 1) {         /* Run broken, only 2? */
                    223:             rpt = 0;                   /* Yes, reset repeat flag & count. */
                    224:            encode(a);                  /* Do the character twice. */
                    225:            if (size <= maxsize) osize = size;
                    226:            rpt = 0;
                    227:            encode(a);
                    228:            return;
                    229:        } else if (rpt > 1) {           /* More than two */
                    230:             data[size++] = rptq;       /* Insert the repeat prefix */
                    231:             data[size++] = tochar(++rpt); /* and count. */
                    232:            rptn += rpt;
                    233:             rpt = 0;                   /* Reset repeat counter. */
                    234:         }
                    235:     }
                    236:     a7 = a & 0177;                     /* Isolate ASCII part */
                    237:     b8 = a & 0200;                     /* and 8th (parity) bit. */
                    238: 
                    239:     if (ebqflg && b8) {                        /* Do 8th bit prefix if necessary. */
                    240:         data[size++] = ebq;
                    241:         a = a7;
                    242:     }
                    243:     if ((a7 < SP) || (a7==DEL))        {       /* Do control prefix if necessary */
                    244:         data[size++] = myctlq;
                    245:        a = ctl(a);
                    246:     }
                    247:     if (a7 == myctlq)                  /* Prefix the control prefix */
                    248:         data[size++] = myctlq;
                    249: 
                    250:     if ((rptflg) && (a7 == rptq))      /* If it's the repeat prefix, */
                    251:         data[size++] = myctlq;         /* quote it if doing repeat counts. */
                    252: 
                    253:     if ((ebqflg) && (a7 == ebq))       /* Prefix the 8th bit prefix */
                    254:         data[size++] = myctlq;         /* if doing 8th-bit prefixes */
                    255: 
                    256:     data[size++] = a;                  /* Finally, insert the character */
                    257:     data[size] = '\0';                 /* itself, and mark the end. */
                    258: }
                    259: #endif /* COMMENT */
                    260: 
                    261: /*  Output functions passed to 'decode':  */
                    262: 
                    263: int                           /*  Put character in server command buffer  */
                    264: #ifdef CK_ANSIC
                    265: putsrv(char c)
                    266: #else
                    267: putsrv(c) register char c;
                    268: #endif /* CK_ANSIC */
                    269: /* putsrv */ {
                    270:     *srvptr++ = c;
                    271:     *srvptr = '\0';            /* Make sure buffer is null-terminated */
                    272:     return(0);
                    273: }
                    274: 
                    275: int                                    /*  Output character to console.  */
                    276: #ifdef CK_ANSIC
                    277: puttrm(char c)
                    278: #else
                    279: puttrm(c) register char c;
                    280: #endif /* CK_ANSIC */
                    281: /* puttrm */ {
                    282:     conoc(c);
                    283:     return(0);
                    284: }
                    285: 
                    286: int                                    /*  Output char to file. */
                    287: #ifdef CK_ANSIC
                    288: putfil(char c)
                    289: #else
                    290: putfil(c) register char c;
                    291: #endif /* CK_ANSIC */
                    292: /* putfil */ {
                    293:     if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
                    294:        czseen = 1;                     /* If write error... */
                    295:        debug(F101,"putfil zchout write error, setting czseen","",1);
                    296:        return(-1);
                    297:     }
                    298:     return(0);
                    299: }
                    300: 
                    301: /* D E C O D E  --  Kermit packet decoding procedure */
                    302: 
                    303: /*
                    304:  Call with string to be decoded and an output function.
                    305:  Returns 0 on success, -1 on failure (e.g. disk full).
                    306: 
                    307:  This is the "inner loop" when receiving files, and must be coded as 
                    308:  efficiently as possible.  Note some potential problems:  if a packet
                    309:  is badly formed, having a prefixed sequence ending prematurely, this
                    310:  function, as coded, could read past the end of the packet.  This has
                    311:  never happened, thus the additional (time-consuming) tests have not
                    312:  been added.
                    313: */
                    314: 
                    315: static CHAR *xdbuf;    /* Global version of decode()'s buffer pointer */
                    316:                         /* for use by translation functions. */
                    317: 
                    318: /* Function for pushing a character onto decode()'s input stream. */
                    319: 
                    320: VOID
                    321: #ifdef CK_ANSIC
                    322: zdstuff(CHAR c)
                    323: #else
                    324: zdstuff(c) CHAR c;
                    325: #endif /* CK_ANSIC */
                    326: /* zdstuff */ {        
                    327:     xdbuf--;                           /* Back up the pointer. */
                    328:     *xdbuf = c;                                /* Stuff the character. */
                    329: }
                    330: 
                    331: int
                    332: #ifdef CK_ANSIC
                    333: decode(CHAR *buf, int (*fn)(char), int xlate)
                    334: #else
                    335: decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
                    336: #endif /* CK_ANSIC */
                    337: /* decode */ {
                    338:     register unsigned int a, a7, a8, b8; /* Various copies of current char */
                    339:     int t;                             /* Int version of character */
                    340:     int ssflg;                         /* Character was single-shifted */
                    341: 
                    342: /*
                    343:   Catch the case in which we are asked to decode into a file that is not open,
                    344:   for example, if the user interrupted the transfer, but the other Kermit
                    345:   keeps sending.
                    346: */
                    347:     if ((cxseen || czseen || discard) && (fn == putfil))
                    348:       return(0);
                    349: 
                    350:     xdbuf = buf;                       /* Make global copy of pointer. */
                    351:     rpt = 0;                           /* Initialize repeat count. */
                    352: 
                    353:     while ((a = *xdbuf++ & 0xFF) != '\0') { /* Get next character. */
                    354:        if (a == rptq && rptflg) {      /* Got a repeat prefix? */
                    355:            rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
                    356:            rptn += rpt;
                    357:            a = *xdbuf++ & 0xFF;        /* and get the prefixed character. */
                    358:        }
                    359:        b8 = lsstate ? 0200 : 0;        /* 8th-bit value from SHIFT-STATE */
                    360:        if (ebqflg && a == ebq) {       /* Have 8th-bit prefix? */
                    361:            b8 ^= 0200;                 /* Yes, invert the 8th bit's value, */
                    362:            ssflg = 1;                  /* remember we did this, */
                    363:            a = *xdbuf++ & 0xFF;        /* and get the prefixed character. */
                    364:        } else ssflg = 0;
                    365: 
                    366:        if (a == ctlq) {                /* If control prefix, */
                    367:            a  = *xdbuf++ & 0xFF;       /* get its operand */
                    368:            a7 = a & 0x7F;              /* and its low 7 bits. */
                    369:            if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Controllify */
                    370:              a = ctl(a);               /* if in control range. */
                    371:            if (lscapu) {               /* If doing locking shifts... */
                    372:                if (lsstate)            /* If SHIFTED */
                    373:                  a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
                    374:                else                    /* otherwise */
                    375:                  a8 = a | b8;          /* OR in 8th bit */
                    376:                /* If we're not in a quoted sequence */
                    377:                if (!lsquote && (!lsstate || !ssflg)) {
                    378:                    if (a8 == DLE) {    /* Check for DLE quote */
                    379:                        lsquote = 1;    /* prefixed by single shift! */
                    380:                        continue;
                    381:                    } else if (a8 == SO) { /* Check for Shift-Out */
                    382:                        lsstate = 1;    /* SHIFT-STATE = SHIFTED */
                    383:                        continue;
                    384:                    } else if (a8 == SI) { /* or Shift-In */
                    385:                        lsstate = 0;    /* SHIFT-STATE = UNSHIFTED */
                    386:                        continue;
                    387:                    }
                    388:                } else lsquote = 0;
                    389:            }
                    390:        }
                    391:        a |= b8;                        /* OR in the 8th bit */
                    392:        if (rpt == 0) rpt = 1;          /* If no repeats, then one */
                    393:        if (!binary) {                  /* If in text mode, */
                    394: #ifdef NLCHAR
                    395:            if (a == CR) continue;      /* Discard carriage returns, */
                    396:            if (a == LF) a = NLCHAR;    /* convert LF to system's newline. */
                    397: #endif /* NLCHAR */
                    398: 
                    399: #ifndef NOCSETS                                /* Character-set translation */
                    400: #ifdef KANJI                           /* For Kanji transfers, */
                    401:            if (tcharset != TC_JEUC)    /* postpone translation. */
                    402: #endif /* KANJI */
                    403:              if (xlate && rx) a = (*rx)((CHAR) a); /* Translate charset */
                    404: #endif /* NOCSETS */
                    405:        }
                    406:        if (fn == putfil) { /* (PWP) speedup via buffered output and a macro */
                    407:            for (; rpt > 0; rpt--) {    /* Output the char RPT times */
                    408: #ifndef NOCSETS
                    409: #ifdef KANJI
                    410:                if (!binary && tcharset == TC_JEUC &&
                    411:                    fcharset != FC_JEUC) { /* Translating from J-EUC */
                    412:                    if (ffc == 0L) xkanjf();
                    413:                    if (xkanji(a,fn) < 0)  /* to something else? */
                    414:                      return(-1);
                    415:                } else
                    416: #endif /* KANJI */
                    417: #endif /* NOCSETS */
                    418:                if ((t = zmchout(a & fmask)) < 0) { /* zmchout is a macro */
                    419: #ifdef COMMENT
                    420: /* Too costly, uncomment these if you really need them. */
                    421:                    debug(F101,"decode zmchout","",t);
                    422:                    debug(F101,"decode zoutcnt","",zoutcnt);
                    423:                    debug(F101,"decode a","",a);
                    424: #endif /* COMMENT */
                    425:                    return(-1);
                    426:                }
                    427:                ffc++;                  /* Count the character */
                    428:            }
                    429:        } else {                        /* Output to something else. */
                    430:            a &= fmask;                 /* Apply file mask */
                    431:            for (; rpt > 0; rpt--) {    /* Output the char RPT times */
                    432:                if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
                    433:                ffc++;
                    434:            }
                    435:        }
                    436:     }
                    437:     return(0);
                    438: }
                    439: 
                    440: /*  G E T P K T -- Fill a packet data field  */
                    441: 
                    442: /*
                    443:  Gets characters from the current source -- file or memory string.
                    444:  Encodes the data into the packet, filling the packet optimally.
                    445:  Set first = 1 when calling for the first time on a given input stream
                    446:  (string or file).
                    447: 
                    448:  Call with:
                    449:  bufmax -- current send-packet size
                    450:  xlate  -- flag: 0 to skip character-set translation, 1 to translate
                    451: 
                    452:  Uses global variables:
                    453:  t     -- current character.
                    454:  first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
                    455:  next  -- next character.
                    456:  data  -- pointer to the packet data buffer.
                    457:  size  -- number of characters in the data buffer.
                    458:  memstr - flag that input is coming from a memory string instead of a file.
                    459:  memptr - pointer to string in memory.
                    460:  (*sx)()  character set translation function
                    461: 
                    462: Returns the size as value of the function, and also sets global "size",
                    463: and fills (and null-terminates) the global data array.  Returns 0 upon eof.
                    464: 
                    465: Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
                    466: Incorporates old getchx() and encode() inline to reduce function calls,
                    467: uses buffered input for much-improved efficiency, and clears up some
                    468: confusion with line termination (CRLF vs LF vs CR).
                    469: 
                    470: Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
                    471: May 1991.
                    472: */
                    473: 
                    474: /*
                    475:   Lookahead function to decide whether locking shift is worth it.  Looks at
                    476:   the next four input characters to see if all of their 8th bits match the
                    477:   argument.  Call with 0 or 0200.  Returns 1 if so, 0 if not.  If we don't
                    478:   happen to have at least 4 more characters waiting in the input buffer,
                    479:   returns 1.  Note that zinptr points two characters ahead of the current
                    480:   character because of repeat-count lookahead.
                    481: */
                    482: 
                    483: #ifdef KANJI
                    484: int
                    485: kgetf() {
                    486:     return(zminchar());
                    487: }
                    488: 
                    489: int
                    490: kgetm() {
                    491:     int x;
                    492:     if (x = *memptr++) return(x);
                    493:     else return(-1);
                    494: }
                    495: #endif /* KANJI */
                    496: 
                    497: int
                    498: lslook(b) unsigned int b; {            /* Locking Shift Lookahead */
                    499:     int i;
                    500:     if (zincnt < 3)                    /* If not enough chars in buffer, */
                    501:       return(1);                       /* force shift-state switch. */
                    502:     b &= 0200;                         /* Force argument to proper form. */
                    503:     for (i = -1; i < 3; i++)           /* Look at next 5 characters to */
                    504:       if (((*(zinptr+i)) & 0200) != b) /* see if all their 8th bits match.  */
                    505:        return(0);                      /* They don't. */
                    506:     return(1);                         /* They do. */
                    507: }
                    508: 
                    509: int
                    510: getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
                    511:     register CHAR rt = t, rnext = next; /* register shadows of the globals */
                    512:     register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
                    513:     register int x;                    /* Loop index. */
                    514:     register int a7;                   /* Low 7 bits of character */
                    515:     static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' };
                    516:     CHAR xxls, xxdl, xxrc, xxss, xxcq; /* Pieces of prefixed sequence */
                    517:     int n;                             /* worker */
                    518: 
                    519: /*
                    520:   Assume bufmax is the receiver's total receive-packet buffer length.
                    521:   Our whole packet has to fit into it, so we adjust the data field length.
                    522:   We also decide optimally whether it is better to use a short-format or
                    523:   long-format packet when we're near the borderline.
                    524: */
                    525:     n = bufmax - 5;                    /* Space for Data and Checksum */
                    526:     if (n > 92 && n < 96) n = 92;      /* "Short" Long packets don't pay */
                    527:     if (n > 92 && lpcapu == 0)         /* If long packets needed, */
                    528:       n = 92;                          /* make sure they've been negotiated */
                    529:     bufmax = n - bctl;                 /* Space for data */
                    530:     if (n > 92) bufmax -= 3;           /* Long packet needs header chksum */
                    531: 
                    532:     if (first == 1) {          /* If first character of this file... */
                    533:        ffc = 0L;               /* Reset file character counter */
                    534:        first = 0;              /* Next character won't be first */
                    535:        *leftover = '\0';       /* Discard any interrupted leftovers, */
                    536: 
                    537:        /* get first character of file into rt, watching out for null file */
                    538: 
                    539: #ifndef NOCSETS
                    540: #ifdef KANJI
                    541:        if (!binary && tcharset == TC_JEUC && xlate) {
                    542:            x = zkanjf();
                    543:            if ((x = zkanji( memstr ? kgetm : kgetf )) < 0) {
                    544:                first = -1;
                    545:                size = 0;
                    546:                if (x == -2) {
                    547:                    debug(F100,"getpkt(zkanji): input error","",0);
                    548:                    cxseen = 1;
                    549:                } else debug(F100,"getpkt(zkanji): empty string/file","",0);
                    550:                return (0);
                    551:            }
                    552:            ffc++;
                    553:            rt = x;
                    554:        } else {
                    555: #endif /* KANJI */
                    556: #endif /* not NOCSETS */
                    557:        if (memstr) {                   /* Reading data from memory string */
                    558:            if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
                    559:                first = -1;
                    560:                size = 0;
                    561:                debug(F100,"getpkt: empty string","",0);
                    562:                return (0);
                    563:            }
                    564: 
                    565:        } else {                        /* Reading data from a file */
                    566: 
                    567:            if ((x = zminchar()) < 0) { /* End of file or input error */
                    568:                first = -1;
                    569:                size = 0;
                    570:                if (x == -2) {          /* Error */
                    571:                    debug(F100,"getpkt: input error","",0);
                    572:                    cxseen = 1;         /* Interrupt the file transfer */
                    573:                } else debug(F100,"getpkt: empty file","",0); /* Empty file */
                    574:                return(0);
                    575:            }
                    576:            ffc++;                      /* Count a file character */
                    577:            rt = x;                     /* Convert int to char */
                    578:            debug(F101,"getpkt zminchar","",rt);
                    579:        }
                    580: #ifndef NOCSETS
                    581: #ifdef KANJI
                    582:        }
                    583: #endif /* KANJI */
                    584: #endif /* not NOCSETS */
                    585: 
                    586:        rt &= fmask;                    /* Apply SET FILE BYTESIZE mask */
                    587:        debug(F101,"getpkt fmask","",fmask);
                    588:        debug(F101,"getpkt new rt","",rt);
                    589: 
                    590: #ifndef NOCSETS
                    591:        if (xlate) {
                    592:            debug(F101,"getpkt about to call translate function","",rt);
                    593:            debug(F101,"tcharset","",tcharset);
                    594:            debug(F101,"fcharset","",fcharset);
                    595:        }
                    596: #ifdef KANJI
                    597:        if (tcharset != TC_JEUC)
                    598: #endif /* KANJI */
                    599:          if (!binary && sx && xlate) {
                    600:              rt = (*sx)(rt); /* Translate */
                    601:              debug(F101," translate function returns","",rt);
                    602:          }
                    603: #endif /* not NOCSETS */
                    604: 
                    605:        /* PWP: handling of NLCHAR is done later (in the while loop)... */
                    606: 
                    607:     } else if ((first == -1) && (*leftover == '\0')) /* EOF from last time? */
                    608:         return(size = 0);
                    609: /*
                    610:   Here we handle characters that were encoded for the last packet but
                    611:   did not fit, and so were saved in the "leftover" array.
                    612: */
                    613:     dp = data;                         /* Point to packet data buffer */
                    614:     for (p1 = leftover; (*dp = *p1) != '\0'; p1++, dp++) /* Copy leftovers */
                    615:        ;
                    616:     *leftover = '\0';                  /* Delete leftovers */
                    617:     if (first == -1)                   /* Handle EOF */
                    618:       return(size = (dp - data));
                    619:   
                    620: /* Now fill up the rest of the packet. */
                    621: 
                    622:     rpt = 0;                           /* Initialize character repeat count */
                    623: 
                    624:     while (first > -1) {               /* Until EOF... */
                    625: #ifndef NOCSETS
                    626: #ifdef KANJI
                    627:        if (!binary && xlate && tcharset == TC_JEUC) {
                    628:            if ((x = zkanji( memstr ? kgetm : kgetf )) < 0) {
                    629:                first = -1;
                    630:                if (x == -2) cxseen = 1;
                    631:            }
                    632:            ffc++;
                    633:            rnext = x & fmask;
                    634:        } else {
                    635: #endif /* KANJI */
                    636: #endif /* not NOCSETS */
                    637:        if (memstr) {                   /* Get next char from memory string */
                    638:            if ((x = *memptr++) == '\0') /* End of string means EOF */
                    639:              first = -1;               /* Flag EOF for next time. */
                    640:            rnext = x & fmask;          /* Apply file mask */
                    641:        } else {
                    642:            if ((x = zminchar()) < 0) { /* Real file, check for EOF */
                    643:                first = -1;             /* Flag eof for next time. */
                    644:                if (x == -2) cxseen = 1; /* If error, cancel this file. */
                    645:            }
                    646:            rnext = x & fmask;          /* Apply file mask */
                    647:        } 
                    648:        ffc++;                          /* Count the character */
                    649: #ifndef NOCSETS
                    650: #ifdef KANJI
                    651:        }
                    652: #endif /* KANJI */
                    653: #endif /* not NOCSETS */
                    654: 
                    655:        /*** debug(F101,"getpkt rnext","",rnext); ***/
                    656: 
                    657: #ifndef NOCSETS
                    658: #ifdef KANJI
                    659:        if (tcharset != TC_JEUC)
                    660: #endif /* KANJI */
                    661:            if (!binary && sx && xlate) {
                    662:                rnext = (*sx)(rnext); /* Translate */
                    663:                debug(F101,"getpkt xlated rnext to","",rnext);
                    664:            }
                    665: #endif /* not NOCSETS */
                    666: 
                    667:        odp = dp;                       /* Remember where we started. */
                    668:        xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */
                    669: 
                    670: /*
                    671:   Now encode the character according to the options that are in effect:
                    672:     binary: text or binary mode.
                    673:     rptflg: repeat counts enabled.
                    674:     ebqflg: 8th-bit prefixing enabled.
                    675:     lscapu: locking shifts enabled.
                    676: */
                    677:        if (rptflg) {                   /* Repeat processing is on? */
                    678:            if (
                    679: #ifdef NLCHAR
                    680:                /*
                    681:                 * If the next char is really CRLF, then we cannot
                    682:                 * be doing a repeat (unless CR,CR,LF which becomes
                    683:                 * "~ <n-1> CR CR LF", which is OK but not most efficient).
                    684:                 * I just plain don't worry about this case.  The actual
                    685:                 * conversion from NL to CRLF is done after the rptflg if...
                    686:                 */
                    687:            (binary || (rnext != NLCHAR)) &&
                    688: #endif /* NLCHAR */
                    689:            (rt == rnext) && (first == 0)) { /* Got a run... */
                    690:                if (++rpt < 94) {       /* Below max, just count */
                    691:                    continue;           /* go back and get another */
                    692:                }
                    693:                else if (rpt == 94) {   /* Reached max, must dump */
                    694:                    xxrc = tochar(rpt); /* Put the repeat count here */
                    695:                    rptn += rpt;        /* Accumulate it for statistics */
                    696:                    rpt = 0;            /* And reset it */
                    697:                }
                    698:            } else if (rpt > 1) {       /* More than two */
                    699:                xxrc = tochar(++rpt);   /* and count. */
                    700:                rptn += rpt;
                    701:                rpt = 0;                /* Reset repeat counter. */
                    702:            }
                    703:            /*
                    704:              If (rpt == 1) we must encode exactly two characters.
                    705:              This is done later, after the first character is encoded.
                    706:            */
                    707:        }
                    708: 
                    709: #ifdef NLCHAR
                    710:        if (!binary && (rt == NLCHAR)) { /* It's the newline character */
                    711:            if (lscapu && lsstate) {    /* If SHIFT-STATE is SHIFTED */
                    712:                if (ebqflg) {           /* If single shifts enabled, */
                    713:                    *dp++ = ebq;        /* insert a single shift. */
                    714:                } else {                /* Otherwise must shift in. */
                    715:                    *dp++ = myctlq;     /* Insert shift-out code */
                    716:                    *dp++ = 'O';
                    717:                    lsstate = 0;        /* Change shift state */
                    718:                }
                    719:            }
                    720:            *dp++ = myctlq;             /* Insert carriage return directly */
                    721:            *dp++ = 'M';
                    722:            rt = LF;                    /* Now make next char be linefeed. */
                    723:        }
                    724: #endif /* NLCHAR */
                    725: 
                    726: /*
                    727:   Now handle the 8th bit of the file character.  If we have an 8-bit
                    728:   connection, we preserve the 8th bit.  If we have a 7-bit connection,
                    729:   we employ either single or locking shifts (if they are enabled).
                    730: */
                    731:        a7 = rt & 0177;                 /* Get low 7 bits of character */
                    732:        if (rt & 0200) {                /* 8-bit character? */
                    733:            if (lscapu) {               /* Locking shifts enabled? */
                    734:                if (!lsstate) {         /* Not currently shifted? */
                    735:                    x = lslook(0200);   /* Look ahead */
                    736:                    if (x != 0 || ebqflg == 0) { /* Locking shift decision */
                    737:                        xxls = 'N';        /* Need locking shift-out */
                    738:                        lsstate = 1;       /* and change to shifted state */
                    739:                    } else if (ebqflg) {   /* Not worth it */
                    740:                        xxss = ebq;        /* Use single shift */
                    741:                    }
                    742:                }
                    743:                rt = a7;                /* Replace character by 7-bit value */
                    744:            } else if (ebqflg) {        /* 8th bit prefixing is on? */
                    745:                xxss = ebq;             /* Insert single shift */
                    746:                rt = a7;                /* Replace character by 7-bit value */
                    747:            }
                    748: 
                    749:        } else if (lscapu) {            /* 7-bit character */
                    750: 
                    751:            if (lsstate) {              /* Comes while shifted out? */
                    752:                x = lslook(0);          /* Yes, look ahead */
                    753:                if (x || ebqflg == 0) { /* Time to shift in. */
                    754:                    xxls = 'O';         /* Set shift-in code */
                    755:                    lsstate = 0;        /* Exit shifted state */
                    756:                } else if (ebqflg) {    /* Not worth it, stay shifted out */
                    757:                    xxss = ebq;         /* Insert single shift */
                    758:                }
                    759:            }
                    760:        }
                    761:        /* If data character is significant to locking shift protocol... */
                    762:        if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
                    763:          xxdl = 'P';                   /* Insert datalink escape */
                    764: 
                    765:        if ((a7 < SP) || (a7 == DEL)) { /* Do control prefixing if necessary */
                    766:            xxcq = myctlq;              /* The prefix */
                    767:            rt = ctl(rt);               /* Uncontrollify the character */
                    768:        }
                    769:        if (a7 == myctlq)               /* Always prefix the control prefix */
                    770:          xxcq = myctlq;
                    771: 
                    772:        if ((rptflg) && (a7 == rptq))   /* If it's the repeat prefix, */
                    773:          xxcq = myctlq;                /* prefix it if doing repeat counts */
                    774: 
                    775:        if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th-bit prefix */
                    776:          xxcq = myctlq;                /* if doing 8th-bit prefixes */
                    777: 
                    778: /* Now construct the entire sequence */
                    779: 
                    780:        if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
                    781:        odp2 = dp;                                  /* (Save this place) */
                    782:        if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
                    783:        if (xxrc) { *dp++ = rptq;   *dp++ = xxrc; } /* Repeat count */
                    784:        if (xxss) { *dp++ = ebq; }                  /* Single shift */
                    785:        if (xxcq) { *dp++ = myctlq; }               /* Control prefix */
                    786:        *dp++ = rt;                     /* Finally, the character itself */
                    787: 
                    788:        if (rpt == 1) {                 /* Exactly two copies? */
                    789:            rpt = 0;
                    790:            p2 = dp;                    /* Save place temporarily */
                    791:            for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
                    792:              *dp++ = *p1;
                    793:            if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
                    794:        }
                    795:        rt = rnext;                     /* Next character is now current. */
                    796: 
                    797: /* Done encoding the character.  Now take care of packet buffer overflow. */
                    798: 
                    799:        if ((dp-data) >= bufmax) {      /* If too big, save some for next. */
                    800:            size = (dp-data);           /* Calculate the size. */
                    801:            *dp = '\0';                 /* Mark the end. */
                    802:            if ((dp-data) > bufmax) {   /* if packet is overfull */
                    803:                /* copy the part that doesn't fit into the leftover buffer, */
                    804:                /* taking care not to split a prefixed sequence. */
                    805:                for (p1 = leftover, p2=odp; (*p1 = *p2) != '\0'; p1++,p2++)
                    806:                    ;
                    807:                debug(F111,"getpkt leftover",leftover,size);
                    808:                debug(F101," osize","",(odp-data));
                    809:                size = (odp-data);      /* Return truncated packet. */
                    810:                *odp = '\0';            /* Mark the new end */
                    811:            }
                    812:            t = rt; next = rnext;       /* save for next time */
                    813:            return(size);
                    814:        }
                    815:     }                                  /* Otherwise, keep filling. */
                    816: 
                    817:     size = (dp-data);                  /* End of file */
                    818:     *dp = '\0';                                /* Mark the end of the data. */
                    819:     debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
                    820:     return(size);                   /* return partially filled last packet. */
                    821: }
                    822: 
                    823: /*  T I N I T  --  Initialize a transaction  */
                    824: 
                    825: int
                    826: tinit() {
                    827:     int x;
                    828: 
                    829: #ifndef NOCSETS
                    830:     if (tcharset == TC_TRANSP) {       /* Character set translation */
                    831:        rx = sx = NULL;                 /* Transparent, no translation */
                    832: #ifdef KANJI
                    833:     } else if (tcharset == TC_JEUC) {
                    834:        rx = sx = NULL;                 /* Transparent, no translation */      
                    835: #endif /* KANJI */
                    836:     } else {                           /* otherwise */
                    837:        rx = xlr[tcharset][fcharset];   /* Input translation function */
                    838:        sx = xls[tcharset][fcharset];   /* Output translation function */
                    839:     }
                    840:     debug(F101,"tinit tcharset","",tcharset);
                    841:     debug(F101,"tinit fcharset","",fcharset);
                    842: #ifdef COMMENT
                    843:     debug(F101,"tinit sx   ","",sx);
                    844:     debug(F101,"tinit rx   ","",rx);
                    845: #endif /* COMMENT */
                    846: #endif /* NOCSETS */
                    847:     myinit[0] = '\0';                  /* Haven't sent init string yet */
                    848:     autopar = 0;                       /* Automatic parity detection flag */
                    849:     retrans = 0;                       /* Packet retransmission count */
                    850:     sndtyp = 0;                                /* No previous packet */
                    851:     xflg = 0;                          /* Reset x-packet flag */
                    852:     rqf = -1;                          /* Reset 8th-bit-quote request flag */
                    853:     memstr = 0;                                /* Reset memory-string flag */
                    854:     memptr = NULL;                     /*  and pointer */
                    855:     bctu = bctl = 1;                   /* Reset block check type to 1 */
                    856:     ebq = MYEBQ;                       /* Reset 8th-bit quoting stuff */
                    857:     ebqflg = 0;
                    858:     if (savmod) {                      /* If global file mode was saved, */
                    859:        binary = savmod;                /*  restore it, */
                    860:        savmod = 0;                     /*  unsave it. */
                    861:     }
                    862:     pktnum = 0;                                /* Initial packet number */
                    863:     cxseen = czseen = discard = 0;     /* Reset interrupt flags */
                    864:     *filnam = '\0';                    /* Clear file name */
                    865:     spktl = 0;                         /* And its length */
                    866:     nakstate = 0;                      /* Assume not in a NAK'ing state */
                    867:     numerrs = 0;                       /* Transmission error counter */
                    868:     if (server)                        /* If acting as server, */
                    869:       timint = srvtim;                 /* Use server timeout interval. */
                    870:     else                               /* Otherwise */
                    871:       timint = chktimo(rtimo,timef);   /* Begin by using local value */
                    872:     spsiz = spsizr;                    /* Initial send-packet size */
                    873:     wslots = 1;                                /* One window slot */
                    874:     wslotn = 1;                                /* No window negotiated yet */
                    875:     winlo = 0;                         /* Packet 0 is at window-low */
                    876:     x = mksbuf(1);                     /* Make a 1-slot send-packet buffer */
                    877:     if (x < 0) return(x);
                    878:     x = getsbuf(0);                    /* Allocate first send-buffer. */
                    879:     debug(F101,"tinit getsbuf","",x);
                    880:     if (x < 0) return(x);
                    881:     dumpsbuf();
                    882:     x = mkrbuf(wslots);                        /* & a 1-slot receive-packet buffer. */
                    883:     if (x < 0) return(x);
                    884:     what = W_NOTHING;                  /* Doing nothing so far... */
                    885:     lsstate = 0;                       /* Initialize locking shift state */
                    886:     return(0);
                    887: }
                    888: 
                    889: VOID
                    890: pktinit() {                            /* Initialize packet sequence */
                    891:     pktnum = 0;                                /* number & window low. */
                    892:     winlo = 0;
                    893: }
                    894: 
                    895: /*  R I N I T  --  Respond to S or I packet  */
                    896: 
                    897: VOID
                    898: rinit(d) CHAR *d; {
                    899:     char *tp;
                    900:     ztime(&tp);
                    901:     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
                    902:     if (binary)
                    903:       tlog(F100,"Global file mode = binary","",0L);
                    904:     else
                    905:       tlog(F100,"Global file mode = text","",0L);
                    906:     filcnt = 0;                                /* Init file counter */
                    907:     spar(d);
                    908:     ack1(rpar());
                    909: #ifdef datageneral
                    910:     if ((local) && (!quiet))            /* Only do this if local & not quiet */
                    911:         consta_mt();                    /* Start the asynch read task */
                    912: #endif /* datageneral */
                    913: }
                    914: 
                    915: 
                    916: /*  R E S E T C  --  Reset per-transaction character counters */
                    917: 
                    918: VOID
                    919: resetc() {
                    920:     rptn = 0;                          /* Repeat counts */
                    921:     fsecs = flci = flco = 0L;          /* File chars in and out */
                    922:     tfc = tlci = tlco = 0L;            /* Total file, line chars in & out */
                    923: #ifdef COMMENT
                    924:     fsize = -1L;                       /* File size */
                    925: #else
                    926:     if (what != W_SEND)
                    927:       fsize = -1L;
                    928:     debug(F101,"resetc fsize","",fsize);
                    929: #endif /* COMMENT */
                    930:     timeouts = retrans = 0;            /* Timeouts, retransmissions */
                    931:     spackets = rpackets = 0;           /* Packet counts out & in */
                    932:     crunched = 0;                      /* Crunched packets */
                    933:     wmax = 1;                          /* Maximum window size used */
                    934: }
                    935: 
                    936: /*  S I N I T  --  Get & verify first file name, then send Send-Init packet */
                    937: /*
                    938:  Returns:
                    939:    1 if send operation begins successfully
                    940:    0 if send operation fails
                    941: */
                    942: #ifdef DYNAMIC
                    943: char *cmargbuf = NULL;
                    944: #else
                    945: char cmargbuf[256];
                    946: #endif /* DYNAMIC */
                    947: char *cmargp[2];
                    948: 
                    949: int
                    950: sinit() {
                    951:     int x;                             /* Worker int */
                    952:     char *tp, *xp, *m;                 /* Worker string pointers */
                    953: 
                    954:     filcnt = 0;                                /* Initialize file counter */
                    955:     sndsrc = nfils;                    /* Source for filenames */
                    956: #ifdef DYNAMIC
                    957:     if (!cmargbuf && !(cmargbuf = malloc(256)))
                    958:        fatal("sinit: no memory for cmargbuf");
                    959: #endif /* DYNAMIC */
                    960:     cmargbuf[0] = NUL;                 /* Initialize name buffer */
                    961: 
                    962:     debug(F101,"sinit nfils","",nfils);
                    963:     debug(F110,"sinit cmarg",cmarg,0);
                    964:     debug(F110,"sinit cmarg2",cmarg2,0);
                    965:     if (nfils == 0) {                  /* Sending from stdin or memory. */
                    966:        if ((cmarg2 != NULL) && (*cmarg2)) {
                    967:            cmarg = cmarg2;             /* If F packet, "as-name" is used */
                    968:            cmarg2 = "";                /* if provided */
                    969:        } else cmarg = "stdin";         /* otherwise just use "stdin" */
                    970:        strcpy(cmargbuf,cmarg);
                    971:        cmargp[0] = cmargbuf;
                    972:        cmargp[1] = "";
                    973:        cmlist = cmargp;
                    974:        nfils = 1;
                    975:     }
                    976: #ifdef COMMENT
                    977:     if (nfils < 1) {                   /* Filespec pointed to by cmarg */
                    978:        if (nfils < 0) sndsrc = 1;
                    979:        nfils = 1;                      /* Change it to cmlist */
                    980:        strcpy(cmargbuf,cmarg);         /* so we have a consistent way */
                    981:        cmargp[0] = cmargbuf;           /* of going thru the file list. */
                    982:        cmargp[1] = "";
                    983:        cmlist = cmargp;
                    984:     }
                    985: 
                    986: /* At this point, cmlist contains the list of filespecs to send */
                    987: 
                    988:     debug(F111,"sinit *cmlist",*cmlist,nfils);
                    989: 
                    990:     xp = *cmlist;                      /* Save this for messages */
                    991: #else
                    992:     xp = (nfils < 0) ? cmarg : *cmlist;
                    993: #endif
                    994: 
                    995:     x = gnfile();                      /* Get first filename. */
                    996:     m = NULL;                          /* Error message pointer */
                    997:     debug(F101,"sinit gnfil","",x);
                    998:     switch (x) {
                    999:       case -5: m = "Too many files match wildcard"; break;
                   1000:       case -4: m = "Cancelled"; break;
                   1001:       case -3: m = "Read access denied"; break;
                   1002:       case -2: m = "File is not readable"; break;
                   1003:       case -1: m = iswild(filnam) ? "No files match" : "File not found";
                   1004:        break;
                   1005:       case  0: m = "No filespec given!" ; break;
                   1006:       default:
                   1007:        break;
                   1008:     }
                   1009:     debug(F101,"sinit nfils","",nfils);
                   1010:     debug(F110,"sinit filnam",filnam,0);
                   1011:     debug(F110,"sinit cmdstr",cmdstr,0);
                   1012:     if (x < 1) {                       /* Didn't get a file. */
                   1013:        if (server)                     /* Doing GET command */
                   1014:          errpkt((CHAR *)m);            /* so send Error packet. */
                   1015:        else                            /* Doing SEND command */
                   1016:          screen(SCR_EM,0,0l,m);        /* so print message. */
                   1017:        tlog(F110,xp,m,0L);             /* Make transaction log entry. */
                   1018:        freerbuf(rseqtbl[0]);           /* Free the buffer the GET came in. */
                   1019:        return(0);                      /* Return failure code */
                   1020:     }
                   1021:     if (!local && !server) sleep(delay); /* Delay if requested */
                   1022: #ifdef datageneral
                   1023:     if ((local) && (!quiet))            /* Only do this if local & not quiet */
                   1024:         consta_mt();                    /* Start the asynch read task */
                   1025: #endif /* datageneral */
                   1026:     freerbuf(rseqtbl[0]);              /* Free the buffer the GET came in. */
                   1027:     sipkt('S');                                /* Send the Send-Init packet. */
                   1028:     ztime(&tp);                                /* Get current date/time */
                   1029:     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
                   1030:     debug(F111,"sinit ok",filnam,0);
                   1031:     return(1);
                   1032: }
                   1033: 
                   1034: int
                   1035: #ifdef CK_ANSIC
                   1036: sipkt(char c)                          /* Send S or I packet. */
                   1037: #else
                   1038: sipkt(c) char c;
                   1039: #endif
                   1040: /* sipkt */ {
                   1041:     CHAR *rp; int k;
                   1042:     debug(F101,"sipkt pktnum","",pktnum);
                   1043:     k = sseqtbl[pktnum];               /* Find slot for this packet */
                   1044:     debug(F101,"sipkt k","",k);
                   1045:     if (k < 0) {                       /* No slot? */
                   1046:        k = getsbuf(winlo = pktnum);    /* Make one. */
                   1047:        debug(F101,"sipkt getsbuf","",k);    
                   1048:     }
                   1049:     ttflui();                          /* Flush pending input. */
                   1050:     rp = rpar();                       /* Get protocol parameters. */
                   1051:     return(spack(c,pktnum,(int)strlen((char *)rp),rp)); /* Send them. */
                   1052: }
                   1053: 
                   1054: /*  X S I N I T  --  Retransmit S-packet  */
                   1055: /*
                   1056:   For use in the GET-SEND sequence, when we start to send, but receive another
                   1057:   copy of the GET command because the receiver didn't get our S packet.
                   1058:   This retransmits the S packet and frees the receive buffer for the ACK.
                   1059:   The only reason this special case is necessary is that packet number zero
                   1060:   is being re-used.
                   1061: */
                   1062: VOID
                   1063: xsinit() {
                   1064:     int k;     
                   1065:     k = rseqtbl[0];
                   1066:     debug(F101,"xsinit k","",k);
                   1067:     if (k > -1)
                   1068:       freerbuf(k);
                   1069:     resend(0);
                   1070: }        
                   1071: 
                   1072: /*  R C V F I L -- Receive a file  */
                   1073: 
                   1074: /*
                   1075:   Incoming filename is in data field of F packet.
                   1076:   This function decodes it into the srvcmd buffer, substituting an
                   1077:   alternate "as-name", if one was given.
                   1078:   Then it does any requested transformations (like converting to
                   1079:   lowercase), and finally if a file of the same name already exists, 
                   1080:   takes the desired collision action.
                   1081: */
                   1082: #ifdef pdp11
                   1083: #define XNAMLEN 256
                   1084: #else
                   1085: #define XNAMLEN 65
                   1086: #endif /* pdp11 */
                   1087: 
                   1088: int
                   1089: rcvfil(n) char *n; {
                   1090:     char xname[XNAMLEN], *xp;          /* Buffer for constructing name */
                   1091: #ifdef DTILDE
                   1092:     char *dirp, *tilde_expand();
                   1093: #endif /* DTILDE */
                   1094: 
                   1095:     lsstate = 0;                       /* Cancel locking-shift state */
                   1096:     srvptr = srvcmd;                   /* Decode file name from packet. */
                   1097:     decode(rdatap,putsrv,0);           /* Don't xlate charsets. */
                   1098:     if (*srvcmd == '\0')               /* Watch out for null F packet. */
                   1099:       strcpy((char *)srvcmd,"NONAME");
                   1100: #ifdef DTILDE
                   1101:     dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
                   1102:     if (*dirp != '\0') strcpy((char *)srvcmd,dirp);
                   1103: #endif /* DTILDE */
                   1104:     screen(SCR_FN,0,0l,(char *)srvcmd);        /* Put it on screen if local */
                   1105:     debug(F110,"rcvfil",(char *)srvcmd,0); /* Debug log entry */
                   1106:     debug(F101,"rcvfil cmarg2","",cmarg2);
                   1107:     tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
                   1108:     if (cmarg2 != NULL) {               /* Check for alternate name */
                   1109:         if (*cmarg2 != '\0') {
                   1110:             strcpy((char *)srvcmd,cmarg2); /* Got one, use it. */
                   1111:         }
                   1112:     } else cmarg2 = "";
                   1113: /*
                   1114:   NOTE: Much of this code should be moved to opena(), where the file is
                   1115:   actually opened, AFTER we have received the Attribute packet(s).  That
                   1116:   way, if the file is mail, or is being sent to the printer, we don't have
                   1117:   to fuss with collision options, etc, but instead we just pipe the data
                   1118:   straight into lpr or mail (in UNIX anyway), and then we can also have
                   1119:   nice subject lines for mail messages by using whatever is in the file
                   1120:   header packet data field, whether it's a legal filename or not.
                   1121: */
                   1122:     if ((int)strlen((char *)srvcmd) > XNAMLEN) /* Watch out for overflow */
                   1123:       *(srvcmd + XNAMLEN - 1) = NUL;
                   1124: 
                   1125:     xp = xname;                                /* OK to proceed. */
                   1126:     if (fncnv && !*cmarg2)
                   1127:       zrtol((char *)srvcmd,xp);                /* convert name to local form */
                   1128:     else                               /* otherwise, */
                   1129:       strcpy(xname,(char *)srvcmd);    /* use it literally */
                   1130:     cmarg2 = "";                       /* Remove alternate name */
                   1131:     debug(F110,"rcvfil as",xname,0);
                   1132: 
                   1133: #ifdef COMMENT                         /* Old code... */
                   1134:     if (warn) {                                /* File collision avoidance? */
                   1135:        if (zchki(xname) != -1) {       /* Yes, file exists? */
                   1136:            znewn(xname,&xp);           /* Yes, make new name. */
                   1137:            strcpy(xname,xp);
                   1138:            debug(F110," exists, new name ",xname,0);
                   1139:         }
                   1140:     }
                   1141: #endif /* COMMENT */
                   1142: 
                   1143: /* Filename collision action section. */
                   1144: 
                   1145:     if (
                   1146: #ifdef UNIX
                   1147:        strcmp(xname,"/dev/null") &&    /* It's not the null device? */
                   1148: #endif /* UNIX */
                   1149:        (zchki(xname) != -1)            /* File of same name exists? */
                   1150:        ) {                             
                   1151:        debug(F111,"rcvfil exists",xname,fncact);
                   1152:        switch (fncact) {               /* Yes, do what user said. */
                   1153:          case XYFX_A:                  /* Append */
                   1154:            debug(F100,"rcvfil append","",0);
                   1155:            break;
                   1156:          case XYFX_Q:                  /* Query (Ask) */
                   1157:            break;                      /* not yet implemented */
                   1158:          case XYFX_B:                  /* Backup (rename old file) */
                   1159:            znewn(xname,&xp);           /* Get new unique name */
                   1160:            debug(F110,"rcvfil backup",xname,0);
                   1161:            debug(F110,"rcvfil backup",xp,0);
                   1162:            if (zrename(xname,xp) < 0) {
                   1163:                debug(F110,"rcvfil rename fails",xname,0);
                   1164:                return(0);
                   1165:            }
                   1166:            break;
                   1167:          case XYFX_D:                  /* Discard (refuse new file) */
                   1168:            discard = 1;
                   1169:            debug(F101,"rcvfil discard","",discard);
                   1170:            break;                      /* not yet implemented */
                   1171:          case XYFX_R:                  /* Rename new file */
                   1172:            znewn(xname,&xp);           /* Make new name. */
                   1173:            strcpy(xname,xp);
                   1174:            debug(F110,"rcvfil rename",xname,0);
                   1175:          case XYFX_X:                  /* Replace old file */
                   1176:            debug(F100,"rcvfil overwrite","",0);
                   1177:            break;
                   1178:          case XYFX_U:                  /* Refuse if older */
                   1179:            debug(F100,"rcvfil update","",0);
                   1180:            break;                      /* Not here, we don't have */
                   1181:                                        /* the attribute packet yet. */
                   1182:          default:
                   1183:            debug(F101,"rcvfil bad collision action","",fncact);
                   1184:            break;
                   1185:        }
                   1186:     }
                   1187:     debug(F110,"rcvfil: xname",xname,0);
                   1188:     screen(SCR_AN,0,0l,xname);         /* Display it */
                   1189:     strcpy(n,xname);                   /* Return pointer to actual name. */
                   1190: 
                   1191: #ifndef NOICP
                   1192: #ifndef MAC
                   1193: /* Why not Mac? */
                   1194:     strcpy(fspec,xname);               /* Here too for \v(filespec) */
                   1195: #endif /* MAC */
                   1196: #endif /* NOICP */
                   1197:     debug(F110,"rcvfil: n",n,0);
                   1198:     ffc = 0L;                          /* Init per-file counters */
                   1199:     fsecs = gtimer();                  /* Time this file started */
                   1200:     filcnt++;
                   1201:     intmsg(filcnt);
                   1202:     return(1);                         /* Always succeeds */
                   1203: }
                   1204: 
                   1205: 
                   1206: /*  R E O F  --  Receive End Of File packet for incoming file */
                   1207: 
                   1208: /*
                   1209:   Closes the received file.
                   1210:   Returns:
                   1211:     0 on success.
                   1212:    -1 if file could not be closed.
                   1213:     2 if disposition was mail, mail was sent, but temp file not deleted.
                   1214:     3 if disposition was print, file was printed, but not deleted.
                   1215:    -2 if disposition was mail and mail could not be sent
                   1216:    -3 if disposition was print and file could not be printed
                   1217: */
                   1218: int
                   1219: reof(f,yy) char *f; struct zattr *yy; {
                   1220:     int x;
                   1221:     char *p;
                   1222:     char c;
                   1223: 
                   1224:     debug(F111,"reof fncact",f,fncact);
                   1225:     debug(F101,"reof discard","",discard);
                   1226:     success = 1;                       /* Assume status is OK */
                   1227:     lsstate = 0;                       /* Cancel locking-shift state */
                   1228:     if (
                   1229: #ifdef COMMENT
                   1230: /*
                   1231:   If the discard flag is set, for whatever reason, we discard it, right?
                   1232: */
                   1233:        (fncact == XYFX_D || fncact == XYFX_U) &&
                   1234: #endif /* COMMENT */
                   1235:        discard != 0) {    /* SET FILE COLLISION DISCARD or UPDATE */
                   1236: 
                   1237:        debug(F101,"reof discarding","",0);
                   1238:        discard = 0;                    /* We never opened it, */
                   1239:        return(0);                      /* so we won't close it. */
                   1240:     }
                   1241:     if (cxseen == 0) cxseen = (*rdatap == 'D');        /* Got cancel directive? */
                   1242:     success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
                   1243:     x = clsof(cxseen || czseen);       /* Close the file (resets cxseen) */
                   1244:     if (x < 0) success = 0;            /* If failure to close, FAIL */
                   1245:     if (atcapu) zstime(f,yy,0);                /* Set file creation date */
                   1246: 
                   1247: /* Handle dispositions from attribute packet... */
                   1248: 
                   1249: #ifndef NOFRILLS
                   1250:     if (yy->disp.len != 0) {
                   1251:        p = yy->disp.val;
                   1252:        c = *p++;
                   1253:        if (c == 'M') {                 /* Mail to user. */
                   1254:            x = zmail(p,filnam);        /* Do the system's mail command */
                   1255:            if (x < 0) success = 0;     /* Remember status */
                   1256:            tlog(F110,"mailed",filnam,0L);
                   1257:            tlog(F110," to",p,0L);
                   1258:            zdelet(filnam);             /* Delete the file */
                   1259:        } else if (c == 'P') {          /* Print the file. */
                   1260:            x = zprint(p,filnam);       /* Do the system's print command */
                   1261:            if (x < 0) success = 0;     /* Remember status */
                   1262:            tlog(F110,"printed",filnam,0L);
                   1263:            tlog(F110," with options",p,0L);
                   1264: #ifndef VMS
                   1265:            if (zdelet(filnam) && x == 0) x = 3; /* Delete the file */
                   1266: #endif /* VMS */
                   1267:        }
                   1268:     }
                   1269: #endif /* NOFRILLS */
                   1270:     debug(F101,"reof returns","",x);
                   1271:     *filnam = '\0';
                   1272:     return(x);
                   1273: }
                   1274: 
                   1275: /*  R E O T  --  Receive End Of Transaction  */
                   1276: 
                   1277: VOID
                   1278: reot() {
                   1279:     cxseen = czseen = discard = 0;     /* Reset interruption flags */
                   1280:     tstats();
                   1281: }
                   1282: 
                   1283: /*  S F I L E -- Send File header or teXt header packet  */
                   1284: 
                   1285: /*  Call with x nonzero for X packet, zero for F packet  */
                   1286: /*  Returns 1 on success, 0 on failure                   */
                   1287: 
                   1288: int
                   1289: sfile(x) int x; {
                   1290: #ifdef pdp11
                   1291: #define PKTNL 64
                   1292: #else
                   1293: #define PKTNL 256
                   1294: #endif /* pdp11 */
                   1295:     char pktnam[PKTNL+1];              /* Local copy of name */
                   1296:     char *s;
                   1297: 
                   1298:     lsstate = 0;                       /* Cancel locking-shift state */
                   1299:     if (nxtpkt() < 0) return(0);       /* Bump packet number, get buffer */
                   1300:     if (x == 0) {                      /* F-Packet setup */
                   1301: 
                   1302:        if (*cmarg2 != '\0') {          /* If we have a send-as name, */
                   1303:            strncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
                   1304:            cmarg2 = "";                /* and blank it out for next time. */
                   1305:        } else {                        /* Otherwise use actual file name: */
                   1306:            if (fncnv) {                /* If converting names, */
                   1307:                zltor(filnam,pktnam);   /* convert it to common form, */
                   1308:            } else {                    /* otherwise, */
                   1309:                strncpy(pktnam,filnam,PKTNL); /* copy it literally. */
                   1310:             }
                   1311:        }
                   1312:        debug(F110,"sfile",filnam,0);   /* Log debugging info */
                   1313:        debug(F110," pktnam",pktnam,0);
                   1314:        if (openi(filnam) == 0)         /* Try to open the file */
                   1315:          return(0);            
                   1316:        s = pktnam;                     /* Name for packet data field */
                   1317: 
                   1318:     } else {                           /* X-packet setup */
                   1319: 
                   1320:        debug(F110,"sxpack",cmdstr,0);  /* Log debugging info */
                   1321:        s = cmdstr;                     /* Name for data field */
                   1322:     }
                   1323: 
                   1324:     encstr((CHAR *)s);                 /* Encode the name into encbuf[]. */
                   1325:                                        /* Send the F or X packet */
                   1326:     spack((char) (x ? 'X' : 'F'), pktnum, size, encbuf+7);
                   1327: 
                   1328:     if (x == 0) {                      /* Display for F packet */
                   1329:        if (displa) {                   /* Screen */
                   1330:            screen(SCR_FN,'F',(long)pktnum,filnam);
                   1331:            screen(SCR_AN,0,0l,pktnam);
                   1332:            screen(SCR_FS,0,fsize,"");
                   1333:        }
                   1334:        tlog(F110,"Sending",filnam,0L); /* Transaction log entry */
                   1335:        tlog(F110," as",pktnam,0L);
                   1336:        if (binary) {                   /* Log file mode in transaction log */
                   1337:            tlog(F101," mode: binary","",(long) binary);
                   1338:        } else {                        /* If text mode, check character set */
                   1339:            tlog(F100," mode: text","",0L);
                   1340: #ifndef NOCSETS
                   1341:            tlog(F110," file character set",fcsinfo[fcharset].name,0L);
                   1342:            if (tcharset == TC_TRANSP)
                   1343:              tlog(F110," xfer character set","transparent",0L);
                   1344:            else
                   1345:              tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
                   1346: #endif /* NOCSETS */
                   1347:        }
                   1348:     } else {                           /* Display for X-packet */
                   1349: 
                   1350:        screen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */
                   1351:        tlog(F110,"Sending from:",cmdstr,0L);   /* Transaction log */
                   1352:     }
                   1353:     intmsg(++filcnt);                  /* Count file, give interrupt msg */
                   1354:     first = 1;                         /* Init file character lookahead. */
                   1355:     ffc = 0L;                          /* Init file character counter. */
                   1356:     fsecs = gtimer();                  /* Time this file started */
                   1357:     debug(F101,"SFILE fsecs","",fsecs);
                   1358:     return(1);
                   1359: }
                   1360: 
                   1361: /*  S D A T A -- Send a data packet */
                   1362: 
                   1363: /*
                   1364:   Returns -1 if no data to send (end of file).  If there is data, a data
                   1365:   packet is sent, and sdata() returns 1.
                   1366: 
                   1367:   For window size greater than 1, keep sending data packets until window
                   1368:   is full or characters start to appear from the other Kermit, whichever
                   1369:   happens first.
                   1370: 
                   1371:   In the windowing case, when there is no more data left to send (or when
                   1372:   sending has been interrupted), sdata() does nothing and returns 0 each time
                   1373:   it is called until the current packet number catches up to the last data
                   1374:   packet that was sent.
                   1375: */
                   1376: 
                   1377: int
                   1378: sdata() {
                   1379:     int i, x, len;
                   1380:     
                   1381:     debug(F101,"sdata entry, first","",first);
                   1382:     debug(F101," drain","",drain);
                   1383: 
                   1384: /* The "drain" flag is used with window size > 1.  It means we have sent  */
                   1385: /* our last data packet.  If called and drain is not zero, then we return */
                   1386: /* 0 as if we had sent an empty data packet, until all data packets have  */
                   1387: /* been ACK'd, then then we can finally return -1 indicating EOF, so that */
                   1388: /* the protocol can switch to seof state.  This is a kludge, but at least */
                   1389: /* it's localized...  */
                   1390: 
                   1391:     if (first == 1) drain = 0;         /* Start of file, init drain flag. */
                   1392: 
                   1393:     if (drain) {                       /* If draining... */
                   1394:        debug(F101,"sdata draining, winlo","",winlo);
                   1395:        if (winlo == pktnum)            /* If all data packets are ACK'd */
                   1396:          return(-1);                   /* return EOF indication */
                   1397:        else                            /* otherwise */
                   1398:          return(0);                    /* pretend we sent a data packet. */
                   1399:     }
                   1400:     debug(F101,"sdata sbufnum","",sbufnum);
                   1401:     for (i = sbufnum; i > 0; i--) {
                   1402:         debug(F101,"sdata countdown","",i);
                   1403:        x = nxtpkt();                   /* Get next pkt number and buffer */
                   1404:        debug(F101,"sdata packet","",pktnum);
                   1405:        if (x < 0) return(0);
                   1406: /***   dumpsbuf(); */
                   1407:        if (cxseen || czseen) {         /* If interrupted, done. */
                   1408:            if (wslots > 1) {
                   1409:                drain = 1;
                   1410:                debug(F101,"sdata cx/zseen, drain","",cxseen);
                   1411:                return(0);
                   1412:            } else {
                   1413:                return(-1);
                   1414:            }
                   1415:        }
                   1416: #ifdef COMMENT
                   1417:        if (spsiz > 94)                 /* Fill the packet's data buffer */
                   1418:          len = getpkt(spsiz-bctl-6,1); /* long packet */
                   1419:        else                            /*  or */
                   1420:          len = getpkt(spsiz-bctl-3,1); /* short packet */
                   1421: #else
                   1422:        len = getpkt(spsiz,1);
                   1423: #endif /* COMMENT */
                   1424:        if (len == 0) {                 /* Done if no data. */
                   1425:            if (pktnum == winlo) return(-1);
                   1426:            drain = 1;                  /* But can't return -1 until all */
                   1427:            debug(F101,"sdata eof, drain","",drain);
                   1428:            return(0);                  /* ACKs are drained. */
                   1429:        }
                   1430:        spack('D',pktnum,len,data);     /* Send the data packet. */
                   1431:        x = ttchk();                    /* Peek at input buffer. */
                   1432:        debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe?  */
                   1433:        if (x) return(1);               /* Yes, stop sending data packets */
                   1434:     }                                  /* and go try to read the ACKs. */
                   1435:     return(1);
                   1436: }
                   1437: 
                   1438: 
                   1439: /*  S E O F -- Send an End-Of-File packet */
                   1440: 
                   1441: /*  Call with a string pointer to character to put in the data field, */
                   1442: /*  or else a null pointer or "" for no data.  */
                   1443: 
                   1444: /*
                   1445:   There are two "send-eof" functions.  seof() is used to send the normal eof
                   1446:   packet at the end of a file's data (even if the file has no data), or when
                   1447:   a file transfer is interrupted.  sxeof() is used to send an EOF packet that
                   1448:   occurs because of attribute refusal.  The difference is purely a matter of
                   1449:   buffer allocation and packet sequence number management.  Both functions
                   1450:   act as "front ends" to the common send-eof function, szeof().
                   1451: */
                   1452: 
                   1453: /* Code common to both seof() and sxeof() */
                   1454: 
                   1455: int
                   1456: szeof(s) CHAR *s; {
                   1457:     lsstate = 0;                       /* Cancel locking-shift state */
                   1458:     if ((s != NULL) && (*s != '\0')) {
                   1459:        spack('Z',pktnum,1,s);
                   1460:        tlog(F100," *** interrupted, sending discard request","",0L);
                   1461:     } else {
                   1462:        spack('Z',pktnum,0,(CHAR *)"");
                   1463:     }
                   1464:     discard = 0;                       /* Turn off per-file discard flag */
                   1465:     return(0);
                   1466: }
                   1467: 
                   1468: int
                   1469: seof(s) CHAR *s; {
                   1470: 
                   1471: /*
                   1472:   ckcpro.w, before calling seof(), sets window size back to 1 and then calls
                   1473:   window(), which clears out the old buffers.  This is OK because the final
                   1474:   data packet for the file has been ACK'd.  However, sdata() has already
                   1475:   called nxtpkt(), which set the new value of pktnum which seof() will use.
                   1476:   So all we need to do here is is allocate a new send-buffer.
                   1477: */
                   1478:     if (getsbuf(pktnum) < 0) { /* Get a buffer for packet n */
                   1479:        debug(F101,"seof can't get s-buffer","",pktnum);
                   1480:        return(-1);
                   1481:     }
                   1482:     return(szeof(s));
                   1483: }
                   1484: 
                   1485: /*
                   1486:   Version of seof() to be called when sdata() has not been called before.  The
                   1487:   difference is that this version calls nxtpkt() to allocate a send-buffer and
                   1488:   get the next packet number.
                   1489: */
                   1490: int
                   1491: sxeof(s) CHAR *s; {
                   1492:     int x;
                   1493:     x = nxtpkt();                      /* Get next pkt number and buffer */
                   1494:     if (x < 0)
                   1495:       debug(F101,"sxeof nxtpkt fails","",pktnum);
                   1496:     else
                   1497:       debug(F101,"sxeof packet","",pktnum);
                   1498:     return(szeof(s));
                   1499: }
                   1500: 
                   1501: /*  S E O T -- Send an End-Of-Transaction packet */
                   1502: 
                   1503: int
                   1504: seot() {
                   1505:     if (nxtpkt() < 0) return(-1);      /* Bump packet number, get buffer */
                   1506:     spack('B',pktnum,0,(CHAR *)"");    /* Send the EOT packet */
                   1507:     cxseen = czseen = discard = 0;     /* Reset interruption flags */
                   1508:     tstats();                          /* Log timing info */
                   1509:     return(0);
                   1510: }
                   1511: 
                   1512: /*   R P A R -- Fill the data array with my send-init parameters  */
                   1513: 
                   1514: 
                   1515: CHAR dada[20];                         /* Use this instead of data[]. */
                   1516:                                        /* To avoid some kind of wierd */
                   1517:                                        /* addressing foulup in spack()... */
                   1518:                                        /* (which might be fixed now...) */
                   1519: 
                   1520: CHAR *
                   1521: rpar() {
                   1522:     if (rpsiz > MAXPACK)               /* Biggest normal packet I want. */
                   1523:       dada[0] = tochar(MAXPACK);       /* If > 94, use 94, but specify */
                   1524:     else                               /* extended packet length below... */
                   1525:       dada[0] = tochar(rpsiz);         /* else use what the user said. */
                   1526:     dada[1] = tochar(chktimo(pkttim,0)); /* When I want to be timed out */
                   1527:     dada[2] = tochar(mypadn);          /* How much padding I need (none) */
                   1528:     dada[3] = ctl(mypadc);             /* Padding character I want */
                   1529:     dada[4] = tochar(eol);             /* End-Of-Line character I want */
                   1530:     dada[5] = '#';                     /* Control-Quote character I send */
                   1531:     switch (rqf) {                     /* 8th-bit prefix */
                   1532:        case -1:
                   1533:        case  1: if (parity) ebq = sq = '&'; break;
                   1534:        case  0:
                   1535:        case  2: break;
                   1536:     }
                   1537:     debug(F000,"rpar 8bq sq","",sq);
                   1538:     debug(F000,"rpar 8bq ebq","",ebq);
                   1539:     if (lscapu == 2)                   /* LOCKING-SHIFT FORCED */
                   1540:       dada[6] = 'N';                   /* means no single-shift */
                   1541:     else
                   1542:       dada[6] = sq;
                   1543:     dada[7] = (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
                   1544:     if (rptflg)                                /* Run length encoding */
                   1545:        dada[8] = rptq;                 /* If receiving, agree. */
                   1546:     else
                   1547:        dada[8] = '~';          
                   1548:     /* CAPAS mask */
                   1549:     dada[9] = tochar((lscapr ? lscapb : 0) | /* Locking shifts */
                   1550:                     (atcapr ? atcapb : 0) | /* Attribute packets */
                   1551:                     (lpcapr ? lpcapb : 0) | /* Long packets */
                   1552:                     (swcapr ? swcapb : 0)); /* Sliding windows */
                   1553:     dada[10] = tochar(swcapr ? wslotr : 1);  /* Window size */
                   1554:     rpsiz = urpsiz - 1;                        /* Long packets ... */
                   1555:     dada[11] = tochar(rpsiz / 95);     /* Long packet size, big part */
                   1556:     dada[12] = tochar(rpsiz % 95);     /* Long packet size, little part */
                   1557:     dada[13] = '\0';                   /* Terminate the init string */
                   1558: #ifdef DEBUG
                   1559:     if (deblog) {
                   1560:        debug(F110,"rpar",dada,0);
                   1561:        rdebu(dada,(int)strlen((char *)dada));
                   1562:     }
                   1563: #endif /* DEBUG */
                   1564:     strcpy((char *)myinit,(char *)dada);
                   1565:     return(dada);                      /* Return pointer to string. */
                   1566: }
                   1567: 
                   1568: int
                   1569: spar(s) CHAR *s; {                     /* Set parameters */
                   1570:     int x, y, lpsiz;
                   1571: 
                   1572:     debug(F110,"entering spar",s,0);
                   1573: 
                   1574:     s--;                               /* Line up with field numbers. */
                   1575: 
                   1576: /* Limit on size of outbound packets */
                   1577:     x = (rln >= 1) ? xunchar(s[1]) : 80;
                   1578:     lpsiz = spsizr;                    /* Remember what they SET. */
                   1579:     if (spsizf) {                      /* SET-command override? */
                   1580:        if (x < spsizr) spsiz = x;      /* Ignore LEN unless smaller */
                   1581:     } else {                           /* otherwise */
                   1582:        spsiz = (x < 10) ? 80 : x;      /* believe them if reasonable */
                   1583:     }
                   1584:     spmax = spsiz;                     /* Remember maximum size */
                   1585: 
                   1586: /* Timeout on inbound packets */
                   1587:     if (timef) {
                   1588:        timint = rtimo;                 /* SET SEND TIMEOUT value overrides */
                   1589:     } else {                           /* Otherwise use requested value, */
                   1590:        x = (rln >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
                   1591:        timint = (x < 0) ? rtimo : x;
                   1592:     }
                   1593:     timint = chktimo(timint,timef);    /* Adjust if necessary */
                   1594: 
                   1595: /* Outbound Padding */
                   1596:     npad = 0; padch = '\0';
                   1597:     if (rln >= 3) {
                   1598:        npad = xunchar(s[3]);
                   1599:        if (rln >= 4) padch = ctl(s[4]); else padch = 0;
                   1600:     }
                   1601:     if (npad) {
                   1602:        int i;
                   1603:        for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
                   1604:     }
                   1605: 
                   1606: /* Outbound Packet Terminator */
                   1607:     seol = (rln >= 5) ? xunchar(s[5]) : CR;
                   1608:     if ((seol < 2) || (seol > 31)) seol = CR;
                   1609: 
                   1610: /* Control prefix */
                   1611:     x = (rln >= 6) ? s[6] : '#';
                   1612:     myctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
                   1613: 
                   1614: /* 8th-bit prefix */
                   1615:     rq = (rln >= 7) ? s[7] : 0;
                   1616:     if (rq == 'Y') rqf = 1;
                   1617:       else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
                   1618:         else rqf = 0;
                   1619:     debug(F000,"spar 8bq rq","",rq);
                   1620:     debug(F000,"spar 8bq sq","",sq);
                   1621:     debug(F000,"spar 8bq ebq","",ebq);
                   1622:     debug(F101,"spar 8bq rqf","",rqf);
                   1623:     switch (rqf) {
                   1624:        case 0: ebqflg = 0; break;
                   1625:        case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
                   1626:        case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
                   1627:     }
                   1628:     if (lscapu == 2) {     /* No single-shifts if LOCKING-SHIFT FORCED */
                   1629:        ebqflg = 0;
                   1630:        ebq = 'N';
                   1631:     }
                   1632: 
                   1633: /* Block check */
                   1634:     x = 1;
                   1635:     if (rln >= 8) {
                   1636:        if (s[8] == 'B') x = 4;
                   1637:        else x = s[8] - '0';
                   1638:        if ((x < 1) || (x > 4)) x = 1;
                   1639:     }
                   1640:     bctr = x;
                   1641: 
                   1642: /* Repeat prefix */
                   1643:     if (rln >= 9) {
                   1644:        rptq = s[9]; 
                   1645:        rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
                   1646:     } else rptflg = 0;
                   1647: 
                   1648: /* Capabilities */
                   1649:     atcapu = lpcapu = swcapu = 0;      /* Assume none of these */
                   1650:     if (lscapu != 2) lscapu = 0;       /* Assume no LS unless forced. */
                   1651:     y = 11;                            /* Position of next field, if any */
                   1652:     if (rln >= 10) {
                   1653:         x = xunchar(s[10]);
                   1654:        debug(F101,"spar capas","",x);
                   1655:         atcapu = (x & atcapb) && atcapr;
                   1656:        lpcapu = (x & lpcapb) && lpcapr;
                   1657:        swcapu = (x & swcapb) && swcapr;
                   1658:        debug(F101,"spar lscapu","",lscapu);
                   1659:        debug(F101,"spar lscapr","",lscapr);
                   1660:        debug(F101,"spar ebqflg","",ebqflg);
                   1661:        if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
                   1662:        debug(F101,"spar swcapr","",swcapr);
                   1663:        debug(F101,"spar swcapu","",swcapu);
                   1664:        debug(F101,"spar lscapu","",lscapu);
                   1665:        for (y = 10; (xunchar(s[y]) & 1) && (rln >= y); y++) ;
                   1666:        debug(F101,"spar y","",y);
                   1667:     }
                   1668: 
                   1669: /* Long Packets */
                   1670:     debug(F101,"spar lpcapu","",lpcapu);
                   1671:     if (lpcapu) {
                   1672:         if (rln > y+1) {
                   1673:            x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
                   1674:            debug(F101,"spar lp len","",x);
                   1675:            if (spsizf) {               /* If overriding negotiations */
                   1676:                spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
                   1677:            } else {                             /* otherwise */
                   1678:                spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
                   1679:            }
                   1680:            if (spsiz < 10) spsiz = 80; /* Be defensive... */
                   1681:        }
                   1682:     }
                   1683:     /* (PWP) save current send packet size for optimal packet size calcs */
                   1684:     spmax = spsiz;
                   1685:     debug(F101,"spar lp spmax","",spmax);
                   1686:     timint = chktimo(timint,timef);    /* Recalculate the packet timeout! */
                   1687:     
                   1688: /* Sliding Windows... */
                   1689: 
                   1690:     if (swcapr) {                      /* Only if requested... */
                   1691:         if (rln > y) {                 /* See what other Kermit says */
                   1692:            x = xunchar(s[y+1]);
                   1693:            debug(F101,"spar window","",x);
                   1694:            wslotn = (x > MAXWS) ? MAXWS : x;
                   1695: /*
                   1696:   wslotn = negotiated size (from other Kermit's S or I packet).
                   1697:   wslotr = requested window size (from this Kermit's SET WINDOW command).
                   1698: */
                   1699:            if (wslotn > wslotr)        /* Use the smaller of the two */
                   1700:              wslotn = wslotr;
                   1701:            if (wslotn < 1)             /* Watch out for bad negotiation */
                   1702:              wslotn = 1;
                   1703:            if (wslotn > 1)
                   1704:              swcapu = 1; /* We do windows... */
                   1705:            debug(F101,"spar window after adjustment","",x);
                   1706:        } else {                        /* No window size specified. */
                   1707:            wslotn = 1;                 /* We don't do windows... */
                   1708:            debug(F101,"spar window","",x);
                   1709:            swcapu = 0;
                   1710:            debug(F101,"spar no windows","",wslotn);
                   1711:        }
                   1712:     }
                   1713: 
                   1714: /* Now recalculate packet length based on number of windows.   */
                   1715: /* The nogotiated number of window slots will be allocated,    */
                   1716: /* and the maximum packet length will be reduced if necessary, */
                   1717: /* so that a windowful of packets can fit in the big buffer.   */
                   1718: 
                   1719:     if (wslotn > 1) {                  /* Shrink to fit... */
                   1720:        x = adjpkl(spsiz,wslotn,bigsbsiz);
                   1721:        if (x < spsiz) {
                   1722:            spsiz = spmax = x;
                   1723:            debug(F101,"spar sending, redefine spsiz","",spsiz);
                   1724:        }
                   1725:     }
                   1726: 
                   1727: /* Record parameters in debug log */
                   1728: #ifdef DEBUG
                   1729:     if (deblog) sdebu(rln);
                   1730: #endif /* DEBUG */
                   1731:     numerrs = 0;                       /* Start counting errors here. */
                   1732:     return(0);
                   1733: }
                   1734: 
                   1735: /*  G N F I L E  --  Get name of next file to send  */
                   1736: /*
                   1737:   Expects global sndsrc to be:
                   1738:    -1: next filename to be obtained by calling znext().
                   1739:     0: no next file name
                   1740:     1: (or greater) next filename to be obtained from **cmlist.
                   1741:   Returns:
                   1742:     1, with name of next file in filnam.
                   1743:     0, no more files, with filnam set to empty string.
                   1744:    -1, file not found
                   1745:    -2, file is not readable
                   1746:    -3, read access denied
                   1747:    -4, cancelled
                   1748:    -5, too many files match wildcard
                   1749: */
                   1750: 
                   1751: int
                   1752: gnfile() {
                   1753:     int x; long y;
                   1754:     int retcode = 0;
                   1755: 
                   1756:     debug(F101,"gnfile sndsrc","",sndsrc);
                   1757:     fsize = -1L;                       /* Initialize file size */
                   1758:     if (sndsrc == 0) {                 /* It's not really a file */
                   1759:        if (nfils > 0) {                /* It's a pipe, or stdin */
                   1760:            strcpy(filnam, *cmlist);    /* Copy its "name" */
                   1761:            nfils = 0;                  /* There is no next file */
                   1762:            return(1);                  /* OK this time */
                   1763:        } else return(0);               /* but not next time */
                   1764:     }
                   1765: 
                   1766: /* If file group interruption (C-Z) occurred, fail.  */
                   1767: 
                   1768:     if (czseen) {
                   1769:        tlog(F100,"Transaction cancelled","",0L);
                   1770:         debug(F100,"gnfile czseen","",0);
                   1771:        return(-4);
                   1772:     }
                   1773: 
                   1774: /* Loop through file list till we find a readable, sendable file */
                   1775: 
                   1776:     y = -1L;                           /* Loop exit (file size) variable */
                   1777:     while (y < 0L) {                   /* Keep trying till we get one... */
                   1778:        if (sndsrc > 0) {               /* File list in cmlist */
                   1779:            debug(F101,"gnfile nfils","",nfils);
                   1780:            if (nfils-- > 0) {          /* Still some left? */
                   1781:                strcpy(filnam,*cmlist++);
                   1782:                debug(F111,"gnfile cmlist filnam",filnam,nfils);
                   1783:                if (!clfils) {          /* Expand only if not from cmdline */
                   1784:                    x = zxpand(filnam);
                   1785:                    debug(F101,"gnfile zxpand","",x);
                   1786:                    if (x == 1) {
                   1787:                        znext(filnam);
                   1788:                        goto gotnam;
                   1789:                    }
                   1790:                    if (x == 0) {
                   1791:                        retcode = -1; /* None match */
                   1792:                        continue;
                   1793:                    }
                   1794:                    if (x < 0) return(-5); /* Too many to expand */
                   1795:                    sndsrc = -1;        /* Change send-source to znext() */
                   1796:                }
                   1797:            } else {                    /* We're out of files. */
                   1798:                debug(F101,"gnfile done","",nfils);
                   1799:                *filnam = '\0';
                   1800:                return(retcode);
                   1801:            }
                   1802:        }
                   1803: 
                   1804: /* Otherwise, step to next element of internal wildcard expansion list. */
                   1805: 
                   1806:        if (sndsrc < 0) {
                   1807:            x = znext(filnam);
                   1808:            debug(F111,"gnfile znext",filnam,x);
                   1809:            if (x == 0) {               /* If no more, */
                   1810:                sndsrc = 1;             /* go back to list */
                   1811:                continue;
                   1812:            }
                   1813:        }
                   1814: 
                   1815: /* Get here with a filename. */
                   1816: 
                   1817: gotnam:
                   1818:        if (sndsrc) {
                   1819:            y = zchki(filnam);          /* Check if file readable */
                   1820:            retcode = (int) y;          /* Possible return code */
                   1821:            if (y == -1L) {             /* If not found */
                   1822:                debug(F110,"gnfile skipping:",filnam,0);
                   1823:                tlog(F111,filnam,"not sent, reason",(long)y);
                   1824:                screen(SCR_ST,ST_SKIP,0l,filnam);
                   1825:                continue;
                   1826:            } else if (y < 0) {
                   1827:                continue;
                   1828:            } else {
                   1829:                fsize = y;
                   1830:                return(1);
                   1831:            }
                   1832:        } else return(1);               /* sndsrc is 0... */
                   1833:     }
                   1834:     *filnam = '\0';                    /* Should never get here */
                   1835:     return(0);
                   1836: }
                   1837: 
                   1838: 
                   1839: /*  S N D H L P  --  Routine to send builtin help  */
                   1840: 
                   1841: int
                   1842: sndhlp() {
                   1843: #ifndef NOSERVER
                   1844:     nfils = 0;                         /* No files, no lists. */
                   1845:     xflg = 1;                          /* Flag we must send X packet. */
                   1846:     strcpy(cmdstr,"help text");                /* Data for X packet. */
                   1847:     first = 1;                         /* Init getchx lookahead */
                   1848:     memstr = 1;                                /* Just set the flag. */
                   1849:     memptr = hlptxt;                   /* And the pointer. */
                   1850:     if (binary) {                      /* If file mode is binary, */
                   1851:        savmod = binary;                /*  remember to restore it later. */
                   1852:        binary = 0;                     /*  turn it back to text for this, */
                   1853:     }
                   1854:     return(sinit());
                   1855: #else
                   1856:     return(0);
                   1857: #endif /* NOSERVER */
                   1858: }
                   1859: 
                   1860: #ifdef OS2
                   1861: /*  S N D S P A C E -- send disk space message  */
                   1862: int
                   1863: sndspace(int drive) {
                   1864: #ifndef NOSERVER
                   1865:     static char spctext[64];
                   1866:     if (drive)
                   1867:       sprintf(spctext, " Drive %c: %ldK free\n", drive, 
                   1868:              zdskspace(drive - 'A' + 1) / 1024L);
                   1869:     else
                   1870:       sprintf(spctext, " Free space: %ldK\n", zdskspace(0)/1024L);
                   1871:     nfils = 0;                 /* No files, no lists. */
                   1872:     xflg = 1;                  /* Flag we must send X packet. */
                   1873:     strcpy(cmdstr,"free space");/* Data for X packet. */
                   1874:     first = 1;                 /* Init getchx lookahead */
                   1875:     memstr = 1;                        /* Just set the flag. */
                   1876:     memptr = spctext;          /* And the pointer. */
                   1877:     if (binary) {              /* If file mode is binary, */
                   1878:         savmod = binary;       /*  remember to restore it later. */
                   1879:         binary = 0;            /*  turn it back to text for this, */
                   1880:     }
                   1881:     return(sinit());
                   1882: #else
                   1883:     return(0);
                   1884: #endif /* NOSERVER */
                   1885: }
                   1886: #endif /* OS2 */
                   1887: 
                   1888: /*  C W D  --  Change current working directory  */
                   1889: 
                   1890: /*
                   1891:  String passed has first byte as length of directory name, rest of string
                   1892:  is name.  Fails if can't connect, else ACKs (with name) and succeeds. 
                   1893: */
                   1894: 
                   1895: int
                   1896: cwd(vdir) char *vdir; {
                   1897:     char *cdd, *zgtdir(), *dirp;
                   1898: 
                   1899:     vdir[xunchar(*vdir) + 1] = '\0';   /* Terminate string with a null */
                   1900:     dirp = vdir+1;
                   1901:     tlog(F110,"Directory requested: ",dirp,0L);
                   1902:     if (zchdir(dirp)) {                /* Try to change */
                   1903:        cdd = zgtdir();         /* Get new working directory. */
                   1904:        debug(F110,"cwd",cdd,0);
                   1905:        encstr((CHAR *)cdd);
                   1906:        ack1((CHAR *)(encbuf+7));
                   1907:        tlog(F110,"Changed directory to",cdd,0L);
                   1908:        return(1); 
                   1909:     } else {
                   1910:        debug(F110,"cwd failed",dirp,0);
                   1911:        tlog(F110,"Failed to change directory to",dirp,0L);
                   1912:        return(0);
                   1913:     }
                   1914: }
                   1915: 
                   1916: 
                   1917: /*  S Y S C M D  --  Do a system command  */
                   1918: 
                   1919: /*  Command string is formed by concatenating the two arguments.  */
                   1920: 
                   1921: int
                   1922: syscmd(prefix,suffix) char *prefix, *suffix; {
                   1923:     char *cp;
                   1924: 
                   1925:     if (prefix == NULL || *prefix == '\0') return(0);
                   1926: 
                   1927:     for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
                   1928:     while (*cp++ = *suffix++) ;                /* copy suffix */
                   1929: 
                   1930:     debug(F110,"syscmd",cmdstr,0);
                   1931:     if (zxcmd(ZIFILE,cmdstr) > 0) {
                   1932:        debug(F110,"syscmd zxcmd ok",cmdstr,0);
                   1933:        nfils = sndsrc = 0;             /* Flag that input is from stdin */
                   1934:        xflg = hcflg = 1;               /* And special flags for pipe */
                   1935:        if (binary) {                   /* If file mode is binary, */
                   1936:            savmod = binary;            /*  remember to restore it later. */
                   1937:            binary = 0;                 /*  turn it back to text for this, */
                   1938:        }
                   1939:        return (sinit());               /* Send S packet */
                   1940:     } else {
                   1941:        debug(F100,"syscmd zxcmd failed",cmdstr,0);
                   1942:        return(0);
                   1943:     }
                   1944: }
                   1945: 
                   1946: /*  R E M S E T  --  Remote Set  */
                   1947: /*  Called by server to set variables as commanded in REMOTE SET packets.  */
                   1948: /*  Returns 1 on success, 0 on failure.  */
                   1949: 
                   1950: int
                   1951: remset(s) char *s; {
                   1952:     int len, i, x, y;
                   1953:     char *p;
                   1954: 
                   1955:     len = xunchar(*s++);               /* Length of first field */
                   1956:     p = s + len;                       /* Pointer to second length field */
                   1957:     *p++ = '\0';                       /* Zero out second length field */
                   1958:     x = atoi(s);                       /* Value of first field */
                   1959:     debug(F111,"remset",s,x);
                   1960:     debug(F110,"remset",p,0);
                   1961:     switch (x) {                       /* Do the right thing */
                   1962:       case 132:                                /* Attributes (all, in) */
                   1963:        atcapr = atoi(p);
                   1964:        return(1);
                   1965:       case 133:                                /* File length attributes */
                   1966:       case 233:                                /* IN/OUT combined */
                   1967:       case 148:                                /* Both kinds of lengths */
                   1968:       case 248:
                   1969:        atleni = atleno = atoi(p);
                   1970:        return(1);
                   1971:       case 134:                                /* File Type (text/binary) */
                   1972:       case 234:
                   1973:        attypi = attypo = atoi(p);
                   1974:        return(1);
                   1975:       case 135:                                /* File creation date */
                   1976:       case 235:
                   1977:        atdati = atdato = atoi(p);
                   1978:        return(1);
                   1979:       case 139:                                /* File Blocksize */
                   1980:       case 239:
                   1981:        atblki = atblko = atoi(p);
                   1982:        return(1);
                   1983:       case 141:                                /* Encoding / Character Set */
                   1984:       case 241:
                   1985:        atenci = atenco = atoi(p);
                   1986:        return(1);
                   1987:       case 142:                                /* Disposition */
                   1988:       case 242:
                   1989:        atdisi = atdiso = atoi(p);
                   1990:        return(1);
                   1991:       case 145:                                /* System ID */
                   1992:       case 245:
                   1993:        atsidi = atsido = atoi(p);
                   1994:        return(1);
                   1995:       case 147:                                /* System-Dependent Info */
                   1996:       case 247:
                   1997:        atsysi = atsyso = atoi(p);
                   1998:        return(1);
                   1999:       case 232:                                /* Attributes (all, out) */
                   2000:        atcapr = atoi(p);
                   2001:        return(1);
                   2002:       case 300:                                /* File type (text, binary) */
                   2003:        binary = atoi(p);
                   2004:        return(1);
                   2005:       case 301:                                /* File name conversion */
                   2006:        fncnv = 1 - atoi(p);            /* (oops) */
                   2007:        return(1);
                   2008:       case 302:                                /* File name collision */
                   2009:        x = atoi(p);
                   2010:        if (x == XYFX_R) warn = 1;      /* Rename */
                   2011:        if (x == XYFX_X) warn = 0;      /* Replace */
                   2012:        fncact = x;
                   2013:        return(1);
                   2014:       case 310:                                /* Incomplete File Disposition */
                   2015:        keep = atoi(p);                 /* Keep, Discard */
                   2016:        return(1);
                   2017:       case 311:                                /* Blocksize */
                   2018:        fblksiz = atoi(p);
                   2019:        return(1);
                   2020:       case 312:                                /* Record Length */
                   2021:        frecl = atoi(p);
                   2022:        return(1);
                   2023:       case 313:                                /* Record format */
                   2024:        frecfm = atoi(p);
                   2025:        return(1);
                   2026:       case 314:                                /* File organization */
                   2027:        forg = atoi(p);
                   2028:        return(1);
                   2029:       case 315:                                /* File carriage control */
                   2030:        fcctrl = atoi(p);
                   2031:        return(1);
                   2032:       case 400:                                /* Block check */
                   2033:        y = atoi(p);
                   2034:        if (y < 5 && y > 0) {
                   2035:            bctr = y;
                   2036:            return(1);
                   2037:        } else if (*p == 'B') {
                   2038:            bctr = 4;
                   2039:            return(1);
                   2040:        }
                   2041:        return(0);
                   2042:       case 401:                                /* Receive packet-length */
                   2043:        urpsiz = atoi(p);
                   2044:        if (urpsiz > MAXRP) urpsiz = MAXRP;
                   2045:        urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
                   2046:        return(1);
                   2047:       case 402:                                /* Receive timeout */
                   2048:        y = atoi(p);                    /* Client is telling us */
                   2049:        if (y > -1 && y < 999) {        /* the timeout that it wants */
                   2050:            pkttim = chktimo(y,timef);  /* us to tell it to use. */
                   2051:            return(1);
                   2052:        } else return(0);
                   2053:       case 403:                                /* Retry limit */
                   2054:        y = atoi(p);
                   2055:        if (y > -1 && y < 95) {
                   2056:            maxtry = y;
                   2057:            return(1);
                   2058:        } else return(0);
                   2059:       case 404:                                /* Server timeout */
                   2060:        y = atoi(p);
                   2061:        if (y < 0) return(0);
                   2062:        srvtim = y;
                   2063:        return(1);
                   2064: 
                   2065: #ifndef NOCSETS
                   2066:       case 405:                                /* Transfer character set */
                   2067:        for (i = 0; i < ntcsets; i++) { 
                   2068:            if (!strcmp(tcsinfo[i].designator,p)) break;
                   2069:        }
                   2070:        debug(F101,"remset xfer charset lookup","",i);
                   2071:        if (i == ntcsets) return(0);
                   2072:        tcharset = tcsinfo[i].code;     /* if known, use it */
                   2073:        if (tcharset == TC_TRANSP)
                   2074:          rx = NULL;
                   2075:        else
                   2076:          rx = xlr[tcharset][fcharset]; /* translation function */
                   2077:        return(1);
                   2078: #endif /* NOCSETS */
                   2079: 
                   2080:       case 406:                                /* Window slots */
                   2081:        y = atoi(p);
                   2082:        if (y == 0) y = 1;
                   2083:        if (y < 1 && y > 31) return(0);
                   2084:        wslotr = y;
                   2085:        swcapr = 1;
                   2086:        urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
                   2087:        return(1);
                   2088:       default:                         /* Anything else... */
                   2089:        return(0);
                   2090:     }
                   2091: }
                   2092: 
                   2093: /* Adjust packet length based on number of window slots and buffer size */
                   2094: 
                   2095: int
                   2096: adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
                   2097:     debug(F101,"adjpkl len","",pktlen);
                   2098:     debug(F101,"adjpkl slots","",slots);
                   2099:     debug(F101,"adjpkl bufsiz","",bufsiz);
                   2100:     if (((pktlen + 6) * slots) > bufsiz)
                   2101:       pktlen = (bufsiz / slots) - 6;
                   2102:     debug(F101,"adjpkl new len","",pktlen);
                   2103:     return(pktlen);
                   2104: }

unix.superglobalmegacorp.com

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