home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc192.zip / CKCFN3.C < prev    next >
C/C++ Source or Header  |  1996-11-10  |  56KB  |  1,745 lines

  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.  
  30. extern int unkcs, wmax, wcur, discard, bctu, bctl, local, fdispla, what,
  31.   sendmode, opnerr, dest;
  32. extern long sendstart;
  33.  
  34. extern char * ofn2;
  35. extern char ofn1[];
  36. extern int ofn1x;
  37.  
  38. extern int xflg, remfile, remappd;
  39. extern CHAR *data;
  40. extern char filnam[];
  41. #ifndef NOFRILLS
  42. extern int rprintf, rmailf;        /* REMOTE MAIL, PRINT */
  43. extern char * printfile;
  44. extern int printpipe;
  45. char optbuf[100];            /* Options for MAIL or REMOTE PRINT */
  46. #endif /* NOFRILLS */
  47. extern int wslots;
  48. extern 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.  
  63. extern int binary, spsiz;
  64. extern int pktnum, cxseen, czseen, nfils, stdinf;
  65. extern int memstr, stdouf, keep, sndsrc, hcflg;
  66. extern int server, en_cwd, en_mai, en_pri;
  67.  
  68. extern int
  69.   atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
  70.   attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; 
  71.  
  72. #ifdef STRATUS
  73. extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto;
  74. #endif /* STRATUS */
  75.  
  76. #ifdef datageneral
  77. extern int quiet;
  78. #endif /* datageneral */
  79.  
  80. extern long fsize, filcnt, ffc, tfc;
  81.  
  82. #ifndef NOCSETS
  83. extern int tcharset, fcharset;
  84. extern int ntcsets;
  85. extern struct csinfo tcsinfo[], fcsinfo[];
  86.  
  87. /* Pointers to translation functions */
  88. #ifdef CK_ANSIC
  89. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  90. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  91. extern CHAR (*rx)(CHAR); /* Pointer to input character translation function */
  92. extern CHAR (*sx)(CHAR); /* Pointer to output character translation function */
  93. #else
  94. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();    /* Character set */
  95. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();    /* translation functions. */
  96. extern CHAR (*rx)();    /* Pointer to input character translation function */
  97. extern 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.  
  103. int winlo;                /* packet number at low window edge  */
  104.  
  105. int sbufnum;                /* number of free buffers */
  106. int dum001 = 1234;            /* protection... */
  107. int sbufuse[MAXWS];            /* buffer in-use flag */
  108. int dum003 = 1111;
  109. int rbufnum;                /* number of free buffers */
  110. int dum002 = 4321;            /* more protection */
  111. int rbufuse[MAXWS];            /* buffer in-use flag */
  112. int sseqtbl[64];            /* sequence # to buffer # table */
  113. int rseqtbl[64];            /* sequence # to buffer # table */
  114. int sacktbl[64];            /* sequence # ack table */
  115.  
  116. #ifdef DYNAMIC
  117. struct pktinfo *s_pkt = NULL;        /* array of pktinfo structures */
  118. struct pktinfo *r_pkt = NULL;        /* array of pktinfo structures */
  119. #else
  120. struct pktinfo s_pkt[MAXWS];        /* array of pktinfo structures */
  121. struct pktinfo r_pkt[MAXWS];        /* array of pktinfo structures */
  122. #endif /* DYNAMIC */
  123.  
  124. #ifdef DEBUG
  125. char xbuf[200];                /* For debug logging */
  126. #endif /* DEBUG */
  127.  
  128. #ifdef DYNAMIC
  129. CHAR *bigsbuf = NULL, *bigrbuf = NULL;
  130. #else
  131. char bigsbt[8];                /* Protection (shouldn't need this). */
  132.                     /* BUT DON'T REMOVE IT! */
  133. CHAR bigsbuf[SBSIZ + 5];        /* Send-packet buffer area */
  134. char bigrbt[8];                /* Safety padding */
  135. CHAR bigrbuf[RBSIZ + 5];        /* Receive-packet area */
  136. #endif
  137. int bigsbsiz = SBSIZ;            /* Sizes of big send & rcv buffers. */
  138. int bigrbsiz = RBSIZ;
  139.  
  140. #ifdef VMS
  141. int 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.  
  162. CHAR *bigbufp = NULL;
  163.  
  164. int
  165. inibufs(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.  
  276. int
  277. makebuf(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.  
  309. int
  310. mksbuf(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.  
  331. int
  332. mkrbuf(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.  
  352. int
  353. window(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.  
  376. int
  377. getsbuf(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.  
  407. int
  408. getrbuf() {                /* 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.  
  437. int
  438. freesbuf(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.  
  468. int
  469. freerbuf(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.  
  508. VOID
  509. freerpkt(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.  
  532. int
  533. chkwin(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.  
  585. int
  586. dumpsbuf() {                /* 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. }
  639. int
  640. dumprbuf() {                /* 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. */
  695. int
  696. sattr(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.  
  850. static char *refused = "";
  851.  
  852. static 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. };
  874. static int nreason = sizeof(reason) / sizeof(char *);
  875. int rejection = -1;
  876.  
  877. char *
  878. getreason(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.  
  892. int
  893. rsattr(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.  
  926. long 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. */
  933. int
  934. gattr(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.  
  1326. int
  1327. initattr(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.  
  1369. int
  1370. adebu(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. */
  1407. extern char *rf_err;
  1408.  
  1409. int
  1410. opena(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.  
  1539. int
  1540. canned(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.  
  1551. int
  1552. openi(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.  
  1603. static int isopen = 0;
  1604.  
  1605. int
  1606. openo(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.  
  1647. int
  1648. opent(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.  
  1656. int
  1657. clsif() {
  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.  
  1693. int
  1694. clsof(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
  1742. tolower(c) char c; { return((c)-'A'+'a'); }
  1743. toupper(c) char c; { return((c)-'a'+'A'); }
  1744. #endif /* SUNOS4S5 */
  1745.