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

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