|
|
1.1 root 1: char *fnsv = "C-Kermit functions, 5A(071) 8 Feb 92";
2:
3: /* C K C F N S -- System-independent Kermit protocol support functions. */
4:
5: /* ...Part 1 (others moved to ckcfn2,3 to make this module small enough) */
6:
7: /*
8: Author: Frank da Cruz ([email protected], [email protected]),
9: Columbia University Center for Computing Activities.
10: First released January 1985.
11: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
12: York. Permission is granted to any individual or institution to use, copy, or
13: redistribute this software so long as it is not sold for profit, provided this
14: copyright notice is retained.
15: */
16: /*
17: System-dependent primitives defined in:
18:
19: ck?tio.c -- terminal i/o
20: cx?fio.c -- file i/o, directory structure
21: */
22: #include "ckcsym.h" /* Once needed this for Mac... */
23: #include "ckcasc.h" /* ASCII symbols */
24: #include "ckcdeb.h" /* Debug formats, typedefs, etc. */
25: #include "ckcker.h" /* Symbol definitions for Kermit */
26: #include "ckcxla.h" /* Character set symbols */
27:
28: /* Externals from ckcmai.c */
29: extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
30: rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr;
31: extern int pktnum, bctr, bctu, fmask, clfils, sbufnum,
32: size, osize, spktl, nfils, warn, timef, spsizf;
33: extern int parity, turn, network, what,
34: delay, displa, xflg, mypadn;
35: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize, speed;
36: extern int fblksiz, frecl, frecfm, forg, fcctrl;
37: extern int spackets, rpackets, timeouts, retrans, crunched, wmax;
38: extern int hcflg, binary, savmod, fncnv, local, server, cxseen, czseen;
39: extern int nakstate, discard;
40: extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
41: extern int atcapr, atcapb, atcapu;
42: extern int lpcapr, lpcapb, lpcapu;
43: extern int swcapr, swcapb, swcapu;
44: extern int lscapr, lscapb, lscapu;
45: extern int bsave, bsavef;
46: extern int sseqtbl[];
47: extern int numerrs;
48: extern long rptn;
49: extern int maxtry;
50:
51: #ifndef NOCSETS
52: extern int tcharset, fcharset;
53: extern int ntcsets;
54: extern struct csinfo tcsinfo[], fcsinfo[];
55: #endif /* NOCSETS */
56:
57: extern int
58: atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
59: attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
60:
61: extern int bigsbsiz, bigrbsiz;
62:
63: #ifdef DYNAMIC
64: extern CHAR *srvcmd;
65: #else
66: extern CHAR srvcmd[];
67: #endif /* DYNAMIC */
68: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate;
69: extern CHAR *recpkt, *data, padbuf[], stchr, mystch;
70: extern CHAR *srvptr;
71: extern CHAR *rdatap;
72: extern char *cmarg, *cmarg2, *hlptxt, **cmlist, filnam[], fspec[];
73:
74: _PROTOTYP( CHAR *rpar, (void) );
75: _PROTOTYP( int lslook, (unsigned int b) ); /* Locking Shift Lookahead */
76: _PROTOTYP( int szeof, (CHAR *s) );
77:
78: /* International character sets */
79:
80: #ifndef NOCSETS
81: /* Pointers to translation functions */
82: #ifdef CK_ANSIC
83: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
84: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
85: #else
86: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
87: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
88: #endif /* CK_ANSIC */
89: _PROTOTYP( CHAR (*rx), (CHAR) ); /* Input translation function */
90: _PROTOTYP( CHAR (*sx), (CHAR) ); /* Output translation function */
91: _PROTOTYP( CHAR ident, (CHAR) ); /* Identity translation function */
92: #endif /* NOCSETS */
93:
94: /* Windowing things */
95:
96: extern int rseqtbl[]; /* Rec'd-packet sequence # table */
97:
98: /* (PWP) external def. of things used in buffered file input and output */
99:
100: #ifdef DYNAMIC
101: extern char *zinbuffer, *zoutbuffer;
102: #else
103: extern char zinbuffer[], zoutbuffer[];
104: #endif
105: extern char *zinptr, *zoutptr;
106: extern int zincnt, zoutcnt;
107:
108: /* Variables defined in this module, but shared by ckcfn3, to which */
109: /* several functions have been moved... */
110:
111: int sndsrc; /* Flag for where to get names of files to send: */
112: /* -1: znext() function */
113: /* 0: stdin */
114: /* >0: list in cmlist */
115:
116: int memstr; /* Flag for input from memory string */
117:
118: /* Variables local to this module */
119:
120: static char *memptr; /* Pointer for memory strings */
121:
122: static char cmdstr[100]; /* Unix system command string */
123:
124: static int drain; /* For draining stacked-up ACKs. */
125:
126: static int first; /* Flag for first char from input */
127: static CHAR t, /* Current character */
128: next; /* Next character */
129:
130: static int lsstate = 0; /* Locking shift state */
131: static int lsquote = 0; /* Locking shift quote */
132:
133: #ifdef datageneral
134: extern int quiet;
135: #endif
136:
137: /* E N C S T R -- Encode a string from memory. */
138:
139: /*
140: Call this instead of getpkt() if source is a string, rather than a file.
141: Note: Character set translation is never done in this case.
142: */
143:
144: #define ENCBUFL 200
145: CHAR encbuf[ENCBUFL]; /* Because getpkt always writes */
146: /* into "data", but when this */
147: /* function is called, "data" might */
148: /* might not be allocated. */
149: int
150: encstr(s) CHAR* s; {
151: int m; char *p;
152: CHAR *dsave;
153:
154: if ((m = (int)strlen((char *)s)) > ENCBUFL) {
155: debug(F111,"encstr string too long for buffer",s,ENCBUFL);
156: s[ENCBUFL] = '\0';
157: }
158: if (m > spsiz-bctu-3) {
159: debug(F111,"encstr string too long for packet",s,spsiz-bctu-3);
160: s[spsiz-bctu-3] = '\0';
161: }
162: m = memstr; p = memptr; /* Save these. */
163:
164: memptr = (char *)s; /* Point to the string. */
165: memstr = 1; /* Flag memory string as source. */
166: first = 1; /* Initialize character lookahead. */
167: dsave = data; /* Boy is this ugly... */
168: data = encbuf + 7; /* Why + 7? See spack()... */
169: getpkt(spsiz-bctu-3,0); /* Fill a packet from the string. */
170: data = dsave; /* (sorry...) */
171: memstr = m; /* Restore memory string flag */
172: memptr = p; /* and pointer */
173: first = 1; /* Put this back as we found it. */
174: return(0);
175: }
176:
177: #ifdef COMMENT
178: /*
179: We don't use this routine any more -- the code has been incorporated
180: directly into getpkt() to reduce per-character function call overhead.
181: Also, watch out: it hasn't been updated since it was commented out a
182: long time ago.
183: */
184: /* E N C O D E - Kermit packet encoding procedure */
185:
186: VOID
187: encode(a) CHAR a; { /* The current character */
188: int a7; /* Low order 7 bits of character */
189: int b8; /* 8th bit of character */
190:
191: #ifndef NOCSETS
192: if (!binary && sx) a = (*sx)(a); /* Translate. */
193: #endif /* NOCSETS */
194:
195: if (rptflg) { /* Repeat processing? */
196: if (a == next && (first == 0)) { /* Got a run... */
197: if (++rpt < 94) /* Below max, just count */
198: return;
199: else if (rpt == 94) { /* Reached max, must dump */
200: data[size++] = rptq;
201: data[size++] = tochar(rpt);
202: rptn += rpt; /* Count, for stats */
203: rpt = 0;
204: }
205: } else if (rpt == 1) { /* Run broken, only 2? */
206: rpt = 0; /* Yes, reset repeat flag & count. */
207: encode(a); /* Do the character twice. */
208: if (size <= maxsize) osize = size;
209: rpt = 0;
210: encode(a);
211: return;
212: } else if (rpt > 1) { /* More than two */
213: data[size++] = rptq; /* Insert the repeat prefix */
214: data[size++] = tochar(++rpt); /* and count. */
215: rptn += rpt;
216: rpt = 0; /* Reset repeat counter. */
217: }
218: }
219: a7 = a & 0177; /* Isolate ASCII part */
220: b8 = a & 0200; /* and 8th (parity) bit. */
221:
222: if (ebqflg && b8) { /* Do 8th bit prefix if necessary. */
223: data[size++] = ebq;
224: a = a7;
225: }
226: if ((a7 < SP) || (a7==DEL)) { /* Do control prefix if necessary */
227: data[size++] = myctlq;
228: a = ctl(a);
229: }
230: if (a7 == myctlq) /* Prefix the control prefix */
231: data[size++] = myctlq;
232:
233: if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
234: data[size++] = myctlq; /* quote it if doing repeat counts. */
235:
236: if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */
237: data[size++] = myctlq; /* if doing 8th-bit prefixes */
238:
239: data[size++] = a; /* Finally, insert the character */
240: data[size] = '\0'; /* itself, and mark the end. */
241: }
242: #endif /* COMMENT */
243:
244: /* Output functions passed to 'decode': */
245:
246: int /* Put character in server command buffer */
247: #ifdef CK_ANSIC
248: putsrv(char c)
249: #else
250: putsrv(c) register char c;
251: #endif /* CK_ANSIC */
252: /* putsrv */ {
253: *srvptr++ = c;
254: *srvptr = '\0'; /* Make sure buffer is null-terminated */
255: return(0);
256: }
257:
258: int /* Output character to console. */
259: #ifdef CK_ANSIC
260: puttrm(char c)
261: #else
262: puttrm(c) register char c;
263: #endif /* CK_ANSIC */
264: /* puttrm */ {
265: conoc(c);
266: return(0);
267: }
268:
269: int /* Output char to file. */
270: #ifdef CK_ANSIC
271: putfil(char c)
272: #else
273: putfil(c) register char c;
274: #endif /* CK_ANSIC */
275: /* putfil */ {
276: if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
277: czseen = 1; /* If write error... */
278: debug(F101,"putfil zchout write error, setting czseen","",1);
279: return(-1);
280: }
281: return(0);
282: }
283:
284: /* D E C O D E -- Kermit packet decoding procedure */
285:
286: /*
287: Call with string to be decoded and an output function.
288: Returns 0 on success, -1 on failure (e.g. disk full).
289:
290: This is the "inner loop" when receiving files, and must be coded as
291: efficiently as possible. Note some potential problems: if a packet
292: is badly formed, having a prefixed sequence ending prematurely, this
293: function, as coded, could read past the end of the packet. This has
294: never happened, thus the additional (time-consuming) tests have not
295: been added.
296: */
297:
298: static CHAR *xdbuf; /* Global version of decode()'s buffer pointer */
299: /* for use by translation functions. */
300:
301: /* Function for pushing a character onto decode()'s input stream. */
302:
303: VOID
304: #ifdef CK_ANSIC
305: zdstuff(CHAR c)
306: #else
307: zdstuff(c) CHAR c;
308: #endif /* CK_ANSIC */
309: /* zdstuff */ {
310: xdbuf--; /* Back up the pointer. */
311: *xdbuf = c; /* Stuff the character. */
312: }
313:
314: int
315: #ifdef CK_ANSIC
316: decode(CHAR *buf, int (*fn)(char), int xlate)
317: #else
318: decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
319: #endif /* CK_ANSIC */
320: /* decode */ {
321: register unsigned int a, a7, a8, b8; /* Various copies of current char */
322: int t; /* Int version of character */
323: int ssflg; /* Character was single-shifted */
324:
325: xdbuf = buf; /* Make global copy of pointer. */
326: rpt = 0; /* Initialize repeat count. */
327:
328: while ((a = *xdbuf++ & 0xFF) != '\0') { /* Get next character. */
329: if (a == rptq && rptflg) { /* Got a repeat prefix? */
330: rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
331: rptn += rpt;
332: a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
333: }
334: b8 = lsstate ? 0200 : 0; /* 8th-bit value from SHIFT-STATE */
335: if (ebqflg && a == ebq) { /* Have 8th-bit prefix? */
336: b8 ^= 0200; /* Yes, invert the 8th bit's value, */
337: ssflg = 1; /* remember we did this, */
338: a = *xdbuf++ & 0xFF; /* and get the prefixed character. */
339: } else ssflg = 0;
340:
341: if (a == ctlq) { /* If control prefix, */
342: a = *xdbuf++ & 0xFF; /* get its operand */
343: a7 = a & 0x7F; /* and its low 7 bits. */
344: if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Controllify */
345: a = ctl(a); /* if in control range. */
346: if (lscapu) { /* If doing locking shifts... */
347: if (lsstate) /* If SHIFTED */
348: a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
349: else /* otherwise */
350: a8 = a | b8; /* OR in 8th bit */
351: /* If we're not in a quoted sequence */
352: if (!lsquote && (!lsstate || !ssflg)) {
353: if (a8 == DLE) { /* Check for DLE quote */
354: lsquote = 1; /* prefixed by single shift! */
355: continue;
356: } else if (a8 == SO) { /* Check for Shift-Out */
357: lsstate = 1; /* SHIFT-STATE = SHIFTED */
358: continue;
359: } else if (a8 == SI) { /* or Shift-In */
360: lsstate = 0; /* SHIFT-STATE = UNSHIFTED */
361: continue;
362: }
363: } else lsquote = 0;
364: }
365: }
366: a |= b8; /* OR in the 8th bit */
367: if (rpt == 0) rpt = 1; /* If no repeats, then one */
368: if (!binary) { /* If in text mode, */
369: #ifdef NLCHAR
370: if (a == CR) continue; /* Discard carriage returns, */
371: if (a == LF) a = NLCHAR; /* convert LF to system's newline. */
372: #endif /* NLCHAR */
373:
374: #ifndef NOCSETS /* Character-set translation */
375: #ifdef KANJI /* For Kanji transfers, */
376: if (tcharset != TC_JEUC) /* postpone translation. */
377: #endif /* KANJI */
378: if (xlate && rx) a = (*rx)((CHAR) a); /* Translate charset */
379: #endif /* NOCSETS */
380: }
381: if (fn == putfil) { /* (PWP) speedup via buffered output and a macro */
382: for (; rpt > 0; rpt--) { /* Output the char RPT times */
383: #ifndef NOCSETS
384: #ifdef KANJI
385: if (!binary && tcharset == TC_JEUC &&
386: fcharset != FC_JEUC) { /* Translating from J-EUC */
387: if (ffc == 0L) xkanjf();
388: if (xkanji(a,fn) < 0) /* to something else? */
389: return(-1);
390: } else
391: #endif /* KANJI */
392: #endif /* NOCSETS */
393: if ((t = zmchout(a)) < 0) { /* zmchout is a macro */
394: #ifdef COMMENT
395: /* Too costly, uncomment these if you really need them. */
396: debug(F101,"decode zmchout","",t);
397: debug(F101,"decode zoutcnt","",zoutcnt);
398: debug(F101,"decode a","",a);
399: #endif /* COMMENT */
400: return(-1);
401: }
402: ffc++; /* Count the character */
403: }
404: } else { /* Output to something else. */
405: for (; rpt > 0; rpt--) { /* Output the char RPT times */
406: if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
407: ffc++;
408: }
409: }
410: }
411: return(0);
412: }
413:
414: /* G E T P K T -- Fill a packet data field */
415:
416: /*
417: Gets characters from the current source -- file or memory string.
418: Encodes the data into the packet, filling the packet optimally.
419: Set first = 1 when calling for the first time on a given input stream
420: (string or file).
421:
422: Uses global variables:
423: t -- current character.
424: first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
425: next -- next character.
426: data -- pointer to the packet data buffer.
427: size -- number of characters in the data buffer.
428: memstr - flag that input is coming from a memory string instead of a file.
429: memptr - pointer to string in memory.
430: (*sx)() character set translation function
431:
432: Returns the size as value of the function, and also sets global "size",
433: and fills (and null-terminates) the global data array. Returns 0 upon eof.
434:
435: Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
436: Incorporates old getchx() and encode() inline to reduce function calls,
437: uses buffered input for much-improved efficiency, and clears up some
438: confusion with line termination (CRLF vs LF vs CR).
439:
440: Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
441: May 1991.
442: */
443:
444: /*
445: Lookahead function to decide whether locking shift is worth it. Looks at
446: the next four input characters to see if all of their 8th bits match the
447: argument. Call with 0 or 0200. Returns 1 if so, 0 if not. If we don't
448: happen to have at least 4 more characters waiting in the input buffer,
449: returns 1. Note that zinptr points two characters ahead of the current
450: character because of repeat-count lookahead.
451: */
452:
453: #ifdef KANJI
454: int
455: kgetf() {
456: return(zminchar());
457: }
458:
459: int
460: kgetm() {
461: int x;
462: if (x = *memptr++) return(x);
463: else return(-1);
464: }
465: #endif /* KANJI */
466:
467: int
468: lslook(b) unsigned int b; { /* Locking Shift Lookahead */
469: int i;
470: if (zincnt < 3) /* If not enough chars in buffer, */
471: return(1); /* force shift-state switch. */
472: b &= 0200; /* Force argument to proper form. */
473: for (i = -1; i < 3; i++) /* Look at next 5 characters to */
474: if (((*(zinptr+i)) & 0200) != b) /* see if all their 8th bits match. */
475: return(0); /* They don't. */
476: return(1); /* They do. */
477: }
478:
479: int
480: getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
481: register CHAR rt = t, rnext = next; /* register shadows of the globals */
482: register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
483: register int x; /* Loop index. */
484: register int a7; /* Low 7 bits of character */
485: static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' };
486: CHAR xxls, xxdl, xxrc, xxss, xxcq; /* Pieces of prefixed sequence */
487:
488: #ifdef KANJI
489: int zkanji(); /* For translating Kanji characters */
490: int zkanjf();
491: int zkanjz();
492: #endif /* KANJI */
493:
494: if (first == 1) { /* If first character of this file... */
495: ffc = 0L; /* Reset file character counter */
496: first = 0; /* Next character won't be first */
497: *leftover = '\0'; /* Discard any interrupted leftovers, */
498:
499: /* get first character of file into rt, watching out for null file */
500:
501: #ifndef NOCSETS
502: #ifdef KANJI
503: if (!binary && tcharset == TC_JEUC && xlate) {
504: x = zkanjf();
505: if ((x = zkanji( memstr ? kgetm : kgetf )) < 0) {
506: first = -1;
507: size = 0;
508: if (x == -2) {
509: debug(F100,"getpkt(zkanji): input error","",0);
510: cxseen = 1;
511: } else debug(F100,"getpkt(zkanji): empty string/file","",0);
512: return (0);
513: }
514: ffc++;
515: rt = x;
516: } else {
517: #endif /* KANJI */
518: #endif /* not NOCSETS */
519: if (memstr) { /* Reading data from memory string */
520: if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
521: first = -1;
522: size = 0;
523: debug(F100,"getpkt: empty string","",0);
524: return (0);
525: }
526:
527: } else { /* Reading data from a file */
528:
529: if ((x = zminchar()) < 0) { /* End of file or input error */
530: first = -1;
531: size = 0;
532: if (x == -2) { /* Error */
533: debug(F100,"getpkt: input error","",0);
534: cxseen = 1; /* Interrupt the file transfer */
535: } else debug(F100,"getpkt: empty file","",0); /* Empty file */
536: return(0);
537: }
538: ffc++; /* Count a file character */
539: rt = x; /* Convert int to char */
540: debug(F101,"getpkt zminchar","",rt);
541: }
542: #ifndef NOCSETS
543: #ifdef KANJI
544: }
545: #endif /* KANJI */
546: #endif /* not NOCSETS */
547:
548: rt &= fmask; /* Apply SET FILE BYTESIZE mask */
549:
550: #ifndef NOCSETS
551: if (xlate) {
552: debug(F101,"getpkt about to call translate function","",rt);
553: debug(F101,"tcharset","",tcharset);
554: debug(F101,"fcharset","",fcharset);
555: }
556: #ifdef KANJI
557: if (tcharset != TC_JEUC)
558: #endif /* KANJI */
559: if (!binary && sx && xlate) {
560: rt = (*sx)(rt); /* Translate */
561: debug(F101," translate function returns","",rt);
562: }
563: #endif /* not NOCSETS */
564:
565: /* PWP: handling of NLCHAR is done later (in the while loop)... */
566:
567: } else if ((first == -1) && (*leftover == '\0')) /* EOF from last time? */
568: return(size = 0);
569: /*
570: Here we handle characters that were encoded for the last packet but
571: did not fit, and so were saved in the "leftover" array.
572: */
573: dp = data; /* Point to packet data buffer */
574: for (p1 = leftover; (*dp = *p1) != '\0'; p1++, dp++) /* Copy leftovers */
575: ;
576: *leftover = '\0'; /* Delete leftovers */
577: if (first == -1) /* Handle EOF */
578: return(size = (dp - data));
579:
580: /* Now fill up the rest of the packet. */
581:
582: rpt = 0; /* Initialize character repeat count */
583:
584: while (first > -1) { /* Until EOF... */
585: #ifndef NOCSETS
586: #ifdef KANJI
587: if (!binary && xlate && tcharset == TC_JEUC) {
588: if ((x = zkanji( memstr ? kgetm : kgetf )) < 0) {
589: first = -1;
590: if (x == -2) cxseen = 1;
591: }
592: ffc++;
593: rnext = x & fmask;
594: } else {
595: #endif /* KANJI */
596: #endif /* not NOCSETS */
597: if (memstr) { /* Get next char from memory string */
598: if ((x = *memptr++) == '\0') /* End of string means EOF */
599: first = -1; /* Flag EOF for next time. */
600: rnext = x & fmask; /* Apply file mask */
601: } else {
602: if ((x = zminchar()) < 0) { /* Real file, check for EOF */
603: first = -1; /* Flag eof for next time. */
604: if (x == -2) cxseen = 1; /* If error, cancel this file. */
605: }
606: rnext = x & fmask; /* Apply file mask */
607: }
608: ffc++; /* Count the character */
609: #ifndef NOCSETS
610: #ifdef KANJI
611: }
612: #endif /* KANJI */
613: #endif /* not NOCSETS */
614:
615: debug(F101,"getpkt rnext","",rnext);
616:
617: #ifndef NOCSETS
618: #ifdef KANJI
619: if (tcharset != TC_JEUC)
620: #endif /* KANJI */
621: if (!binary && sx && xlate) {
622: rnext = (*sx)(rnext); /* Translate */
623: debug(F101,"getpkt xlated rnext to","",rnext);
624: }
625: #endif /* not NOCSETS */
626:
627: odp = dp; /* Remember where we started. */
628: xxls = xxdl = xxrc = xxss = xxcq = NUL; /* Clear these. */
629:
630: /*
631: Now encode the character according to the options that are in effect:
632: binary: text or binary mode.
633: rptflg: repeat counts enabled.
634: ebqflg: 8th-bit prefixing enabled.
635: lscapu: locking shifts enabled.
636: */
637: if (rptflg) { /* Repeat processing is on? */
638: if (
639: #ifdef NLCHAR
640: /*
641: * If the next char is really CRLF, then we cannot
642: * be doing a repeat (unless CR,CR,LF which becomes
643: * "~ <n-1> CR CR LF", which is OK but not most efficient).
644: * I just plain don't worry about this case. The actual
645: * conversion from NL to CRLF is done after the rptflg if...
646: */
647: (binary || (rnext != NLCHAR)) &&
648: #endif /* NLCHAR */
649: (rt == rnext) && (first == 0)) { /* Got a run... */
650: if (++rpt < 94) { /* Below max, just count */
651: continue; /* go back and get another */
652: }
653: else if (rpt == 94) { /* Reached max, must dump */
654: xxrc = tochar(rpt); /* Put the repeat count here */
655: rptn += rpt; /* Accumulate it for statistics */
656: rpt = 0; /* And reset it */
657: }
658: } else if (rpt > 1) { /* More than two */
659: xxrc = tochar(++rpt); /* and count. */
660: rptn += rpt;
661: rpt = 0; /* Reset repeat counter. */
662: }
663: /*
664: If (rpt == 1) we must encode exactly two characters.
665: This is done later, after the first character is encoded.
666: */
667: }
668:
669: #ifdef NLCHAR
670: if (!binary && (rt == NLCHAR)) { /* It's the newline character */
671: if (lscapu && lsstate) { /* If SHIFT-STATE is SHIFTED */
672: if (ebqflg) { /* If single shifts enabled, */
673: *dp++ = ebq; /* insert a single shift. */
674: } else { /* Otherwise must shift in. */
675: *dp++ = myctlq; /* Insert shift-out code */
676: *dp++ = 'O';
677: lsstate = 0; /* Change shift state */
678: }
679: }
680: *dp++ = myctlq; /* Insert carriage return directly */
681: *dp++ = 'M';
682: rt = LF; /* Now make next char be linefeed. */
683: }
684: #endif /* NLCHAR */
685:
686: /*
687: Now handle the 8th bit of the file character. If we have an 8-bit
688: connection, we preserve the 8th bit. If we have a 7-bit connection,
689: we employ either single or locking shifts (if they are enabled).
690: */
691: a7 = rt & 0177; /* Get low 7 bits of character */
692: if (rt & 0200) { /* 8-bit character? */
693: if (lscapu) { /* Locking shifts enabled? */
694: if (!lsstate) { /* Not currently shifted? */
695: x = lslook(0200); /* Look ahead */
696: if (x != 0 || ebqflg == 0) { /* Locking shift decision */
697: xxls = 'N'; /* Need locking shift-out */
698: lsstate = 1; /* and change to shifted state */
699: } else if (ebqflg) { /* Not worth it */
700: xxss = ebq; /* Use single shift */
701: }
702: }
703: rt = a7; /* Replace character by 7-bit value */
704: } else if (ebqflg) { /* 8th bit prefixing is on? */
705: xxss = ebq; /* Insert single shift */
706: rt = a7; /* Replace character by 7-bit value */
707: }
708:
709: } else if (lscapu) { /* 7-bit character */
710:
711: if (lsstate) { /* Comes while shifted out? */
712: x = lslook(0); /* Yes, look ahead */
713: if (x || ebqflg == 0) { /* Time to shift in. */
714: xxls = 'O'; /* Set shift-in code */
715: lsstate = 0; /* Exit shifted state */
716: } else if (ebqflg) { /* Not worth it, stay shifted out */
717: xxss = ebq; /* Insert single shift */
718: }
719: }
720: }
721: /* If data character is significant to locking shift protocol... */
722: if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
723: xxdl = 'P'; /* Insert datalink escape */
724:
725: if ((a7 < SP) || (a7 == DEL)) { /* Do control prefixing if necessary */
726: xxcq = myctlq; /* The prefix */
727: rt = ctl(rt); /* Uncontrollify the character */
728: }
729: if (a7 == myctlq) /* Always prefix the control prefix */
730: xxcq = myctlq;
731:
732: if ((rptflg) && (a7 == rptq)) /* If it's the repeat prefix, */
733: xxcq = myctlq; /* prefix it if doing repeat counts */
734:
735: if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th-bit prefix */
736: xxcq = myctlq; /* if doing 8th-bit prefixes */
737:
738: /* Now construct the entire sequence */
739:
740: if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
741: odp2 = dp; /* (Save this place) */
742: if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
743: if (xxrc) { *dp++ = rptq; *dp++ = xxrc; } /* Repeat count */
744: if (xxss) { *dp++ = ebq; } /* Single shift */
745: if (xxcq) { *dp++ = myctlq; } /* Control prefix */
746: *dp++ = rt; /* Finally, the character itself */
747:
748: if (rpt == 1) { /* Exactly two copies? */
749: rpt = 0;
750: p2 = dp; /* Save place temporarily */
751: for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
752: *dp++ = *p1;
753: if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
754: }
755: rt = rnext; /* Next character is now current. */
756:
757: /* Done encoding the character. Now take care of packet buffer overflow. */
758:
759: if ((dp-data) >= bufmax) { /* If too big, save some for next. */
760: size = (dp-data); /* Calculate the size. */
761: *dp = '\0'; /* Mark the end. */
762: if ((dp-data) > bufmax) { /* if packet is overfull */
763: /* copy the part that doesn't fit into the leftover buffer, */
764: /* taking care not to split a prefixed sequence. */
765: for (p1 = leftover, p2=odp; (*p1 = *p2) != '\0'; p1++,p2++)
766: ;
767: debug(F111,"getpkt leftover",leftover,size);
768: debug(F101," osize","",(odp-data));
769: size = (odp-data); /* Return truncated packet. */
770: *odp = '\0'; /* Mark the new end */
771: }
772: t = rt; next = rnext; /* save for next time */
773: return(size);
774: }
775: } /* Otherwise, keep filling. */
776:
777: size = (dp-data); /* End of file */
778: *dp = '\0'; /* Mark the end of the data. */
779: debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
780: return(size); /* return partially filled last packet. */
781: }
782:
783: /* T I N I T -- Initialize a transaction */
784:
785: int
786: tinit() {
787: int x;
788:
789: #ifndef NOCSETS
790: if (tcharset == TC_TRANSP) { /* Character set translation */
791: rx = sx = NULL; /* Transparent, no translation */
792: #ifdef KANJI
793: } else if (tcharset == TC_JEUC) {
794: rx = sx = NULL; /* Transparent, no translation */
795: #endif /* KANJI */
796: } else { /* otherwise */
797: rx = xlr[tcharset][fcharset]; /* Input translation function */
798: sx = xls[tcharset][fcharset]; /* Output translation function */
799: }
800: debug(F101,"tinit tcharset","",tcharset);
801: debug(F101,"tinit fcharset","",fcharset);
802: #ifdef COMMENT
803: debug(F101,"tinit sx ","",sx);
804: debug(F101,"tinit rx ","",rx);
805: #endif /* COMMENT */
806: #endif /* NOCSETS */
807: autopar = 0; /* Automatic parity detection flag */
808: xflg = 0; /* Reset x-packet flag */
809: rqf = -1; /* Reset 8th-bit-quote request flag */
810: memstr = 0; /* Reset memory-string flag */
811: memptr = NULL; /* and pointer */
812: bctu = 1; /* Reset block check type to 1 */
813: ebq = MYEBQ; /* Reset 8th-bit quoting stuff */
814: ebqflg = 0;
815: if (savmod) { /* If global file mode was saved, */
816: binary = savmod; /* restore it, */
817: savmod = 0; /* unsave it. */
818: }
819: pktnum = 0; /* Initial packet number */
820: cxseen = czseen = discard = 0; /* Reset interrupt flags */
821: *filnam = '\0'; /* Clear file name */
822: spktl = 0; /* And its length */
823: nakstate = 0; /* Assume not in a NAK'ing state */
824: numerrs = 0; /* Transmission error counter */
825: if (server) /* If acting as server, */
826: timint = srvtim; /* Use server timeout interval. */
827: else
828: timint = pkttim;
829: spsiz = spsizr; /* Initial send-packet size */
830: wslots = 1; /* One window slot */
831: winlo = 0; /* Packet 0 is at window-low */
832: x = mksbuf(wslots); /* Make a 1-slot send-packet buffer */
833: if (x < 0) return(x);
834: x = getsbuf(0); /* Allocate first send-buffer. */
835: debug(F101,"tinit getsbuf","",x);
836: if (x < 0) return(x);
837: dumpsbuf();
838: x = mkrbuf(wslots); /* & a 1-slot receive-packet buffer. */
839: if (x < 0) return(x);
840: what = W_NOTHING; /* Doing nothing so far... */
841: lsstate = 0; /* Initialize locking shift state */
842: return(0);
843: }
844:
845: VOID
846: pktinit() { /* Initialize packet sequence */
847: pktnum = 0; /* number & window low. */
848: winlo = 0;
849: }
850:
851: /* R I N I T -- Respond to S or I packet */
852:
853: VOID
854: rinit(d) CHAR *d; {
855: char *tp;
856: ztime(&tp);
857: tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
858: if (binary)
859: tlog(F100,"Global file mode = binary","",0L);
860: else
861: tlog(F100,"Global file mode = text","",0L);
862: filcnt = 0; /* Init file counter */
863: spar(d);
864: ack1(rpar());
865: #ifdef datageneral
866: if ((local) && (!quiet)) /* Only do this if local & not quiet */
867: consta_mt(); /* Start the asynch read task */
868: #endif /* datageneral */
869: }
870:
871:
872: /* R E S E T C -- Reset per-transaction character counters */
873:
874: VOID
875: resetc() {
876: rptn = 0; /* Repeat counts */
877: flci = flco = 0L; /* File chars in and out */
878: tfc = tlci = tlco = 0L; /* Total file, line chars in & out */
879: fsize = 0L; /* File size */
880: timeouts = retrans = 0; /* Timeouts, retransmissions */
881: spackets = rpackets = 0; /* Packet counts out & in */
882: crunched = 0; /* Crunched packets */
883: wmax = 1; /* Maximum window size used */
884: }
885:
886: /* S I N I T -- Get & verify first file name, then send Send-Init packet */
887: /*
888: Returns:
889: 1 if send operation begins successfully
890: 0 if send operation fails
891: */
892: #ifdef DYNAMIC
893: char *cmargbuf = NULL;
894: #else
895: char cmargbuf[256]; /* Filename buffer must be static */
896: #endif /* DYNAMIC */
897: char *cmargp[2];
898:
899: int
900: sinit() {
901: int x; /* Worker int */
902: char *tp, *xp, *m; /* Worker string pointers */
903:
904: filcnt = 0; /* Initialize file counter */
905: sndsrc = nfils; /* Source for filenames */
906: #ifdef DYNAMIC
907: if (!cmargbuf && !(cmargbuf = malloc(256)))
908: fatal("sinit: no memory for cmargbuf");
909: #endif /* DYNAMIC */
910: cmargbuf[0] = NUL; /* Initialize name buffer */
911:
912: debug(F101,"sinit nfils","",nfils);
913: debug(F110,"sinit cmarg",cmarg,0);
914: debug(F110,"sinit cmarg2",cmarg2,0);
915: if (nfils == 0) { /* Sending from stdin or memory. */
916: if ((cmarg2 != NULL) && (*cmarg2)) {
917: cmarg = cmarg2; /* If F packet, "as-name" is used */
918: cmarg2 = ""; /* if provided */
919: } else cmarg = "stdin"; /* otherwise just use "stdin" */
920: strcpy(cmargbuf,cmarg);
921: cmargp[0] = cmargbuf;
922: cmargp[1] = "";
923: cmlist = cmargp;
924: nfils = 1;
925: }
926: #ifdef COMMENT
927: if (nfils < 1) { /* Filespec pointed to by cmarg */
928: if (nfils < 0) sndsrc = 1;
929: nfils = 1; /* Change it to cmlist */
930: strcpy(cmargbuf,cmarg); /* so we have a consistent way */
931: cmargp[0] = cmargbuf; /* of going thru the file list. */
932: cmargp[1] = "";
933: cmlist = cmargp;
934: }
935:
936: /* At this point, cmlist contains the list of filespecs to send */
937:
938: debug(F111,"sinit *cmlist",*cmlist,nfils);
939:
940: xp = *cmlist; /* Save this for messages */
941: #else
942: xp = (nfils < 0) ? cmarg : *cmlist;
943: #endif
944:
945: x = gnfile(); /* Get first filename. */
946: m = NULL; /* Error message pointer */
947: debug(F101,"sinit gnfil","",x);
948: switch (x) {
949: case -5: m = "Too many files match wildcard"; break;
950: case -4: m = "Cancelled"; break;
951: case -3: m = "Read access denied"; break;
952: case -2: m = "File is not readable"; break;
953: case -1: m = iswild(filnam) ? "No files match" : "File not found";
954: break;
955: case 0: m = "No filespec given!" ; break;
956: default:
957: break;
958: }
959: debug(F101,"sinit nfils","",nfils);
960: debug(F110,"sinit filnam",filnam,0);
961: debug(F110,"sinit cmdstr",cmdstr,0);
962: if (x < 1) { /* Didn't get a file. */
963: if (server) /* Doing GET command */
964: errpkt((CHAR *)m); /* so send Error packet. */
965: else /* Doing SEND command */
966: screen(SCR_EM,0,0l,m); /* so print message. */
967: tlog(F110,xp,m,0L); /* Make transaction log entry. */
968: freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
969: return(0); /* Return failure code */
970: }
971: if (!local && !server) sleep(delay); /* Delay if requested */
972: #ifdef datageneral
973: if ((local) && (!quiet)) /* Only do this if local & not quiet */
974: consta_mt(); /* Start the asynch read task */
975: #endif /* datageneral */
976: freerbuf(rseqtbl[0]); /* Free the buffer the GET came in. */
977: sipkt('S'); /* Send the Send-Init packet. */
978: ztime(&tp); /* Get current date/time */
979: tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
980: debug(F111,"sinit ok",filnam,0);
981: return(1);
982: }
983:
984: int
985: #ifdef CK_ANSIC
986: sipkt(char c) /* Send S or I packet. */
987: #else
988: sipkt(c) char c;
989: #endif
990: /* sipkt */ {
991: CHAR *rp; int k;
992: debug(F101,"sipkt pktnum","",pktnum);
993: k = sseqtbl[pktnum]; /* Find slot for this packet */
994: debug(F101,"sipkt k","",k);
995: if (k < 0) { /* No slot? */
996: k = getsbuf(winlo = pktnum); /* Make one. */
997: debug(F101,"sipkt getsbuf","",k);
998: }
999: ttflui(); /* Flush pending input. */
1000: rp = rpar(); /* Get parameters. */
1001: return(spack(c,pktnum,(int)strlen((char *)rp),rp)); /* Send them. */
1002: }
1003:
1004: /* X S I N I T -- Retransmit S-packet */
1005: /*
1006: For use in the GET-SEND sequence, when we start to send, but receive another
1007: copy of the GET command because the receiver didn't get our S packet.
1008: This retransmits the S packet and frees the receive buffer for the ACK.
1009: The only reason this special case is necessary is that packet number zero
1010: is being re-used.
1011: */
1012: VOID
1013: xsinit() {
1014: int k;
1015: k = rseqtbl[0];
1016: debug(F101,"xsinit k","",k);
1017: if (k > -1)
1018: freerbuf(k);
1019: resend(0);
1020: }
1021:
1022: /* R C V F I L -- Receive a file */
1023:
1024: /*
1025: Incoming filename is in data field of F packet.
1026: This function decodes it into the srvcmd buffer, substituting an
1027: alternate "as-name", if one was given.
1028: Then it does any requested transformations (like converting to
1029: lowercase), and finally if a file of the same name already exists,
1030: takes the desired collision action.
1031: */
1032: #define XNAMLEN 256
1033: int
1034: rcvfil(n) char *n; {
1035: char xname[XNAMLEN], *xp; /* Buffer for constructing name */
1036: #ifdef DTILDE
1037: char *dirp, *tilde_expand();
1038: #endif /* DTILDE */
1039:
1040: lsstate = 0; /* Cancel locking-shift state */
1041: srvptr = srvcmd; /* Decode file name from packet. */
1042: decode(rdatap,putsrv,0); /* Don't xlate charsets. */
1043: if (*srvcmd == '\0') /* Watch out for null F packet. */
1044: strcpy((char *)srvcmd,"NONAME");
1045: #ifdef DTILDE
1046: dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
1047: if (*dirp != '\0') strcpy((char *)srvcmd,dirp);
1048: #endif /* DTILDE */
1049: screen(SCR_FN,0,0l,(char *)srvcmd); /* Put it on screen if local */
1050: debug(F110,"rcvfil",(char *)srvcmd,0); /* Debug log entry */
1051: tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
1052: if (cmarg2 != NULL) { /* Check for alternate name */
1053: if (*cmarg2 != '\0') {
1054: strcpy((char *)srvcmd,cmarg2); /* Got one, use it. */
1055: }
1056: }
1057: /*
1058: NOTE: Much of this code should be moved to opena(), where the file is
1059: actually opened, AFTER we have received the Attribute packet(s). That
1060: way, if the file is mail, or is being sent to the printer, we don't have
1061: to fuss with collision options, etc, but instead we just pipe the data
1062: straight into lpr or mail (in UNIX anyway), and then we can also have
1063: nice subject lines for mail messages by using whatever is in the file
1064: header packet data field, whether it's a legal filename or not.
1065: */
1066: if ((int)strlen((char *)srvcmd) > XNAMLEN) /* Watch out for overflow */
1067: *(srvcmd + XNAMLEN - 1) = NUL;
1068:
1069: xp = xname; /* OK to proceed. */
1070: if (fncnv && !*cmarg2)
1071: zrtol((char *)srvcmd,xp); /* convert name to local form */
1072: else{ /* otherwise, */
1073: strcpy(xname,(char *)srvcmd); /* use it literally */
1074: if (cmarg2)
1075: *cmarg2 = '\0';
1076: }
1077: debug(F110,"rcvfil as",xname,0);
1078:
1079: #ifdef COMMENT /* Old code... */
1080: if (warn) { /* File collision avoidance? */
1081: if (zchki(xname) != -1) { /* Yes, file exists? */
1082: znewn(xname,&xp); /* Yes, make new name. */
1083: strcpy(xname,xp);
1084: debug(F110," exists, new name ",xname,0);
1085: }
1086: }
1087: #endif /* COMMENT */
1088:
1089: /* Filename collision action section. */
1090:
1091: if (zchki(xname) != -1) { /* File of same name exists? */
1092: debug(F111,"rcvfil exists",xname,fncact);
1093: switch (fncact) { /* Yes, do what user said. */
1094: case XYFX_A: /* Append */
1095: debug(F100,"rcvfil append","",0);
1096: break;
1097: case XYFX_Q: /* Query (Ask) */
1098: break; /* not yet implemented */
1099: case XYFX_B: /* Backup (rename old file) */
1100: znewn(xname,&xp); /* Get new unique name */
1101: debug(F110,"rcvfil backup",xname,0);
1102: debug(F110,"rcvfil backup",xp,0);
1103: if (zrename(xname,xp) < 0) {
1104: debug(F110,"rcvfil rename fails",xname,0);
1105: return(0);
1106: }
1107: break;
1108: case XYFX_D: /* Discard (refuse new file) */
1109: discard = 1;
1110: debug(F101,"rcvfil discard","",discard);
1111: break; /* not yet implemented */
1112: case XYFX_R: /* Rename new file */
1113: znewn(xname,&xp); /* Make new name. */
1114: strcpy(xname,xp);
1115: debug(F110,"rcvfil rename",xname,0);
1116: case XYFX_X: /* Replace old file */
1117: debug(F100,"rcvfil overwrite","",0);
1118: break;
1119: case XYFX_U: /* Refuse if older */
1120: debug(F100,"rcvfil update","",0);
1121: break; /* Not here, we don't have */
1122: /* the attribute packet yet. */
1123: default:
1124: debug(F101,"rcvfil bad collision action","",fncact);
1125: break;
1126: }
1127: }
1128: debug(F110,"rcvfil: xname",xname,0);
1129: strcpy(n,xname); /* Return pointer to actual name. */
1130: #ifndef NOICP
1131: #ifndef MAC
1132: strcpy(fspec,xname); /* Here too for \v(filespec) */
1133: #endif /* MAC */
1134: #endif /* NOICP */
1135: debug(F110,"rcvfil: n",n,0);
1136: ffc = 0L; /* Init per-file counters */
1137: filcnt++;
1138: return(1); /* Always succeeds */
1139: }
1140:
1141:
1142: /* R E O F -- Receive End Of File */
1143:
1144: /*
1145: Closes the received file.
1146: Returns:
1147: 0 on success.
1148: -1 if file could not be closed.
1149: 2 if disposition was mail, mail was sent, but temp file not deleted.
1150: 3 if disposition was print, file was printed, but not deleted.
1151: -2 if disposition was mail and mail could not be sent
1152: -3 if disposition was print file could not be printed
1153: */
1154: int
1155: reof(f,yy) char *f; struct zattr *yy; {
1156: int x;
1157: char *p;
1158: char c;
1159:
1160: debug(F111,"reof fncact",f,fncact);
1161: debug(F101,"reof discard","",discard);
1162: lsstate = 0; /* Cancel locking-shift state */
1163: if ((fncact == XYFX_D || fncact == XYFX_U)
1164: && discard != 0) { /* SET FILE COLLISION DISCARD or UPDATE */
1165: debug(F101,"reof discarding","",0);
1166: discard = 0; /* We never opened it, */
1167: return(0); /* so we won't close it. */
1168: }
1169: if (cxseen == 0) cxseen = (*rdatap == 'D'); /* Got discard directive? */
1170: x = (cxseen || czseen) && (keep == 0);
1171: debug(F101,"reof x","",x);
1172: x = clsof((cxseen || czseen) && (keep == 0));
1173: if (atcapu) zstime(f,yy,0); /* Set file creation date */
1174: if (cxseen || czseen) {
1175: cxseen = 0;
1176: if (keep) {
1177: tlog(F100," *** Incomplete","",0L);
1178: fstats();
1179: } else {
1180: tlog(F100," *** Discarding","",0L);
1181: }
1182: } else {
1183: fstats();
1184:
1185: /* Handle dispositions from attribute packet... */
1186:
1187: #ifndef NOFRILLS
1188: if (yy->disp.len != 0) {
1189: p = yy->disp.val;
1190: c = *p++;
1191: if (c == 'M') { /* Mail to user. */
1192: x = zmail(p,filnam); /* Do the system's mail command */
1193: tlog(F110,"mailed",filnam,0L);
1194: tlog(F110," to",p,0L);
1195: zdelet(filnam); /* Delete the file */
1196: } else if (c == 'P') { /* Print the file. */
1197: x = zprint(p,filnam); /* Do the system's print command */
1198: tlog(F110,"printed",filnam,0L);
1199: tlog(F110," with options",p,0L);
1200: #ifndef vms
1201: if (zdelet(filnam) && x == 0) x = 3; /* Delete the file */
1202: #endif /* vms */
1203: }
1204: }
1205: #endif /* NOFRILLS */
1206: }
1207: debug(F101,"reof returns","",x);
1208: *filnam = '\0';
1209: return(x);
1210: }
1211:
1212: /* R E O T -- Receive End Of Transaction */
1213:
1214: VOID
1215: reot() {
1216: cxseen = czseen = discard = 0; /* Reset interruption flags */
1217: tstats();
1218: }
1219:
1220: /* S F I L E -- Send File header or teXt header packet */
1221:
1222: /* Call with x nonzero for X packet, zero for F packet */
1223: /* Returns 1 on success, 0 on failure */
1224:
1225: int
1226: sfile(x) int x; {
1227: char pktnam[257]; /* Local copy of name */
1228: char *s;
1229:
1230: lsstate = 0; /* Cancel locking-shift state */
1231: if (nxtpkt() < 0) return(0); /* Bump packet number, get buffer */
1232: if (x == 0) { /* F-Packet setup */
1233:
1234: if (*cmarg2 != '\0') { /* If we have a send-as name, */
1235: strncpy(pktnam,cmarg2,256); /* copy it literally, */
1236: cmarg2 = ""; /* and blank it out for next time. */
1237: } else { /* Otherwise use actual file name: */
1238: if (fncnv) { /* If converting names, */
1239: zltor(filnam,pktnam); /* convert it to common form, */
1240: } else { /* otherwise, */
1241: strncpy(pktnam,filnam,256); /* copy it literally. */
1242: }
1243: }
1244: debug(F110,"sfile",filnam,0); /* Log debugging info */
1245: debug(F110," pktnam",pktnam,0);
1246: if (openi(filnam) == 0) /* Try to open the file */
1247: return(0);
1248: s = pktnam; /* Name for packet data field */
1249:
1250: } else { /* X-packet setup */
1251:
1252: debug(F110,"sxpack",cmdstr,0); /* Log debugging info */
1253: s = cmdstr; /* Name for data field */
1254: }
1255:
1256: encstr((CHAR *)s); /* Encode the name into encbuf[]. */
1257: /* Send the F or X packet */
1258: spack((char) (x ? 'X' : 'F'), pktnum, size, encbuf+7);
1259:
1260: if (x == 0) { /* Display for F packet */
1261: if (displa) { /* Screen */
1262: screen(SCR_FN,'F',(long)pktnum,filnam);
1263: screen(SCR_AN,0,0l,pktnam);
1264: screen(SCR_FS,0,fsize,"");
1265: }
1266: tlog(F110,"Sending",filnam,0L); /* Transaction log entry */
1267: tlog(F110," as",pktnam,0L);
1268: if (binary) { /* Log file mode in transaction log */
1269: tlog(F101," mode: binary","",(long) binary);
1270: } else { /* If text mode, check character set */
1271: tlog(F100," mode: text","",0L);
1272: #ifndef NOCSETS
1273: tlog(F110," file character set",fcsinfo[fcharset].name,0L);
1274: if (tcharset == TC_TRANSP)
1275: tlog(F110," xfer character set","transparent",0L);
1276: else
1277: tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
1278: #endif /* NOCSETS */
1279: }
1280: } else { /* Display for X-packet */
1281:
1282: screen(SCR_XD,'X',(long)pktnum,cmdstr); /* Screen */
1283: tlog(F110,"Sending from:",cmdstr,0L); /* Transaction log */
1284: }
1285: intmsg(++filcnt); /* Count file, give interrupt msg */
1286: first = 1; /* Init file character lookahead. */
1287: ffc = 0L; /* Init file character counter. */
1288: return(1);
1289: }
1290:
1291: /* S D A T A -- Send a data packet */
1292:
1293: /*
1294: Returns -1 if no data to send (end of file). If there is data, a data
1295: packet is sent, and sdata() returns 1.
1296:
1297: For window size greater than 1, keep sending data packets until window
1298: is full or characters start to appear from the other Kermit, whichever
1299: happens first.
1300:
1301: In the windowing case, when there is no more data left to send (or when
1302: sending has been interrupted), sdata() does nothing and returns 0 each time
1303: it is called until the current packet number catches up to the last data
1304: packet that was sent.
1305: */
1306:
1307: int
1308: sdata() {
1309: int i, x, len;
1310:
1311: debug(F101,"sdata entry, first","",first);
1312: debug(F101," drain","",drain);
1313:
1314: /* The "drain" flag is used with window size > 1. It means we have sent */
1315: /* our last data packet. If called and drain is not zero, then we return */
1316: /* 0 as if we had sent an empty data packet, until all data packets have */
1317: /* been ACK'd, then then we can finally return -1 indicating EOF, so that */
1318: /* the protocol can switch to seof state. This is a kludge, but at least */
1319: /* it's localized... */
1320:
1321: if (first == 1) drain = 0; /* Start of file, init drain flag. */
1322:
1323: if (drain) { /* If draining... */
1324: debug(F101,"sdata draining, winlo","",winlo);
1325: if (winlo == pktnum) /* If all data packets are ACK'd */
1326: return(-1); /* return EOF indication */
1327: else /* otherwise */
1328: return(0); /* pretend we sent a data packet. */
1329: }
1330: debug(F101,"sdata sbufnum","",sbufnum);
1331: for (i = sbufnum; i > 0; i--) {
1332: debug(F101,"sdata countdown","",i);
1333: x = nxtpkt(); /* Get next pkt number and buffer */
1334: debug(F101,"sdata packet","",pktnum);
1335: if (x < 0) return(0);
1336: /*** dumpsbuf(); */
1337: if (cxseen || czseen) { /* If interrupted, done. */
1338: if (wslots > 1) {
1339: drain = 1;
1340: debug(F101,"sdata cx/zseen, drain","",cxseen);
1341: return(0);
1342: } else {
1343: return(-1);
1344: }
1345: }
1346: if (spsiz > 94) /* Fill the packet's data buffer */
1347: len = getpkt(spsiz-bctu-6,1); /* long packet */
1348: else /* or */
1349: len = getpkt(spsiz-bctu-3,1); /* short packet */
1350: if (len == 0) { /* Done if no data. */
1351: if (pktnum == winlo) return(-1);
1352: drain = 1; /* But can't return -1 until all */
1353: debug(F101,"sdata eof, drain","",drain);
1354: return(0); /* ACKs are drained. */
1355: }
1356: spack('D',pktnum,len,data); /* Send the data packet. */
1357: x = ttchk(); /* Peek at input buffer. */
1358: debug(F101,"sdata ttchk","",x); /* ACKs waiting, maybe? */
1359: if (x) return(1); /* Yes, stop sending data packets */
1360: } /* and go try to read the ACKs. */
1361: return(1);
1362: }
1363:
1364:
1365: /* S E O F -- Send an End-Of-File packet */
1366:
1367: /* Call with a string pointer to character to put in the data field, */
1368: /* or else a null pointer or "" for no data. */
1369:
1370: /*
1371: There are two "send-eof" functions. seof() is used to send the normal eof
1372: packet at the end of a file's data (even if the file has no data), or when
1373: a file transfer is interrupted. sxeof() is used to send an EOF packet that
1374: occurs because of attribute refusal. The difference is purely a matter of
1375: buffer allocation and packet sequence number management. Both functions
1376: act as "front ends" to the common send-eof function, szeof().
1377: */
1378:
1379: /* Code common to both seof() and sxeof() */
1380:
1381: int
1382: szeof(s) CHAR *s; {
1383: lsstate = 0; /* Cancel locking-shift state */
1384: if ((s != NULL) && (*s != '\0')) {
1385: spack('Z',pktnum,1,s);
1386: tlog(F100," *** interrupted, sending discard request","",0L);
1387: } else {
1388: spack('Z',pktnum,0,(CHAR *)"");
1389: fstats();
1390: }
1391: return(0);
1392: }
1393:
1394: int
1395: seof(s) CHAR *s; {
1396:
1397: /*
1398: ckcpro.w, before calling seof(), sets window size back to 1 and then calls
1399: window(), which clears out the old buffers. This is OK because the final
1400: data packet for the file has been ACK'd. However, sdata() has already
1401: called nxtpkt(), which set the new value of pktnum which seof() will use.
1402: So all we need to do here is is allocate a new send-buffer.
1403: */
1404: if (getsbuf(pktnum) < 0) { /* Get a buffer for packet n */
1405: debug(F101,"seof can't get s-buffer","",pktnum);
1406: return(-1);
1407: }
1408: return(szeof(s));
1409: }
1410:
1411: /*
1412: Version of seof() to be called when sdata() has not been called before. The
1413: difference is that this version calls nxtpkt() to allocate a send-buffer and
1414: get the next packet number.
1415: */
1416: int
1417: sxeof(s) CHAR *s; {
1418: int x;
1419: x = nxtpkt(); /* Get next pkt number and buffer */
1420: if (x < 0)
1421: debug(F101,"sxeof nxtpkt fails","",pktnum);
1422: else
1423: debug(F101,"sxeof packet","",pktnum);
1424: return(szeof(s));
1425: }
1426:
1427: /* S E O T -- Send an End-Of-Transaction packet */
1428:
1429: int
1430: seot() {
1431: if (nxtpkt() < 0) return(-1); /* Bump packet number, get buffer */
1432: spack('B',pktnum,0,(CHAR *)""); /* Send the EOT packet */
1433: cxseen = czseen = discard = 0; /* Reset interruption flags */
1434: tstats(); /* Log timing info */
1435: return(0);
1436: }
1437:
1438: /* R P A R -- Fill the data array with my send-init parameters */
1439:
1440:
1441: CHAR dada[20]; /* Use this instead of data[]. */
1442: /* To avoid some kind of wierd */
1443: /* addressing foulup in spack()... */
1444: /* (which might be fixed now...) */
1445:
1446: CHAR *
1447: rpar() {
1448: int cps;
1449:
1450: /* The following bit is in case user's timeout is shorter than the amount */
1451: /* of time it would take to receive a packet of the negotiated size. */
1452:
1453: if (speed > 0L && !network) { /* First recompute timeout */
1454: cps = (int) (speed / 10L); /* Characters per second */
1455: if (cps * rtimo < spsiz) {
1456: rtimo = (spsiz / cps) + 2;
1457: debug(F101,"rpar new rtimo","",rtimo);
1458: }
1459: }
1460: if (rpsiz > MAXPACK) /* Biggest normal packet I want. */
1461: dada[0] = tochar(MAXPACK); /* If > 94, use 94, but specify */
1462: else /* extended packet length below... */
1463: dada[0] = tochar(rpsiz); /* else use what the user said. */
1464: dada[1] = tochar(rtimo); /* When I want to be timed out */
1465: dada[2] = tochar(mypadn); /* How much padding I need (none) */
1466: dada[3] = ctl(mypadc); /* Padding character I want */
1467: dada[4] = tochar(eol); /* End-Of-Line character I want */
1468: dada[5] = '#'; /* Control-Quote character I send */
1469: switch (rqf) { /* 8th-bit prefix */
1470: case -1:
1471: case 1: if (parity) ebq = sq = '&'; break;
1472: case 0:
1473: case 2: break;
1474: }
1475: debug(F000,"rpar 8bq sq","",sq);
1476: debug(F000,"rpar 8bq ebq","",ebq);
1477: if (lscapu == 2) /* LOCKING-SHIFT FORCED */
1478: dada[6] = 'N'; /* means no single-shift */
1479: else
1480: dada[6] = sq;
1481: dada[7] = bctr + '0'; /* Block check type */
1482: if (rptflg) /* Run length encoding */
1483: dada[8] = rptq; /* If receiving, agree. */
1484: else
1485: dada[8] = '~';
1486: /* CAPAS mask */
1487: dada[9] = tochar((lscapr ? lscapb : 0) | /* Locking shifts */
1488: (atcapr ? atcapb : 0) | /* Attribute packets */
1489: (lpcapr ? lpcapb : 0) | /* Long packets */
1490: (swcapr ? swcapb : 0)); /* Sliding windows */
1491: dada[10] = tochar(swcapr ? wslotr : 0); /* Window size */
1492: rpsiz = urpsiz - 1; /* Long packets ... */
1493: dada[11] = tochar(rpsiz / 95); /* Long packet size, big part */
1494: dada[12] = tochar(rpsiz % 95); /* Long packet size, little part */
1495: dada[13] = '\0'; /* Terminate the init string */
1496: #ifdef DEBUG
1497: if (deblog) {
1498: debug(F110,"rpar",dada,0);
1499: rdebu(dada,(int)strlen((char *)dada));
1500: }
1501: #endif /* DEBUG */
1502: return(dada); /* Return pointer to string. */
1503: }
1504:
1505: int
1506: spar(s) CHAR *s; { /* Set parameters */
1507: int x, y, lpsiz;
1508:
1509: debug(F110,"entering spar",s,0);
1510:
1511: s--; /* Line up with field numbers. */
1512:
1513: /* Limit on size of outbound packets */
1514: x = (rln >= 1) ? xunchar(s[1]) : 80;
1515: lpsiz = spsizr; /* Remember what they SET. */
1516: if (spsizf) { /* SET-command override? */
1517: if (x < spsizr) spsiz = x; /* Ignore LEN unless smaller */
1518: } else { /* otherwise */
1519: spsiz = (x < 10) ? 80 : x; /* believe them if reasonable */
1520: }
1521: spmax = spsiz; /* Remember maximum size */
1522:
1523: /* Timeout on inbound packets */
1524: if (!timef) { /* Only if not SET-cmd override */
1525: x = (rln >= 2) ? xunchar(s[2]) : 5;
1526: timint = pkttim = (x < 0) ? 5 : x;
1527: }
1528:
1529: /* Outbound Padding */
1530: npad = 0; padch = '\0';
1531: if (rln >= 3) {
1532: npad = xunchar(s[3]);
1533: if (rln >= 4) padch = ctl(s[4]); else padch = 0;
1534: }
1535: if (npad) {
1536: int i;
1537: for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
1538: }
1539:
1540: /* Outbound Packet Terminator */
1541: seol = (rln >= 5) ? xunchar(s[5]) : CR;
1542: if ((seol < 2) || (seol > 31)) seol = CR;
1543:
1544: /* Control prefix */
1545: x = (rln >= 6) ? s[6] : '#';
1546: myctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
1547:
1548: /* 8th-bit prefix */
1549: rq = (rln >= 7) ? s[7] : 0;
1550: if (rq == 'Y') rqf = 1;
1551: else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
1552: else rqf = 0;
1553: debug(F000,"spar 8bq rq","",rq);
1554: debug(F000,"spar 8bq sq","",sq);
1555: debug(F000,"spar 8bq ebq","",ebq);
1556: debug(F101,"spar 8bq rqf","",rqf);
1557: switch (rqf) {
1558: case 0: ebqflg = 0; break;
1559: case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
1560: case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
1561: }
1562: if (lscapu == 2) { /* No single-shifts if LOCKING-SHIFT FORCED */
1563: ebqflg = 0;
1564: ebq = 'N';
1565: }
1566:
1567: /* Block check */
1568: x = 1;
1569: if (rln >= 8) {
1570: x = s[8] - '0';
1571: if ((x < 1) || (x > 3)) x = 1;
1572: }
1573: bctr = x;
1574:
1575: /* Repeat prefix */
1576: if (rln >= 9) {
1577: rptq = s[9];
1578: rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
1579: } else rptflg = 0;
1580:
1581: /* Capabilities */
1582: atcapu = lpcapu = swcapu = 0; /* Assume none of these */
1583: if (lscapu != 2) lscapu = 0; /* Assume no LS unless forced. */
1584: y = 11; /* Position of next field, if any */
1585: if (rln >= 10) {
1586: x = xunchar(s[10]);
1587: debug(F101,"spar capas","",x);
1588: atcapu = (x & atcapb) && atcapr;
1589: lpcapu = (x & lpcapb) && lpcapr;
1590: swcapu = (x & swcapb) && swcapr;
1591: debug(F101,"spar lscapu","",lscapu);
1592: debug(F101,"spar lscapr","",lscapr);
1593: debug(F101,"spar ebqflg","",ebqflg);
1594: if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
1595: debug(F101,"spar swcapr","",swcapr);
1596: debug(F101,"spar swcapu","",swcapu);
1597: debug(F101,"spar lscapu","",lscapu);
1598: for (y = 10; (xunchar(s[y]) & 1) && (rln >= y); y++) ;
1599: debug(F101,"spar y","",y);
1600: }
1601:
1602: /* Long Packets */
1603: if (lpcapu) {
1604: if (rln > y+1) {
1605: x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
1606: if (spsizf) { /* If overriding negotiations */
1607: spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
1608: } else { /* otherwise */
1609: spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
1610: }
1611: if (spsiz < 10) spsiz = 80; /* Be defensive... */
1612: }
1613: }
1614: /* (PWP) save current send packet size for optimal packet size calcs */
1615: spmax = spsiz;
1616:
1617: /* Sliding Windows... */
1618:
1619: if (swcapr) { /* Only if requested... */
1620: if (rln > y) { /* See what other Kermit says */
1621: x = xunchar(s[y+1]);
1622: debug(F101,"spar window","",x);
1623: wslotn = x > MAXWS ? MAXWS : x;
1624: #ifdef COMMENT
1625: /*
1626: During testing of windows, this code required the user to SET WINDOW n
1627: on BOTH Kermits. Now that windows appear to be working pretty well, let's
1628: use whatever the other Kermit requests.
1629: */
1630: if (wslotn > wslotr) wslotn = wslotr;
1631: #endif /* COMMENT */
1632: if (wslotn > 1) swcapu = 1; /* We do windows... */
1633: } else {
1634: wslotn = 1; /* We don't do windows... */
1635: swcapu = 0;
1636: debug(F101,"spar no windows","",wslotn);
1637: }
1638: }
1639:
1640: /* Now recalculate packet length based on number of windows. */
1641: /* The nogotiated number of window slots will be allocated, */
1642: /* and the maximum packet length will be reduced if necessary, */
1643: /* so that a windowful of packets can fit in the big buffer. */
1644:
1645: if (wslotn > 1) { /* Shrink to fit... */
1646: x = adjpkl(spsiz,wslotn,bigsbsiz);
1647: if (x < spsiz) {
1648: spsiz = spmax = x;
1649: debug(F101,"spar sending, redefine spsiz","",spsiz);
1650: }
1651: }
1652:
1653: /* Record parameters in debug log */
1654: #ifdef DEBUG
1655: if (deblog) sdebu(rln);
1656: #endif /* DEBUG */
1657: numerrs = 0; /* Start counting errors here. */
1658: return(0);
1659: }
1660:
1661: /* G N F I L E -- Get name of next file to send */
1662: /*
1663: Expects global sndsrc to be:
1664: -1: next filename to be obtained by calling znext().
1665: 0: no next file name
1666: 1: (or greater) next filename to be obtained from **cmlist.
1667: Returns:
1668: 1, with name of next file in filnam.
1669: 0, no more files, with filnam set to empty string.
1670: -1, file not found
1671: -2, file is not readable
1672: -3, read access denied
1673: -4, cancelled
1674: -5, too many files match wildcard
1675: */
1676:
1677: int
1678: gnfile() {
1679: int x; long y;
1680: int retcode = 0;
1681:
1682: debug(F101,"gnfile sndsrc","",sndsrc);
1683: fsize = 0L; /* Initialize file size */
1684: if (sndsrc == 0) { /* It's not really a file */
1685: if (nfils > 0) { /* It's a pipe, or stdin */
1686: strcpy(filnam, *cmlist); /* Copy its "name" */
1687: nfils = 0; /* There is no next file */
1688: return(1); /* OK this time */
1689: } else return(0); /* but not next time */
1690: }
1691:
1692: /* If file group interruption (C-Z) occurred, fail. */
1693:
1694: if (czseen) {
1695: tlog(F100,"Transaction cancelled","",0L);
1696: debug(F100,"gnfile czseen","",0);
1697: return(-4);
1698: }
1699:
1700: /* Loop through file list till we find a readable, sendable file */
1701:
1702: y = -1L; /* Loop exit (file size) variable */
1703: while (y < 0L) { /* Keep trying till we get one... */
1704: if (sndsrc > 0) { /* File list in cmlist */
1705: debug(F101,"gnfile nfils","",nfils);
1706: if (nfils-- > 0) { /* Still some left? */
1707: strcpy(filnam,*cmlist++);
1708: debug(F111,"gnfile cmlist filnam",filnam,nfils);
1709: if (!clfils) { /* Expand only if not from cmdline */
1710: x = zxpand(filnam);
1711: debug(F101,"gnfile zxpand","",x);
1712: if (x == 1) {
1713: znext(filnam);
1714: goto gotnam;
1715: }
1716: if (x == 0) {
1717: retcode = -1; /* None match */
1718: continue;
1719: }
1720: if (x < 0) return(-5); /* Too many to expand */
1721: sndsrc = -1; /* Change send-source to znext() */
1722: }
1723: } else { /* We're out of files. */
1724: debug(F101,"gnfile done","",nfils);
1725: *filnam = '\0';
1726: return(retcode);
1727: }
1728: }
1729:
1730: /* Otherwise, step to next element of internal wildcard expansion list. */
1731:
1732: if (sndsrc < 0) {
1733: x = znext(filnam);
1734: debug(F111,"gnfile znext",filnam,x);
1735: if (x == 0) { /* If no more, */
1736: sndsrc = 1; /* go back to list */
1737: continue;
1738: }
1739: }
1740:
1741: /* Get here with a filename. */
1742:
1743: gotnam:
1744: if (sndsrc) {
1745: y = zchki(filnam); /* Check if file readable */
1746: retcode = (int) y; /* Possible return code */
1747: if (y == -1L) { /* If not found */
1748: debug(F110,"gnfile skipping:",filnam,0);
1749: tlog(F111,filnam,"not sent, reason",(long)y);
1750: screen(SCR_ST,ST_SKIP,0l,filnam);
1751: continue;
1752: } else if (y < 0) {
1753: continue;
1754: } else {
1755: fsize = y;
1756: return(1);
1757: }
1758: } else return(1); /* sndsrc is 0... */
1759: }
1760: *filnam = '\0'; /* Should never get here */
1761: return(0);
1762: }
1763:
1764:
1765: /* S N D H L P -- Routine to send builtin help */
1766:
1767: int
1768: sndhlp() {
1769: #ifndef NOSERVER
1770: nfils = 0; /* No files, no lists. */
1771: xflg = 1; /* Flag we must send X packet. */
1772: strcpy(cmdstr,"help text"); /* Data for X packet. */
1773: first = 1; /* Init getchx lookahead */
1774: memstr = 1; /* Just set the flag. */
1775: memptr = hlptxt; /* And the pointer. */
1776: if (binary) { /* If file mode is binary, */
1777: savmod = binary; /* remember to restore it later. */
1778: binary = 0; /* turn it back to text for this, */
1779: }
1780: return(sinit());
1781: #else
1782: return(0);
1783: #endif /* NOSERVER */
1784: }
1785:
1786: /* C W D -- Change current working directory */
1787:
1788: /*
1789: String passed has first byte as length of directory name, rest of string
1790: is name. Fails if can't connect, else ACKs (with name) and succeeds.
1791: */
1792:
1793: int
1794: cwd(vdir) char *vdir; {
1795: char *cdd, *zgtdir(), *dirp;
1796:
1797: vdir[xunchar(*vdir) + 1] = '\0'; /* Terminate string with a null */
1798: dirp = vdir+1;
1799: tlog(F110,"Directory requested: ",dirp,0L);
1800: if (zchdir(dirp)) { /* Try to change */
1801: cdd = zgtdir(); /* Get new working directory. */
1802: debug(F110,"cwd",cdd,0);
1803: encstr((CHAR *)cdd);
1804: ack1((CHAR *)(encbuf+7));
1805: tlog(F110,"Changed directory to",cdd,0L);
1806: return(1);
1807: } else {
1808: debug(F110,"cwd failed",dirp,0);
1809: tlog(F110,"Failed to change directory to",dirp,0L);
1810: return(0);
1811: }
1812: }
1813:
1814:
1815: /* S Y S C M D -- Do a system command */
1816:
1817: /* Command string is formed by concatenating the two arguments. */
1818:
1819: int
1820: syscmd(prefix,suffix) char *prefix, *suffix; {
1821: char *cp;
1822:
1823: if (prefix == NULL || *prefix == '\0') return(0);
1824:
1825: #ifdef datageneral
1826: /* A kludge for now -- the real change needs to be done elsewhere... */
1827: {
1828: extern char *WHOCMD;
1829: if ((strcmp(prefix,WHOCMD) == 0) && (*suffix == 0))
1830: strcpy(suffix,"[!pids]");
1831: }
1832: #endif /* datageneral */
1833: for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
1834: while (*cp++ = *suffix++) ; /* copy suffix */
1835:
1836: debug(F110,"syscmd",cmdstr,0);
1837: if (zxcmd(ZIFILE,cmdstr) > 0) {
1838: debug(F110,"syscmd zxcmd ok",cmdstr,0);
1839: nfils = sndsrc = 0; /* Flag that input is from stdin */
1840: xflg = hcflg = 1; /* And special flags for pipe */
1841: if (binary) { /* If file mode is binary, */
1842: savmod = binary; /* remember to restore it later. */
1843: binary = 0; /* turn it back to text for this, */
1844: }
1845: return (sinit()); /* Send S packet */
1846: } else {
1847: debug(F100,"syscmd zxcmd failed",cmdstr,0);
1848: return(0);
1849: }
1850: }
1851:
1852: /* R E M S E T -- Remote Set */
1853: /* Called by server to set variables as commanded in REMOTE SET packets. */
1854: /* Returns 1 on success, 0 on failure. */
1855:
1856: int
1857: remset(s) char *s; {
1858: int len, i, x, y;
1859: char *p;
1860:
1861: len = xunchar(*s++); /* Length of first field */
1862: p = s + len; /* Pointer to second length field */
1863: *p++ = '\0'; /* Zero out second length field */
1864: x = atoi(s); /* Value of first field */
1865: debug(F111,"remset",s,x);
1866: debug(F110,"remset",p,0);
1867: switch (x) { /* Do the right thing */
1868: case 132: /* Attributes (all, in) */
1869: atcapr = atoi(p);
1870: return(1);
1871: case 133: /* File length attributes */
1872: case 233: /* IN/OUT combined */
1873: case 148: /* Both kinds of lengths */
1874: case 248:
1875: atleni = atleno = atoi(p);
1876: return(1);
1877: case 134: /* File Type (text/binary) */
1878: case 234:
1879: attypi = attypo = atoi(p);
1880: return(1);
1881: case 135: /* File creation date */
1882: case 235:
1883: atdati = atdato = atoi(p);
1884: return(1);
1885: case 139: /* File Blocksize */
1886: case 239:
1887: atblki = atblko = atoi(p);
1888: return(1);
1889: case 141: /* Encoding / Character Set */
1890: case 241:
1891: atenci = atenco = atoi(p);
1892: return(1);
1893: case 142: /* Disposition */
1894: case 242:
1895: atdisi = atdiso = atoi(p);
1896: return(1);
1897: case 145: /* System ID */
1898: case 245:
1899: atsidi = atsido = atoi(p);
1900: return(1);
1901: case 147: /* System-Dependent Info */
1902: case 247:
1903: atsysi = atsyso = atoi(p);
1904: return(1);
1905: case 232: /* Attributes (all, out) */
1906: atcapr = atoi(p);
1907: return(1);
1908: case 300: /* File type (text, binary) */
1909: binary = atoi(p);
1910: return(1);
1911: case 301: /* File name conversion */
1912: fncnv = 1 - atoi(p); /* (oops) */
1913: return(1);
1914: case 302: /* File name collision */
1915: x = atoi(p);
1916: if (x == XYFX_R) warn = 1; /* Rename */
1917: if (x == XYFX_X) warn = 0; /* Replace */
1918: fncact = x;
1919: return(1);
1920: case 310: /* Incomplete File Disposition */
1921: keep = atoi(p); /* Keep, Discard */
1922: return(1);
1923: case 311: /* Blocksize */
1924: fblksiz = atoi(p);
1925: return(1);
1926: case 312: /* Record Length */
1927: frecl = atoi(p);
1928: return(1);
1929: case 313: /* Record format */
1930: frecfm = atoi(p);
1931: return(1);
1932: case 314: /* File organization */
1933: forg = atoi(p);
1934: return(1);
1935: case 315: /* File carriage control */
1936: fcctrl = atoi(p);
1937: return(1);
1938: case 400: /* Block check */
1939: y = atoi(p);
1940: if (y < 4 && y > 0) {
1941: bctr = y;
1942: return(1);
1943: } else return(0);
1944: case 401: /* Receive packet-length */
1945: urpsiz = atoi(p);
1946: if (urpsiz > MAXRP) urpsiz = MAXRP;
1947: urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
1948: return(1);
1949: case 402: /* Receive timeout */
1950: y = atoi(p);
1951: if (y > -1 && y < 95) {
1952: timef = 1;
1953: timint = pkttim = y;
1954: chktimo();
1955: return(1);
1956: } else return(0);
1957: case 403: /* Retry limit */
1958: y = atoi(p);
1959: if (y > -1 && y < 95) {
1960: maxtry = y;
1961: return(1);
1962: } else return(0);
1963: case 404: /* Server timeout */
1964: y = atoi(p);
1965: if (y < 0) return(0);
1966: srvtim = y;
1967: return(1);
1968:
1969: #ifndef NOCSETS
1970: case 405: /* Transfer character set */
1971: for (i = 0; i < ntcsets; i++) {
1972: if (!strcmp(tcsinfo[i].designator,p)) break;
1973: }
1974: debug(F101,"remset xfer charset lookup","",i);
1975: if (i == ntcsets) return(0);
1976: tcharset = tcsinfo[i].code; /* if known, use it */
1977: if (tcharset == TC_TRANSP)
1978: rx = NULL;
1979: else
1980: rx = xlr[tcharset][fcharset]; /* translation function */
1981: return(1);
1982: #endif /* NOCSETS */
1983:
1984: case 406: /* Window slots */
1985: y = atoi(p);
1986: if (y == 0) y = 1;
1987: if (y < 1 && y > 31) return(0);
1988: wslotr = y;
1989: swcapr = 1;
1990: urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
1991: return(1);
1992: default: /* Anything else... */
1993: return(0);
1994: }
1995: }
1996:
1997: /* Adjust packet length based on number of window slots and buffer size */
1998:
1999: int
2000: adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
2001: debug(F101,"adjpkl len","",pktlen);
2002: debug(F101,"adjpkl slots","",slots);
2003: debug(F101,"adjpkl bufsiz","",bufsiz);
2004: if (((pktlen + 6) * slots) > bufsiz)
2005: pktlen = (bufsiz / slots) - 6;
2006: debug(F101,"adjpkl new len","",pktlen);
2007: return(pktlen);
2008: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.