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