home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / ckc192.zip / CKCFNS.C < prev    next >
C/C++ Source or Header  |  1996-11-24  |  108KB  |  3,389 lines

  1. char *fnsv = "C-Kermit functions, 6.0.133, 6 Sep 96";
  2.  
  3. /*  C K C F N S  --  System-independent Kermit protocol support functions.  */
  4.  
  5. /*  ...Part 1 (others moved to ckcfn2,3 to make this module smaller) */
  6.  
  7. /*
  8.   Author: Frank da Cruz <fdc@columbia.edu>,
  9.   Columbia University Academic Information Systems, New York City.
  10.  
  11.   Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
  12.   York.  The C-Kermit software may not be, in whole or in part, licensed or
  13.   sold for profit as a software product itself, nor may it be included in or
  14.   distributed with commercial products or otherwise distributed by commercial
  15.   concerns to their clients or customers without written permission of the
  16.   Office of Kermit Development and Distribution, Columbia University.  This
  17.   copyright notice must not be removed, altered, or obscured.
  18. */
  19. /*
  20.  System-dependent primitives defined in:
  21.  
  22.    ck?tio.c -- terminal i/o
  23.    cx?fio.c -- file i/o, directory structure
  24. */
  25. #include "ckcsym.h"            /* Needed for Stratus VOS */
  26. #include "ckcasc.h"            /* ASCII symbols */
  27. #include "ckcdeb.h"            /* Debug formats, typedefs, etc. */
  28. #include "ckcker.h"            /* Symbol definitions for Kermit */
  29. #include "ckcxla.h"            /* Character set symbols */
  30.  
  31. #ifdef OS2
  32. #include <io.h>
  33. #endif /* OS2 */
  34.  
  35. #ifdef VMS
  36. #include <errno.h>
  37. #endif /* VMS */
  38.  
  39. /* Externals from ckcmai.c */
  40. extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
  41.  rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr, xitsta;
  42. extern int pktnum, bctr, bctu, bctl, fmask, clfils, sbufnum, protocol,
  43.  size, osize, spktl, nfils, warn, timef, spsizf, sndtyp, rcvtyp, success;
  44. extern int parity, turn, network, what, whatru, fsecs, justone, slostart,
  45.  delay, displa, xflg, mypadn, remfile, moving;
  46. extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize, sendstart, rs_len;
  47. extern long filrej, oldcps, cps, ccu, ccp;
  48. extern int fblksiz, frecl, frecfm, forg, fcctrl;
  49. extern int spackets, rpackets, timeouts, retrans, crunched, wmax, wcur;
  50. extern int hcflg, binary, fncnv, b_save, f_save, server, cxseen, czseen;
  51. extern int nakstate, discard, rejection, local;
  52. extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
  53. extern int fnspath, fnrpath;
  54. extern int atcapr, atcapb, atcapu;
  55. extern int lpcapr, lpcapb, lpcapu;
  56. extern int swcapr, swcapb, swcapu;
  57. extern int lscapr, lscapb, lscapu;
  58. extern int rscapr, rscapb, rscapu;
  59. extern int rptena, rptmin;
  60. extern int sseqtbl[];
  61. extern int numerrs;
  62. extern long rptn;
  63. extern int maxtry;
  64. extern int stdouf;
  65. extern int sendmode;
  66. #ifdef OS2
  67. extern struct zattr iattr;
  68. #endif /* OS2 */
  69.  
  70. #ifndef NOCSETS
  71. extern int tcharset, fcharset;
  72. extern int ntcsets;
  73. extern struct csinfo tcsinfo[], fcsinfo[];
  74. #endif /* NOCSETS */
  75.  
  76. extern int
  77.   atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
  78.   attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; 
  79.  
  80. extern int bigsbsiz, bigrbsiz;
  81. extern char *versio;
  82. extern char whoareu[], * cksysid;
  83.  
  84. #ifndef NOSERVER
  85. extern int ngetpath;
  86. extern char * getpath[];
  87. #endif /* NOSERVER */
  88.  
  89. #ifdef DYNAMIC
  90.   extern CHAR *srvcmd;
  91. #else
  92.   extern CHAR srvcmd[];
  93. #endif /* DYNAMIC */
  94. extern CHAR padch, mypadc, eol, seol, feol, ctlq, myctlq, sstate, myrptq;
  95. extern CHAR *data, padbuf[], stchr, mystch;
  96. extern CHAR *srvptr;
  97. extern CHAR *rdatap;
  98. extern char *cmarg, *cmarg2, *hlptxt, **cmlist, filnam[], fspec[];
  99.  
  100. #ifndef NOMSEND
  101. extern struct filelist * filehead, * filenext;
  102. extern int addlist;
  103. #endif /* NOMSEND */
  104.  
  105. _PROTOTYP( CHAR *rpar, (void) );
  106. _PROTOTYP( int lslook, (unsigned int b) );    /* Locking Shift Lookahead */
  107. _PROTOTYP( int szeof, (CHAR *s) );
  108. _PROTOTYP( VOID fnlist, (void) );
  109. _PROTOTYP( static int nxtdir, (void) );
  110. _PROTOTYP( static int nxtdel, (void) );
  111.  
  112. /* International character sets */
  113.  
  114. #ifndef NOCSETS
  115. /* Pointers to translation functions */
  116. #ifdef CK_ANSIC
  117. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  118. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  119. #else
  120. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();    /* Character set */
  121. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();    /* translation functions. */
  122. #endif /* CK_ANSIC */
  123. _PROTOTYP( CHAR (*rx), (CHAR) );    /* Input translation function */
  124. _PROTOTYP( CHAR (*sx), (CHAR) );    /* Output translation function */
  125. _PROTOTYP( CHAR ident, (CHAR) );    /* Identity translation function */
  126. #endif /* NOCSETS */
  127.  
  128. /* Windowing things */
  129.  
  130. extern int rseqtbl[];            /* Rec'd-packet sequence # table */
  131.  
  132. /* (PWP) external def. of things used in buffered file input and output */
  133.  
  134. #ifdef DYNAMIC
  135. extern char *zinbuffer, *zoutbuffer;
  136. #else
  137. extern char zinbuffer[], zoutbuffer[];
  138. #endif
  139. extern char *zinptr, *zoutptr;
  140. extern int zincnt, zoutcnt;
  141.  
  142. extern long crcta[], crctb[];        /* CRC-16 generation tables */
  143.  
  144. /*
  145.   Variables defined in this module but shared by other modules.
  146. */
  147.  
  148. long crc16 = 0L;            /* File CRC = \v(crc16) */
  149. int docrc = 1;
  150. int xfrbel = 1;
  151.  
  152. char * rf_err = "Error receiving file";    /* rcvfil() error message */
  153.  
  154. #ifdef CK_SPEED
  155. short ctlp[256] = {        /* Control-Prefix table */
  156.   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C0  */
  157.   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, /* G0  */
  158.   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,
  159.   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,1, /* DEL */
  160.   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* C1  */
  161.   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, /* G1  */
  162.   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,
  163.   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,1  /* 255 */
  164. };
  165. #endif /* CK_SPEED */
  166.  
  167. int sndsrc;        /* Flag for where to get names of files to send: */
  168.                     /* -1: znext() function */
  169.                     /*  0: stdin */
  170.                     /* >0: list in cmlist */
  171.  
  172. int  memstr;                /* Flag for input from memory string */
  173. int  funcstr;                /* Flag for input from function */
  174. int  bestlen = 0;
  175. int  maxsend = 0;
  176.  
  177. #ifdef pdp11
  178. CHAR myinit[32];            /* Copy of my Send-Init data */
  179. #else
  180. CHAR myinit[100];            /* Copy of my Send-Init data */
  181. #endif /* pdp11 */
  182.  
  183. /* Variables local to this module */
  184.  
  185. #ifdef TLOG
  186. #ifndef XYZ_INTERNAL
  187. static
  188. #endif /* XYZ_INTERNAL */
  189. char *fncnam[] = {
  190.   "rename", "replace", "backup", "append", "discard", "ask", "update", ""
  191. };
  192. #endif /* TLOG */
  193.  
  194. static char *memptr;            /* Pointer for memory strings */
  195.  
  196. #ifdef CK_ANSI
  197. static int (*funcptr)(char *);        /* Pointer for function strings */
  198. #else
  199. static int (*funcptr)();
  200. #endif /* CK_ANSI */
  201.  
  202. #ifdef pdp11
  203. static char cmdstr[50];            /* System command string. */
  204. #else
  205. static char cmdstr[256];
  206. #endif /* pdp11 */
  207.  
  208. static int drain;            /* For draining stacked-up ACKs. */
  209.  
  210. static int first;            /* Flag for first char from input */
  211. static CHAR t;                /* Current character */
  212. #ifdef COMMENT
  213. static CHAR next;            /* Next character */
  214. #endif /* COMMENT */
  215.  
  216. static int ebqsent = 0;            /* 8th-bit prefix bid that I sent */
  217. static int lsstate = 0;            /* Locking shift state */
  218. static int lsquote = 0;            /* Locking shift quote */
  219.  
  220. #ifdef datageneral
  221. extern int quiet;
  222. #endif
  223.  
  224. /*  E N C S T R  --  Encode a string from memory. */
  225.  
  226. /*
  227.   Call this instead of getpkt() if source is a string, rather than a file.
  228.   Note: Character set translation is never done in this case.
  229. */
  230.  
  231. #ifdef COMMENT
  232. #define ENCBUFL 200
  233. #ifndef pdp11
  234. CHAR encbuf[ENCBUFL];
  235. #else
  236. /* This is gross, but the pdp11 root segment is out of space */
  237. /* Will allocate it in ckuusr.c. */
  238. extern CHAR encbuf[];
  239. #endif /* pdp11 */
  240. #endif /* COMMENT */
  241.  
  242. /*
  243.   Encode packet data from a string in memory rather than from a file.
  244.   Returns 0 on success, -1 if the string could not be completely encoded
  245.   into the currently negotiated data field length.
  246. */
  247. int
  248. encstr(s) CHAR* s; {
  249. #ifdef COMMENT
  250.     int m; char *p;
  251.     CHAR *dsave;
  252.  
  253.     if (!s) s = (CHAR *)"";
  254.     if ((m = (int)strlen((char *)s)) > ENCBUFL) {
  255.     debug(F111,"encstr string too long for buffer",s,ENCBUFL);
  256.     s[ENCBUFL] = '\0';
  257.     }
  258.     if (m > spsiz-bctl-3) {
  259.     debug(F111,"encstr string too long for packet",s,spsiz-bctl-3);
  260.     s[spsiz-bctl-3] = '\0';
  261.     }
  262.     m = memstr; p = memptr;        /* Save these. */
  263.  
  264.     memptr = (char *)s;            /* Point to the string. */
  265.     memstr = 1;                /* Flag memory string as source. */
  266.     first = 1;                /* Initialize character lookahead. */
  267.     dsave = data;            /* Boy is this ugly... */
  268.     data = encbuf + 7;            /* Why + 7?  See spack()... */
  269.     *data = NUL;            /* In case s is empty */
  270.     getpkt(spsiz,0);            /* Fill a packet from the string. */
  271.     data = dsave;            /* (sorry...) */
  272.     memstr = m;                /* Restore memory string flag */
  273.     memptr = p;                /* and pointer */
  274.     first = 1;                /* Put this back as we found it. */
  275.     return(0);
  276. #else
  277. /*
  278.   Recoded 30 Jul 94 to use the regular data buffer and the negotiated
  279.   maximum packet size.  Previously we were limited to the length of encbuf[].
  280.   Also, to return a failure code if the entire encoded string would not fit.
  281. */
  282.     int m, rc, slen; char *p;
  283.     if (!s) s = (CHAR *)"";        /* Watch out for null pointers. */
  284.     slen = strlen((char *)s);        /* Length of source string. */
  285.     rc = 0;                /* Return code. */
  286.     m = memstr; p = memptr;        /* Save these. */
  287.     memptr = (char *)s;            /* Point to the string. */
  288.     memstr = 1;                /* Flag memory string as source. */
  289.     first = 1;                /* Initialize character lookahead. */
  290.     *data = NUL;            /* In case s is empty */
  291.     getpkt(spsiz,0);            /* Fill a packet from the string. */
  292.  
  293.     if (
  294. #ifdef COMMENT
  295.     *memptr
  296. #else
  297.     memptr < (char *)(s + slen)
  298. #endif /* COMMENT */
  299.     ) {                /* This means we didn't encode */
  300.     rc = -1;            /* the whole string. */
  301.     debug(F101,"encstr string too big","",size);
  302.     } else
  303.       debug(F101,"encstr fits OK, size","",size);
  304.     memstr = m;                /* Restore memory string flag */
  305.     memptr = p;                /* and pointer */
  306.     first = 1;                /* Put this back as we found it. */
  307.     return(rc);
  308. #endif /* COMMENT */
  309. }
  310.  
  311. #ifdef COMMENT
  312. /*
  313.   We don't use this routine any more -- the code has been incorporated
  314.   directly into getpkt() to reduce per-character function call overhead.
  315.   Also, watch out: this routine hasn't been updated since it was commented
  316.   out a long time ago.
  317. */
  318. /* E N C O D E - Kermit packet encoding procedure */
  319.  
  320. VOID
  321. encode(a) CHAR a; {            /* The current character */
  322.     int a7;                /* Low order 7 bits of character */
  323.     int b8;                /* 8th bit of character */
  324.  
  325. #ifndef NOCSETS
  326.     if (!binary && sx) a = (*sx)(a);    /* Translate. */
  327. #endif /* NOCSETS */
  328.  
  329.     if (rptflg)    {                   /* Repeat processing? */
  330.         if (a == next && (first == 0)) { /* Got a run... */
  331.         if (++rpt < 94)        /* Below max, just count */
  332.                 return;
  333.         else if (rpt == 94) {    /* Reached max, must dump */
  334.                 data[size++] = rptq;
  335.                 data[size++] = tochar(rpt);
  336.         rptn += rpt;        /* Count, for stats */
  337.                 rpt = 0;
  338.         }
  339.         } else if (rpt == 1) {        /* Run broken, only 2? */
  340.             rpt = 0;            /* Yes, reset repeat flag & count. */
  341.         encode(a);            /* Do the character twice. */
  342.         if (size <= maxsize) osize = size;
  343.         rpt = 0;
  344.         encode(a);
  345.         return;
  346.     } else if (rpt > 1) {        /* More than two */
  347.             data[size++] = rptq;    /* Insert the repeat prefix */
  348.             data[size++] = tochar(++rpt); /* and count. */
  349.         rptn += rpt;
  350.             rpt = 0;            /* Reset repeat counter. */
  351.         }
  352.     }
  353.     a7 = a & 0177;            /* Isolate ASCII part */
  354.     b8 = a & 0200;            /* and 8th (parity) bit. */
  355.  
  356.     if (ebqflg && b8) {            /* Do 8th bit prefix if necessary. */
  357.         data[size++] = ebq;
  358.         a = a7;
  359.     }
  360.     if ((a7 < SP) || (a7==DEL))    {    /* Do control prefix if necessary */
  361.         data[size++] = myctlq;
  362.     a = ctl(a);
  363.     }
  364.     if (a7 == myctlq)            /* Prefix the control prefix */
  365.         data[size++] = myctlq;
  366.  
  367.     if ((rptflg) && (a7 == rptq))    /* If it's the repeat prefix, */
  368.         data[size++] = myctlq;        /* quote it if doing repeat counts. */
  369.  
  370.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th bit prefix */
  371.         data[size++] = myctlq;        /* if doing 8th-bit prefixes */
  372.  
  373.     data[size++] = a;            /* Finally, insert the character */
  374.     data[size] = '\0';            /* itself, and mark the end. */
  375. }
  376. #endif /* COMMENT */
  377.  
  378. /*  Output functions passed to 'decode':  */
  379.  
  380. int                   /*  Put character in server command buffer  */
  381. #ifdef CK_ANSIC
  382. putsrv(char c)
  383. #else
  384. putsrv(c) register char c;
  385. #endif /* CK_ANSIC */
  386. /* putsrv */ {
  387.     *srvptr++ = c;
  388.     *srvptr = '\0';        /* Make sure buffer is null-terminated */
  389.     return(0);
  390. }
  391.  
  392. int                    /*  Output character to console.  */
  393. #ifdef CK_ANSIC
  394. puttrm(char c)
  395. #else
  396. puttrm(c) register char c;
  397. #endif /* CK_ANSIC */
  398. /* puttrm */ {
  399. #ifndef NOSPL    
  400.     extern char * qbufp;        /* If REMOTE QUERY active, */
  401.     extern int query, qbufn;        /* also store response in */
  402.     if (query && qbufn++ < 1024) {    /* query buffer. */
  403.     *qbufp++ = c;
  404.     *qbufp = NUL;
  405.     } /* else */            /* else means don't display */
  406. #endif /* NOSPL */
  407.     conoc(c);
  408.     return(0);
  409. }
  410.  
  411. int                    /*  Output char to file. */
  412. #ifdef CK_ANSIC
  413. putfil(char c)
  414. #else
  415. putfil(c) register char c;
  416. #endif /* CK_ANSIC */
  417. /* putfil */ {
  418.     if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
  419.     czseen = 1;               /* If write error... */
  420.     debug(F101,"putfil zchout write error, setting czseen","",1);
  421.     return(-1);
  422.     }
  423.     return(0);
  424. }
  425.  
  426. /* D E C O D E  --  Kermit packet decoding procedure */
  427.  
  428. /*
  429.  Call with string to be decoded and an output function.
  430.  Returns 0 on success, -1 on failure (e.g. disk full).
  431.  
  432.  This is the "inner loop" when receiving files, and must be coded as 
  433.  efficiently as possible.  Note some potential problems:  if a packet
  434.  is badly formed, having a prefixed sequence ending prematurely, this
  435.  function, as coded, could read past the end of the packet.  This has
  436.  never happened, thus the additional (time-consuming) tests have not
  437.  been added.
  438. */
  439.  
  440. static CHAR *xdbuf;    /* Global version of decode()'s buffer pointer */
  441.                         /* for use by translation functions. */
  442.  
  443. /* Function for pushing a character onto decode()'s input stream. */
  444.  
  445. VOID
  446. #ifdef CK_ANSIC
  447. zdstuff(CHAR c)
  448. #else
  449. zdstuff(c) CHAR c;
  450. #endif /* CK_ANSIC */
  451. /* zdstuff */ {    
  452.     xdbuf--;                /* Back up the pointer. */
  453.     *xdbuf = c;                /* Stuff the character. */
  454. }
  455.  
  456. int
  457. #ifdef CK_ANSIC
  458. decode(CHAR *buf, int (*fn)(char), int xlate)
  459. #else
  460. decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
  461. #endif /* CK_ANSIC */
  462. /* decode */ {
  463.     register unsigned int a, a7, a8, b8; /* Various copies of current char */
  464.     int t;                /* Int version of character */
  465.     int ssflg;                /* Character was single-shifted */
  466.     int ccpflg;                /* For Ctrl-unprefixing stats */
  467.     long z;
  468.     CHAR c;
  469. /*
  470.   Catch the case in which we are asked to decode into a file that is not open,
  471.   for example, if the user interrupted the transfer, but the other Kermit
  472.   keeps sending.
  473. */
  474.     if ((cxseen || czseen || discard) && (fn == putfil))
  475.       return(0);
  476.  
  477.     xdbuf = buf;            /* Make global copy of pointer. */
  478.     rpt = 0;                /* Initialize repeat count. */
  479.  
  480.     while ((a = *xdbuf++ & 0xFF) != '\0') { /* Get next character. */
  481.     if (a == rptq && rptflg) {    /* Got a repeat prefix? */
  482.         rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
  483.         rptn += rpt;
  484.         a = *xdbuf++ & 0xFF;    /* and get the prefixed character. */
  485.     }
  486.     b8 = lsstate ? 0200 : 0;    /* 8th-bit value from SHIFT-STATE */
  487.     if (ebqflg && a == ebq) {    /* Have 8th-bit prefix? */
  488.         b8 ^= 0200;            /* Yes, invert the 8th bit's value, */
  489.         ssflg = 1;            /* remember we did this, */
  490.         a = *xdbuf++ & 0xFF;    /* and get the prefixed character. */
  491.     } else ssflg = 0;
  492.  
  493.     ccpflg = 0;
  494.     if (a == ctlq) {        /* If control prefix, */
  495.         a  = *xdbuf++ & 0xFF;    /* get its operand */
  496.         a7 = a & 0x7F;        /* and its low 7 bits. */
  497.         if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') { /* Controllify */
  498.         a = ctl(a);        /* if in control range. */
  499.         a7 = a & 0x7F;
  500.         ccpflg = 1;        /* Note that we did this */
  501.         ccp++;            /* Count for stats */
  502.         }
  503.     } else a7 = a & 0x7f;        /* Not control quote */
  504.  
  505.     if (a7 < 32 || a7 == 127) {    /* Control character? */
  506.         if (!ccpflg) ccu++;        /* A bare one, count it */
  507.         if (lscapu) {        /* If doing locking shifts... */
  508.         if (lsstate)        /* If SHIFTED */
  509.           a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
  510.         else            /* otherwise */
  511.           a8 = a | b8;        /* OR in 8th bit */
  512.         /* If we're not in a quoted sequence */
  513.         if (!lsquote && (!lsstate || !ssflg)) {
  514.             if (a8 == DLE) {    /* Check for DLE quote */
  515.             lsquote = 1;    /* prefixed by single shift! */
  516.             continue;
  517.             } else if (a8 == SO) { /* Check for Shift-Out */
  518.             lsstate = 1;    /* SHIFT-STATE = SHIFTED */
  519.             continue;
  520.             } else if (a8 == SI) { /* or Shift-In */
  521.             lsstate = 0;    /* SHIFT-STATE = UNSHIFTED */
  522.             continue;
  523.             }
  524.         } else lsquote = 0;
  525.         }
  526.     }
  527.     a |= b8;            /* OR in the 8th bit */
  528.     if (rpt == 0) rpt = 1;        /* If no repeats, then one */
  529.     if (!binary) {            /* If in text mode, */
  530.         if (feol && a == CR) continue; /* Convert CRLF to newline char */
  531.             if (feol && a == LF) a = feol;
  532.  
  533. #ifndef NOCSETS                /* Character-set translation */
  534. #ifdef KANJI                /* For Kanji transfers, */
  535.         if (tcharset != TC_JEUC)    /* postpone translation. */
  536. #endif /* KANJI */
  537.           if (xlate && rx) a = (*rx)((CHAR) a); /* Translate charset */
  538. #endif /* NOCSETS */
  539.         }
  540.     if (fn == putfil) { /* (PWP) speedup via buffered output and a macro */
  541.         for (; rpt > 0; rpt--) {    /* Output the char RPT times */
  542. #ifndef NOCSETS
  543. #ifdef KANJI
  544.         if (!binary && tcharset == TC_JEUC &&
  545.             fcharset != FC_JEUC) { /* Translating from J-EUC */
  546.             if (ffc == 0L) xkanjf();
  547.             if (xkanji(a,fn) < 0)  /* to something else? */
  548.               return(-1);
  549.             else t = 1;
  550.         } else
  551. #endif /* KANJI */
  552. #endif /* NOCSETS */
  553. #ifdef OS2
  554.           if (xflg && !remfile) { /* Write to virtual screen */
  555.               char _a;
  556.               _a = a & fmask;
  557.               t = conoc(_a);
  558.               if (t < 1) t = -1;
  559.           } else
  560. #endif /* OS2 */
  561.             t = zmchout(a & fmask); /* zmchout is a macro */
  562.         if (t < 0) {
  563.             debug(F101,"decode _write error - errno","",errno);
  564.             return(-1);
  565.         }
  566. #ifdef COMMENT
  567.         if (ffc == 0 && filcnt <= 1) {
  568.             debug(F101,"decode new file, filcnt","",filcnt);
  569.             debug(F101,"decode crc16","",crc16);
  570.             crc16 = 0L;        /* Should already have been done */
  571.         }
  572. #endif /* COMMENT */
  573.         ffc++;            /* Count the character */
  574.         if (docrc && !xflg && !remfile) { /* Update file CRC */
  575.             c = a;        /* Force conversion to unsigned char */
  576.             z = crc16 ^ (long)c;
  577.             crc16 = (crc16 >> 8) ^
  578.               (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
  579.         }
  580.         }
  581.     } else {            /* Output to something else. */
  582.         a &= fmask;            /* Apply file mask */
  583.         for (; rpt > 0; rpt--) {    /* Output the char RPT times */
  584.         if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
  585. #ifdef COMMENT
  586. /*
  587.   This was causing the server to count extra bytes that were part of
  588.   server command packets, like FINISH.
  589. */
  590.         ffc++;
  591. #endif /* COMMENT */
  592.         }
  593.     }
  594.     }
  595.     return(0);
  596. }
  597.  
  598. /*  G E T P K T -- Fill a packet data field  */
  599.  
  600. /*
  601.  Gets characters from the current source -- file or memory string.
  602.  Encodes the data into the packet, filling the packet optimally.
  603.  Set first = 1 when calling for the first time on a given input stream
  604.  (string or file).
  605.  
  606.  Call with:
  607.  bufmax -- current send-packet size
  608.  xlate  -- flag: 0 to skip character-set translation, 1 to translate
  609.  
  610.  Uses global variables:
  611.  t     -- current character.
  612.  first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
  613.  next  -- next character (not used any more).
  614.  data  -- pointer to the packet data buffer.
  615.  size  -- number of characters in the data buffer.
  616.  memstr - flag that input is coming from a memory string instead of a file.
  617.  memptr - pointer to string in memory.
  618.  (*sx)()  character set translation function
  619.  
  620. Returns the size as value of the function, and also sets global "size",
  621. and fills (and null-terminates) the global data array.  Returns 0 upon eof.
  622.  
  623. Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
  624. Incorporates old getchx() and encode() inline to reduce function calls,
  625. uses buffered input for much-improved efficiency, and clears up some
  626. confusion with line termination (CRLF vs LF vs CR).
  627.  
  628. Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
  629. May 1991.
  630. */
  631.  
  632. /*
  633.   Lookahead function to decide whether locking shift is worth it.  Looks at
  634.   the next four input characters to see if all of their 8th bits match the
  635.   argument.  Call with 0 or 0200.  Returns 1 if so, 0 if not.  If we don't
  636.   happen to have at least 4 more characters waiting in the input buffer,
  637.   returns 1.  Note that zinptr points two characters ahead of the current
  638.   character because of repeat-count lookahead.
  639. */
  640.  
  641. #ifdef KANJI
  642. int
  643. kgetf(
  644. #ifdef CK_ANSIC
  645.       VOID
  646. #endif /* CK_ANSIC */
  647.       ) {
  648.     if (funcstr)
  649.       return((*funcptr)());
  650.     else
  651.       return(zminchar());
  652. }
  653.  
  654. int
  655. kgetm(
  656. #ifdef CK_ANSIC
  657.       VOID
  658. #endif /* CK_ANSIC */
  659.       ) {
  660.     int x;
  661.     if (x = *memptr++) return(x);
  662.     else return(-1);
  663. }
  664. #endif /* KANJI */
  665.  
  666. int
  667. lslook(b) unsigned int b; {        /* Locking Shift Lookahead */
  668.     int i;
  669.     if (zincnt < 3)            /* If not enough chars in buffer, */
  670.       return(1);            /* force shift-state switch. */
  671.     b &= 0200;                /* Force argument to proper form. */
  672.     for (i = -1; i < 3; i++)        /* Look at next 5 characters to */
  673.       if (((*(zinptr+i)) & 0200) != b)    /* see if all their 8th bits match.  */
  674.     return(0);            /* They don't. */
  675.     return(1);                /* They do. */
  676. }
  677.  
  678. int
  679. getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
  680.     register CHAR rt = t, rnext;      /* Register shadows of the globals */
  681.     register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
  682.     register int x;            /* Loop index. */
  683.     register int a7;            /* Low 7 bits of character */
  684.  
  685.     static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' };
  686.  
  687.     CHAR xxls, xxdl, xxrc, xxss, xxcq;    /* Pieces of prefixed sequence */
  688.     int n;                /* worker */
  689.  
  690.     long z;                /* A long worker (for CRC) */
  691. /*
  692.   Assume bufmax is the receiver's total receive-packet buffer length.
  693.   Our whole packet has to fit into it, so we adjust the data field length.
  694.   We also decide optimally whether it is better to use a short-format or
  695.   long-format packet when we're near the borderline.
  696. */
  697.     n = bufmax - 5;            /* Space for Data and Checksum */
  698.     if (n > 92 && n < 96) n = 92;    /* "Short" Long packets don't pay */
  699.     if (n > 92 && lpcapu == 0)        /* If long packets needed, */
  700.       n = 92;                /* make sure they've been negotiated */
  701.     bufmax = n - bctl;            /* Space for data */
  702.     if (n > 92) bufmax -= 3;        /* Long packet needs header chksum */
  703.  
  704.     if (first == 1) {          /* If first character of this file... */
  705.     if (!memstr && ! funcstr)    /* and real file... */
  706.       ffc = 0L;            /* reset file character counter */
  707.     first = 0;            /* Next character won't be first */
  708.     *leftover = '\0';        /* Discard any interrupted leftovers */
  709.  
  710.     /* get first character of file into rt, watching out for null file */
  711.  
  712. #ifndef NOCSETS
  713. #ifdef KANJI
  714.     if (!binary && tcharset == TC_JEUC && xlate) {
  715.         x = zkanjf();
  716.         if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
  717.             first = -1;
  718.             size = 0;
  719.             if (x == -2) {
  720.                 debug(F100,"getpkt(zkanji): input error","",0);
  721.                 cxseen = 1;
  722.             } else debug(F100,"getpkt(zkanji): empty string/file","",0);
  723.             return (0);
  724.         }
  725.         rt = x;
  726.         if (!memstr) {
  727.         ffc++;
  728.         if (docrc && what == W_SEND) { /* Accumulate file crc */
  729.             z = crc16 ^ (long)rt;
  730.             crc16 = (crc16 >> 8) ^
  731.               (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
  732.         }        
  733.         }
  734.     } else {
  735. #endif /* KANJI */
  736. #endif /* not NOCSETS */
  737.     if (memstr) {            /* Reading data from memory string */
  738.         if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
  739.         first = -1;
  740.             size = 0;
  741.         debug(F100,"getpkt: empty string","",0);
  742.         return (0);
  743.         }
  744.  
  745.     } else if (funcstr) {        /* Reading data from a function */
  746.  
  747.         if ((x = (*funcptr)()) < 0) { /* End of input  */
  748.         first = -1;
  749.             size = 0;
  750.         debug(F100,"getpkt: empty input function","",0); /* Empty */
  751.         return(0);
  752.         }
  753.         ffc++;            /* Count a file character */
  754.         rt = (CHAR) x;        /* Convert int to char */
  755.         debug(F101,"getpkt funcstr","",rt);
  756.  
  757.     } else {            /* Reading data from a file */
  758.  
  759.         if ((x = zminchar()) < 0) { /* End of file or input error */
  760.         first = -1;
  761.             size = 0;
  762.         if (x == -2) {        /* Error */
  763.             debug(F100,"getpkt: input error","",0);
  764.             cxseen = 1;        /* Interrupt the file transfer */
  765.         } else {
  766.             debug(F100,"getpkt empty file","",0);
  767.         }
  768.         return(0);
  769.         }
  770.         ffc++;            /* Count a file character */
  771.         rt = (CHAR) x;        /* Convert int to char */
  772.         debug(F101,"getpkt 1st char","",rt);
  773.         if (docrc && what == W_SEND) {    /* Accumulate file crc */
  774.         z = crc16 ^ (long)rt;
  775.         crc16 = (crc16 >> 8) ^
  776.           (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
  777.         }        
  778.     }
  779. #ifndef NOCSETS
  780. #ifdef KANJI
  781.     }
  782. #endif /* KANJI */
  783. #endif /* not NOCSETS */
  784.  
  785.     rt &= fmask;            /* Apply SET FILE BYTESIZE mask */
  786.     debug(F101,"getpkt fmask","",fmask);
  787.     debug(F101,"getpkt new rt","",rt);
  788.  
  789. #ifndef NOCSETS
  790.     if (xlate) {
  791.         debug(F101,"getpkt about to call translate function","",rt);
  792.         debug(F101,"tcharset","",tcharset);
  793.         debug(F101,"fcharset","",fcharset);
  794.     }
  795. #ifdef KANJI
  796.     if (tcharset != TC_JEUC)
  797. #endif /* KANJI */
  798.       if (!binary && sx && xlate) {
  799.           rt = (*sx)(rt); /* Translate */
  800.           debug(F101," translate function returns","",rt);
  801.       }
  802. #endif /* not NOCSETS */
  803.  
  804.     /* PWP: handling of feol is done later (in the while loop)... */
  805.  
  806.     } else if ((first == -1) && (*leftover == '\0')) { /* EOF from last time */
  807.     debug(F101,"getpkt eof crc16","",crc16);
  808.     debug(F101,"getpkt eof ffc","",ffc);
  809.         return(size = 0);
  810.     }
  811. /*
  812.   Here we handle characters that were encoded for the last packet but
  813.   did not fit, and so were saved in the "leftover" array.
  814. */
  815.     dp = data;                /* Point to packet data buffer */
  816.     for (p1 = leftover; (*dp = *p1) != '\0'; p1++, dp++) /* Copy leftovers */
  817.         ;
  818.     *leftover = '\0';            /* Delete leftovers */
  819.     if (first == -1)            /* Handle EOF */
  820.       return(size = (dp - data));
  821.   
  822. /* Now fill up the rest of the packet. */
  823.  
  824.     rpt = 0;                /* Initialize character repeat count */
  825.  
  826.     while (first > -1) {        /* Until EOF... */
  827. #ifndef NOCSETS
  828. #ifdef KANJI
  829.     if (!binary && xlate && tcharset == TC_JEUC) {
  830.         if ((x = zkanji(memstr ? kgetm : kgetf)) < 0) {
  831.             first = -1;
  832.             if (x == -2) cxseen = 1;
  833.         } else if (!memstr) ffc++;
  834.         rnext = (CHAR) (x & fmask);
  835.     } else {
  836. #endif /* KANJI */
  837. #endif /* not NOCSETS */
  838.     if (memstr) {            /* Get next char from memory string */
  839.         if ((x = *memptr++) == '\0') /* End of string means EOF */
  840.           first = -1;        /* Flag EOF for next time. */
  841.         rnext = (CHAR) (x & fmask);    /* Apply file mask */
  842.     } else if (funcstr) {        /* Get next char from function */
  843.         if ((x = (*funcptr)()) < 0) /* End of string means EOF */
  844.           first = -1;        /* Flag EOF for next time. */
  845.         rnext = (CHAR) (x & fmask);    /* Apply file mask */
  846.     } else {
  847.         if ((x = zminchar()) < 0) { /* Real file, check for EOF */
  848.         first = -1;        /* Flag eof for next time. */
  849.         if (x == -2) cxseen = 1; /* If error, cancel this file. */
  850.         } else {
  851.         ffc++;        /* Count the character */
  852.         if (docrc && what == W_SEND) {    /* Accumulate file crc */
  853.             z = crc16 ^ (long)((CHAR)x & 0xff);
  854.             crc16 = (crc16 >> 8) ^
  855.               (crcta[(z & 0xF0) >> 4] ^ crctb[z & 0x0F]);
  856.         }        
  857.         }
  858.         rnext = (CHAR) (x & fmask);    /* Apply file mask */
  859.     } 
  860. #ifndef NOCSETS
  861. #ifdef KANJI
  862.     }
  863. #endif /* KANJI */
  864. #endif /* not NOCSETS */
  865.  
  866. #ifndef NOCSETS
  867. #ifdef KANJI
  868.     if (tcharset != TC_JEUC)
  869. #endif /* KANJI */
  870.         if (!binary && sx && xlate) {
  871.         rnext = (*sx)(rnext); /* Translate */
  872.         debug(F101,"getpkt xlated rnext to","",rnext);
  873.         }
  874. #endif /* not NOCSETS */
  875.  
  876.     odp = dp;            /* Remember where we started. */
  877.     xxls = xxdl = xxrc = xxss = xxcq = NUL;    /* Clear these. */
  878.  
  879. /*
  880.   Now encode the character according to the options that are in effect:
  881.     ctlp[]: whether this control character needs prefixing.
  882.     binary: text or binary mode.
  883.     rptflg: repeat counts enabled.
  884.     ebqflg: 8th-bit prefixing enabled.
  885.     lscapu: locking shifts enabled.
  886. */
  887.     if (rptflg) {            /* Repeat processing is on? */
  888.         if (
  889.         /*
  890.          * If the next char is really CRLF, then we cannot
  891.          * be doing a repeat (unless CR,CR,LF which becomes
  892.          * "~ <n-1> CR CR LF", which is OK but not most efficient).
  893.          * I just plain don't worry about this case.  The actual
  894.          * conversion from NL to CRLF is done after the rptflg if...
  895.          */
  896.         (binary || (feol && (rnext != feol))) &&
  897.  
  898.         (rt == rnext) && (first == 0)) { /* Got a run... */
  899.         if (++rpt < 94) {    /* Below max, just count */
  900.             continue;        /* go back and get another */
  901.         }
  902.         else if (rpt == 94) {    /* Reached max, must dump */
  903.             xxrc = (CHAR) tochar(rpt); /* Put the repeat count here */
  904.             rptn += rpt;    /* Accumulate it for statistics */
  905.             rpt = 0;        /* And reset it */
  906.         }
  907.         } else if (rpt > 1) {    /* More than two */
  908.         xxrc = (CHAR) tochar(++rpt); /* and count. */
  909.         rptn += rpt;
  910.         rpt = 0;        /* Reset repeat counter. */
  911.         }
  912.         /*
  913.           If (rpt == 1) we must encode exactly two characters.
  914.           This is done later, after the first character is encoded.
  915.         */
  916.     }
  917.  
  918.     if (!binary && feol && (rt == feol)) { /* It's the newline character */
  919.         if (lscapu && lsstate) {    /* If SHIFT-STATE is SHIFTED */
  920.         if (ebqflg) {        /* If single shifts enabled, */
  921.             *dp++ = (CHAR) ebq;    /* insert a single shift. */
  922.         } else {        /* Otherwise must shift in. */
  923.             *dp++ = myctlq;    /* Insert shift-out code */
  924.             *dp++ = 'O';
  925.             lsstate = 0;    /* Change shift state */
  926.         }
  927.         }
  928. #ifdef CK_SPEED
  929.         if (ctlp[CR]) {
  930.         *dp++ = myctlq;        /* Insert carriage return directly */
  931.         *dp++ = 'M';
  932.         ccp++;
  933.         } else {
  934.         *dp++ = CR;        /* Perhaps literally */
  935.         ccu++;
  936.         }
  937. #else /* !CK_SPEED */
  938.         *dp++ = myctlq;        /* Insert carriage return directly */
  939.         *dp++ = 'M';
  940.         ccp++;
  941. #endif /* CK_SPEED */
  942.         rt = LF;            /* Now make next char be linefeed. */
  943.     }
  944. /*
  945.   Now handle the 8th bit of the file character.  If we have an 8-bit
  946.   connection, we preserve the 8th bit.  If we have a 7-bit connection,
  947.   we employ either single or locking shifts (if they are enabled).
  948. */
  949.     a7 = rt & 0177;            /* Get low 7 bits of character */
  950.     if (rt & 0200) {        /* 8-bit character? */
  951.         if (lscapu) {        /* Locking shifts enabled? */
  952.         if (!lsstate) {        /* Not currently shifted? */
  953.             x = lslook(0200);    /* Look ahead */
  954.             if (x != 0 || ebqflg == 0) { /* Locking shift decision */
  955.             xxls = 'N';       /* Need locking shift-out */
  956.             lsstate = 1;       /* and change to shifted state */
  957.             } else if (ebqflg) {   /* Not worth it */
  958.             xxss = (CHAR) ebq; /* Use single shift */
  959.             }
  960.         }
  961.         rt = (CHAR) a7;        /* Replace character by 7-bit value */
  962.         } else if (ebqflg) {    /* 8th bit prefixing is on? */
  963.         xxss = (CHAR) ebq;    /* Insert single shift */
  964.         rt = (CHAR) a7;        /* Replace character by 7-bit value */
  965.         }
  966. /*
  967.   In case we have a 7-bit connection and this is an 8-bit character, AND
  968.   neither locking shifts nor single shifts are enabled, then the character's
  969.   8th bit will be destroyed in transmission, and a block check error will
  970.   occur.
  971. */
  972.     } else if (lscapu) {        /* 7-bit character */
  973.  
  974.         if (lsstate) {        /* Comes while shifted out? */
  975.         x = lslook(0);        /* Yes, look ahead */
  976.         if (x || ebqflg == 0) {    /* Time to shift in. */
  977.             xxls = 'O';        /* Set shift-in code */
  978.             lsstate = 0;    /* Exit shifted state */
  979.         } else if (ebqflg) {    /* Not worth it, stay shifted out */
  980.             xxss = (CHAR) ebq;    /* Insert single shift */
  981.         }
  982.         }
  983.     }
  984.     /* If data character is significant to locking shift protocol... */
  985.     if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
  986.       xxdl = 'P';            /* Insert datalink escape */
  987.  
  988.     if (
  989. #ifdef CK_SPEED
  990.         /*
  991.           Thwart YET ANOTHER unwanted, unneeded, and unloved sign
  992.           extension.  This one was particularly nasty because it prevented
  993.           255 (Telnet IAC) from being prefixed on some platforms -- e.g.
  994.           VMS with VAX C -- but not others, thus causing file transfers to
  995.           fail on Telnet connections by sending bare IACs.  Not to mention
  996.           the stray memory reference.  Whoever thought it was a good idea
  997.           for characters to be signed (by default or at all) should have
  998.           thunk again.  (Sep 96)
  999.         */
  1000.         ctlp[(rt & 0xff)]        /* Lop off any "sign" extension */
  1001. #else
  1002.         (a7 < SP) || (a7 == DEL)
  1003. #endif /* CK_SPEED */
  1004.         ) {                /* Do control prefixing if necessary */
  1005.         xxcq = myctlq;        /* The prefix */
  1006.         ccp++;            /* Count it */
  1007.         rt = (CHAR) ctl(rt);    /* Uncontrollify the character */
  1008.     }
  1009. #ifdef CK_SPEED
  1010.     else if ((a7 < SP) || (a7 == DEL)) /* Count an unprefixed one */
  1011.       ccu++;
  1012. #endif /* CK_SPEED */
  1013.  
  1014.     if (a7 == myctlq)        /* Always prefix the control prefix */
  1015.       xxcq = myctlq;
  1016.  
  1017.     if ((rptflg) && (a7 == rptq))    /* If it's the repeat prefix, */
  1018.       xxcq = myctlq;        /* prefix it if doing repeat counts */
  1019.  
  1020.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th-bit prefix */
  1021.       xxcq = myctlq;        /* if doing 8th-bit prefixes */
  1022.  
  1023. /* Now construct the entire sequence */
  1024.  
  1025.     if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
  1026.     odp2 = dp;                    /* (Save this place) */
  1027.     if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
  1028.     if (xxrc) { *dp++ = (CHAR) rptq; *dp++ = xxrc; } /* Repeat count */
  1029.     if (xxss) { *dp++ = (CHAR) ebq; }           /* Single shift */
  1030.     if (xxcq) { *dp++ = myctlq; }                /* Control prefix */
  1031.     *dp++ = rt;            /* Finally, the character itself */
  1032.  
  1033.     if (rpt == 1) {            /* Exactly two copies? */
  1034.         rpt = 0;
  1035.         p2 = dp;            /* Save place temporarily */
  1036.         for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
  1037.           *dp++ = *p1;
  1038.         if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
  1039.     }
  1040.     rt = rnext;            /* Next character is now current. */
  1041.  
  1042. /* Done encoding the character.  Now take care of packet buffer overflow. */
  1043.  
  1044.     if ((dp-data) >= bufmax) {    /* If too big, save some for next. */
  1045.         size = (dp-data);        /* Calculate the size. */
  1046.         *dp = '\0';            /* Mark the end. */
  1047.         if ((dp-data) > bufmax) {    /* if packet is overfull */
  1048.         /* copy the part that doesn't fit into the leftover buffer, */
  1049.         /* taking care not to split a prefixed sequence. */
  1050.         for (p1 = leftover, p2=odp; (*p1 = *p2) != '\0'; p1++,p2++)
  1051.             ;
  1052.         debug(F111,"getpkt leftover",leftover,size);
  1053.         debug(F101,"getpkt osize","",(odp-data));
  1054.         size = (odp-data);    /* Return truncated packet. */
  1055.         *odp = '\0';        /* Mark the new end */
  1056.         }
  1057.         t = rt;            /* save for next time */
  1058. #ifdef COMMENT
  1059.         next = rnext;    
  1060. #endif /* COMMENT */
  1061.         return(size);
  1062.     }
  1063.     }                    /* Otherwise, keep filling. */
  1064.  
  1065.     size = (dp-data);            /* End of file */
  1066.     *dp = '\0';                /* Mark the end of the data. */
  1067.     debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
  1068.     return(size);             /* return partially filled last packet. */
  1069. }
  1070.  
  1071. /*  T I N I T  --  Initialize a transaction  */
  1072.  
  1073. int
  1074. tinit() {
  1075.     int x;
  1076.  
  1077. #ifdef CK_TIMERS
  1078.     extern int rttflg;
  1079. #endif /* CK_TIMERS */
  1080.     extern int rcvtimo;
  1081.     extern char whoareu[];
  1082.  
  1083.     if (server)
  1084.       moving  = 0;
  1085.     bestlen = 0;
  1086.     maxsend = 0;
  1087.     debug(F101,"tinit bestlen","",bestlen);
  1088.     whoareu[0] = NUL;
  1089.     debug(F100,"tinit setting justone=0","",0);
  1090.     justone = 0;
  1091.  
  1092. #ifndef NOCSETS
  1093.     if (tcharset == TC_TRANSP) {    /* Character set translation */
  1094.     rx = sx = NULL;            /* Transparent, no translation */
  1095. #ifdef KANJI
  1096.     } else if (tcharset == TC_JEUC) {
  1097.     rx = sx = NULL;            /* Transparent, no translation */      
  1098. #endif /* KANJI */
  1099.     } else {                /* otherwise */
  1100.     rx = xlr[tcharset][fcharset];    /* Input translation function */
  1101.     sx = xls[tcharset][fcharset];    /* Output translation function */
  1102.     }
  1103.     debug(F101,"tinit tcharset","",tcharset);
  1104.     debug(F101,"tinit fcharset","",fcharset);
  1105. #ifdef COMMENT
  1106.     debug(F101,"tinit sx   ","",sx);
  1107.     debug(F101,"tinit rx   ","",rx);
  1108. #endif /* COMMENT */
  1109. #endif /* NOCSETS */
  1110.     myinit[0] = '\0';            /* Haven't sent init string yet */
  1111.     retrans = 0;            /* Packet retransmission count */
  1112.     sndtyp = 0;                /* No previous packet */
  1113.     xflg = 0;                /* Reset x-packet flag */
  1114.     memstr = 0;                /* Reset memory-string flag */
  1115.     memptr = NULL;            /*  and buffer pointer */
  1116.     funcstr = 0;            /* Reset "read from function" flag */
  1117.     funcptr = NULL;            /*  and function pointer */
  1118.     bctu = bctl = 1;            /* Reset block check type to 1 */
  1119.     autopar = 0;            /* Automatic parity detection flag */
  1120.     rqf = -1;                /* Reset 8th-bit-quote request flag */
  1121.     ebq = MYEBQ;            /* Reset 8th-bit quoting stuff */
  1122.     ebqflg = 0;                /* 8th bit quoting not enabled */
  1123.     ebqsent = 0;            /* No 8th-bit prefix bid sent yet */
  1124.     sq = 'Y';                /* 8th-bit prefix bid I usually send */
  1125.     binary = b_save;            /* Back to what user last said */
  1126.     fncnv = f_save;            /* ... */
  1127.     pktnum = 0;                /* Initial packet number to send */
  1128.     cxseen = czseen = discard = 0;    /* Reset interrupt flags */
  1129.     *filnam = '\0';            /* Clear file name */
  1130.     spktl = 0;                /* And its length */
  1131.     nakstate = 0;            /* Assume not in a NAK'ing state */
  1132.     numerrs = 0;            /* Transmission error counter */
  1133.     if (server)             /* If acting as server, */
  1134.       timint = srvtim;            /* Use server timeout interval. */
  1135.     else                /* Otherwise */
  1136.       timint = chktimo(rtimo,timef);    /* Begin by using local value */
  1137.  
  1138. #ifdef CK_TIMERS
  1139.     if (rttflg)                /* Using round-trip timers? */
  1140.       rttinit();
  1141. #else
  1142.     rcvtimo = timint;
  1143. #endif /* CK_TIMERS */
  1144.  
  1145.     spsiz = spsizr;            /* Initial send-packet size */
  1146.     wslots = 1;                /* One window slot */
  1147.     wslotn = 1;                /* No window negotiated yet */
  1148.     winlo = 0;                /* Packet 0 is at window-low */
  1149.     x = mksbuf(1);            /* Make a 1-slot send-packet buffer */
  1150.     if (x < 0) return(x);
  1151.     x = getsbuf(0);            /* Allocate first send-buffer. */
  1152.     debug(F101,"tinit getsbuf","",x);
  1153.     if (x < 0) return(x);
  1154.     dumpsbuf();
  1155.     x = mkrbuf(wslots);            /* & a 1-slot receive-packet buffer. */
  1156.     if (x < 0) return(x);
  1157.     what = W_NOTHING;            /* Doing nothing so far... */
  1158.     lsstate = 0;            /* Initialize locking shift state */
  1159.     whatru = 0;
  1160.     return(0);
  1161. }
  1162.  
  1163. VOID
  1164. pktinit() {                /* Initialize packet sequence */
  1165.     pktnum = 0;                /* number & window low. */
  1166.     winlo = 0;
  1167. }
  1168.  
  1169. /*  R I N I T  --  Respond to S or I packet  */
  1170.  
  1171. VOID
  1172. rinit(d) CHAR *d; {
  1173.     char *tp;
  1174.     ztime(&tp);
  1175.     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
  1176.     tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
  1177.     tlog(F110,"Collision action:", fncnam[fncact],0);
  1178.     tlog(F100,"","",0);
  1179.     filcnt = filrej = 0;        /* Init file counters */
  1180.     spar(d);
  1181.     ack1(rpar());
  1182. #ifdef datageneral
  1183.     if ((local) && (!quiet))            /* Only do this if local & not quiet */
  1184.         consta_mt();                    /* Start the asynch read task */
  1185. #endif /* datageneral */
  1186. }
  1187.  
  1188.  
  1189. /*  R E S E T C  --  Reset per-transaction character counters */
  1190.  
  1191. VOID
  1192. resetc() {
  1193.     rptn = 0;                /* Repeat counts */
  1194.     fsecs = flci = flco = 0L;        /* File chars in and out */
  1195.     tfc = tlci = tlco = 0L;        /* Total file, line chars in & out */
  1196.     ccu = ccp = 0L;            /* Control-char statistics */
  1197. #ifdef COMMENT
  1198.     fsize = -1L;            /* File size */
  1199. #else
  1200.     if (what != W_SEND)
  1201.       fsize = -1L;
  1202.     debug(F101,"resetc fsize","",fsize);
  1203. #endif /* COMMENT */
  1204.     timeouts = retrans = 0;        /* Timeouts, retransmissions */
  1205.     spackets = rpackets = 0;        /* Packet counts out & in */
  1206.     crunched = 0;            /* Crunched packets */
  1207.     wcur = 0;                /* Current window size */
  1208.     wmax = 0;                /* Maximum window size used */
  1209. }
  1210.  
  1211. /*  S I N I T  --  Get & verify first file name, then send Send-Init packet */
  1212. /*
  1213.  Returns:
  1214.    1 if send operation begins successfully
  1215.    0 if send operation fails
  1216. */
  1217. #ifdef DYNAMIC
  1218. char *cmargbuf = NULL;
  1219. #else
  1220. char cmargbuf[256];
  1221. #endif /* DYNAMIC */
  1222. char *cmargp[2];
  1223.  
  1224. VOID
  1225. fnlist() {
  1226.     sndsrc = nfils;            /* Source for filenames */
  1227. #ifdef DYNAMIC
  1228.     if (!cmargbuf && !(cmargbuf = malloc(256)))
  1229.     fatal("fnlist: no memory for cmargbuf");
  1230. #endif /* DYNAMIC */
  1231.     cmargbuf[0] = NUL;            /* Initialize name buffer */
  1232.  
  1233.     debug(F101,"sinit nfils","",nfils);
  1234.     debug(F110,"sinit cmarg",cmarg,0);
  1235.     debug(F110,"sinit cmarg2",cmarg2,0);
  1236.     if (nfils == 0) {            /* Sending from stdin or memory. */
  1237.     if ((cmarg2 != NULL) && (*cmarg2)) {
  1238.         cmarg = cmarg2;        /* If F packet, "as-name" is used */
  1239.         cmarg2 = "";        /* if provided */
  1240.     } else cmarg = "stdin";        /* otherwise just use "stdin" */
  1241.     strcpy(cmargbuf,cmarg);
  1242.     cmargp[0] = cmargbuf;
  1243.     cmargp[1] = "";
  1244.     cmlist = cmargp;
  1245.     nfils = 1;
  1246.     }
  1247. }
  1248.  
  1249. int
  1250. sinit() {
  1251.     int x;                /* Worker int */
  1252.     char *tp, *xp, *m;            /* Worker string pointers */
  1253. /*
  1254.   The DECC prototype for sleep() moved from <signal.h> to <unistd.h>
  1255.   in DECC 5.2, but rather than pull in an entire header file (that might
  1256.   not even be there), potentially involving unwanted conflicts, just do this:
  1257. */  
  1258. #ifdef __DECC
  1259. #ifndef __DECC_VER            /* This exists only in 5.0 and above */
  1260.     _PROTOTYP( int sleep, (unsigned) );
  1261. #else
  1262. #if __DECC_VER < 50200000
  1263.     _PROTOTYP( int sleep, (unsigned) );
  1264. #endif /* __DECC_VER */
  1265. #endif /* __DECC_VER */
  1266. #endif /* __DECC */
  1267.  
  1268.     filcnt = filrej = 0;        /* Initialize file counters */
  1269.     fnlist();
  1270.  
  1271.     if (nfils < 0) {
  1272.     xp = cmarg;
  1273.     } else {
  1274. #ifndef NOMSEND
  1275.     if (addlist)
  1276.       xp = filehead->fl_name;
  1277.     else
  1278. #endif /* NOMSEND */
  1279.       xp = *cmlist;
  1280.     }
  1281.     x = gnfile();            /* Get first filename. */
  1282.     m = NULL;                /* Error message pointer */
  1283.     debug(F101,"sinit gnfil","",x);
  1284.     switch (x) {
  1285.       case -5: m = "Too many files match wildcard"; break;
  1286.       case -4: m = "Cancelled"; break;
  1287.       case -3: m = "Read access denied"; break;
  1288.       case -2: m = "File is not readable"; break;
  1289.       case -1: m = iswild(filnam) ? "No files match" : "File not found";
  1290.     break;
  1291.       case  0: m = "No filespec given!"; break;
  1292.       default:
  1293.     break;
  1294.     }
  1295.     debug(F101,"sinit nfils","",nfils);
  1296.     debug(F110,"sinit filnam",filnam,0);
  1297.     if (x < 1) {            /* Didn't get a file. */
  1298.     if (server)            /* Doing GET command */
  1299.       errpkt((CHAR *)m);        /* so send Error packet. */
  1300.     else                /* Doing SEND command */
  1301.       screen(SCR_EM,0,0l,m);    /* so print message. */
  1302.     tlog(F110,xp,m,0L);        /* Make transaction log entry. */
  1303.     freerbuf(rseqtbl[0]);        /* Free the buffer the GET came in. */
  1304.     return(0);            /* Return failure code */
  1305.     }
  1306.     if (!local && !server && delay > 0)    /* OS-9 sleep(0) == infinite */
  1307.       sleep(delay);            /* Delay if requested */
  1308. #ifdef datageneral
  1309.     if ((local) && (!quiet))            /* Only do this if local & not quiet */
  1310.         consta_mt();                    /* Start the asynch read task */
  1311. #endif /* datageneral */
  1312.     freerbuf(rseqtbl[0]);        /* Free the buffer the GET came in. */
  1313.     sipkt('S');                /* Send the Send-Init packet. */
  1314.     ztime(&tp);                /* Get current date/time */
  1315.     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
  1316.     tlog(F110,"Global file mode:", binary ? "binary" : "text", 0L);
  1317.     tlog(F100,"","",0);
  1318.     debug(F111,"sinit ok",filnam,0);
  1319.     return(1);
  1320. }
  1321.  
  1322. int
  1323. #ifdef CK_ANSIC
  1324. sipkt(char c)                /* Send S or I packet. */
  1325. #else
  1326. sipkt(c) char c;
  1327. #endif
  1328. /* sipkt */ {
  1329.     CHAR *rp; int k;
  1330.     debug(F101,"sipkt pktnum","",pktnum);
  1331.     k = sseqtbl[pktnum];        /* Find slot for this packet */
  1332.     debug(F101,"sipkt k","",k);
  1333.     if (k < 0) {            /* No slot? */
  1334.     k = getsbuf(winlo = pktnum);    /* Make one. */
  1335.     debug(F101,"sipkt getsbuf","",k);    
  1336.     }
  1337.     ttflui();                /* Flush pending input. */
  1338.     rp = rpar();            /* Get protocol parameters. */
  1339.     return(spack(c,pktnum,(int)strlen((char *)rp),rp)); /* Send them. */
  1340. }
  1341.  
  1342. /*  X S I N I T  --  Retransmit S-packet  */
  1343. /*
  1344.   For use in the GET-SEND sequence, when we start to send, but receive another
  1345.   copy of the GET command because the receiver didn't get our S packet.
  1346.   This retransmits the S packet and frees the receive buffer for the ACK.
  1347.   This special case is necessary because packet number zero is being re-used.
  1348. */
  1349. VOID
  1350. xsinit() {
  1351.     int k;
  1352.     k = rseqtbl[0];
  1353.     debug(F101,"xsinit k","",k);
  1354.     if (k > -1)
  1355.       freerbuf(k);
  1356.     resend(0);
  1357. }
  1358.  
  1359. /*  R C V F I L -- Receive a file  */
  1360.  
  1361. /*
  1362.   Incoming filename is in data field of F packet.
  1363.   This function decodes it into the srvcmd buffer, substituting an
  1364.   alternate "as-name", if one was given.
  1365.   Then it does any requested transformations (like converting to
  1366.   lowercase), and finally if a file of the same name already exists, 
  1367.   takes the desired collision action.
  1368. */
  1369. char ofn1[CKMAXPATH+1];            /* Buffer for output file name */
  1370. char * ofn2;                /* Pointer to backup file name */
  1371. int ofn1x;                /* Flag output file already exists */
  1372. int opnerr;                /* Flag for open error */
  1373.  
  1374. int                    /* Returns success ? 1 : 0 */
  1375. rcvfil(n) char *n; {
  1376. #ifdef OS2
  1377. #ifdef __32BIT__
  1378.     char *zs, *longname, *newlongname, *pn; /* OS/2 long name items */
  1379. #endif /* __32BIT__ */
  1380. #endif /* OS2 */
  1381. #ifdef DTILDE
  1382.     char *dirp, *tilde_expand();
  1383. #endif /* DTILDE */
  1384.     int dirflg;
  1385.  
  1386.     opnerr = 0;
  1387.     ofn2 = NULL;            /* No new name (yet) */
  1388.     lsstate = 0;            /* Cancel locking-shift state */
  1389.     srvptr = srvcmd;            /* Decode file name from packet. */
  1390.     decode(rdatap,putsrv,0);        /* Don't xlate charsets. */
  1391.     if (*srvcmd == '\0')        /* Watch out for null F packet. */
  1392.       strcpy((char *)srvcmd,"NONAME");
  1393. #ifdef DTILDE
  1394.     if (*srvcmd == '~') {
  1395.     dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
  1396.     if (*dirp != '\0') strcpy((char *)srvcmd,dirp);
  1397.     }
  1398. #else
  1399. #ifdef OS2
  1400.     if (isalpha(*srvcmd) && srvcmd[1] == ':' && srvcmd[2] == '\0')
  1401.       strcat((char *)srvcmd,"NONAME");
  1402. #endif /* OS2 */
  1403. #endif /* DTILDE */
  1404.     screen(SCR_FN,0,0l,(char *)srvcmd);    /* Put it on screen if local */
  1405.     debug(F110,"rcvfil",(char *)srvcmd,0); /* Debug log entry */
  1406.     debug(F110,"rcvfil cmarg2",cmarg2,0);
  1407.     tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
  1408.     if (cmarg2) {            /* Check for alternate name */
  1409.         if (*cmarg2) {
  1410.         debug(F110,"rcvfil substituting cmarg2",cmarg2,0);
  1411.         strcpy((char *)srvcmd,cmarg2); /* Got one, use it. */
  1412.     }
  1413.     }
  1414.     cmarg2 = "";            /* Done with alternate name */
  1415.  
  1416.     if ((int)strlen((char *)srvcmd) > CKMAXPATH) /* Watch out for overflow */
  1417.       *(srvcmd + CKMAXPATH - 1) = NUL;
  1418.  
  1419.     /* At this point, srvcmd[] contains the incoming filename or as-name */
  1420.  
  1421.     if (fnrpath) {            /* RECEIVE PATHNAMES OFF? */
  1422.     char *t;            /* Yes. */
  1423.     zstrip((char *)srvcmd,&t);    /* Off with it. */
  1424.     debug(F110,"rcvfil zstrip",t,0);
  1425.     if (!t)                /* Be sure we didn't strip too much */
  1426.       strcpy(ofn1,"UNKNOWN");
  1427.     else if (*t == '\0')
  1428.       strcpy(ofn1,"UNKNOWN");
  1429.     else
  1430.       strcpy(ofn1,t);
  1431.     strcpy((char *)srvcmd,ofn1);    /* Now copy it back. */
  1432.     }
  1433.  
  1434.     /* Now srvcmd contains incoming filename with path possibly stripped */
  1435.  
  1436.     if (fncnv)                /* FILE NAMES CONVERTED? */
  1437.       zrtol((char *)srvcmd,(char *)ofn1); /* Yes, convert to local form */
  1438.     else
  1439.       strcpy(ofn1,(char *)srvcmd);    /* No, copy literally. */
  1440.  
  1441.     /* Now the incoming filename, possibly converted, is in ofn1[]. */
  1442.  
  1443. #ifdef OS2
  1444.     /* Don't refuse the file just because the name is illegal. */
  1445.     if (!IsFileNameValid(ofn1)) {    /* Name is OK for OS/2? */
  1446. #ifdef __32BIT__
  1447.     char *zs = NULL;
  1448.     zstrip(ofn1, &zs);        /* Not valid, strip unconditionally */
  1449.     if (zs) {
  1450.         if (iattr.longname.len &&    /* Free previous longname, if any */
  1451.         iattr.longname.val)
  1452.           free(iattr.longname.val);
  1453.         iattr.longname.len = strlen(zs); /* Store in attribute structure */
  1454.         iattr.longname.val = (char *) malloc(iattr.longname.len + 1);
  1455.         if (iattr.longname.val)    /* Remember this (illegal) name */
  1456.           strcpy(iattr.longname.val, zs);
  1457.     }
  1458. #endif /* __32BIT__ */
  1459.     debug(F110,"rcvfil: invalid file name",ofn1,0);
  1460.     ChangeNameForFAT(ofn1);    /* Change to an acceptable name */
  1461.     debug(F110,"rcvfil: FAT file name",ofn1,0);
  1462.  
  1463.     } else {                /* Name is OK. */
  1464.  
  1465.     debug(F110,"rcvfil: valid file name",ofn1,0);
  1466. #ifdef __32BIT__
  1467.     if (iattr.longname.len &&
  1468.          iattr.longname.val)    /* Free previous longname, if any */
  1469.       free(iattr.longname.val);
  1470.     iattr.longname.len = 0;
  1471.     iattr.longname.val = NULL;    /* This file doesn't need a longname */
  1472. #endif /* __32BIT__ */
  1473.     }
  1474. #endif /* OS2 */
  1475.     debug(F110,"rcvfil as",ofn1,0);
  1476.  
  1477. /* Filename collision action section. */
  1478.  
  1479.     dirflg =                /* Is it a directory name? */
  1480. #ifdef CK_TMPDIR
  1481.         isdir(ofn1)
  1482. #else
  1483.     0
  1484. #endif /* CK_TMPDIR */
  1485.       ;
  1486.     debug(F101,"rcvfil dirflg","",dirflg);
  1487.     ofn1x = (zchki(ofn1) != -1);    /* File already exists? */
  1488.     debug(F101,"rcvfil ofn1x",ofn1,ofn1x);
  1489.  
  1490.     if ( (
  1491. #ifdef UNIX
  1492.     strcmp(ofn1,"/dev/null") &&    /* It's not the null device? */
  1493. #else
  1494. #ifdef OSK
  1495.     strcmp(ofn1,"/nil") &&    /* It's not the null device? */
  1496. #endif /* OSK */
  1497. #endif /* UNIX */
  1498.     !stdouf ) &&            /* Not copying to standard output? */
  1499.     ofn1x ||            /* File of same name exists? */
  1500.     dirflg ) {            /* Or file is a directory? */
  1501.         debug(F111,"rcvfil exists",ofn1,fncact);
  1502.     switch (fncact) {        /* Yes, do what user said. */
  1503.       case XYFX_A:            /* Append */
  1504.         debug(F100,"rcvfil append","",0);
  1505.         if (dirflg) {
  1506.         rf_err = "Can't append to a directory";
  1507.         tlog(F100," error - can't append to directory","",0);
  1508.         discard = opnerr = 1;
  1509.         return(0);
  1510.         }
  1511.         tlog(F110," appending to",ofn1,0);
  1512.         break;
  1513.       case XYFX_Q:            /* Query (Ask) */
  1514.         break;            /* not implemented */
  1515.       case XYFX_B:            /* Backup (rename old file) */
  1516.         if (dirflg) {
  1517.         rf_err = "Can't rename existing directory";
  1518.         tlog(F100," error - can't rename directory","",0);
  1519.         discard = opnerr = 1;
  1520.         return(0);
  1521.         }
  1522.         znewn(ofn1,&ofn2);        /* Get new unique name */
  1523.         tlog(F110," backup:",ofn2,0);
  1524.         debug(F110,"rcvfil backup ofn1",ofn1,0);
  1525.         debug(F110,"rcvfil backup ofn2",ofn2,0);
  1526. #ifdef OS2
  1527. #ifdef CK_LABELED
  1528. #ifdef __32BIT__
  1529. /*
  1530.   In case this is a FAT file system, we can't change only the FAT name, we
  1531.   also have to change the longname from the extended attributes block.
  1532.   Otherwise, we'll have many files with the same longname and if we copy them
  1533.   to an HPFS volume, only one will survive.
  1534. */
  1535.         if (os2getlongname(ofn1, &longname) > -1) {
  1536.         if (strlen(longname)) {
  1537.             char tmp[10];
  1538.             extern int ck_znewn;
  1539.             sprintf(tmp,".~%d~",ck_znewn);
  1540.             newlongname =
  1541.               (char *) malloc(strlen(longname) + strlen(tmp) + 1);
  1542.             if (newlongname) {
  1543.             strcpy(newlongname, longname);
  1544.             strcat(newlongname, tmp);
  1545.             os2setlongname(ofn1, newlongname);
  1546.             free(newlongname);
  1547.             newlongname = NULL;
  1548.             }
  1549.         }
  1550.         } else debug(F100,"rcvfil os2getlongname failed","",0);
  1551. #endif /* __32BIT__ */
  1552. #endif /* CK_LABELED */
  1553. #endif /* OS2 */
  1554.  
  1555. #ifdef COMMENT
  1556.         /* Do this later, in opena()... */
  1557.         if (zrename(ofn1,ofn2) < 0) {
  1558.         rf_err = "Can't transform filename";
  1559.         debug(F110,"rcvfil rename fails",ofn1,0);
  1560.         discard = opnerr = 1;
  1561.         return(0);
  1562.         }
  1563. #endif /* COMMENT */
  1564.         break;
  1565.  
  1566.       case XYFX_D:            /* Discard (refuse new file) */
  1567.         discard = 1;
  1568.         rejection = 1;        /* Horrible hack: reason = name */
  1569.         debug(F101,"rcvfil discard","",discard);
  1570.         tlog(F100," refused: name","",0);
  1571.         break;
  1572.  
  1573.       case XYFX_R:            /* Rename incoming file */
  1574.         znewn(ofn1,&ofn2);        /* Make new name for it */
  1575. #ifdef OS2
  1576. #ifdef __32BIT__
  1577.         if (iattr.longname.len) {
  1578.             char tmp[10];
  1579.             extern int ck_znewn;
  1580.             sprintf(tmp,".~%d~",ck_znewn);
  1581.             newlongname =
  1582.               (char *) malloc(iattr.longname.len + strlen(tmp) + 1);
  1583.             if (newlongname) {
  1584.             strcpy(newlongname, iattr.longname.val);
  1585.             strcat(newlongname, tmp);
  1586.             debug(F110,
  1587.                   "Rename Incoming: newlongname",newlongname,0);
  1588.  
  1589.             if (iattr.longname.len &&
  1590.                  iattr.longname.val)
  1591.               free(iattr.longname.val);
  1592.             iattr.longname.len = strlen(newlongname);
  1593.             iattr.longname.val = newlongname;
  1594.             }
  1595.         }
  1596. #endif /* __32BIT__ */
  1597. #endif /* OS2 */
  1598.         break;
  1599.       case XYFX_X:            /* Replace old file */
  1600.         debug(F100,"rcvfil overwrite","",0);
  1601.         if (dirflg) {
  1602.         rf_err = "Can't overwrite existing directory";
  1603.         tlog(F100," error - can't overwrite directory","",0);
  1604.         discard = opnerr = 1;
  1605. #ifdef COMMENT
  1606.         return(0);
  1607. #else
  1608.         break;
  1609. #endif /* COMMENT */
  1610.         }
  1611.         tlog(F110,"overwriting",ofn1,0);
  1612.         break;
  1613.       case XYFX_U:            /* Refuse if older */
  1614.         debug(F100,"rcvfil update","",0);
  1615.         if (dirflg) {
  1616.         rf_err = "File has same name as existing directory";
  1617.         tlog(F110," error - directory exists:",ofn1,0);
  1618.         discard = opnerr = 1;
  1619. #ifdef COMMENT
  1620.         /* Don't send an error packet, just refuse the file */
  1621.         return(0);
  1622. #endif /* COMMENT */
  1623.         }
  1624.         break;            /* Not here, we don't have */
  1625.                     /* the attribute packet yet. */
  1626.       default:
  1627.         debug(F101,"rcvfil bad collision action","",fncact);
  1628.         break;
  1629.     }
  1630.     }
  1631.     debug(F110,"rcvfil ofn1",ofn1,0);
  1632.     debug(F110,"rcvfil ofn2",ofn2,0);
  1633.     if (fncact == XYFX_R && ofn1x && ofn2) { /* Renaming incoming file? */
  1634.     screen(SCR_AN,0,0l,ofn2);    /* Display renamed name */
  1635.     strcpy(n, ofn2);        /* Return it */
  1636.     } else {                /* No */
  1637.     screen(SCR_AN,0,0l,ofn1);    /* Display regular name */
  1638.     strcpy(n, ofn1);        /* and return it. */
  1639.     }
  1640.  
  1641. #ifdef CK_MKDIR
  1642. /*  Create directory(s) if necessary.  */
  1643.     if (!discard && !fnrpath) {        /* RECEIVE PATHAMES ON? */
  1644.     debug(F110,"rcvfil calling zmkdir",ofn1,0); /* Yes */
  1645.     if (zmkdir(ofn1) < 0) {
  1646.         debug(F100,"zmkdir fails","",0);
  1647.         tlog(F110," error - directory creation failure:",ofn1,0);
  1648.         rf_err = "Directory creation failure.";
  1649.         discard = 1;
  1650.         return(0);
  1651.     }
  1652.     }
  1653. #else
  1654.     debug(F110,"sfile CK_MKDIR not defined",ofn1,0);
  1655. #endif /* CK_MKDIR */
  1656.  
  1657. #ifndef NOICP
  1658. /* #ifndef MAC */
  1659. /* Why not Mac? */
  1660.     strcpy(fspec,ofn1);            /* Here too for \v(filespec) */
  1661. /* #endif */ 
  1662. #endif /* NOICP */
  1663.     debug(F110,"rcvfil: n",n,0);
  1664.     ffc = 0L;                /* Init per-file counters */
  1665.     cps = oldcps = 0L;
  1666.     rs_len = 0L;
  1667.     rejection = -1;
  1668.     fsecs = gtimer();            /* Time this file started */
  1669.     filcnt++;
  1670.     intmsg(filcnt);
  1671.     return(1);                /* Successful return */
  1672. }
  1673.  
  1674.  
  1675. /*  R E O F  --  Receive End Of File packet for incoming file */
  1676.  
  1677. /*
  1678.   Closes the received file.
  1679.   Returns:
  1680.     0 on success.
  1681.    -1 if file could not be closed.
  1682.     2 if disposition was mail, mail was sent, but temp file not deleted.
  1683.     3 if disposition was print, file was printed, but not deleted.
  1684.    -2 if disposition was mail and mail could not be sent
  1685.    -3 if disposition was print and file could not be printed
  1686. */
  1687. int
  1688. reof(f,yy) char *f; struct zattr *yy; {
  1689.     int x;
  1690.     char *p;
  1691.     char c;
  1692.  
  1693.     debug(F111,"reof fncact",f,fncact);
  1694.     debug(F101,"reof discard","",discard);
  1695.     success = 1;            /* Assume status is OK */
  1696.     lsstate = 0;            /* Cancel locking-shift state */
  1697.     if (discard) {            /* Handle attribute refusals, etc. */
  1698.     debug(F101,"reof discarding","",0);
  1699.     success = 0;            /* Status = failed. */
  1700.     if (rejection == '#' ||        /* Unless rejection reason is */
  1701.         rejection ==  1  ||        /* date or name (SET FILE COLLISION */
  1702.         rejection == '?')        /* UPDATE or DISCARD) */
  1703.       success = 1;                
  1704.     debug(F101,"reof success","",success);
  1705.     filrej++;            /* Count this rejection. */
  1706.     discard = 0;            /* We never opened the file, */
  1707.     return(0);            /* so we don't close it. */
  1708.     }
  1709. #ifdef DEBUG
  1710.     if (deblog) {
  1711.     debug(F101,"reof cxseen","",cxseen);
  1712.     debug(F101,"reof czseen","",czseen);
  1713.     debug(F110,"reof rdatap",rdatap,0);
  1714.     }
  1715. #endif /* DEBUG */
  1716.     if (cxseen == 0) cxseen = (*rdatap == 'D');    /* Got cancel directive? */
  1717.     success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
  1718.     if (!success) filrej++;        /* "Uncount" this file */
  1719.     debug(F101,"reof success","",czseen);
  1720.     x = clsof(cxseen || czseen);    /* Close the file (resets cxseen) */
  1721.     if (x < 0) {            /* If failure to close, FAIL */
  1722.     if (success) filrej++;
  1723.     success = 0;
  1724.     }
  1725.     if (success && atcapu) zstime(f,yy,0); /* Set file creation date */
  1726. #ifdef OS2
  1727. #ifdef __32BIT__
  1728. #ifdef CK_LABELED
  1729.     if (success && yy->longname.len)
  1730.       os2setlongname(f, yy->longname.val);
  1731. #endif /* CK_LABELED */
  1732. #endif /* __32BIT__ */
  1733. #endif /* OS2 */
  1734.     if (success == 0) xitsta |= W_RECV;    /* And program return code */
  1735.  
  1736. /* Handle dispositions from attribute packet... */
  1737.  
  1738. #ifndef NOFRILLS
  1739.     if (yy->disp.len != 0) {
  1740.     p = yy->disp.val;
  1741.     c = *p++;
  1742.     if (c == 'M') {            /* Mail to user. */
  1743.         x = zmail(p,filnam);    /* Do the system's mail command */
  1744.         if (x < 0) success = 0;    /* Remember status */
  1745.         tlog(F110,"mailed",filnam,0L);
  1746.         tlog(F110," to",p,0L);
  1747.         zdelet(filnam);        /* Delete the file */
  1748.     } else if (c == 'P') {        /* Print the file. */
  1749.         x = zprint(p,filnam);    /* Do the system's print command */
  1750.         if (x < 0) success = 0;    /* Remember status */
  1751.         tlog(F110,"printed",filnam,0L);
  1752.         tlog(F110," with options",p,0L);
  1753. #ifndef VMS
  1754. #ifndef STRATUS
  1755.         /* spooler will delete file after print complete in VOS & VMS */
  1756.         if (zdelet(filnam) && x == 0) x = 3; /* Delete the file */
  1757. #endif /* STRATUS */
  1758. #endif /* VMS */
  1759.     }
  1760.     }
  1761. #endif /* NOFRILLS */
  1762.     debug(F101,"reof returns","",x);
  1763.     *filnam = '\0';
  1764.     return(x);
  1765. }
  1766.  
  1767. /*  R E O T  --  Receive End Of Transaction  */
  1768.  
  1769. VOID
  1770. reot() {
  1771.     cxseen = czseen = discard = 0;    /* Reset interruption flags */
  1772.     tstats();
  1773. }
  1774.  
  1775. /*  S F I L E -- Send File header or teXt header packet  */
  1776.  
  1777. /*  Call with x nonzero for X packet, zero for F packet  */
  1778. /*  Returns 1 on success, 0 on failure                   */
  1779.  
  1780. int
  1781. sfile(x) int x; {
  1782. #ifdef pdp11
  1783. #define PKTNL 64
  1784. #else
  1785. #define PKTNL 256
  1786. #endif /* pdp11 */
  1787.     char pktnam[PKTNL+1];        /* Local copy of name */
  1788.     char *s;
  1789.  
  1790.     /* cmarg2 or filnam (with that precedence) have the file's name */
  1791.  
  1792.     lsstate = 0;            /* Cancel locking-shift state */
  1793.     if (nxtpkt() < 0) return(0);    /* Bump packet number, get buffer */
  1794.     if (x == 0) {            /* F-Packet setup */
  1795.         if (cmarg2 && *cmarg2) {    /* If we have a send-as name, */
  1796.         debug(F111,"sfile cmarg2",cmarg2,cmarg2);
  1797.         strncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
  1798.         cmarg2 = "";        /* and blank it out for next time. */
  1799.         } else {            /* Otherwise... */
  1800.         debug(F101,"sfile fnspath","",fnspath);
  1801.         if (fnspath) {        /* Stripping path names? */
  1802.         char *t;        /* Yes. */
  1803.         zstrip(filnam,&t);    /* Strip off the path. */
  1804.         debug(F110,"sfile zstrip",t,0);
  1805.         if (!t) t = "UNKNOWN";    /* Be cautious... */
  1806.         else if (*t == '\0')
  1807.           t = "UNKNOWN";
  1808.         strncpy(pktnam,t,PKTNL); /* Copy stripped name literally. */
  1809.         } else {            /* No stripping. */
  1810.         strcpy(pktnam,filnam);    /* Copy whole name. */
  1811.         }
  1812.         /* pktnam[] has the packet name, filnam[] has the original name. */
  1813.         /* But we still need to convert pktnam if FILE NAMES CONVERTED.  */
  1814.  
  1815.         debug(F101,"SATURDAY fncnv","",fncnv);
  1816.         if (fncnv) {        /* If converting names, */
  1817.         zltor(pktnam,(char *)srvcmd); /* convert it to common form, */
  1818.         strcpy(pktnam,(char *)srvcmd); /* with srvcmd as temp buffer */
  1819.         *srvcmd = NUL;
  1820.         }
  1821.         }
  1822.         debug(F110,"sfile",filnam,0);    /* Log debugging info */
  1823.         debug(F110," pktnam",pktnam,0);
  1824.         if (openi(filnam) == 0)     /* Try to open the input file */
  1825.       return(0);         
  1826. #ifdef CK_RESEND
  1827.     if (sendmode == SM_PSEND)    /* PSENDing? */
  1828.       if (sendstart > 0L)        /* Starting position */
  1829.         if (zfseek(sendstart) < 0)    /* seek to it... */
  1830.           return(0);
  1831. #endif /* CK_RESEND */
  1832.         s = pktnam;            /* Name for packet data field */
  1833. #ifdef OS2
  1834.     /* Never send a disk letter. */
  1835.     if (isalpha(*s) && (*(s+1) == ':'))
  1836.       s += 2;
  1837. #endif /* OS2 */
  1838.  
  1839.     } else {                /* X-packet setup, not F-packet. */
  1840.  
  1841.         debug(F110,"sxpack",cmdstr,0);    /* Log debugging info */
  1842.         s = cmdstr;            /* Name for data field */
  1843.     }
  1844.  
  1845.     /* Now s points to the string that goes in the packet data field. */
  1846.  
  1847.     encstr((CHAR *)s);            /* Encode the name. */
  1848.                     /* Send the F or X packet */
  1849.     /* If the encoded string did not fit into the packet, it was truncated. */
  1850.    
  1851. #ifdef COMMENT
  1852.     spack((char) (x ? 'X' : 'F'), pktnum, size, encbuf+7);
  1853. #else
  1854.     spack((char) (x ? 'X' : 'F'), pktnum, size, data);
  1855. #endif /* COMMENT */
  1856.  
  1857.     if (x == 0) {            /* Display for F packet */
  1858.         if (displa) {            /* Screen */
  1859.         screen(SCR_FN,'F',(long)pktnum,filnam);
  1860.         screen(SCR_AN,0,0l,pktnam);
  1861.         screen(SCR_FS,0,fsize,"");
  1862.         }
  1863. #ifdef pdp11
  1864.         tlog(F110,"Sending",filnam,0L);    /* Transaction log entry */
  1865. #else
  1866. #ifndef ZFNQFP
  1867.         tlog(F110,"Sending",filnam,0L);
  1868. #else
  1869.     {                /* Log fully qualified filename */
  1870.         char *p = NULL, *q = filnam;
  1871.         if ((p = malloc(CKMAXPATH+1)))
  1872.           if (zfnqfp(filnam, CKMAXPATH, p))
  1873.         q = p;
  1874.         tlog(F110,"Sending",q,0L);
  1875.         if (p) free(p);
  1876.     }
  1877. #endif /* ZFNQFP */
  1878. #endif /* pdp11 */
  1879.         tlog(F110," as",pktnam,0L);
  1880.     if (binary) {            /* Log file mode in transaction log */
  1881.         tlog(F101," mode: binary","",(long) binary);
  1882.     } else {            /* If text mode, check character set */
  1883.         tlog(F100," mode: text","",0L);
  1884. #ifndef NOCSETS
  1885.         tlog(F110," file character set",fcsinfo[fcharset].name,0L);
  1886.         if (tcharset == TC_TRANSP)
  1887.           tlog(F110," xfer character set","transparent",0L);
  1888.         else
  1889.           tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
  1890. #endif /* NOCSETS */
  1891.     }
  1892.     } else {                /* Display for X-packet */
  1893.  
  1894.         screen(SCR_XD,'X',(long)pktnum,cmdstr);    /* Screen */
  1895.         tlog(F110,"Sending from:",cmdstr,0L);    /* Transaction log */
  1896.     }
  1897.     intmsg(++filcnt);            /* Count file, give interrupt msg */
  1898.     first = 1;                /* Init file character lookahead. */
  1899.     ffc = 0L;                /* Init file character counter. */
  1900.     cps = oldcps = 0L;            /* Init cps statistics */
  1901.     rejection = -1;
  1902.     fsecs = gtimer();            /* Time this file started */
  1903.     debug(F101,"SFILE fsecs","",fsecs);
  1904.     return(1);
  1905. }
  1906.  
  1907. /*  S D A T A -- Send a data packet */
  1908.  
  1909. /*
  1910.   Returns -1 if no data to send (end of file), -2 if connection is broken.
  1911.   If there is data, a data packet is sent, and sdata() returns 1.
  1912.  
  1913.   For window size greater than 1, we keep sending data packets until window
  1914.   is full or characters start to appear from the other Kermit, whichever
  1915.   happens first.
  1916.  
  1917.   In the windowing case, when there is no more data left to send (or when
  1918.   sending has been interrupted), sdata() does nothing and returns 0 each time
  1919.   it is called until the current packet number catches up to the last data
  1920.   packet that was sent.
  1921. */
  1922.  
  1923. int
  1924. sdata() {
  1925.     int i, x, len;
  1926.     
  1927.     debug(F101,"sdata entry, first","",first);
  1928.     debug(F101," drain","",drain);
  1929.  
  1930. /* The "drain" flag is used with window size > 1.  It means we have sent  */
  1931. /* our last data packet.  If called and drain is not zero, then we return */
  1932. /* 0 as if we had sent an empty data packet, until all data packets have  */
  1933. /* been ACK'd, then then we can finally return -1 indicating EOF, so that */
  1934. /* the protocol can switch to seof state.  This is a kludge, but at least */
  1935. /* it's localized...  */
  1936.  
  1937.     if (first == 1) drain = 0;        /* Start of file, init drain flag. */
  1938.  
  1939.     if (drain) {            /* If draining... */
  1940.     debug(F101,"sdata draining, winlo","",winlo);
  1941.     if (winlo == pktnum)        /* If all data packets are ACK'd */
  1942.       return(-1);            /* return EOF indication */
  1943.     else                /* otherwise */
  1944.       return(0);            /* pretend we sent a data packet. */
  1945.     }
  1946.     debug(F101,"sdata sbufnum","",sbufnum);
  1947.     for (i = sbufnum; i > 0; i--) {
  1948.         debug(F101,"sdata countdown","",i);
  1949.     x = nxtpkt();            /* Get next pkt number and buffer */
  1950.     debug(F101,"sdata packet","",pktnum);
  1951.     if (x < 0) return(0);
  1952.     if (cxseen || czseen) {        /* If interrupted, done. */
  1953.         if (wslots > 1) {
  1954.         drain = 1;
  1955.         debug(F101,"sdata cx/zseen, drain","",cxseen);
  1956.         return(0);
  1957.         } else {
  1958.         return(-1);
  1959.         }
  1960.     }
  1961.     debug(F101,"sdata spsiz","",spsiz);
  1962.     len = getpkt(spsiz,1);
  1963.     if (len == 0) {            /* Done if no data. */
  1964.         if (pktnum == winlo) return(-1);
  1965.         drain = 1;            /* But can't return -1 until all */
  1966.         debug(F101,"sdata eof, drain","",drain);
  1967.         return(0);            /* ACKs are drained. */
  1968.     }
  1969.     spack('D',pktnum,len,data);    /* Send the data packet. */
  1970. /*
  1971.   We should also want to call chkint() here to catch keyboard interruptions.
  1972.   But its return codes don't tell us whether we should return from here or
  1973.   keep going.
  1974. */
  1975.     x = ttchk();            /* Peek at input buffer. */
  1976.     debug(F101,"sdata ttchk","",x);    /* ACKs waiting, maybe?  */
  1977.     if (x < 0)            /* Or connection broken? */
  1978.       return(-2);
  1979. /*
  1980.   Here we check to see if any ACKs or NAKs have arrived, in which case we
  1981.   break out of the D-packet-sending loop and return to the state switcher
  1982.   to process them.  This is what makes our windows slide instead of lurch.
  1983. */
  1984.     if (
  1985. #ifdef GEMDOS
  1986. /*
  1987.   In the Atari ST version, ttchk() can only return 0 or 1.  But note: x will
  1988.   probably always be > 0, since the as-yet-unread packet terminator from the
  1989.   last packet is probably still in the buffer, so sliding windows will
  1990.   probably never happen when the Atari ST is the file sender.  The alternative
  1991.   is to say "if (0)", in which case the ST will always send a window full of
  1992.   packets before reading any ACKs or NAKs.
  1993. */
  1994.         x > 0
  1995.   
  1996. #else /* !GEMDOS */
  1997. /*
  1998.   In most other versions, ttchk() returns the actual count.
  1999.   It can't be a Kermit packet if it's less than five bytes long.
  2000. */
  2001.         x > 4 + bctu
  2002.   
  2003. #endif /* GEMDOS */
  2004.         )
  2005.       return(1);            /* Yes, stop sending data packets */
  2006.     }                    /* and go try to read the ACKs. */
  2007.     return(1);
  2008. }
  2009.  
  2010.  
  2011. /*  S E O F -- Send an End-Of-File packet */
  2012.  
  2013. /*  Call with a string pointer to character to put in the data field, */
  2014. /*  or else a null pointer or "" for no data.  */
  2015.  
  2016. /*
  2017.   There are two "send-eof" functions.  seof() is used to send the normal eof
  2018.   packet at the end of a file's data (even if the file has no data), or when
  2019.   a file transfer is interrupted.  sxeof() is used to send an EOF packet that
  2020.   occurs because of attribute refusal.  The difference is purely a matter of
  2021.   buffer allocation and packet sequence number management.  Both functions
  2022.   act as "front ends" to the common send-eof function, szeof().
  2023. */
  2024.  
  2025. /* Code common to both seof() and sxeof() */
  2026.  
  2027. int
  2028. szeof(s) CHAR *s; {
  2029.     lsstate = 0;            /* Cancel locking-shift state */
  2030.     if ((s != NULL) && (*s != '\0')) {
  2031.     spack('Z',pktnum,1,s);
  2032.     xitsta |= W_SEND;
  2033.     tlog(F100," *** interrupted, sending discard request","",0L);
  2034.     filrej++;
  2035.     } else {
  2036.     spack('Z',pktnum,0,(CHAR *)"");
  2037.     }
  2038.     discard = 0;            /* Turn off per-file discard flag */
  2039.     return(0);
  2040. }
  2041.  
  2042. int
  2043. seof(s) CHAR *s; {
  2044.  
  2045. /*
  2046.   ckcpro.w, before calling seof(), sets window size back to 1 and then calls
  2047.   window(), which clears out the old buffers.  This is OK because the final
  2048.   data packet for the file has been ACK'd.  However, sdata() has already
  2049.   called nxtpkt(), which set the new value of pktnum which seof() will use.
  2050.   So all we need to do here is is allocate a new send-buffer.
  2051. */
  2052.     if (getsbuf(pktnum) < 0) {    /* Get a buffer for packet n */
  2053.     debug(F101,"seof can't get s-buffer","",pktnum);
  2054.     return(-1);
  2055.     }
  2056.     return(szeof(s));
  2057. }
  2058.  
  2059. /*
  2060.   Version of seof() to be called when sdata() has not been called before.  The
  2061.   difference is that this version calls nxtpkt() to allocate a send-buffer and
  2062.   get the next packet number.
  2063. */
  2064. int
  2065. sxeof(s) CHAR *s; {
  2066.     int x;
  2067.     x = nxtpkt();            /* Get next pkt number and buffer */
  2068.     if (x < 0)
  2069.       debug(F101,"sxeof nxtpkt fails","",pktnum);
  2070.     else
  2071.       debug(F101,"sxeof packet","",pktnum);
  2072.     return(szeof(s));
  2073. }
  2074.  
  2075. /*  S E O T -- Send an End-Of-Transaction packet */
  2076.  
  2077. int
  2078. seot() {
  2079.     if (nxtpkt() < 0) return(-1);    /* Bump packet number, get buffer */
  2080.     spack('B',pktnum,0,(CHAR *)"");    /* Send the EOT packet */
  2081.     cxseen = czseen = discard = 0;    /* Reset interruption flags */
  2082.     tstats();                /* Log timing info */
  2083.     return(0);
  2084. }
  2085.  
  2086.  
  2087. /*   R P A R -- Fill the data array with my send-init parameters  */
  2088.  
  2089. CHAR dada[32];                /* Use this instead of data[]. */
  2090.                     /* To avoid some kind of wierd */
  2091.                     /* addressing foulup in spack()... */
  2092.                     /* (which might be fixed now...) */
  2093.  
  2094. CHAR *
  2095. rpar() {
  2096.     char *p;
  2097.     int i, x;
  2098.     extern int xfermode;
  2099.     if (rpsiz > MAXPACK)        /* Biggest normal packet I want. */
  2100.       dada[0] = (char) tochar(MAXPACK);    /* If > 94, use 94, but specify */
  2101.     else                /* extended packet length below... */
  2102.       dada[0] = (char) tochar(rpsiz);    /* else use what the user said. */
  2103.     dada[1] = (char) tochar(chktimo(pkttim,0)); /* When to time me out */
  2104.     dada[2] = (char) tochar(mypadn);    /* How much padding I need (none) */
  2105.     dada[3] = (char) ctl(mypadc);    /* Padding character I want */
  2106.     dada[4] = (char) tochar(eol);    /* End-Of-Line character I want */
  2107.     dada[5] = myctlq;            /* Control-Quote character I send */
  2108.  
  2109.     switch (rqf) {            /* 8th-bit prefix (single-shift) */
  2110.       case -1:                /* I'm opening the bids */
  2111.       case  1:                /* Other Kermit already bid 'Y' */
  2112.     if (parity) ebq = sq = MYEBQ;    /* So I reply with '&' if parity */
  2113.     break;                /*  otherwise with 'Y'. */
  2114.       case  0:                /* Other Kermit bid nothing */
  2115.       case  2:                /* Other Kermit sent a valid prefix */
  2116.     break;                /* So I reply with 'Y'. */
  2117.     }
  2118.     debug(F000,"rpar 8bq sq","",sq);
  2119.     debug(F000,"rpar 8bq ebq","",ebq);
  2120.     if (lscapu == 2)            /* LOCKING-SHIFT FORCED */
  2121.       dada[6] = 'N';            /* requires no single-shift */
  2122.     else                /* otherwise send prefix or 'Y' */
  2123.       dada[6] = (char) sq;
  2124.     ebqsent = dada[6];            /* And remember what I really sent */
  2125.  
  2126.     dada[7] = (char) (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
  2127.     if (rptena) {
  2128.     if (rptflg)            /* Run length encoding */
  2129.       dada[8] = (char) rptq;    /* If receiving, agree */
  2130.     else                /* by replying with same character. */
  2131.       dada[8] = (char) (rptq = myrptq); /* When sending use this. */
  2132.     } else dada[8] = SP;        /* Not enabled, put a space here. */
  2133.  
  2134.     /* CAPAS mask */
  2135.  
  2136.     dada[9] = (char) tochar((lscapr ? lscapb : 0) | /* Locking shifts */
  2137.              (atcapr ? atcapb : 0) | /* Attribute packets */
  2138.              (lpcapr ? lpcapb : 0) | /* Long packets */
  2139.              (swcapr ? swcapb : 0) | /* Sliding windows */
  2140.              (rscapr ? rscapb : 0)); /* RESEND */
  2141.     dada[10] = (char) tochar(swcapr ? wslotr : 1); /* CAPAS+1 = Window size */
  2142.     if (urpsiz > 94)
  2143.       rpsiz = urpsiz - 1;        /* Long packets ... */
  2144.     dada[11] = (char) tochar(rpsiz / 95); /* Long packet size, big part */
  2145.     dada[12] = (char) tochar(rpsiz % 95); /* Long packet size, little part */
  2146.     dada[13] = '0';            /* CAPAS+4 = WONT CHKPNT */
  2147.     dada[14] = '_';            /* CAPAS+5 = CHKINT (reserved) */
  2148.     dada[15] = '_';            /* CAPAS+6 = CHKINT (reserved) */
  2149.     dada[16] = '_';            /* CAPAS+7 = CHKINT (reserved) */
  2150. #ifndef WHATAMI
  2151.     dada[17] = ' ';
  2152. #else
  2153.     dada[17] = (char) tochar( WM_FLAG |    /* CAPAS+8 = WHATAMI... */
  2154.       (server ? WM_SERVE : 0)    |    /* I am (not) a server */
  2155.     (binary ? WM_FMODE : 0)  |    /*  My file transfer mode is ... */
  2156.       (fncnv ? WM_FNAME : 0));     /*    My filename conversion is ... */
  2157. #endif /* WHATAMI */
  2158.     i = 18;                /* Position of next field */
  2159.     if (xfermode == XMODE_A) {        /* If TRANSFER MODE AUTOMATIC */
  2160.     p = cksysid;            /* WHOAMI (my system ID) */
  2161.     x = strlen(p);
  2162.     if (x > 0) {
  2163.         dada[i++] = (char) tochar(x);
  2164.         while (*p)
  2165.           dada[i++] = *p++;
  2166.     }
  2167.     } else {                /* TRANSFER MODE MANUAL */
  2168.     dada[i++] = (char) tochar(1);    /* Length */
  2169.     dada[i++] = '0';        /* "0" means anonymous - don't do it */
  2170.     }
  2171.     dada[i] = '\0';            /* Terminate the init string */
  2172.  
  2173. #ifdef DEBUG
  2174.     if (deblog) {
  2175.     debug(F110,"rpar",dada,0);
  2176.     rdebu(dada,(int)strlen((char *)dada));
  2177.     }
  2178. #endif /* DEBUG */
  2179.     strcpy((char *)myinit,(char *)dada);
  2180.     return(dada);            /* Return pointer to string. */
  2181. }
  2182.  
  2183. int
  2184. spar(s) CHAR *s; {            /* Set parameters */
  2185.     int x, y, lpsiz;
  2186.  
  2187.     debug(F110,"entering spar",s,0);
  2188.  
  2189.     s--;                /* Line up with field numbers. */
  2190.  
  2191. /* Limit on size of outbound packets */
  2192.     x = (rln >= 1) ? xunchar(s[1]) : 80;
  2193.     lpsiz = spsizr;            /* Remember what they SET. */
  2194.     if (spsizf) {            /* SET-command override? */
  2195.     if (x < spsizr) spsiz = x;    /* Ignore LEN unless smaller */
  2196.     } else {                /* otherwise */
  2197.     spsiz = (x < 10) ? 80 : x;    /* believe them if reasonable */
  2198.     }
  2199.     spmax = spsiz;            /* Remember maximum size */
  2200.  
  2201. /* Timeout on inbound packets */
  2202.     if (timef) {
  2203.     timint = rtimo;            /* SET SEND TIMEOUT value overrides */
  2204.     } else {                /* Otherwise use requested value, */
  2205.     x = (rln >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
  2206.     timint = (x < 0) ? rtimo : x;
  2207.     }
  2208.     timint = chktimo(timint,timef);    /* Adjust if necessary */
  2209.  
  2210. /* Outbound Padding */
  2211.     npad = 0; padch = '\0';
  2212.     if (rln >= 3) {
  2213.     npad = xunchar(s[3]);
  2214.     if (rln >= 4) padch = (CHAR) ctl(s[4]); else padch = 0;
  2215.     }
  2216.     if (npad) {
  2217.     int i;
  2218.     for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
  2219.     }
  2220.  
  2221. /* Outbound Packet Terminator */
  2222.     seol = (CHAR) (rln >= 5) ? xunchar(s[5]) : CR;
  2223.     if ((seol < 1) || (seol > 31)) seol = CR;
  2224.  
  2225. /* Control prefix that the other Kermit is sending */
  2226.     x = (rln >= 6) ? s[6] : '#';
  2227.     ctlq = (CHAR) (((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#');
  2228.  
  2229. /* 8th-bit prefix */
  2230. /*
  2231.   NOTE: Maybe this could be simplified using rcvtyp.
  2232.   If rcvtyp == 'Y' then we're reading the ACK,
  2233.   otherwise we're reading the other Kermit's initial bid.
  2234.   But his horrendous code works, so leave it alone for now.
  2235. */
  2236.     rq = (rln >= 7) ? s[7] : 0;
  2237.     if (rq == 'Y') rqf = 1;
  2238.       else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
  2239.         else rqf = 0;
  2240.     debug(F000,"spar 8bq rq","",rq);
  2241.     debug(F000,"spar 8bq sq","",sq);
  2242.     debug(F000,"spar 8bq ebq","",ebq);
  2243.     debug(F101,"spar 8bq rqf","",rqf);
  2244.     switch (rqf) {
  2245.       case 0:                /* Field is missing from packet. */
  2246.     ebqflg = 0;            /* So no 8th-bit prefixing. */
  2247.     break;
  2248.       case 1:                /* Other Kermit sent 'Y' = Will Do. */
  2249.     /*
  2250.           When I am the file receiver, ebqsent is 0 because I didn't send a
  2251.           negotiation yet.  If my parity is set to anything other than NONE,
  2252.           either because my user SET PARITY or because I detected parity bits
  2253.           on this packet, I reply with '&', otherwise 'Y'.
  2254.  
  2255.       When I am the file sender, ebqsent is what I just sent in rpar(),
  2256.           which can be 'Y', 'N', or '&'.  If I sent '&', then this 'Y' means
  2257.           the other Kermit agrees to do 8th-bit prefixing.
  2258.  
  2259.           If I sent 'Y' or 'N', but then detected parity on the ACK packet
  2260.           that came back, then it's too late: there is no longer any way for
  2261.           me to tell the other Kermit that I want to do 8th-bit prefixing, so
  2262.           I must not do it, and in that case, if there is any 8-bit data in 
  2263.           the file to be transferred, the transfer will fail because of block
  2264.           check errors.
  2265.  
  2266.           The following clause covers all of these situations:
  2267.     */
  2268.     if (parity && (ebqsent == 0 || ebqsent == '&')) {
  2269.         ebqflg = 1;
  2270.         ebq = MYEBQ;
  2271.     }
  2272.     break;
  2273.       case 2:                /* Other Kermit send a valid prefix */
  2274.     if (ebqflg = (ebq == sq || sq == 'Y'))
  2275.       ebq = rq;
  2276.     }
  2277.     if (lscapu == 2) {     /* But no single-shifts if LOCKING-SHIFT FORCED */
  2278.     ebqflg = 0;
  2279.     ebq = 'N';
  2280.     }
  2281.  
  2282. /* Block check */
  2283.     x = 1;
  2284.     if (rln >= 8) {
  2285.     if (s[8] == 'B') x = 4;
  2286.     else x = s[8] - '0';
  2287.     if ((x < 1) || (x > 4)) x = 1;
  2288.     }
  2289.     bctr = x;
  2290.  
  2291. /* Repeat prefix */
  2292.  
  2293.     rptflg = 0;                /* Assume no repeat-counts */
  2294.     if (rln >= 9) {            /* Is there a repeat-count field? */
  2295.     char t;                /* Yes. */
  2296.     t = s[9];            /* Get its contents. */
  2297. /*
  2298.   If I'm sending files, then I'm reading these parameters from an ACK, and so
  2299.   this character must agree with what I sent.
  2300. */
  2301.     if (rptena) {            /* If enabled ... */
  2302.         if ((char) rcvtyp == 'Y') {    /* Sending files, reading ACK. */
  2303.         if (t == myrptq) rptflg = 1;
  2304.         } else {            /* I'm receiving files */
  2305.         if ((t > 32 && t < 63) || (t > 95 && t < 127)) {
  2306.             rptflg = 1;
  2307.             rptq = t;
  2308.         }
  2309.         }
  2310.     } else rptflg = 0;
  2311.     }
  2312.  
  2313. /* Capabilities */
  2314.  
  2315.     atcapu = lpcapu = swcapu = rscapu = 0; /* Assume none of these. */
  2316.     if (lscapu != 2) lscapu = 0;    /* Assume no LS unless forced. */
  2317.     y = 11;                /* Position of next field, if any */
  2318.     if (rln >= 10) {
  2319.         x = xunchar(s[10]);
  2320.     debug(F101,"spar capas","",x);
  2321.         atcapu = (x & atcapb) && atcapr; /* Attributes */
  2322.     lpcapu = (x & lpcapb) && lpcapr; /* Long packets */
  2323.     swcapu = (x & swcapb) && swcapr; /* Sliding windows */
  2324.     rscapu = (x & rscapb) && rscapr; /* RESEND */
  2325.     debug(F101,"spar lscapu","",lscapu);
  2326.     debug(F101,"spar lscapr","",lscapr);
  2327.     debug(F101,"spar ebqflg","",ebqflg);
  2328.     if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
  2329.     debug(F101,"spar swcapr","",swcapr);
  2330.     debug(F101,"spar swcapu","",swcapu);
  2331.     debug(F101,"spar lscapu","",lscapu);
  2332.     for (y = 10; (xunchar(s[y]) & 1) && (rln >= y); y++);
  2333.     debug(F101,"spar y","",y);
  2334.     }
  2335.  
  2336. /* Long Packets */
  2337.     debug(F101,"spar lpcapu","",lpcapu);
  2338.     if (lpcapu) {
  2339.         if (rln > y+1) {
  2340.         x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
  2341.         debug(F101,"spar lp len","",x);
  2342.         if (spsizf) {        /* If overriding negotiations */
  2343.         spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
  2344.         } else {                     /* otherwise */
  2345.         spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
  2346.         }
  2347.         if (spsiz < 10) spsiz = 80;    /* Be defensive... */
  2348.     }
  2349.     }
  2350.     /* (PWP) save current send packet size for optimal packet size calcs */
  2351.     spmax = spsiz;            /* Maximum negotiated length */
  2352.     if (slostart && spsiz > 499) spsiz = 244; /* Slow start length */
  2353.     debug(F101,"spar slow-start spsiz","",spsiz);
  2354.     debug(F101,"spar lp spmax","",spmax);
  2355.     timint = chktimo(timint,timef);    /* Recalculate the packet timeout */
  2356.     
  2357. /* Sliding Windows... */
  2358.  
  2359.     if (swcapr) {            /* Only if requested... */
  2360.         if (rln > y) {            /* See what other Kermit says */
  2361.         x = xunchar(s[y+1]);
  2362.         debug(F101,"spar window","",x);
  2363.         wslotn = (x > MAXWS) ? MAXWS : x;
  2364. /*
  2365.   wslotn = negotiated size (from other Kermit's S or I packet).
  2366.   wslotr = requested window size (from this Kermit's SET WINDOW command).
  2367. */
  2368.         if (wslotn > wslotr)    /* Use the smaller of the two */
  2369.           wslotn = wslotr;
  2370.         if (wslotn < 1)        /* Watch out for bad negotiation */
  2371.           wslotn = 1;
  2372.         if (wslotn > 1) {
  2373.         swcapu = 1;        /* We do windows... */
  2374.         if (wslotn > maxtry)    /* Retry limit must be greater */
  2375.           maxtry = wslotn + 1;    /* than window size. */
  2376.         }
  2377.         debug(F101,"spar window after adjustment","",x);
  2378.     } else {            /* No window size specified. */
  2379.         wslotn = 1;            /* We don't do windows... */
  2380.         debug(F101,"spar window","",x);
  2381.         swcapu = 0;
  2382.         debug(F101,"spar no windows","",wslotn);
  2383.     }
  2384.     }
  2385.  
  2386. /* Now recalculate packet length based on number of windows.   */
  2387. /* The nogotiated number of window slots will be allocated,    */
  2388. /* and the maximum packet length will be reduced if necessary, */
  2389. /* so that a windowful of packets can fit in the big buffer.   */
  2390.  
  2391.     if (wslotn > 1) {            /* Shrink to fit... */
  2392.     x = adjpkl(spmax,wslotn,bigsbsiz);
  2393.     if (x < spmax) {
  2394.         spmax = x;
  2395.         if (slostart && spsiz > 499) spsiz = 244; /* Slow start again */
  2396.         debug(F101,"spar sending, redefine spmax","",spmax);
  2397.     }
  2398.     }
  2399. #ifdef WHATAMI
  2400.     if (rln > y+7)            /* Get WHATAMI info if any */
  2401.       whatru = xunchar(s[y+8]);
  2402. #endif /* WHATAMI */
  2403.  
  2404.     if (rln > y+8) {            /* Get WHOAREYOU info if any */
  2405.     int x;
  2406.     x = xunchar(s[y+9]);        /* Length of it */
  2407.     if (x > 0 && x < 16 && rln >= y + 9 + x) {
  2408.         strncpy(whoareu,(char *)s+y+10,x); /* Other Kermit's system ID */
  2409.         if (whoareu[0]) {        /* Got one? */
  2410.         char *p;
  2411. #ifdef COMMENT
  2412.         char buf[64];
  2413. #endif /* COMMENT */
  2414.         extern int sysindex;
  2415.         extern struct sysdata sysidlist[];
  2416.  
  2417.         sysindex = getsysix((char *)whoareu);
  2418.         if (sysindex > -1) {
  2419.             p = sysidlist[sysindex].sid_name;
  2420. #ifdef COMMENT
  2421.             sprintf(buf,"Remote system type is %s", p);
  2422.             screen(SCR_ST,ST_MSG,0L,buf);
  2423. #endif /* COMMENT */
  2424.             tlog(F110,"Remote system type: ",p,0L);
  2425.             if (sysindex > 0)    /* Skip this for "anonymous" */
  2426.               whoarewe();
  2427.         }
  2428.         }
  2429.     }
  2430.     }
  2431. /* Record parameters in debug log */
  2432. #ifdef DEBUG
  2433.     if (deblog) sdebu(rln);
  2434. #endif /* DEBUG */
  2435.     numerrs = 0;            /* Start counting errors here. */
  2436.     return(0);
  2437. }
  2438.  
  2439. /*  G N F I L E  --  Get name of next file to send  */
  2440. /*
  2441.   Expects global sndsrc to be:
  2442.    -1: next filename to be obtained by calling znext().
  2443.     0: no next file name
  2444.     1: (or greater) next filename to be obtained from **cmlist,
  2445.        or if addlist != 0, from the "filehead" linked list.
  2446.   Returns:
  2447.     1, with name of next file in filnam.
  2448.     0, no more files, with filnam set to empty string.
  2449.    -1, file not found
  2450.    -2, file is not readable
  2451.    -3, read access denied
  2452.    -4, cancelled
  2453.    -5, too many files match wildcard
  2454. */
  2455.  
  2456. int
  2457. gnfile() {
  2458.     int i, x; long y;
  2459.     int retcode = 0;
  2460.     char fullname[CKMAXPATH+1];
  2461.  
  2462.     debug(F101,"gnfile sndsrc","",sndsrc);
  2463.     fsize = -1L;            /* Initialize file size */
  2464.     if (sndsrc == 0) {            /* It's not really a file */
  2465.     if (nfils > 0) {        /* It's a pipe, or stdin */
  2466.         strcpy(filnam, *cmlist);    /* Copy its "name" */
  2467.         nfils = 0;            /* There is no next file */
  2468.         return(1);            /* OK this time */
  2469.     } else return(0);        /* but not next time */
  2470.     }
  2471.  
  2472. /* If file group interruption (C-Z) occurred, fail.  */
  2473.  
  2474.     if (czseen) {
  2475.     tlog(F100,"Transaction cancelled","",0L);
  2476.         debug(F100,"gnfile czseen","",0);
  2477.     return(-4);
  2478.     }
  2479.  
  2480. /* Loop through file list till we find a readable, sendable file */
  2481.  
  2482.     y = -1L;                /* Loop exit (file size) variable */
  2483.     while (y < 0L) {            /* Keep trying till we get one... */
  2484.     if (sndsrc > 0) {        /* File list in cmlist */
  2485.         debug(F101,"gnfile nfils","",nfils);
  2486.         if (nfils-- > 0) {        /* Still some left? */
  2487. #ifndef NOMSEND
  2488.         if (addlist) {
  2489.             if (filenext && filenext->fl_name) {
  2490.             strncpy(filnam,filenext->fl_name,CKMAXPATH);
  2491.             cmarg2 =
  2492.               filenext->fl_alias ?
  2493.                 filenext->fl_alias :
  2494.                   "";
  2495.             binary = filenext->fl_mode; /* plug and pray... */
  2496.             } else {
  2497.             printf("?Internal error expanding ADD list\n");
  2498.             return(-5);
  2499.             }
  2500.             filenext = filenext->fl_next;
  2501.             debug(F111,"gnfile addlist filnam",filnam,nfils);
  2502.         } else {
  2503. #endif /* NOMSEND */
  2504.             strncpy(filnam,*cmlist++,CKMAXPATH);
  2505.             debug(F111,"gnfile cmlist filnam",filnam,nfils);
  2506. #ifndef NOMSEND
  2507.         }
  2508. #endif /* NOMSEND */
  2509.         i = 0;
  2510. #ifndef NOSERVER
  2511.         debug(F101,"gnfile ngetpath","",ngetpath);
  2512. #endif /* NOSERVER */
  2513. nextinpath:
  2514. #ifndef NOSERVER
  2515.         if (server && !isabsolute(filnam) && (ngetpath > i)) {
  2516.             strncpy(fullname,getpath[i],CKMAXPATH);
  2517.             strncat(fullname,filnam,CKMAXPATH);
  2518.             debug(F111,"gnfile getpath",fullname,i);
  2519.             i++;
  2520.         } else {
  2521.             i = ngetpath + 1;
  2522. #else
  2523.             i = 1;        /* ? */
  2524. #endif /* NOSERVER */
  2525.             strncpy(fullname,filnam,CKMAXPATH);
  2526.             debug(F110,"gnfile absolute",fullname,0);
  2527. #ifndef NOSERVER
  2528.         }
  2529. #endif /* NOSERVER */
  2530.         if (iswild(fullname)) {    /* It looks wild... */
  2531.             /* First check if a file with this name exists */
  2532.             debug(F110,"gnfile wild",fullname,0);
  2533.             if (zchki(fullname) > -1) {
  2534.             /*
  2535.                Here we have a file whose name actually
  2536.                contains wildcard characters.
  2537.             */
  2538.             goto gotnam;
  2539.             }
  2540.             x = zxpand(fullname); /* Now try to expand wildcards */
  2541.             debug(F101,"gnfile zxpand","",x);
  2542.             if (x == 1) {
  2543.             znext(fullname);
  2544.             debug(F110,"gnfile znext",fullname,0);
  2545.             goto gotnam;
  2546.             }
  2547.             if (x == 0) {    /* None match */
  2548. #ifndef NOSERVER
  2549.             if (server && ngetpath > i)
  2550.               goto nextinpath;
  2551. #endif /* NOSERVER */
  2552.             retcode = -1;
  2553.             continue;
  2554.             }
  2555.             if (x < 0)        /* Too many to expand */
  2556.               return(-5);
  2557.             sndsrc = -1;    /* Change send-source to znext() */
  2558.         }
  2559.         } else {            /* We're out of files. */
  2560.         debug(F101,"gnfile done","",nfils);
  2561.         *filnam = '\0';
  2562.         return(retcode);
  2563.         }
  2564.     }
  2565.  
  2566. /* Otherwise, step to next element of internal wildcard expansion list. */
  2567.  
  2568.     if (sndsrc < 0) {
  2569.         x = znext(filnam);
  2570.         debug(F111,"gnfile znext",filnam,x);
  2571.         if (x == 0) {        /* If no more, */
  2572.         sndsrc = 1;        /* go back to list */
  2573.         continue;
  2574.         } else strncpy(fullname,filnam,CKMAXPATH);
  2575.     }
  2576.  
  2577. /* Get here with a filename. */
  2578.  
  2579. gotnam:
  2580.     if (sndsrc) {
  2581.         y = zchki(fullname);    /* Check if file readable */
  2582.         retcode = (int) y;        /* Possible return code */
  2583.         if (y == -1L) {        /* If not found */
  2584. #ifndef NOSERVER
  2585.         if (server && ngetpath > i)
  2586.           goto nextinpath;
  2587. #endif /* NOSERVER */
  2588.         debug(F110,"gnfile skipping:",fullname,0);
  2589.         tlog(F111,fullname,"not sent, reason",(long)y);
  2590.         screen(SCR_ST,ST_SKIP,0l,fullname);
  2591.         continue;
  2592.         } else if (y < 0) {
  2593.         if (y == -3) {        /* Exists but not readable */
  2594.             filrej++;        /* Count this one as not sent */
  2595.             tlog(F110,"Read access denied",fullname,0); /* Log this */
  2596.             screen(SCR_ST,ST_SKIP,0l,fullname);    /* Display message */
  2597.         }
  2598.         continue;
  2599.         } else {
  2600.         fsize = y;
  2601.         strncpy(filnam,fullname,CKMAXPATH);
  2602.         return(1);
  2603.         }
  2604.     } else {            /* sndsrc is 0... */
  2605.         strncpy(filnam,fullname,CKMAXPATH);
  2606.         return(1);
  2607.     }
  2608.     }
  2609.     *filnam = '\0';            /* Should never get here */
  2610.     return(0);
  2611. }
  2612.  
  2613. /*  S N D H L P  --  Routine to send builtin help  */
  2614.  
  2615. int
  2616. sndhlp(p) char *p; {
  2617. #ifndef NOSERVER
  2618.     nfils = 0;                /* No files, no lists. */
  2619.     xflg = 1;                /* Flag we must send X packet. */
  2620.     strcpy(cmdstr,versio);        /* Data for X packet. */
  2621.     first = 1;                /* Init getchx lookahead */
  2622.     memstr = 1;                /* Just set the flag. */
  2623.     memptr = p;                /* And the pointer. */
  2624.     binary = XYFT_T;            /* Text mode for this. */
  2625.     return(sinit());
  2626. #else
  2627.     return(0);
  2628. #endif /* NOSERVER */
  2629. }
  2630.  
  2631. /*
  2632.   The following bunch of routines feed internally generated data to the server
  2633.   to send to the client in response to REMOTE commands like DIRECTORY, DELETE,
  2634.   and so on.  Note that in writing this data to buffers, we do not use "\n".
  2635.   Instead we use "\15\12", i.e. LITERAL carriage return and linefeed, because
  2636.   that it was is required by the Kermit protocol in text mode.
  2637. */
  2638. static
  2639. char funcbuf[512];
  2640. static int
  2641.   funcnxt = 0,
  2642.   funclen = 0,
  2643.   nxpnd = - 1;
  2644. static long
  2645.   ndirs =   0,
  2646.   nfiles =  0,
  2647.   nbytes =  0;
  2648.  
  2649. /*  N X T T Y P -- provide data to type file to remote client */
  2650. /*
  2651.    Returns the next available character, 
  2652.   -1 if no more data.
  2653. */
  2654. int 
  2655. nxttype() {
  2656.     int c;
  2657.  
  2658.     if (zchin(ZIFILE,&c) < 0) {
  2659.         zclose(ZIFILE);
  2660.         return(-1);
  2661.     } else
  2662.       return((unsigned)c);
  2663. }
  2664.  
  2665. /*  S N D T Y P -- TYPE a file to remote client */
  2666.  
  2667. int
  2668. #ifdef CK_ANSI
  2669. sndtype(char * file) 
  2670. #else
  2671. sndtype(file) char * file; 
  2672. #endif /* CK_ANSI */
  2673. /* sndtype */ {
  2674.  
  2675. #ifndef NOSERVER
  2676.     char * p = NULL, name[CKMAXPATH+1];
  2677.  
  2678. #ifdef OS2
  2679.     if (*file) {
  2680.         strcpy(name, file);
  2681.         /* change / to \. */
  2682.         p = name;
  2683.         while (*p) {            /* Change them back to \ */
  2684.             if (*p == '/') *p = '\\';
  2685.             p++;
  2686.         }
  2687.     } else
  2688.       return(0);
  2689. #else
  2690.     strcpy(name, file);
  2691. #endif /* OS2 */
  2692.  
  2693.     funcnxt = 0;
  2694.     funclen = strlen(funcbuf);
  2695.     if (zchki(name) == -2) {
  2696.         /* Found a directory */
  2697.         return(0);
  2698.     }
  2699.     if (!zopeni(ZIFILE,name))
  2700.       return(0);
  2701.  
  2702.     nfils = 0;                /* No files, no lists. */
  2703.     xflg = 1;                /* Flag we must send X packet. */
  2704.     strcpy(cmdstr,"type");        /* Data for X packet. */
  2705.     first = 1;                /* Init getchx lookahead */
  2706.     funcstr = 1;            /* Just set the flag. */
  2707.     funcptr = nxttype;            /* And the pointer. */
  2708.     binary = XYFT_T;            /* Text mode for this */
  2709.     return(sinit());
  2710. #else
  2711.     return(0);
  2712. #endif /* NOSERVER */
  2713. }
  2714.  
  2715. /*
  2716.    N X T D I R  --  Provide data for senddir()
  2717.  
  2718.    Returns the next available character or -1 if no more data.
  2719. */
  2720. static int
  2721. nxtdir() {
  2722.     char name[257], *p = NULL;
  2723.     char * dstr = NULL;
  2724.     long len = 0;
  2725.     short month = 0, date = 0, year = 0, hour = 0, minute = 0, seconds = 0;
  2726.  
  2727.     debug(F111,"nxtdir","funcnxt",funcnxt);
  2728.     debug(F110,"nxtdir funcbuf",funcbuf+funcnxt,0);
  2729.     if (funcnxt < funclen)
  2730.       return (funcbuf[funcnxt++]);
  2731.  
  2732.     if (nxpnd > 0) {
  2733.         nxpnd--; 
  2734.         if (!znext(name)) {
  2735.             nxpnd = 0;
  2736.             return(nxtdir());
  2737.         }
  2738.         dstr = zfcdat(name);
  2739.     if (!dstr) dstr = "";
  2740.         if (*dstr) {
  2741.         month = (dstr[4]-48)*10 + (dstr[5]-48);
  2742. #ifdef COMMENT
  2743.         switch(month) {        /* For anglophones only... */
  2744.           case 1:  mstr = "Jan"; break;
  2745.           case 2:  mstr = "Feb"; break;
  2746.           case 3:  mstr = "Mar"; break;
  2747.           case 4:  mstr = "Apr"; break;
  2748.           case 5:  mstr = "May"; break;
  2749.           case 6:  mstr = "Jun"; break;
  2750.           case 7:  mstr = "Jul"; break;
  2751.           case 8:  mstr = "Aug"; break;
  2752.           case 9:  mstr = "Sep"; break;
  2753.           case 10: mstr = "Oct"; break;
  2754.           case 11: mstr = "Nov"; break;
  2755.           case 12: mstr = "Dec"; break;
  2756.           default: mstr = "   ";
  2757.         }
  2758. #endif /* COMMENT */
  2759.         date = (dstr[6]-48)*10 + (dstr[7]-48);
  2760.         year = (((dstr[0]-48)*10 + (dstr[1]-48))*10
  2761.             + (dstr[2]-48))*10 + (dstr[3]-48);
  2762.         hour = (dstr[9]-48)*10 + (dstr[10]-48);
  2763.         minute = (dstr[12]-48)*10 + (dstr[13]-48);
  2764.         seconds = (dstr[15]-48)*10 + (dstr[16]-48);
  2765.         } else {
  2766.             month = 0;
  2767.         date = 0;
  2768.         year = 0;
  2769.         hour = 0;
  2770.         minute = 0;
  2771.         seconds = 0;
  2772.         }
  2773.         len = zchki(name);
  2774.         /* Find just the name of the file */
  2775. #ifdef VMS
  2776.     p = name + ckindex("]",name,0,0,1);
  2777. #else
  2778.         for (p = name + (int) strlen(name); 
  2779.          p != name && *p != '/' 
  2780. #ifdef OS2
  2781.          && *p != '\\' && *p != ':' 
  2782. #endif /* OS2 */              
  2783.               ; p--
  2784.          );
  2785.         if (*p == '/' 
  2786. #ifdef OS2
  2787.              || *p == '\\' || *p == ':'
  2788. #endif /* OS2 */
  2789.             )
  2790.           p++;
  2791. #endif /* VMS */
  2792.         if (len > -1L) {
  2793.             nfiles++;
  2794.             nbytes += len;
  2795.             sprintf(funcbuf," %04d-%02d-%02d %02d:%02d %11ld %s\15\12",
  2796.                     year, month, date, hour, minute, len, p);
  2797.         } else {
  2798.             ndirs++;
  2799.             sprintf(funcbuf,
  2800.             " %04d-%02d-%02d %02d:%02d %11s %s\15\12", 
  2801.                     year, month, date, hour, minute, "(directory)", p);
  2802.         }
  2803.         funcnxt = 0;
  2804.         funclen = strlen(funcbuf);
  2805.     } else if (nxpnd == 0) {        /* Done, send summary */
  2806.     char *blankline = "";        /* At beginning of summary */
  2807.     char *endline = "\15\12";    /* At end of summary */
  2808. /*
  2809.   The idea is to prevent (a) unnecessary multiple blanklines, and (b)
  2810.   prompt-stomping.  Preventing (b) is practically impossible, because it
  2811.   depends on the client so for now always include that final CRLF.
  2812. */
  2813.     if (!ndirs || !nbytes || !nfiles)
  2814.       blankline = "\15\12";
  2815.         sprintf(funcbuf,
  2816.         "%sSummary: %ld director%s, %ld file%s, %ld byte%s%s",
  2817.         blankline,
  2818.         ndirs,
  2819.         (ndirs == 1) ? "y" : "ies",
  2820.         nfiles,
  2821.         (nfiles == 1) ? "" : "s",
  2822.         nbytes,
  2823.         (nbytes == 1) ? "" : "s",
  2824.         endline
  2825.         );
  2826.         nxpnd--;
  2827.         funcnxt = 0;
  2828.         funclen = strlen(funcbuf);
  2829.     } else {
  2830.         funcbuf[0] = '\0';
  2831.         funcnxt = 0;
  2832.         funclen = 0;
  2833.     }
  2834.     /* If we have data to send... */
  2835.  
  2836.     if (funcnxt < funclen)
  2837.       return(funcbuf[funcnxt++]);    /* Return a character */
  2838.     else
  2839.       return(-1);            /* Nothing left, done. */
  2840. }
  2841.  
  2842. /*  S N D D I R -- send directory listing  */
  2843.  
  2844. int
  2845. #ifdef CK_ANSI
  2846. snddir(char * spec) 
  2847. #else
  2848. snddir(spec) char * spec; 
  2849. #endif /* CK_ANSI */
  2850. /* snddir */ {
  2851. #ifndef NOSERVER
  2852.     char * p = NULL, name[257];  
  2853.     int rc = 0;
  2854.  
  2855.     if (!spec) spec = "";
  2856.     debug(F110,"snddir",spec,0);
  2857.     if (*spec) {
  2858.         strcpy(name, spec);
  2859. #ifdef OS2
  2860.         /* change / to \. */
  2861.         p = name;
  2862.         while (*p) {            /* Change them back to \ */
  2863.             if (*p == '/') *p = '\\';
  2864.             p++;
  2865.         }
  2866. #endif /* OS2 */
  2867.     } else {
  2868. #ifdef OS2
  2869.     strcpy(name, ".");
  2870. #else
  2871. #ifdef UNIX
  2872.     strcpy(name, "./*");
  2873. #else
  2874. #ifdef VMS
  2875.     strcpy(name, "*.*");
  2876. #else
  2877. #ifdef datageneral
  2878.     strcpy(name, "+");
  2879. #else
  2880.     return(0);
  2881. #endif /* datageneral */
  2882. #endif /* VMS */
  2883. #endif /* UNIX */
  2884. #endif /* OS2 */
  2885.     p = name + strlen(name);     /* Move it to end of list */
  2886.     }
  2887.     ndirs = 0L;
  2888.     nfiles = 0L;
  2889.     nbytes = 0L;
  2890.     sprintf(funcbuf,"Listing files: \"%s\"\15\12\15\12",name);
  2891.     funcnxt = 0;
  2892.     funclen = strlen(funcbuf);
  2893.  
  2894. #ifdef OS2
  2895.     debug(F110,"snddir about to zchki",name,0);
  2896.     if (zchki(name) == -2) {        /* Found a directory */
  2897.         p--;
  2898.         if (*p == '\\' || *p == '/')
  2899.           strcat(name, "*");
  2900.         else if (*p == ':')
  2901.           strcat(name, ".");
  2902.         else
  2903.           strcat(name, "\\*");
  2904.     }
  2905. #endif /* OS2 */
  2906.  
  2907.     nxpnd = zxpand(name);
  2908.     debug(F111,"snddir zxpand","nxpnd",nxpnd);
  2909.  
  2910.     nfils = 0;                /* No files, no lists. */
  2911.     xflg = 1;                /* Flag we must send X packet. */
  2912.     strcpy(cmdstr,"REMOTE DIRECTORY");    /* Data for X packet. */
  2913.     first = 1;                /* Init getchx lookahead */
  2914.     funcstr = 1;            /* Just set the flag. */
  2915.     funcptr = nxtdir;            /* And the pointer. */
  2916.     binary = XYFT_T;            /* Text mode for this, */
  2917.     rc = sinit();
  2918.     debug(F111,"snddir","sinit()",rc);
  2919.     return(rc);
  2920. #else
  2921.     return(0);
  2922. #endif /* NOSERVER */
  2923. }
  2924.  
  2925. /*  N X T D E L -- provide data for delete   */
  2926.  
  2927. /*  Returns the next available character or -1 if no more data  */
  2928.  
  2929. static int
  2930. nxtdel() {
  2931.     char name[257], *p = NULL;
  2932.     char * dstr = NULL;
  2933.     int len = 0;
  2934.     short month = 0, date = 0, year = 0, hour = 0, minute = 0, seconds = 0;
  2935.  
  2936.     if (funcnxt < funclen)
  2937.       return (funcbuf[funcnxt++]);
  2938.  
  2939.     if (nxpnd > 0) {
  2940.         nxpnd--; 
  2941.         if (!znext(name)) {
  2942.             nxpnd = 0;
  2943.             return(nxtdel());
  2944.         }
  2945.  
  2946.         len = zchki(name);
  2947.  
  2948.         /* Find just the name of the file */
  2949.  
  2950.         for (p = name + strlen(name); p != name && *p != '/' ; p--) ;
  2951.         if (*p == '/') p++;
  2952.  
  2953.         if (len > -1L) {
  2954.             nfiles++;
  2955.             nbytes += len;
  2956.             sprintf(funcbuf,
  2957.             " %10s: %s\15\12",
  2958.                     zdelet(name) ? "skipping" : "deleted",
  2959.             p
  2960.             );
  2961.         } else
  2962.       sprintf(funcbuf," directory: %s\15\12", p);
  2963.         funcnxt = 0;
  2964.         funclen = strlen(funcbuf);
  2965.     } else 
  2966.     
  2967.     /* If done processing the expanded entries send a summary statement */
  2968.  
  2969.       if (nxpnd == 0) {
  2970.       sprintf(funcbuf,
  2971.           "\15\12%ld file%s deleted, %ld byte%s freed\15\12",
  2972.           nfiles,
  2973.           (nfiles == 1) ? "" : "s",
  2974.           nbytes,
  2975.           (nbytes == 1) ? "" : "s"
  2976.           );
  2977.       nxpnd--;
  2978.       funcnxt = 0;
  2979.       funclen = strlen(funcbuf);
  2980.       } else {
  2981.       funcbuf[0] = '\0';
  2982.       funcnxt = 0;
  2983.       funclen = 0;
  2984.       }
  2985.  
  2986.     /* If we have data to send */
  2987.  
  2988.     if (funcnxt < funclen)
  2989.       return (funcbuf[funcnxt++]);    /* Return a character */
  2990.     else
  2991.       return(-1);            /* No more input */
  2992. }
  2993.  
  2994. /*  S N D D E L  --  Send delete message  */
  2995.  
  2996. int
  2997. #ifdef CK_ANSI
  2998. snddel(char * spec) 
  2999. #else
  3000. snddel(spec) char * spec; 
  3001. #endif /* CK_ANSI */
  3002. /* snddel */ {
  3003. #ifndef NOSERVER
  3004.     char * p=NULL, name[257]; 
  3005.  
  3006.     if (!*spec)
  3007.       return(0);
  3008.  
  3009.     strcpy(name, spec);
  3010.  
  3011. #ifdef OS2
  3012.     /* change / to \. */
  3013.     p = name;
  3014.     while (*p) {            /* Change them back to \ */
  3015.         if (*p == '/') *p = '\\';
  3016.         p++;
  3017.     }
  3018. #endif /* OS2 */
  3019.  
  3020.     nfiles = nbytes = 0L;
  3021.     sprintf(funcbuf,"Deleting \"%s\"\15\12",name);
  3022.     funcnxt = 0;
  3023.     funclen = strlen(funcbuf);
  3024.  
  3025.     nxpnd = zxpand(name);
  3026.     nfils = 0;                /* No files, no lists. */
  3027.     xflg = 1;                /* Flag we must send X packet. */
  3028.     strcpy(cmdstr,"REMOTE DELETE");    /* Data for X packet. */
  3029.     first = 1;                /* Init getchx lookahead */
  3030.     funcstr = 1;            /* Just set the flag. */
  3031.     funcptr = nxtdel;            /* And the pointer. */
  3032.     binary = XYFT_T;            /* Use text mode for this, */
  3033.     return(sinit());
  3034. #else
  3035.     return(0);
  3036. #endif /* NOSERVER */
  3037. }
  3038.  
  3039. #ifdef OS2
  3040. /*  S N D S P A C E -- send disk space message  */
  3041. int
  3042. sndspace(int drive) {
  3043. #ifndef NOSERVER
  3044.     static char spctext[64];
  3045.     if (drive)
  3046.       sprintf(spctext,
  3047.           " Drive %c: %ldK free\15\12", drive, 
  3048.           zdskspace(drive - 'A' + 1) / 1024L);
  3049.     else
  3050.       sprintf(spctext, " Free space: %ldK\15\12", zdskspace(0) / 1024L);
  3051.     nfils = 0;                /* No files, no lists. */
  3052.     xflg = 1;                /* Flag we must send X packet. */
  3053.     strcpy(cmdstr,"free space");    /* Data for X packet. */
  3054.     first = 1;                /* Init getchx lookahead */
  3055.     memstr = 1;                /* Just set the flag. */
  3056.     memptr = spctext;            /* And the pointer. */
  3057.     binary = XYFT_T;            /* Text mode for this. */
  3058.     return(sinit());
  3059. #else
  3060.     return(0);
  3061. #endif /* NOSERVER */
  3062. }
  3063.  
  3064. /*  S N D W H O -- send who message  */
  3065. int
  3066. sndwho(char * who) {
  3067. #ifndef NOSERVER
  3068.     nfils = 0;                /* No files, no lists. */
  3069.     xflg = 1;                /* Flag we must send X packet. */
  3070.     strcpy(cmdstr,"who");        /* Data for X packet. */
  3071.     first = 1;                /* Init getchx lookahead */
  3072.     memstr = 1;                /* Just set the flag. */
  3073. #ifdef NT
  3074.     memptr = "\15\12K95 SERVER\15\12";    /* And the pointer. */
  3075. #else
  3076.     memptr = "\15\12K/2 SERVER\15\12";
  3077. #endif /* NT */
  3078.     binary = XYFT_T;            /* Use text mode */
  3079.     return(sinit());
  3080. #else
  3081.     return(0);
  3082. #endif /* NOSERVER */
  3083. }
  3084. #endif /* OS2 */
  3085.  
  3086. /*  C W D  --  Change current working directory  */
  3087.  
  3088. /*
  3089.  String passed has first byte as length of directory name, rest of string
  3090.  is name.  Fails if can't connect, else ACKs (with name) and succeeds. 
  3091. */
  3092.  
  3093. int
  3094. cwd(vdir) char *vdir; {
  3095.     char *cdd, *zgtdir(), *dirp;
  3096.  
  3097.     vdir[xunchar(*vdir) + 1] = '\0';    /* Terminate string with a null */
  3098.     dirp = vdir+1;
  3099.     tlog(F110,"Directory requested: ",dirp,0L);
  3100.     if (zchdir(dirp)) {            /* Try to change */
  3101.     cdd = zgtdir();            /* Get new working directory. */
  3102.     debug(F110,"cwd",cdd,0);
  3103.     encstr((CHAR *)cdd);
  3104. #ifdef COMMENT
  3105.     ack1((CHAR *)(encbuf+7));
  3106. #else
  3107.     ack1(data);
  3108. #endif /* COMMENT */
  3109.     screen(SCR_CD,0,0l,cdd);
  3110.     tlog(F110,"Changed directory to",cdd,0L);
  3111.     return(1); 
  3112.     } else {
  3113.     debug(F110,"cwd failed",dirp,0);
  3114.     tlog(F110,"Failed to change directory to",dirp,0L);
  3115.     return(0);
  3116.     }
  3117. }
  3118.  
  3119.  
  3120. /*  S Y S C M D  --  Do a system command  */
  3121.  
  3122. /*  Command string is formed by concatenating the two arguments.  */
  3123.  
  3124. int
  3125. syscmd(prefix,suffix) char *prefix, *suffix; {
  3126.     char *cp;
  3127.  
  3128.     if (!prefix)
  3129.       return(0);
  3130.     if (!*prefix)
  3131.       return(0);
  3132.     for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++);
  3133.     while (*cp++ = *suffix++)
  3134. #ifdef OS2
  3135.         /* This takes away more than we gain in convenience 
  3136.         if (*(cp-1) == '/') *(cp-1) = '\\' */
  3137. #endif /* OS2 */
  3138.       ;                    /* Copy suffix */
  3139.  
  3140.     debug(F110,"syscmd",cmdstr,0);
  3141.  
  3142.     if (zxcmd(ZIFILE,cmdstr) > 0) {
  3143.         debug(F110,"syscmd zxcmd ok",cmdstr,0);
  3144.         nfils = sndsrc = 0;        /* Flag that input is from stdin */
  3145.         xflg = hcflg = 1;        /* And special flags for pipe */
  3146.     binary = XYFT_T;        /* Go to text mode */
  3147.         return (sinit());        /* Send S packet */
  3148.     } else {
  3149.         debug(F100,"syscmd zxcmd failed",cmdstr,0);
  3150.         return(0);
  3151.     }
  3152. }
  3153.  
  3154. /*  R E M S E T  --  Remote Set  */
  3155. /*  Called by server to set variables as commanded in REMOTE SET packets.  */
  3156. /*  Returns 1 on success, 0 on failure.  */
  3157.  
  3158. int
  3159. remset(s) char *s; {
  3160.     int len, i, x, y;
  3161.     char *p;
  3162.  
  3163.     len = xunchar(*s++);        /* Length of first field */
  3164.     p = s + len;            /* Pointer to second length field */
  3165.     *p++ = '\0';            /* Zero out second length field */
  3166.     x = atoi(s);            /* Value of first field */
  3167.     debug(F111,"remset",s,x);
  3168.     debug(F110,"remset",p,0);
  3169.     switch (x) {            /* Do the right thing */
  3170.       case 132:                /* Attributes (all, in) */
  3171.     atcapr = atoi(p);
  3172.     return(1);
  3173.       case 133:                /* File length attributes */
  3174.       case 233:                /* IN/OUT combined */
  3175.       case 148:                /* Both kinds of lengths */
  3176.       case 248:
  3177.     atleni = atleno = atoi(p);
  3178.     return(1);
  3179.       case 134:                /* File Type (text/binary) */
  3180.       case 234:
  3181.     attypi = attypo = atoi(p);
  3182.     return(1);
  3183.       case 135:                /* File creation date */
  3184.       case 235:
  3185.     atdati = atdato = atoi(p);
  3186.     return(1);
  3187.       case 139:                /* File Blocksize */
  3188.       case 239:
  3189.     atblki = atblko = atoi(p);
  3190.     return(1);
  3191.       case 141:                /* Encoding / Character Set */
  3192.       case 241:
  3193.     atenci = atenco = atoi(p);
  3194.     return(1);
  3195.       case 142:                /* Disposition */
  3196.       case 242:
  3197.     atdisi = atdiso = atoi(p);
  3198.     return(1);
  3199.       case 145:                /* System ID */
  3200.       case 245:
  3201.     atsidi = atsido = atoi(p);
  3202.     return(1);
  3203.       case 147:                /* System-Dependent Info */
  3204.       case 247:
  3205.     atsysi = atsyso = atoi(p);
  3206.     return(1);
  3207.       case 232:                /* Attributes (all, out) */
  3208.     atcapr = atoi(p);
  3209.     return(1);
  3210.       case 300:                /* File type (text, binary) */
  3211.     binary = atoi(p);
  3212.     return(1);
  3213.       case 301:                /* File name conversion */
  3214.     fncnv = 1 - atoi(p);        /* (oops) */
  3215.     return(1);
  3216.       case 302:                /* File name collision */
  3217.     x = atoi(p);
  3218.     if (x == XYFX_R) warn = 1;    /* Rename */
  3219.     if (x == XYFX_X) warn = 0;    /* Replace */
  3220.     fncact = x;
  3221.     return(1);
  3222.       case 310:                /* Incomplete File Disposition */
  3223.     keep = atoi(p);            /* Keep, Discard */
  3224.     return(1);
  3225.       case 311:                /* Blocksize */
  3226.     fblksiz = atoi(p);
  3227.     return(1);
  3228.       case 312:                /* Record Length */
  3229.     frecl = atoi(p);
  3230.     return(1);
  3231.       case 313:                /* Record format */
  3232.     frecfm = atoi(p);
  3233.     return(1);
  3234.       case 314:                /* File organization */
  3235.     forg = atoi(p);
  3236.     return(1);
  3237.       case 315:                /* File carriage control */
  3238.     fcctrl = atoi(p);
  3239.     return(1);
  3240.       case 400:                /* Block check */
  3241.     y = atoi(p);
  3242.     if (y < 5 && y > 0) {
  3243.         bctr = y;
  3244.         return(1);
  3245.     } else if (*p == 'B') {
  3246.         bctr = 4;
  3247.         return(1);
  3248.     }
  3249.     return(0);
  3250.       case 401:                /* Receive packet-length */
  3251.     rpsiz = urpsiz = atoi(p);
  3252.     if (urpsiz > MAXRP) urpsiz = MAXRP; /* Max long-packet length */
  3253.     if (rpsiz > 94) rpsiz = 94;        /* Max short-packet length */
  3254.     urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
  3255.     return(1);
  3256.       case 402:                /* Receive timeout */
  3257.     y = atoi(p);            /* Client is telling us */
  3258.     if (y > -1 && y < 999) {    /* the timeout that it wants */
  3259.         pkttim = chktimo(y,timef);    /* us to tell it to use. */
  3260.         return(1);
  3261.     } else return(0);
  3262.       case 403:                /* Retry limit */
  3263.     y = atoi(p);
  3264.     if (y > -1 && y < 95) {
  3265.         maxtry = y;
  3266.         return(1);
  3267.     } else return(0);
  3268.       case 404:                /* Server timeout */
  3269.     y = atoi(p);
  3270.     if (y < 0) return(0);
  3271.     srvtim = y;
  3272.     return(1);
  3273.  
  3274. #ifndef NOCSETS
  3275.       case 405:                /* Transfer character set */
  3276.     for (i = 0; i < ntcsets; i++) { 
  3277.         if (!strcmp(tcsinfo[i].designator,p)) break;
  3278.     }
  3279.     debug(F101,"remset xfer charset lookup","",i);
  3280.     if (i == ntcsets) return(0);
  3281.     tcharset = tcsinfo[i].code;    /* if known, use it */
  3282.     if (tcharset == TC_TRANSP)
  3283.       rx = NULL;
  3284.     else
  3285.       rx = xlr[tcharset][fcharset];    /* translation function */
  3286.     return(1);
  3287. #endif /* NOCSETS */
  3288.  
  3289.       case 406:                /* Window slots */
  3290.     y = atoi(p);
  3291.     if (y == 0) y = 1;
  3292.     if (y < 1 && y > MAXWS) return(0);
  3293.     wslotr = y;
  3294.     swcapr = 1;
  3295.     urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
  3296.     return(1);
  3297.       default:                /* Anything else... */
  3298.     return(0);
  3299.     }
  3300. }
  3301.  
  3302. /* Adjust packet length based on number of window slots and buffer size */
  3303.  
  3304. int
  3305. adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
  3306.     if (protocol != PROTO_K) return(pktlen);
  3307.     debug(F101,"adjpkl len","",pktlen);
  3308.     debug(F101,"adjpkl slots","",slots);
  3309.     debug(F101,"adjpkl bufsiz","",bufsiz);
  3310.     if (((pktlen + 6) * slots) > bufsiz)
  3311.       pktlen = (bufsiz / slots) - 6;
  3312.     debug(F101,"adjpkl new len","",pktlen);
  3313.     return(pktlen);
  3314. }
  3315.  
  3316. /* Set transfer mode and file naming based on comparison of system types */
  3317.  
  3318. VOID
  3319. whoarewe() {
  3320.     extern int xfermode;
  3321.     extern char whoareu[];
  3322.     int flag = 0;
  3323.     debug(F101,"whoarewe xfermode","",xfermode);
  3324.     if (xfermode == XMODE_A) {        /* If TRANSFER MODE AUTOMATIC */
  3325.     if (whoareu[0]) {        /* and we know partner's system type */
  3326.         char * p = (char *)whoareu;
  3327.         debug(F110,"whoarewe remote sysid",whoareu,0);
  3328.         if (!strcmp(p,cksysid))    /* Other system same as us */
  3329.           flag = 1;
  3330. #ifdef UNIX
  3331.         if (!strcmp(p,"L3"))    /* UNIX is sort of like AmigaDOS */
  3332.           flag = 1;            /* (same directory separator) */
  3333.         else if (!strcmp(p,"N3"))    /* UNIX like Aegis */
  3334.           flag = 1;
  3335. #else
  3336. #ifdef AMIGA
  3337. /* Like UNIX, but case distinctions are ignored and can begin with device:. */
  3338.         else if (!strcmp(p,"U1"))    /* Amiga is sort of like UNIX */
  3339.           flag = 1;
  3340.         else if (!strcmp(p,"N3"))    /* Amiga is sort of like Aegis */
  3341.           flag = 1;
  3342. #else
  3343. #ifdef OS2                /* (Includes Windows 95/NT) */
  3344.  
  3345.         /* DOS, GEMDOS, Windows 3.x, Windows 95, Windows NT */
  3346.         /* All "the same" for FAT partitions but all bets off otherwise */
  3347.         /* so this part needs some refinement ...  */
  3348.  
  3349.         else if (!strcmp(p,"U8"))    /* MS-DOS */
  3350.           flag = 1;
  3351.         else if (!strcmp(p,"UO"))    /* OS/2 */
  3352.           flag = 1;
  3353.         else if (!strcmp(p,"UN"))    /* Windows NT or 95 */
  3354.           flag = 1;
  3355.         else if (!strcmp(p,"K2"))    /* GEMDOS */
  3356.           flag = 1;
  3357. #else
  3358. #ifdef GEMDOS
  3359.         else if (!strcmp(p,"U8"))
  3360.           flag = 1;
  3361.         else if (!strcmp(p,"UO"))
  3362.           flag = 1;
  3363.         else if (!strcmp(p,"UN"))
  3364.           flag = 1;
  3365.         else if (!strcmp(p,"K2"))
  3366.           flag = 1;
  3367. #endif /* GEMDOS */
  3368. #endif /* OS2 */
  3369. #endif /* AMIGA */
  3370. #endif /* UNIX */
  3371.  
  3372.         debug(F101,"whoarewe flag","",flag);
  3373.         if (flag) {            /* We have a match */
  3374.         fncnv = XYFN_L;        /* so literal filenames */
  3375. #ifdef VMS
  3376.         binary = XYFT_L;    /* For VMS-to-VMS, use labeled */
  3377. #else
  3378. #ifdef OS2
  3379.         if (!strcmp(cksysid,"UO") && !strcmp((char *)whoareu,"UO"))
  3380.           binary = XYFT_L;    /* For OS/2-to-OS/2, use labeled */
  3381. #else
  3382.         binary = XYFT_B;    /* For all others use binary */
  3383. #endif /* OS2 */
  3384. #endif /* VMS */
  3385.         }
  3386.     }
  3387.     }
  3388. }
  3389.