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