1 /* C K C F N 3 -- Packet buffer management for C-Kermit */
3 /* (plus assorted functions tacked on at the end) */
6 Author: Frank da Cruz <fdc@columbia.edu>,
7 Columbia University Academic Information Systems, New York City.
9 Copyright (C) 1985, 2004,
10 Trustees of Columbia University in the City of New York.
11 All rights reserved. See the C-Kermit COPYING.TXT file or the
12 copyright text in the ckcmai.c module for disclaimer and permissions.
15 Note -- if you change this file, please amend the version number and date at
16 the top of ckcfns.c accordingly.
25 /* C K M K D I R -- Create a directory */
28 int fc = 0 to create, nonzero to remove, a directory.
29 char * s = pointer to name of directory to create or remove.
30 char ** r = address of pointer to return name or message.
31 int m = 1 to print error messages, 0 to be silent.
32 int cvt = 1 means convert s from standard format to local format;
35 0 on success (directory was created or removed).
36 -1 when attempt to create the directory failed.
37 -2 on internal error (e.g. no code for creating directories).
38 On success, the name is pointed to by p.
39 On failure, the reason is pointed to by p.
42 static char ckmkdbuf[CKMAXPATH+1];
45 static char ckmkdbuf[CKMAXPATH+1];
46 #endif /* datageneral */
51 ckmkdir(fc,s,r,m,cvt) int fc; char * s; char ** r; int m; int cvt; {
53 char tmpbuf[CKMAXPATH+1];
54 char buf2[CKMAXPATH+1];
56 debug(F110,"ckmkdir 1 fc",s,fc);
60 (fc == 0) ? "mkdir" : "rmdir",
69 /* Come back and make this nicer later if anybody notices */
70 if (fc == 0) { /* mkdir */
73 /* AOS/VS rmdir() is a no-op. */
74 ckmakmsg(tmpbuf,CKMAXPATH+1,"delete ",s,NULL,NULL);
75 debug(F110,"ckmkdir 2",tmpbuf,0);
79 #else /* not datageneral */
81 /* First make sure the name has an acceptable directory-name format */
86 int lb = 0, rb = 0, sl = 0;
88 if (*p == '[' || *p == '<') lb++; /* Count brackets */
89 else if (*p == ']' || *p == '>') rb++;
90 else if (*p == '/') sl++; /* and slashes */
93 if (lb != 1 && rb != 1 && sl == 0 && p > s && *(p-1) != ':') {
94 /* Probably just a word - convert to VMS format */
98 (*s == '.') ? "" : ".",
103 } else if (lb == 0 && rb == 0 && sl != 0 && p > s && *(p-1) != ':') {
105 /* Seems to be in UNIX format */
107 if (x > 0 && s[x-1] != '/')
109 ckmakmsg(buf2,CKMAXPATH+1,s,flag ? "/" : "",NULL,NULL);
113 ckstrncpy(tmpbuf,s,CKMAXPATH+1);
116 debug(F110,"ckmkdir 2+VMS",s,0);
123 ckstrncpy(tmpbuf,s,CKMAXPATH+1);
126 if (x > 0 && s[x-1] != '/') { /* Must end in "/" for zmkdir() */
129 debug(F110,"ckmkdir 2+UNIXOROSK",s,0);
131 #else /* UNIXOROSK */
133 ckstrncpy(tmpbuf,s,CKMAXPATH+1);
136 if (fc == 0 && x > 0 && s[x-1] != '/') { /* Must end in "/" for zmkdir() */
139 debug(F110,"ckmkdir 2+OS2",s,0);
142 #endif /* UNIXOROSK */
145 /* Server is calling us, so convert to local format if necessary */
147 nzrtol(s,(char *)buf2,1,PATH_ABS,CKMAXPATH);
149 debug(F110,"ckmkdir 3",s,0);
152 debug(F110,"ckmkdir 4",s,0);
153 if (fc == 0) { /* Making */
162 #endif /* CK_MKDIR */
163 } else { /* Removing */
178 #endif /* datageneral */
179 debug(F101,"ckmkdir rc","",rc);
184 (fc == 0) ? "creation" : "removal",
185 "not implemented in this version of C-Kermit",
189 if (m) printf("%s\n",*r);
192 ckmakmsg(ckmkdbuf,CKMAXPATH,s,": ",ck_errstr(),NULL);
194 } else if (fc == 0 && zfnqfp(s,CKMAXPATH,ckmkdbuf)) {
196 } else if (fc != 0) {
197 ckmakmsg(ckmkdbuf,CKMAXPATH,s,": removed",NULL,NULL);
202 #endif /* CK_MKDIR */
204 #ifndef NOXFER /* Rest of this file... */
214 extern char ** sndfilter;
215 #endif /* PIPESEND */
217 extern int unkcs, wmax, wcur, discard, bctu, bctl, local, fdispla, what,
218 sendmode, opnerr, dest, epktrcvd, epktsent, filestatus, eofmethod, dispos;
219 extern long sendstart, calibrate, fncnv, fnrpath;
222 extern char * rfspec, * sfspec, * prfspec, * psfspec, * rrfspec, * prrfspec;
225 extern char * ofperms;
233 extern int xflg, remfile, remappd;
235 extern char filnam[];
237 extern int rprintf, rmailf; /* REMOTE MAIL, PRINT */
238 char optbuf[OPTBUFLEN]; /* Options for MAIL or REMOTE PRINT */
239 #endif /* NOFRILLS */
241 extern int fblksiz, frecl, forg, frecfm, fncact, fncsav, fcctrl, lf_opts;
242 extern CHAR * srvcmd;
243 extern int srvcmdlen;
245 extern int binary, spsiz;
246 extern int pktnum, cxseen, czseen, nfils, stdinf;
247 extern int memstr, stdouf, keep, sndsrc, hcflg;
248 extern int server, en_cwd, en_mai, en_pri;
250 /* Attributes in/out enabled flags */
253 atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
254 attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
257 extern int atlpri, atlpro, atgpri, atgpro;
258 #endif /* CK_PERMS */
261 extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto;
266 #endif /* datageneral */
268 extern long fsize, filcnt, ffc, tfc;
271 _PROTOTYP (VOID setxlate, (void));
272 extern int tcharset, fcharset;
273 extern int ntcsets, xlatype, xfrxla;
274 extern struct csinfo tcsinfo[], fcsinfo[];
277 /* Variables global to Kermit that are defined in this module */
279 #ifdef CKXXCHAR /* DOUBLE / IGNORE char table */
283 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
284 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
285 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
286 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
287 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
288 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
289 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
290 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
292 #endif /* CKXXCHAR */
294 int winlo; /* packet number at low window edge */
296 int sbufnum; /* number of free buffers */
297 int dum001 = 1234; /* protection... */
298 int sbufuse[MAXWS]; /* buffer in-use flag */
300 int rbufnum; /* number of free buffers */
301 int dum002 = 4321; /* more protection */
302 int rbufuse[MAXWS]; /* buffer in-use flag */
303 int sseqtbl[64]; /* sequence # to buffer # table */
304 int rseqtbl[64]; /* sequence # to buffer # table */
305 int sacktbl[64]; /* sequence # ack table */
307 int o_isopen = 0, i_isopen = 0; /* Input & output files are open */
310 struct pktinfo *s_pkt = NULL; /* array of pktinfo structures */
311 struct pktinfo *r_pkt = NULL; /* array of pktinfo structures */
313 struct pktinfo s_pkt[MAXWS]; /* array of pktinfo structures */
314 struct pktinfo r_pkt[MAXWS]; /* array of pktinfo structures */
318 char xbuf[200]; /* For debug logging */
322 CHAR *bigsbuf = NULL, *bigrbuf = NULL;
324 char bigsbt[8]; /* Protection (shouldn't need this). */
325 /* BUT DON'T REMOVE IT! */
326 CHAR bigsbuf[SBSIZ + 5]; /* Send-packet buffer area */
327 char bigrbt[8]; /* Safety padding */
328 CHAR bigrbuf[RBSIZ + 5]; /* Receive-packet area */
330 int bigsbsiz = SBSIZ; /* Sizes of big send & rcv buffers. */
331 int bigrbsiz = RBSIZ;
334 int zchkpath(char *s);
341 long maxbufsiz = RBSIZ; /* Configuration parameters */
342 int maxpktsiz = MAXSP;
343 extern int spsizf, /* For bug in IRIX Telnet server */
344 rpsiz, urpsiz, spsizr, spmax, wslotr;
345 extern struct ck_p ptab[];
347 if (maxpktsiz < 40) /* Long packet length */
349 else if (maxpktsiz > 4000)
351 wslotr = maxbufsiz / maxpktsiz;
352 if (wslotr > MAXWS) /* Window slots */
358 urpsiz = adjpkl(maxpktsiz,wslotr,maxbufsiz);
359 ptab[PROTO_K].rpktlen = urpsiz;
360 rpsiz = (urpsiz > 94) ? 94 : urpsiz; /* Max non-long packet length */
361 debug(F111,"dofast","uprsiz",urpsiz);
364 /* IRIX Telnet server chops off writes longer than 4K */
365 spsiz = spmax = spsizr = urpsiz;
366 debug(F101,"doarg Q IRIX spsiz","",spsiz);
371 setprefix(PX_CAU); /* Cautious unprefixing */
372 #endif /* CK_SPEED */
376 /* For sanity, use "i" for buffer slots, "n" for packet numbers. */
381 Allocates the big send and receive buffers.
382 Call with size for big send buffer (s) and receive buffer (r).
383 These sizes can be different.
384 Attempts to allocate buffers of the requested size, but if it can't,
385 it will allocate smaller ones.
386 Sets global variables bigsbsiz and bigrbsiz to the actual sizes,
387 and bigsbuf and bigrbuf pointing to the actual buffers.
388 Designed to be called more than once.
389 Returns 0 on success, -1 on failure.
392 CHAR *bigbufp = NULL;
395 inibufs(s,r) int s, r; {
400 unsigned /* Don't you wish everybody had unsigned long... */
405 debug(F101,"inibufs s","",s);
406 debug(F101,"inibufs r","",r);
408 if (s < 80 || r < 80) return(-1); /* Validate arguments. */
410 if (!s_pkt) { /* Allocate packet info structures */
411 if (!(s_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
412 fatal("ini_pkts: no memory for s_pkt");
414 for (x = 0; x < MAXWS; x++)
415 s_pkt[x].pk_adr = NULL; /* Initialize addresses */
418 if (!(r_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
419 fatal("ini_pkts: no memory for s_pkt");
421 for (x = 0; x < MAXWS; x++)
422 r_pkt[x].pk_adr = NULL; /* Initialize addresses */
424 if (!srvcmd) { /* Allocate srvcmd buffer */
425 srvcmd = (CHAR *) malloc(r + 100);
426 if (!srvcmd) return(-1);
430 if (bigbufp) { /* Free previous buffers, if any. */
434 size = s + r + 40; /* Combined requested size + padding */
435 z = (unsigned) s + (unsigned) r + 40;
436 debug(F101,"inibufs size 1","",size);
437 debug(F101,"inibufs size z","",z);
438 if ((long) size != z) {
439 debug(F100,"inibufs overflow","",0);
443 /* Try to get the space. If malloc fails, try to get a little less. */
444 /* (Obviously, this algorithm can be refined.) */
446 while (!(bigbufp = (CHAR *) malloc(size))) {
447 debug(F101,"inibufs bigbuf malloc failed","",size);
448 size = (size * 2) / 3; /* Failed, cut size by 1/3. */
449 if (size < 200) /* Try again until too small. */
452 debug(F101,"inibufs size 2","",size); /* OK, we got some space. */
455 Now divide the allocated space between the send and receive buffers in the
456 requested proportion. The natural formula would be (s / (s + r)) * size
457 (for the send buffer), but that doesn't work with integer arithmetic and we
458 can't use floating point because some machines don't have it. This can be
459 rearranged as (s * size) / (s + r). But (s * size) can be VERY large, too
460 large for 32 bits. So let's do it this way. This arithmetic works for
461 buffer sizes up to about 5,000,000.
464 z = ( (long) s * FACTOR ) / ( (long) s + (long) r );
465 x = ( z * ( (long) size / FACTOR ) );
466 if (x < 0) return(-1); /* Catch overflow */
468 bigsbsiz = x - 5; /* Size of send buffer */
469 bigsbuf = bigbufp; /* Address of send buffer */
470 debug(F101,"inibufs bigsbsiz","",bigsbsiz);
472 bigrbsiz = size - x - 5; /* Size of receive buffer */
473 bigrbuf = bigbufp + x; /* Addresss of receive buffer */
474 debug(F101,"inibufs bigrbsiz","",bigrbsiz);
476 return(0); /* Success */
477 #else /* No dynamic allocation */
478 bigsbsiz = SBSIZ; /* Just use the symbols */
479 bigrbsiz = RBSIZ; /* ... */
480 return(0); /* Success. */
485 /* M A K E B U F -- Makes and clears a new buffers. */
488 /* slots: number of buffer slots to make, 1 to 32 */
489 /* bufsiz: size of the big buffer */
490 /* buf: address of the big buffer */
491 /* xx: pointer to array of pktinfo structures for these buffers */
493 /* Subdivides the big buffer into "slots" buffers. */
496 /* -1 if too many or too few slots requested, */
497 /* -2 if slots would be too small. */
498 /* n (positive) on success = size of one buffer. */
499 /* with pktinfo structure initialized for this set of buffers. */
502 makebuf(slots,bufsiz,buf,xx)
503 /* makebuf */ int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; {
508 debug(F101,"makebuf","",slots);
509 debug(F101,"makebuf bufsiz","",bufsiz);
510 debug(F101,"makebuf MAXWS","",MAXWS);
512 if (slots > MAXWS || slots < 1) return(-1);
513 if (bufsiz < slots * 10 ) return(-2);
515 size = bufsiz / slots; /* Divide up the big buffer. */
516 a = buf; /* Address of first piece. */
518 for (i = 0; i < slots; i++) {
519 struct pktinfo *x = &xx[i];
520 x->bf_adr = a; /* Address of this buffer */
521 x->bf_len = size; /* Length of this buffer */
522 x->pk_len = 0; /* Length of data field */
523 x->pk_typ = ' '; /* packet type */
524 x->pk_seq = -1; /* packet sequence number */
525 x->pk_rtr = 0; /* retransmissions */
526 *a = '\0'; /* Clear the buffer */
527 a += size; /* Position to next buffer slot */
532 /* M A K S B U F -- Makes the send-packet buffer */
535 mksbuf(slots) int slots; {
538 if ((x = makebuf(slots,bigsbsiz,bigsbuf,s_pkt)) < 0) {
539 debug(F101,"mksbuf makebuf return","",x);
542 debug(F101,"mksbuf makebuf return","",x);
543 for (i = 0; i < 64; i++) { /* Initialize sequence-number- */
544 sseqtbl[i] = -1; /* to-buffer-number table. */
547 for (i = 0; i < MAXWS; i++)
548 sbufuse[i] = 0; /* Mark each buffer as free */
554 /* M A K R B U F -- Makes the receive-packet buffer */
557 mkrbuf(slots) int slots; {
560 if ((x = makebuf(slots,bigrbsiz,bigrbuf,r_pkt)) < 0) {
561 debug(F101,"mkrbuf makebuf return","",x);
564 debug(F101,"mkrbuf makebuf return","",x);
565 for (i = 0; i < 64; i++) { /* Initialize sequence-number- */
566 rseqtbl[i] = -1; /* to-buffer-number table. */
568 for (i = 0; i < MAXWS; i++)
569 rbufuse[i] = 0; /* Mark each buffer as free */
575 /* W I N D O W -- Resize the window to n */
579 debug(F101,"window","",n);
580 if (n < 1 || n > MAXWS) return(-1);
581 if (mksbuf(n) < 0) return(-1);
582 if (mkrbuf(n) < 0) return(-1);
585 if (deblog) dumpsbuf();
586 if (deblog) dumprbuf();
591 /* G E T S B U F -- Allocate a send-buffer. */
593 /* Call with packet sequence number to allocate buffer for. */
595 /* -4 if argument is invalid (negative, or greater than 63) */
596 /* -3 if buffers were thought to be available but really weren't (bug!) */
597 /* -2 if the number of free buffers is negative (bug!) */
598 /* -1 if no free buffers. */
599 /* 0 or positive, packet sequence number, with buffer allocated for it. */
602 getsbuf(n) int n; { /* Allocate a send-buffer */
605 if (n < 0 || n > 63) {
606 debug(F101,"getsbuf bad arg","",n);
607 return(-4); /* Bad argument */
609 debug(F101,"getsbuf packet","",n);
610 /* debug(F101,"getsbuf, sbufnum","",sbufnum); */
611 if (sbufnum == 0) return(-1); /* No free buffers. */
612 if (sbufnum < 0) return(-2); /* Shouldn't happen. */
613 for (i = 0; i < wslots; i++) /* Find the first one not in use. */
614 if (sbufuse[i] == 0) { /* Got one? */
615 sbufuse[i] = 1; /* Mark it as in use. */
616 sbufnum--; /* One less free buffer. */
617 *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
618 s_pkt[i].pk_seq = n; /* Put in the sequence number */
619 sseqtbl[n] = i; /* Back pointer from sequence number */
620 sacktbl[n] = 0; /* ACK flag */
621 s_pkt[i].pk_len = 0; /* Data field length now zero. */
622 s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
623 s_pkt[i].pk_rtr = 0; /* Zero the retransmission count */
624 p = s_pkt[i].bf_adr + 7; /* Set global "data" address. */
625 debug(F101,"getsbuf p","",0);
628 debug(F100,"getsbuf data == NULL","",0);
631 if ((what & (W_SEND|W_REMO)) && (++wcur > wmax))
632 wmax = wcur; /* For statistics. */
633 /* debug(F101,"getsbuf wcur","",wcur); */
634 return(n); /* Return its index. */
636 sbufnum = 0; /* Didn't find one. */
637 return(-3); /* Shouldn't happen! */
641 getrbuf() { /* Allocate a receive buffer */
644 /* This code is pretty stable by now... */
645 /* Looks like we might need this after all */
646 debug(F101,"getrbuf rbufnum","",rbufnum);
647 debug(F101,"getrbuf wslots","",wslots);
648 debug(F101,"getrbuf dum002","",dum002);
649 debug(F101,"getrbuf dum003","",dum003);
651 if (rbufnum == 0) return(-1); /* No free buffers. */
652 if (rbufnum < 0) return(-2); /* Shouldn't happen. */
653 for (i = 0; i < wslots; i++) /* Find the first one not in use. */
654 if (rbufuse[i] == 0) { /* Got one? */
655 rbufuse[i] = 1; /* Mark it as in use. */
656 *r_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
657 rbufnum--; /* One less free buffer. */
658 debug(F101,"getrbuf new rbufnum","",rbufnum);
659 if ((what & W_RECV) && (++wcur > wmax))
660 wmax = wcur; /* For statistics. */
661 /* debug(F101,"getrbuf wcur","",wcur); */
662 return(i); /* Return its index. */
664 /* debug(F101,"getrbuf foulup","",i); */
665 rbufnum = 0; /* Didn't find one. */
666 return(-3); /* Shouldn't happen! */
669 /* F R E E S B U F -- Free send-buffer for given packet sequence number */
673 /* -1 if specified buffer does not exist */
676 freesbuf(n) int n; { /* Release send-buffer for packet n. */
679 debug(F101,"freesbuf","",n);
680 if (n < 0 || n > 63) /* No such packet. */
682 i = sseqtbl[n]; /* Get the window slot number. */
683 if (i > -1 && i <= wslots) {
684 sseqtbl[n] = -1; /* If valid, remove from seqtbl */
685 sbufnum++; /* and count one more free buffer */
686 sbufuse[i] = 0; /* and mark it as free, */
687 if (what & (W_SEND|W_REMO)) /* decrement active slots */
688 wcur--; /* for statistics and display. */
690 debug(F101," sseqtbl[n]","",sseqtbl[n]);
694 /* The following is done only so dumped buffers will look right. */
697 *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
698 s_pkt[i].pk_seq = -1; /* Invalidate the sequence number */
699 s_pkt[i].pk_len = 0; /* Data field length now zero. */
700 s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
701 s_pkt[i].pk_rtr = 0; /* And the retries field. */
707 freerbuf(i) int i; { /* Release receive-buffer slot "i". */
710 /* NOTE !! Currently, this function frees the indicated buffer, but */
711 /* does NOT erase the data. The program counts on this. Will find a */
712 /* better way later.... */
714 /* debug(F101,"freerbuf, slot","",i); */
715 if (i < 0 || i >= wslots) { /* No such slot. */
716 debug(F101,"freerbuf no such slot","",i);
719 n = r_pkt[i].pk_seq; /* Get the packet sequence number */
720 debug(F101,"freerbuf packet","",n);
721 if (n > -1 && n < 64) /* If valid, remove from seqtbl */
723 if (rbufuse[i] != 0) { /* If really allocated, */
724 rbufuse[i] = 0; /* mark it as free, */
725 rbufnum++; /* and count one more free buffer. */
726 if (what & W_RECV) /* Keep track of current slots */
727 wcur--; /* for statistics and display */
728 debug(F101,"freerbuf rbufnum","",rbufnum);
731 /* The following is done only so dumped buffers will look right. */
734 /* *r_pkt[i].bf_adr = '\0'; */ /* Zero the buffer data field */
735 r_pkt[i].pk_seq = -1; /* And from packet list */
736 r_pkt[i].pk_len = 0; /* Data field length now zero. */
737 r_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
738 r_pkt[i].pk_rtr = 0; /* And the retries field. */
743 /* This is like freerbuf, except it's called with a packet sequence number */
744 /* rather than a packet buffer index. */
747 freerpkt(seq) int seq; {
749 debug(F101,"freerpkt seq","",seq);
751 /* debug(F101,"freerpkt k","",k); */
754 /* debug(F101,"freerpkt freerbuf","",k); */
759 /* C H K W I N -- Check if packet n is in window. */
762 /* 0 if it is in the current window, */
763 /* +1 if it would have been in previous window (e.g. if ack was lost), */
764 /* -1 if it is outside any window (protocol error), */
765 /* -2 if either of the argument packet numbers is out of range. */
767 /* Call with packet number to check (n), lowest packet number in window */
768 /* (bottom), and number of slots in window (slots). */
771 chkwin(n,bottom,slots) int n, bottom, slots; {
774 debug(F101,"chkwin packet","",n);
775 debug(F101,"chkwin winlo","",bottom);
776 debug(F101,"chkwin slots","",slots);
778 /* First do the easy and common cases, where the windows are not split. */
780 if (n < 0 || n > 63 || bottom < 0 || bottom > 63)
783 if (n == bottom) return(0); /* In a perfect world... */
785 top = bottom + slots; /* Calculate window top. */
786 if (top < 64 && n < top && n >= bottom)
787 return(0); /* In current window. */
789 prev = bottom - slots; /* Bottom of previous window. */
790 if (prev > -1 && n < bottom && n > prev)
791 return(1); /* In previous. */
793 /* Now consider the case where the current window is split. */
795 if (top > 63) { /* Wraparound... */
796 top -= 64; /* Get modulo-64 sequence number */
797 if (n < top || n >= bottom) {
798 return(0); /* In current window. */
799 } else { /* Not in current window. */
800 if (n < bottom && n >= prev) /* Previous window can't be split. */
801 return(1); /* In previous window. */
803 return(-1); /* Not in previous window. */
807 /* Now the case where current window not split, but previous window is. */
809 if (prev < 0) { /* Is previous window split? */
810 prev += 64; /* Yes. */
811 if (n < bottom || n >= prev)
812 return(1); /* In previous window. */
813 } else { /* Previous window not split. */
814 if (n < bottom && n >= prev)
815 return(1); /* In previous window. */
818 /* It's not in the current window, and not in the previous window... */
820 return(-1); /* So it's not in any window. */
824 dumpsbuf() { /* Dump send-buffers */
826 int j, x, z; /* to debug log. */
828 if (! deblog) return(0);
829 x = zsoutl(ZDFILE,"SEND BUFFERS:");
834 x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
839 for (j = 0; j < wslots; j++) {
842 z = ((unsigned long)(s_pkt[j].bf_adr)) & 0xffff;
844 sprintf(xbuf, /* safe (200) */
845 "%4d%6d%10d%5d%6d%4c%5d%6d\n",
848 /* Avoid warnings when addresses are bigger than ints */
856 if (zsout(ZDFILE,xbuf) < 0) {
860 if (s_pkt[j].pk_adr) {
861 x = (int)strlen((char *) s_pkt[j].pk_adr);
863 sprintf(xbuf, /* safe (checked) */
864 "[%.72s%s]\n",s_pkt[j].pk_adr, x > 72 ? "..." : "");
866 sprintf(xbuf,"[(empty string)]\n"); /* safe (200) */
868 sprintf(xbuf,"[(null pointer)]\n"); /* safe (200) */
870 if (zsout(ZDFILE,xbuf) < 0) {
875 sprintf(xbuf,"free: %d, winlo: %d\n", sbufnum, winlo); /* safe (200) */
876 if (zsout(ZDFILE,xbuf) < 0) {
884 dumprbuf() { /* Dump receive-buffers */
887 if (! deblog) return(0);
888 if (zsoutl(ZDFILE,"RECEIVE BUFFERS:") < 0) {
892 x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
897 for ( j = 0; j < wslots; j++ ) {
900 z = ((unsigned long)(r_pkt[j].bf_adr)) & 0xffff;
901 sprintf(xbuf, /* 200, safe */
902 "%4d%6d%10d%5d%6d%4c%5d%6d\n",
905 /* Avoid warnings when addresses are bigger than ints */
913 if (zsout(ZDFILE,xbuf) < 0) {
917 x = (int)strlen((char *)r_pkt[j].bf_adr);
918 sprintf(xbuf, /* safe (checked) */
919 "[%.72s%s]\n",r_pkt[j].bf_adr, x > 72 ? "..." : "");
920 if (zsout(ZDFILE,xbuf) < 0) {
925 sprintf(xbuf,"free: %d, winlo: %d\n", rbufnum, winlo); /* safe (200) */
926 if (zsout(ZDFILE,xbuf) < 0) {
934 /* S A T T R -- Send an Attribute Packet */
937 Sends attribute packet(s) for the current file. If the info will not
938 fit into one packet, it can be called repeatedly until all the fields
939 that will fit are sent.
942 xp == 0 if we're sending a real file (F packet), or:
943 xp != 0 for screen data (X packet).
945 flag == 1 for first A packet
946 flag == 0 for subsequent A packets.
948 1 or greater if an A packet was sent, or:
949 0 if an S-packet was not sent because there was no data to send or
950 there was no data left that was short enough to send, or:
951 -1 on any kind of error.
954 /* (don't) #define TSOFORMAT */
955 /* which was only for making C-Kermit send TSO-Kermit-like A packets */
956 /* to try to track down a problem somebody reported... */
959 sattr(xp, flag) int xp, flag; { /* Send Attributes */
961 static int max; /* Maximum length for Attributes */
962 static short done[95]; /* Field-complete array */
963 static struct zattr x; /* File attribute struct */
964 static char xdate[24];
966 extern char * cksysid;
968 /* Some extra flags are used because the "done" array is sparse */
970 int i, j, rc, aln, left = 0, numset = 0, xbin = 0; /* Workers */
974 notafile = sndarray || pipesend ||
977 #endif /* PIPESEND */
980 debug(F101,"sattr flag","",flag);
981 if (!flag) /* No more attributes to send */
982 if (done[xunchar('@')])
985 /* Initialize Attribute mechanism */
987 if (flag) { /* First time here for this file? */
988 initattr(&x); /* Blank out all the fields. */
989 for (j = 0; j < 95; j++) /* Init array of completed fields */
991 max = maxdata(); /* Get maximum data field length */
992 if (notafile || xp == 1) { /* Is it not a real file? */
993 extern char * zzndate();
997 if (calibrate) { /* Calibration run... */
998 x.lengthk = calibrate / 1024L; /* We know the length */
999 x.length = calibrate;
1001 #endif /* CALIBRATE */
1002 x.systemid.val = cksysid; /* System ID */
1003 x.systemid.len = (int)strlen(cksysid);
1004 ckstrncpy(xdate,zzndate(),24);
1007 for (i = 11; i < 19; i++) /* copy hh:mm:ss */
1008 xdate[i - 2] = p[i]; /* to xdate */
1009 xdate[17] = NUL; /* terminate */
1012 debug(F111,"sattr notafile date",x.date.val,x.date.len);
1013 } else { /* Real file */
1014 rc = zsattr(&x); /* Get attributes for this file */
1015 debug(F101,"sattr zsattr","",rc);
1016 if (rc < 0) /* Can't get 'em so don't send 'em */
1018 debug(F101,"sattr init max","",max);
1021 if (nxtpkt() < 0) /* Got 'em, get next packet number */
1022 return(-1); /* Bad news if we can't */
1024 i = 0; /* Init data field character number */
1026 /* Do each attribute using first-fit method, marking as we go */
1027 /* This is rather long and repititious - could be done more cleverly */
1029 if (atsido && !done[xunchar(c = '.')]) { /* System type */
1030 if (max - i >= x.systemid.len + 2) { /* Enough space ? */
1031 data[i++] = c; /* Yes, add parameter */
1032 data[i++] = tochar(x.systemid.len); /* Add length */
1033 for (j = 0; j < x.systemid.len; j++) /* Add data */
1034 data[i++] = x.systemid.val[j];
1035 numset++; /* Count that we did at least one */
1036 done[xunchar(c)] = 1; /* Mark this attribute as done */
1038 left++; /* so mark this one left to do */
1041 if (atcreo && !done[xunchar(c = '$')]) { /* Creator */
1042 if (max - i >= x.creator.len + 2) { /* Enough space ? */
1044 data[i++] = tochar(x.creator.len);
1045 for (j = 0; j < x.creator.len; j++)
1046 data[i++] = x.creator.val[j];
1048 done[xunchar(c)] = 1;
1052 if (atacto && !done[xunchar(c = '%')]) { /* File account */
1053 if (max - i >= x.account.len + 2) {
1055 data[i++] = tochar(x.account.len);
1056 for (j = 0; j < x.account.len; j++)
1057 data[i++] = x.account.val[j];
1059 done[xunchar(c)] = 1;
1063 if (atfrmo && !done[xunchar(c = '/')]) { /* Packet data format */
1064 if (max - i >= x.recfm.len + 2) {
1066 data[i++] = tochar(x.recfm.len); /* Copy from attr structure */
1067 for (j = 0; j < x.recfm.len; j++)
1068 data[i++] = x.recfm.val[j];
1070 done[xunchar(c)] = 1;
1074 #endif /* STRATUS */
1076 xbin = /* Is the transfer in binary mode? */
1078 binary == XYFT_I || binary == XYFT_L || /* IMAGE or LABELED */
1079 !strncmp(x.recfm.val,"F",1) /* or RECFM=Fxxxxxx */
1081 binary /* User said SET FILE TYPE BINARY */
1085 if (attypo && !done[xunchar(c = '"')]) { /* File type */
1086 if (max - i >= 5) { /* Max length for this field */
1088 if (xbin) { /* Binary */
1089 data[i++] = tochar(2); /* Two characters */
1090 data[i++] = 'B'; /* B for Binary */
1091 data[i++] = '8'; /* 8-bit bytes (note assumption...) */
1093 if (binary != XYFT_L
1099 #endif /* CK_LABELED */
1102 data[i++] = tochar(1); /* One character */
1103 data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */
1105 data[i++] = tochar(3); /* Three characters */
1106 data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */
1107 data[i++] = 'M'; /* M for carriage return */
1108 data[i++] = 'J'; /* J for linefeed */
1109 #endif /* TSOFORMAT */
1112 binary = XYFT_T; /* We automatically detected text */
1116 done[xunchar(c)] = 1;
1122 if (attypo && !xbin && !done[xunchar(c = '/')]) { /* Record format */
1125 data[i++] = tochar(3); /* Three characters */
1126 data[i++] = 'A'; /* A = variable with CRLFs */
1127 data[i++] = 'M'; /* M for carriage return */
1128 data[i++] = 'J'; /* J for linefeed */
1131 #endif /* TSOFORMAT */
1133 if (attypo && !xbin && !done[xunchar(c = '*')]) { /* Text encoding */
1137 data[i++] = tochar(1); /* Length of value is 1 */
1138 data[i++] = 'A'; /* A for ASCII */
1140 done[xunchar(c)] = 1;
1144 if (tcharset == TC_TRANSP || !xfrxla) { /* Transfer character set */
1146 data[i++] = c; /* Encoding */
1147 data[i++] = tochar(1); /* Length of value is 1 */
1148 data[i++] = 'A'; /* A for ASCII (i.e. text) */
1150 done[xunchar(c)] = 1;
1154 tp = tcsinfo[tcharset].designator;
1158 if (max - i >= aln + 2) {
1159 data[i++] = c; /* Encoding */
1160 data[i++] = tochar(aln+1); /* Length of designator. */
1161 data[i++] = 'C'; /* Text in specified charset. */
1162 for (j = 0; j < aln; j++) /* Copy designator */
1163 data[i++] = *tp++; /* Example: *&I6/100 */
1165 done[xunchar(c)] = 1;
1169 done[xunchar(c)] = 1;
1171 #endif /* NOCSETS */
1173 if (atdato && !done[xunchar(c = '#')] && /* Creation date, if any */
1174 (aln = x.date.len) > 0) {
1175 if (max - i >= aln + 2) {
1177 data[i++] = tochar(aln);
1178 for (j = 0; j < aln; j++)
1179 data[i++] = x.date.val[j];
1181 done[xunchar(c)] = 1;
1185 /* File length in K */
1186 if (atleno && !done[xunchar(c = '!')] && x.lengthk > -1L) {
1187 sprintf((char *) &data[i+2],"%ld",x.lengthk); /* safe */
1188 aln = (int)strlen((char *)(data+i+2));
1189 if (max - i >= aln + 2) {
1191 data[i+1] = tochar(aln);
1194 done[xunchar(c)] = 1;
1200 /* File length in bytes */
1201 if (atleno && !done[xunchar(c = '1')] && x.length > -1L) {
1202 sprintf((char *) &data[i+2],"%ld",x.length); /* safe */
1203 aln = (int)strlen((char *)(data+i+2));
1204 if (max - i >= aln + 2) {
1206 data[i+1] = tochar(aln);
1209 done[xunchar(c)] = 1;
1216 if (atlpro && !done[xunchar(c = ',')] && /* Local protection */
1217 (aln = x.lprotect.len) > 0 && !notafile && xp == 0) {
1218 if (max - i >= aln + 2) {
1220 data[i++] = tochar(aln);
1221 for (j = 0; j < aln; j++)
1222 data[i++] = x.lprotect.val[j];
1224 done[xunchar(c)] = 1;
1228 if (atgpro && !done[xunchar(c = '-')] && /* Generic protection */
1229 (aln = x.gprotect.len) > 0 && !notafile && xp == 0) {
1230 if (max - i >= aln + 2) {
1232 data[i++] = tochar(aln);
1233 for (j = 0; j < aln; j++)
1234 data[i++] = x.gprotect.val[j];
1236 done[xunchar(c)] = 1;
1240 #endif /* CK_PERMS */
1241 if (atblko && fblksiz && !done[xunchar(c = '(')] &&
1242 !notafile && xp == 0) { /* Blocksize */
1243 sprintf((char *) &data[i+2],"%d",fblksiz); /* safe */
1244 aln = (int)strlen((char *)(data+i+2));
1245 if (max - i >= aln + 2) {
1247 data[i+1] = tochar(aln);
1250 done[xunchar(c)] = 1;
1257 if ((rprintf || rmailf) && atdiso && /* MAIL, or REMOTE PRINT? */
1258 !done[xunchar(c = '+')]) {
1259 aln = (int) strlen(optbuf) + 1; /* Options, if any */
1260 if (max - i >= aln + 2) {
1261 data[i++] = c; /* Disposition */
1262 data[i++] = tochar(aln); /* Options, if any */
1264 data[i++] = 'P'; /* P for Print */
1266 data[i++] = 'M'; /* M for Mail */
1267 for (j = 0; optbuf[j]; j++) /* Copy any options */
1268 data[i++] = optbuf[j];
1270 done[xunchar(c)] = 1;
1276 #endif /* NOFRILLS */
1278 if (sendmode == SM_RESEND && !done[xunchar(c = '+')]) {
1280 data[i++] = c; /* Disposition */
1281 data[i++] = tochar(1);
1282 data[i++] = 'R'; /* is RESEND */
1284 done[xunchar(c)] = 1;
1288 #endif /* CK_RESEND */
1290 /* End of Attributes -- to be sent only after sending all others */
1292 debug(F111,"sattr","@",i);
1293 debug(F101,"sattr numset","",numset);
1294 debug(F101,"sattr left","",left);
1296 if ((left == 0 || numset == 0) && !done[xunchar(c = '@')]) {
1298 data[i++] = c; /* End of Attributes */
1299 data[i++] = SP; /* Length 0 */
1300 data[i] = NUL; /* Make sure it's null-terminated */
1302 done[xunchar(c)] = 1;
1306 /* Finished - send the packet off if we have anything in it */
1309 data[i] = NUL; /* Terminate last good field */
1310 debug(F111,"sattr sending",data,left);
1311 aln = (int)strlen((char *)data); /* Get overall length of attributes */
1312 return(spack('A',pktnum,aln,data)); /* Send it */
1317 static char *refused = "";
1319 static char *reason[] = {
1320 "size", "type", "date", "creator", "account", "area", "password",
1321 "blocksize", "access", "encoding", "disposition", "protection",
1322 "protection", "origin", "format",
1323 "sys-dependent", /* 0 */
1341 static int nreason = sizeof(reason) / sizeof(char *);
1345 getreason(s) char *s; { /* Decode attribute refusal reason */
1347 if (rejection == 1) /* Kludge for SET FIL COLL DISCARD */
1348 return("name"); /* when other Kermit doesn't... */
1350 if (*p++ != 'N') return(""); /* Should start with N */
1351 else if ((c = *p) > SP) { /* get reason, */
1352 rejection = c; /* remember it, */
1353 c -= '!'; /* get offset */
1354 p = ((unsigned int) ((CHAR) c) <= (unsigned int) nreason) ?
1362 rsattr(s) CHAR *s; { /* Read response to attribute packet */
1363 debug(F111,"rsattr",s,*s);
1364 if (*s == 'N') { /* If it's 'N' followed by anything, */
1365 refused = getreason((char *)s); /* they are refusing, get reason. */
1366 debug(F110,"rsattr refused",refused,0);
1367 tlog(F110," refused:",refused,0L);
1371 if (sendmode == SM_RESEND && *s == '1') { /* RESEND length */
1372 int n; long z; CHAR *p;
1375 debug(F101,"rsattr RESEND n","",n);
1377 while (n-- > 0) /* We assume the format is good. */
1378 z = 10L * z + (long) (*p++ - '0');
1379 debug(F101,"rsattr RESEND z","",z);
1380 if (z > 0L) sendstart = z;
1381 debug(F101,"rsattr RESEND sendstart","",sendstart);
1383 if (zfseek(sendstart) < 0) /* Input file is already open. */
1386 if (fdispla == XYFD_C)
1387 xxscreen(SCR_FS,0,fsize,""); /* Refresh file transfer display */
1388 #endif /* CK_CURSES */
1390 #endif /* CK_RESEND */
1395 long rs_len = 0L; /* Length of file being resent to */
1398 Get attributes from incoming A packet. Returns:
1399 0 on success, file is to be accepted
1400 -1 on failure, file is to be refused
1403 gattr(s, yy) CHAR *s; struct zattr *yy; { /* Read incoming attribute packet */
1409 extern int r_cset, axcset[];
1410 #endif /* NOCSETS */
1412 #define ABUFL 40 /* Temporary buffer for conversions */
1414 #define RFBUFL 10 /* Record-format buffer */
1415 static char rfbuf[RFBUFL+1];
1416 #define FTBUFL 10 /* File type buffer */
1417 static char ftbuf[FTBUFL+1];
1418 #define DTBUFL 40 /* File creation date */
1419 static char dtbuf[DTBUFL+1];
1420 #define TSBUFL 10 /* Transfer syntax */
1421 static char tsbuf[TSBUFL+1];
1422 #define IDBUFL 10 /* System ID */
1423 static char idbuf[IDBUFL+1];
1425 #define DSBUFL 100 /* Disposition */
1426 static char dsbuf[DSBUFL+1];
1427 #define SPBUFL 512 /* System-dependent parameters */
1428 static char spbuf[SPBUFL+1];
1430 #define DSBUFL 100 /* Disposition */
1431 static char *dsbuf = NULL;
1432 #define SPBUFL 512 /* System-dependent parameters */
1433 static char *spbuf = NULL;
1434 #endif /* DYNAMIC */
1435 #define RPBUFL 20 /* Attribute reply */
1436 static char rpbuf[RPBUFL+1];
1439 static char lprmbuf[CK_PERMLEN+1];
1440 static char gprmbuf[2];
1441 #endif /* CK_PERMS */
1443 char *rp; /* Pointer to reply buffer */
1444 int retcode; /* Return code */
1446 d = SP; /* Initialize disposition */
1447 ff = filnam; /* Filename returned by rcvfil */
1448 if (fncact == XYFX_R && ofn1x && ofn1[0]) /* But watch out for FC=RENAME */
1449 ff = ofn1; /* because we haven't renamed it yet */
1451 /* Fill in the attributes we have received */
1453 rp = rpbuf; /* Initialize reply buffer */
1454 *rp++ = 'N'; /* for negative reply. */
1456 retcode = 0; /* Initialize return code. */
1458 if (dest == DEST_P) { /* SET DESTINATION PRINTER */
1461 if ((dsbuf = malloc(DSBUFL+1)) == NULL)
1462 fatal("gtattr: no memory for dsbuf");
1463 #endif /* DYNAMIC */
1466 yy->disp.val = dsbuf;
1469 while (c = *s++) { /* Get attribute tag */
1470 aln = xunchar(*s++); /* Length of attribute string */
1472 case '!': /* File length in K */
1473 for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1475 abuf[i] = '\0'; /* Terminate with null */
1476 if (i < aln) s += (aln - i); /* If field was too long for buffer */
1477 yy->lengthk = atol(abuf); /* Convert to number */
1480 case '/': /* Record format */
1483 for (i = 0; (i < aln) && (i < RFBUFL); i++) /* Copy it */
1485 rfbuf[i] = NUL; /* Terminate with null */
1486 yy->recfm.val = rfbuf; /* Pointer to string */
1487 yy->recfm.len = i; /* Length of string */
1488 if ((rfbuf[0] != 'A') ||
1489 (rfbuf[1] && rfbuf[1] != 'M') ||
1490 (rfbuf[2] && rfbuf[2] != 'J')) {
1491 debug(F110,"gattr bad recfm",rfbuf,0);
1497 case '"': /* File type (text, binary, ...) */
1498 for (i = 0; (i < aln) && (i < FTBUFL); i++)
1499 ftbuf[i] = *s++; /* Copy it into a static string */
1501 if (i < aln) s += (aln - i);
1502 /* TYPE attribute is enabled? */
1504 yy->type.val = ftbuf; /* Pointer to string */
1505 yy->type.len = i; /* Length of string */
1506 debug(F111,"gattr file type", ftbuf, i);
1507 debug(F101,"gattr binary 1","",binary);
1509 if ((*ftbuf != 'A' && *ftbuf != 'B' && *ftbuf != 'I')
1511 /* ... Or our FILE TYPE is LABELED and the incoming file is text... */
1512 || (binary == XYFT_L && *ftbuf == 'A' && !xflg)
1513 #endif /* CK_LABELED */
1515 retcode = -1; /* Reject the file */
1517 if (!opnerr) tlog(F100," refused: type","",0);
1521 The following code moved here from opena() so we set binary mode
1522 as soon as requested by the attribute packet. That way when the first
1523 data packet comes, the mode of transfer can be displayed correctly
1524 before opena() is called.
1526 if (yy->type.val[0] == 'A') { /* Check received attributes. */
1528 if (binary != XYFT_I) /* VMS IMAGE overrides this */
1530 binary = XYFT_T; /* Set current type to Text. */
1531 debug(F101,"gattr binary 2","",binary);
1532 } else if (yy->type.val[0] == 'B') {
1534 if (binary != XYFT_L
1536 && binary != XYFT_U /* VMS special case */
1539 #endif /* CK_LABELED */
1541 if (binary != XYFT_M) /* If not MacBinary... */
1544 debug(F101,"gattr binary 3","",binary);
1549 case '#': /* File creation date */
1550 for (i = 0; (i < aln) && (i < DTBUFL); i++)
1551 dtbuf[i] = *s++; /* Copy it into a static string */
1552 if (i < aln) s += (aln - i);
1554 if (atdati && !xflg) { /* Real file and dates enabled */
1555 yy->date.val = dtbuf; /* Pointer to string */
1556 yy->date.len = i; /* Length of string */
1557 if (fncact == XYFX_U) { /* Receiving in update mode? */
1558 if (zstime(ff,yy,1) > 0) { /* Compare dates */
1559 *rp++ = c; /* Discard if older, reason = date. */
1560 if (!opnerr) tlog(F100," refused: date","",0);
1561 retcode = -1; /* Rejection notice. */
1567 case '(': /* File Block Size */
1568 for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1570 abuf[i] = '\0'; /* Terminate with null */
1571 if (i < aln) s += (aln - i);
1573 yy->blksize = atol(abuf); /* Convert to number */
1576 case '*': /* Encoding (transfer syntax) */
1577 for (i = 0; (i < aln) && (i < TSBUFL); i++)
1578 tsbuf[i] = *s++; /* Copy it into a static string */
1579 if (i < aln) s += (aln - i);
1582 xlatype = XLA_NONE; /* Assume no translation */
1583 #endif /* NOCSETS */
1586 yy->encoding.val = tsbuf; /* Pointer to string */
1587 yy->encoding.len = i; /* Length of string */
1588 debug(F101,"gattr encoding",tsbuf,i);
1592 case 'A': /* Normal, nothing special */
1593 tcharset = TC_TRANSP; /* Transparent chars untranslated */
1594 debug(F110,"gattr sets tcharset TC_TRANSP","A",0);
1596 case 'C': /* Specified character set */
1597 if (!xfrxla) { /* But translation disabled */
1598 tcharset = TC_TRANSP;
1599 debug(F110,"gattr sets tcharset TC_TRANSP","C",0);
1603 if (!strcmp("I196",ss)) /* Treat I196 (UTF-8 no level) */
1604 ss = "I190"; /* as I190 (UTF-8 Level 1) */
1605 #endif /* UNICODE */
1606 if (!strcmp("I6/204",ss)) /* Treat "Latin-1 + Euro" */
1607 ss = "I6/100"; /* as I6/100 (regular Latin-1) */
1608 for (i = 0; i < ntcsets; i++) {
1609 if (!strcmp(tcsinfo[i].designator,ss))
1612 debug(F101,"gattr xfer charset lookup","",i);
1613 if (i == ntcsets) { /* If unknown character set, */
1614 debug(F110,"gattr: xfer charset unknown",ss,0);
1615 if (!unkcs) { /* and SET UNKNOWN DISCARD, */
1616 retcode = -1; /* reject the file. */
1619 tlog(F100," refused: character set","",0);
1622 tcharset = tcsinfo[i].code; /* it's known, use it */
1623 debug(F101,"gattr switch tcharset","",tcharset);
1624 debug(F101,"gattr fcharset","",fcharset);
1625 if (r_cset == XMODE_A) { /* Automatic switching? */
1626 if (tcharset > -1 && tcharset <= MAXTCSETS) {
1628 x = axcset[tcharset];
1629 if (x > 0 && x <= MAXFCSETS) {
1631 debug(F101,"gattr switch fcharset","",x);
1635 /* Set up translation type and function */
1636 setxlatype(tcharset,fcharset);
1639 #endif /* NOCSETS */
1640 default: /* Something else. */
1641 debug(F110,"gattr unk encoding attribute",tsbuf,0);
1642 if (!unkcs) { /* If SET UNK DISC */
1645 if (!opnerr) tlog(F100," refused: encoding","",0);
1652 case '+': /* Disposition */
1655 if ((dsbuf = malloc(DSBUFL+1)) == NULL)
1656 fatal("gtattr: no memory for dsbuf");
1657 #endif /* DYNAMIC */
1658 for (i = 0; (i < aln) && (i < DSBUFL); i++)
1659 dsbuf[i] = *s++; /* Copy it into a separate string */
1661 if (i < aln) s += (aln - i);
1663 if (atdisi) { /* We are doing this attribute */
1664 /* Copy it into the attribute structure */
1665 yy->disp.val = dsbuf; /* Pointer to string */
1666 yy->disp.len = i; /* Length of string */
1670 Define NODISPO to disable receipt of mail or print files and of RESEND.
1673 #ifndef datageneral /* MAIL supported only for */
1674 #ifndef OS2 /* UNIX, VMS, and OS-9 */
1678 d != 'M' && /* MAIL */
1683 #endif /* datageneral */
1685 d != 'R' && /* RESEND */
1686 #endif /* CK_RESEND */
1687 d != 'P') { /* PRINT */
1688 retcode = -1; /* Unknown/unsupported disposition */
1690 if (!opnerr) tlog(F101," refused: bad disposition","",d);
1693 debug(F000,"gattr dispos","",dispos);
1700 if (!opnerr) tlog(F100," refused: mail disabled","",0);
1704 #endif /* NOFRILLS */
1710 tlog(F100," refused: print disabled","",0);
1718 rs_len = zgetfs(ff); /* Get length of file */
1719 debug(F111,"gattr RESEND",ff,rs_len);
1721 rs_len &= (long) -512; /* Ensure block boundary if VMS */
1722 rs_len -= 512; /* In case last block not complete */
1723 debug(F111,"gattr rs_len",ff,rs_len);
1726 if (rs_len < 0L) /* Local file doesn't exist */
1728 #endif /* COMMENT */
1730 Another possibility here (or later, really) would be to check if the two
1731 file lengths are the same, and if so, keep the prevailing collision action
1732 as is (note: rs_len == length of existing file; yy->length == fsize ==
1733 length of incoming file). This could be complicated, though, since
1734 (a) we might not have received the length attribute yet, and in fact it
1735 might even be in a subsequent A-packet, yet (b) we have to accept or reject
1736 the Recover attribute now. So better to leave as-is. Anyway, it's probably
1737 more useful this way.
1740 fncsav = fncact; /* Save collision action */
1741 fncact = XYFX_A; /* Switch to APPEND */
1744 retcode = -1; /* This shouldn't happen */
1745 *rp++ = c; /* 'cause it wasn't negotiated. */
1746 if (!opnerr) tlog(F100," refused: resend","",0);
1747 #endif /* CK_RESEND */
1752 if (!opnerr) tlog(F100," refused: NODISPO","",0);
1753 #endif /* NODISPO */
1757 case '.': /* Sender's system ID */
1758 for (i = 0; (i < aln) && (i < IDBUFL); i++)
1759 idbuf[i] = *s++; /* Copy it into a static string */
1761 if (i < aln) s += (aln - i);
1763 yy->systemid.val = idbuf; /* Pointer to string */
1764 yy->systemid.len = i; /* Length of string */
1768 case '0': /* System-dependent parameters */
1770 if (!spbuf && !(spbuf = malloc(SPBUFL)))
1771 fatal("gattr: no memory for spbuf");
1772 #endif /* DYNAMIC */
1773 for (i = 0; (i < aln) && (i < SPBUFL); i++)
1774 spbuf[i] = *s++; /* Copy it into a static string */
1776 if (i < aln) s += (aln - i);
1778 yy->sysparam.val = spbuf; /* Pointer to string */
1779 yy->sysparam.len = i; /* Length of string */
1783 case '1': /* File length in bytes */
1784 for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1786 abuf[i] = '\0'; /* Terminate with null */
1787 if (i < aln) s += (aln - i);
1788 yy->length = atol(abuf); /* Convert to number */
1789 debug(F111,"gattr length",abuf,(int) yy->length);
1794 case ',': /* System-dependent protection code */
1795 for (i = 0; (i < aln) && (i < CK_PERMLEN); i++)
1796 lprmbuf[i] = *s++; /* Just copy it - decode later */
1797 lprmbuf[i] = '\0'; /* Terminate with null */
1798 if (i < aln) s += (aln - i);
1800 yy->lprotect.val = (char *)lprmbuf;
1801 yy->lprotect.len = i;
1806 case '-': /* Generic "world" protection code */
1807 gprmbuf[0] = NUL; /* Just 1 byte by definition */
1808 for (i = 0; i < aln; i++) /* But allow for more... */
1809 if (i == 0) gprmbuf[0] = *s++;
1812 yy->gprotect.val = (char *)gprmbuf;
1813 yy->gprotect.len = gprmbuf[0] ? 1 : 0;
1817 #endif /* CK_PERMS */
1819 default: /* Unknown attribute */
1820 s += aln; /* Just skip past it */
1825 /* Check file length now, because we also need to know the file type */
1826 /* in case zchkspa() differentiates text and binary (VMS version does) */
1828 if (atleni) { /* Length attribute enabled? */
1829 if (yy->length > -1L) { /* Length-in-bytes attribute rec'd? */
1830 if (!zchkspa(ff,(yy->length))) { /* Check space */
1831 retcode = -1; /* Not enuf */
1833 if (!opnerr) tlog(F100," refused: length bytes","",0);
1835 } else if (yy->lengthk > -1L) { /* Length in K attribute rec'd? */
1836 if (!zchkspa(ff,(yy->lengthk * 1024))) {
1837 retcode = -1; /* Check space */
1839 if (!opnerr) tlog(F100," refused: length K","",0);
1843 if (yy->length > -1L) { /* Remember the file size */
1845 } else if (yy->lengthk > -1L) {
1846 fsize = yy->lengthk * 1024L;
1851 sprintf(abuf,"%ld",fsize); /* safe */
1852 debug(F110,"gattr fsize",abuf,0);
1856 if (retcode == 0) rp = rpbuf; /* Null reply string if accepted */
1857 *rp = '\0'; /* End of reply string */
1860 if (d == 'R') { /* Receiving a RESEND? */
1861 debug(F101,"gattr RESEND","",retcode);
1862 /* We ignore retcodes because this overrides */
1863 if (binary != XYFT_B) { /* Reject if not binary */
1864 retcode = -1; /* in case type field came */
1865 ckstrncpy(rpbuf,"N+",RPBUFL); /* after the disposition field */
1866 debug(F111,"gattr RESEND not binary",rpbuf,binary);
1867 } else { /* Binary mode */
1868 retcode = 0; /* Accept the file */
1869 discard = 0; /* If SET FILE COLLISION DISCARD */
1870 sprintf(rpbuf+2,"%ld",rs_len); /* Reply with length of file */
1871 rpbuf[0] = '1'; /* '1' means Length in Bytes */
1872 rpbuf[1] = tochar((int)strlen(rpbuf+2)); /* Length of length */
1873 debug(F111,"gattr RESEND OK",rpbuf,retcode);
1876 #endif /* CK_RESEND */
1877 if (retcode == 0 && discard != 0) { /* Do we still have a discard flag? */
1878 ckstrncpy(rpbuf,"N?",RPBUFL); /* Yes, must be filename collision */
1879 retcode = -1; /* "?" = name (reply-only code) */
1881 yy->reply.val = rpbuf; /* Add it to attribute structure */
1882 yy->reply.len = (int)strlen(rpbuf);
1883 if (retcode < 0) { /* If we are rejecting */
1884 discard = 1; /* remember to discard the file */
1885 rejection = rpbuf[1]; /* and use the first reason given. */
1891 debug(F111,"gattr return",rpbuf,retcode);
1895 /* I N I T A T T R -- Initialize file attribute structure */
1898 initattr(yy) struct zattr *yy; {
1899 yy->lengthk = yy->length = -1L;
1904 yy->encoding.val = "";
1905 yy->encoding.len = 0;
1908 yy->systemid.val = "";
1909 yy->systemid.len = 0;
1910 yy->sysparam.val = "";
1911 yy->sysparam.len = 0;
1912 yy->creator.val = "";
1913 yy->creator.len = 0;
1914 yy->account.val = "";
1915 yy->account.len = 0;
1918 yy->password.val = "";
1919 yy->password.len = 0;
1921 yy->xaccess.val = "";
1922 yy->xaccess.len = 0;
1924 if (!ofperms) ofperms = "";
1925 debug(F110,"initattr ofperms",ofperms,0);
1926 yy->lprotect.val = ofperms;
1927 yy->lprotect.len = 0 - strlen(ofperms); /* <-- NOTE! */
1929 A negative length indicates that we have a permissions string but it has
1930 been inherited from a previously existing file rather than picked up
1931 from an incoming A-packet.
1934 yy->lprotect.val = "";
1935 yy->lprotect.len = 0;
1936 #endif /* CK_PERMS */
1937 yy->gprotect.val = "";
1938 yy->gprotect.len = 0;
1944 yy->longname.len = 0 ;
1945 yy->longname.val = "" ;
1950 /* A D E B U -- Write attribute packet info to debug log */
1953 adebu(f,zz) char *f; struct zattr *zz; {
1955 if (deblog == 0) return(0);
1956 debug(F110,"Attributes for incoming file ",f,0);
1957 debug(F101," length in K","",(int) zz->lengthk);
1958 debug(F111," file type",zz->type.val,zz->type.len);
1959 debug(F111," creation date",zz->date.val,zz->date.len);
1960 debug(F111," creator",zz->creator.val,zz->creator.len);
1961 debug(F111," account",zz->account.val,zz->account.len);
1962 debug(F111," area",zz->area.val,zz->area.len);
1963 debug(F111," password",zz->password.val,zz->password.len);
1964 debug(F101," blksize","",(int) zz->blksize);
1965 debug(F111," access",zz->xaccess.val,zz->xaccess.len);
1966 debug(F111," encoding",zz->encoding.val,zz->encoding.len);
1967 debug(F111," disposition",zz->disp.val,zz->disp.len);
1968 debug(F111," lprotection",zz->lprotect.val,zz->lprotect.len);
1969 debug(F111," gprotection",zz->gprotect.val,zz->gprotect.len);
1970 debug(F111," systemid",zz->systemid.val,zz->systemid.len);
1971 debug(F111," recfm",zz->recfm.val,zz->recfm.len);
1972 debug(F111," sysparam",zz->sysparam.val,zz->sysparam.len);
1973 debug(F101," length","",(int) zz->length);
1974 debug(F110," reply",zz->reply.val,0);
1979 /* O P E N A -- Open a file, with attributes. */
1981 This function tries to open a new file to put the arriving data in. The
1982 filename is the one in the srvcmd buffer. File collision actions are:
1983 OVERWRITE (the existing file is overwritten), RENAME (the new file is
1984 renamed), BACKUP (the existing file is renamed), DISCARD (the new file is
1985 refused), UPDATE (the incoming file replaces the existing file only if the
1986 incoming file has a newer creation date).
1988 Returns 0 on failure, nonzero on success.
1990 extern char *rf_err;
1993 opena(f,zz) char *f; struct zattr *zz; {
1995 static struct filinfo fcb; /* Must be static! */
1997 debug(F110,"opena f",f,0);
1998 debug(F101,"opena discard","",discard);
2000 adebu(f,zz); /* Write attributes to debug log */
2002 ffc = 0L; /* Init file-character counter */
2005 if (pipesend) /* Receiving to a pipe - easy. */
2006 return(openo(f,zz,&fcb)); /* Just open the pipe. */
2007 #endif /* PIPESEND */
2009 /* Receiving to a file - set up file control structure */
2011 fcb.bs = fblksiz; /* Blocksize */
2013 fcb.cs = fcharset; /* Character set */
2015 fcb.cs = 0; /* Character set */
2016 #endif /* NOCSETS */
2017 fcb.rl = frecl; /* Record Length */
2018 fcb.fmt = frecfm; /* Record Format */
2019 fcb.org = forg; /* Organization */
2020 fcb.cc = fcctrl; /* Carriage control */
2021 fcb.typ = binary; /* Type */
2022 debug(F101,"opena xflg","",xflg);
2023 debug(F101,"opena remfile","",remfile);
2024 debug(F101,"opena remappd","",remappd);
2025 if (xflg && remfile && remappd) /* REMOTE output redirected with >> */
2028 fcb.dsp = (fncact == XYFX_A) ? XYFZ_A : XYFZ_N; /* Disposition */
2029 debug(F101,"opena disp","",fcb.dsp);
2030 fcb.os_specific = ""; /* OS-specific info */
2032 fcb.lblopts = lf_opts; /* Labeled file options */
2035 #endif /* CK_LABELED */
2037 if (zz->disp.len > 0) { /* Incoming file has a disposition? */
2038 debug(F111,"open disposition",zz->disp.val,zz->disp.len);
2039 dispos = (int) (*(zz->disp.val));
2041 if (!dispos && xflg && remfile && remappd) /* REMOTE redirect append ? */
2044 debug(F101,"opena dispos","",dispos);
2046 if (!dispos) { /* No special disposition? */
2047 if (fncact == XYFX_B && ofn1x && ofn2) { /* File collision = BACKUP? */
2048 if (zrename(ofn1,ofn2) < 0) { /* Rename existing file. */
2049 debug(F110,"opena rename fails",ofn1,0);
2050 rf_err = "Can't create backup file";
2052 } else debug(F110,"opena rename ok",ofn2,0);
2054 } else if (dispos == 'R') { /* Receiving a RESEND */
2055 debug(F101,"opena remote len","",zz->length);
2056 debug(F101,"opena local len","",rs_len);
2058 if (fncact == XYFX_R) /* and file collision = RENAME */
2060 #endif /* COMMENT */
2062 f = ofn1; /* use original name. */
2063 if (fncact == XYFX_R) /* if file collision is RENAME */
2064 ckstrncpy(filnam,ofn1,CKMAXPATH+1); /* restore the real name */
2065 xxscreen(SCR_AN,0,0L,f); /* update name on screen */
2066 if (zz->length == rs_len) /* Local and remote lengths equal? */
2067 return(-17); /* Secret code */
2069 debug(F111,"opena [file]=mode: ",f,fcb.dsp);
2070 if (x = openo(f,zz,&fcb)) { /* Try to open the file. */
2072 tlog(F110," local name:",f,0L); /* OK, open, record local name. */
2073 makestr(&prfspec,f); /* New preliminary name */
2076 tlog(F110," local name:",f,0L);
2077 makestr(&prfspec,f);
2079 { /* Log full local pathname */
2080 char *p = NULL, *q = f;
2081 if ((p = malloc(CKMAXPATH+1)))
2082 if (zfnqfp(filnam, CKMAXPATH, p))
2084 tlog(F110," local name:",q,0L);
2085 makestr(&prfspec,q);
2091 if (binary) { /* Log file mode in transaction log */
2092 tlog(F101," mode: binary","",(long) binary);
2093 } else { /* If text mode, check character set */
2094 tlog(F100," mode: text","",0L);
2097 if (fcharset > -1 && fcharset <= MAXFCSETS)
2098 tlog(F110," file character-set:",fcsinfo[fcharset].name,0L);
2099 if (tcharset > -1 && tcharset <= MAXTCSETS)
2100 tlog(F110," xfer character-set:",tcsinfo[tcharset].name,0L);
2102 tlog(F110," character-set:","transparent",0L);
2104 #endif /* NOCSETS */
2105 debug(F111,"opena charset",zz->encoding.val,zz->encoding.len);
2107 debug(F101,"opena binary","",binary);
2111 #endif /* COMMENT */
2112 xxscreen(SCR_FS,0,fsize,"");
2116 Need to turn on multi-tasking console interrupt task here, since multiple
2117 files may be received (huh?) ...
2119 if ((local) && (!quiet)) /* Only do this if local & not quiet */
2120 consta_mt(); /* Start the async read task */
2121 #endif /* datageneral */
2123 } else { /* Did not open file OK. */
2125 rf_err = ck_errstr(); /* Get system error message */
2127 xxscreen(SCR_EM,0,0l,rf_err);
2129 xxscreen(SCR_EM,0,0l,"Can't open output file");
2130 tlog(F110,"Failure to open",f,0L);
2131 tlog(F110,"Error:",rf_err,0L);
2132 debug(F110,"opena error",rf_err,0);
2134 return(x); /* Pass on return code from openo */
2137 /* O P E N C -- Open a command (in place of a file) for output */
2140 openc(n,s) int n; char * s; {
2147 debug(F111,"openc zxcmd",s,x);
2148 o_isopen = (x > 0) ? 1 : 0;
2152 /* C A N N E D -- Check if current file transfer cancelled */
2155 canned(buf) CHAR *buf; {
2156 extern int interrupted;
2157 if (*buf == 'X') cxseen = 1;
2158 if (*buf == 'Z') czseen = 1;
2159 if (czseen || cxseen)
2161 debug(F101,"canned: cxseen","",cxseen);
2162 debug(F101," czseen","",czseen);
2163 return((czseen || cxseen) ? 1 : 0);
2167 /* O P E N I -- Open an existing file for input */
2170 openi(name) char *name; {
2172 extern int fromgetpath;
2173 #endif /* NOSERVER */
2176 extern CHAR *epktmsg;
2178 epktmsg[0] = NUL; /* Initialize error message */
2179 if (memstr || sndarray) { /* Just return if "file" is memory. */
2183 debug(F110,"openi name",name,0);
2184 debug(F101,"openi sndsrc","",sndsrc);
2186 filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */
2187 debug(F101,"openi file number","",filno);
2190 /* If I'm a server and CWD is disabled and name is not from GET-PATH... */
2192 if (server && !en_cwd && !fromgetpath) {
2193 zstrip(name,&name2);
2194 if ( /* ... check if pathname included. */
2201 tlog(F110,name,"access denied",0L);
2202 debug(F110,"openi CD disabled",name,0);
2203 ckstrncpy((char *)epktmsg,"Access denied",PKTMSGLEN);
2205 } else name = name2;
2207 #endif /* NOSERVER */
2210 debug(F101,"openi pipesend","",pipesend);
2214 x = zxcmd(ZIFILE,name);
2218 i_isopen = (x > 0) ? 1 : 0;
2220 ckstrncpy((char *)epktmsg,"Command or pipe failure",PKTMSGLEN);
2221 debug(F111,"openi pipesend zxcmd",name,x);
2224 #endif /* PIPESEND */
2231 #endif /* CALIBRATE */
2233 x = zopeni(filno,name); /* Otherwise, try to open it. */
2234 debug(F111,"openi zopeni 1",name,x);
2238 } else { /* If not found, */
2239 char xname[CKMAXPATH]; /* convert the name */
2241 nzrtol(name,xname,fncnv,fnrpath,CKMAXPATH);
2243 zrtol(name,xname); /* to local form and then */
2245 x = zopeni(filno,xname); /* try opening it again. */
2246 debug(F111,"openi zopeni 2",xname,x);
2249 return(1); /* It worked. */
2253 if (s) if (!s) s = NULL;
2254 if (!s) s = "Can't open file";
2255 ckstrncpy((char *)epktmsg,s,PKTMSGLEN);
2256 tlog(F110,xname,s,0L);
2257 debug(F110,"openi failed",xname,0);
2258 debug(F110,"openi message",s,0);
2265 /* O P E N O -- Open a new file for output. */
2268 openo(name,zz,fcb) char *name; struct zattr *zz; struct filinfo *fcb; {
2276 if (stdouf) { /* Receiving to stdout? */
2277 x = zopeno(ZSTDIO,"",zz,NULL);
2279 debug(F101,"openo stdouf zopeno","",x);
2282 debug(F110,"openo: name",name,0);
2284 if (cxseen || czseen || discard) { /* If interrupted, get out before */
2285 debug(F100," open cancelled","",0); /* destroying existing file. */
2286 return(1); /* Pretend to succeed. */
2288 channel = ZOFILE; /* SET DESTINATION DISK or PRINTER */
2291 debug(F101,"openo pipesend","",pipesend);
2295 x = zxcmd(ZOFILE,(char *)srvcmd);
2300 debug(F101,"openo zxcmd","",x);
2303 #endif /* PIPESEND */
2305 if (dest == DEST_S) { /* SET DEST SCREEN... */
2311 dirp = tilde_expand(name);
2312 if (*dirp) ckstrncpy(name,dirp,CKMAXPATH+1);
2315 if (server && !en_cwd) { /* If running as server */
2316 zstrip(name,&name2); /* and CWD is disabled, */
2317 if (strcmp(name,name2)) { /* check if pathname was included. */
2318 tlog(F110,name,"authorization failure",0L);
2319 debug(F110,"openo CD disabled",name,0);
2321 } else name = name2;
2323 if (zopeno(channel,name,zz,fcb) <= 0) { /* Try to open the file */
2325 debug(F110,"openo failed",name,0);
2326 /* tlog(F110,"Failure to open",name,0L); */
2330 debug(F110,"openo ok, name",name,0);
2335 /* O P E N T -- Open the terminal for output, in place of a file */
2338 opent(zz) struct zattr *zz; {
2341 x = zopeno(ZCTERM,"",zz,NULL);
2342 debug(F101,"opent zopeno","",x);
2351 /* O P E N X -- Open nothing (incoming file to be accepted but ignored) */
2354 ckopenx(zz) struct zattr *zz; {
2355 ffc = tfc = 0L; /* Reset counters */
2357 debug(F101,"ckopenx fsize","",fsize);
2358 xxscreen(SCR_FS,0,fsize,""); /* Let screen display know the size */
2362 /* C L S I F -- Close the current input file. */
2366 extern int xferstat, success;
2369 fcps(); /* Calculate CPS quickly */
2372 if ((local) && (!quiet)) /* Only do this if local & not quiet */
2373 if (nfils < 1) /* More files to send ... leave it on! */
2375 #endif /* datageneral */
2377 debug(F101,"clsif i_isopen","",i_isopen);
2378 if (i_isopen) { /* If input file is open... */
2379 if (memstr) { /* If input was memory string, */
2380 memstr = 0; /* indicate no more. */
2382 x = zclose(ZIFILE); /* else close input file. */
2386 debug(F101,"clsif zclose","",x);
2387 debug(F101,"clsif success","",success);
2388 debug(F101,"clsif xferstat","",xferstat);
2389 debug(F101,"clsif fsize","",fsize);
2390 debug(F101,"clsif ffc","",ffc);
2391 debug(F101,"clsif cxseen","",cxseen);
2392 debug(F101,"clsif czseen","",czseen);
2393 debug(F101,"clsif discard","",czseen);
2396 if ((cxseen || czseen) && !epktsent) { /* If interrupted */
2397 xxscreen(SCR_ST,ST_INT,0l,""); /* say so */
2399 if (tralog && !tlogfmt)
2400 doxlog(what,psfspec,fsize,binary,1,"Interrupted");
2402 } else if (discard && !epktsent) { /* If I'm refusing */
2403 xxscreen(SCR_ST,ST_REFU,0l,refused); /* say why */
2405 if (tralog && !tlogfmt) {
2407 ckmakmsg(buf,128,"Refused: ",refused,NULL,NULL);
2408 doxlog(what,psfspec,fsize,binary,1,buf);
2411 } else if (!epktrcvd && !epktsent && !cxseen && !czseen) {
2415 if (sendmode == SM_RESEND || sendmode == SM_PSEND)
2417 #endif /* CK_RESEND */
2418 debug(F101,"clsif fstats","",zz);
2419 fstats(); /* Update statistics */
2420 if ( /* Was the whole file sent? */
2422 0 /* Not a reliable check in VMS */
2425 0 /* Probably not for VOS either */
2429 && ((eofmethod != XYEOF_Z && !binary) || binary)
2430 #endif /* CK_CTRLZ */
2431 #endif /* STRATUS */
2434 xxscreen(SCR_ST,ST_INT,0l,"");
2436 if (tralog && !tlogfmt)
2437 doxlog(what,psfspec,fsize,binary,1,"Incomplete");
2441 /* Not yet -- we don't have confirmation from the receiver */
2442 xxscreen(SCR_ST,ST_OK,0l,"");
2443 #endif /* COMMENT */
2445 if (tralog && !tlogfmt)
2446 doxlog(what,psfspec,fsize,binary,0,"");
2452 hcflg = 0; /* Reset flags */
2453 sendstart = 0L; /* Don't do this again! */
2456 This prevents a subsequent call to clsof() from deleting the file
2457 when given the discard flag.
2459 *filnam = '\0'; /* and current file name */
2460 #endif /* COMMENT */
2465 /* C L S O F -- Close an output file. */
2467 /* Call with disp != 0 if file is to be discarded. */
2468 /* Returns -1 upon failure to close, 0 or greater on success. */
2471 clsof(disp) int disp; {
2475 fcps(); /* Calculate CPS quickly */
2477 debug(F101,"clsof disp","",disp);
2478 debug(F101,"clsof cxseen","",cxseen);
2479 debug(F101,"clsof success","",success);
2481 debug(F101,"clsof o_isopen","",o_isopen);
2482 if (fncsav != -1) { /* Saved file collision action... */
2483 fncact = fncsav; /* Restore it. */
2484 fncsav = -1; /* Unsave it. */
2487 if ((local) && (!quiet)) /* Only do this if local & not quiet */
2489 #endif /* datageneral */
2490 if (o_isopen && !calibrate) {
2491 if ((x = zclose(ZOFILE)) < 0) { /* Try to close the file */
2492 tlog(F100,"Failure to close",filnam,0L);
2493 xxscreen(SCR_ST,ST_ERR,0l,"Can't close file");
2495 if (tralog && !tlogfmt)
2496 doxlog(what,prfspec,fsize,binary,1,"Can't close file");
2498 } else if (disp) { /* Interrupted or refused */
2499 if (keep == 0 || /* If not keeping incomplete files */
2500 (keep == SET_AUTO && binary == XYFT_T)
2502 if (*filnam && (what & W_RECV)) /* AND we're receiving */
2503 zdelet(filnam); /* ONLY THEN, delete it */
2504 if (what & W_KERMIT) {
2505 debug(F100,"clsof incomplete discarded","",0);
2506 tlog(F100," incomplete: discarded","",0L);
2507 if (!epktrcvd && !epktsent) {
2508 xxscreen(SCR_ST,ST_DISC,0l,"");
2510 if (tralog && !tlogfmt)
2511 doxlog(what,prfspec,fsize,binary,1,"Discarded");
2515 } else { /* Keep incomplete copy */
2516 debug(F100,"clsof fstats 1","",0);
2518 if (!discard) { /* Unless discarding for other reason... */
2519 if (what & W_KERMIT) {
2520 debug(F100,"closf incomplete kept","",0);
2521 tlog(F100," incomplete: kept","",0L);
2524 if (what & W_KERMIT) {
2525 if (!epktrcvd && !epktsent) {
2526 xxscreen(SCR_ST,ST_INC,0l,"");
2528 if (tralog && !tlogfmt)
2529 doxlog(what,prfspec,fsize,binary,1,"Incomplete");
2536 if (o_isopen && x > -1 && !disp) {
2537 debug(F110,"clsof OK",rfspec,0);
2538 makestr(&rfspec,prfspec);
2539 makestr(&rrfspec,prrfspec);
2541 if (!epktrcvd && !epktsent && !cxseen && !czseen) {
2542 xxscreen(SCR_ST,ST_OK,0L,"");
2544 if (tralog && !tlogfmt)
2545 doxlog(what,rfspec,fsize,binary,0,"");
2550 o_isopen = 0; /* The file is not open any more. */
2551 cxseen = 0; /* Reset per-file interruption flag */
2552 return(x); /* Send back zclose() return code. */
2556 tolower(c) char c; { return((c)-'A'+'a'); }
2557 toupper(c) char c; { return((c)-'a'+'A'); }
2558 #endif /* SUNOS4S5 */