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