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