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: }