1 /* C K C F N 3 -- Packet buffer management for C-Kermit */
2
3 /* (plus assorted functions tacked on at the end) */
4
5 /*
6 Author: Frank da Cruz <fdc@columbia.edu>,
7 Columbia University Academic Information Systems, New York City.
8
9 Copyright (C) 1985, 2010,
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.
13 */
14 /*
15 Note -- if you change this file, please amend the version number and date at
16 the top of ckcfns.c accordingly.
17 */
18
19 #include "ckcsym.h"
20 #include "ckcdeb.h"
21 #include "ckcasc.h"
22 #include "ckcker.h"
23 #include "ckcxla.h"
24
25 /* C K M K D I R -- Create a directory */
26 /*
27 Call with:
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;
33 0 means use s as is.
34 Returns:
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.
40 */
41 #ifdef CK_MKDIR
42 static char ckmkdbuf[CKMAXPATH+1];
43 #else
44 #ifdef datageneral
45 static char ckmkdbuf[CKMAXPATH+1];
46 #endif /* datageneral */
47 #endif /* CK_MKDIR */
48
49 #ifdef CK_MKDIR
50 int
ckmkdir(fc,s,r,m,cvt)51 ckmkdir(fc,s,r,m,cvt) int fc; char * s; char ** r; int m; int cvt; {
52 int x, rc = -2;
53 char tmpbuf[CKMAXPATH+1];
54 char buf2[CKMAXPATH+1];
55 if (!s) s = "";
56 debug(F110,"ckmkdir 1 fc",s,fc);
57 if (!*s) {
58 ckmakmsg(ckmkdbuf,
59 CKMAXPATH+1,
60 (fc == 0) ? "mkdir" : "rmdir",
61 ": no name given",
62 NULL,
63 NULL
64 );
65 *r = ckmkdbuf;
66 return(-2);
67 }
68 #ifdef datageneral
69 /* Come back and make this nicer later if anybody notices */
70 if (fc == 0) { /* mkdir */
71 rc = createdir(s,0);
72 } else { /* rmdir */
73 /* AOS/VS rmdir() is a no-op. */
74 ckmakmsg(tmpbuf,CKMAXPATH+1,"delete ",s,NULL,NULL);
75 debug(F110,"ckmkdir 2",tmpbuf,0);
76 rc = system(tmpbuf);
77 }
78 *r = NULL;
79 #else /* not datageneral */
80
81 /* First make sure the name has an acceptable directory-name format */
82
83 #ifdef VMS
84 {
85 char *p = s;
86 int lb = 0, rb = 0, sl = 0;
87 while (*p) {
88 if (*p == '[' || *p == '<') lb++; /* Count brackets */
89 else if (*p == ']' || *p == '>') rb++;
90 else if (*p == '/') sl++; /* and slashes */
91 p++;
92 }
93 if (lb != 1 && rb != 1 && sl == 0 && p > s && *(p-1) != ':') {
94 /* Probably just a word - convert to VMS format */
95 ckmakmsg(buf2,
96 CKMAXPATH+1,
97 "[",
98 (*s == '.') ? "" : ".",
99 s,
100 "]"
101 );
102 s = buf2;
103 } else if (lb == 0 && rb == 0 && sl != 0 && p > s && *(p-1) != ':') {
104 int flag = 0;
105 /* Seems to be in UNIX format */
106 x = strlen(s);
107 if (x > 0 && s[x-1] != '/')
108 flag = 1;
109 ckmakmsg(buf2,CKMAXPATH+1,s,flag ? "/" : "",NULL,NULL);
110 s = buf2;
111 }
112 if (s == buf2) {
113 ckstrncpy(tmpbuf,s,CKMAXPATH+1);
114 s = tmpbuf;
115 }
116 debug(F110,"ckmkdir 2+VMS",s,0);
117 }
118 #else
119 #ifdef UNIXOROSK
120 #ifdef DTILDE
121 s = tilde_expand(s);
122 #endif /* DTILDE */
123 ckstrncpy(tmpbuf,s,CKMAXPATH+1);
124 s = tmpbuf;
125 x = strlen(s);
126 if (x > 0 && s[x-1] != '/') { /* Must end in "/" for zmkdir() */
127 s[x] = '/';
128 s[x+1] = NUL;
129 debug(F110,"ckmkdir 2+UNIXOROSK",s,0);
130 }
131 #else /* UNIXOROSK */
132 #ifdef OS2
133 ckstrncpy(tmpbuf,s,CKMAXPATH+1);
134 s = tmpbuf;
135 x = strlen(s);
136 if (fc == 0 && x > 0 && s[x-1] != '/') { /* Must end in "/" for zmkdir() */
137 s[x] = '/';
138 s[x+1] = NUL;
139 debug(F110,"ckmkdir 2+OS2",s,0);
140 }
141 #endif /* OS2 */
142 #endif /* UNIXOROSK */
143 #endif /* VMS */
144 #ifdef NZLTOR
145 /* Server is calling us, so convert to local format if necessary */
146 if (cvt) {
147 nzrtol(s,(char *)buf2,1,PATH_ABS,CKMAXPATH);
148 s = buf2;
149 debug(F110,"ckmkdir 3",s,0);
150 }
151 #endif /* NZLTOR */
152 debug(F110,"ckmkdir 4",s,0);
153 if (fc == 0) { /* Making */
154 #ifdef CK_MKDIR
155 rc = zmkdir(s);
156 #else
157 #ifdef NT
158 rc = _mkdir(s);
159 #else
160 rc = mkdir(s,0777);
161 #endif /* NT */
162 #endif /* CK_MKDIR */
163 } else { /* Removing */
164 #ifdef ZRMDIR
165 rc = zrmdir(s);
166 #else
167 #ifdef NT
168 rc = _rmdir(s);
169 #else
170 #ifdef OSK
171 rc = -2;
172 #else
173 rc = rmdir(s);
174 #endif /* OSK */
175 #endif /* NT */
176 #endif /* ZRMDIR */
177 }
178 #endif /* datageneral */
179 debug(F101,"ckmkdir rc","",rc);
180 if (rc == -2) {
181 ckmakmsg(ckmkdbuf,
182 CKMAXPATH,
183 "Directory ",
184 (fc == 0) ? "creation" : "removal",
185 "not implemented in this version of C-Kermit",
186 NULL
187 );
188 *r = ckmkdbuf;
189 if (m) printf("%s\n",*r);
190 } else if (rc < 0) {
191 if (m) perror(s);
192 ckmakmsg(ckmkdbuf,CKMAXPATH,s,": ",ck_errstr(),NULL);
193 *r = ckmkdbuf;
194 } else if (fc == 0 && zfnqfp(s,CKMAXPATH,ckmkdbuf)) {
195 *r = ckmkdbuf;
196 } else if (fc != 0) {
197 ckmakmsg(ckmkdbuf,CKMAXPATH,s,": removed",NULL,NULL);
198 *r = ckmkdbuf;
199 }
200 return(rc);
201 }
202 #endif /* CK_MKDIR */
203
204 #ifndef NOXFER /* Rest of this file... */
205
206 #ifndef NODISPO
207 #ifdef pdp11
208 #define NODISPO
209 #endif /* pdpd11 */
210 #endif /* NODISPO */
211
212 extern int pipesend;
213 #ifdef PIPESEND
214 extern char ** sndfilter;
215 #endif /* PIPESEND */
216
217 extern int unkcs, wmax, wcur, discard, bctu, bctl, local, fdispla, what,
218 sendmode, opnerr, dest, epktrcvd, epktsent, filestatus, eofmethod, dispos,
219 fncnv, fnrpath;
220
221 extern char * ofn2;
222 extern char * rfspec, * sfspec, * prfspec, * psfspec, * rrfspec, * prrfspec;
223 extern char ofn1[];
224 extern int ofn1x;
225 extern char * ofperms;
226
227 #ifdef VMS
228 extern int batch;
229 #else
230 extern int backgrd;
231 #endif /* VMS */
232
233 extern int xflg, remfile, remappd;
234 extern CHAR *data;
235 extern char filnam[];
236 #ifndef NOFRILLS
237 extern int rprintf, rmailf; /* REMOTE MAIL, PRINT */
238 char optbuf[OPTBUFLEN]; /* Options for MAIL or REMOTE PRINT */
239 #endif /* NOFRILLS */
240 extern int wslots;
241 extern int fblksiz, frecl, forg, frecfm, fncact, fncsav, fcctrl, lf_opts;
242 extern CHAR * srvcmd;
243 extern int srvcmdlen;
244
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;
249
250 /* Attributes in/out enabled flags */
251
252 extern int
253 atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
254 attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
255
256 #ifdef CK_PERMS
257 extern int atlpri, atlpro, atgpri, atgpro;
258 #endif /* CK_PERMS */
259
260 #ifdef STRATUS
261 extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto;
262 #endif /* STRATUS */
263
264 #ifdef datageneral
265 extern int quiet;
266 #endif /* datageneral */
267
268 extern long filcnt;
269 extern CK_OFF_T fsize, ffc, tfc, sendstart, calibrate;
270 CK_OFF_T rs_len;
271
272 #ifndef NOCSETS
273 _PROTOTYP (VOID setxlate, (void));
274 extern int tcharset, fcharset;
275 extern int ntcsets, xlatype, xfrxla;
276 extern struct csinfo tcsinfo[], fcsinfo[];
277 #endif /* NOCSETS */
278
279 /* Variables global to Kermit that are defined in this module */
280
281 #ifdef CKXXCHAR /* DOUBLE / IGNORE char table */
282 int dblflag = 0;
283 int ignflag = 0;
284 short dblt[256] = {
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,
291 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 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
293 };
294 #endif /* CKXXCHAR */
295
296 int winlo; /* packet number at low window edge */
297
298 int sbufnum; /* number of free buffers */
299 int dum001 = 1234; /* protection... */
300 int sbufuse[MAXWS]; /* buffer in-use flag */
301 int dum003 = 1111;
302 int rbufnum; /* number of free buffers */
303 int dum002 = 4321; /* more protection */
304 int rbufuse[MAXWS]; /* buffer in-use flag */
305 int sseqtbl[64]; /* sequence # to buffer # table */
306 int rseqtbl[64]; /* sequence # to buffer # table */
307 int sacktbl[64]; /* sequence # ack table */
308
309 int o_isopen = 0, i_isopen = 0; /* Input & output files are open */
310
311 #ifdef DYNAMIC
312 struct pktinfo *s_pkt = NULL; /* array of pktinfo structures */
313 struct pktinfo *r_pkt = NULL; /* array of pktinfo structures */
314 #else
315 struct pktinfo s_pkt[MAXWS]; /* array of pktinfo structures */
316 struct pktinfo r_pkt[MAXWS]; /* array of pktinfo structures */
317 #endif /* DYNAMIC */
318
319 #ifdef DEBUG
320 char xbuf[200]; /* For debug logging */
321 #endif /* DEBUG */
322
323 #ifdef DYNAMIC
324 CHAR *bigsbuf = NULL, *bigrbuf = NULL;
325 #else
326 char bigsbt[8]; /* Protection (shouldn't need this). */
327 /* BUT DON'T REMOVE IT! */
328 CHAR bigsbuf[SBSIZ + 5]; /* Send-packet buffer area */
329 char bigrbt[8]; /* Safety padding */
330 CHAR bigrbuf[RBSIZ + 5]; /* Receive-packet area */
331 #endif
332 int bigsbsiz = SBSIZ; /* Sizes of big send & rcv buffers. */
333 int bigrbsiz = RBSIZ;
334
335 #ifdef VMS
336 int zchkpath(char *s);
337 #endif /* VMS */
338
339 /* FUNCTIONS */
340
341 VOID
dofast()342 dofast() {
343 long maxbufsiz = RBSIZ; /* Configuration parameters */
344 int maxpktsiz = MAXSP;
345 extern int spsizf, /* For bug in IRIX Telnet server */
346 rpsiz, urpsiz, spsizr, spmax, wslotr;
347 extern struct ck_p ptab[];
348
349 if (maxpktsiz < 40) /* Long packet length */
350 maxpktsiz = 40;
351 else if (maxpktsiz > 4000)
352 maxpktsiz = 4000;
353 wslotr = maxbufsiz / maxpktsiz;
354 if (wslotr > MAXWS) /* Window slots */
355 wslotr = MAXWS;
356 if (wslotr > 30)
357 wslotr = 30;
358 else if (wslotr < 1)
359 wslotr = 1;
360 urpsiz = adjpkl(maxpktsiz,wslotr,maxbufsiz);
361 ptab[PROTO_K].rpktlen = urpsiz;
362 rpsiz = (urpsiz > 94) ? 94 : urpsiz; /* Max non-long packet length */
363 debug(F111,"dofast","uprsiz",urpsiz);
364 #ifdef IRIX
365 #ifndef IRIX65
366 /* IRIX Telnet server chops off writes longer than 4K */
367 spsiz = spmax = spsizr = urpsiz;
368 debug(F101,"doarg Q IRIX spsiz","",spsiz);
369 spsizf = 1;
370 #endif /* IRIX65 */
371 #endif /* IRIX */
372 #ifdef CK_SPEED
373 setprefix(PX_CAU); /* Cautious unprefixing */
374 #endif /* CK_SPEED */
375 }
376
377
378 /* For sanity, use "i" for buffer slots, "n" for packet numbers. */
379
380 /* I N I B U F S */
381
382 /*
383 Allocates the big send and receive buffers.
384 Call with size for big send buffer (s) and receive buffer (r).
385 These sizes can be different.
386 Attempts to allocate buffers of the requested size, but if it can't,
387 it will allocate smaller ones.
388 Sets global variables bigsbsiz and bigrbsiz to the actual sizes,
389 and bigsbuf and bigrbuf pointing to the actual buffers.
390 Designed to be called more than once.
391 Returns 0 on success, -1 on failure.
392 */
393
394 CHAR *bigbufp = NULL;
395
396 int
inibufs(s,r)397 inibufs(s,r) int s, r; {
398 #ifdef DYNAMIC
399 unsigned
400 int size;
401 #ifdef OS2
402 unsigned /* Don't you wish everybody had unsigned long... */
403 #endif /* OS2 */
404 long z;
405 int x;
406
407 debug(F101,"inibufs s","",s);
408 debug(F101,"inibufs r","",r);
409
410 if (s < 80 || r < 80) return(-1); /* Validate arguments. */
411
412 if (!s_pkt) { /* Allocate packet info structures */
413 if (!(s_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
414 fatal("ini_pkts: no memory for s_pkt");
415 }
416 for (x = 0; x < MAXWS; x++)
417 s_pkt[x].pk_adr = NULL; /* Initialize addresses */
418
419 if (!r_pkt) {
420 if (!(r_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
421 fatal("ini_pkts: no memory for s_pkt");
422 }
423 for (x = 0; x < MAXWS; x++)
424 r_pkt[x].pk_adr = NULL; /* Initialize addresses */
425
426 if (!srvcmd) { /* Allocate srvcmd buffer */
427 srvcmd = (CHAR *) malloc(r + 100);
428 if (!srvcmd) return(-1);
429 srvcmdlen = r + 99;
430 *srvcmd = NUL;
431 }
432 if (bigbufp) { /* Free previous buffers, if any. */
433 free(bigbufp);
434 bigbufp = NULL;
435 }
436 size = s + r + 40; /* Combined requested size + padding */
437 z = (unsigned) s + (unsigned) r + 40;
438 debug(F101,"inibufs size 1","",size);
439 debug(F101,"inibufs size z","",z);
440 if ((long) size != z) {
441 debug(F100,"inibufs overflow","",0);
442 size = 65535;
443 }
444
445 /* Try to get the space. If malloc fails, try to get a little less. */
446 /* (Obviously, this algorithm can be refined.) */
447
448 while (!(bigbufp = (CHAR *) malloc(size))) {
449 debug(F101,"inibufs bigbuf malloc failed","",size);
450 size = (size * 2) / 3; /* Failed, cut size by 1/3. */
451 if (size < 200) /* Try again until too small. */
452 return(-1);
453 }
454 debug(F101,"inibufs size 2","",size); /* OK, we got some space. */
455
456 /*
457 Now divide the allocated space between the send and receive buffers in the
458 requested proportion. The natural formula would be (s / (s + r)) * size
459 (for the send buffer), but that doesn't work with integer arithmetic and we
460 can't use floating point because some machines don't have it. This can be
461 rearranged as (s * size) / (s + r). But (s * size) can be VERY large, too
462 large for 32 bits. So let's do it this way. This arithmetic works for
463 buffer sizes up to about 5,000,000.
464 */
465 #define FACTOR 20L
466 z = ( (long) s * FACTOR ) / ( (long) s + (long) r );
467 x = ( z * ( (long) size / FACTOR ) );
468 if (x < 0) return(-1); /* Catch overflow */
469
470 bigsbsiz = x - 5; /* Size of send buffer */
471 bigsbuf = bigbufp; /* Address of send buffer */
472 debug(F101,"inibufs bigsbsiz","",bigsbsiz);
473
474 bigrbsiz = size - x - 5; /* Size of receive buffer */
475 bigrbuf = bigbufp + x; /* Addresss of receive buffer */
476 debug(F101,"inibufs bigrbsiz","",bigrbsiz);
477
478 return(0); /* Success */
479 #else /* No dynamic allocation */
480 bigsbsiz = SBSIZ; /* Just use the symbols */
481 bigrbsiz = RBSIZ; /* ... */
482 return(0); /* Success. */
483 #endif /* DYNAMIC */
484 }
485
486
487 /* M A K E B U F -- Makes and clears a new buffers. */
488
489 /* Call with: */
490 /* slots: number of buffer slots to make, 1 to 32 */
491 /* bufsiz: size of the big buffer */
492 /* buf: address of the big buffer */
493 /* xx: pointer to array of pktinfo structures for these buffers */
494
495 /* Subdivides the big buffer into "slots" buffers. */
496
497 /* Returns: */
498 /* -1 if too many or too few slots requested, */
499 /* -2 if slots would be too small. */
500 /* n (positive) on success = size of one buffer. */
501 /* with pktinfo structure initialized for this set of buffers. */
502
503 int
makebuf(slots,bufsiz,buf,xx)504 makebuf(slots,bufsiz,buf,xx)
505 /* makebuf */ int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; {
506
507 CHAR *a;
508 int i, size;
509
510 debug(F101,"makebuf","",slots);
511 debug(F101,"makebuf bufsiz","",bufsiz);
512 debug(F101,"makebuf MAXWS","",MAXWS);
513
514 if (slots > MAXWS || slots < 1) return(-1);
515 if (bufsiz < slots * 10 ) return(-2);
516
517 size = bufsiz / slots; /* Divide up the big buffer. */
518 a = buf; /* Address of first piece. */
519
520 for (i = 0; i < slots; i++) {
521 struct pktinfo *x = &xx[i];
522 x->bf_adr = a; /* Address of this buffer */
523 x->bf_len = size; /* Length of this buffer */
524 x->pk_len = 0; /* Length of data field */
525 x->pk_typ = ' '; /* packet type */
526 x->pk_seq = -1; /* packet sequence number */
527 x->pk_rtr = 0; /* retransmissions */
528 *a = '\0'; /* Clear the buffer */
529 a += size; /* Position to next buffer slot */
530 }
531 return(size);
532 }
533
534 /* M A K S B U F -- Makes the send-packet buffer */
535
536 int
mksbuf(slots)537 mksbuf(slots) int slots; {
538 int i, x;
539 sbufnum = 0;
540 if ((x = makebuf(slots,bigsbsiz,bigsbuf,s_pkt)) < 0) {
541 debug(F101,"mksbuf makebuf return","",x);
542 return(x);
543 }
544 debug(F101,"mksbuf makebuf return","",x);
545 for (i = 0; i < 64; i++) { /* Initialize sequence-number- */
546 sseqtbl[i] = -1; /* to-buffer-number table. */
547 sacktbl[i] = 0;
548 }
549 for (i = 0; i < MAXWS; i++)
550 sbufuse[i] = 0; /* Mark each buffer as free */
551 sbufnum = slots;
552 wcur = 0;
553 return(x);
554 }
555
556 /* M A K R B U F -- Makes the receive-packet buffer */
557
558 int
mkrbuf(slots)559 mkrbuf(slots) int slots; {
560 int i, x;
561 rbufnum = 0;
562 if ((x = makebuf(slots,bigrbsiz,bigrbuf,r_pkt)) < 0) {
563 debug(F101,"mkrbuf makebuf return","",x);
564 return(x);
565 }
566 debug(F101,"mkrbuf makebuf return","",x);
567 for (i = 0; i < 64; i++) { /* Initialize sequence-number- */
568 rseqtbl[i] = -1; /* to-buffer-number table. */
569 }
570 for (i = 0; i < MAXWS; i++)
571 rbufuse[i] = 0; /* Mark each buffer as free */
572 rbufnum = slots;
573 wcur = 0;
574 return(x);
575 }
576
577 /* W I N D O W -- Resize the window to n */
578
579 int
window(n)580 window(n) int n; {
581 debug(F101,"window","",n);
582 if (n < 1 || n > MAXWS) return(-1);
583 if (mksbuf(n) < 0) return(-1);
584 if (mkrbuf(n) < 0) return(-1);
585 wslots = n;
586 #ifdef DEBUG
587 if (deblog) dumpsbuf();
588 if (deblog) dumprbuf();
589 #endif /* DEBUG */
590 return(0);
591 }
592
593 /* G E T S B U F -- Allocate a send-buffer. */
594
595 /* Call with packet sequence number to allocate buffer for. */
596 /* Returns: */
597 /* -4 if argument is invalid (negative, or greater than 63) */
598 /* -3 if buffers were thought to be available but really weren't (bug!) */
599 /* -2 if the number of free buffers is negative (bug!) */
600 /* -1 if no free buffers. */
601 /* 0 or positive, packet sequence number, with buffer allocated for it. */
602
603 int
getsbuf(n)604 getsbuf(n) int n; { /* Allocate a send-buffer */
605 int i;
606 CHAR * p = NULL;
607 if (n < 0 || n > 63) {
608 debug(F101,"getsbuf bad arg","",n);
609 return(-4); /* Bad argument */
610 }
611 debug(F101,"getsbuf packet","",n);
612 /* debug(F101,"getsbuf, sbufnum","",sbufnum); */
613 if (sbufnum == 0) return(-1); /* No free buffers. */
614 if (sbufnum < 0) return(-2); /* Shouldn't happen. */
615 for (i = 0; i < wslots; i++) /* Find the first one not in use. */
616 if (sbufuse[i] == 0) { /* Got one? */
617 sbufuse[i] = 1; /* Mark it as in use. */
618 sbufnum--; /* One less free buffer. */
619 *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
620 s_pkt[i].pk_seq = n; /* Put in the sequence number */
621 sseqtbl[n] = i; /* Back pointer from sequence number */
622 sacktbl[n] = 0; /* ACK flag */
623 s_pkt[i].pk_len = 0; /* Data field length now zero. */
624 s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
625 s_pkt[i].pk_rtr = 0; /* Zero the retransmission count */
626 p = s_pkt[i].bf_adr + 7; /* Set global "data" address. */
627 debug(F101,"getsbuf p","",0);
628 data = p;
629 if (!data) {
630 debug(F100,"getsbuf data == NULL","",0);
631 return(-3);
632 }
633 if ((what & (W_SEND|W_REMO)) && (++wcur > wmax))
634 wmax = wcur; /* For statistics. */
635 /* debug(F101,"getsbuf wcur","",wcur); */
636 return(n); /* Return its index. */
637 }
638 sbufnum = 0; /* Didn't find one. */
639 return(-3); /* Shouldn't happen! */
640 }
641
642 int
getrbuf()643 getrbuf() { /* Allocate a receive buffer */
644 int i;
645 #ifdef COMMENT
646 /* This code is pretty stable by now... */
647 /* Looks like we might need this after all */
648 debug(F101,"getrbuf rbufnum","",rbufnum);
649 debug(F101,"getrbuf wslots","",wslots);
650 debug(F101,"getrbuf dum002","",dum002);
651 debug(F101,"getrbuf dum003","",dum003);
652 #endif /* COMMENT */
653 if (rbufnum == 0) return(-1); /* No free buffers. */
654 if (rbufnum < 0) return(-2); /* Shouldn't happen. */
655 for (i = 0; i < wslots; i++) /* Find the first one not in use. */
656 if (rbufuse[i] == 0) { /* Got one? */
657 rbufuse[i] = 1; /* Mark it as in use. */
658 *r_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
659 rbufnum--; /* One less free buffer. */
660 debug(F101,"getrbuf new rbufnum","",rbufnum);
661 if ((what & W_RECV) && (++wcur > wmax))
662 wmax = wcur; /* For statistics. */
663 /* debug(F101,"getrbuf wcur","",wcur); */
664 return(i); /* Return its index. */
665 }
666 /* debug(F101,"getrbuf foulup","",i); */
667 rbufnum = 0; /* Didn't find one. */
668 return(-3); /* Shouldn't happen! */
669 }
670
671 /* F R E E S B U F -- Free send-buffer for given packet sequence number */
672
673 /* Returns: */
674 /* 1 upon success */
675 /* -1 if specified buffer does not exist */
676
677 int
freesbuf(n)678 freesbuf(n) int n; { /* Release send-buffer for packet n. */
679 int i;
680
681 debug(F101,"freesbuf","",n);
682 if (n < 0 || n > 63) /* No such packet. */
683 return(-1);
684 i = sseqtbl[n]; /* Get the window slot number. */
685 if (i > -1 && i <= wslots) {
686 sseqtbl[n] = -1; /* If valid, remove from seqtbl */
687 sbufnum++; /* and count one more free buffer */
688 sbufuse[i] = 0; /* and mark it as free, */
689 if (what & (W_SEND|W_REMO)) /* decrement active slots */
690 wcur--; /* for statistics and display. */
691 } else {
692 debug(F101," sseqtbl[n]","",sseqtbl[n]);
693 return(-1);
694 }
695
696 /* The following is done only so dumped buffers will look right. */
697
698 if (1) {
699 *s_pkt[i].bf_adr = '\0'; /* Zero the buffer data field */
700 s_pkt[i].pk_seq = -1; /* Invalidate the sequence number */
701 s_pkt[i].pk_len = 0; /* Data field length now zero. */
702 s_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
703 s_pkt[i].pk_rtr = 0; /* And the retries field. */
704 }
705 return(1);
706 }
707
708 int
freerbuf(i)709 freerbuf(i) int i; { /* Release receive-buffer slot "i". */
710 int n;
711
712 /* NOTE !! Currently, this function frees the indicated buffer, but */
713 /* does NOT erase the data. The program counts on this. Will find a */
714 /* better way later.... */
715
716 /* debug(F101,"freerbuf, slot","",i); */
717 if (i < 0 || i >= wslots) { /* No such slot. */
718 debug(F101,"freerbuf no such slot","",i);
719 return(-1);
720 }
721 n = r_pkt[i].pk_seq; /* Get the packet sequence number */
722 debug(F101,"freerbuf packet","",n);
723 if (n > -1 && n < 64) /* If valid, remove from seqtbl */
724 rseqtbl[n] = -1;
725 if (rbufuse[i] != 0) { /* If really allocated, */
726 rbufuse[i] = 0; /* mark it as free, */
727 rbufnum++; /* and count one more free buffer. */
728 if (what & W_RECV) /* Keep track of current slots */
729 wcur--; /* for statistics and display */
730 debug(F101,"freerbuf rbufnum","",rbufnum);
731 }
732
733 /* The following is done only so dumped buffers will look right. */
734
735 if (1) {
736 /* *r_pkt[i].bf_adr = '\0'; */ /* Zero the buffer data field */
737 r_pkt[i].pk_seq = -1; /* And from packet list */
738 r_pkt[i].pk_len = 0; /* Data field length now zero. */
739 r_pkt[i].pk_typ = ' '; /* Blank the packet type too. */
740 r_pkt[i].pk_rtr = 0; /* And the retries field. */
741 }
742 return(1);
743 }
744
745 /* This is like freerbuf, except it's called with a packet sequence number */
746 /* rather than a packet buffer index. */
747
748 VOID
freerpkt(seq)749 freerpkt(seq) int seq; {
750 int k;
751 debug(F101,"freerpkt seq","",seq);
752 k = rseqtbl[seq];
753 /* debug(F101,"freerpkt k","",k); */
754 if (k > -1) {
755 k = freerbuf(k);
756 /* debug(F101,"freerpkt freerbuf","",k); */
757 }
758 }
759
760
761 /* C H K W I N -- Check if packet n is in window. */
762
763 /* Returns: */
764 /* 0 if it is in the current window, */
765 /* +1 if it would have been in previous window (e.g. if ack was lost), */
766 /* -1 if it is outside any window (protocol error), */
767 /* -2 if either of the argument packet numbers is out of range. */
768
769 /* Call with packet number to check (n), lowest packet number in window */
770 /* (bottom), and number of slots in window (slots). */
771
772 int
chkwin(n,bottom,slots)773 chkwin(n,bottom,slots) int n, bottom, slots; {
774 int top, prev;
775
776 debug(F101,"chkwin packet","",n);
777 debug(F101,"chkwin winlo","",bottom);
778 debug(F101,"chkwin slots","",slots);
779
780 /* First do the easy and common cases, where the windows are not split. */
781
782 if (n < 0 || n > 63 || bottom < 0 || bottom > 63)
783 return(-2);
784
785 if (n == bottom) return(0); /* In a perfect world... */
786
787 top = bottom + slots; /* Calculate window top. */
788 if (top < 64 && n < top && n >= bottom)
789 return(0); /* In current window. */
790
791 prev = bottom - slots; /* Bottom of previous window. */
792 if (prev > -1 && n < bottom && n > prev)
793 return(1); /* In previous. */
794
795 /* Now consider the case where the current window is split. */
796
797 if (top > 63) { /* Wraparound... */
798 top -= 64; /* Get modulo-64 sequence number */
799 if (n < top || n >= bottom) {
800 return(0); /* In current window. */
801 } else { /* Not in current window. */
802 if (n < bottom && n >= prev) /* Previous window can't be split. */
803 return(1); /* In previous window. */
804 else
805 return(-1); /* Not in previous window. */
806 }
807 }
808
809 /* Now the case where current window not split, but previous window is. */
810
811 if (prev < 0) { /* Is previous window split? */
812 prev += 64; /* Yes. */
813 if (n < bottom || n >= prev)
814 return(1); /* In previous window. */
815 } else { /* Previous window not split. */
816 if (n < bottom && n >= prev)
817 return(1); /* In previous window. */
818 }
819
820 /* It's not in the current window, and not in the previous window... */
821
822 return(-1); /* So it's not in any window. */
823 }
824
825 int
dumpsbuf()826 dumpsbuf() { /* Dump send-buffers */
827 #ifdef DEBUG
828 int j, x, z; /* to debug log. */
829
830 if (! deblog) return(0);
831 x = zsoutl(ZDFILE,"SEND BUFFERS:");
832 if (x < 0) {
833 deblog = 0;
834 return(0);
835 }
836 x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
837 if (x < 0) {
838 deblog = 0;
839 return(0);
840 }
841 for (j = 0; j < wslots; j++) {
842 if (!sbufuse[j])
843 continue;
844 z = ((unsigned long)(s_pkt[j].bf_adr)) & 0xffff;
845
846 sprintf(xbuf, /* safe (200) */
847 "%4d%6d%10d%5d%6d%4c%5d%6d\n",
848 j,
849 sbufuse[j],
850 /* Avoid warnings when addresses are bigger than ints */
851 z,
852 s_pkt[j].bf_len,
853 s_pkt[j].pk_len,
854 s_pkt[j].pk_typ,
855 s_pkt[j].pk_seq,
856 s_pkt[j].pk_rtr
857 );
858 if (zsout(ZDFILE,xbuf) < 0) {
859 deblog = 0;
860 return(0);
861 }
862 if (s_pkt[j].pk_adr) {
863 x = (int)strlen((char *) s_pkt[j].pk_adr);
864 if (x)
865 sprintf(xbuf, /* safe (checked) */
866 "[%.72s%s]\n",s_pkt[j].pk_adr, x > 72 ? "..." : "");
867 else
868 sprintf(xbuf,"[(empty string)]\n"); /* safe (200) */
869 } else {
870 sprintf(xbuf,"[(null pointer)]\n"); /* safe (200) */
871 }
872 if (zsout(ZDFILE,xbuf) < 0) {
873 deblog = 0;
874 return(0);
875 }
876 }
877 sprintf(xbuf,"free: %d, winlo: %d\n", sbufnum, winlo); /* safe (200) */
878 if (zsout(ZDFILE,xbuf) < 0) {
879 deblog = 0;
880 return(0);
881 }
882 #endif /* DEBUG */
883 return(0);
884 }
885 int
dumprbuf()886 dumprbuf() { /* Dump receive-buffers */
887 #ifdef DEBUG
888 int j, x, z;
889 if (! deblog) return(0);
890 if (zsoutl(ZDFILE,"RECEIVE BUFFERS:") < 0) {
891 deblog = 0;
892 return(0);
893 }
894 x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
895 if (x < 0) {
896 deblog = 0;
897 return(0);
898 }
899 for ( j = 0; j < wslots; j++ ) {
900 if (!rbufuse[j])
901 continue;
902 z = ((unsigned long)(r_pkt[j].bf_adr)) & 0xffff;
903 sprintf(xbuf, /* 200, safe */
904 "%4d%6d%10d%5d%6d%4c%5d%6d\n",
905 j,
906 rbufuse[j],
907 /* Avoid warnings when addresses are bigger than ints */
908 z,
909 r_pkt[j].bf_len,
910 r_pkt[j].pk_len,
911 r_pkt[j].pk_typ,
912 r_pkt[j].pk_seq,
913 r_pkt[j].pk_rtr
914 );
915 if (zsout(ZDFILE,xbuf) < 0) {
916 deblog = 0;
917 return(0);
918 }
919 x = (int)strlen((char *)r_pkt[j].bf_adr);
920 sprintf(xbuf, /* safe (checked) */
921 "[%.72s%s]\n",r_pkt[j].bf_adr, x > 72 ? "..." : "");
922 if (zsout(ZDFILE,xbuf) < 0) {
923 deblog = 0;
924 return(0);
925 }
926 }
927 sprintf(xbuf,"free: %d, winlo: %d\n", rbufnum, winlo); /* safe (200) */
928 if (zsout(ZDFILE,xbuf) < 0) {
929 deblog = 0;
930 return(0);
931 }
932 #endif /* DEBUG */
933 return(0);
934 }
935
936 /* S A T T R -- Send an Attribute Packet */
937
938 /*
939 Sends attribute packet(s) for the current file. If the info will not
940 fit into one packet, it can be called repeatedly until all the fields
941 that will fit are sent.
942
943 Call with:
944 xp == 0 if we're sending a real file (F packet), or:
945 xp != 0 for screen data (X packet).
946 And:
947 flag == 1 for first A packet
948 flag == 0 for subsequent A packets.
949 Returns:
950 1 or greater if an A packet was sent, or:
951 0 if an S-packet was not sent because there was no data to send or
952 there was no data left that was short enough to send, or:
953 -1 on any kind of error.
954 */
955
956 /* (don't) #define TSOFORMAT */
957 /* which was only for making C-Kermit send TSO-Kermit-like A packets */
958 /* to try to track down a problem somebody reported... */
959
960 int
sattr(xp,flag)961 sattr(xp, flag) int xp, flag; { /* Send Attributes */
962
963 static int max; /* Maximum length for Attributes */
964 static short done[95]; /* Field-complete array */
965 static struct zattr x; /* File attribute struct */
966 static char xdate[24];
967
968 extern char * cksysid;
969
970 /* Some extra flags are used because the "done" array is sparse */
971
972 int i, j, rc, aln, left = 0, numset = 0, xbin = 0; /* Workers */
973 int notafile = 0;
974 char *tp, c;
975
976 notafile = sndarray || pipesend ||
977 #ifdef PIPESEND
978 sndfilter ||
979 #endif /* PIPESEND */
980 calibrate;
981
982 debug(F101,"sattr flag","",flag);
983 if (!flag) /* No more attributes to send */
984 if (done[xunchar('@')])
985 return(0);
986
987 /* Initialize Attribute mechanism */
988
989 if (flag) { /* First time here for this file? */
990 initattr(&x); /* Blank out all the fields. */
991 for (j = 0; j < 95; j++) /* Init array of completed fields */
992 done[j] = 0;
993 max = maxdata(); /* Get maximum data field length */
994 if (notafile || xp == 1) { /* Is it not a real file? */
995 extern char * zzndate();
996 char * p;
997 int i;
998 #ifdef CALIBRATE
999 if (calibrate) { /* Calibration run... */
1000 x.lengthk = calibrate / 1024L; /* We know the length */
1001 x.length = calibrate;
1002 }
1003 #endif /* CALIBRATE */
1004 x.systemid.val = cksysid; /* System ID */
1005 x.systemid.len = (int)strlen(cksysid);
1006 ckstrncpy(xdate,zzndate(),24);
1007 xdate[8] = SP;
1008 ztime(&p);
1009 for (i = 11; i < 19; i++) /* copy hh:mm:ss */
1010 xdate[i - 2] = p[i]; /* to xdate */
1011 xdate[17] = NUL; /* terminate */
1012 x.date.val = xdate;
1013 x.date.len = 17;
1014 debug(F111,"sattr notafile date",x.date.val,x.date.len);
1015 } else { /* Real file */
1016 rc = zsattr(&x); /* Get attributes for this file */
1017 debug(F101,"sattr zsattr","",rc);
1018 if (rc < 0) /* Can't get 'em so don't send 'em */
1019 return(0);
1020 debug(F101,"sattr init max","",max);
1021 }
1022 }
1023 if (nxtpkt() < 0) /* Got 'em, get next packet number */
1024 return(-1); /* Bad news if we can't */
1025
1026 i = 0; /* Init data field character number */
1027
1028 /* Do each attribute using first-fit method, marking as we go */
1029 /* This is rather long and repititious - could be done more cleverly */
1030
1031 if (atsido && !done[xunchar(c = '.')]) { /* System type */
1032 if (max - i >= x.systemid.len + 2) { /* Enough space ? */
1033 data[i++] = c; /* Yes, add parameter */
1034 data[i++] = tochar(x.systemid.len); /* Add length */
1035 for (j = 0; j < x.systemid.len; j++) /* Add data */
1036 data[i++] = x.systemid.val[j];
1037 numset++; /* Count that we did at least one */
1038 done[xunchar(c)] = 1; /* Mark this attribute as done */
1039 } else /* No */
1040 left++; /* so mark this one left to do */
1041 }
1042 #ifdef STRATUS
1043 if (atcreo && !done[xunchar(c = '$')]) { /* Creator */
1044 if (max - i >= x.creator.len + 2) { /* Enough space ? */
1045 data[i++] = c;
1046 data[i++] = tochar(x.creator.len);
1047 for (j = 0; j < x.creator.len; j++)
1048 data[i++] = x.creator.val[j];
1049 numset++;
1050 done[xunchar(c)] = 1;
1051 } else
1052 left++;
1053 }
1054 if (atacto && !done[xunchar(c = '%')]) { /* File account */
1055 if (max - i >= x.account.len + 2) {
1056 data[i++] = c;
1057 data[i++] = tochar(x.account.len);
1058 for (j = 0; j < x.account.len; j++)
1059 data[i++] = x.account.val[j];
1060 numset++;
1061 done[xunchar(c)] = 1;
1062 } else
1063 left++;
1064 }
1065 if (atfrmo && !done[xunchar(c = '/')]) { /* Packet data format */
1066 if (max - i >= x.recfm.len + 2) {
1067 data[i++] = c;
1068 data[i++] = tochar(x.recfm.len); /* Copy from attr structure */
1069 for (j = 0; j < x.recfm.len; j++)
1070 data[i++] = x.recfm.val[j];
1071 numset++;
1072 done[xunchar(c)] = 1;
1073 } else
1074 left++;
1075 }
1076 #endif /* STRATUS */
1077
1078 xbin = /* Is the transfer in binary mode? */
1079 #ifdef VMS
1080 binary == XYFT_I || binary == XYFT_L || /* IMAGE or LABELED */
1081 !strncmp(x.recfm.val,"F",1) /* or RECFM=Fxxxxxx */
1082 #else
1083 binary /* User said SET FILE TYPE BINARY */
1084 #endif /* VMS */
1085 ;
1086
1087 if (attypo && !done[xunchar(c = '"')]) { /* File type */
1088 if (max - i >= 5) { /* Max length for this field */
1089 data[i++] = c;
1090 if (xbin) { /* Binary */
1091 data[i++] = tochar(2); /* Two characters */
1092 data[i++] = 'B'; /* B for Binary */
1093 data[i++] = '8'; /* 8-bit bytes (note assumption...) */
1094 #ifdef CK_LABELED
1095 if (binary != XYFT_L
1096 #ifdef VMS
1097 && binary != XYFT_I
1098 #endif /* VMS */
1099 )
1100 binary = XYFT_B;
1101 #endif /* CK_LABELED */
1102 } else { /* Text */
1103 #ifdef TSOFORMAT
1104 data[i++] = tochar(1); /* One character */
1105 data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */
1106 #else
1107 data[i++] = tochar(3); /* Three characters */
1108 data[i++] = 'A'; /* A = (extended) ASCII with CRLFs */
1109 data[i++] = 'M'; /* M for carriage return */
1110 data[i++] = 'J'; /* J for linefeed */
1111 #endif /* TSOFORMAT */
1112
1113 #ifdef VMS
1114 binary = XYFT_T; /* We automatically detected text */
1115 #endif /* VMS */
1116 }
1117 numset++;
1118 done[xunchar(c)] = 1;
1119 } else
1120 left++;
1121 }
1122
1123 #ifdef TSOFORMAT
1124 if (attypo && !xbin && !done[xunchar(c = '/')]) { /* Record format */
1125 if (max - i >= 5) {
1126 data[i++] = c;
1127 data[i++] = tochar(3); /* Three characters */
1128 data[i++] = 'A'; /* A = variable with CRLFs */
1129 data[i++] = 'M'; /* M for carriage return */
1130 data[i++] = 'J'; /* J for linefeed */
1131 }
1132 }
1133 #endif /* TSOFORMAT */
1134
1135 if (attypo && !xbin && !done[xunchar(c = '*')]) { /* Text encoding */
1136 #ifdef NOCSETS
1137 if (max - i >= 3) {
1138 data[i++] = c;
1139 data[i++] = tochar(1); /* Length of value is 1 */
1140 data[i++] = 'A'; /* A for ASCII */
1141 numset++;
1142 done[xunchar(c)] = 1;
1143 } else
1144 left++;
1145 #else
1146 if (tcharset == TC_TRANSP || !xfrxla) { /* Transfer character set */
1147 if (max - i >= 3) {
1148 data[i++] = c; /* Encoding */
1149 data[i++] = tochar(1); /* Length of value is 1 */
1150 data[i++] = 'A'; /* A for ASCII (i.e. text) */
1151 numset++;
1152 done[xunchar(c)] = 1;
1153 } else
1154 left++;
1155 } else {
1156 tp = tcsinfo[tcharset].designator;
1157 if (!tp) tp = "";
1158 aln = strlen(tp);
1159 if (aln > 0) {
1160 if (max - i >= aln + 2) {
1161 data[i++] = c; /* Encoding */
1162 data[i++] = tochar(aln+1); /* Length of designator. */
1163 data[i++] = 'C'; /* Text in specified charset. */
1164 for (j = 0; j < aln; j++) /* Copy designator */
1165 data[i++] = *tp++; /* Example: *&I6/100 */
1166 numset++;
1167 done[xunchar(c)] = 1;
1168 } else
1169 left++;
1170 } else
1171 done[xunchar(c)] = 1;
1172 }
1173 #endif /* NOCSETS */
1174 }
1175 if (atdato && !done[xunchar(c = '#')] && /* Creation date, if any */
1176 (aln = x.date.len) > 0) {
1177 if (max - i >= aln + 2) {
1178 data[i++] = c;
1179 data[i++] = tochar(aln);
1180 for (j = 0; j < aln; j++)
1181 data[i++] = x.date.val[j];
1182 numset++;
1183 done[xunchar(c)] = 1;
1184 } else
1185 left++;
1186 }
1187 /* File length in K */
1188 if (atleno && !done[xunchar(c = '!')] && x.lengthk > (CK_OFF_T)-1) {
1189 #ifdef COMMENT
1190 sprintf((char *) &data[i+2],"%ld",x.lengthk); /* safe */
1191 #else
1192 ckstrncpy((char *)&data[i+2],ckfstoa(x.lengthk),32);
1193 #endif /* COMMENT */
1194 aln = (int)strlen((char *)(data+i+2));
1195 if (max - i >= aln + 2) {
1196 data[i] = c;
1197 data[i+1] = tochar(aln);
1198 i += aln + 2;
1199 numset++;
1200 done[xunchar(c)] = 1;
1201 } else {
1202 data[i] = NUL;
1203 left++;
1204 }
1205 }
1206 /* File length in bytes */
1207 if (atleno && !done[xunchar(c = '1')] && x.length > (CK_OFF_T)-1) {
1208 #ifdef COMMENT
1209 sprintf((char *) &data[i+2],"%ld",x.length); /* safe */
1210 #else
1211 ckstrncpy((char *)&data[i+2],ckfstoa(x.length),32);
1212 #endif /* COMMENT */
1213 aln = (int)strlen((char *)(data+i+2));
1214 if (max - i >= aln + 2) {
1215 data[i] = c;
1216 data[i+1] = tochar(aln);
1217 i += aln + 2;
1218 numset++;
1219 done[xunchar(c)] = 1;
1220 } else {
1221 data[i] = NUL;
1222 left++;
1223 }
1224 }
1225 #ifdef CK_PERMS
1226 if (atlpro && !done[xunchar(c = ',')] && /* Local protection */
1227 (aln = x.lprotect.len) > 0 && !notafile && xp == 0) {
1228 if (max - i >= aln + 2) {
1229 data[i++] = c;
1230 data[i++] = tochar(aln);
1231 for (j = 0; j < aln; j++)
1232 data[i++] = x.lprotect.val[j];
1233 numset++;
1234 done[xunchar(c)] = 1;
1235 } else
1236 left++;
1237 }
1238 if (atgpro && !done[xunchar(c = '-')] && /* Generic protection */
1239 (aln = x.gprotect.len) > 0 && !notafile && xp == 0) {
1240 if (max - i >= aln + 2) {
1241 data[i++] = c;
1242 data[i++] = tochar(aln);
1243 for (j = 0; j < aln; j++)
1244 data[i++] = x.gprotect.val[j];
1245 numset++;
1246 done[xunchar(c)] = 1;
1247 } else
1248 left++;
1249 }
1250 #endif /* CK_PERMS */
1251 if (atblko && fblksiz && !done[xunchar(c = '(')] &&
1252 !notafile && xp == 0) { /* Blocksize */
1253 sprintf((char *) &data[i+2],"%d",fblksiz); /* safe */
1254 aln = (int)strlen((char *)(data+i+2));
1255 if (max - i >= aln + 2) {
1256 data[i] = c;
1257 data[i+1] = tochar(aln);
1258 i += aln + 2;
1259 numset++;
1260 done[xunchar(c)] = 1;
1261 } else {
1262 data[i] = NUL;
1263 left++;
1264 }
1265 }
1266 #ifndef NOFRILLS
1267 if ((rprintf || rmailf) && atdiso && /* MAIL, or REMOTE PRINT? */
1268 !done[xunchar(c = '+')]) {
1269 aln = (int) strlen(optbuf) + 1; /* Options, if any */
1270 if (max - i >= aln + 2) {
1271 data[i++] = c; /* Disposition */
1272 data[i++] = tochar(aln); /* Options, if any */
1273 if (rprintf)
1274 data[i++] = 'P'; /* P for Print */
1275 else
1276 data[i++] = 'M'; /* M for Mail */
1277 for (j = 0; optbuf[j]; j++) /* Copy any options */
1278 data[i++] = optbuf[j];
1279 numset++;
1280 done[xunchar(c)] = 1;
1281 } else {
1282 data[i] = NUL;
1283 left++;
1284 }
1285 }
1286 #endif /* NOFRILLS */
1287 #ifdef CK_RESEND
1288 if (sendmode == SM_RESEND && !done[xunchar(c = '+')]) {
1289 if (max - i >= 3) {
1290 data[i++] = c; /* Disposition */
1291 data[i++] = tochar(1);
1292 data[i++] = 'R'; /* is RESEND */
1293 numset++;
1294 done[xunchar(c)] = 1;
1295 } else
1296 left++;
1297 }
1298 #endif /* CK_RESEND */
1299
1300 /* End of Attributes -- to be sent only after sending all others */
1301
1302 debug(F111,"sattr","@",i);
1303 debug(F101,"sattr numset","",numset);
1304 debug(F101,"sattr left","",left);
1305
1306 if ((left == 0 || numset == 0) && !done[xunchar(c = '@')]) {
1307 if (max - i >= 3) {
1308 data[i++] = c; /* End of Attributes */
1309 data[i++] = SP; /* Length 0 */
1310 data[i] = NUL; /* Make sure it's null-terminated */
1311 numset++;
1312 done[xunchar(c)] = 1;
1313 }
1314 }
1315
1316 /* Finished - send the packet off if we have anything in it */
1317
1318 if (numset) {
1319 data[i] = NUL; /* Terminate last good field */
1320 debug(F111,"sattr sending",data,left);
1321 aln = (int)strlen((char *)data); /* Get overall length of attributes */
1322 return(spack('A',pktnum,aln,data)); /* Send it */
1323 } else
1324 return(0);
1325 }
1326
1327 static char *refused = "";
1328
1329 static char *reason[] = {
1330 "size", "type", "date", "creator", "account", "area", "password",
1331 "blocksize", "access", "encoding", "disposition", "protection",
1332 "protection", "origin", "format",
1333 "sys-dependent", /* 0 */
1334 "size", /* 1 */
1335 "2", /* 2 */
1336 "3", /* 3 */
1337 "4", /* 4 */
1338 "5", /* 5 */
1339 "6", /* 6 */
1340 "7", /* 7 */
1341 "8", /* 8 */
1342 "9", /* 9 */
1343 ":", /* : */
1344 ";", /* ; */
1345 "<", /* < */
1346 "=", /* = */
1347 ">", /* > */
1348 "name", /* ? */
1349 "@"
1350 };
1351 static int nreason = sizeof(reason) / sizeof(char *);
1352 int rejection = -1;
1353
1354 char *
getreason(s)1355 getreason(s) char *s; { /* Decode attribute refusal reason */
1356 char c, *p;
1357 if (rejection == 1) /* Kludge for SET FIL COLL DISCARD */
1358 return("name"); /* when other Kermit doesn't... */
1359 p = s;
1360 if (*p++ != 'N') return(""); /* Should start with N */
1361 else if ((c = *p) > SP) { /* get reason, */
1362 rejection = c; /* remember it, */
1363 c -= '!'; /* get offset */
1364 p = ((unsigned int) ((CHAR) c) <= (unsigned int) nreason) ?
1365 reason[c] :
1366 "unknown";
1367 }
1368 return(p);
1369 }
1370
1371 int
rsattr(s)1372 rsattr(s) CHAR *s; { /* Read response to attribute packet */
1373 debug(F111,"rsattr",s,*s);
1374 if (*s == 'N') { /* If it's 'N' followed by anything, */
1375 refused = getreason((char *)s); /* they are refusing, get reason. */
1376 debug(F110,"rsattr refused",refused,0);
1377 tlog(F110," refused:",refused,0L);
1378 return(-1);
1379 }
1380 #ifdef CK_RESEND
1381 if (sendmode == SM_RESEND && *s == '1') { /* RESEND length */
1382 int n; CK_OFF_T z; CHAR *p;
1383 p = s + 1;
1384 n = xunchar(*p++);
1385 debug(F101,"rsattr RESEND n","",n);
1386 z = (CK_OFF_T)0;
1387 while (n-- > 0) /* We assume the format is good. */
1388 z = (CK_OFF_T)10 * z + (CK_OFF_T)(*p++ - '0');
1389 debug(F101,"rsattr RESEND z","",z);
1390 if (z > (CK_OFF_T)0) sendstart = z;
1391 debug(F101,"rsattr RESEND sendstart","",sendstart);
1392 if (sendstart > (CK_OFF_T)0)
1393 if (zfseek(sendstart) < 0) /* Input file is already open. */
1394 return(0);
1395 #ifdef CK_CURSES
1396 if (fdispla == XYFD_C)
1397 xxscreen(SCR_FS,0,fsize,""); /* Refresh file transfer display */
1398 #endif /* CK_CURSES */
1399 }
1400 #endif /* CK_RESEND */
1401 refused = "";
1402 return(0);
1403 }
1404
1405 /*
1406 Get attributes from incoming A packet. Returns:
1407 0 on success, file is to be accepted
1408 -1 on failure, file is to be refused
1409 */
1410 int
gattr(s,yy)1411 gattr(s, yy) CHAR *s; struct zattr *yy; { /* Read incoming attribute packet */
1412 char c, d;
1413 char *ff;
1414 int aln, i, overflow = 0;
1415
1416 #ifndef NOCSETS
1417 extern int r_cset, axcset[];
1418 #endif /* NOCSETS */
1419
1420 #define ABUFL 40 /* Temporary buffer for conversions */
1421 char abuf[ABUFL+1];
1422 #define RFBUFL 10 /* Record-format buffer */
1423 static char rfbuf[RFBUFL+1];
1424 #define FTBUFL 10 /* File type buffer */
1425 static char ftbuf[FTBUFL+1];
1426 #define DTBUFL 40 /* File creation date */
1427 static char dtbuf[DTBUFL+1];
1428 #define TSBUFL 10 /* Transfer syntax */
1429 static char tsbuf[TSBUFL+1];
1430 #define IDBUFL 10 /* System ID */
1431 static char idbuf[IDBUFL+1];
1432 #ifndef DYNAMIC
1433 #define DSBUFL 100 /* Disposition */
1434 static char dsbuf[DSBUFL+1];
1435 #define SPBUFL 512 /* System-dependent parameters */
1436 static char spbuf[SPBUFL+1];
1437 #else
1438 #define DSBUFL 100 /* Disposition */
1439 static char *dsbuf = NULL;
1440 #define SPBUFL 512 /* System-dependent parameters */
1441 static char *spbuf = NULL;
1442 #endif /* DYNAMIC */
1443 #define RPBUFL 20 /* Attribute reply */
1444 static char rpbuf[RPBUFL+1];
1445
1446 #ifdef CK_PERMS
1447 static char lprmbuf[CK_PERMLEN+1];
1448 static char gprmbuf[2];
1449 #endif /* CK_PERMS */
1450
1451 char *rp; /* Pointer to reply buffer */
1452 int retcode; /* Return code */
1453
1454 d = SP; /* Initialize disposition */
1455 ff = filnam; /* Filename returned by rcvfil */
1456 if (fncact == XYFX_R && ofn1x && ofn1[0]) /* But watch out for FC=RENAME */
1457 ff = ofn1; /* because we haven't renamed it yet */
1458
1459 /* Fill in the attributes we have received */
1460
1461 rp = rpbuf; /* Initialize reply buffer */
1462 *rp++ = 'N'; /* for negative reply. */
1463 *rp = NUL;
1464 retcode = 0; /* Initialize return code. */
1465
1466 if (dest == DEST_P) { /* SET DESTINATION PRINTER */
1467 #ifdef DYNAMIC
1468 if (!dsbuf)
1469 if ((dsbuf = malloc(DSBUFL+1)) == NULL)
1470 fatal("gtattr: no memory for dsbuf");
1471 #endif /* DYNAMIC */
1472 dsbuf[0] = 'P';
1473 dsbuf[1] = '\0';
1474 yy->disp.val = dsbuf;
1475 yy->disp.len = 1;
1476 }
1477 while (c = *s++) { /* Get attribute tag */
1478 aln = xunchar(*s++); /* Length of attribute string */
1479 switch (c) {
1480 #ifdef COMMENT /* This case combined with '1' below */
1481 case '!': /* File length in K */
1482 for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1483 abuf[i] = *s++;
1484 abuf[i] = '\0'; /* Terminate with null */
1485 if (i < aln) s += (aln - i); /* If field was too long for buffer */
1486 yy->lengthk = ckatofs(abuf); /* Convert to number */
1487 break;
1488 #endif /* COMMENT */
1489
1490 case '/': /* Record format */
1491 rfbuf[1] = NUL;
1492 rfbuf[2] = NUL;
1493 for (i = 0; (i < aln) && (i < RFBUFL); i++) /* Copy it */
1494 rfbuf[i] = *s++;
1495 rfbuf[i] = NUL; /* Terminate with null */
1496 yy->recfm.val = rfbuf; /* Pointer to string */
1497 yy->recfm.len = i; /* Length of string */
1498 if ((rfbuf[0] != 'A') ||
1499 (rfbuf[1] && rfbuf[1] != 'M') ||
1500 (rfbuf[2] && rfbuf[2] != 'J')) {
1501 debug(F110,"gattr bad recfm",rfbuf,0);
1502 *rp++ = c;
1503 retcode = -1;
1504 }
1505 break;
1506
1507 case '"': /* File type (text, binary, ...) */
1508 for (i = 0; (i < aln) && (i < FTBUFL); i++)
1509 ftbuf[i] = *s++; /* Copy it into a static string */
1510 ftbuf[i] = '\0';
1511 if (i < aln) s += (aln - i);
1512 /* TYPE attribute is enabled? */
1513 if (attypi) {
1514 yy->type.val = ftbuf; /* Pointer to string */
1515 yy->type.len = i; /* Length of string */
1516 debug(F111,"gattr file type", ftbuf, i);
1517 debug(F101,"gattr binary 1","",binary);
1518 /* Unknown type? */
1519 if ((*ftbuf != 'A' && *ftbuf != 'B' && *ftbuf != 'I')
1520 #ifdef CK_LABELED
1521 /* ... Or our FILE TYPE is LABELED and the incoming file is text... */
1522 || (binary == XYFT_L && *ftbuf == 'A' && !xflg)
1523 #endif /* CK_LABELED */
1524 ) {
1525 retcode = -1; /* Reject the file */
1526 *rp++ = c;
1527 if (!opnerr) tlog(F100," refused: type","",0);
1528 break;
1529 }
1530 /*
1531 The following code moved here from opena() so we set binary mode
1532 as soon as requested by the attribute packet. That way when the first
1533 data packet comes, the mode of transfer can be displayed correctly
1534 before opena() is called.
1535 */
1536 if (yy->type.val[0] == 'A') { /* Check received attributes. */
1537 #ifdef VMS
1538 if (binary != XYFT_I) /* VMS IMAGE overrides this */
1539 #endif /* VMS */
1540 binary = XYFT_T; /* Set current type to Text. */
1541 debug(F101,"gattr binary 2","",binary);
1542 } else if (yy->type.val[0] == 'B') {
1543 #ifdef CK_LABELED
1544 if (binary != XYFT_L
1545 #ifdef VMS
1546 && binary != XYFT_U /* VMS special case */
1547 #endif /* VMS */
1548 )
1549 #endif /* CK_LABELED */
1550 #ifdef MAC
1551 if (binary != XYFT_M) /* If not MacBinary... */
1552 #endif /* MAC */
1553 binary = XYFT_B;
1554 debug(F101,"gattr binary 3","",binary);
1555 }
1556 }
1557 break;
1558
1559 case '#': /* File creation date */
1560 for (i = 0; (i < aln) && (i < DTBUFL); i++)
1561 dtbuf[i] = *s++; /* Copy it into a static string */
1562 if (i < aln) s += (aln - i);
1563 dtbuf[i] = '\0';
1564 if (atdati && !xflg) { /* Real file and dates enabled */
1565 yy->date.val = dtbuf; /* Pointer to string */
1566 yy->date.len = i; /* Length of string */
1567 if (fncact == XYFX_U) { /* Receiving in update mode? */
1568 if (zstime(ff,yy,1) > 0) { /* Compare dates */
1569 *rp++ = c; /* Discard if older, reason = date. */
1570 if (!opnerr) tlog(F100," refused: date","",0);
1571 retcode = -1; /* Rejection notice. */
1572 }
1573 }
1574 }
1575 break;
1576
1577 case '(': /* File Block Size */
1578 for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1579 abuf[i] = *s++;
1580 abuf[i] = '\0'; /* Terminate with null */
1581 if (i < aln) s += (aln - i);
1582 if (atblki)
1583 yy->blksize = atol(abuf); /* Convert to number */
1584 break;
1585
1586 case '*': /* Encoding (transfer syntax) */
1587 for (i = 0; (i < aln) && (i < TSBUFL); i++)
1588 tsbuf[i] = *s++; /* Copy it into a static string */
1589 if (i < aln) s += (aln - i);
1590 tsbuf[i] = '\0';
1591 #ifndef NOCSETS
1592 xlatype = XLA_NONE; /* Assume no translation */
1593 #endif /* NOCSETS */
1594 if (atenci) {
1595 char * ss;
1596 yy->encoding.val = tsbuf; /* Pointer to string */
1597 yy->encoding.len = i; /* Length of string */
1598 debug(F101,"gattr encoding",tsbuf,i);
1599 ss = tsbuf+1;
1600 switch (*tsbuf) {
1601 #ifndef NOCSETS
1602 case 'A': /* Normal, nothing special */
1603 tcharset = TC_TRANSP; /* Transparent chars untranslated */
1604 debug(F110,"gattr sets tcharset TC_TRANSP","A",0);
1605 break;
1606 case 'C': /* Specified character set */
1607 if (!xfrxla) { /* But translation disabled */
1608 tcharset = TC_TRANSP;
1609 debug(F110,"gattr sets tcharset TC_TRANSP","C",0);
1610 break;
1611 }
1612 #ifdef UNICODE
1613 if (!strcmp("I196",ss)) /* Treat I196 (UTF-8 no level) */
1614 ss = "I190"; /* as I190 (UTF-8 Level 1) */
1615 #endif /* UNICODE */
1616 if (!strcmp("I6/204",ss)) /* Treat "Latin-1 + Euro" */
1617 ss = "I6/100"; /* as I6/100 (regular Latin-1) */
1618 for (i = 0; i < ntcsets; i++) {
1619 if (!strcmp(tcsinfo[i].designator,ss))
1620 break;
1621 }
1622 debug(F101,"gattr xfer charset lookup","",i);
1623 if (i == ntcsets) { /* If unknown character set, */
1624 debug(F110,"gattr: xfer charset unknown",ss,0);
1625 if (!unkcs) { /* and SET UNKNOWN DISCARD, */
1626 retcode = -1; /* reject the file. */
1627 *rp++ = c;
1628 if (!opnerr)
1629 tlog(F100," refused: character set","",0);
1630 }
1631 } else {
1632 tcharset = tcsinfo[i].code; /* it's known, use it */
1633 debug(F101,"gattr switch tcharset","",tcharset);
1634 debug(F101,"gattr fcharset","",fcharset);
1635 if (r_cset == XMODE_A) { /* Automatic switching? */
1636 if (tcharset > -1 && tcharset <= MAXTCSETS) {
1637 int x;
1638 x = axcset[tcharset];
1639 if (x > 0 && x <= MAXFCSETS) {
1640 fcharset = x;
1641 debug(F101,"gattr switch fcharset","",x);
1642 }
1643 }
1644 }
1645 /* Set up translation type and function */
1646 setxlatype(tcharset,fcharset);
1647 }
1648 break;
1649 #endif /* NOCSETS */
1650 default: /* Something else. */
1651 debug(F110,"gattr unk encoding attribute",tsbuf,0);
1652 if (!unkcs) { /* If SET UNK DISC */
1653 retcode = -1;
1654 *rp++ = c;
1655 if (!opnerr) tlog(F100," refused: encoding","",0);
1656 }
1657 break;
1658 }
1659 }
1660 break;
1661
1662 case '+': /* Disposition */
1663 #ifdef DYNAMIC
1664 if (!dsbuf)
1665 if ((dsbuf = malloc(DSBUFL+1)) == NULL)
1666 fatal("gtattr: no memory for dsbuf");
1667 #endif /* DYNAMIC */
1668 for (i = 0; (i < aln) && (i < DSBUFL); i++)
1669 dsbuf[i] = *s++; /* Copy it into a separate string */
1670 dsbuf[i] = '\0';
1671 if (i < aln) s += (aln - i);
1672 rs_len = (CK_OFF_T)0;
1673 if (atdisi) { /* We are doing this attribute */
1674 /* Copy it into the attribute structure */
1675 yy->disp.val = dsbuf; /* Pointer to string */
1676 yy->disp.len = i; /* Length of string */
1677 d = *dsbuf;
1678 #ifndef NODISPO
1679 /*
1680 Define NODISPO to disable receipt of mail or print files and of RESEND.
1681 */
1682 if (
1683 #ifndef datageneral /* MAIL supported only for */
1684 #ifndef OS2 /* UNIX, VMS, and OS-9 */
1685 #ifndef MAC
1686 #ifndef GEMDOS
1687 #ifndef AMIGA
1688 d != 'M' && /* MAIL */
1689 #endif /* AMIGA */
1690 #endif /* GEMDOS */
1691 #endif /* MAC */
1692 #endif /* OS/2 */
1693 #endif /* datageneral */
1694 #ifdef CK_RESEND
1695 d != 'R' && /* RESEND */
1696 #endif /* CK_RESEND */
1697 d != 'P') { /* PRINT */
1698 retcode = -1; /* Unknown/unsupported disposition */
1699 *rp++ = c;
1700 if (!opnerr) tlog(F101," refused: bad disposition","",d);
1701 }
1702 dispos = d;
1703 debug(F000,"gattr dispos","",dispos);
1704 switch (d) {
1705 #ifndef NOFRILLS
1706 case 'M':
1707 if (!en_mai) {
1708 retcode = -1;
1709 *rp++ = c;
1710 if (!opnerr) tlog(F100," refused: mail disabled","",0);
1711 dispos = 0;
1712 }
1713 break;
1714 #endif /* NOFRILLS */
1715 case 'P':
1716 if (!en_pri) {
1717 retcode = -1;
1718 *rp++ = c;
1719 if (!opnerr)
1720 tlog(F100," refused: print disabled","",0);
1721 dispos = 0;
1722 }
1723 break;
1724
1725 case 'R':
1726 dispos = 0;
1727 #ifdef CK_RESEND
1728 rs_len = zgetfs(ff); /* Get length of file */
1729 debug(F111,"gattr RESEND",ff,rs_len);
1730 #ifdef VMS
1731 rs_len &= (long) -512; /* Ensure block boundary if VMS */
1732 rs_len -= 512; /* In case last block not complete */
1733 debug(F111,"gattr rs_len",ff,rs_len);
1734 #endif /* VMS */
1735 #ifdef COMMENT
1736 if (rs_len < 0L) /* Local file doesn't exist */
1737 rs_len = 0L;
1738 #endif /* COMMENT */
1739 /*
1740 Another possibility here (or later, really) would be to check if the two
1741 file lengths are the same, and if so, keep the prevailing collision action
1742 as is (note: rs_len == length of existing file; yy->length == fsize ==
1743 length of incoming file). This could be complicated, though, since
1744 (a) we might not have received the length attribute yet, and in fact it
1745 might even be in a subsequent A-packet, yet (b) we have to accept or reject
1746 the Recover attribute now. So better to leave as-is. Anyway, it's probably
1747 more useful this way.
1748 */
1749 if (rs_len > (CK_OFF_T)0) {
1750 fncsav = fncact; /* Save collision action */
1751 fncact = XYFX_A; /* Switch to APPEND */
1752 }
1753 #else
1754 retcode = -1; /* This shouldn't happen */
1755 *rp++ = c; /* 'cause it wasn't negotiated. */
1756 if (!opnerr) tlog(F100," refused: resend","",0);
1757 #endif /* CK_RESEND */
1758 }
1759 #else /* NODISPO */
1760 retcode = -1;
1761 *rp++ = c;
1762 if (!opnerr) tlog(F100," refused: NODISPO","",0);
1763 #endif /* NODISPO */
1764 }
1765 break;
1766
1767 case '.': /* Sender's system ID */
1768 for (i = 0; (i < aln) && (i < IDBUFL); i++)
1769 idbuf[i] = *s++; /* Copy it into a static string */
1770 idbuf[i] = '\0';
1771 if (i < aln) s += (aln - i);
1772 if (atsidi) {
1773 yy->systemid.val = idbuf; /* Pointer to string */
1774 yy->systemid.len = i; /* Length of string */
1775 }
1776 break;
1777
1778 case '0': /* System-dependent parameters */
1779 #ifdef DYNAMIC
1780 if (!spbuf && !(spbuf = malloc(SPBUFL)))
1781 fatal("gattr: no memory for spbuf");
1782 #endif /* DYNAMIC */
1783 for (i = 0; (i < aln) && (i < SPBUFL); i++)
1784 spbuf[i] = *s++; /* Copy it into a static string */
1785 spbuf[i] = '\0';
1786 if (i < aln) s += (aln - i);
1787 if (atsysi) {
1788 yy->sysparam.val = spbuf; /* Pointer to string */
1789 yy->sysparam.len = i; /* Length of string */
1790 }
1791 break;
1792
1793 case '!': /* File length in K */
1794 case '1': { /* File length in bytes */
1795 char * l2;
1796 CK_OFF_T xlen;
1797 for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1798 abuf[i] = *s++;
1799 abuf[i] = '\0'; /* Terminate with null */
1800 if (i < aln) s += (aln - i);
1801 if (rdigits(abuf)) { /* Make sure string is all digits */
1802 xlen = ckatofs(abuf); /* Convert to number */
1803 l2 = ckfstoa(xlen); /* Convert number back to string */
1804 if (c == '1')
1805 debug(F111,"gattr length",abuf,xlen);
1806 else
1807 debug(F111,"gattr lengthk",abuf,xlen);
1808 if (ckstrcmp(abuf,l2,-1,1)) { /* This is how we check... */
1809 xlen = (CK_OFF_T)-2; /* -2 = unk, possibly too long */
1810 overflow++;
1811 debug(F111,"gattr overflow",
1812 (c == '1') ? "length" : "lengthk",
1813 xlen);
1814 }
1815 if (c == '1') {
1816 yy->length = xlen;
1817 debug(F101,"gattr length","",xlen);
1818 } else {
1819 yy->lengthk = xlen;
1820 debug(F101,"gattr lengthk","",xlen);
1821 }
1822 }
1823 /* If the length field is not numeric accept the file */
1824 /* anyway but with an unknown length */
1825 break;
1826 }
1827
1828 #ifdef CK_PERMS
1829 case ',': /* System-dependent protection code */
1830 for (i = 0; (i < aln) && (i < CK_PERMLEN); i++)
1831 lprmbuf[i] = *s++; /* Just copy it - decode later */
1832 lprmbuf[i] = '\0'; /* Terminate with null */
1833 if (i < aln) s += (aln - i);
1834 if (atlpri) {
1835 yy->lprotect.val = (char *)lprmbuf;
1836 yy->lprotect.len = i;
1837 } else
1838 lprmbuf[0] = NUL;
1839 break;
1840
1841 case '-': /* Generic "world" protection code */
1842 gprmbuf[0] = NUL; /* Just 1 byte by definition */
1843 for (i = 0; i < aln; i++) /* But allow for more... */
1844 if (i == 0) gprmbuf[0] = *s++;
1845 gprmbuf[1] = NUL;
1846 if (atgpri) {
1847 yy->gprotect.val = (char *)gprmbuf;
1848 yy->gprotect.len = gprmbuf[0] ? 1 : 0;
1849 } else
1850 gprmbuf[0] = NUL;
1851 break;
1852 #endif /* CK_PERMS */
1853
1854 default: /* Unknown attribute */
1855 s += aln; /* Just skip past it */
1856 break;
1857 }
1858 }
1859
1860 /* Check space now, because we also need to know the file type */
1861 /* in case zchkspa() differentiates text and binary (VMS version does) */
1862
1863 if (atleni && !calibrate) { /* Length attribute enabled? */
1864 if (yy->length > (CK_OFF_T)-1) { /* Length-in-bytes attribute rec'd? */
1865 if (!zchkspa(ff,(yy->length))) { /* Check space */
1866 retcode = -1; /* Not enuf */
1867 *rp++ = '1';
1868 if (!opnerr) tlog(F100," refused: length bytes","",0);
1869 }
1870 } else if (yy->lengthk > (CK_OFF_T)-1) { /* Length in K received? */
1871 long xlen;
1872 xlen = yy->lengthk * 1024;
1873 if (!zchkspa(ff,xlen)) {
1874 retcode = -1; /* Check space */
1875 *rp++ = '!';
1876 if (!opnerr) tlog(F100," refused: length K","",0);
1877 }
1878 }
1879 }
1880 if (retcode > -1L) { /* Remember the file size */
1881 if (yy->length > (CK_OFF_T)-1) {
1882 fsize = yy->length;
1883 } else if (yy->lengthk > (CK_OFF_T)-1 && !overflow) {
1884 fsize = yy->lengthk * 1024L;
1885 } else fsize = yy->length; /* (e.g. -2L) */
1886 }
1887
1888 #ifdef DEBUG
1889 if (deblog) {
1890 #ifdef COMMENT
1891 sprintf(abuf,"%ld",fsize); /* safe */
1892 #else
1893 ckstrncpy(abuf,ckfstoa(fsize),ABUFL);
1894 #endif /* COMMENT */
1895 debug(F110,"gattr fsize",abuf,0);
1896 }
1897 #endif /* DEBUG */
1898
1899 if (retcode == 0) rp = rpbuf; /* Null reply string if accepted */
1900 *rp = '\0'; /* End of reply string */
1901
1902 #ifdef CK_RESEND
1903 if (d == 'R') { /* Receiving a RESEND? */
1904 debug(F101,"gattr RESEND","",retcode);
1905 /* We ignore retcodes because this overrides */
1906 if (binary != XYFT_B) { /* Reject if not binary */
1907 retcode = -1; /* in case type field came */
1908 ckstrncpy(rpbuf,"N+",RPBUFL); /* after the disposition field */
1909 debug(F111,"gattr RESEND not binary",rpbuf,binary);
1910 } else { /* Binary mode */
1911 retcode = 0; /* Accept the file */
1912 discard = 0; /* If SET FILE COLLISION DISCARD */
1913 #ifdef COMMENT
1914 sprintf(rpbuf+2,"%ld",rs_len); /* Reply with length of file */
1915 #else
1916 ckstrncpy(rpbuf+2,ckfstoa(rs_len),RPBUFL-2);
1917 #endif /* COMMENT */
1918 rpbuf[0] = '1'; /* '1' means Length in Bytes */
1919 rpbuf[1] = tochar((int)strlen(rpbuf+2)); /* Length of length */
1920 debug(F111,"gattr RESEND OK",rpbuf,retcode);
1921 }
1922 }
1923 #endif /* CK_RESEND */
1924 if (retcode == 0 && discard != 0) { /* Do we still have a discard flag? */
1925 ckstrncpy(rpbuf,"N?",RPBUFL); /* Yes, must be filename collision */
1926 retcode = -1; /* "?" = name (reply-only code) */
1927 }
1928 yy->reply.val = rpbuf; /* Add it to attribute structure */
1929 yy->reply.len = (int)strlen(rpbuf);
1930 if (retcode < 0) { /* If we are rejecting */
1931 discard = 1; /* remember to discard the file */
1932 rejection = rpbuf[1]; /* and use the first reason given. */
1933 if (fncsav != -1) {
1934 fncact = fncsav;
1935 fncsav = -1;
1936 }
1937 }
1938 debug(F111,"gattr return",rpbuf,retcode);
1939 return(retcode);
1940 }
1941
1942 /* I N I T A T T R -- Initialize file attribute structure */
1943
1944 int
initattr(yy)1945 initattr(yy) struct zattr *yy; {
1946 yy->lengthk = yy->length = (CK_OFF_T)-1;
1947 yy->type.val = "";
1948 yy->type.len = 0;
1949 yy->date.val = "";
1950 yy->date.len = 0;
1951 yy->encoding.val = "";
1952 yy->encoding.len = 0;
1953 yy->disp.val = "";
1954 yy->disp.len = 0;
1955 yy->systemid.val = "";
1956 yy->systemid.len = 0;
1957 yy->sysparam.val = "";
1958 yy->sysparam.len = 0;
1959 yy->creator.val = "";
1960 yy->creator.len = 0;
1961 yy->account.val = "";
1962 yy->account.len = 0;
1963 yy->area.val = "";
1964 yy->area.len = 0;
1965 yy->password.val = "";
1966 yy->password.len = 0;
1967 yy->blksize = -1L;
1968 yy->xaccess.val = "";
1969 yy->xaccess.len = 0;
1970 #ifdef CK_PERMS
1971 if (!ofperms) ofperms = "";
1972 debug(F110,"initattr ofperms",ofperms,0);
1973 yy->lprotect.val = ofperms;
1974 yy->lprotect.len = 0 - strlen(ofperms); /* <-- NOTE! */
1975 /*
1976 A negative length indicates that we have a permissions string but it has
1977 been inherited from a previously existing file rather than picked up
1978 from an incoming A-packet.
1979 */
1980 #else
1981 yy->lprotect.val = "";
1982 yy->lprotect.len = 0;
1983 #endif /* CK_PERMS */
1984 yy->gprotect.val = "";
1985 yy->gprotect.len = 0;
1986 yy->recfm.val = "";
1987 yy->recfm.len = 0;
1988 yy->reply.val = "";
1989 yy->reply.len = 0;
1990 #ifdef OS2
1991 yy->longname.len = 0 ;
1992 yy->longname.val = "" ;
1993 #endif /* OS2 */
1994 return(0);
1995 }
1996
1997 /* A D E B U -- Write attribute packet info to debug log */
1998
1999 int
adebu(f,zz)2000 adebu(f,zz) char *f; struct zattr *zz; {
2001 #ifdef DEBUG
2002 if (deblog == 0) return(0);
2003 debug(F110,"Attributes for incoming file ",f,0);
2004 debug(F101," length in K","",(int) zz->lengthk);
2005 debug(F111," file type",zz->type.val,zz->type.len);
2006 debug(F111," creation date",zz->date.val,zz->date.len);
2007 debug(F111," creator",zz->creator.val,zz->creator.len);
2008 debug(F111," account",zz->account.val,zz->account.len);
2009 debug(F111," area",zz->area.val,zz->area.len);
2010 debug(F111," password",zz->password.val,zz->password.len);
2011 debug(F101," blksize","",(int) zz->blksize);
2012 debug(F111," access",zz->xaccess.val,zz->xaccess.len);
2013 debug(F111," encoding",zz->encoding.val,zz->encoding.len);
2014 debug(F111," disposition",zz->disp.val,zz->disp.len);
2015 debug(F111," lprotection",zz->lprotect.val,zz->lprotect.len);
2016 debug(F111," gprotection",zz->gprotect.val,zz->gprotect.len);
2017 debug(F111," systemid",zz->systemid.val,zz->systemid.len);
2018 debug(F111," recfm",zz->recfm.val,zz->recfm.len);
2019 debug(F111," sysparam",zz->sysparam.val,zz->sysparam.len);
2020 debug(F101," length","",(int) zz->length);
2021 debug(F110," reply",zz->reply.val,0);
2022 #endif /* DEBUG */
2023 return(0);
2024 }
2025
2026 /* O P E N A -- Open a file, with attributes. */
2027 /*
2028 This function tries to open a new file to put the arriving data in. The
2029 filename is the one in the srvcmd buffer. File collision actions are:
2030 OVERWRITE (the existing file is overwritten), RENAME (the new file is
2031 renamed), BACKUP (the existing file is renamed), DISCARD (the new file is
2032 refused), UPDATE (the incoming file replaces the existing file only if the
2033 incoming file has a newer creation date).
2034
2035 Returns 0 on failure, nonzero on success.
2036 */
2037 extern char *rf_err;
2038
2039 int
opena(f,zz)2040 opena(f,zz) char *f; struct zattr *zz; {
2041 int x, dispos = 0;
2042 static struct filinfo fcb; /* Must be static! */
2043
2044 debug(F110,"opena f",f,0);
2045 debug(F101,"opena discard","",discard);
2046
2047 adebu(f,zz); /* Write attributes to debug log */
2048
2049 ffc = (CK_OFF_T)0; /* Init file-character counter */
2050
2051 #ifdef PIPESEND
2052 if (pipesend) /* Receiving to a pipe - easy. */
2053 return(openo(f,zz,&fcb)); /* Just open the pipe. */
2054 #endif /* PIPESEND */
2055
2056 /* Receiving to a file - set up file control structure */
2057
2058 fcb.bs = fblksiz; /* Blocksize */
2059 #ifndef NOCSETS
2060 fcb.cs = fcharset; /* Character set */
2061 #else
2062 fcb.cs = 0; /* Character set */
2063 #endif /* NOCSETS */
2064 fcb.rl = frecl; /* Record Length */
2065 fcb.fmt = frecfm; /* Record Format */
2066 fcb.org = forg; /* Organization */
2067 fcb.cc = fcctrl; /* Carriage control */
2068 fcb.typ = binary; /* Type */
2069 debug(F101,"opena xflg","",xflg);
2070 debug(F101,"opena remfile","",remfile);
2071 debug(F101,"opena remappd","",remappd);
2072 if (xflg && remfile && remappd) /* REMOTE output redirected with >> */
2073 fcb.dsp = XYFZ_A;
2074 else
2075 fcb.dsp = (fncact == XYFX_A) ? XYFZ_A : XYFZ_N; /* Disposition */
2076 debug(F101,"opena disp","",fcb.dsp);
2077 fcb.os_specific = ""; /* OS-specific info */
2078 #ifdef CK_LABELED
2079 fcb.lblopts = lf_opts; /* Labeled file options */
2080 #else
2081 fcb.lblopts = 0;
2082 #endif /* CK_LABELED */
2083
2084 if (zz->disp.len > 0) { /* Incoming file has a disposition? */
2085 debug(F111,"open disposition",zz->disp.val,zz->disp.len);
2086 dispos = (int) (*(zz->disp.val));
2087 }
2088 if (!dispos && xflg && remfile && remappd) /* REMOTE redirect append ? */
2089 dispos = fcb.dsp;
2090
2091 debug(F101,"opena dispos","",dispos);
2092
2093 if (!dispos) { /* No special disposition? */
2094 if (fncact == XYFX_B && ofn1x && ofn2) { /* File collision = BACKUP? */
2095 if (zrename(ofn1,ofn2) < 0) { /* Rename existing file. */
2096 debug(F110,"opena rename fails",ofn1,0);
2097 rf_err = "Can't create backup file";
2098 return(0);
2099 } else debug(F110,"opena rename ok",ofn2,0);
2100 }
2101 } else if (dispos == 'R') { /* Receiving a RESEND */
2102 debug(F101,"opena remote len","",zz->length);
2103 debug(F101,"opena local len","",rs_len);
2104 #ifdef COMMENT
2105 if (fncact == XYFX_R) /* and file collision = RENAME */
2106 if (ofn1x)
2107 #endif /* COMMENT */
2108 if (ofn1[0])
2109 f = ofn1; /* use original name. */
2110 if (fncact == XYFX_R) /* if file collision is RENAME */
2111 ckstrncpy(filnam,ofn1,CKMAXPATH+1); /* restore the real name */
2112 xxscreen(SCR_AN,0,0L,f); /* update name on screen */
2113 if (zz->length == rs_len) /* Local and remote lengths equal? */
2114 return(-17); /* Secret code */
2115 }
2116 debug(F111,"opena [file]=mode: ",f,fcb.dsp);
2117 if (x = openo(f,zz,&fcb)) { /* Try to open the file. */
2118 #ifdef pdp11
2119 tlog(F110," local name:",f,0L); /* OK, open, record local name. */
2120 makestr(&prfspec,f); /* New preliminary name */
2121 #else
2122 #ifndef ZFNQFP
2123 tlog(F110," local name:",f,0L);
2124 makestr(&prfspec,f);
2125 #else
2126 { /* Log full local pathname */
2127 char *p = NULL, *q = f;
2128 if ((p = malloc(CKMAXPATH+1)))
2129 if (zfnqfp(filnam, CKMAXPATH, p))
2130 q = p;
2131 tlog(F110," local name:",q,0L);
2132 makestr(&prfspec,q);
2133 if (p) free(p);
2134 }
2135 #endif /* ZFNQFP */
2136 #endif /* pdp11 */
2137
2138 if (binary) { /* Log file mode in transaction log */
2139 tlog(F101," mode: binary","",(long) binary);
2140 } else { /* If text mode, check character set */
2141 tlog(F100," mode: text","",0L);
2142 #ifndef NOCSETS
2143 if (xfrxla) {
2144 if (fcharset > -1 && fcharset <= MAXFCSETS)
2145 tlog(F110," file character-set:",fcsinfo[fcharset].name,0L);
2146 if (tcharset > -1 && tcharset <= MAXTCSETS)
2147 tlog(F110," xfer character-set:",tcsinfo[tcharset].name,0L);
2148 } else {
2149 tlog(F110," character-set:","transparent",0L);
2150 }
2151 #endif /* NOCSETS */
2152 debug(F111,"opena charset",zz->encoding.val,zz->encoding.len);
2153 }
2154 debug(F101,"opena binary","",binary);
2155
2156 #ifdef COMMENT
2157 if (fsize >= 0)
2158 #endif /* COMMENT */
2159 xxscreen(SCR_FS,0,fsize,"");
2160
2161 #ifdef datageneral
2162 /*
2163 Need to turn on multi-tasking console interrupt task here, since multiple
2164 files may be received (huh?) ...
2165 */
2166 if ((local) && (!quiet)) /* Only do this if local & not quiet */
2167 consta_mt(); /* Start the async read task */
2168 #endif /* datageneral */
2169
2170 } else { /* Did not open file OK. */
2171
2172 rf_err = ck_errstr(); /* Get system error message */
2173 if (*rf_err)
2174 xxscreen(SCR_EM,0,0l,rf_err);
2175 else
2176 xxscreen(SCR_EM,0,0l,"Can't open output file");
2177 tlog(F110,"Failure to open",f,0L);
2178 tlog(F110,"Error:",rf_err,0L);
2179 debug(F110,"opena error",rf_err,0);
2180 }
2181 return(x); /* Pass on return code from openo */
2182 }
2183
2184 /* O P E N C -- Open a command (in place of a file) for output */
2185
2186 int
openc(n,s)2187 openc(n,s) int n; char * s; {
2188 int x;
2189 #ifndef NOPUSH
2190 x = zxcmd(n,s);
2191 #else
2192 x = 0;
2193 #endif /* NOPUSH */
2194 debug(F111,"openc zxcmd",s,x);
2195 o_isopen = (x > 0) ? 1 : 0;
2196 return(x);
2197 }
2198
2199 /* C A N N E D -- Check if current file transfer cancelled */
2200
2201 int
canned(buf)2202 canned(buf) CHAR *buf; {
2203 extern int interrupted;
2204 if (*buf == 'X') cxseen = 1;
2205 if (*buf == 'Z') czseen = 1;
2206 if (czseen || cxseen)
2207 interrupted = 1;
2208 debug(F101,"canned: cxseen","",cxseen);
2209 debug(F101," czseen","",czseen);
2210 return((czseen || cxseen) ? 1 : 0);
2211 }
2212
2213
2214 /* O P E N I -- Open an existing file for input */
2215
2216 int
openi(name)2217 openi(name) char *name; {
2218 #ifndef NOSERVER
2219 extern int fromgetpath;
2220 #endif /* NOSERVER */
2221 int x, filno;
2222 char *name2;
2223 extern CHAR *epktmsg;
2224
2225 epktmsg[0] = NUL; /* Initialize error message */
2226 if (memstr || sndarray) { /* Just return if "file" is memory. */
2227 i_isopen = 1;
2228 return(1);
2229 }
2230 debug(F110,"openi name",name,0);
2231 debug(F101,"openi sndsrc","",sndsrc);
2232
2233 filno = (sndsrc == 0) ? ZSTDIO : ZIFILE; /* ... */
2234 debug(F101,"openi file number","",filno);
2235
2236 #ifndef NOSERVER
2237 /* If I'm a server and CWD is disabled and name is not from GET-PATH... */
2238
2239 if (server && !en_cwd && !fromgetpath) {
2240 zstrip(name,&name2);
2241 if ( /* ... check if pathname included. */
2242 #ifdef VMS
2243 zchkpath(name)
2244 #else
2245 strcmp(name,name2)
2246 #endif /* VMS */
2247 ) {
2248 tlog(F110,name,"access denied",0L);
2249 debug(F110,"openi CD disabled",name,0);
2250 ckstrncpy((char *)epktmsg,"Access denied",PKTMSGLEN);
2251 return(0);
2252 } else name = name2;
2253 }
2254 #endif /* NOSERVER */
2255
2256 #ifdef PIPESEND
2257 debug(F101,"openi pipesend","",pipesend);
2258 if (pipesend) {
2259 int x;
2260 #ifndef NOPUSH
2261 x = zxcmd(ZIFILE,name);
2262 #else
2263 x = 0;
2264 #endif /* NOPUSH */
2265 i_isopen = (x > 0) ? 1 : 0;
2266 if (!i_isopen)
2267 ckstrncpy((char *)epktmsg,"Command or pipe failure",PKTMSGLEN);
2268 debug(F111,"openi pipesend zxcmd",name,x);
2269 return(i_isopen);
2270 }
2271 #endif /* PIPESEND */
2272
2273 #ifdef CALIBRATE
2274 if (calibrate) {
2275 i_isopen = 1;
2276 return(1);
2277 }
2278 #endif /* CALIBRATE */
2279
2280 x = zopeni(filno,name); /* Otherwise, try to open it. */
2281 debug(F111,"openi zopeni 1",name,x);
2282 if (x) {
2283 i_isopen = 1;
2284 return(1);
2285 } else { /* If not found, */
2286 char xname[CKMAXPATH]; /* convert the name */
2287 #ifdef NZLTOR
2288 nzrtol(name,xname,fncnv,fnrpath,CKMAXPATH);
2289 #else
2290 zrtol(name,xname); /* to local form and then */
2291 #endif /* NZLTOR */
2292 x = zopeni(filno,xname); /* try opening it again. */
2293 debug(F111,"openi zopeni 2",xname,x);
2294 if (x) {
2295 i_isopen = 1;
2296 return(1); /* It worked. */
2297 } else {
2298 char * s;
2299 s = ck_errstr();
2300 if (s) if (!s) s = NULL;
2301 if (!s) s = "Can't open file";
2302 ckstrncpy((char *)epktmsg,s,PKTMSGLEN);
2303 tlog(F110,xname,s,0L);
2304 debug(F110,"openi failed",xname,0);
2305 debug(F110,"openi message",s,0);
2306 i_isopen = 0;
2307 return(0);
2308 }
2309 }
2310 }
2311
2312 /* O P E N O -- Open a new file for output. */
2313
2314 int
openo(name,zz,fcb)2315 openo(name,zz,fcb) char *name; struct zattr *zz; struct filinfo *fcb; {
2316 char *name2;
2317 #ifdef DTILDE
2318 char *dirp;
2319 #endif /* DTILDE */
2320
2321 int channel, x;
2322
2323 if (stdouf) { /* Receiving to stdout? */
2324 x = zopeno(ZSTDIO,"",zz,NULL);
2325 o_isopen = (x > 0);
2326 debug(F101,"openo stdouf zopeno","",x);
2327 return(x);
2328 }
2329 debug(F110,"openo: name",name,0);
2330
2331 if (cxseen || czseen || discard) { /* If interrupted, get out before */
2332 debug(F100," open cancelled","",0); /* destroying existing file. */
2333 return(1); /* Pretend to succeed. */
2334 }
2335 channel = ZOFILE; /* SET DESTINATION DISK or PRINTER */
2336
2337 #ifdef PIPESEND
2338 debug(F101,"openo pipesend","",pipesend);
2339 if (pipesend) {
2340 int x;
2341 #ifndef NOPUSH
2342 x = zxcmd(ZOFILE,(char *)srvcmd);
2343 #else
2344 x = 0;
2345 #endif /* NOPUSH */
2346 o_isopen = x > 0;
2347 debug(F101,"openo zxcmd","",x);
2348 return(x);
2349 }
2350 #endif /* PIPESEND */
2351
2352 if (dest == DEST_S) { /* SET DEST SCREEN... */
2353 channel = ZCTERM;
2354 fcb = NULL;
2355 }
2356 #ifdef DTILDE
2357 if (*name == '~') {
2358 dirp = tilde_expand(name);
2359 if (*dirp) ckstrncpy(name,dirp,CKMAXPATH+1);
2360 }
2361 #endif /* DTILDE */
2362 if (server && !en_cwd) { /* If running as server */
2363 zstrip(name,&name2); /* and CWD is disabled, */
2364 if (strcmp(name,name2)) { /* check if pathname was included. */
2365 tlog(F110,name,"authorization failure",0L);
2366 debug(F110,"openo CD disabled",name,0);
2367 return(0);
2368 } else name = name2;
2369 }
2370 if (zopeno(channel,name,zz,fcb) <= 0) { /* Try to open the file */
2371 o_isopen = 0;
2372 debug(F110,"openo failed",name,0);
2373 /* tlog(F110,"Failure to open",name,0L); */
2374 return(0);
2375 } else {
2376 o_isopen = 1;
2377 debug(F110,"openo ok, name",name,0);
2378 return(1);
2379 }
2380 }
2381
2382 /* O P E N T -- Open the terminal for output, in place of a file */
2383
2384 int
opent(zz)2385 opent(zz) struct zattr *zz; {
2386 int x;
2387 ffc = tfc = (CK_OFF_T)0;
2388 x = zopeno(ZCTERM,"",zz,NULL);
2389 debug(F101,"opent zopeno","",x);
2390 if (x >= 0) {
2391 o_isopen = 1;
2392 binary = XYFT_T;
2393 } else
2394 return(0);
2395 return(x);
2396 }
2397
2398 /* O P E N X -- Open nothing (incoming file to be accepted but ignored) */
2399
2400 int
ckopenx(zz)2401 ckopenx(zz) struct zattr *zz; {
2402 ffc = tfc = (CK_OFF_T)0; /* Reset counters */
2403 o_isopen = 1;
2404 debug(F101,"ckopenx fsize","",fsize);
2405 xxscreen(SCR_FS,0,fsize,""); /* Let screen display know the size */
2406 return(1);
2407 }
2408
2409 /* C L S I F -- Close the current input file. */
2410
2411 int
clsif()2412 clsif() {
2413 extern int xferstat, success;
2414 int x = 0;
2415
2416 fcps(); /* Calculate CPS quickly */
2417
2418 #ifdef datageneral
2419 if ((local) && (!quiet)) /* Only do this if local & not quiet */
2420 if (nfils < 1) /* More files to send ... leave it on! */
2421 connoi_mt();
2422 #endif /* datageneral */
2423
2424 debug(F101,"clsif i_isopen","",i_isopen);
2425 if (i_isopen) { /* If input file is open... */
2426 if (memstr) { /* If input was memory string, */
2427 memstr = 0; /* indicate no more. */
2428 } else {
2429 x = zclose(ZIFILE); /* else close input file. */
2430 }
2431 #ifdef DEBUG
2432 if (deblog) {
2433 debug(F101,"clsif zclose","",x);
2434 debug(F101,"clsif success","",success);
2435 debug(F101,"clsif xferstat","",xferstat);
2436 debug(F101,"clsif fsize","",fsize);
2437 debug(F101,"clsif ffc","",ffc);
2438 debug(F101,"clsif cxseen","",cxseen);
2439 debug(F101,"clsif czseen","",czseen);
2440 debug(F101,"clsif discard","",czseen);
2441 }
2442 #endif /* DEBUG */
2443 if ((cxseen || czseen) && !epktsent) { /* If interrupted */
2444 xxscreen(SCR_ST,ST_INT,0l,""); /* say so */
2445 #ifdef TLOG
2446 if (tralog && !tlogfmt)
2447 doxlog(what,psfspec,fsize,binary,1,"Interrupted");
2448 #endif /* TLOG */
2449 } else if (discard && !epktsent) { /* If I'm refusing */
2450 xxscreen(SCR_ST,ST_REFU,0l,refused); /* say why */
2451 #ifdef TLOG
2452 if (tralog && !tlogfmt) {
2453 char buf[128];
2454 ckmakmsg(buf,128,"Refused: ",refused,NULL,NULL);
2455 doxlog(what,psfspec,fsize,binary,1,buf);
2456 }
2457 #endif /* TLOG */
2458 } else if (!epktrcvd && !epktsent && !cxseen && !czseen) {
2459 CK_OFF_T zz;
2460 zz = ffc;
2461 #ifdef CK_RESEND
2462 if (sendmode == SM_RESEND || sendmode == SM_PSEND)
2463 zz += sendstart;
2464 #endif /* CK_RESEND */
2465 debug(F101,"clsif fstats","",zz);
2466 fstats(); /* Update statistics */
2467 if ( /* Was the whole file sent? */
2468 #ifdef VMS
2469 0 /* Not a reliable check in VMS */
2470 #else
2471 #ifdef STRATUS
2472 0 /* Probably not for VOS either */
2473 #else
2474 zz < fsize
2475 #ifdef CK_CTRLZ
2476 && ((eofmethod != XYEOF_Z && !binary) || binary)
2477 #endif /* CK_CTRLZ */
2478 #endif /* STRATUS */
2479 #endif /* VMS */
2480 ) {
2481 xxscreen(SCR_ST,ST_INT,0l,"");
2482 #ifdef TLOG
2483 if (tralog && !tlogfmt)
2484 doxlog(what,psfspec,fsize,binary,1,"Incomplete");
2485 #endif /* TLOG */
2486 } else {
2487 #ifdef COMMENT
2488 /* Not yet -- we don't have confirmation from the receiver */
2489 xxscreen(SCR_ST,ST_OK,0l,"");
2490 #endif /* COMMENT */
2491 #ifdef TLOG
2492 if (tralog && !tlogfmt)
2493 doxlog(what,psfspec,fsize,binary,0,"");
2494 #endif /* TLOG */
2495 }
2496 }
2497 }
2498 i_isopen = 0;
2499 hcflg = 0; /* Reset flags */
2500 sendstart = (CK_OFF_T)0; /* Don't do this again! */
2501 #ifdef COMMENT
2502 /*
2503 This prevents a subsequent call to clsof() from deleting the file
2504 when given the discard flag.
2505 */
2506 *filnam = '\0'; /* and current file name */
2507 #endif /* COMMENT */
2508 return(x);
2509 }
2510
2511
2512 /* C L S O F -- Close an output file. */
2513
2514 /* Call with disp != 0 if file is to be discarded. */
2515 /* Returns -1 upon failure to close, 0 or greater on success. */
2516
2517 int
clsof(disp)2518 clsof(disp) int disp; {
2519 int x = 0;
2520 extern int success;
2521
2522 fcps(); /* Calculate CPS quickly */
2523
2524 debug(F101,"clsof disp","",disp);
2525 debug(F101,"clsof cxseen","",cxseen);
2526 debug(F101,"clsof success","",success);
2527
2528 debug(F101,"clsof o_isopen","",o_isopen);
2529 if (fncsav != -1) { /* Saved file collision action... */
2530 fncact = fncsav; /* Restore it. */
2531 fncsav = -1; /* Unsave it. */
2532 }
2533 #ifdef datageneral
2534 if ((local) && (!quiet)) /* Only do this if local & not quiet */
2535 connoi_mt();
2536 #endif /* datageneral */
2537 if (o_isopen && !calibrate) {
2538 if ((x = zclose(ZOFILE)) < 0) { /* Try to close the file */
2539 tlog(F100,"Failure to close",filnam,0L);
2540 xxscreen(SCR_ST,ST_ERR,0l,"Can't close file");
2541 #ifdef TLOG
2542 if (tralog && !tlogfmt)
2543 doxlog(what,prfspec,fsize,binary,1,"Can't close file");
2544 #endif /* TLOG */
2545 } else if (disp) { /* Interrupted or refused */
2546 if (keep == 0 || /* If not keeping incomplete files */
2547 (keep == SET_AUTO && binary == XYFT_T)
2548 ) {
2549 if (*filnam && (what & W_RECV)) /* AND we're receiving */
2550 zdelet(filnam); /* ONLY THEN, delete it */
2551 if (what & W_KERMIT) {
2552 debug(F100,"clsof incomplete discarded","",0);
2553 tlog(F100," incomplete: discarded","",0L);
2554 if (!epktrcvd && !epktsent) {
2555 xxscreen(SCR_ST,ST_DISC,0l,"");
2556 #ifdef TLOG
2557 if (tralog && !tlogfmt)
2558 doxlog(what,prfspec,fsize,binary,1,"Discarded");
2559 #endif /* TLOG */
2560 }
2561 }
2562 } else { /* Keep incomplete copy */
2563 debug(F100,"clsof fstats 1","",0);
2564 fstats();
2565 if (!discard) { /* Unless discarding for other reason... */
2566 if (what & W_KERMIT) {
2567 debug(F100,"closf incomplete kept","",0);
2568 tlog(F100," incomplete: kept","",0L);
2569 }
2570 }
2571 if (what & W_KERMIT) {
2572 if (!epktrcvd && !epktsent) {
2573 xxscreen(SCR_ST,ST_INC,0l,"");
2574 #ifdef TLOG
2575 if (tralog && !tlogfmt)
2576 doxlog(what,prfspec,fsize,binary,1,"Incomplete");
2577 #endif /* TLOG */
2578 }
2579 }
2580 }
2581 }
2582 }
2583 if (o_isopen && x > -1 && !disp) {
2584 debug(F110,"clsof OK",rfspec,0);
2585 makestr(&rfspec,prfspec);
2586 makestr(&rrfspec,prrfspec);
2587 fstats();
2588 if (!epktrcvd && !epktsent && !cxseen && !czseen) {
2589 xxscreen(SCR_ST,ST_OK,0L,"");
2590 #ifdef TLOG
2591 if (tralog && !tlogfmt)
2592 doxlog(what,rfspec,fsize,binary,0,"");
2593 #endif /* TLOG */
2594 }
2595 }
2596 rs_len = (CK_OFF_T)0;
2597 o_isopen = 0; /* The file is not open any more. */
2598 cxseen = 0; /* Reset per-file interruption flag */
2599 return(x); /* Send back zclose() return code. */
2600 }
2601
2602 #ifdef SUNOS4S5
tolower(c)2603 tolower(c) char c; { return((c)-'A'+'a'); }
toupper(c)2604 toupper(c) char c; { return((c)-'a'+'A'); }
2605 #endif /* SUNOS4S5 */
2606 #endif /* NOXFER */
2607