source: trunk/third/kermit/ckcfn3.c @ 20081

Revision 20081, 73.5 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20080, which included commits to RCS files with non-trunk default branches.
Line 
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, 2002,
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
42static char ckmkdbuf[CKMAXPATH+1];
43#else
44#ifdef datageneral
45static char ckmkdbuf[CKMAXPATH+1];
46#endif /* datageneral */
47#endif /* CK_MKDIR */
48
49#ifdef CK_MKDIR
50int
51ckmkdir(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
212extern int pipesend;
213#ifdef PIPESEND
214extern char ** sndfilter;
215#endif /* PIPESEND */
216
217extern int unkcs, wmax, wcur, discard, bctu, bctl, local, fdispla, what,
218  sendmode, opnerr, dest, epktrcvd, epktsent, filestatus, eofmethod, dispos;
219extern long sendstart, calibrate, fncnv, fnrpath;
220
221extern char * ofn2;
222extern char * rfspec, * sfspec, * prfspec, * psfspec, * rrfspec, * prrfspec;
223extern char ofn1[];
224extern int ofn1x;
225extern char * ofperms;
226
227#ifdef VMS
228extern int batch;
229#else
230extern int backgrd;
231#endif /* VMS */
232
233extern int xflg, remfile, remappd;
234extern CHAR *data;
235extern char filnam[];
236#ifndef NOFRILLS
237extern int rprintf, rmailf;             /* REMOTE MAIL, PRINT */
238char optbuf[OPTBUFLEN];                 /* Options for MAIL or REMOTE PRINT */
239#endif /* NOFRILLS */
240extern int wslots;
241extern int fblksiz, frecl, forg, frecfm, fncact, fncsav, fcctrl, lf_opts;
242extern CHAR * srvcmd;
243extern int srvcmdlen;
244
245extern int binary, spsiz;
246extern int pktnum, cxseen, czseen, nfils, stdinf;
247extern int memstr, stdouf, keep, sndsrc, hcflg;
248extern int server, en_cwd, en_mai, en_pri;
249
250/* Attributes in/out enabled flags */
251
252extern int
253  atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
254  attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
255
256#ifdef CK_PERMS
257extern int atlpri, atlpro, atgpri, atgpro;
258#endif /* CK_PERMS */
259
260#ifdef STRATUS
261extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto;
262#endif /* STRATUS */
263
264#ifdef datageneral
265extern int quiet;
266#endif /* datageneral */
267
268extern long fsize, filcnt, ffc, tfc;
269
270#ifndef NOCSETS
271_PROTOTYP (VOID setxlate, (void));
272extern int tcharset, fcharset;
273extern int ntcsets, xlatype, xfrxla;
274extern struct csinfo tcsinfo[], fcsinfo[];
275#endif /* NOCSETS */
276
277/* Variables global to Kermit that are defined in this module */
278
279#ifdef CKXXCHAR                         /* DOUBLE / IGNORE char table */
280int dblflag = 0;
281int ignflag = 0;
282short dblt[256] = {
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
291};
292#endif /* CKXXCHAR */
293
294int winlo;                              /* packet number at low window edge  */
295
296int sbufnum;                            /* number of free buffers */
297int dum001 = 1234;                      /* protection... */
298int sbufuse[MAXWS];                     /* buffer in-use flag */
299int dum003 = 1111;
300int rbufnum;                            /* number of free buffers */
301int dum002 = 4321;                      /* more protection */
302int rbufuse[MAXWS];                     /* buffer in-use flag */
303int sseqtbl[64];                        /* sequence # to buffer # table */
304int rseqtbl[64];                        /* sequence # to buffer # table */
305int sacktbl[64];                        /* sequence # ack table */
306
307int o_isopen = 0, i_isopen = 0;         /* Input & output files are open */
308
309#ifdef DYNAMIC
310struct pktinfo *s_pkt = NULL;           /* array of pktinfo structures */
311struct pktinfo *r_pkt = NULL;           /* array of pktinfo structures */
312#else
313struct pktinfo s_pkt[MAXWS];            /* array of pktinfo structures */
314struct pktinfo r_pkt[MAXWS];            /* array of pktinfo structures */
315#endif /* DYNAMIC */
316
317#ifdef DEBUG
318char xbuf[200];                         /* For debug logging */
319#endif /* DEBUG */
320
321#ifdef DYNAMIC
322CHAR *bigsbuf = NULL, *bigrbuf = NULL;
323#else
324char bigsbt[8];                         /* Protection (shouldn't need this). */
325                                        /* BUT DON'T REMOVE IT! */
326CHAR bigsbuf[SBSIZ + 5];                /* Send-packet buffer area */
327char bigrbt[8];                         /* Safety padding */
328CHAR bigrbuf[RBSIZ + 5];                /* Receive-packet area */
329#endif
330int bigsbsiz = SBSIZ;                   /* Sizes of big send & rcv buffers. */
331int bigrbsiz = RBSIZ;
332
333#ifdef VMS
334int zchkpath(char *s);
335#endif /* VMS */
336
337/* FUNCTIONS */
338
339VOID
340dofast() {
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[];
346
347    if (maxpktsiz < 40)                 /* Long packet length */
348      maxpktsiz = 40;
349    else if (maxpktsiz > 4000)
350      maxpktsiz = 4000;
351    wslotr = maxbufsiz / maxpktsiz;
352    if (wslotr > MAXWS)                 /* Window slots */
353      wslotr = MAXWS;
354    if (wslotr > 30)
355      wslotr = 30;
356    else if (wslotr < 1)
357      wslotr = 1;
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);
362#ifdef IRIX
363#ifndef IRIX65
364    /* IRIX Telnet server chops off writes longer than 4K */
365    spsiz = spmax = spsizr = urpsiz;
366    debug(F101,"doarg Q IRIX spsiz","",spsiz);
367    spsizf = 1;
368#endif /* IRIX65 */
369#endif /* IRIX */
370#ifdef CK_SPEED
371    setprefix(PX_CAU);                  /* Cautious unprefixing */
372#endif /* CK_SPEED */
373}
374
375
376/* For sanity, use "i" for buffer slots, "n" for packet numbers. */
377
378/* I N I B U F S */
379
380/*
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.
390*/
391
392CHAR *bigbufp = NULL;
393
394int
395inibufs(s,r) int s, r; {
396#ifdef DYNAMIC
397    unsigned
398      int size;
399#ifdef OS2
400    unsigned            /* Don't you wish everybody had unsigned long... */
401#endif /* OS2 */
402      long z;
403    int x;
404
405    debug(F101,"inibufs s","",s);
406    debug(F101,"inibufs r","",r);
407
408    if (s < 80 || r < 80) return(-1);   /* Validate arguments. */
409
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");
413    }
414    for (x = 0; x < MAXWS; x++)
415      s_pkt[x].pk_adr = NULL;           /* Initialize addresses */
416
417    if (!r_pkt) {
418        if (!(r_pkt = (struct pktinfo *) malloc(sizeof(struct pktinfo)*MAXWS)))
419          fatal("ini_pkts: no memory for s_pkt");
420    }
421    for (x = 0; x < MAXWS; x++)
422      r_pkt[x].pk_adr = NULL;           /* Initialize addresses */
423
424    if (!srvcmd) {                      /* Allocate srvcmd buffer */
425        srvcmd = (CHAR *) malloc(r + 100);
426        if (!srvcmd) return(-1);
427        srvcmdlen = r + 99;
428        *srvcmd = NUL;
429    }
430    if (bigbufp) {                      /* Free previous buffers, if any. */
431        free(bigbufp);
432        bigbufp = NULL;
433    }
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);
440        size = 65535;
441    }
442
443    /* Try to get the space.  If malloc fails, try to get a little less. */
444    /* (Obviously, this algorithm can be refined.) */
445
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. */
450          return(-1);
451    }
452    debug(F101,"inibufs size 2","",size); /* OK, we got some space. */
453
454/*
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.
462*/
463#define FACTOR 20L
464    z = ( (long) s * FACTOR ) / ( (long) s + (long) r );
465    x = ( z * ( (long) size / FACTOR ) );
466    if (x < 0) return(-1);              /* Catch overflow */
467
468    bigsbsiz = x - 5;                   /* Size of send buffer */
469    bigsbuf = bigbufp;                  /* Address of send buffer */
470    debug(F101,"inibufs bigsbsiz","",bigsbsiz);
471
472    bigrbsiz = size - x - 5;            /* Size of receive buffer */
473    bigrbuf = bigbufp + x;              /* Addresss of receive buffer */
474    debug(F101,"inibufs bigrbsiz","",bigrbsiz);
475
476    return(0);                          /* Success */
477#else                                   /* No dynamic allocation */
478    bigsbsiz = SBSIZ;                   /* Just use the symbols */
479    bigrbsiz = RBSIZ;                   /* ... */
480    return(0);                          /* Success. */
481#endif /* DYNAMIC */
482}
483
484
485/* M A K E B U F  --  Makes and clears a new buffers.  */
486
487/* Call with: */
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 */
492
493/* Subdivides the big buffer into "slots" buffers. */
494
495/* Returns: */
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. */
500
501int
502makebuf(slots,bufsiz,buf,xx)
503/* makebuf */ int slots, bufsiz; CHAR buf[]; struct pktinfo *xx; {
504
505    CHAR *a;
506    int i, size;
507
508    debug(F101,"makebuf","",slots);
509    debug(F101,"makebuf bufsiz","",bufsiz);
510    debug(F101,"makebuf MAXWS","",MAXWS);
511
512    if (slots > MAXWS || slots < 1) return(-1);
513    if (bufsiz < slots * 10 ) return(-2);
514
515    size = bufsiz / slots;              /* Divide up the big buffer. */
516    a = buf;                            /* Address of first piece. */
517
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 */
528    }
529    return(size);
530}
531
532/*  M A K S B U F  --  Makes the send-packet buffer  */
533
534int
535mksbuf(slots) int slots; {
536    int i, x;
537    sbufnum = 0;
538    if ((x = makebuf(slots,bigsbsiz,bigsbuf,s_pkt)) < 0) {
539        debug(F101,"mksbuf makebuf return","",x);
540        return(x);
541    }
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. */
545        sacktbl[i] = 0;
546    }
547    for (i = 0; i < MAXWS; i++)
548      sbufuse[i] = 0;                   /* Mark each buffer as free */
549    sbufnum = slots;
550    wcur = 0;
551    return(x);
552}
553
554/*  M A K R B U F  --  Makes the receive-packet buffer  */
555
556int
557mkrbuf(slots) int slots; {
558    int i, x;
559    rbufnum = 0;
560    if ((x = makebuf(slots,bigrbsiz,bigrbuf,r_pkt)) < 0) {
561        debug(F101,"mkrbuf makebuf return","",x);
562        return(x);
563    }
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. */
567    }
568    for (i = 0; i < MAXWS; i++)
569      rbufuse[i] = 0;                   /* Mark each buffer as free */
570    rbufnum = slots;
571    wcur = 0;
572    return(x);
573}
574
575/*  W I N D O W  --  Resize the window to n  */
576
577int
578window(n) int 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);
583    wslots = n;
584#ifdef DEBUG
585    if (deblog) dumpsbuf();
586    if (deblog) dumprbuf();
587#endif /* DEBUG */
588    return(0);
589}
590
591/*  G E T S B U F  --  Allocate a send-buffer.  */
592
593/*  Call with packet sequence number to allocate buffer for. */
594/*  Returns: */
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. */
600
601int
602getsbuf(n) int n; {                     /* Allocate a send-buffer */
603    int i;
604    CHAR * p = NULL;
605    if (n < 0 || n > 63) {
606        debug(F101,"getsbuf bad arg","",n);
607        return(-4);     /* Bad argument */
608    }
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);
626          data = p;
627          if (!data) {
628              debug(F100,"getsbuf data == NULL","",0);
629              return(-3);
630          }
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. */
635      }
636    sbufnum = 0;                        /* Didn't find one. */
637    return(-3);                         /* Shouldn't happen! */
638}
639
640int
641getrbuf() {                             /* Allocate a receive buffer */
642    int i;
643#ifdef COMMENT
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);
650#endif /* COMMENT */
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. */
663      }
664    /* debug(F101,"getrbuf foulup","",i); */
665    rbufnum = 0;                        /* Didn't find one. */
666    return(-3);                         /* Shouldn't happen! */
667}
668
669/*  F R E E S B U F  --  Free send-buffer for given packet sequence number */
670
671/*  Returns:  */
672/*   1 upon success  */
673/*  -1 if specified buffer does not exist */
674
675int
676freesbuf(n) int n; {                    /* Release send-buffer for packet n. */
677    int i;
678
679    debug(F101,"freesbuf","",n);
680    if (n < 0 || n > 63)                /* No such packet. */
681      return(-1);
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. */
689    } else {
690        debug(F101," sseqtbl[n]","",sseqtbl[n]);
691        return(-1);
692    }
693
694/* The following is done only so dumped buffers will look right. */
695
696    if (1) {
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. */
702    }
703    return(1);
704}
705
706int
707freerbuf(i) int i; {                    /* Release receive-buffer slot "i". */
708    int n;
709
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.... */
713
714    /* debug(F101,"freerbuf, slot","",i); */
715    if (i < 0 || i >= wslots) {         /* No such slot. */
716        debug(F101,"freerbuf no such slot","",i);
717        return(-1);
718    }
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 */
722      rseqtbl[n] = -1;
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);
729    }
730
731/* The following is done only so dumped buffers will look right. */
732
733    if (1) {
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. */
739    }
740    return(1);
741}
742
743/* This is like freerbuf, except it's called with a packet sequence number */
744/* rather than a packet buffer index. */
745
746VOID
747freerpkt(seq) int seq; {
748    int k;
749    debug(F101,"freerpkt seq","",seq);
750    k = rseqtbl[seq];
751    /* debug(F101,"freerpkt k","",k); */
752    if (k > -1) {
753        k = freerbuf(k);
754        /* debug(F101,"freerpkt freerbuf","",k); */
755    }
756}
757
758
759/*  C H K W I N  --  Check if packet n is in window. */
760
761/*  Returns: */
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.  */
766
767/* Call with packet number to check (n), lowest packet number in window */
768/* (bottom), and number of slots in window (slots).  */
769
770int
771chkwin(n,bottom,slots) int n, bottom, slots; {
772    int top, prev;
773
774    debug(F101,"chkwin packet","",n);
775    debug(F101,"chkwin winlo","",bottom);
776    debug(F101,"chkwin slots","",slots);
777
778/* First do the easy and common cases, where the windows are not split. */
779
780    if (n < 0 || n > 63 || bottom < 0 || bottom > 63)
781      return(-2);
782
783    if (n == bottom) return(0);         /* In a perfect world... */
784
785    top = bottom + slots;               /* Calculate window top. */
786    if (top < 64 && n < top && n >= bottom)
787      return(0);                        /* In current window. */
788
789    prev = bottom - slots;              /* Bottom of previous window. */
790    if (prev > -1 && n < bottom && n > prev)
791      return(1);                        /* In previous. */
792
793/* Now consider the case where the current window is split. */
794
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. */
802            else
803              return(-1);               /* Not in previous window. */
804        }
805    }
806
807/* Now the case where current window not split, but previous window is. */
808
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. */
816    }
817
818/* It's not in the current window, and not in the previous window... */
819
820    return(-1);                         /* So it's not in any window. */
821}
822
823int
824dumpsbuf() {                            /* Dump send-buffers */
825#ifdef DEBUG
826    int j, x, z;                        /* to debug log. */
827
828    if (! deblog) return(0);
829    x = zsoutl(ZDFILE,"SEND BUFFERS:");
830    if (x < 0) {
831        deblog = 0;
832        return(0);
833    }
834    x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
835    if (x < 0) {
836        deblog = 0;
837        return(0);
838    }
839    for (j = 0; j < wslots; j++) {
840        if (!sbufuse[j])
841          continue;
842        z = ((unsigned long)(s_pkt[j].bf_adr)) & 0xffff;
843
844        sprintf(xbuf,                   /* safe (200) */
845                "%4d%6d%10d%5d%6d%4c%5d%6d\n",
846                j,
847                sbufuse[j],
848                /* Avoid warnings when addresses are bigger than ints */
849                z,
850                s_pkt[j].bf_len,
851                s_pkt[j].pk_len,
852                s_pkt[j].pk_typ,
853                s_pkt[j].pk_seq,
854                s_pkt[j].pk_rtr
855                );
856        if (zsout(ZDFILE,xbuf) < 0)  {
857            deblog = 0;
858            return(0);
859        }
860        if (s_pkt[j].pk_adr) {
861            x = (int)strlen((char *) s_pkt[j].pk_adr);
862            if (x)
863              sprintf(xbuf,             /* safe (checked) */
864                      "[%.72s%s]\n",s_pkt[j].pk_adr, x > 72 ? "..." : "");
865            else
866              sprintf(xbuf,"[(empty string)]\n"); /* safe (200) */
867        } else {
868            sprintf(xbuf,"[(null pointer)]\n"); /* safe (200) */
869        }
870        if (zsout(ZDFILE,xbuf) < 0) {
871            deblog = 0;
872            return(0);
873        }
874    }
875    sprintf(xbuf,"free: %d, winlo: %d\n", sbufnum, winlo); /* safe (200) */
876    if (zsout(ZDFILE,xbuf) < 0) {
877        deblog = 0;
878        return(0);
879    }
880#endif /* DEBUG */
881    return(0);
882}
883int
884dumprbuf() {                            /* Dump receive-buffers */
885#ifdef DEBUG
886    int j, x, z;
887    if (! deblog) return(0);
888    if (zsoutl(ZDFILE,"RECEIVE BUFFERS:") < 0) {
889        deblog = 0;
890        return(0);
891    }
892    x=zsoutl(ZDFILE,"buffer inuse address length data type seq flag retries");
893    if (x < 0) {
894        deblog = 0;
895        return(0);
896    }
897    for ( j = 0; j < wslots; j++ ) {
898        if (!rbufuse[j])
899          continue;
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",
903                j,
904                rbufuse[j],
905                /* Avoid warnings when addresses are bigger than ints */
906                z,
907                r_pkt[j].bf_len,
908                r_pkt[j].pk_len,
909                r_pkt[j].pk_typ,
910                r_pkt[j].pk_seq,
911                r_pkt[j].pk_rtr
912                );
913        if (zsout(ZDFILE,xbuf) < 0) {
914            deblog = 0;
915            return(0);
916        }
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)  {
921            deblog = 0;
922            return(0);
923        }
924    }
925    sprintf(xbuf,"free: %d, winlo: %d\n", rbufnum, winlo); /* safe (200) */
926    if (zsout(ZDFILE,xbuf) < 0)  {
927        deblog = 0;
928        return(0);
929    }
930#endif /* DEBUG */
931    return(0);
932}
933
934/*  S A T T R  --  Send an Attribute Packet  */
935
936/*
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.
940
941  Call with:
942    xp == 0 if we're sending a real file (F packet), or:
943    xp != 0 for screen data (X packet).
944  And:
945    flag == 1 for first A packet
946    flag == 0 for subsequent A packets.
947  Returns:
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.
952*/
953
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... */
957
958int
959sattr(xp, flag) int xp, flag; {         /* Send Attributes */
960
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];
965
966    extern char * cksysid;
967
968    /* Some extra flags are used because the "done" array is sparse */
969
970    int i, j, rc, aln, left = 0, numset = 0, xbin = 0; /* Workers */
971    int notafile = 0;
972    char *tp, c;
973
974    notafile = sndarray || pipesend ||
975#ifdef PIPESEND
976      sndfilter ||
977#endif /* PIPESEND */
978        calibrate;
979
980    debug(F101,"sattr flag","",flag);
981    if (!flag)                          /* No more attributes to send */
982      if (done[xunchar('@')])
983        return(0);
984
985    /* Initialize Attribute mechanism */
986
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 */
990          done[j] = 0;
991        max = maxdata();                /* Get maximum data field length */
992        if (notafile || xp == 1) {      /* Is it not a real file? */
993            extern char * zzndate();
994            char * p;
995            int i;
996#ifdef CALIBRATE
997            if (calibrate) {            /* Calibration run... */
998                x.lengthk = calibrate / 1024L; /* We know the length */
999                x.length = calibrate;
1000            }
1001#endif /* CALIBRATE */
1002            x.systemid.val = cksysid;   /* System ID */
1003            x.systemid.len = (int)strlen(cksysid);
1004            ckstrncpy(xdate,zzndate(),24);
1005            xdate[8] = SP;
1006            ztime(&p);
1007            for (i = 11; i < 19; i++)   /* copy hh:mm:ss */
1008              xdate[i - 2] = p[i];      /* to xdate */
1009            xdate[17] = NUL;            /* terminate */
1010            x.date.val = xdate;
1011            x.date.len = 17;
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 */
1017              return(0);
1018            debug(F101,"sattr init max","",max);
1019        }
1020    }
1021    if (nxtpkt() < 0)                   /* Got 'em, get next packet number */
1022      return(-1);                       /* Bad news if we can't */
1023
1024    i = 0;                              /* Init data field character number */
1025
1026    /* Do each attribute using first-fit method, marking as we go */
1027    /* This is rather long and repititious - could be done more cleverly */
1028
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 */
1037        } else                          /* No */
1038          left++;                       /* so mark this one left to do */
1039    }
1040#ifdef STRATUS
1041    if (atcreo && !done[xunchar(c = '$')]) { /* Creator */
1042        if (max - i >= x.creator.len + 2) { /* Enough space ? */
1043            data[i++] = c;
1044            data[i++] = tochar(x.creator.len);
1045            for (j = 0; j < x.creator.len; j++)
1046              data[i++] = x.creator.val[j];
1047            numset++;
1048            done[xunchar(c)] = 1;
1049        } else
1050          left++;
1051    }
1052    if (atacto && !done[xunchar(c = '%')]) { /* File account */
1053        if (max - i >= x.account.len + 2) {
1054            data[i++] = c;
1055            data[i++] = tochar(x.account.len);
1056            for (j = 0; j < x.account.len; j++)
1057              data[i++] = x.account.val[j];
1058            numset++;
1059            done[xunchar(c)] = 1;
1060        } else
1061          left++;
1062    }
1063    if (atfrmo && !done[xunchar(c = '/')]) { /* Packet data format */
1064        if (max - i >= x.recfm.len + 2) {
1065            data[i++] = c;
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];
1069            numset++;
1070            done[xunchar(c)] = 1;
1071        } else
1072          left++;
1073    }
1074#endif /* STRATUS */
1075
1076    xbin =                              /* Is the transfer in binary mode? */
1077#ifdef VMS
1078      binary == XYFT_I || binary == XYFT_L || /* IMAGE or LABELED */
1079        !strncmp(x.recfm.val,"F",1)     /* or RECFM=Fxxxxxx */
1080#else
1081      binary                            /* User said SET FILE TYPE BINARY  */
1082#endif /* VMS */
1083        ;
1084
1085    if (attypo && !done[xunchar(c = '"')]) { /* File type */
1086        if (max - i >= 5) {             /* Max length for this field */
1087            data[i++] = c;
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...) */
1092#ifdef CK_LABELED
1093                if (binary != XYFT_L
1094#ifdef VMS
1095                    && binary != XYFT_I
1096#endif /* VMS */
1097                    )
1098                  binary = XYFT_B;
1099#endif /* CK_LABELED */
1100            } else {                    /* Text */
1101#ifdef TSOFORMAT
1102                data[i++] = tochar(1);  /*  One character */
1103                data[i++] = 'A';        /*  A = (extended) ASCII with CRLFs */
1104#else
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 */
1110
1111#ifdef VMS
1112                binary = XYFT_T;        /* We automatically detected text */
1113#endif /* VMS */
1114            }
1115            numset++;
1116            done[xunchar(c)] = 1;
1117        } else
1118          left++;
1119    }
1120
1121#ifdef TSOFORMAT
1122    if (attypo && !xbin && !done[xunchar(c = '/')]) { /* Record format */
1123        if (max - i >= 5) {
1124            data[i++] = c;
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 */
1129        }
1130    }
1131#endif /* TSOFORMAT */
1132
1133    if (attypo && !xbin && !done[xunchar(c = '*')]) { /* Text encoding */
1134#ifdef NOCSETS
1135        if (max - i >= 3) {
1136            data[i++] = c;
1137            data[i++] = tochar(1);      /* Length of value is 1 */
1138            data[i++] = 'A';            /* A for ASCII */
1139            numset++;
1140            done[xunchar(c)] = 1;
1141        } else
1142          left++;
1143#else
1144        if (tcharset == TC_TRANSP || !xfrxla) { /* Transfer character set */
1145            if (max - i >= 3) {
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) */
1149                numset++;
1150                done[xunchar(c)] = 1;
1151            } else
1152              left++;
1153        } else {
1154            tp = tcsinfo[tcharset].designator;
1155            if (!tp) tp = "";
1156            aln = strlen(tp);
1157            if (aln > 0) {
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 */
1164                    numset++;
1165                    done[xunchar(c)] = 1;
1166                } else
1167                  left++;
1168            } else
1169              done[xunchar(c)] = 1;
1170        }
1171#endif /* NOCSETS */
1172    }
1173    if (atdato && !done[xunchar(c = '#')] && /* Creation date, if any */
1174        (aln = x.date.len) > 0) {
1175        if (max - i >= aln + 2) {
1176            data[i++] = c;
1177            data[i++] = tochar(aln);
1178            for (j = 0; j < aln; j++)
1179              data[i++] = x.date.val[j];
1180            numset++;
1181            done[xunchar(c)] = 1;
1182        } else
1183          left++;
1184    }
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) {
1190            data[i] = c;
1191            data[i+1] = tochar(aln);
1192            i += aln + 2;
1193            numset++;
1194            done[xunchar(c)] = 1;
1195        } else {
1196            data[i] = NUL;
1197            left++;
1198        }
1199    }
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) {
1205            data[i] = c;
1206            data[i+1] = tochar(aln);
1207            i += aln + 2;
1208            numset++;
1209            done[xunchar(c)] = 1;
1210        } else {
1211            data[i] = NUL;
1212            left++;
1213        }
1214    }
1215#ifdef CK_PERMS
1216    if (atlpro && !done[xunchar(c = ',')] && /* Local protection */
1217        (aln = x.lprotect.len) > 0 && !notafile && xp == 0) {
1218        if (max - i >= aln + 2) {
1219            data[i++] = c;
1220            data[i++] = tochar(aln);
1221            for (j = 0; j < aln; j++)
1222              data[i++] = x.lprotect.val[j];
1223            numset++;
1224            done[xunchar(c)] = 1;
1225        } else
1226          left++;
1227    }
1228    if (atgpro && !done[xunchar(c = '-')] && /* Generic protection */
1229        (aln = x.gprotect.len) > 0 && !notafile && xp == 0) {
1230        if (max - i >= aln + 2) {
1231            data[i++] = c;
1232            data[i++] = tochar(aln);
1233            for (j = 0; j < aln; j++)
1234              data[i++] = x.gprotect.val[j];
1235            numset++;
1236            done[xunchar(c)] = 1;
1237        } else
1238          left++;
1239    }
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) {
1246            data[i] = c;
1247            data[i+1] = tochar(aln);
1248            i += aln + 2;
1249            numset++;
1250            done[xunchar(c)] = 1;
1251        } else {
1252            data[i] = NUL;
1253            left++;
1254        }
1255    }
1256#ifndef NOFRILLS
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 */
1263            if (rprintf)
1264              data[i++] = 'P';          /* P for Print */
1265            else
1266              data[i++] = 'M';          /* M for Mail */
1267            for (j = 0; optbuf[j]; j++) /* Copy any options */
1268              data[i++] = optbuf[j];
1269            numset++;
1270            done[xunchar(c)] = 1;
1271        } else {
1272            data[i] = NUL;
1273            left++;
1274        }
1275    }
1276#endif /* NOFRILLS */
1277#ifdef CK_RESEND
1278    if (sendmode == SM_RESEND && !done[xunchar(c = '+')]) {
1279        if (max - i >= 3) {
1280            data[i++] = c;              /* Disposition */
1281            data[i++] = tochar(1);
1282            data[i++] = 'R';            /* is RESEND */
1283            numset++;
1284            done[xunchar(c)] = 1;
1285        } else
1286          left++;
1287    }
1288#endif /* CK_RESEND */
1289
1290    /* End of Attributes -- to be sent only after sending all others */
1291
1292    debug(F111,"sattr","@",i);
1293    debug(F101,"sattr numset","",numset);
1294    debug(F101,"sattr left","",left);
1295
1296    if ((left == 0 || numset == 0) && !done[xunchar(c = '@')]) {
1297        if (max - i >= 3) {
1298            data[i++] = c;              /* End of Attributes */
1299            data[i++] = SP;             /* Length 0 */
1300            data[i] = NUL;              /* Make sure it's null-terminated */
1301            numset++;
1302            done[xunchar(c)] = 1;
1303        }
1304    }
1305
1306    /* Finished - send the packet off if we have anything in it */
1307
1308    if (numset) {
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 */
1313    } else
1314      return(0);
1315}
1316
1317static char *refused = "";
1318
1319static char *reason[] = {
1320    "size", "type", "date", "creator", "account", "area", "password",
1321    "blocksize", "access", "encoding", "disposition", "protection",
1322    "protection", "origin", "format",
1323    "sys-dependent",                    /* 0 */
1324    "size",                             /* 1 */
1325    "2",                                /* 2 */
1326    "3",                                /* 3 */
1327    "4",                                /* 4 */
1328    "5",                                /* 5 */
1329    "6",                                /* 6 */
1330    "7",                                /* 7 */
1331    "8",                                /* 8 */
1332    "9",                                /* 9 */
1333    ":",                                /* : */
1334    ";",                                /* ; */
1335    "<",                                /* < */
1336    "=",                                /* = */
1337    ">",                                /* > */
1338    "name",                             /* ? */
1339    "@"
1340};
1341static int nreason = sizeof(reason) / sizeof(char *);
1342int rejection = -1;
1343
1344char *
1345getreason(s) char *s; {                 /* Decode attribute refusal reason */
1346    char c, *p;
1347    if (rejection == 1)                 /* Kludge for SET FIL COLL DISCARD */
1348      return("name");                   /* when other Kermit doesn't... */
1349    p = s;
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) ?
1355          reason[c] :
1356            "unknown";
1357    }
1358    return(p);
1359}
1360
1361int
1362rsattr(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);
1368        return(-1);
1369    }
1370#ifdef CK_RESEND
1371    if (sendmode == SM_RESEND && *s == '1') { /* RESEND length */
1372        int n; long z; CHAR *p;
1373        p = s + 1;
1374        n = xunchar(*p++);
1375        debug(F101,"rsattr RESEND n","",n);
1376        z = 0L;
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);
1382        if (sendstart > 0L)
1383          if (zfseek(sendstart) < 0)    /* Input file is already open. */
1384            return(0);
1385#ifdef CK_CURSES
1386        if (fdispla == XYFD_C)
1387          xxscreen(SCR_FS,0,fsize,"");  /* Refresh file transfer display */
1388#endif /* CK_CURSES */
1389    }
1390#endif /* CK_RESEND */
1391    refused = "";
1392    return(0);
1393}
1394
1395long rs_len = 0L;                       /* Length of file being resent to */
1396
1397/*
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
1401*/
1402int
1403gattr(s, yy) CHAR *s; struct zattr *yy; { /* Read incoming attribute packet */
1404    char c, d;
1405    char *ff;
1406    int aln, i;
1407
1408#ifndef NOCSETS
1409    extern int r_cset, axcset[];
1410#endif /* NOCSETS */
1411
1412#define ABUFL 40                        /* Temporary buffer for conversions */
1413    char abuf[ABUFL+1];
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];
1424#ifndef DYNAMIC
1425#define DSBUFL 100                      /* Disposition */
1426    static char dsbuf[DSBUFL+1];
1427#define SPBUFL 512                      /* System-dependent parameters */
1428    static char spbuf[SPBUFL+1];
1429#else
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];
1437
1438#ifdef CK_PERMS
1439    static char lprmbuf[CK_PERMLEN+1];
1440    static char gprmbuf[2];
1441#endif /* CK_PERMS */
1442
1443    char *rp;                           /* Pointer to reply buffer */
1444    int retcode;                        /* Return code */
1445
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 */
1450
1451/* Fill in the attributes we have received */
1452
1453    rp = rpbuf;                         /* Initialize reply buffer */
1454    *rp++ = 'N';                        /* for negative reply. */
1455    *rp = NUL;
1456    retcode = 0;                        /* Initialize return code. */
1457
1458    if (dest == DEST_P) {               /* SET DESTINATION PRINTER */
1459#ifdef DYNAMIC
1460        if (!dsbuf)
1461          if ((dsbuf = malloc(DSBUFL+1)) == NULL)
1462            fatal("gtattr: no memory for dsbuf");
1463#endif /* DYNAMIC */
1464        dsbuf[0] = 'P';
1465        dsbuf[1] = '\0';
1466        yy->disp.val = dsbuf;
1467        yy->disp.len = 1;
1468    }
1469    while (c = *s++) {                  /* Get attribute tag */
1470        aln = xunchar(*s++);            /* Length of attribute string */
1471        switch (c) {
1472          case '!':                     /* File length in K */
1473            for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1474              abuf[i] = *s++;
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 */
1478            break;
1479
1480          case '/':                     /* Record format */
1481            rfbuf[1] = NUL;
1482            rfbuf[2] = NUL;
1483            for (i = 0; (i < aln) && (i < RFBUFL); i++) /* Copy it */
1484              rfbuf[i] = *s++;
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);
1492                *rp++ = c;
1493                retcode = -1;
1494            }
1495            break;
1496
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 */
1500            ftbuf[i] = '\0';
1501            if (i < aln) s += (aln - i);
1502            /* TYPE attribute is enabled? */
1503            if (attypi) {
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);
1508                /* Unknown type? */
1509                if ((*ftbuf != 'A' && *ftbuf != 'B' && *ftbuf != 'I')
1510#ifdef CK_LABELED
1511/* ... Or our FILE TYPE is LABELED and the incoming file is text... */
1512                    || (binary == XYFT_L && *ftbuf == 'A' && !xflg)
1513#endif /* CK_LABELED */
1514                    ) {
1515                    retcode = -1;       /* Reject the file */
1516                    *rp++ = c;
1517                    if (!opnerr) tlog(F100," refused: type","",0);
1518                    break;
1519                }
1520/*
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.
1525*/
1526                if (yy->type.val[0] == 'A') { /* Check received attributes. */
1527#ifdef VMS
1528                    if (binary != XYFT_I) /* VMS IMAGE overrides this */
1529#endif /* VMS */
1530                      binary = XYFT_T;  /* Set current type to Text. */
1531                    debug(F101,"gattr binary 2","",binary);
1532                } else if (yy->type.val[0] == 'B') {
1533#ifdef CK_LABELED
1534                    if (binary != XYFT_L
1535#ifdef VMS
1536                        && binary != XYFT_U /* VMS special case */
1537#endif /* VMS */
1538                        )
1539#endif /* CK_LABELED */
1540#ifdef MAC
1541                    if (binary != XYFT_M) /* If not MacBinary... */
1542#endif /* MAC */
1543                      binary = XYFT_B;
1544                    debug(F101,"gattr binary 3","",binary);
1545                }
1546            }
1547            break;
1548
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);
1553            dtbuf[i] = '\0';
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. */
1562                    }
1563                }
1564            }
1565            break;
1566
1567          case '(':                     /* File Block Size */
1568            for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1569              abuf[i] = *s++;
1570            abuf[i] = '\0';             /* Terminate with null */
1571            if (i < aln) s += (aln - i);
1572            if (atblki)
1573              yy->blksize = atol(abuf); /* Convert to number */
1574            break;
1575
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);
1580            tsbuf[i] = '\0';
1581#ifndef NOCSETS
1582            xlatype = XLA_NONE;         /* Assume no translation */
1583#endif /* NOCSETS */
1584            if (atenci) {
1585                char * ss;
1586                yy->encoding.val = tsbuf; /* Pointer to string */
1587                yy->encoding.len = i;   /* Length of string */
1588                debug(F101,"gattr encoding",tsbuf,i);
1589                ss = tsbuf+1;
1590                switch (*tsbuf) {
1591#ifndef NOCSETS
1592                  case 'A':               /* Normal, nothing special */
1593                    tcharset = TC_TRANSP; /* Transparent chars untranslated */
1594                    debug(F110,"gattr sets tcharset TC_TRANSP","A",0);
1595                    break;
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);
1600                        break;
1601                    }
1602#ifdef UNICODE
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))
1610                          break;
1611                    }
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. */
1617                            *rp++ = c;
1618                            if (!opnerr)
1619                              tlog(F100," refused: character set","",0);
1620                        }
1621                    } else {
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) {
1627                                int x;
1628                                x = axcset[tcharset];
1629                                if (x > 0 && x <= MAXFCSETS) {
1630                                    fcharset = x;
1631                                    debug(F101,"gattr switch fcharset","",x);
1632                                }
1633                            }
1634                        }
1635                        /* Set up translation type and function */
1636                        setxlatype(tcharset,fcharset);
1637                    }
1638                break;
1639#endif /* NOCSETS */
1640              default:                  /* Something else. */
1641                debug(F110,"gattr unk encoding attribute",tsbuf,0);
1642                if (!unkcs) {           /* If SET UNK DISC */
1643                    retcode = -1;
1644                    *rp++ = c;
1645                    if (!opnerr) tlog(F100," refused: encoding","",0);
1646                }
1647                break;
1648                }
1649            }
1650            break;
1651
1652          case '+':                     /* Disposition */
1653#ifdef DYNAMIC
1654            if (!dsbuf)
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 */
1660            dsbuf[i] = '\0';
1661            if (i < aln) s += (aln - i);
1662            rs_len = 0;
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 */
1667                d = *dsbuf;
1668#ifndef NODISPO
1669/*
1670  Define NODISPO to disable receipt of mail or print files and of RESEND.
1671*/
1672                if (
1673#ifndef datageneral                     /* MAIL supported only for */
1674#ifndef OS2                             /* UNIX, VMS, and OS-9 */
1675#ifndef MAC
1676#ifndef GEMDOS
1677#ifndef AMIGA
1678                    d != 'M' &&         /* MAIL */
1679#endif /* AMIGA */
1680#endif /* GEMDOS */
1681#endif /* MAC */
1682#endif /* OS/2 */
1683#endif /* datageneral */
1684#ifdef CK_RESEND
1685                    d != 'R' &&         /* RESEND */
1686#endif /* CK_RESEND */
1687                    d != 'P') {         /* PRINT */
1688                    retcode = -1;       /* Unknown/unsupported disposition */
1689                    *rp++ = c;
1690                    if (!opnerr) tlog(F101," refused: bad disposition","",d);
1691                }
1692                dispos = d;
1693                debug(F000,"gattr dispos","",dispos);
1694                switch (d) {
1695#ifndef NOFRILLS
1696                  case 'M':
1697                    if (!en_mai) {
1698                        retcode = -1;
1699                        *rp++ = c;
1700                        if (!opnerr) tlog(F100," refused: mail disabled","",0);
1701                        dispos = 0;
1702                    }
1703                    break;
1704#endif /* NOFRILLS */
1705                  case 'P':
1706                    if (!en_pri) {
1707                        retcode = -1;
1708                        *rp++ = c;
1709                        if (!opnerr)
1710                          tlog(F100," refused: print disabled","",0);
1711                        dispos = 0;
1712                    }
1713                    break;
1714
1715                  case 'R':
1716                    dispos = 0;
1717#ifdef CK_RESEND
1718                    rs_len = zgetfs(ff); /* Get length of file */
1719                    debug(F111,"gattr RESEND",ff,rs_len);
1720#ifdef VMS
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);
1724#endif /* VMS */
1725#ifdef COMMENT
1726                    if (rs_len < 0L)    /* Local file doesn't exist */
1727                      rs_len = 0L;
1728#endif /* COMMENT */
1729/*
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.
1738*/
1739                    if (rs_len > 0L) {
1740                        fncsav = fncact; /* Save collision action */
1741                        fncact = XYFX_A; /* Switch to APPEND */
1742                    }
1743#else
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 */
1748                }
1749#else  /* NODISPO */
1750                retcode = -1;
1751                *rp++ = c;
1752                if (!opnerr) tlog(F100," refused: NODISPO","",0);
1753#endif /* NODISPO */
1754            }
1755            break;
1756
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 */
1760            idbuf[i] = '\0';
1761            if (i < aln) s += (aln - i);
1762            if (atsidi) {
1763                yy->systemid.val = idbuf; /* Pointer to string */
1764                yy->systemid.len = i;   /* Length of string */
1765            }
1766            break;
1767
1768          case '0':                     /* System-dependent parameters */
1769#ifdef DYNAMIC
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 */
1775            spbuf[i] = '\0';
1776            if (i < aln) s += (aln - i);
1777            if (atsysi) {
1778                yy->sysparam.val = spbuf; /* Pointer to string */
1779                yy->sysparam.len = i;   /* Length of string */
1780            }
1781            break;
1782
1783          case '1':                     /* File length in bytes */
1784            for (i = 0; (i < aln) && (i < ABUFL); i++) /* Copy it */
1785              abuf[i] = *s++;
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);
1790            break;
1791
1792
1793#ifdef CK_PERMS
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);
1799            if (atlpri) {
1800                yy->lprotect.val = (char *)lprmbuf;
1801                yy->lprotect.len = i;
1802            } else
1803              lprmbuf[0] = NUL;
1804            break;
1805
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++;
1810            gprmbuf[1] = NUL;
1811            if (atgpri) {
1812                yy->gprotect.val = (char *)gprmbuf;
1813                yy->gprotect.len = gprmbuf[0] ? 1 : 0;
1814            } else
1815              gprmbuf[0] = NUL;
1816            break;
1817#endif /* CK_PERMS */
1818
1819          default:                      /* Unknown attribute */
1820            s += aln;                   /* Just skip past it */
1821            break;
1822        }
1823    }
1824
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) */
1827
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 */
1832                *rp++ = '1';
1833                if (!opnerr) tlog(F100," refused: length bytes","",0);
1834            }
1835        } else if (yy->lengthk > -1L) { /* Length in K attribute rec'd? */
1836            if (!zchkspa(ff,(yy->lengthk * 1024))) {
1837                retcode = -1;           /* Check space */
1838                *rp++ = '!';
1839                if (!opnerr) tlog(F100," refused: length K","",0);
1840            }
1841        }
1842    }
1843    if (yy->length > -1L) {             /* Remember the file size */
1844        fsize = yy->length;
1845    } else if (yy->lengthk > -1L) {
1846        fsize = yy->lengthk * 1024L;
1847    } else fsize = -1L;
1848
1849#ifdef DEBUG
1850    if (deblog) {
1851        sprintf(abuf,"%ld",fsize);      /* safe */
1852        debug(F110,"gattr fsize",abuf,0);
1853    }
1854#endif /* DEBUG */
1855
1856    if (retcode == 0) rp = rpbuf;       /* Null reply string if accepted */
1857    *rp = '\0';                         /* End of reply string */
1858
1859#ifdef CK_RESEND
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);
1874        }
1875    }
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) */
1880    }
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. */
1886        if (fncsav != -1) {
1887            fncact = fncsav;
1888            fncsav = -1;
1889        }
1890    }
1891    debug(F111,"gattr return",rpbuf,retcode);
1892    return(retcode);
1893}
1894
1895/*  I N I T A T T R  --  Initialize file attribute structure  */
1896
1897int
1898initattr(yy) struct zattr *yy; {
1899    yy->lengthk = yy->length = -1L;
1900    yy->type.val = "";
1901    yy->type.len = 0;
1902    yy->date.val = "";
1903    yy->date.len = 0;
1904    yy->encoding.val = "";
1905    yy->encoding.len = 0;
1906    yy->disp.val = "";
1907    yy->disp.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;
1916    yy->area.val = "";
1917    yy->area.len = 0;
1918    yy->password.val = "";
1919    yy->password.len = 0;
1920    yy->blksize = -1L;
1921    yy->xaccess.val = "";
1922    yy->xaccess.len = 0;
1923#ifdef CK_PERMS
1924    if (!ofperms) ofperms = "";
1925    debug(F110,"initattr ofperms",ofperms,0);
1926    yy->lprotect.val = ofperms;
1927    yy->lprotect.len = 0 - strlen(ofperms); /* <-- NOTE! */
1928    /*
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.
1932    */
1933#else
1934    yy->lprotect.val = "";
1935    yy->lprotect.len = 0;
1936#endif /* CK_PERMS */
1937    yy->gprotect.val = "";
1938    yy->gprotect.len = 0;
1939    yy->recfm.val = "";
1940    yy->recfm.len = 0;
1941    yy->reply.val = "";
1942    yy->reply.len = 0;
1943#ifdef OS2
1944    yy->longname.len = 0 ;
1945    yy->longname.val = "" ;
1946#endif /* OS2 */
1947    return(0);
1948}
1949
1950/*  A D E B U -- Write attribute packet info to debug log  */
1951
1952int
1953adebu(f,zz) char *f; struct zattr *zz; {
1954#ifdef DEBUG
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);
1975#endif /* DEBUG */
1976    return(0);
1977}
1978
1979/*  O P E N A -- Open a file, with attributes.  */
1980/*
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).
1987
1988  Returns 0 on failure, nonzero on success.
1989*/
1990extern char *rf_err;
1991
1992int
1993opena(f,zz) char *f; struct zattr *zz; {
1994    int x, dispos = 0;
1995    static struct filinfo fcb;          /* Must be static! */
1996
1997    debug(F110,"opena f",f,0);
1998    debug(F101,"opena discard","",discard);
1999
2000    adebu(f,zz);                        /* Write attributes to debug log */
2001
2002    ffc = 0L;                           /* Init file-character counter */
2003
2004#ifdef PIPESEND
2005    if (pipesend)                       /* Receiving to a pipe - easy. */
2006      return(openo(f,zz,&fcb));         /* Just open the pipe. */
2007#endif /* PIPESEND */
2008
2009    /* Receiving to a file - set up file control structure */
2010
2011    fcb.bs = fblksiz;                   /* Blocksize */
2012#ifndef NOCSETS
2013    fcb.cs = fcharset;                  /* Character set */
2014#else
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 >> */
2026      fcb.dsp = XYFZ_A;
2027    else
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 */
2031#ifdef CK_LABELED
2032    fcb.lblopts = lf_opts;              /* Labeled file options */
2033#else
2034    fcb.lblopts = 0;
2035#endif /* CK_LABELED */
2036
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));
2040    }
2041    if (!dispos && xflg && remfile && remappd) /* REMOTE redirect append ? */
2042      dispos = fcb.dsp;
2043
2044    debug(F101,"opena dispos","",dispos);
2045
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";
2051                return(0);
2052            } else debug(F110,"opena rename ok",ofn2,0);
2053        }
2054    } else if (dispos == 'R') {         /* Receiving a RESEND */
2055        debug(F101,"opena remote len","",zz->length);
2056        debug(F101,"opena local len","",rs_len);
2057#ifdef COMMENT
2058        if (fncact == XYFX_R)           /* and file collision = RENAME */
2059          if (ofn1x)
2060#endif /* COMMENT */
2061        if (ofn1[0])
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 */
2068    }
2069    debug(F111,"opena [file]=mode: ",f,fcb.dsp);
2070    if (x = openo(f,zz,&fcb)) {         /* Try to open the file. */
2071#ifdef pdp11
2072        tlog(F110," local name:",f,0L); /* OK, open, record local name. */
2073        makestr(&prfspec,f);            /* New preliminary name */
2074#else
2075#ifndef ZFNQFP
2076        tlog(F110," local name:",f,0L);
2077        makestr(&prfspec,f);
2078#else
2079        {                               /* Log full local pathname */
2080            char *p = NULL, *q = f;
2081            if ((p = malloc(CKMAXPATH+1)))
2082              if (zfnqfp(filnam, CKMAXPATH, p))
2083                q = p;
2084            tlog(F110," local name:",q,0L);
2085            makestr(&prfspec,q);
2086            if (p) free(p);
2087        }
2088#endif /* ZFNQFP */
2089#endif /* pdp11 */
2090
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);
2095#ifndef NOCSETS
2096            if (xfrxla) {
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);
2101            } else {
2102                  tlog(F110," character-set:","transparent",0L);
2103            }
2104#endif /* NOCSETS */
2105            debug(F111,"opena charset",zz->encoding.val,zz->encoding.len);
2106        }
2107        debug(F101,"opena binary","",binary);
2108
2109#ifdef COMMENT
2110        if (fsize > -1L)
2111#endif /* COMMENT */
2112          xxscreen(SCR_FS,0,fsize,"");
2113
2114#ifdef datageneral
2115/*
2116  Need to turn on multi-tasking console interrupt task here, since multiple
2117  files may be received (huh?) ...
2118*/
2119        if ((local) && (!quiet))        /* Only do this if local & not quiet */
2120          consta_mt();                  /* Start the async read task */
2121#endif /* datageneral */
2122
2123    } else {                            /* Did not open file OK. */
2124
2125        rf_err = ck_errstr();           /* Get system error message */
2126        if (*rf_err)
2127          xxscreen(SCR_EM,0,0l,rf_err);
2128        else
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);
2133    }
2134    return(x);                          /* Pass on return code from openo */
2135}
2136
2137/*  O P E N C  --  Open a command (in place of a file) for output */
2138
2139int
2140openc(n,s) int n; char * s; {
2141    int x;
2142#ifndef NOPUSH
2143    x = zxcmd(n,s);
2144#else
2145    x = 0;
2146#endif /* NOPUSH */
2147    debug(F111,"openc zxcmd",s,x);
2148    o_isopen = (x > 0) ? 1 : 0;
2149    return(x);
2150}
2151
2152/*  C A N N E D  --  Check if current file transfer cancelled */
2153
2154int
2155canned(buf) CHAR *buf; {
2156    extern int interrupted;
2157    if (*buf == 'X') cxseen = 1;
2158    if (*buf == 'Z') czseen = 1;
2159    if (czseen || cxseen)
2160      interrupted = 1;
2161    debug(F101,"canned: cxseen","",cxseen);
2162    debug(F101," czseen","",czseen);
2163    return((czseen || cxseen) ? 1 : 0);
2164}
2165
2166
2167/*  O P E N I  --  Open an existing file for input  */
2168
2169int
2170openi(name) char *name; {
2171#ifndef NOSERVER
2172    extern int fromgetpath;
2173#endif /* NOSERVER */
2174    int x, filno;
2175    char *name2;
2176    extern CHAR *epktmsg;
2177
2178    epktmsg[0] = NUL;                   /* Initialize error message */
2179    if (memstr || sndarray) {           /* Just return if "file" is memory. */
2180        i_isopen = 1;
2181        return(1);
2182    }
2183    debug(F110,"openi name",name,0);
2184    debug(F101,"openi sndsrc","",sndsrc);
2185
2186    filno = (sndsrc == 0) ? ZSTDIO : ZIFILE;    /* ... */
2187    debug(F101,"openi file number","",filno);
2188
2189#ifndef NOSERVER
2190    /* If I'm a server and CWD is disabled and name is not from GET-PATH... */
2191
2192    if (server && !en_cwd && !fromgetpath) {
2193        zstrip(name,&name2);
2194        if (                            /* ... check if pathname included. */
2195#ifdef VMS
2196            zchkpath(name)
2197#else
2198            strcmp(name,name2)
2199#endif /* VMS */
2200            ) {
2201            tlog(F110,name,"access denied",0L);
2202            debug(F110,"openi CD disabled",name,0);
2203            ckstrncpy((char *)epktmsg,"Access denied",PKTMSGLEN);
2204            return(0);
2205        } else name = name2;
2206    }
2207#endif /* NOSERVER */
2208
2209#ifdef PIPESEND
2210    debug(F101,"openi pipesend","",pipesend);
2211    if (pipesend) {
2212        int x;
2213#ifndef NOPUSH
2214        x = zxcmd(ZIFILE,name);
2215#else
2216        x = 0;
2217#endif /* NOPUSH */
2218        i_isopen = (x > 0) ? 1 : 0;
2219        if (!i_isopen)
2220          ckstrncpy((char *)epktmsg,"Command or pipe failure",PKTMSGLEN);
2221        debug(F111,"openi pipesend zxcmd",name,x);
2222        return(i_isopen);
2223    }
2224#endif /* PIPESEND */
2225
2226#ifdef CALIBRATE
2227    if (calibrate) {
2228        i_isopen = 1;
2229        return(1);
2230    }
2231#endif /* CALIBRATE */
2232
2233    x = zopeni(filno,name);             /* Otherwise, try to open it. */
2234    debug(F111,"openi zopeni 1",name,x);
2235    if (x) {
2236        i_isopen = 1;
2237        return(1);
2238    } else {                            /* If not found, */
2239        char xname[CKMAXPATH];          /* convert the name */
2240#ifdef NZLTOR
2241        nzrtol(name,xname,fncnv,fnrpath,CKMAXPATH);
2242#else
2243        zrtol(name,xname);              /* to local form and then */
2244#endif /*  NZLTOR */
2245        x = zopeni(filno,xname);        /* try opening it again. */
2246        debug(F111,"openi zopeni 2",xname,x);
2247        if (x) {
2248            i_isopen = 1;
2249            return(1);                  /* It worked. */
2250        } else {
2251            char * s;
2252            s = ck_errstr();
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);
2259            i_isopen = 0;
2260            return(0);
2261        }
2262    }
2263}
2264
2265/*  O P E N O  --  Open a new file for output.  */
2266
2267int
2268openo(name,zz,fcb) char *name; struct zattr *zz; struct filinfo *fcb; {
2269    char *name2;
2270#ifdef DTILDE
2271    char *dirp;
2272#endif /* DTILDE */
2273
2274    int channel, x;
2275
2276    if (stdouf) {                               /* Receiving to stdout? */
2277        x = zopeno(ZSTDIO,"",zz,NULL);
2278        o_isopen = (x > 0);
2279        debug(F101,"openo stdouf zopeno","",x);
2280        return(x);
2281    }
2282    debug(F110,"openo: name",name,0);
2283
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. */
2287    }
2288    channel = ZOFILE;                   /* SET DESTINATION DISK or PRINTER */
2289
2290#ifdef PIPESEND
2291    debug(F101,"openo pipesend","",pipesend);
2292    if (pipesend) {
2293        int x;
2294#ifndef NOPUSH
2295        x = zxcmd(ZOFILE,(char *)srvcmd);
2296#else
2297        x = 0;
2298#endif /* NOPUSH */
2299        o_isopen = x > 0;
2300        debug(F101,"openo zxcmd","",x);
2301        return(x);
2302    }
2303#endif /* PIPESEND */
2304
2305    if (dest == DEST_S) {               /* SET DEST SCREEN... */
2306        channel = ZCTERM;
2307        fcb = NULL;
2308    }
2309#ifdef DTILDE
2310    if (*name == '~') {
2311        dirp = tilde_expand(name);
2312        if (*dirp) ckstrncpy(name,dirp,CKMAXPATH+1);
2313    }
2314#endif /* DTILDE */
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);
2320            return(0);
2321        } else name = name2;
2322    }
2323    if (zopeno(channel,name,zz,fcb) <= 0) { /* Try to open the file */
2324        o_isopen = 0;
2325        debug(F110,"openo failed",name,0);
2326        /* tlog(F110,"Failure to open",name,0L); */
2327        return(0);
2328    } else {
2329        o_isopen = 1;
2330        debug(F110,"openo ok, name",name,0);
2331        return(1);
2332    }
2333}
2334
2335/*  O P E N T  --  Open the terminal for output, in place of a file  */
2336
2337int
2338opent(zz) struct zattr *zz; {
2339    int x;
2340    ffc = tfc = 0L;
2341    x = zopeno(ZCTERM,"",zz,NULL);
2342    debug(F101,"opent zopeno","",x);
2343    if (x >= 0) {
2344        o_isopen = 1;
2345        binary = XYFT_T;
2346    } else
2347      return(0);
2348    return(x);
2349}
2350
2351/*  O P E N X  --  Open nothing (incoming file to be accepted but ignored)  */
2352
2353int
2354ckopenx(zz) struct zattr *zz; {
2355    ffc = tfc = 0L;                     /* Reset counters */
2356    o_isopen = 1;
2357    debug(F101,"ckopenx fsize","",fsize);
2358    xxscreen(SCR_FS,0,fsize,"");        /* Let screen display know the size */
2359    return(1);
2360}
2361
2362/*  C L S I F  --  Close the current input file. */
2363
2364int
2365clsif() {
2366    extern int xferstat, success;
2367    int x = 0;
2368
2369    fcps();                     /* Calculate CPS quickly */
2370
2371#ifdef datageneral
2372    if ((local) && (!quiet))    /* Only do this if local & not quiet */
2373      if (nfils < 1)            /* More files to send ... leave it on! */
2374        connoi_mt();
2375#endif /* datageneral */
2376
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. */
2381        } else {
2382            x = zclose(ZIFILE);         /* else close input file. */
2383        }
2384#ifdef DEBUG
2385        if (deblog) {
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);
2394        }
2395#endif /* DEBUG */
2396        if ((cxseen || czseen) && !epktsent) { /* If interrupted */
2397            xxscreen(SCR_ST,ST_INT,0l,""); /* say so */
2398#ifdef TLOG
2399            if (tralog && !tlogfmt)
2400              doxlog(what,psfspec,fsize,binary,1,"Interrupted");
2401#endif /* TLOG */
2402        } else if (discard && !epktsent) { /* If I'm refusing */
2403            xxscreen(SCR_ST,ST_REFU,0l,refused); /* say why */
2404#ifdef TLOG
2405            if (tralog && !tlogfmt) {
2406                char buf[128];
2407                ckmakmsg(buf,128,"Refused: ",refused,NULL,NULL);
2408                doxlog(what,psfspec,fsize,binary,1,buf);
2409            }
2410#endif /* TLOG */
2411        } else if (!epktrcvd && !epktsent && !cxseen && !czseen) {
2412            long zz;
2413            zz = ffc;
2414#ifdef CK_RESEND
2415            if (sendmode == SM_RESEND || sendmode == SM_PSEND)
2416              zz += sendstart;
2417#endif /* CK_RESEND */
2418            debug(F101,"clsif fstats","",zz);
2419            fstats();                   /* Update statistics */
2420            if (                        /* Was the whole file sent? */
2421#ifdef VMS
2422                0                       /* Not a reliable check in VMS */
2423#else
2424#ifdef STRATUS
2425                0                       /* Probably not for VOS either */
2426#else
2427                zz < fsize
2428#ifdef CK_CTRLZ
2429                && ((eofmethod != XYEOF_Z && !binary) || binary)
2430#endif /* CK_CTRLZ */
2431#endif /* STRATUS */
2432#endif /* VMS */
2433                ) {
2434                xxscreen(SCR_ST,ST_INT,0l,"");
2435#ifdef TLOG
2436                if (tralog && !tlogfmt)
2437                  doxlog(what,psfspec,fsize,binary,1,"Incomplete");
2438#endif /* TLOG */
2439            } else {
2440#ifdef COMMENT
2441                /* Not yet -- we don't have confirmation from the receiver */
2442                xxscreen(SCR_ST,ST_OK,0l,"");
2443#endif /* COMMENT */
2444#ifdef TLOG
2445                if (tralog && !tlogfmt)
2446                  doxlog(what,psfspec,fsize,binary,0,"");
2447#endif /* TLOG */
2448            }
2449        }
2450    }
2451    i_isopen = 0;
2452    hcflg = 0;                          /* Reset flags */
2453    sendstart = 0L;                     /* Don't do this again! */
2454#ifdef COMMENT
2455/*
2456  This prevents a subsequent call to clsof() from deleting the file
2457  when given the discard flag.
2458*/
2459    *filnam = '\0';                     /* and current file name */
2460#endif /* COMMENT */
2461    return(x);
2462}
2463
2464
2465/*  C L S O F  --  Close an output file.  */
2466
2467/*  Call with disp != 0 if file is to be discarded.  */
2468/*  Returns -1 upon failure to close, 0 or greater on success. */
2469
2470int
2471clsof(disp) int disp; {
2472    int x = 0;
2473    extern int success;
2474
2475    fcps();                             /* Calculate CPS quickly */
2476
2477    debug(F101,"clsof disp","",disp);
2478    debug(F101,"clsof cxseen","",cxseen);
2479    debug(F101,"clsof success","",success);
2480
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. */
2485    }
2486#ifdef datageneral
2487    if ((local) && (!quiet))            /* Only do this if local & not quiet */
2488      connoi_mt();
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");
2494#ifdef TLOG
2495            if (tralog && !tlogfmt)
2496              doxlog(what,prfspec,fsize,binary,1,"Can't close file");
2497#endif /* TLOG */
2498        } else if (disp) {              /* Interrupted or refused */
2499            if (keep == 0 ||            /* If not keeping incomplete files */
2500                (keep == SET_AUTO && binary == XYFT_T)
2501                ) {
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,"");
2509#ifdef TLOG
2510                        if (tralog && !tlogfmt)
2511                          doxlog(what,prfspec,fsize,binary,1,"Discarded");
2512#endif /* TLOG */
2513                    }
2514                }
2515            } else {                    /* Keep incomplete copy */
2516                debug(F100,"clsof fstats 1","",0);
2517                fstats();
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);
2522                    }
2523                }
2524                if (what & W_KERMIT) {
2525                    if (!epktrcvd && !epktsent) {
2526                        xxscreen(SCR_ST,ST_INC,0l,"");
2527#ifdef TLOG
2528                        if (tralog && !tlogfmt)
2529                          doxlog(what,prfspec,fsize,binary,1,"Incomplete");
2530#endif /* TLOG */
2531                    }
2532                }
2533            }
2534        }
2535    }
2536    if (o_isopen && x > -1 && !disp) {
2537        debug(F110,"clsof OK",rfspec,0);
2538        makestr(&rfspec,prfspec);
2539        makestr(&rrfspec,prrfspec);
2540        fstats();
2541        if (!epktrcvd && !epktsent && !cxseen && !czseen) {
2542            xxscreen(SCR_ST,ST_OK,0L,"");
2543#ifdef TLOG
2544            if (tralog && !tlogfmt)
2545              doxlog(what,rfspec,fsize,binary,0,"");
2546#endif /* TLOG */
2547        }
2548    }
2549    rs_len = 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. */
2553}
2554
2555#ifdef SUNOS4S5
2556tolower(c) char c; { return((c)-'A'+'a'); }
2557toupper(c) char c; { return((c)-'a'+'A'); }
2558#endif /* SUNOS4S5 */
2559#endif /* NOXFER */
Note: See TracBrowser for help on using the repository browser.