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

Defined functions

adjpkl defined in line 2095; used 8 times
cwd defined in line 1895; never used
decode defined in line 331; used 1 times
encode defined in line 203; used 2 times
encstr defined in line 162; used 5 times
getpkt defined in line 509; used 5 times
gnfile defined in line 1751; used 1 times
kgetf defined in line 484; used 2 times
kgetm defined in line 489; used 2 times
lslook defined in line 497; used 3 times
pktinit defined in line 889; never used
putfil defined in line 286; used 2 times
putsrv defined in line 263; used 1 times
puttrm defined in line 275; never used
rcvfil defined in line 1088; never used
remset defined in line 1950; never used
reof defined in line 1218; never used
reot defined in line 1277; never used
resetc defined in line 918; never used
rinit defined in line 897; never used
rpar defined in line 1520; used 3 times
sdata defined in line 1377; never used
seof defined in line 1468; never used
seot defined in line 1503; never used
sfile defined in line 1288; never used
sinit defined in line 949; used 3 times
sipkt defined in line 1034; used 1 times
sndhlp defined in line 1841; never used
sndspace defined in line 1862; never used
spar defined in line 1568; used 1 times
sxeof defined in line 1490; never used
syscmd defined in line 1921; never used
szeof defined in line 1455; used 3 times
tinit defined in line 825; never used
xsinit defined in line 1062; never used
zdstuff defined in line 320; used 16 times

Defined variables

VOID defined in line 897; never used
cmargbuf defined in line 945; used 7 times
cmargp defined in line 947; used 6 times
cmdstr defined in line 132; used 12 times
dada defined in line 1515; used 22 times
drain defined in line 135; used 6 times
encbuf defined in line 160; used 6 times
first defined in line 137; used 20 times
fnsv defined in line 1; used 1 times
lsquote defined in line 142; used 3 times
lsstate defined in line 141; used 16 times
memptr defined in line 127; used 9 times
memstr defined in line 117; used 13 times
myinit defined in line 122; used 5 times
next defined in line 139; used 3 times
sndsrc defined in line 112; used 13 times
t defined in line 138; used 5 times
xdbuf defined in line 315; used 8 times

Defined macros

ENCBUFL defined in line 158; used 4 times
PKTNL defined in line 1293; used 3 times
XNAMLEN defined in line 1085; used 3 times
Last modified: 1992-11-24
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 10177
Valid CSS Valid XHTML 1.0 Strict