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