|
|
1.1 root 1: /* C K C F N 3 -- Packet buffer management for C-Kermit */
2:
3: /* (plus assorted functions tacked on at the end) */
4:
5: /*
6: Author: Frank da Cruz ([email protected], [email protected]),
7: Columbia University Center for Computing Activities.
8: First released January 1985.
9: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
10: York. Permission is granted to any individual or institution to use this
11: software as long as it is not sold for profit. This copyright notice must be
12: retained. This software may not be included in commercial products without
13: written permission of Columbia University.
14: */
15:
16: #include "ckcdeb.h"
17: #include "ckcasc.h"
18: #include "ckcker.h"
19: #include "ckcxla.h"
20:
21: extern int unkcs, wmax, wcur, discard, bctu, bctl, local, fdispla;
22: extern CHAR *data;
23: extern char filnam[];
24: #ifndef NOFRILLS
25: extern int rprintf, rmailf; /* REMOTE MAIL, PRINT */
26: extern char optbuf[]; /* Options buffer for mail, print */
27: #endif /* NOFRILLS */
28: extern int wslots;
29: extern int fblksiz, frecl, forg, frecfm, fncact, fcctrl, lf_opts;
30: #ifdef DYNAMIC
31: extern CHAR *srvcmd;
32: #else
33: extern CHAR srvcmd[];
34: #endif
35:
36: extern int binary, spsiz;
37: extern int pktnum, cxseen, czseen, bsave, bsavef, nfils, stdinf;
38: extern int memstr, stdouf, keep, sndsrc, hcflg;
39: extern int server, en_cwd;
40:
41: extern int
42: atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
43: attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
44:
45: #ifdef datageneral
46: extern int quiet;
47: #endif /* datageneral */
48:
49: extern long fsize, filcnt, ffc, tfc;
50:
51: #ifndef NOCSETS
52: extern int tcharset, fcharset;
53: extern int ntcsets;
54: extern struct csinfo tcsinfo[], fcsinfo[];
55:
56: /* Pointers to translation functions */
57: #ifdef CK_ANSIC
58: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
59: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
60: extern CHAR (*rx)(CHAR); /* Pointer to input character translation function */
61: extern CHAR (*sx)(CHAR); /* Pointer to output character translation function */
62: #else
63: extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(); /* Character set */
64: extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(); /* translation functions. */
65: extern CHAR (*rx)(); /* Pointer to input character translation function */
66: extern CHAR (*sx)(); /* Pointer to output character translation function */
67: #endif /* CK_ANSIC */
68: #endif /* NOCSETS */
69:
70: /* Variables global to Kermit that are defined in this module */
71:
72: int winlo; /* packet number at low window edge */
73:
74: int sbufnum; /* number of free buffers */
75: int dum001 = 1234; /* protection... */
76: int sbufuse[MAXWS]; /* buffer in-use flag */
77: int dum003 = 1111;
78: int rbufnum; /* number of free buffers */
79: int dum002 = 4321; /* more protection */
80: int rbufuse[MAXWS]; /* buffer in-use flag */
81: int sseqtbl[64]; /* sequence # to buffer # table */
82: int rseqtbl[64]; /* sequence # to buffer # table */
83: int sacktbl[64]; /* sequence # ack table */
84:
85: #ifdef DYNAMIC
86: struct pktinfo *s_pkt = NULL; /* array of pktinfo structures */
87: struct pktinfo *r_pkt = NULL; /* array of pktinfo structures */
88: #else
89: struct pktinfo s_pkt[MAXWS]; /* array of pktinfo structures */
90: struct pktinfo r_pkt[MAXWS]; /* array of pktinfo structures */
91: #endif /* DYNAMIC */
92:
93: #ifdef DEBUG
94: char xbuf[200]; /* For debug logging */
95: #endif /* DEBUG */
96:
97: #ifdef DYNAMIC
98: CHAR *bigsbuf = NULL, *bigrbuf = NULL;
99: #else
100: char bigsbt[8]; /* Protection (shouldn't need this). */
101: /* BUT DON'T REMOVE IT! */
102: CHAR bigsbuf[SBSIZ + 5]; /* Send-packet buffer area */
103: char bigrbt[8]; /* Safety padding */
104: CHAR bigrbuf[RBSIZ + 5]; /* Receive-packet area */
105: #endif
106: int bigsbsiz = SBSIZ; /* Sizes of big send & rcv buffers. */
107: int bigrbsiz = RBSIZ;
108:
109: /* FUNCTIONS */
110:
111: /* For sanity, use "i" for buffer slots, "n" for packet numbers. */
112:
113: /* I N I B U F S */
114:
115: /*
116: Allocates the big send and receive buffers.
117: Call with size for big send buffer (s) and receive buffer (r).
118: These sizes can be different.
119: Attempts to allocate buffers of the requested size, but if it can't,
120: it will allocate smaller ones.
121: Sets global variables bigsbsiz and bigrbsiz to the actual sizes,
122: and bigsbuf and bigrbuf pointing to the actual buffers.
123: Designed to be called more than once.
124: Returns 0 on success, -1 on failure.
125: */
126:
127: CHAR *bigbufp = NULL;
128:
129: int
130: inibufs(s,r) int s, r; {
131: #ifdef DYNAMIC
132: int size, x;
133: long z;
134:
135: if (s < 80 || r < 80) return(-1); /* Validate arguments. */
136:
137: if (!s_pkt) { /* Allocate packet info structures */
138: if (!(s_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
139: fatal("ini_pkts: no memory for s_pkt");
140: }
141: for (x = 0; x < MAXWS; x++)
142: s_pkt[x].pk_adr = NULL; /* Initialize addresses */
143:
144: if (!r_pkt) {
145: if (!(r_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
146: fatal("ini_pkts: no memory for s_pkt");
147: }
148: for (x = 0; x < MAXWS; x++)
149: r_pkt[x].pk_adr = NULL; /* Initialize addresses */
150:
151: if (!srvcmd) { /* Allocate srvcmd buffer */
152: srvcmd = (CHAR *) malloc(r + 100);
153: if (!srvcmd) return(-1);
154: }
155: if (bigbufp) { /* Free previous buffers, if any. */
156: free(bigbufp);
157: bigbufp = NULL;
158: }
159: size = s + r + 40; /* Combined requested size + padding */
160:
161: /* Try to get the space. If malloc fails, try to get a little less. */
162: /* (Obviously, this algorithm can be refined.) */
163:
164: while (!(bigbufp = (CHAR *) malloc(size))) {
165: size = (size * 3) / 2; /* Failed, cut size by 1/3. */
166: if (size < 200) /* Try again until too small. */
167: return(-1);
168: }
169: debug(F101,"inibufs size","",size); /* OK, we got some space. */
170:
171: /*
172: Now divide the allocated space between the send and receive buffers in the
173: requested proportion. The natural formula would be (s / (s + r)) * size
174: (for the send buffer), but that doesn't work with integer arithmetic and we
175: can't use floating point because some machines don't have it. This can be
176: rearranged as (s * size) / (s + r). But (s * size) can be VERY large, too
177: large for 32 bits. So let's do it this way. This arithmetic works for
178: buffer sizes up to about 5,000,000.
179: */
180: #define FACTOR 20L
181: z = ( (long) s * FACTOR ) / ( (long) s + (long) r );
182: x = ( z * ( (long) size / FACTOR ) );
183: if (x < 0) return(-1); /* Catch overflow */
184:
185: bigsbsiz = x - 5; /* Size of send buffer */
186: bigsbuf = bigbufp; /* Address of send buffer */
187: debug(F101,"inibufs bigsbsiz","",bigsbsiz);
188:
189: bigrbsiz = size - x - 5; /* Size of receive buffer */
190: bigrbuf = bigbufp + x; /* Addresss of receive buffer */
191: debug(F101,"inibufs bigrbsiz","",bigrbsiz);
192:
193: return(0); /* Success */
194: #else /* No dynamic allocation */
195: bigsbsiz = SBSIZ; /* Just use the symbols */
196: bigrbsiz = RBSIZ; /* ... */
197: return(0); /* Success. */
198: #endif /* DYNAMIC */
199: }
200:
201:
202: /* M A K E B U F -- Makes and clears a new buffers. */
203:
204: /* Call with: */
205: /* slots: number of buffer slots to make, 1 to 31 */
206: /* bufsiz: size of the big buffer */
207: /* buf: address of the big buffer */
208: /* xx: pointer to array of pktinfo structures for these buffers */
209:
210: /* Subdivides the big buffer into "slots" buffers. */
211:
212: /* Returns: */
213: /* -1 if too many or too few slots requested, */
214: /* -2 if slots would be too small. */
215: /* n (positive) on success = size of one buffer. */
216: /* with pktinfo structure initialized for this set of buffers. */
217:
218: int
219: makebuf(slots,bufsiz,buf,xx)
220: /* makebuf */ int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; {
221:
222: CHAR *a;
223: int i, size;
224:
225: debug(F101,"makebuf","",slots);
226: debug(F101,"makebuf bufsiz","",bufsiz);
227: debug(F101,"makebuf MAXWS","",MAXWS);
228:
229: if (slots > MAXWS || slots < 1) return(-1);
230: if (bufsiz < slots * 10 ) return(-2);
231:
232: size = bufsiz / slots; /* Divide up the big buffer. */
233: a = buf; /* Address of first piece. */
234:
235: for (i = 0; i < slots; i++) {
236: struct pktinfo *x = &xx[i];
237: x->bf_adr = a; /* Address of this buffer */
238: x->bf_len = size; /* Length of this buffer */
239: x->pk_len = 0; /* Length of data field */
240: x->pk_typ = ' '; /* packet type */
241: x->pk_seq = -1; /* packet sequence number */
242: x->pk_flg = 0; /* ack'd bit */
243: x->pk_rtr = 0; /* retransmissions */
244: *a = '\0'; /* Clear the buffer */
245: a += size; /* Position to next buffer slot */
246: }
247: return(size);
248: }
249:
250: /* M A K S B U F -- Makes the send-packet buffer */
251:
252: int
253: mksbuf(slots) int slots; {
254: int i, x;
255: sbufnum = 0;
256: if ((x = makebuf(slots,bigsbsiz,bigsbuf,s_pkt)) < 0) {
257: debug(F101,"mksbuf makebuf return","",x);
258: return(x);
259: }
260: debug(F101,"mksbuf makebuf return","",x);
261: for (i = 0; i < 64; i++) { /* Initialize sequence-number- */
262: sseqtbl[i] = -1; /* to-buffer-number table. */
263: sacktbl[i] = 0;
264: }
265: for (i = 0; i < MAXWS; i++)
266: sbufuse[i] = 0; /* Mark each buffer as free */
267: sbufnum = slots;
268: return(x);
269: }
270:
271: /* M A K R B U F -- Makes the receive-packet buffer */
272:
273: int
274: mkrbuf(slots) int slots; {
275: int i, x;
276: rbufnum = 0;
277: if ((x = makebuf(slots,bigrbsiz,bigrbuf,r_pkt)) < 0) {
278: debug(F101,"mkrbuf makebuf return","",x);
279: return(x);
280: }
281: debug(F101,"mkrbuf makebuf return","",x);
282: for (i = 0; i < 64; i++) { /* Initialize sequence-number- */
283: rseqtbl[i] = -1; /* to-buffer-number table. */
284: }
285: for (i = 0; i < MAXWS; i++)
286: rbufuse[i] = 0; /* Mark each buffer as free */
287: rbufnum = slots;
288: return(x);
289: }
290:
291: /* W I N D O W -- Resize the window to n */
292:
293: int
294: window(n) int n; {
295: debug(F101,"window","",n);
296: if (n < 1 || n > 31) return(-1);
297: if (mksbuf(n) < 0) return(-1);
298: if (mkrbuf(n) < 0) return(-1);
299: wslots = n;
300: #ifdef DEBUG
301: if (deblog) dumpsbuf();
302: if (deblog) dumprbuf();
303: #endif /* DEBUG */
304: return(0);
305: }
306:
307: /* G E T S B U F -- Allocate a send-buffer. */
308:
309: /* Call with packet sequence number to allocate buffer for. */
310: /* Returns: */
311: /* -4 if argument is invalid (negative, or greater than 63) */
312: /* -3 if buffers were thought to be available but really weren't (bug!) */
313: /* -2 if the number of free buffers is negative (bug!) */
314: /* -1 if no free buffers. */
315: /* 0 or positive, packet sequence number, with buffer allocated for it. */
316:
317: int
318: getsbuf(n) int n; { /* Allocate a send-buffer */
319: int i;
320: if (n < 0 || n > 63) {
321: debug(F101,"getsbuf bad arg","",n);
322: return(-4); /* Bad argument */
323: }
324: debug(F101,"getsbuf, packet","",n);
325: debug(F101,"getsbuf, sbufnum","",sbufnum);
326: if (sbufnum == 0) return(-1); /* No free buffers. */
327: if (sbufnum < 0) return(-2); /* Shouldn't happen. */
328: for (i = 0; i < wslots; i++) /* Find the first one not in use. */
329: if (sbufuse[i] == 0) { /* Got one? */
330: sbufuse[i] = 1; /* Mark it as in use. */
331: sbufnum--; /* One less free buffer. */
332: *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
333: s_pkt[i].pk_seq = n; /* Put in the sequence number */
334: sseqtbl[n] = i; /* Back pointer from sequence number */
335: sacktbl[n] = 0; /* ACK flag */
336: s_pkt[i].pk_len = 0; /* Data field length now zero. */
337: s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
338: s_pkt[i].pk_flg = 0; /* Zero the flags */
339: s_pkt[i].pk_rtr = 0; /* Zero the retransmission count */
340: data = s_pkt[i].bf_adr + 7; /* Set global "data" address. */
341: wcur = wslots - sbufnum; /* Current number of window slots */
342: if (i+1 > wmax) wmax = i+1; /* For statistics. */
343: return(n); /* Return its index. */
344: }
345: sbufnum = 0; /* Didn't find one. */
346: return(-3); /* Shouldn't happen! */
347: }
348:
349: int
350: getrbuf() { /* Allocate a receive buffer */
351: int i;
352: debug(F101,"getrbuf rbufnum","",rbufnum);
353: debug(F101,"getrbuf wslots","",wslots);
354: debug(F101,"getrbuf dum002","",dum002);
355: debug(F101,"getrbuf dum003","",dum003);
356: if (rbufnum == 0) return(-1); /* No free buffers. */
357: if (rbufnum < 0) return(-2); /* Shouldn't happen. */
358: for (i = 0; i < wslots; i++) /* Find the first one not in use. */
359: if (rbufuse[i] == 0) { /* Got one? */
360: rbufuse[i] = 1; /* Mark it as in use. */
361: *r_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
362: rbufnum--; /* One less free buffer. */
363: debug(F101,"getrbuf new rbufnum","",rbufnum);
364: #ifdef COMMENT
365: wcur = wslots - rbufnum; /* Current number of window slots */
366: #endif /* COMMENT */
367: if (i+1 > wmax) wmax = i+1; /* For statistics. */
368: return(i); /* Return its index. */
369: }
370: debug(F101,"getrbuf foulup","",i);
371: rbufnum = 0; /* Didn't find one. */
372: return(-3); /* Shouldn't happen! */
373: }
374:
375: /* F R E E S B U F -- Free send-buffer for given packet sequence number */
376:
377: /* Returns: */
378: /* 1 upon success */
379: /* -1 if specified buffer does not exist */
380:
381: int
382: freesbuf(n) int n; { /* Release send-buffer for packet n. */
383: int i;
384:
385: debug(F101,"freesbuf","",n);
386: if (n < 0 || n > 63) /* No such packet. */
387: return(-1);
388: i = sseqtbl[n]; /* Get the window slot number. */
389: if (i > -1 && i <= wslots) {
390: sseqtbl[n] = -1; /* If valid, remove from seqtbl */
391: sbufnum++; /* and count one more free buffer */
392: sbufuse[i] = 0; /* and mark it as free, */
393: } else {
394: debug(F101," sseqtbl[n]","",sseqtbl[n]);
395: return(-1);
396: }
397:
398: /* The following is done only so dumped buffers will look right. */
399:
400: if (1) {
401: *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
402: s_pkt[i].pk_seq = -1; /* Invalidate the sequence number */
403: s_pkt[i].pk_len = 0; /* Data field length now zero. */
404: s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
405: s_pkt[i].pk_flg = 0; /* And zero the flag */
406: s_pkt[i].pk_rtr = 0; /* And the retries field. */
407: }
408: return(1);
409: }
410:
411: int
412: freerbuf(i) int i; { /* Release receive-buffer slot "i". */
413: int n;
414:
415: /* NOTE !! Currently, this function frees the indicated buffer, but */
416: /* does NOT erase the data. The program counts on this. Will find a */
417: /* better way later.... */
418:
419: debug(F101,"freerbuf, slot","",i);
420: if (i < 0 || i >= wslots) { /* No such slot. */
421: debug(F101,"freerbuf no such slot","",i);
422: return(-1);
423: }
424: n = r_pkt[i].pk_seq; /* Get the packet sequence number */
425: debug(F101,"freerbuf, packet","",n);
426: if (n > -1 && n < 64) /* If valid, remove from seqtbl */
427: rseqtbl[n] = -1;
428: if (rbufuse[i] != 0) { /* If really allocated, */
429: rbufuse[i] = 0; /* mark it as free, */
430: rbufnum++; /* and count one more free buffer. */
431: debug(F101,"freerbuf, new rbufnum","",rbufnum);
432: }
433:
434: /* The following is done only so dumped buffers will look right. */
435:
436: if (1) {
437: /* *r_pkt[i].bf_adr = '\0'; */ /* Zero the buffer data field */
438: r_pkt[i].pk_seq = -1; /* And from packet list */
439: r_pkt[i].pk_len = 0; /* Data field length now zero. */
440: r_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
441: r_pkt[i].pk_flg = 0; /* And zero the flag */
442: r_pkt[i].pk_rtr = 0; /* And the retries field. */
443: }
444: return(1);
445: }
446:
447: /* This is like freerbuf, except it's called with a packet sequence number */
448: /* rather than a packet buffer index. */
449:
450: VOID
451: freerpkt(seq) int seq; {
452: int k;
453: debug(F101,"freerpkt seq","",seq);
454: k = rseqtbl[seq];
455: debug(F101,"freerpkt k","",k);
456: if (k > -1) {
457: k = freerbuf(k);
458: debug(F101,"freerpkt freerbuf","",k);
459: }
460: }
461:
462:
463: /* C H K W I N -- Check if packet n is in window. */
464:
465: /* Returns: */
466: /* 0 if it is in the current window, */
467: /* +1 if it would have been in previous window (e.g. if ack was lost), */
468: /* -1 if it is outside any window (protocol error), */
469: /* -2 if either of the argument packet numbers is out of range. */
470:
471: /* Call with packet number to check (n), lowest packet number in window */
472: /* (bottom), and number of slots in window (slots). */
473:
474: int
475: chkwin(n,bottom,slots) int n, bottom, slots; {
476: int top, prev;
477:
478: debug(F101,"chkwin packet","",n);
479: debug(F101,"chkwin winlo","",bottom);
480: debug(F101,"chkwin slots","",slots);
481:
482: /* First do the easy and common cases, where the windows are not split. */
483:
484: if (n < 0 || n > 63 || bottom < 0 || bottom > 63)
485: return(-2);
486:
487: if (n == bottom) return(0); /* In a perfect world... */
488:
489: top = bottom + slots; /* Calculate window top. */
490: if (top < 64 && n < top && n >= bottom)
491: return(0); /* In current window. */
492:
493: prev = bottom - slots; /* Bottom of previous window. */
494: if (prev > -1 && n < bottom && n > prev)
495: return(1); /* In previous. */
496:
497: /* Now consider the case where the current window is split. */
498:
499: if (top > 63) { /* Wraparound... */
500: top -= 64; /* Get modulo-64 sequence number */
501: if (n < top || n >= bottom) {
502: return(0); /* In current window. */
503: } else { /* Not in current window. */
504: if (n < bottom && n >= prev) /* Previous window can't be split. */
505: return(1); /* In previous window. */
506: else
507: return(-1); /* Not in previous window. */
508: }
509: }
510:
511: /* Now the case where current window not split, but previous window is. */
512:
513: if (prev < 0) { /* Is previous window split? */
514: prev += 64; /* Yes. */
515: if (n < bottom || n >= prev)
516: return(1); /* In previous window. */
517: } else { /* Previous window not split. */
518: if (n < bottom && n >= prev)
519: return(1); /* In previous window. */
520: }
521:
522: /* It's not in the current window, and not in the previous window... */
523:
524: return(-1); /* So it's not in any window. */
525: }
526:
527: int
528: dumpsbuf() { /* Dump send-buffers */
529: #ifdef DEBUG
530: int j, x; /* to debug log. */
531:
532: if (! deblog) return(0);
533: x = zsoutl(ZDFILE,"SEND BUFFERS:");
534: if (x < 0) {
535: deblog = 0;
536: return(0);
537: }
538: x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
539: if (x < 0) {
540: deblog = 0;
541: return(0);
542: }
543: for ( j = 0; j < wslots; j++ ) {
544: sprintf(xbuf,"%4d%6d%10d%5d%6d%4c%5d%5d%6d\n",
545: j,
546: sbufuse[j],
547: s_pkt[j].bf_adr,
548: s_pkt[j].bf_len,
549: s_pkt[j].pk_len,
550: s_pkt[j].pk_typ,
551: s_pkt[j].pk_seq,
552: s_pkt[j].pk_flg,
553: s_pkt[j].pk_rtr
554: );
555: if (zsout(ZDFILE,xbuf) < 0) {
556: deblog = 0;
557: return(0);
558: }
559: if (s_pkt[j].pk_adr) {
560: x = (int)strlen((char *) s_pkt[j].pk_adr);
561: if (x)
562: sprintf(xbuf,"[%.72s%s]\n",s_pkt[j].pk_adr, x > 72 ? "..." : "");
563: else
564: sprintf(xbuf,"[(empty string)]\n");
565: } else {
566: sprintf(xbuf,"[(null pointer)]\n");
567: }
568: if (zsout(ZDFILE,xbuf) < 0) {
569: deblog = 0;
570: return(0);
571: }
572: }
573: sprintf(xbuf,"free: %d, winlo: %d\n", sbufnum, winlo);
574: if (zsout(ZDFILE,xbuf) < 0) {
575: deblog = 0;
576: return(0);
577: }
578: return(0);
579: #endif /* DEBUG */
580: }
581: int
582: dumprbuf() { /* Dump receive-buffers */
583: #ifdef DEBUG
584: int j, x;
585: if (! deblog) return(0);
586: if (zsoutl(ZDFILE,"RECEIVE BUFFERS:") < 0) {
587: deblog = 0;
588: return(0);
589: }
590: x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
591: if (x < 0) {
592: deblog = 0;
593: return(0);
594: }
595: for ( j = 0; j < wslots; j++ ) {
596: sprintf(xbuf,"%4d%6d%10d%5d%6d%4c%5d%5d%6d\n",
597: j,
598: rbufuse[j],
599: r_pkt[j].bf_adr,
600: r_pkt[j].bf_len,
601: r_pkt[j].pk_len,
602: r_pkt[j].pk_typ,
603: r_pkt[j].pk_seq,
604: r_pkt[j].pk_flg,
605: r_pkt[j].pk_rtr
606: );
607: if (zsout(ZDFILE,xbuf) < 0) {
608: deblog = 0;
609: return(0);
610: }
611: x = (int)strlen((char *)r_pkt[j].bf_adr);
612: sprintf(xbuf,"[%.72s%s]\n",r_pkt[j].bf_adr, x > 72 ? "..." : "");
613: if (zsout(ZDFILE,xbuf) < 0) {
614: deblog = 0;
615: return(0);
616: }
617: }
618: sprintf(xbuf,"free: %d, winlo: %d\n", rbufnum, winlo);
619: if (zsout(ZDFILE,xbuf) < 0) {
620: deblog = 0;
621: return(0);
622: }
623: return(0);
624: #endif /* DEBUG */
625: }
626:
627: /*** Some misc functions also moved here from the other ckcfn*.c modules ***/
628: /*** to even out the module sizes. ***/
629:
630: /* Attribute Packets. */
631:
632: /*
633: Call with xp == 0 if we're sending a real file (F packet),
634: or xp != 0 for screen data (X packet).
635: Returns 0 on success, -1 on failure.
636: */
637: int
638: sattr(xp) int xp; { /* Send Attributes */
639: int i, j, aln;
640: char *tp;
641: struct zattr x;
642:
643: if (zsattr(&x) < 0) return(-1); /* Get attributes or die trying */
644: if (nxtpkt() < 0) return(-1); /* Next packet number */
645: i = 0; /* i = Data field character number */
646: if (atsido) { /* System type */
647: data[i++] = '.';
648: data[i++] = tochar(x.systemid.len); /* Copy from attr structure */
649: for (j = 0; j < x.systemid.len; j++)
650: data[i++] = x.systemid.val[j];
651: }
652: if (attypo) { /* File type */
653: data[i++] = '"';
654: if (
655: #ifdef VMS
656: binary == XYFT_I || binary == XYFT_L || /* IMAGE or LABELED */
657: !strncmp(x.recfm.val,"F",1) /* or RECFM=Fxxxxxx */
658: #else
659: binary /* User said SET FILE TYPE BINARY */
660: #endif /* VMS */
661: ) { /* Binary */
662: data[i++] = tochar(2); /* Two characters */
663: data[i++] = 'B'; /* B for Binary */
664: data[i++] = '8'; /* 8-bit bytes (note assumption...) */
665: #ifdef VMS
666: if (binary != XYFT_I && binary != XYFT_L) binary = XYFT_B;
667: #endif /* VMS */
668: } else { /* Text */
669: data[i++] = tochar(3); /* Three characters */
670: data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */
671: data[i++] = 'M'; /* M for carriage return */
672: data[i++] = 'J'; /* J for linefeed */
673: #ifdef VMS
674: binary = XYFT_T; /* We automatically detected text */
675: #endif /* VMS */
676:
677: #ifdef NOCSETS
678: data[i++] = '*'; /* Encoding */
679: data[i++] = tochar(1); /* Length of value is 1 */
680: data[i++] = 'A'; /* A for ASCII */
681: #else
682: if (tcharset == TC_TRANSP) /* Transfer character set */
683: tp = NULL;
684: else
685: tp = tcsinfo[tcharset].designator;
686: if ((tp != NULL) && (aln = (int)strlen(tp)) > 0) {
687: data[i++] = '*'; /* Encoding */
688: data[i++] = tochar(aln+1); /* Length of charset designator. */
689: data[i++] = 'C'; /* Text in specified character set. */
690: for (j = 0; j < aln; j++) /* Designator from tcsinfo struct */
691: data[i++] = *tp++; /* Example: *&I6/100 */
692: }
693: #endif /* NOCSETS */
694: }
695: }
696: if ((xp == 0) && (x.length > -1L)) { /* If it's a real file */
697:
698: if (atdato && (aln = x.date.len) > 0) { /* Creation date, if any */
699: data[i++] = '#';
700: data[i++] = tochar(aln);
701: for (j = 0; j < aln; j++)
702: data[i++] = x.date.val[j];
703: }
704: if (atleno) {
705: data[i] = '!'; /* File length in K */
706: sprintf((char *) &data[i+2],"%ld",x.lengthk);
707: aln = (int)strlen((char *)(data+i+2));
708: data[i+1] = tochar(aln);
709: i += aln + 2;
710:
711: data[i] = '1'; /* File length in bytes */
712: sprintf((char *) &data[i+2],"%ld",x.length);
713: aln = (int)strlen((char *)(data+i+2));
714: data[i+1] = tochar(aln);
715: i += aln + 2;
716: }
717: if (atblko && fblksiz) { /* Blocksize, if set */
718: data[i] = '(';
719: sprintf((char *) &data[i+2],"%d",fblksiz);
720: aln = (int)strlen((char *)(data+i+2));
721: data[i+1] = tochar(aln);
722: i += aln + 2;
723: }
724: }
725: #ifndef NOFRILLS
726: if ((rprintf || rmailf) && atdiso) { /* MAIL, or REMOTE PRINT? */
727: data[i++] = '+'; /* Disposition */
728: data[i++] = tochar((int)strlen(optbuf) + 1); /* Options, if any */
729: if (rprintf)
730: data[i++] = 'P'; /* P for Print */
731: else
732: data[i++] = 'M'; /* M for Mail */
733: for (j = 0; optbuf[j]; j++) /* Copy any options */
734: data[i++] = optbuf[j];
735: }
736: #endif /* NOFRILLS */
737: data[i] = '\0'; /* Make sure it's null-terminated */
738: aln = (int)strlen((char *)data); /* Get overall length of attributes */
739:
740: /* Change this code to break attribute data up into multiple packets! */
741:
742: j = (spsiz < 95) ? (92 - bctl) : (spsiz - 2 - bctl);
743: if (aln > j) { /* Check length of result */
744: spack('A',pktnum,0,(CHAR *)""); /* send an empty attribute packet */
745: debug(F101,"sattr pkt too long","",aln); /* if too long */
746: debug(F101,"sattr spsiz","",spsiz);
747: } else { /* Otherwise */
748: spack('A',pktnum,aln,data); /* send the real thing. */
749: debug(F111,"sattr",data,aln);
750: }
751:
752: return(0);
753: }
754:
755: static char *refused = "";
756:
757: static char *reason[] = {
758: "size", "type", "date", "creator", "account", "area", "password",
759: "blocksize", "access", "encoding", "disposition", "protection",
760: "protection", "origin", "format", "sys-dependent", "size" };
761: static int nreason = sizeof(reason) / sizeof(char *);
762:
763: char *
764: getreason(s) char *s; { /* Decode attribute refusal reason */
765: char c, *p;
766: p = s;
767: if (*p++ != 'N') return(""); /* Should start with N */
768: if ((c = *p) > SP) { /* get reason, */
769: c -= '!'; /* get offset */
770: p = ((unsigned int) ((CHAR) c) <= nreason) ? reason[c] : "unknown";
771: }
772: return(p);
773: }
774:
775: int
776: rsattr(s) CHAR *s; { /* Read response to attribute packet */
777: debug(F111,"rsattr: ",s,*s);
778: if (*s == 'N') { /* If it's 'N' followed by anything, */
779: refused = getreason((char *)s); /* they are refusing, get reason. */
780: debug(F110,"refused",refused,0);
781: tlog(F110,"refused",refused,0L);
782: return(-1);
783: } else refused = "";
784: return(0);
785: }
786:
787: int
788: gattr(s, yy) CHAR *s; struct zattr *yy; { /* Read incoming attribute packet */
789: char c;
790: int aln, i;
791: #define ABUFL 40 /* Temporary buffer for conversions */
792: char abuf[ABUFL];
793: #define FTBUFL 10 /* File type buffer */
794: static char ftbuf[FTBUFL];
795: #define DTBUFL 40 /* File creation date */
796: static char dtbuf[DTBUFL];
797: #define TSBUFL 10 /* Transfer syntax */
798: static char tsbuf[TSBUFL];
799: #define IDBUFL 10 /* System ID */
800: static char idbuf[IDBUFL];
801: #ifndef DYNAMIC
802: #define DSBUFL 100 /* Disposition */
803: static char dsbuf[DSBUFL];
804: #define SPBUFL 512 /* System-dependent parameters */
805: static char spbuf[SPBUFL];
806: #else
807: #define DSBUFL 100 /* Disposition */
808: static char *dsbuf = NULL;
809: #define SPBUFL 512 /* System-dependent parameters */
810: static char *spbuf = NULL;
811: #endif /* DYNAMIC */
812: #define RPBUFL 20 /* Attribute reply */
813: static char rpbuf[RPBUFL];
814:
815: char *rp; /* Pointer to reply buffer */
816: int retcode; /* Return code */
817:
818: /* fill in the attributes we have received */
819:
820: rp = rpbuf; /* Initialize reply buffer */
821: *rp++ = 'N'; /* for negative reply. */
822: retcode = 0; /* Initialize return code. */
823:
824: while (c = *s++) { /* Get attribute tag */
825: aln = xunchar(*s++); /* Length of attribute string */
826: switch (c) {
827: case '!': /* File length in K */
828: for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
829: abuf[i] = *s++;
830: abuf[i] = '\0'; /* Terminate with null */
831: if (i < aln) s += (aln - i); /* If field was too long for buffer */
832: yy->lengthk = atol(abuf); /* Convert to number */
833: break;
834:
835: case '"': /* file type */
836: for (i = 0; (i < aln) && (i < FTBUFL); i++)
837: ftbuf[i] = *s++; /* Copy it into a static string */
838: ftbuf[i] = '\0';
839: if (i < aln) s += (aln - i);
840: if (attypi) { /* TYPE attribute is enabled? */
841: yy->type.val = ftbuf; /* Pointer to string */
842: yy->type.len = i; /* Length of string */
843: debug(F101,"gattr file type",tsbuf,i);
844: if (
845: *ftbuf != 'A' && *ftbuf != 'B' /* Unknown type? */
846: #ifdef VMS
847: /* or (VMS) our FILE TYPE is LABELED and the incoming file is text... */
848: || binary == XYFT_L && *ftbuf == 'A'
849: #endif /* VMS */
850: ) {
851: discard = 1; /* Reject the file */
852: retcode = -1;
853: *rp++ = c;
854: break;
855: }
856: /*
857: The following code moved here from opena() so we set binary mode
858: as soon as requested by the attribute packet. That way when the first
859: data packet comes, the mode of transfer can be displayed correctly
860: before opena() is called.
861: */
862: if (bsavef) { /* If somehow file mode */
863: binary = bsave; /* was saved but not restored, */
864: bsavef = 0; /* restore it. */
865: debug(F101,"gattr restoring binary","",binary);
866: }
867: if (yy->type.val[0] == 'A') { /* Check received attributes. */
868: bsave = binary; /* ASCII. Save global file type */
869: bsavef = 1; /* ( restore it in clsof() ) */
870: binary = XYFT_T; /* Set current type to Text. */
871: debug(F100,"gattr attribute A = text","",binary); /* */
872: } else if (yy->type.val[0] == 'B') {
873: bsave = binary; /* Binary. Save global file type */
874: bsavef = 1;
875: #ifdef VMS
876: if (binary != XYFT_L && binary != XYFT_U) /* VMS cases */
877: #endif /* VMS */
878: binary = XYFT_B;
879: debug(F101,"gattr attribute B = binary","",binary);
880: }
881: }
882: break;
883:
884: case '#': /* File creation date */
885: for (i = 0; (i < aln) && (i < DTBUFL); i++)
886: dtbuf[i] = *s++; /* Copy it into a static string */
887: if (i < aln) s += (aln - i);
888: dtbuf[i] = '\0';
889: if (atdati) {
890: yy->date.val = dtbuf; /* Pointer to string */
891: yy->date.len = i; /* Length of string */
892: if (fncact == XYFX_U) { /* Receiving in update mode? */
893: if (zstime(filnam,yy,1) > 0) { /* Compare dates */
894: discard = 1; /* If incoming file is older, */
895: *rp++ = c; /* discard it, reason = date. */
896: retcode = -1; /* Rejection notice. */
897: }
898: }
899: }
900: break;
901:
902: case '(': /* File Block Size */
903: for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
904: abuf[i] = *s++;
905: abuf[i] = '\0'; /* Terminate with null */
906: if (i < aln) s += (aln - i);
907: if (atblki)
908: yy->blksize = atol(abuf); /* Convert to number */
909: break;
910:
911: case '*': /* Encoding (transfer syntax) */
912: for (i = 0; (i < aln) && (i < TSBUFL); i++)
913: tsbuf[i] = *s++; /* Copy it into a static string */
914: if (i < aln) s += (aln - i);
915: tsbuf[i] = '\0';
916: if (atenci) {
917: yy->encoding.val = tsbuf; /* Pointer to string */
918: yy->encoding.len = i; /* Length of string */
919: debug(F101,"gattr encoding",tsbuf,i);
920: switch (*tsbuf) {
921: #ifndef NOCSETS
922: case 'A': /* Normal (maybe extended) ASCII */
923: tcharset = TC_USASCII; /* Transparent chars untranslated */
924: break;
925: case 'C': /* Specified character set */
926: for (i = 0; i < ntcsets; i++) {
927: if (!strcmp(tcsinfo[i].designator,tsbuf+1)) break;
928: }
929: debug(F101,"gattr xfer charset lookup","",i);
930: if (i == ntcsets) { /* If unknown character set, */
931: debug(F110,"gattr: xfer charset unknown",tsbuf+1,0);
932: if (!unkcs) { /* and SET UNKNOWN DISCARD, */
933: retcode = -1; /* reject the file. */
934: *rp++ = c;
935: }
936: } else {
937: tcharset = tcsinfo[i].code; /* if known, use it */
938: rx = xlr[tcharset][fcharset]; /* xlation function */
939: }
940: debug(F101,"gattr tcharset","",tcharset);
941: break;
942: #endif /* NOCSETS */
943: default: /* Something else. */
944: debug(F110,"gattr unk encoding attribute",tsbuf,0);
945: if (!unkcs) { /* If SET UNK DISC */
946: retcode = -1; /* reject the file */
947: *rp++ = c;
948: }
949: break;
950: }
951: }
952: break;
953:
954: case '+': /* disposition */
955: #ifdef DYNAMIC
956: if (!dsbuf)
957: if ((dsbuf = malloc(DSBUFL+1)) == NULL)
958: fatal("gtattr: no memory for dsbuf");
959: #endif /* DYNAMIC */
960: for (i = 0; (i < aln) && (i < DSBUFL); i++)
961: dsbuf[i] = *s++; /* Copy it into a static string */
962: dsbuf[i] = '\0';
963: if (i < aln) s += (aln - i);
964: if (atdisi) {
965: yy->disp.val = dsbuf; /* Pointer to string */
966: yy->disp.len = i; /* Length of string */
967: if (
968: #ifndef datageneral /* MAIL supported only for */
969: #ifndef OS2 /* UNIX, VMS, and OS-9 */
970: #ifndef MAC
971: #ifndef GEMDOS
972: #ifndef AMIGA
973: *dsbuf != 'M' &&
974: #endif /* AMIGA */
975: #endif /* GEMDOS */
976: #endif /* MAC */
977: #endif /* OS/2 */
978: #endif /* datageneral */
979: *dsbuf != 'P') {
980: retcode = -1;
981: *rp++ = c;
982: }
983: }
984: break;
985:
986: case '.': /* Sender's system ID */
987: for (i = 0; (i < aln) && (i < IDBUFL); i++)
988: idbuf[i] = *s++; /* Copy it into a static string */
989: idbuf[i] = '\0';
990: if (i < aln) s += (aln - i);
991: if (atsidi) {
992: yy->systemid.val = idbuf; /* Pointer to string */
993: yy->systemid.len = i; /* Length of string */
994: }
995: break;
996:
997: case '0': /* System-dependent parameters */
998: #ifdef DYNAMIC
999: if (!spbuf && !(spbuf = malloc(SPBUFL)))
1000: fatal("gattr: no memory for spbuf");
1001: #endif /* DYNAMIC */
1002: for (i = 0; (i < aln) && (i < SPBUFL); i++)
1003: spbuf[i] = *s++; /* Copy it into a static string */
1004: spbuf[i] = '\0';
1005: if (i < aln) s += (aln - i);
1006: if (atsysi) {
1007: yy->sysparam.val = spbuf; /* Pointer to string */
1008: yy->sysparam.len = i; /* Length of string */
1009: }
1010: break;
1011:
1012: case '1': /* File length in bytes */
1013: for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1014: abuf[i] = *s++;
1015: abuf[i] = '\0'; /* Terminate with null */
1016: if (i < aln) s += (aln - i);
1017: yy->length = atol(abuf); /* Convert to number */
1018: debug(F111,"gattr length",abuf,(int) yy->length);
1019: break;
1020:
1021: default: /* Unknown attribute */
1022: s += aln; /* Just skip past it */
1023: break;
1024: }
1025: }
1026:
1027: /* Check file length now, because we also need to know the file type */
1028: /* in case zchkspa() differentiates text and binary (VMS version does) */
1029:
1030: if (atleni) { /* Length attribute enabled? */
1031: if (yy->length > -1L) { /* Length-in-bytes attribute rec'd? */
1032: if (!zchkspa(filnam,(yy->length))) { /* Check space */
1033: retcode = -1;
1034: *rp++ = '1';
1035: }
1036: } else if (yy->lengthk > -1L) { /* Length in K attribute rec'd? */
1037: if (!zchkspa(filnam,(yy->lengthk * 1024))) {
1038: retcode = -1; /* Check space */
1039: *rp++ = '!';
1040: }
1041: }
1042: }
1043: if (yy->length > -1L) { /* Get the file size */
1044: fsize = yy->length;
1045: } else if (yy->lengthk > -1L) {
1046: fsize = yy->lengthk * 1024L;
1047: } else fsize = -1L;
1048:
1049: #ifdef DEBUG
1050: if (deblog) {
1051: sprintf(abuf,"%ld",fsize);
1052: debug(F110,"gattr fsize",abuf,0);
1053: }
1054: #endif /* DEBUG */
1055: if (retcode == 0) rp = rpbuf; /* Null reply string if accepted */
1056: *rp = '\0'; /* End of reply string */
1057: yy->reply.val = rpbuf; /* Add it to attribute structure */
1058: yy->reply.len = (int)strlen(rpbuf);
1059: debug(F111,"gattr return",rpbuf,retcode);
1060: return(retcode);
1061: }
1062:
1063: /* I N I T A T T R -- Initialize file attribute structure */
1064:
1065: int
1066: initattr(yy) struct zattr *yy; {
1067: yy->lengthk = yy->length = -1L;
1068: yy->type.val = "";
1069: yy->type.len = 0;
1070: yy->date.val = "";
1071: yy->date.len = 0;
1072: yy->encoding.val = "";
1073: yy->encoding.len = 0;
1074: yy->disp.val = "";
1075: yy->disp.len = 0;
1076: yy->systemid.val = "";
1077: yy->systemid.len = 0;
1078: yy->sysparam.val = "";
1079: yy->sysparam.len = 0;
1080: yy->creator.val = "";
1081: yy->creator.len = 0;
1082: yy->account.val = "";
1083: yy->account.len = 0;
1084: yy->area.val = "";
1085: yy->area.len = 0;
1086: yy->passwd.val = "";
1087: yy->passwd.len = 0;
1088: yy->blksize = -1L;
1089: yy->access.val = "";
1090: yy->access.len = 0;
1091: yy->lprotect.val = "";
1092: yy->lprotect.len = 0;
1093: yy->gprotect.val = "";
1094: yy->gprotect.len = 0;
1095: yy->recfm.val = "";
1096: yy->recfm.len = 0;
1097: yy->reply.val = "";
1098: yy->reply.len = 0;
1099: return(0);
1100: }
1101:
1102: /* A D E B U -- Write attribute packet info to debug log */
1103:
1104: int
1105: adebu(f,zz) char *f; struct zattr *zz; {
1106: #ifdef DEBUG
1107: if (deblog == 0) return(0);
1108: debug(F110,"Attributes for incoming file ",f,0);
1109: debug(F101," length in K","",(int) zz->lengthk);
1110: debug(F111," file type",zz->type.val,zz->type.len);
1111: debug(F111," creation date",zz->date.val,zz->date.len);
1112: debug(F111," creator",zz->creator.val,zz->creator.len);
1113: debug(F111," account",zz->account.val,zz->account.len);
1114: debug(F111," area",zz->area.val,zz->area.len);
1115: debug(F111," password",zz->passwd.val,zz->passwd.len);
1116: debug(F101," blksize","",(int) zz->blksize);
1117: debug(F111," access",zz->access.val,zz->access.len);
1118: debug(F111," encoding",zz->encoding.val,zz->encoding.len);
1119: debug(F111," disposition",zz->disp.val,zz->disp.len);
1120: debug(F111," lprotection",zz->lprotect.val,zz->lprotect.len);
1121: debug(F111," gprotection",zz->gprotect.val,zz->gprotect.len);
1122: debug(F111," systemid",zz->systemid.val,zz->systemid.len);
1123: debug(F111," recfm",zz->recfm.val,zz->recfm.len);
1124: debug(F111," sysparam",zz->sysparam.val,zz->sysparam.len);
1125: debug(F101," length","",(int) zz->length);
1126: debug(F110," reply",zz->reply.val,0);
1127: #endif /* DEBUG */
1128: return(0);
1129: }
1130:
1131: /* O P E N A -- Open a file, with attributes. */
1132: /*
1133: This function tries to open a new file to put the arriving data in. The
1134: filename is the one in the srvcmd buffer. File collision actions are:
1135: OVERWRITE (the existing file is overwritten), RENAME (the new file is
1136: renamed), BACKUP (the existing file is renamed), DISCARD (the new file is
1137: refused), UPDATE (the incoming file replaces the existing file only if the
1138: incoming file has a newer creation date).
1139:
1140: Returns 0 on failure, nonzero on success.
1141: */
1142: int
1143: opena(f,zz) char *f; struct zattr *zz; {
1144: int x;
1145: static struct filinfo fcb; /* Must be static! */
1146:
1147: debug(F111,"opena discard",f,discard);
1148:
1149: adebu(f,zz); /* Write attributes to debug log */
1150:
1151: ffc = 0L; /* Init file character counter */
1152:
1153: #ifdef COMMENT
1154: /*
1155: This code moved to sattr().
1156: */
1157: if (bsavef) { /* If somehow file mode */
1158: binary = bsave; /* was saved but not restored, */
1159: bsavef = 0; /* restore it. */
1160: debug(F101,"opena restoring binary","",binary);
1161: }
1162: if (zz->type.val[0] == 'A') { /* Check received attributes */
1163: #ifdef VMS
1164: if (binary == XYFT_L) /* Refuse to receive a file in */
1165: return(0); /* labeled mode if sent as text. */
1166: #endif /* VMS */
1167: bsave = binary; /* ASCII. Save global file type */
1168: bsavef = 1; /* ( restore it in clsof() ) */
1169: binary = XYFT_T; /* Set current type to Text. */
1170: debug(F100,"opena attribute A = text","",binary);
1171: } else if (zz->type.val[0] == 'B') {
1172: bsave = binary; /* Binary. Save global file type */
1173: bsavef = 1;
1174: #ifdef VMS
1175: if (binary != XYFT_L && binary != XYFT_U) /* Special VMS cases */
1176: #endif /* VMS */
1177: binary = XYFT_B;
1178: debug(F101,"opena attribute B = binary","",binary);
1179: }
1180: #endif /* COMMENT */
1181:
1182: /* Set up file control structure */
1183:
1184: fcb.bs = fblksiz; /* Blocksize */
1185: #ifndef NOCSETS
1186: fcb.cs = fcharset; /* Character set */
1187: #else
1188: fcb.cs = 0; /* Character set */
1189: #endif /* NOCSETS */
1190: fcb.rl = frecl; /* Record Length */
1191: fcb.fmt = frecfm; /* Record Format */
1192: fcb.org = forg; /* Organization */
1193: fcb.cc = fcctrl; /* Carriage control */
1194: fcb.typ = binary; /* Type */
1195: fcb.dsp = (fncact == XYFX_A) ? XYFZ_A : XYFZ_N; /* Disposition */
1196: fcb.os_specific = '\0'; /* OS specific info */
1197: #ifdef VMS
1198: fcb.lblopts = lf_opts; /* VMS Labeled file options */
1199: #else
1200: fcb.lblopts = 0;
1201: #endif /* VMS */
1202:
1203: if (x = openo(f,zz,&fcb)) { /* Try to open the file. */
1204: tlog(F110," as",f,0L); /* OK, open, record name. */
1205: if (binary) { /* Log file mode in transaction log */
1206: tlog(F101," mode: binary","",(long) binary);
1207: } else { /* If text mode, check character set */
1208: tlog(F100," mode: text","",0L);
1209: #ifndef NOCSETS
1210: tlog(F110," file character set",fcsinfo[fcharset].name,0L);
1211: if (tcharset == TC_TRANSP)
1212: tlog(F110," xfer character set","transparent",0L);
1213: else
1214: tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
1215: #endif /* NOCSETS */
1216: debug(F111," opena charset",zz->encoding.val,zz->encoding.len);
1217: }
1218: if (fsize > -1L) screen(SCR_FS,0,fsize,"");
1219:
1220: #ifdef datageneral
1221: /* Need to turn on multi-tasking console interrupt task here, since multiple */
1222: /* files may be received. */
1223: if ((local) && (!quiet)) /* Only do this if local & not quiet */
1224: consta_mt(); /* Start the asynch read task */
1225: #endif /* datageneral */
1226:
1227: } else { /* Did not open file OK. */
1228: #ifdef ATTSV
1229: extern char *sys_errlist[];
1230: extern int errno;
1231: screen(SCR_EM,0,0l,sys_errlist[errno]);
1232: #else
1233: #ifdef BSD4
1234: extern char *sys_errlist[];
1235: extern int errno;
1236: screen(SCR_EM,0,0l,sys_errlist[errno]);
1237: #else
1238: screen(SCR_EM,0,0l,"Can't open output file");
1239: #endif /* BSD4 */
1240: #endif /* ATTSV */
1241:
1242: tlog(F110,"Failure to open",f,0L);
1243:
1244:
1245: }
1246: return(x); /* Pass on return code from openo */
1247: }
1248:
1249: /* C A N N E D -- Check if current file transfer cancelled */
1250:
1251: int
1252: canned(buf) CHAR *buf; {
1253: if (*buf == 'X') cxseen = 1;
1254: if (*buf == 'Z') czseen = 1;
1255: debug(F101,"canned: cxseen","",cxseen);
1256: debug(F101," czseen","",czseen);
1257: return((czseen || cxseen) ? 1 : 0);
1258: }
1259:
1260:
1261: /* O P E N I -- Open an existing file for input */
1262:
1263: int
1264: openi(name) char *name; {
1265: int x, filno;
1266: char *name2;
1267:
1268: if (memstr) return(1); /* Just return if file is memory. */
1269:
1270: debug(F110,"openi",name,0);
1271: debug(F101," sndsrc","",sndsrc);
1272:
1273: filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */
1274:
1275: debug(F101," file number","",filno);
1276:
1277: if (server && !en_cwd) { /* If running as server */
1278: zstrip(name,&name2); /* and CWD is disabled... */
1279: if ( /* check if pathname was included. */
1280: #ifdef VMS
1281: zchkpath(name)
1282: #else
1283: strcmp(name,name2)
1284: #endif /* VMS */
1285: ) {
1286: tlog(F110,name,"authorization failure",0L);
1287: debug(F110," openi authorization failure",name,0);
1288: return(0);
1289: } else name = name2;
1290: }
1291: if (zopeni(filno,name)) { /* Otherwise, try to open it. */
1292: debug(F110," ok",name,0);
1293: return(1);
1294: } else { /* If not found, */
1295: char xname[100]; /* convert the name */
1296: zrtol(name,xname); /* to local form and then */
1297: x = zopeni(filno,xname); /* try opening it again. */
1298: debug(F101," zopeni","",x);
1299: if (x) {
1300: debug(F110," ok",xname,0);
1301: return(1); /* It worked. */
1302: } else {
1303: #ifdef COMMENT
1304: screen(SCR_EM,0,0l,"Can't open file"); /* It didn't work. */
1305: #endif /* COMMENT */
1306: tlog(F110,xname,"could not be opened",0L);
1307: debug(F110," openi failed",xname,0);
1308: return(0);
1309: }
1310: }
1311: }
1312:
1313: /* O P E N O -- Open a new file for output. */
1314:
1315: int
1316: openo(name,zz,fcb) char *name; struct zattr *zz; struct filinfo *fcb; {
1317: char *name2;
1318:
1319: if (stdouf) /* Receiving to stdout? */
1320: return(zopeno(ZSTDIO,"",zz,NULL));
1321:
1322: debug(F110,"openo: name",name,0);
1323:
1324: if (cxseen || czseen || discard) { /* If interrupted, get out before */
1325: debug(F100," open cancelled","",0); /* destroying existing file. */
1326: return(1); /* Pretend to succeed. */
1327: }
1328: if (server && !en_cwd) { /* If running as server */
1329: zstrip(name,&name2); /* and CWD is disabled, */
1330: if (strcmp(name,name2)) { /* check if pathname was included. */
1331: tlog(F110,name,"authorization failure",0L);
1332: debug(F110," openo authorization failure",name,0);
1333: return(0);
1334: } else name = name2;
1335: }
1336:
1337: if (zopeno(ZOFILE,name,zz,fcb) == 0) { /* Try to open the file */
1338: debug(F110,"openo failed",name,0);
1339: tlog(F110,"Failure to open",name,0L);
1340: return(0);
1341: } else {
1342: debug(F110,"openo ok, name",name,0);
1343: return(1);
1344: }
1345: }
1346:
1347: /* O P E N T -- Open the terminal for output, in place of a file */
1348:
1349: int
1350: opent(zz) struct zattr *zz; {
1351: ffc = tfc = 0L;
1352: if (bsavef) { /* If somehow file mode */
1353: binary = bsave; /* was saved but not restored, */
1354: bsavef = 0; /* restore it. */
1355: debug(F101,"opena restoring binary","",binary);
1356: }
1357: bsave = binary;
1358: bsavef = 1;
1359: binary = XYFT_T;
1360: return(zopeno(ZCTERM,"",zz,NULL));
1361: }
1362:
1363: /* C L S I F -- Close the current input file. */
1364:
1365: int
1366: clsif() {
1367: int x = 0;
1368: #ifdef datageneral
1369: if ((local) && (!quiet)) /* Only do this if local & not quiet */
1370: if (nfils < 1) /* More files to send ... leave it on! */
1371: connoi_mt();
1372: #endif /* datageneral */
1373: if (memstr) { /* If input was memory string, */
1374: memstr = 0; /* indicate no more. */
1375: } else x = zclose(ZIFILE); /* else close input file. */
1376: if (cxseen || czseen) /* If interrupted */
1377: screen(SCR_ST,ST_INT,0l,""); /* say so */
1378: else if (discard) /* If I'm refusing */
1379: screen(SCR_ST,ST_REFU,0l,refused); /* say why */
1380: else { /* Otherwise */
1381: fstats(); /* update statistics */
1382: screen(SCR_ST,ST_OK,0l,""); /* and say transfer was OK */
1383: }
1384: hcflg = 0; /* Reset flags */
1385: *filnam = '\0'; /* and current file name */
1386: return(x);
1387: }
1388:
1389:
1390: /* C L S O F -- Close an output file. */
1391:
1392: /* Call with disp != 0 if file is to be discarded. */
1393: /* Returns -1 upon failure to close, 0 or greater on success. */
1394:
1395: int
1396: clsof(disp) int disp; {
1397: int x;
1398:
1399: debug(F101,"clsof disp","",disp);
1400: if (bsavef) { /* If we saved global file type */
1401: debug(F101,"clsof restoring binary","",binary);
1402: binary = bsave; /* restore it */
1403: bsavef = 0; /* only this once. */
1404: }
1405: #ifdef datageneral
1406: if ((local) && (!quiet)) /* Only do this if local & not quiet */
1407: connoi_mt();
1408: #endif /* datageneral */
1409: cxseen = 0; /* Reset per-file interruption flag */
1410: if ((x = zclose(ZOFILE)) < 0) { /* Try to close the file */
1411: tlog(F100,"Failure to close",filnam,0L);
1412: screen(SCR_ST,ST_ERR,0l,"");
1413: } else if (disp) { /* Interrupted or refused */
1414: if (keep == 0) { /* If not keep incomplete files */
1415: if (*filnam) zdelet(filnam); /* Delete it */
1416: debug(F100,"Discarded","",0);
1417: tlog(F100,"Discarded","",0L);
1418: screen(SCR_ST,ST_DISC,0l,"");
1419: } else { /* Keep incomplete copy */
1420: if (ffc) ffc++; /* This is off by one (why?) */
1421: fstats();
1422: debug(F100,"Incomplete","",0);
1423: tlog(F100,"Incomplete","",0L);
1424: screen(SCR_ST,ST_INC,0l,"");
1425: }
1426: } else { /* Nothing wrong, just keep it */
1427: debug(F100,"Closed","",0); /* and give comforting messages. */
1428: if (ffc) ffc++; /* Correct off-by-1 error */
1429: fstats();
1430: screen(SCR_ST,ST_OK,0l,"");
1431: }
1432: return(x); /* Send back zclose() return code. */
1433: }
1434:
1435: #ifdef SUNOS4S5
1436: tolower(c) char c; { return((c)-'A'+'a'); }
1437: toupper(c) char c; { return((c)-'a'+'A'); }
1438: #endif /* SUNOS4S5 */
1439:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.