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