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