|
|
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.