|
|
1.1 ! root 1: char *fnsv = "C-Kermit functions, 4E(053) 14 Sep 87"; ! 2: ! 3: /* C K C F N S -- System-independent Kermit protocol support functions. */ ! 4: ! 5: /* ...Part 1 (others moved to ckcfn2 to make this module small enough) */ ! 6: ! 7: /* ! 8: 4E includes support for Data General systems from Phil Julian of SAS ! 9: Institute, and Megamax native Macintosh C compiler support from ! 10: Jim Noble of Planning Research Corporation. ! 11: */ ! 12: /* ! 13: Author: Frank da Cruz (SY.FDC@CU20B), ! 14: Columbia University Center for Computing Activities, January 1985. ! 15: Copyright (C) 1985, Trustees of Columbia University in the City of New York. ! 16: Permission is granted to any individual or institution to use, copy, or ! 17: redistribute this software so long as it is not sold for profit, provided this ! 18: copyright notice is retained. ! 19: */ ! 20: /* ! 21: System-dependent primitives defined in: ! 22: ! 23: ck?tio.c -- terminal i/o ! 24: cx?fio.c -- file i/o, directory structure ! 25: */ ! 26: #include "ckcsym.h" /* Need this for Mac */ ! 27: #include "ckcker.h" /* Symbol definitions for Kermit */ ! 28: #include "ckcdeb.h" /* Debug formats, typedefs, etc. */ ! 29: ! 30: #ifndef NULL ! 31: #define NULL 0 ! 32: #endif ! 33: ! 34: /* Externals from ckcmai.c */ ! 35: extern int spsiz, rpsiz, timint, rtimo, npad, ebq, ebqflg, rpt, rptq, ! 36: rptflg, capas, keep; ! 37: extern int pktnum, prvpkt, sndtyp, bctr, bctu, fmask, ! 38: size, osize, maxsize, spktl, nfils, stdouf, warn, timef, spsizf; ! 39: extern int parity, speed, turn, turnch, ! 40: delay, displa, pktlog, tralog, seslog, xflg, mypadn; ! 41: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize; ! 42: extern int tsecs; ! 43: extern int deblog, hcflg, binary, savmod, fncnv, local, server, cxseen, czseen; ! 44: extern int rq, rqf, sq, wsize, urpsiz, rln; ! 45: extern int atcapr, atcapb, atcapu; ! 46: extern int lpcapr, lpcapb, lpcapu; ! 47: extern int swcapr, swcapb, swcapu; ! 48: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate; ! 49: extern CHAR filnam[], sndpkt[], recpkt[], data[], srvcmd[], stchr, mystch; ! 50: extern char *cmarg, *cmarg2, *hlptxt, **cmlist; ! 51: extern CHAR *srvptr; ! 52: extern char *rdatap; ! 53: long zchki(); ! 54: char *strcpy(); ! 55: CHAR *rpar(); ! 56: ! 57: /* Variables local to this module */ ! 58: ! 59: static char *memptr; /* Pointer for memory strings */ ! 60: ! 61: static char cmdstr[100]; /* Unix system command string */ ! 62: ! 63: static int sndsrc; /* Flag for where to send from: */ ! 64: /* -1: name in cmdata */ ! 65: /* 0: stdin */ ! 66: /* >0: list in cmlist */ ! 67: ! 68: static int memstr, /* Flag for input from memory string */ ! 69: first; /* Flag for first char from input */ ! 70: static CHAR t, /* Current character */ ! 71: next; /* Next character */ ! 72: #ifdef datageneral ! 73: extern int quiet; ! 74: #endif ! 75: ! 76: /* E N C S T R -- Encode a string from memory. */ ! 77: ! 78: /* Call this instead of getpkt() if source is a string, rather than a file. */ ! 79: ! 80: encstr(s) char* s; { ! 81: int m; char *p; ! 82: ! 83: m = memstr; p = memptr; /* Save these. */ ! 84: ! 85: memptr = s; /* Point to the string. */ ! 86: memstr = 1; /* Flag memory string as source. */ ! 87: first = 1; /* Initialize character lookahead. */ ! 88: getpkt(spsiz-bctu-3); /* Fill a packet from the string. */ ! 89: memstr = m; /* Restore memory string flag */ ! 90: memptr = p; /* and pointer */ ! 91: first = 1; /* Put this back as we found it. */ ! 92: } ! 93: ! 94: /* E N C O D E - Kermit packet encoding procedure */ ! 95: ! 96: encode(a) CHAR a; { /* The current character */ ! 97: int a7; /* Low order 7 bits of character */ ! 98: int b8; /* 8th bit of character */ ! 99: ! 100: if (rptflg) { /* Repeat processing? */ ! 101: if (a == next && (first == 0)) { /* Got a run... */ ! 102: if (++rpt < 94) /* Below max, just count */ ! 103: return; ! 104: else if (rpt == 94) { /* Reached max, must dump */ ! 105: data[size++] = rptq; ! 106: data[size++] = tochar(rpt); ! 107: rpt = 0; ! 108: } ! 109: } else if (rpt == 1) { /* Run broken, only 2? */ ! 110: rpt = 0; /* Yes, reset repeat flag & count. */ ! 111: encode(a); /* Do the character twice. */ ! 112: if (size <= maxsize) osize = size; ! 113: rpt = 0; ! 114: encode(a); ! 115: return; ! 116: } else if (rpt > 1) { /* More than two */ ! 117: data[size++] = rptq; /* Insert the repeat prefix */ ! 118: data[size++] = tochar(++rpt); /* and count. */ ! 119: rpt = 0; /* Reset repeat counter. */ ! 120: } ! 121: } ! 122: a7 = a & 0177; /* Isolate ASCII part */ ! 123: b8 = a & 0200; /* and 8th (parity) bit. */ ! 124: ! 125: if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */ ! 126: data[size++] = ebq; ! 127: a = a7; ! 128: } ! 129: if ((a7 < SP) || (a7==DEL)) { /* Do control prefix if necessary */ ! 130: data[size++] = myctlq; ! 131: a = ctl(a); ! 132: } ! 133: if (a7 == myctlq) /* Prefix the control prefix */ ! 134: data[size++] = myctlq; ! 135: ! 136: if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */ ! 137: data[size++] = myctlq; /* quote it if doing repeat counts. */ ! 138: ! 139: if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */ ! 140: data[size++] = myctlq; /* if doing 8th-bit prefixes */ ! 141: ! 142: data[size++] = a; /* Finally, insert the character */ ! 143: data[size] = '\0'; /* itself, and mark the end. */ ! 144: } ! 145: ! 146: /* D E C O D E -- Kermit packet decoding procedure */ ! 147: ! 148: /* Call with string to be decoded and an output function. */ ! 149: /* Returns 0 on success, -1 on failure (e.g. disk full). */ ! 150: ! 151: decode(buf,fn) CHAR *buf; int (*fn)(); { ! 152: unsigned int a, a7, b8; /* Low order 7 bits, and the 8th bit */ ! 153: ! 154: rpt = 0; /* Initialize repeat count. */ ! 155: ! 156: while ((a = *buf++) != '\0') { ! 157: if (rptflg) { /* Repeat processing? */ ! 158: if (a == rptq) { /* Yes, got a repeat prefix? */ ! 159: rpt = xunchar(*buf++); /* Yes, get the repeat count, */ ! 160: a = *buf++; /* and get the prefixed character. */ ! 161: } ! 162: } ! 163: b8 = 0; /* Check high order "8th" bit */ ! 164: if (ebqflg) { /* 8th-bit prefixing? */ ! 165: if (a == ebq) { /* Yes, got an 8th-bit prefix? */ ! 166: b8 = 0200; /* Yes, remember this, */ ! 167: a = *buf++; /* and get the prefixed character. */ ! 168: } ! 169: } ! 170: if (a == ctlq) { /* If control prefix, */ ! 171: a = *buf++; /* get its operand. */ ! 172: a7 = a & 0177; /* Only look at low 7 bits. */ ! 173: if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */ ! 174: a = ctl(a); /* if in control range. */ ! 175: } ! 176: a |= b8; /* OR in the 8th bit */ ! 177: if (rpt == 0) rpt = 1; /* If no repeats, then one */ ! 178: #ifdef NLCHAR ! 179: if (!binary) { /* If in text mode, */ ! 180: if (a == CR) continue; /* discard carriage returns, */ ! 181: if (a == LF) a = NLCHAR; /* convert LF to system's newline. */ ! 182: } ! 183: #endif ! 184: for (; rpt > 0; rpt--) { /* Output the char RPT times */ ! 185: if ((*fn)(a) < 0) return(-1); /* Send it to the output function. */ ! 186: ffc++, tfc++; /* Count the character */ ! 187: } ! 188: } ! 189: return(0); ! 190: } ! 191: ! 192: ! 193: /* Output functions passed to 'decode': */ ! 194: ! 195: putsrv(c) char c; { /* Put character in server command buffer */ ! 196: *srvptr++ = c; ! 197: *srvptr = '\0'; /* Make sure buffer is null-terminated */ ! 198: return(0); ! 199: } ! 200: ! 201: puttrm(c) char c; { /* Output character to console. */ ! 202: conoc(c); ! 203: return(0); ! 204: } ! 205: ! 206: putfil(c) char c; { /* Output char to file. */ ! 207: if (zchout(ZOFILE, c & fmask) < 0) { ! 208: czseen = 1; /* If write error... */ ! 209: debug(F101,"putfil zchout write error, setting czseen","",1); ! 210: return(-1); ! 211: } ! 212: return(0); ! 213: } ! 214: ! 215: /* G E T P K T -- Fill a packet data field */ ! 216: ! 217: /* ! 218: Gets characters from the current source -- file or memory string. ! 219: Encodes the data into the packet, filling the packet optimally. ! 220: Set first = 1 when calling for the first time on a given input stream ! 221: (string or file). ! 222: ! 223: Uses global variables: ! 224: t -- current character. ! 225: first -- flag: 1 to start up, 0 for input in progress, -1 for EOF. ! 226: next -- next character. ! 227: data -- the packet data buffer. ! 228: size -- number of characters in the data buffer. ! 229: ! 230: Returns the size as value of the function, and also sets global size, ! 231: and fills (and null-terminates) the global data array. Returns 0 upon eof. ! 232: */ ! 233: ! 234: getpkt(bufmax) int bufmax; { /* Fill one packet buffer */ ! 235: int i, x; /* Loop index. */ ! 236: ! 237: static char leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' }; ! 238: ! 239: if (first == 1) { /* If first time thru... */ ! 240: first = 0; /* remember, */ ! 241: *leftover = '\0'; /* discard any interrupted leftovers, */ ! 242: x = getchx(&t); /* get first character of file into t, */ ! 243: if (x == 0) { /* watching out for null file, */ ! 244: first = -1; ! 245: return(size = 0); ! 246: } ! 247: } else if ((first == -1) && (*leftover == '\0')) /* EOF from last time? */ ! 248: return(size = 0); ! 249: ! 250: /* Do any leftovers */ ! 251: ! 252: for (size = 0; (data[size] = leftover[size]) != '\0'; size++) ! 253: ; ! 254: *leftover = '\0'; ! 255: if (first == -1) return(size); /* Handle final leftovers leftovers */ ! 256: ! 257: /* Now fill up the rest of the packet. */ ! 258: ! 259: rpt = 0; /* Clear out any old repeat count. */ ! 260: while (first > -1) { /* Until EOF... */ ! 261: x = getchx(&next); /* Get next character for lookahead. */ ! 262: if (x == 0) first = -1; /* Flag eof for next time. */ ! 263: osize = size; /* Remember current position. */ ! 264: encode(t); /* Encode the current character. */ ! 265: t = next; /* Next is now current. */ ! 266: ! 267: if (size == bufmax) { /* If the packet is exactly full, */ ! 268: /** debug(F101,"getpkt exact fit","",size); **/ ! 269: return(size); /* ... return. */ ! 270: } ! 271: if (size > bufmax) { /* If too big, save some for next. */ ! 272: for (i = 0; (leftover[i] = data[osize+i]) != '\0'; i++) ! 273: ; ! 274: /** debug(F111,"getpkt leftover",leftover,size); **/ ! 275: /** debug(F101," osize","",osize); **/ ! 276: size = osize; /* Return truncated packet. */ ! 277: data[size] = '\0'; ! 278: return(size); ! 279: } ! 280: } /* Otherwise, keep filling. */ ! 281: debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */ ! 282: return(size); /* return partially filled last packet. */ ! 283: } ! 284: ! 285: /* G E T C H X -- Get the next character from file (or pipe). */ ! 286: ! 287: /* ! 288: On systems like Unix, the Macintosh, etc, that use a single character ! 289: (NLCHAR, defined in ckcdeb.h) to separate lines in text files, and ! 290: when in text/ascii mode (binary == 0), this function maps the newline ! 291: character to CRLF. If NLCHAR is not defined, then this mapping is ! 292: not done, even in text mode. ! 293: ! 294: Returns 1 on success with ch set to the character, or 0 on failure (EOF) ! 295: */ ! 296: getchx(ch) char *ch; { /* Get next character */ ! 297: int x; CHAR a; /* The character to return. */ ! 298: static int b = 0; /* A character to remember. */ ! 299: ! 300: if (b > 0) { /* Do we have a LF saved? */ ! 301: b = 0; /* Yes, return that. */ ! 302: *ch = LF; ! 303: return(1); ! 304: } ! 305: ! 306: if (memstr) /* Try to get the next character */ ! 307: x = ((a = *memptr++) == '\0'); /* from the appropriate source, */ ! 308: else /* memory or the current file. */ ! 309: x = (zchin(ZIFILE,&a) == -1); ! 310: ! 311: if (x) ! 312: return(0); /* No more, return 0 for EOF. */ ! 313: else { /* Otherwise, read the next char. */ ! 314: ffc++, tfc++; /* Count it. */ ! 315: a &= fmask; /* Bytesize mask. */ ! 316: #ifdef NLCHAR ! 317: if (!binary && (a == NLCHAR)) { /* If nl and we must do nl-CRLF */ ! 318: b = 1; /* mapping, remember a linefeed, */ ! 319: *ch = CR; /* and return a carriage return. */ ! 320: return(1); ! 321: } else { ! 322: *ch = a; /* General case, return the char. */ ! 323: return(1); ! 324: } ! 325: #else ! 326: *ch = a; ! 327: return(1); ! 328: #endif ! 329: } ! 330: } ! 331: ! 332: ! 333: /* C A N N E D -- Check if current file transfer cancelled */ ! 334: ! 335: canned(buf) char *buf; { ! 336: if (*buf == 'X') cxseen = 1; ! 337: if (*buf == 'Z') czseen = 1; ! 338: debug(F101,"canned: cxseen","",cxseen); ! 339: debug(F101," czseen","",czseen); ! 340: return((czseen || cxseen) ? 1 : 0); ! 341: } ! 342: ! 343: /* R E S E T C -- Reset per-transaction character counters */ ! 344: resetc() { ! 345: tfc = tlci = tlco = 0; /* Total file chars, line chars in & out */ ! 346: } ! 347: ! 348: ! 349: /* T I N I T -- Initialize a transaction */ ! 350: ! 351: tinit() { ! 352: xflg = 0; /* Reset x-packet flag */ ! 353: memstr = 0; /* Reset memory-string flag */ ! 354: memptr = NULL; /* and pointer */ ! 355: bctu = 1; /* Reset block check type to 1 */ ! 356: ebq = ebqflg = 0; /* Reset 8th-bit quoting stuff */ ! 357: if (savmod) { /* If binary file mode was saved, */ ! 358: binary = 1; /* restore it, */ ! 359: savmod = 0; /* unsave it. */ ! 360: } ! 361: prvpkt = -1; /* Reset packet number */ ! 362: pktnum = 0; ! 363: cxseen = czseen = 0; /* Reset interrupt flags */ ! 364: *filnam = '\0'; /* Clear file name */ ! 365: *sndpkt = '\0'; /* Clear retransmission buffer */ ! 366: if (server) /* If acting as server, */ ! 367: timint = 30; /* Use 30 second timeout, */ ! 368: } ! 369: ! 370: ! 371: /* R I N I T -- Respond to S packet */ ! 372: ! 373: rinit(d) char *d; { ! 374: char *tp; ! 375: ztime(&tp); ! 376: tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */ ! 377: filcnt = 0; /* Init file counter */ ! 378: spar(d); ! 379: ack1(rpar()); ! 380: #ifdef datageneral ! 381: if ((local) && (!quiet)) /* Only do this if local & not quiet */ ! 382: consta_mt(); /* Start the asynch read task */ ! 383: #endif ! 384: } ! 385: ! 386: /* S I N I T -- Make sure file exists, then send Send-Init packet */ ! 387: ! 388: sinit() { ! 389: int x; char *tp; ! 390: ! 391: filcnt = 0; ! 392: sndsrc = nfils; /* Where to look for files to send */ ! 393: ztime(&tp); ! 394: tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */ ! 395: debug(F101,"sinit: sndsrc","",sndsrc); ! 396: if (sndsrc < 0) { /* Must expand from 'send' command */ ! 397: nfils = zxpand(cmarg); /* Look up literal name. */ ! 398: if (nfils < 0) { ! 399: screen(SCR_EM,0,0l,"Too many files"); ! 400: return(0); ! 401: } else if (nfils == 0) { /* If none found, */ ! 402: char xname[100]; /* convert the name. */ ! 403: zrtol(cmarg,xname); ! 404: nfils = zxpand(xname); /* Look it up again. */ ! 405: } ! 406: if (nfils < 1) { /* If no match, report error. */ ! 407: if (server) ! 408: errpkt("File not found"); ! 409: else ! 410: screen(SCR_EM,0,0l,"File not found"); ! 411: return(0); ! 412: } ! 413: x = gnfile(); /* Position to first file. */ ! 414: if (x < 1) { ! 415: if (!server) ! 416: screen(SCR_EM,0,0l,"No readable file to send"); ! 417: else ! 418: errpkt("No readable file to send"); ! 419: return(0); ! 420: } ! 421: } else if (sndsrc > 0) { /* Command line arglist -- */ ! 422: x = gnfile(); /* Get the first file from it. */ ! 423: if (x < 1) return(0); /* (if any) */ ! 424: } else if (sndsrc == 0) { /* stdin or memory always exist... */ ! 425: if ((cmarg2 != NULL) && (*cmarg2)) { ! 426: strcpy(filnam,cmarg2); /* If F packet, "as" name is used */ ! 427: cmarg2 = ""; /* if provided, */ ! 428: } else /* otherwise */ ! 429: strcpy(filnam,"stdin"); /* just use this. */ ! 430: } ! 431: debug(F101,"sinit: nfils","",nfils); ! 432: debug(F110," filnam",filnam,0); ! 433: debug(F110," cmdstr",cmdstr,0); ! 434: ttflui(); /* Flush input buffer. */ ! 435: if (!local && !server) sleep(delay); ! 436: #ifdef datageneral ! 437: if ((local) && (!quiet)) /* Only do this if local & not quiet */ ! 438: consta_mt(); /* Start the asynch read task */ ! 439: #endif ! 440: sipkt('S'); /* Send the Send-Init packet. */ ! 441: return(1); ! 442: } ! 443: ! 444: sipkt(c) char c; { /* Send S or I packet. */ ! 445: CHAR *rp; ! 446: ttflui(); /* Flush pending input. */ ! 447: rp = rpar(); /* Get parameters. */ ! 448: spack(c,pktnum,strlen(rp),rp); ! 449: } ! 450: ! 451: /* R C V F I L -- Receive a file */ ! 452: ! 453: rcvfil() { ! 454: int x; ! 455: ffc = flci = flco = 0; /* Init per-file counters */ ! 456: srvptr = srvcmd; /* Decode file name from packet. */ ! 457: decode(rdatap,putsrv); ! 458: if (*srvcmd == '\0') /* Watch out for null F packet. */ ! 459: strcpy(srvcmd,"NONAME"); ! 460: screen(SCR_FN,0,0l,srvcmd); /* Put it on screen */ ! 461: tlog(F110,"Receiving",srvcmd,0l); /* Transaction log entry */ ! 462: if (cmarg2 != NULL) { /* Check for alternate name */ ! 463: if (*cmarg2 != '\0') { ! 464: strcpy(srvcmd,cmarg2); /* Got one, use it. */ ! 465: *cmarg2 = '\0'; ! 466: } ! 467: } ! 468: x = openo(srvcmd,filnam); /* Try to open it */ ! 469: if (x) { ! 470: tlog(F110," as",filnam,0l); ! 471: screen(SCR_AN,0,0l,filnam); ! 472: intmsg(++filcnt); ! 473: #ifdef datageneral ! 474: /* Need to turn on multi-tasking console interrupt task here, since multiple */ ! 475: /* files may be received. */ ! 476: if ((local) && (!quiet)) /* Only do this if local & not quiet */ ! 477: consta_mt(); /* Start the asynch read task */ ! 478: #endif ! 479: } else { ! 480: tlog(F110,"Failure to open",filnam,0l); ! 481: screen(SCR_EM,0,0l,"Can't open file"); ! 482: } ! 483: return(x); /* Pass on return code from openo */ ! 484: } ! 485: ! 486: /* R E O F -- Receive End Of File */ ! 487: ! 488: reof() { ! 489: int x; ! 490: if (cxseen == 0) cxseen = (*rdatap == 'D'); /* Got discard directive? */ ! 491: x = clsof(cxseen | czseen); ! 492: if (cxseen || czseen) { ! 493: tlog(F100," *** Discarding","",0l); ! 494: cxseen = 0; ! 495: } else ! 496: fstats(); ! 497: return(x); ! 498: } ! 499: ! 500: ! 501: /* R E O T -- Receive End Of Transaction */ ! 502: ! 503: reot() { ! 504: cxseen = czseen = 0; /* Reset interruption flags */ ! 505: tstats(); ! 506: } ! 507: ! 508: /* S F I L E -- Send File header or teXt header packet */ ! 509: ! 510: /* Call with x nonzero for X packet, zero for F packet */ ! 511: /* Returns 1 on success, 0 on failure */ ! 512: ! 513: sfile(x) int x; { ! 514: char pktnam[100]; /* Local copy of name */ ! 515: char *s; ! 516: ! 517: if (x == 0) { /* F-Packet setup */ ! 518: ! 519: if (*cmarg2 != '\0') { /* If we have a send-as name, */ ! 520: strcpy(pktnam,cmarg2); /* copy it literally, */ ! 521: cmarg2 = ""; /* and blank it out for next time. */ ! 522: } else { /* Otherwise use actual file name: */ ! 523: if (fncnv) { /* If converting names, */ ! 524: zltor(filnam,pktnam); /* convert it to common form, */ ! 525: } else { /* otherwise, */ ! 526: strcpy(pktnam,filnam); /* copy it literally. */ ! 527: } ! 528: } ! 529: debug(F110,"sfile",filnam,0); /* Log debugging info */ ! 530: debug(F110," pktnam",pktnam,0); ! 531: if (openi(filnam) == 0) /* Try to open the file */ ! 532: return(0); ! 533: s = pktnam; /* Name for packet data field */ ! 534: ! 535: } else { /* X-packet setup */ ! 536: ! 537: debug(F110,"sxpack",cmdstr,0); /* Log debugging info */ ! 538: s = cmdstr; /* Name for data field */ ! 539: } ! 540: ! 541: flci = flco = ffc = 0; /* Init counters, etc. */ ! 542: encstr(s); /* Encode the name into data[]. */ ! 543: nxtpkt(&pktnum); /* Increment the packet number */ ! 544: spack(x ? 'X' : 'F', pktnum, size, data); /* Send the F or X packet */ ! 545: ! 546: if (x == 0) { /* Display for F packet */ ! 547: if (displa) { /* Screen */ ! 548: screen(SCR_FN,'F',(long)pktnum,filnam); ! 549: screen(SCR_AN,0,0l,pktnam); ! 550: screen(SCR_FS,0,(long)fsize,""); ! 551: } ! 552: tlog(F110,"Sending",filnam,0l); /* Transaction log entry */ ! 553: tlog(F110," as",pktnam,0l); ! 554: ! 555: } else { /* Display for X-packet */ ! 556: ! 557: screen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */ ! 558: tlog(F110,"Sending from:",cmdstr,0l); /* Transaction log */ ! 559: } ! 560: intmsg(++filcnt); /* Count file, give interrupt msg */ ! 561: first = 1; /* Init file character lookahead. */ ! 562: return(1); ! 563: } ! 564: ! 565: /* S D A T A -- Send a data packet */ ! 566: ! 567: /* Return -1 if no data to send, else send packet and return length */ ! 568: ! 569: sdata() { ! 570: int len; ! 571: if (cxseen || czseen) return(-1); /* If interrupted, done. */ ! 572: if ((len = getpkt(spsiz-bctu-3)) == 0) /* Done if no data. */ ! 573: return(-1); ! 574: nxtpkt(&pktnum); /* Increment the packet number */ ! 575: spack('D',pktnum,len,data); /* Send the packet */ ! 576: return(len); ! 577: } ! 578: ! 579: ! 580: /* S E O F -- Send an End-Of-File packet */ ! 581: ! 582: /* Call with a string pointer to character to put in the data field, */ ! 583: /* or else a null pointer or "" for no data. */ ! 584: ! 585: seof(s) char *s; { ! 586: nxtpkt(&pktnum); /* Increment the packet number */ ! 587: if ((s != NULL) && (*s != '\0')) { ! 588: spack('Z',pktnum,1,s); ! 589: tlog(F100," *** interrupted, sending discard request","",0l); ! 590: } else { ! 591: spack('Z',pktnum,0,""); ! 592: fstats(); ! 593: } ! 594: } ! 595: ! 596: ! 597: /* S E O T -- Send an End-Of-Transaction packet */ ! 598: ! 599: seot() { ! 600: nxtpkt(&pktnum); /* Increment the packet number */ ! 601: spack('B',pktnum,0,""); /* Send the EOT packet */ ! 602: cxseen = czseen = 0; /* Reset interruption flags */ ! 603: tstats(); /* Log timing info */ ! 604: } ! 605: ! 606: /* R P A R -- Fill the data array with my send-init parameters */ ! 607: ! 608: CHAR * ! 609: rpar() { ! 610: data[1] = tochar(rpsiz); /* Biggest packet I can receive */ ! 611: data[2] = tochar(rtimo); /* When I want to be timed out */ ! 612: data[3] = tochar(mypadn); /* How much padding I need (none) */ ! 613: data[4] = ctl(mypadc); /* Padding character I want */ ! 614: data[5] = tochar(eol); /* End-Of-Line character I want */ ! 615: data[6] = '#'; /* Control-Quote character I send */ ! 616: switch (rqf) { /* 8th-bit prefix */ ! 617: case -1: ! 618: case 1: if (parity) ebq = sq = '&'; break; ! 619: case 0: ! 620: case 2: break; ! 621: } ! 622: data[7] = sq; ! 623: data[8] = bctr + '0'; /* Block check type */ ! 624: if (rptflg) /* Run length encoding */ ! 625: data[9] = rptq; /* If receiving, agree. */ ! 626: else ! 627: data[9] = '~'; ! 628: ! 629: data[10] = tochar(atcapr?atcapb:0 | lpcapr?lpcapb:0 | swcapr?swcapb:0); ! 630: data[capas+1] = tochar(swcapr ? wsize : 0); /* Window size */ ! 631: ! 632: rpsiz = urpsiz; /* Long packets ... */ ! 633: data[capas+2] = tochar(rpsiz / 95); /* Long packet size, big part */ ! 634: data[capas+3] = tochar(rpsiz % 95); /* Long packet size, little part */ ! 635: data[capas+4] = '\0'; /* Terminate the init string */ ! 636: if (deblog) { ! 637: debug(F110,"rpar",data+1,0); ! 638: rdebu(capas+2); ! 639: } ! 640: return(data+1); /* Return pointer to string. */ ! 641: } ! 642: ! 643: spar(s) char *s; { /* Set parameters */ ! 644: int x, lpsiz; ! 645: ! 646: s--; /* Line up with field numbers. */ ! 647: ! 648: debug(F101,"spar rln","",rln); ! 649: ! 650: /* Limit on size of outbound packets */ ! 651: x = (rln >= 1) ? xunchar(s[1]) : 80; ! 652: lpsiz = spsiz; /* Remember what they SET. */ ! 653: if (spsizf) { /* SET-command override? */ ! 654: if (x < spsiz) spsiz = x; /* Ignore LEN unless smaller */ ! 655: } else { /* otherwise */ ! 656: spsiz = (x < 10) ? 80 : x; /* believe them if reasonable */ ! 657: } ! 658: ! 659: /* Timeout on inbound packets */ ! 660: if (!timef) { /* Only if not SET-cmd override */ ! 661: x = (rln >= 2) ? xunchar(s[2]) : 5; ! 662: timint = (x < 0) ? 5 : x; ! 663: } ! 664: ! 665: /* Outbound Padding */ ! 666: npad = 0; padch = '\0'; ! 667: if (rln >= 3) { ! 668: npad = xunchar(s[3]); ! 669: if (rln >= 4) padch = ctl(s[4]); else padch = 0; ! 670: } ! 671: ! 672: /* Outbound Packet Terminator */ ! 673: seol = (rln >= 5) ? xunchar(s[5]) : '\r'; ! 674: if ((seol < 2) || (seol > 31)) seol = '\r'; ! 675: ! 676: /* Control prefix */ ! 677: x = (rln >= 6) ? s[6] : '#'; ! 678: myctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#'; ! 679: ! 680: /* 8th-bit prefix */ ! 681: rq = (rln >= 7) ? s[7] : 0; ! 682: if (rq == 'Y') rqf = 1; ! 683: else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2; ! 684: else rqf = 0; ! 685: switch (rqf) { ! 686: case 0: ebqflg = 0; break; ! 687: case 1: if (parity) { ebqflg = 1; ebq = '&'; } break; ! 688: case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq; ! 689: } ! 690: ! 691: /* Block check */ ! 692: x = 1; ! 693: if (rln >= 8) { ! 694: x = s[8] - '0'; ! 695: if ((x < 1) || (x > 3)) x = 1; ! 696: } ! 697: bctr = x; ! 698: ! 699: /* Repeat prefix */ ! 700: if (rln >= 9) { ! 701: rptq = s[9]; ! 702: rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127)); ! 703: } else rptflg = 0; ! 704: ! 705: /* Capabilities */ ! 706: atcapu = lpcapu = swcapu = 0; ! 707: if (rln >= 10) { ! 708: x = xunchar(s[10]); ! 709: atcapu = (x & atcapb) && atcapr; ! 710: lpcapu = (x & lpcapb) && lpcapr; ! 711: swcapu = (x & swcapb) && swcapb; ! 712: for (capas = 10; (xunchar(s[capas]) & 1) && (rln >= capas); capas++) ; ! 713: } ! 714: ! 715: /* Long Packets */ ! 716: if (lpcapu) { ! 717: if (rln > capas+2) { ! 718: x = xunchar(s[capas+2]) * 95 + xunchar(s[capas+3]); ! 719: if (spsizf) { /* If overriding negotiations */ ! 720: spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */ ! 721: } else { /* otherwise */ ! 722: spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */ ! 723: } ! 724: if (spsiz < 10) spsiz = 80; /* Be defensive... */ ! 725: } ! 726: } ! 727: ! 728: /* Sliding Windows */ ! 729: if (swcapu) { ! 730: if (rln > capas+1) { ! 731: x = xunchar(s[capas+1]); ! 732: wsize = x > MAXWS ? MAXWS : x; ! 733: } ! 734: else wsize = 1; ! 735: } ! 736: if (deblog) sdebu(rln); /* Record parameters in debug log */ ! 737: } ! 738: ! 739: /* G N F I L E -- Get the next file name from a file group. */ ! 740: ! 741: /* Returns 1 if there's a next file, 0 otherwise */ ! 742: ! 743: gnfile() { ! 744: int x; long y; ! 745: #ifdef datageneral ! 746: int dgfiles = 0; /* Number of files expanded */ ! 747: static int dgnfils = -1; /* Saved nfils value */ ! 748: #endif ! 749: ! 750: /* If file group interruption (C-Z) occured, fail. */ ! 751: ! 752: debug(F101,"gnfile: czseen","",czseen); ! 753: ! 754: if (czseen) { ! 755: tlog(F100,"Transaction cancelled","",0l); ! 756: return(0); ! 757: } ! 758: ! 759: /* If input was stdin or memory string, there is no next file. */ ! 760: ! 761: if (sndsrc == 0) return(0); ! 762: ! 763: /* If file list comes from command line args, get the next list element. */ ! 764: ! 765: y = -1; ! 766: while (y < 0) { /* Keep trying till we get one... */ ! 767: ! 768: if (sndsrc > 0) { ! 769: if (nfils-- > 0) { ! 770: ! 771: #ifdef datageneral ! 772: /* The DG does not internally expand the file names when a string of */ ! 773: /* filenames is given. So we must in this case. */ ! 774: if (dgnfils == -1) { /* This is executed first time only! */ ! 775: strcpy(filnam,*cmlist++); ! 776: dgfiles = zxpand(filnam); /* Expand the string */ ! 777: debug(F111,"gnfile:cmlist filnam (x-init)",filnam,dgfiles); ! 778: dgnfils = nfils + 1; ! 779: debug(F111,"gnfile:cmlist filnam (x-init)",filnam,dgnfils); ! 780: } ! 781: x = znext(filnam); ! 782: if (x > 0) { /* Get the next file in the expanded list */ ! 783: debug(F111,"gnfile znext: filnam (exp-x=)",filnam,x); ! 784: nfils = dgnfils; /* The virtual number of files left */ ! 785: } ! 786: if (x == 0) { /* Expand the next command argument */ ! 787: if (dgnfils == 1) { ! 788: dgnfils = -1; /* The last argument resets things */ ! 789: *filnam = '\0'; ! 790: debug(F101,"gnfile cmlist: nfils","",nfils); ! 791: return(0); ! 792: } ! 793: ! 794: strcpy(filnam,*cmlist++); /* Finish expanding last arg */ ! 795: dgfiles = zxpand(filnam); /* Expand the string */ ! 796: debug(F111,"gnfile: cmlist filnam (exp)",filnam,dgnfils); ! 797: x = znext(filnam); ! 798: debug(F111,"gnfile znext: filnam (exp)",filnam,x); ! 799: nfils = dgnfils--; ! 800: } ! 801: #else ! 802: strcpy(filnam,*cmlist++); ! 803: debug(F111,"gnfile: cmlist filnam",filnam,nfils); ! 804: #endif ! 805: } else { ! 806: *filnam = '\0'; ! 807: debug(F101,"gnfile cmlist: nfils","",nfils); ! 808: return(0); ! 809: } ! 810: } ! 811: ! 812: /* Otherwise, step to next element of internal wildcard expansion list. */ ! 813: ! 814: if (sndsrc < 0) { ! 815: x = znext(filnam); ! 816: debug(F111,"gnfile znext: filnam",filnam,x); ! 817: if (x == 0) return(0); ! 818: } ! 819: ! 820: /* Get here with a filename. */ ! 821: ! 822: y = zchki(filnam); /* Check if file readable */ ! 823: if (y < 0) { ! 824: debug(F110,"gnfile skipping:",filnam,0); ! 825: tlog(F111,filnam,"not sent, reason",(long)y); ! 826: screen(SCR_ST,ST_SKIP,0l,filnam); ! 827: } else fsize = y; ! 828: } ! 829: return(1); ! 830: } ! 831: ! 832: /* O P E N I -- Open an existing file for input */ ! 833: ! 834: openi(name) char *name; { ! 835: int x, filno; ! 836: if (memstr) return(1); /* Just return if file is memory. */ ! 837: ! 838: debug(F110,"openi",name,0); ! 839: debug(F101," sndsrc","",sndsrc); ! 840: ! 841: filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */ ! 842: ! 843: debug(F101," file number","",filno); ! 844: ! 845: if (zopeni(filno,name)) { /* Otherwise, try to open it. */ ! 846: debug(F110," ok",name,0); ! 847: return(1); ! 848: } else { /* If not found, */ ! 849: char xname[100]; /* convert the name */ ! 850: zrtol(name,xname); /* to local form and then */ ! 851: x = zopeni(filno,xname); /* try opening it again. */ ! 852: debug(F101," zopeni","",x); ! 853: if (x) { ! 854: debug(F110," ok",xname,0); ! 855: return(1); /* It worked. */ ! 856: } else { ! 857: screen(SCR_EM,0,0l,"Can't open file"); /* It didn't work. */ ! 858: tlog(F110,xname,"could not be opened",0l); ! 859: debug(F110," openi failed",xname,0); ! 860: return(0); ! 861: } ! 862: } ! 863: } ! 864: ! 865: /* O P E N O -- Open a new file for output. */ ! 866: ! 867: /* Returns actual name under which the file was opened in string 'name2'. */ ! 868: ! 869: openo(name,name2) char *name, *name2; { ! 870: char xname[100], *xp; ! 871: ! 872: if (stdouf) /* Receiving to stdout? */ ! 873: return(zopeno(ZSTDIO,"")); ! 874: ! 875: debug(F110,"openo: name",name,0); ! 876: ! 877: if (cxseen || czseen) { /* If interrupted, get out before */ ! 878: debug(F100," open cancelled","",0); /* destroying existing file. */ ! 879: return(1); /* Pretend to succeed. */ ! 880: } ! 881: xp = xname; /* OK to proceed. */ ! 882: if (fncnv) /* If desired, */ ! 883: zrtol(name,xp); /* convert name to local form */ ! 884: else /* otherwise, */ ! 885: strcpy(xname,name); /* use it literally */ ! 886: ! 887: debug(F110,"openo: xname",xname,0); ! 888: ! 889: if (warn) { /* File collision avoidance? */ ! 890: if (zchki(xname) != -1) { /* Yes, file exists? */ ! 891: znewn(xname,&xp); /* Yes, make new name. */ ! 892: strcpy(xname,xp); ! 893: debug(F110," exists, new name ",xname,0); ! 894: } ! 895: } ! 896: if (zopeno(ZOFILE,xname) == 0) { /* Try to open the file */ ! 897: debug(F110,"openo failed",xname,0); ! 898: tlog(F110,"Failure to open",xname,0l); ! 899: return(0); ! 900: } else { ! 901: strcpy(name2,xname); ! 902: debug(F110,"openo ok, name2",name2,0); ! 903: return(1); ! 904: } ! 905: } ! 906: ! 907: /* O P E N T -- Open the terminal for output, in place of a file */ ! 908: ! 909: opent() { ! 910: ffc = tfc = 0; ! 911: return(zopeno(ZCTERM,"")); ! 912: } ! 913: ! 914: /* C L S I F -- Close the current input file. */ ! 915: ! 916: clsif() { ! 917: #ifdef datageneral ! 918: if ((local) && (!quiet)) /* Only do this if local & not quiet */ ! 919: if (nfils < 1) /* More files to send ... leave it on! */ ! 920: connoi_mt(); ! 921: #endif ! 922: if (memstr) { /* If input was memory string, */ ! 923: memstr = 0; /* indicate no more. */ ! 924: } else zclose(ZIFILE); /* else close input file. */ ! 925: ! 926: if (czseen || cxseen) ! 927: screen(SCR_ST,ST_DISC,0l,""); ! 928: else ! 929: screen(SCR_ST,ST_OK,0l,""); ! 930: cxseen = hcflg = 0; /* Reset flags, */ ! 931: *filnam = '\0'; /* and current file name */ ! 932: } ! 933: ! 934: ! 935: /* C L S O F -- Close an output file. */ ! 936: ! 937: /* Call with disp != 0 if file is to be discarded. */ ! 938: /* Returns -1 upon failure to close, 0 or greater on success. */ ! 939: ! 940: clsof(disp) int disp; { ! 941: int x; ! 942: #ifdef datageneral ! 943: if ((local) && (!quiet)) /* Only do this if local & not quiet */ ! 944: connoi_mt(); ! 945: #endif ! 946: if ((x = zclose(ZOFILE)) < 0) { /* Try to close the file */ ! 947: tlog(F100,"Failure to close",filnam,0l); ! 948: screen(SCR_ST,ST_ERR,0l,""); ! 949: } else if (disp && (keep == 0)) { /* Delete it if interrupted, */ ! 950: if (*filnam) zdelet(filnam); /* and not keeping incomplete files */ ! 951: debug(F100,"Discarded","",0); ! 952: tlog(F100,"Discarded","",0l); ! 953: screen(SCR_ST,ST_DISC,0l,""); ! 954: } else { /* Nothing wrong, just keep it */ ! 955: debug(F100,"Closed","",0); /* and give comforting messages. */ ! 956: screen(SCR_ST,ST_OK,0l,""); ! 957: } ! 958: *filnam = '\0'; /* Zero the current file name. */ ! 959: return(x); /* Send back zclose() return code. */ ! 960: } ! 961: ! 962: /* S N D H L P -- Routine to send builtin help */ ! 963: ! 964: sndhlp() { ! 965: nfils = 0; /* No files, no lists. */ ! 966: xflg = 1; /* Flag we must send X packet. */ ! 967: strcpy(cmdstr,"help text"); /* Data for X packet. */ ! 968: first = 1; /* Init getchx lookahead */ ! 969: memstr = 1; /* Just set the flag. */ ! 970: memptr = hlptxt; /* And the pointer. */ ! 971: if (binary) { /* If file mode is binary, */ ! 972: binary = 0; /* turn it back to text for this, */ ! 973: savmod = 1; /* remember to restore it later. */ ! 974: } ! 975: return(sinit()); ! 976: } ! 977: ! 978: ! 979: /* C W D -- Change current working directory */ ! 980: ! 981: /* ! 982: String passed has first byte as length of directory name, rest of string ! 983: is name. Fails if can't connect, else ACKs (with name) and succeeds. ! 984: */ ! 985: ! 986: cwd(vdir) char *vdir; { ! 987: char *cdd, *zgtdir(); ! 988: vdir[xunchar(*vdir) + 1] = '\0'; /* End with a null */ ! 989: if (zchdir(vdir+1)) { ! 990: cdd = zgtdir(); /* Get new working directory. */ ! 991: encstr(cdd); ! 992: ack1(data); ! 993: tlog(F110,"Changed directory to",cdd,0l); ! 994: return(1); ! 995: } else { ! 996: tlog(F110,"Failed to change directory to",vdir+1,0l); ! 997: return(0); ! 998: } ! 999: } ! 1000: ! 1001: ! 1002: /* S Y S C M D -- Do a system command */ ! 1003: ! 1004: /* Command string is formed by concatenating the two arguments. */ ! 1005: ! 1006: syscmd(prefix,suffix) char *prefix, *suffix; { ! 1007: char *cp; ! 1008: ! 1009: if (prefix == NULL || *prefix == '\0') return(0); ! 1010: ! 1011: #ifdef datageneral ! 1012: /* A kludge for now -- the real change needs to be done elsewhere... */ ! 1013: { ! 1014: extern char *WHOCMD; ! 1015: if ((strcmp(prefix,WHOCMD) == 0) && (*suffix == 0)) ! 1016: strcpy(suffix,"[!pids]"); ! 1017: } ! 1018: #endif ! 1019: for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ; ! 1020: while (*cp++ = *suffix++) ; ! 1021: ! 1022: debug(F110,"syscmd",cmdstr,0); ! 1023: if (zopeni(ZSYSFN,cmdstr) > 0) { ! 1024: debug(F100,"syscmd zopeni ok",cmdstr,0); ! 1025: nfils = sndsrc = 0; /* Flag that input from stdin */ ! 1026: xflg = hcflg = 1; /* And special flags for pipe */ ! 1027: if (binary) { /* If file mode is binary, */ ! 1028: binary = 0; /* turn it back to text for this, */ ! 1029: savmod = 1; /* remember to restore it later. */ ! 1030: } ! 1031: return (sinit()); /* Send S packet */ ! 1032: } else { ! 1033: debug(F100,"syscmd zopeni failed",cmdstr,0); ! 1034: return(0); ! 1035: } ! 1036: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.