Annotation of coherent/e/bin/cku179/ckcfns.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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