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