home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit5a188 / ckcfns.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  67KB  |  2,105 lines

  1. char *fnsv = "C-Kermit functions, 5A(081) 20 Feb 93";
  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 small enough) */
  6.  
  7. /*
  8.   Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
  9.   Columbia University Center for Computing Activities.
  10.   First released January 1985.
  11.   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  12.   York.  Permission is granted to any individual or institution to use this
  13.   software as long as it is not sold for profit.  This copyright notice must be
  14.   retained.  This software may not be included in commercial products without
  15.   written permission of Columbia University.
  16. */
  17. /*
  18.  System-dependent primitives defined in:
  19.  
  20.    ck?tio.c -- terminal i/o
  21.    cx?fio.c -- file i/o, directory structure
  22. */
  23. #include "ckcsym.h"            /* Once needed this for Mac... */
  24. #include "ckcasc.h"            /* ASCII symbols */
  25. #include "ckcdeb.h"            /* Debug formats, typedefs, etc. */
  26. #include "ckcker.h"            /* Symbol definitions for Kermit */
  27. #include "ckcxla.h"            /* Character set symbols */
  28.  
  29. /* Externals from ckcmai.c */
  30. extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
  31.  rpt, rptq, rptflg, capas, keep, fncact, pkttim, autopar, spsizr;
  32. extern int pktnum, bctr, bctu, bctl, fmask, clfils, sbufnum,
  33.  size, osize, spktl, nfils, warn, timef, spsizf, sndtyp, success;
  34. extern int parity, turn, network, what, fsecs,
  35.  delay, displa, xflg, mypadn;
  36. extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize, speed;
  37. extern int fblksiz, frecl, frecfm, forg, fcctrl;
  38. extern int spackets, rpackets, timeouts, retrans, crunched, wmax;
  39. extern int hcflg, binary, savmod, fncnv, local, server, cxseen, czseen;
  40. extern int nakstate, discard;
  41. extern int rq, rqf, sq, wslots, wslotn, wslotr, winlo, urpsiz, rln;
  42. extern int atcapr, atcapb, atcapu;
  43. extern int lpcapr, lpcapb, lpcapu;
  44. extern int swcapr, swcapb, swcapu;
  45. extern int lscapr, lscapb, lscapu;
  46. extern int bsave, bsavef;
  47. extern int sseqtbl[];
  48. extern int numerrs;
  49. extern long rptn;
  50. extern int maxtry;
  51.  
  52. #ifndef NOCSETS
  53. extern int tcharset, fcharset;
  54. extern int ntcsets;
  55. extern struct csinfo tcsinfo[], fcsinfo[];
  56. #endif /* NOCSETS */
  57.  
  58. extern int
  59.   atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
  60.   attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso; 
  61.  
  62. extern int bigsbsiz, bigrbsiz;
  63.  
  64. #ifdef DYNAMIC
  65.   extern CHAR *srvcmd;
  66. #else
  67.   extern CHAR srvcmd[];
  68. #endif /* DYNAMIC */
  69. extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate;
  70. extern CHAR *recpkt, *data, padbuf[], stchr, mystch;
  71. extern CHAR *srvptr;
  72. extern CHAR *rdatap;
  73. extern char *cmarg, *cmarg2, *hlptxt, **cmlist, filnam[], fspec[];
  74.  
  75. _PROTOTYP( CHAR *rpar, (void) );
  76. _PROTOTYP( int lslook, (unsigned int b) );    /* Locking Shift Lookahead */
  77. _PROTOTYP( int szeof, (CHAR *s) );
  78.  
  79. /* International character sets */
  80.  
  81. #ifndef NOCSETS
  82. /* Pointers to translation functions */
  83. #ifdef CK_ANSIC
  84. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* Character set */
  85. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])(CHAR); /* translation functions */
  86. #else
  87. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();    /* Character set */
  88. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();    /* translation functions. */
  89. #endif /* CK_ANSIC */
  90. _PROTOTYP( CHAR (*rx), (CHAR) );    /* Input translation function */
  91. _PROTOTYP( CHAR (*sx), (CHAR) );    /* Output translation function */
  92. _PROTOTYP( CHAR ident, (CHAR) );    /* Identity translation function */
  93. #endif /* NOCSETS */
  94.  
  95. /* Windowing things */
  96.  
  97. extern int rseqtbl[];            /* Rec'd-packet sequence # table */
  98.  
  99. /* (PWP) external def. of things used in buffered file input and output */
  100.  
  101. #ifdef DYNAMIC
  102. extern char *zinbuffer, *zoutbuffer;
  103. #else
  104. extern char zinbuffer[], zoutbuffer[];
  105. #endif
  106. extern char *zinptr, *zoutptr;
  107. extern int zincnt, zoutcnt;
  108.  
  109. /* Variables defined in this module, but shared by ckcfn3, to which */
  110. /* several functions have been moved... */
  111.  
  112. int sndsrc;        /* Flag for where to get names of files to send: */
  113.                     /* -1: znext() function */
  114.                     /*  0: stdin */
  115.                     /* >0: list in cmlist */
  116.  
  117. int  memstr;                /* Flag for input from memory string */
  118.  
  119. #ifdef pdp11
  120. CHAR myinit[25];            /* Copy of my Send-Init data */
  121. #else
  122. CHAR myinit[100];            /* Copy of my Send-Init data */
  123. #endif /* pdp11 */
  124.  
  125. /* Variables local to this module */
  126.  
  127. static char *memptr;            /* Pointer for memory strings */
  128.  
  129. #ifdef pdp11
  130. static char cmdstr[50];            /* System command string. */
  131. #else
  132. static char cmdstr[100];
  133. #endif /* pdp11 */
  134.  
  135. static int drain;            /* For draining stacked-up ACKs. */
  136.  
  137. static int first;            /* Flag for first char from input */
  138. static CHAR t,                /* Current character */
  139.     next;                /* Next character */
  140.  
  141. static int lsstate = 0;            /* Locking shift state */
  142. static int lsquote = 0;            /* Locking shift quote */
  143.  
  144. #ifdef datageneral
  145. extern int quiet;
  146. #endif
  147.  
  148. /*  E N C S T R  --  Encode a string from memory. */
  149.  
  150. /*
  151.   Call this instead of getpkt() if source is a string, rather than a file.
  152.   Note: Character set translation is never done in this case.
  153. */
  154.  
  155. #ifdef pdp11
  156. #define ENCBUFL 100
  157. #else
  158. #define ENCBUFL 200
  159. #endif /* pdp11 */
  160. CHAR encbuf[ENCBUFL];
  161.  
  162. int
  163. encstr(s) CHAR* s; {
  164.     int m; char *p;
  165.     CHAR *dsave;
  166.  
  167.     if ((m = (int)strlen((char *)s)) > ENCBUFL) {
  168.     debug(F111,"encstr string too long for buffer",s,ENCBUFL);
  169.     s[ENCBUFL] = '\0';
  170.     }
  171.     if (m > spsiz-bctl-3) {
  172.     debug(F111,"encstr string too long for packet",s,spsiz-bctl-3);
  173.     s[spsiz-bctl-3] = '\0';
  174.     }
  175.     m = memstr; p = memptr;        /* Save these. */
  176.  
  177.     memptr = (char *)s;            /* Point to the string. */
  178.     memstr = 1;                /* Flag memory string as source. */
  179.     first = 1;                /* Initialize character lookahead. */
  180.     dsave = data;            /* Boy is this ugly... */
  181.     data = encbuf + 7;            /* Why + 7?  See spack()... */
  182. #ifdef COMMENT
  183.     getpkt(spsiz-bctl-3,0);        /* Fill a packet from the string. */
  184. #else
  185.     getpkt(spsiz,0);
  186. #endif /* COMMENT */
  187.     data = dsave;            /* (sorry...) */
  188.     memstr = m;                /* Restore memory string flag */
  189.     memptr = p;                /* and pointer */
  190.     first = 1;                /* Put this back as we found it. */
  191.     return(0);
  192. }
  193.  
  194. #ifdef COMMENT
  195. /*
  196.   We don't use this routine any more -- the code has been incorporated
  197.   directly into getpkt() to reduce per-character function call overhead.
  198.   Also, watch out: it hasn't been updated since it was commented out a
  199.   long time ago.
  200. */
  201. /* E N C O D E - Kermit packet encoding procedure */
  202.  
  203. VOID
  204. encode(a) CHAR a; {            /* The current character */
  205.     int a7;                /* Low order 7 bits of character */
  206.     int b8;                /* 8th bit of character */
  207.  
  208. #ifndef NOCSETS
  209.     if (!binary && sx) a = (*sx)(a);    /* Translate. */
  210. #endif /* NOCSETS */
  211.  
  212.     if (rptflg)    {                   /* Repeat processing? */
  213.         if (a == next && (first == 0)) { /* Got a run... */
  214.         if (++rpt < 94)        /* Below max, just count */
  215.                 return;
  216.         else if (rpt == 94) {    /* Reached max, must dump */
  217.                 data[size++] = rptq;
  218.                 data[size++] = tochar(rpt);
  219.         rptn += rpt;        /* Count, for stats */
  220.                 rpt = 0;
  221.         }
  222.         } else if (rpt == 1) {        /* Run broken, only 2? */
  223.             rpt = 0;            /* Yes, reset repeat flag & count. */
  224.         encode(a);            /* Do the character twice. */
  225.         if (size <= maxsize) osize = size;
  226.         rpt = 0;
  227.         encode(a);
  228.         return;
  229.     } else if (rpt > 1) {        /* More than two */
  230.             data[size++] = rptq;    /* Insert the repeat prefix */
  231.             data[size++] = tochar(++rpt); /* and count. */
  232.         rptn += rpt;
  233.             rpt = 0;            /* Reset repeat counter. */
  234.         }
  235.     }
  236.     a7 = a & 0177;            /* Isolate ASCII part */
  237.     b8 = a & 0200;            /* and 8th (parity) bit. */
  238.  
  239.     if (ebqflg && b8) {            /* Do 8th bit prefix if necessary. */
  240.         data[size++] = ebq;
  241.         a = a7;
  242.     }
  243.     if ((a7 < SP) || (a7==DEL))    {    /* Do control prefix if necessary */
  244.         data[size++] = myctlq;
  245.     a = ctl(a);
  246.     }
  247.     if (a7 == myctlq)            /* Prefix the control prefix */
  248.         data[size++] = myctlq;
  249.  
  250.     if ((rptflg) && (a7 == rptq))    /* If it's the repeat prefix, */
  251.         data[size++] = myctlq;        /* quote it if doing repeat counts. */
  252.  
  253.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th bit prefix */
  254.         data[size++] = myctlq;        /* if doing 8th-bit prefixes */
  255.  
  256.     data[size++] = a;            /* Finally, insert the character */
  257.     data[size] = '\0';            /* itself, and mark the end. */
  258. }
  259. #endif /* COMMENT */
  260.  
  261. /*  Output functions passed to 'decode':  */
  262.  
  263. int                   /*  Put character in server command buffer  */
  264. #ifdef CK_ANSIC
  265. putsrv(char c)
  266. #else
  267. putsrv(c) register char c;
  268. #endif /* CK_ANSIC */
  269. /* putsrv */ {
  270.     *srvptr++ = c;
  271.     *srvptr = '\0';        /* Make sure buffer is null-terminated */
  272.     return(0);
  273. }
  274.  
  275. int                    /*  Output character to console.  */
  276. #ifdef CK_ANSIC
  277. puttrm(char c)
  278. #else
  279. puttrm(c) register char c;
  280. #endif /* CK_ANSIC */
  281. /* puttrm */ {
  282.     conoc(c);
  283.     return(0);
  284. }
  285.  
  286. int                    /*  Output char to file. */
  287. #ifdef CK_ANSIC
  288. putfil(char c)
  289. #else
  290. putfil(c) register char c;
  291. #endif /* CK_ANSIC */
  292. /* putfil */ {
  293.     if (zchout(ZOFILE, (char) (c & fmask)) < 0) {
  294.     czseen = 1;               /* If write error... */
  295.     debug(F101,"putfil zchout write error, setting czseen","",1);
  296.     return(-1);
  297.     }
  298.     return(0);
  299. }
  300.  
  301. /* D E C O D E  --  Kermit packet decoding procedure */
  302.  
  303. /*
  304.  Call with string to be decoded and an output function.
  305.  Returns 0 on success, -1 on failure (e.g. disk full).
  306.  
  307.  This is the "inner loop" when receiving files, and must be coded as 
  308.  efficiently as possible.  Note some potential problems:  if a packet
  309.  is badly formed, having a prefixed sequence ending prematurely, this
  310.  function, as coded, could read past the end of the packet.  This has
  311.  never happened, thus the additional (time-consuming) tests have not
  312.  been added.
  313. */
  314.  
  315. static CHAR *xdbuf;    /* Global version of decode()'s buffer pointer */
  316.                         /* for use by translation functions. */
  317.  
  318. /* Function for pushing a character onto decode()'s input stream. */
  319.  
  320. VOID
  321. #ifdef CK_ANSIC
  322. zdstuff(CHAR c)
  323. #else
  324. zdstuff(c) CHAR c;
  325. #endif /* CK_ANSIC */
  326. /* zdstuff */ {    
  327.     xdbuf--;                /* Back up the pointer. */
  328.     *xdbuf = c;                /* Stuff the character. */
  329. }
  330.  
  331. int
  332. #ifdef CK_ANSIC
  333. decode(CHAR *buf, int (*fn)(char), int xlate)
  334. #else
  335. decode(buf,fn,xlate) register CHAR *buf; register int (*fn)(); int xlate;
  336. #endif /* CK_ANSIC */
  337. /* decode */ {
  338.     register unsigned int a, a7, a8, b8; /* Various copies of current char */
  339.     int t;                /* Int version of character */
  340.     int ssflg;                /* Character was single-shifted */
  341.  
  342. /*
  343.   Catch the case in which we are asked to decode into a file that is not open,
  344.   for example, if the user interrupted the transfer, but the other Kermit
  345.   keeps sending.
  346. */
  347.     if ((cxseen || czseen || discard) && (fn == putfil))
  348.       return(0);
  349.  
  350.     xdbuf = buf;            /* Make global copy of pointer. */
  351.     rpt = 0;                /* Initialize repeat count. */
  352.  
  353.     while ((a = *xdbuf++ & 0xFF) != '\0') { /* Get next character. */
  354.     if (a == rptq && rptflg) {    /* Got a repeat prefix? */
  355.         rpt = xunchar(*xdbuf++ & 0xFF); /* Yes, get the repeat count, */
  356.         rptn += rpt;
  357.         a = *xdbuf++ & 0xFF;    /* and get the prefixed character. */
  358.     }
  359.     b8 = lsstate ? 0200 : 0;    /* 8th-bit value from SHIFT-STATE */
  360.     if (ebqflg && a == ebq) {    /* Have 8th-bit prefix? */
  361.         b8 ^= 0200;            /* Yes, invert the 8th bit's value, */
  362.         ssflg = 1;            /* remember we did this, */
  363.         a = *xdbuf++ & 0xFF;    /* and get the prefixed character. */
  364.     } else ssflg = 0;
  365.  
  366.     if (a == ctlq) {        /* If control prefix, */
  367.         a  = *xdbuf++ & 0xFF;    /* get its operand */
  368.         a7 = a & 0x7F;        /* and its low 7 bits. */
  369.         if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Controllify */
  370.           a = ctl(a);        /* if in control range. */
  371.         if (lscapu) {        /* If doing locking shifts... */
  372.         if (lsstate)        /* If SHIFTED */
  373.           a8 = (a & ~b8) & 0xFF; /* Invert meaning of 8th bit */
  374.         else            /* otherwise */
  375.           a8 = a | b8;        /* OR in 8th bit */
  376.         /* If we're not in a quoted sequence */
  377.         if (!lsquote && (!lsstate || !ssflg)) {
  378.             if (a8 == DLE) {    /* Check for DLE quote */
  379.             lsquote = 1;    /* prefixed by single shift! */
  380.             continue;
  381.             } else if (a8 == SO) { /* Check for Shift-Out */
  382.             lsstate = 1;    /* SHIFT-STATE = SHIFTED */
  383.             continue;
  384.             } else if (a8 == SI) { /* or Shift-In */
  385.             lsstate = 0;    /* SHIFT-STATE = UNSHIFTED */
  386.             continue;
  387.             }
  388.         } else lsquote = 0;
  389.         }
  390.     }
  391.     a |= b8;            /* OR in the 8th bit */
  392.     if (rpt == 0) rpt = 1;        /* If no repeats, then one */
  393.     if (!binary) {            /* If in text mode, */
  394. #ifdef NLCHAR
  395.         if (a == CR) continue;    /* Discard carriage returns, */
  396.             if (a == LF) a = NLCHAR;     /* convert LF to system's newline. */
  397. #endif /* NLCHAR */
  398.  
  399. #ifndef NOCSETS                /* Character-set translation */
  400. #ifdef KANJI                /* For Kanji transfers, */
  401.         if (tcharset != TC_JEUC)    /* postpone translation. */
  402. #endif /* KANJI */
  403.           if (xlate && rx) a = (*rx)((CHAR) a); /* Translate charset */
  404. #endif /* NOCSETS */
  405.         }
  406.     if (fn == putfil) { /* (PWP) speedup via buffered output and a macro */
  407.         for (; rpt > 0; rpt--) {    /* Output the char RPT times */
  408. #ifndef NOCSETS
  409. #ifdef KANJI
  410.         if (!binary && tcharset == TC_JEUC &&
  411.             fcharset != FC_JEUC) { /* Translating from J-EUC */
  412.             if (ffc == 0L) xkanjf();
  413.             if (xkanji(a,fn) < 0)  /* to something else? */
  414.               return(-1);
  415.         } else
  416. #endif /* KANJI */
  417. #endif /* NOCSETS */
  418.         if ((t = zmchout(a & fmask)) < 0) { /* zmchout is a macro */
  419. #ifdef COMMENT
  420. /* Too costly, uncomment these if you really need them. */
  421.             debug(F101,"decode zmchout","",t);
  422.             debug(F101,"decode zoutcnt","",zoutcnt);
  423.             debug(F101,"decode a","",a);
  424. #endif /* COMMENT */
  425.             return(-1);
  426.         }
  427.         ffc++;            /* Count the character */
  428.         }
  429.     } else {            /* Output to something else. */
  430.         a &= fmask;            /* Apply file mask */
  431.         for (; rpt > 0; rpt--) {    /* Output the char RPT times */
  432.         if ((*fn)((char) a) < 0) return(-1); /* Send to output func. */
  433.         ffc++;
  434.         }
  435.     }
  436.     }
  437.     return(0);
  438. }
  439.  
  440. /*  G E T P K T -- Fill a packet data field  */
  441.  
  442. /*
  443.  Gets characters from the current source -- file or memory string.
  444.  Encodes the data into the packet, filling the packet optimally.
  445.  Set first = 1 when calling for the first time on a given input stream
  446.  (string or file).
  447.  
  448.  Call with:
  449.  bufmax -- current send-packet size
  450.  xlate  -- flag: 0 to skip character-set translation, 1 to translate
  451.  
  452.  Uses global variables:
  453.  t     -- current character.
  454.  first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
  455.  next  -- next character.
  456.  data  -- pointer to the packet data buffer.
  457.  size  -- number of characters in the data buffer.
  458.  memstr - flag that input is coming from a memory string instead of a file.
  459.  memptr - pointer to string in memory.
  460.  (*sx)()  character set translation function
  461.  
  462. Returns the size as value of the function, and also sets global "size",
  463. and fills (and null-terminates) the global data array.  Returns 0 upon eof.
  464.  
  465. Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
  466. Incorporates old getchx() and encode() inline to reduce function calls,
  467. uses buffered input for much-improved efficiency, and clears up some
  468. confusion with line termination (CRLF vs LF vs CR).
  469.  
  470. Rewritten again by Frank da Cruz to incorporate locking shift mechanism,
  471. May 1991.
  472. */
  473.  
  474. /*
  475.   Lookahead function to decide whether locking shift is worth it.  Looks at
  476.   the next four input characters to see if all of their 8th bits match the
  477.   argument.  Call with 0 or 0200.  Returns 1 if so, 0 if not.  If we don't
  478.   happen to have at least 4 more characters waiting in the input buffer,
  479.   returns 1.  Note that zinptr points two characters ahead of the current
  480.   character because of repeat-count lookahead.
  481. */
  482.  
  483. #ifdef KANJI
  484. int
  485. kgetf() {
  486.     return(zminchar());
  487. }
  488.  
  489. int
  490. kgetm() {
  491.     int x;
  492.     if (x = *memptr++) return(x);
  493.     else return(-1);
  494. }
  495. #endif /* KANJI */
  496.  
  497. int
  498. lslook(b) unsigned int b; {        /* Locking Shift Lookahead */
  499.     int i;
  500.     if (zincnt < 3)            /* If not enough chars in buffer, */
  501.       return(1);            /* force shift-state switch. */
  502.     b &= 0200;                /* Force argument to proper form. */
  503.     for (i = -1; i < 3; i++)        /* Look at next 5 characters to */
  504.       if (((*(zinptr+i)) & 0200) != b)    /* see if all their 8th bits match.  */
  505.     return(0);            /* They don't. */
  506.     return(1);                /* They do. */
  507. }
  508.  
  509. int
  510. getpkt(bufmax,xlate) int bufmax, xlate; { /* Fill one packet buffer */
  511.     register CHAR rt = t, rnext = next; /* register shadows of the globals */
  512.     register CHAR *dp, *odp, *odp2, *p1, *p2; /* pointers... */
  513.     register int x;            /* Loop index. */
  514.     register int a7;            /* Low 7 bits of character */
  515.     static CHAR leftover[9] = { '\0','\0','\0','\0','\0','\0','\0','\0','\0' };
  516.     CHAR xxls, xxdl, xxrc, xxss, xxcq;    /* Pieces of prefixed sequence */
  517.     int n;                /* worker */
  518.  
  519. /*
  520.   Assume bufmax is the receiver's total receive-packet buffer length.
  521.   Our whole packet has to fit into it, so we adjust the data field length.
  522.   We also decide optimally whether it is better to use a short-format or
  523.   long-format packet when we're near the borderline.
  524. */
  525.     n = bufmax - 5;            /* Space for Data and Checksum */
  526.     if (n > 92 && n < 96) n = 92;    /* "Short" Long packets don't pay */
  527.     if (n > 92 && lpcapu == 0)        /* If long packets needed, */
  528.       n = 92;                /* make sure they've been negotiated */
  529.     bufmax = n - bctl;            /* Space for data */
  530.     if (n > 92) bufmax -= 3;        /* Long packet needs header chksum */
  531.  
  532.     if (first == 1) {        /* If first character of this file... */
  533.     ffc = 0L;        /* Reset file character counter */
  534.     first = 0;        /* Next character won't be first */
  535.     *leftover = '\0';    /* Discard any interrupted leftovers, */
  536.  
  537.     /* get first character of file into rt, watching out for null file */
  538.  
  539. #ifndef NOCSETS
  540. #ifdef KANJI
  541.     if (!binary && tcharset == TC_JEUC && xlate) {
  542.         x = zkanjf();
  543.         if ((x = zkanji( memstr ? kgetm : kgetf )) < 0) {
  544.             first = -1;
  545.             size = 0;
  546.             if (x == -2) {
  547.                 debug(F100,"getpkt(zkanji): input error","",0);
  548.                 cxseen = 1;
  549.             } else debug(F100,"getpkt(zkanji): empty string/file","",0);
  550.             return (0);
  551.         }
  552.         ffc++;
  553.         rt = x;
  554.     } else {
  555. #endif /* KANJI */
  556. #endif /* not NOCSETS */
  557.     if (memstr) {            /* Reading data from memory string */
  558.         if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
  559.         first = -1;
  560.             size = 0;
  561.         debug(F100,"getpkt: empty string","",0);
  562.         return (0);
  563.         }
  564.  
  565.     } else {            /* Reading data from a file */
  566.  
  567.         if ((x = zminchar()) < 0) { /* End of file or input error */
  568.         first = -1;
  569.             size = 0;
  570.         if (x == -2) {        /* Error */
  571.             debug(F100,"getpkt: input error","",0);
  572.             cxseen = 1;        /* Interrupt the file transfer */
  573.         } else debug(F100,"getpkt: empty file","",0); /* Empty file */
  574.         return(0);
  575.         }
  576.         ffc++;            /* Count a file character */
  577.         rt = x;            /* Convert int to char */
  578.         debug(F101,"getpkt zminchar","",rt);
  579.     }
  580. #ifndef NOCSETS
  581. #ifdef KANJI
  582.     }
  583. #endif /* KANJI */
  584. #endif /* not NOCSETS */
  585.  
  586.     rt &= fmask;            /* Apply SET FILE BYTESIZE mask */
  587.     debug(F101,"getpkt fmask","",fmask);
  588.     debug(F101,"getpkt new rt","",rt);
  589.  
  590. #ifndef NOCSETS
  591.     if (xlate) {
  592.         debug(F101,"getpkt about to call translate function","",rt);
  593.         debug(F101,"tcharset","",tcharset);
  594.         debug(F101,"fcharset","",fcharset);
  595.     }
  596. #ifdef KANJI
  597.     if (tcharset != TC_JEUC)
  598. #endif /* KANJI */
  599.       if (!binary && sx && xlate) {
  600.           rt = (*sx)(rt); /* Translate */
  601.           debug(F101," translate function returns","",rt);
  602.       }
  603. #endif /* not NOCSETS */
  604.  
  605.     /* PWP: handling of NLCHAR is done later (in the while loop)... */
  606.  
  607.     } else if ((first == -1) && (*leftover == '\0')) /* EOF from last time? */
  608.         return(size = 0);
  609. /*
  610.   Here we handle characters that were encoded for the last packet but
  611.   did not fit, and so were saved in the "leftover" array.
  612. */
  613.     dp = data;                /* Point to packet data buffer */
  614.     for (p1 = leftover; (*dp = *p1) != '\0'; p1++, dp++) /* Copy leftovers */
  615.         ;
  616.     *leftover = '\0';            /* Delete leftovers */
  617.     if (first == -1)            /* Handle EOF */
  618.       return(size = (dp - data));
  619.   
  620. /* Now fill up the rest of the packet. */
  621.  
  622.     rpt = 0;                /* Initialize character repeat count */
  623.  
  624.     while (first > -1) {        /* Until EOF... */
  625. #ifndef NOCSETS
  626. #ifdef KANJI
  627.     if (!binary && xlate && tcharset == TC_JEUC) {
  628.         if ((x = zkanji( memstr ? kgetm : kgetf )) < 0) {
  629.             first = -1;
  630.             if (x == -2) cxseen = 1;
  631.         }
  632.         ffc++;
  633.         rnext = x & fmask;
  634.     } else {
  635. #endif /* KANJI */
  636. #endif /* not NOCSETS */
  637.     if (memstr) {            /* Get next char from memory string */
  638.         if ((x = *memptr++) == '\0') /* End of string means EOF */
  639.           first = -1;        /* Flag EOF for next time. */
  640.         rnext = x & fmask;        /* Apply file mask */
  641.     } else {
  642.         if ((x = zminchar()) < 0) { /* Real file, check for EOF */
  643.         first = -1;        /* Flag eof for next time. */
  644.         if (x == -2) cxseen = 1; /* If error, cancel this file. */
  645.         }
  646.         rnext = x & fmask;        /* Apply file mask */
  647.     } 
  648.     ffc++;                /* Count the character */
  649. #ifndef NOCSETS
  650. #ifdef KANJI
  651.     }
  652. #endif /* KANJI */
  653. #endif /* not NOCSETS */
  654.  
  655.     /*** debug(F101,"getpkt rnext","",rnext); ***/
  656.  
  657. #ifndef NOCSETS
  658. #ifdef KANJI
  659.     if (tcharset != TC_JEUC)
  660. #endif /* KANJI */
  661.         if (!binary && sx && xlate) {
  662.         rnext = (*sx)(rnext); /* Translate */
  663.         debug(F101,"getpkt xlated rnext to","",rnext);
  664.         }
  665. #endif /* not NOCSETS */
  666.  
  667.     odp = dp;            /* Remember where we started. */
  668.     xxls = xxdl = xxrc = xxss = xxcq = NUL;    /* Clear these. */
  669.  
  670. /*
  671.   Now encode the character according to the options that are in effect:
  672.     binary: text or binary mode.
  673.     rptflg: repeat counts enabled.
  674.     ebqflg: 8th-bit prefixing enabled.
  675.     lscapu: locking shifts enabled.
  676. */
  677.     if (rptflg) {            /* Repeat processing is on? */
  678.         if (
  679. #ifdef NLCHAR
  680.         /*
  681.          * If the next char is really CRLF, then we cannot
  682.          * be doing a repeat (unless CR,CR,LF which becomes
  683.          * "~ <n-1> CR CR LF", which is OK but not most efficient).
  684.          * I just plain don't worry about this case.  The actual
  685.          * conversion from NL to CRLF is done after the rptflg if...
  686.          */
  687.         (binary || (rnext != NLCHAR)) &&
  688. #endif /* NLCHAR */
  689.         (rt == rnext) && (first == 0)) { /* Got a run... */
  690.         if (++rpt < 94) {    /* Below max, just count */
  691.             continue;        /* go back and get another */
  692.         }
  693.         else if (rpt == 94) {    /* Reached max, must dump */
  694.             xxrc = tochar(rpt);    /* Put the repeat count here */
  695.             rptn += rpt;    /* Accumulate it for statistics */
  696.             rpt = 0;        /* And reset it */
  697.         }
  698.         } else if (rpt > 1) {    /* More than two */
  699.         xxrc = tochar(++rpt);    /* and count. */
  700.         rptn += rpt;
  701.         rpt = 0;        /* Reset repeat counter. */
  702.         }
  703.         /*
  704.           If (rpt == 1) we must encode exactly two characters.
  705.           This is done later, after the first character is encoded.
  706.         */
  707.     }
  708.  
  709. #ifdef NLCHAR
  710.     if (!binary && (rt == NLCHAR)) { /* It's the newline character */
  711.         if (lscapu && lsstate) {    /* If SHIFT-STATE is SHIFTED */
  712.         if (ebqflg) {        /* If single shifts enabled, */
  713.             *dp++ = ebq;    /* insert a single shift. */
  714.         } else {        /* Otherwise must shift in. */
  715.             *dp++ = myctlq;    /* Insert shift-out code */
  716.             *dp++ = 'O';
  717.             lsstate = 0;    /* Change shift state */
  718.         }
  719.         }
  720.         *dp++ = myctlq;        /* Insert carriage return directly */
  721.         *dp++ = 'M';
  722.         rt = LF;            /* Now make next char be linefeed. */
  723.     }
  724. #endif /* NLCHAR */
  725.  
  726. /*
  727.   Now handle the 8th bit of the file character.  If we have an 8-bit
  728.   connection, we preserve the 8th bit.  If we have a 7-bit connection,
  729.   we employ either single or locking shifts (if they are enabled).
  730. */
  731.     a7 = rt & 0177;            /* Get low 7 bits of character */
  732.     if (rt & 0200) {        /* 8-bit character? */
  733.         if (lscapu) {        /* Locking shifts enabled? */
  734.         if (!lsstate) {        /* Not currently shifted? */
  735.             x = lslook(0200);    /* Look ahead */
  736.             if (x != 0 || ebqflg == 0) { /* Locking shift decision */
  737.             xxls = 'N';       /* Need locking shift-out */
  738.             lsstate = 1;       /* and change to shifted state */
  739.             } else if (ebqflg) {   /* Not worth it */
  740.             xxss = ebq;       /* Use single shift */
  741.             }
  742.         }
  743.         rt = a7;        /* Replace character by 7-bit value */
  744.         } else if (ebqflg) {    /* 8th bit prefixing is on? */
  745.         xxss = ebq;        /* Insert single shift */
  746.         rt = a7;        /* Replace character by 7-bit value */
  747.         }
  748.  
  749.     } else if (lscapu) {        /* 7-bit character */
  750.  
  751.         if (lsstate) {        /* Comes while shifted out? */
  752.         x = lslook(0);        /* Yes, look ahead */
  753.         if (x || ebqflg == 0) {    /* Time to shift in. */
  754.             xxls = 'O';        /* Set shift-in code */
  755.             lsstate = 0;    /* Exit shifted state */
  756.         } else if (ebqflg) {    /* Not worth it, stay shifted out */
  757.             xxss = ebq;        /* Insert single shift */
  758.         }
  759.         }
  760.     }
  761.     /* If data character is significant to locking shift protocol... */
  762.     if (lscapu && (a7 == SO || a7 == SI || a7 == DLE))
  763.       xxdl = 'P';            /* Insert datalink escape */
  764.  
  765.     if ((a7 < SP) || (a7 == DEL)) { /* Do control prefixing if necessary */
  766.         xxcq = myctlq;        /* The prefix */
  767.         rt = ctl(rt);        /* Uncontrollify the character */
  768.     }
  769.     if (a7 == myctlq)        /* Always prefix the control prefix */
  770.       xxcq = myctlq;
  771.  
  772.     if ((rptflg) && (a7 == rptq))    /* If it's the repeat prefix, */
  773.       xxcq = myctlq;        /* prefix it if doing repeat counts */
  774.  
  775.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th-bit prefix */
  776.       xxcq = myctlq;        /* if doing 8th-bit prefixes */
  777.  
  778. /* Now construct the entire sequence */
  779.  
  780.     if (xxls) { *dp++ = myctlq; *dp++ = xxls; } /* Locking shift */
  781.     odp2 = dp;                    /* (Save this place) */
  782.     if (xxdl) { *dp++ = myctlq; *dp++ = xxdl; } /* Datalink escape */
  783.     if (xxrc) { *dp++ = rptq;   *dp++ = xxrc; } /* Repeat count */
  784.     if (xxss) { *dp++ = ebq; }            /* Single shift */
  785.     if (xxcq) { *dp++ = myctlq; }                /* Control prefix */
  786.     *dp++ = rt;            /* Finally, the character itself */
  787.  
  788.     if (rpt == 1) {            /* Exactly two copies? */
  789.         rpt = 0;
  790.         p2 = dp;            /* Save place temporarily */
  791.         for (p1 = odp2; p1 < p2; p1++) /* Copy the old chars over again */
  792.           *dp++ = *p1;
  793.         if ((p2-data) <= bufmax) odp = p2; /* Check packet bounds */
  794.     }
  795.     rt = rnext;            /* Next character is now current. */
  796.  
  797. /* Done encoding the character.  Now take care of packet buffer overflow. */
  798.  
  799.     if ((dp-data) >= bufmax) {    /* If too big, save some for next. */
  800.         size = (dp-data);        /* Calculate the size. */
  801.         *dp = '\0';            /* Mark the end. */
  802.         if ((dp-data) > bufmax) {    /* if packet is overfull */
  803.         /* copy the part that doesn't fit into the leftover buffer, */
  804.         /* taking care not to split a prefixed sequence. */
  805.         for (p1 = leftover, p2=odp; (*p1 = *p2) != '\0'; p1++,p2++)
  806.             ;
  807.         debug(F111,"getpkt leftover",leftover,size);
  808.         debug(F101," osize","",(odp-data));
  809.         size = (odp-data);    /* Return truncated packet. */
  810.         *odp = '\0';        /* Mark the new end */
  811.         }
  812.         t = rt; next = rnext;    /* save for next time */
  813.         return(size);
  814.     }
  815.     }                    /* Otherwise, keep filling. */
  816.  
  817.     size = (dp-data);            /* End of file */
  818.     *dp = '\0';                /* Mark the end of the data. */
  819.     debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
  820.     return(size);             /* return partially filled last packet. */
  821. }
  822.  
  823. /*  T I N I T  --  Initialize a transaction  */
  824.  
  825. int
  826. tinit() {
  827.     int x;
  828.  
  829. #ifndef NOCSETS
  830.     if (tcharset == TC_TRANSP) {    /* Character set translation */
  831.     rx = sx = NULL;            /* Transparent, no translation */
  832. #ifdef KANJI
  833.     } else if (tcharset == TC_JEUC) {
  834.     rx = sx = NULL;            /* Transparent, no translation */      
  835. #endif /* KANJI */
  836.     } else {                /* otherwise */
  837.     rx = xlr[tcharset][fcharset];    /* Input translation function */
  838.     sx = xls[tcharset][fcharset];    /* Output translation function */
  839.     }
  840.     debug(F101,"tinit tcharset","",tcharset);
  841.     debug(F101,"tinit fcharset","",fcharset);
  842. #ifdef COMMENT
  843.     debug(F101,"tinit sx   ","",sx);
  844.     debug(F101,"tinit rx   ","",rx);
  845. #endif /* COMMENT */
  846. #endif /* NOCSETS */
  847.     myinit[0] = '\0';            /* Haven't sent init string yet */
  848.     autopar = 0;            /* Automatic parity detection flag */
  849.     retrans = 0;            /* Packet retransmission count */
  850.     sndtyp = 0;                /* No previous packet */
  851.     xflg = 0;                /* Reset x-packet flag */
  852.     rqf = -1;                /* Reset 8th-bit-quote request flag */
  853.     memstr = 0;                /* Reset memory-string flag */
  854.     memptr = NULL;            /*  and pointer */
  855.     bctu = bctl = 1;            /* Reset block check type to 1 */
  856.     ebq = MYEBQ;            /* Reset 8th-bit quoting stuff */
  857.     ebqflg = 0;
  858.     if (savmod) {            /* If global file mode was saved, */
  859.         binary = savmod;        /*  restore it, */
  860.     savmod = 0;            /*  unsave it. */
  861.     }
  862.     pktnum = 0;                /* Initial packet number */
  863.     cxseen = czseen = discard = 0;    /* Reset interrupt flags */
  864.     *filnam = '\0';            /* Clear file name */
  865.     spktl = 0;                /* And its length */
  866.     nakstate = 0;            /* Assume not in a NAK'ing state */
  867.     numerrs = 0;            /* Transmission error counter */
  868.     if (server)             /* If acting as server, */
  869.       timint = srvtim;            /* Use server timeout interval. */
  870.     else                /* Otherwise */
  871.       timint = chktimo(rtimo,timef);    /* Begin by using local value */
  872.     spsiz = spsizr;            /* Initial send-packet size */
  873.     wslots = 1;                /* One window slot */
  874.     wslotn = 1;                /* No window negotiated yet */
  875.     winlo = 0;                /* Packet 0 is at window-low */
  876.     x = mksbuf(1);            /* Make a 1-slot send-packet buffer */
  877.     if (x < 0) return(x);
  878.     x = getsbuf(0);            /* Allocate first send-buffer. */
  879.     debug(F101,"tinit getsbuf","",x);
  880.     if (x < 0) return(x);
  881.     dumpsbuf();
  882.     x = mkrbuf(wslots);            /* & a 1-slot receive-packet buffer. */
  883.     if (x < 0) return(x);
  884.     what = W_NOTHING;            /* Doing nothing so far... */
  885.     lsstate = 0;            /* Initialize locking shift state */
  886.     return(0);
  887. }
  888.  
  889. VOID
  890. pktinit() {                /* Initialize packet sequence */
  891.     pktnum = 0;                /* number & window low. */
  892.     winlo = 0;
  893. }
  894.  
  895. /*  R I N I T  --  Respond to S or I packet  */
  896.  
  897. VOID
  898. rinit(d) CHAR *d; {
  899.     char *tp;
  900.     ztime(&tp);
  901.     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
  902.     if (binary)
  903.       tlog(F100,"Global file mode = binary","",0L);
  904.     else
  905.       tlog(F100,"Global file mode = text","",0L);
  906.     filcnt = 0;                /* Init file counter */
  907.     spar(d);
  908.     ack1(rpar());
  909. #ifdef datageneral
  910.     if ((local) && (!quiet))            /* Only do this if local & not quiet */
  911.         consta_mt();                    /* Start the asynch read task */
  912. #endif /* datageneral */
  913. }
  914.  
  915.  
  916. /*  R E S E T C  --  Reset per-transaction character counters */
  917.  
  918. VOID
  919. resetc() {
  920.     rptn = 0;                /* Repeat counts */
  921.     fsecs = flci = flco = 0L;        /* File chars in and out */
  922.     tfc = tlci = tlco = 0L;        /* Total file, line chars in & out */
  923. #ifdef COMMENT
  924.     fsize = -1L;            /* File size */
  925. #else
  926.     if (what != W_SEND)
  927.       fsize = -1L;
  928.     debug(F101,"resetc fsize","",fsize);
  929. #endif /* COMMENT */
  930.     timeouts = retrans = 0;        /* Timeouts, retransmissions */
  931.     spackets = rpackets = 0;        /* Packet counts out & in */
  932.     crunched = 0;            /* Crunched packets */
  933.     wmax = 1;                /* Maximum window size used */
  934. }
  935.  
  936. /*  S I N I T  --  Get & verify first file name, then send Send-Init packet */
  937. /*
  938.  Returns:
  939.    1 if send operation begins successfully
  940.    0 if send operation fails
  941. */
  942. #ifdef DYNAMIC
  943. char *cmargbuf = NULL;
  944. #else
  945. char cmargbuf[256];
  946. #endif /* DYNAMIC */
  947. char *cmargp[2];
  948.  
  949. int
  950. sinit() {
  951.     int x;                /* Worker int */
  952.     char *tp, *xp, *m;            /* Worker string pointers */
  953.  
  954.     filcnt = 0;                /* Initialize file counter */
  955.     sndsrc = nfils;            /* Source for filenames */
  956. #ifdef DYNAMIC
  957.     if (!cmargbuf && !(cmargbuf = malloc(256)))
  958.     fatal("sinit: no memory for cmargbuf");
  959. #endif /* DYNAMIC */
  960.     cmargbuf[0] = NUL;            /* Initialize name buffer */
  961.  
  962.     debug(F101,"sinit nfils","",nfils);
  963.     debug(F110,"sinit cmarg",cmarg,0);
  964.     debug(F110,"sinit cmarg2",cmarg2,0);
  965.     if (nfils == 0) {            /* Sending from stdin or memory. */
  966.     if ((cmarg2 != NULL) && (*cmarg2)) {
  967.         cmarg = cmarg2;        /* If F packet, "as-name" is used */
  968.         cmarg2 = "";        /* if provided */
  969.     } else cmarg = "stdin";        /* otherwise just use "stdin" */
  970.     strcpy(cmargbuf,cmarg);
  971.     cmargp[0] = cmargbuf;
  972.     cmargp[1] = "";
  973.     cmlist = cmargp;
  974.     nfils = 1;
  975.     }
  976. #ifdef COMMENT
  977.     if (nfils < 1) {            /* Filespec pointed to by cmarg */
  978.     if (nfils < 0) sndsrc = 1;
  979.     nfils = 1;            /* Change it to cmlist */
  980.     strcpy(cmargbuf,cmarg);        /* so we have a consistent way */
  981.     cmargp[0] = cmargbuf;        /* of going thru the file list. */
  982.     cmargp[1] = "";
  983.     cmlist = cmargp;
  984.     }
  985.  
  986. /* At this point, cmlist contains the list of filespecs to send */
  987.  
  988.     debug(F111,"sinit *cmlist",*cmlist,nfils);
  989.  
  990.     xp = *cmlist;            /* Save this for messages */
  991. #else
  992.     xp = (nfils < 0) ? cmarg : *cmlist;
  993. #endif
  994.  
  995.     x = gnfile();            /* Get first filename. */
  996.     m = NULL;                /* Error message pointer */
  997.     debug(F101,"sinit gnfil","",x);
  998.     switch (x) {
  999.       case -5: m = "Too many files match wildcard"; break;
  1000.       case -4: m = "Cancelled"; break;
  1001.       case -3: m = "Read access denied"; break;
  1002.       case -2: m = "File is not readable"; break;
  1003.       case -1: m = iswild(filnam) ? "No files match" : "File not found";
  1004.     break;
  1005.       case  0: m = "No filespec given!" ; break;
  1006.       default:
  1007.     break;
  1008.     }
  1009.     debug(F101,"sinit nfils","",nfils);
  1010.     debug(F110,"sinit filnam",filnam,0);
  1011.     debug(F110,"sinit cmdstr",cmdstr,0);
  1012.     if (x < 1) {            /* Didn't get a file. */
  1013.     if (server)            /* Doing GET command */
  1014.       errpkt((CHAR *)m);        /* so send Error packet. */
  1015.     else                /* Doing SEND command */
  1016.       screen(SCR_EM,0,0l,m);    /* so print message. */
  1017.     tlog(F110,xp,m,0L);        /* Make transaction log entry. */
  1018.     freerbuf(rseqtbl[0]);        /* Free the buffer the GET came in. */
  1019.     return(0);            /* Return failure code */
  1020.     }
  1021.     if (!local && !server) sleep(delay); /* Delay if requested */
  1022. #ifdef datageneral
  1023.     if ((local) && (!quiet))            /* Only do this if local & not quiet */
  1024.         consta_mt();                    /* Start the asynch read task */
  1025. #endif /* datageneral */
  1026.     freerbuf(rseqtbl[0]);        /* Free the buffer the GET came in. */
  1027.     sipkt('S');                /* Send the Send-Init packet. */
  1028.     ztime(&tp);                /* Get current date/time */
  1029.     tlog(F110,"Transaction begins",tp,0L); /* Make transaction log entry */
  1030.     debug(F111,"sinit ok",filnam,0);
  1031.     return(1);
  1032. }
  1033.  
  1034. int
  1035. #ifdef CK_ANSIC
  1036. sipkt(char c)                /* Send S or I packet. */
  1037. #else
  1038. sipkt(c) char c;
  1039. #endif
  1040. /* sipkt */ {
  1041.     CHAR *rp; int k;
  1042.     debug(F101,"sipkt pktnum","",pktnum);
  1043.     k = sseqtbl[pktnum];        /* Find slot for this packet */
  1044.     debug(F101,"sipkt k","",k);
  1045.     if (k < 0) {            /* No slot? */
  1046.     k = getsbuf(winlo = pktnum);    /* Make one. */
  1047.     debug(F101,"sipkt getsbuf","",k);    
  1048.     }
  1049.     ttflui();                /* Flush pending input. */
  1050.     rp = rpar();            /* Get protocol parameters. */
  1051.     return(spack(c,pktnum,(int)strlen((char *)rp),rp)); /* Send them. */
  1052. }
  1053.  
  1054. /*  X S I N I T  --  Retransmit S-packet  */
  1055. /*
  1056.   For use in the GET-SEND sequence, when we start to send, but receive another
  1057.   copy of the GET command because the receiver didn't get our S packet.
  1058.   This retransmits the S packet and frees the receive buffer for the ACK.
  1059.   The only reason this special case is necessary is that packet number zero
  1060.   is being re-used.
  1061. */
  1062. VOID
  1063. xsinit() {
  1064.     int k;    
  1065.     k = rseqtbl[0];
  1066.     debug(F101,"xsinit k","",k);
  1067.     if (k > -1)
  1068.       freerbuf(k);
  1069.     resend(0);
  1070. }        
  1071.  
  1072. /*  R C V F I L -- Receive a file  */
  1073.  
  1074. /*
  1075.   Incoming filename is in data field of F packet.
  1076.   This function decodes it into the srvcmd buffer, substituting an
  1077.   alternate "as-name", if one was given.
  1078.   Then it does any requested transformations (like converting to
  1079.   lowercase), and finally if a file of the same name already exists, 
  1080.   takes the desired collision action.
  1081. */
  1082. #ifdef pdp11
  1083. #define XNAMLEN 65
  1084. #else
  1085. #define XNAMLEN 256
  1086. #endif /* pdp11 */
  1087.  
  1088. int
  1089. rcvfil(n) char *n; {
  1090.     char xname[XNAMLEN], *xp;        /* Buffer for constructing name */
  1091. #ifdef DTILDE
  1092.     char *dirp, *tilde_expand();
  1093. #endif /* DTILDE */
  1094.  
  1095.     lsstate = 0;            /* Cancel locking-shift state */
  1096.     srvptr = srvcmd;            /* Decode file name from packet. */
  1097.     decode(rdatap,putsrv,0);        /* Don't xlate charsets. */
  1098.     if (*srvcmd == '\0')        /* Watch out for null F packet. */
  1099.       strcpy((char *)srvcmd,"NONAME");
  1100. #ifdef DTILDE
  1101.     dirp = tilde_expand((char *)srvcmd); /* Expand tilde, if any. */
  1102.     if (*dirp != '\0') strcpy((char *)srvcmd,dirp);
  1103. #endif /* DTILDE */
  1104.     screen(SCR_FN,0,0l,(char *)srvcmd);    /* Put it on screen if local */
  1105.     debug(F110,"rcvfil",(char *)srvcmd,0); /* Debug log entry */
  1106.     debug(F101,"rcvfil cmarg2","",cmarg2);
  1107.     tlog(F110,"Receiving",(char *)srvcmd,0L); /* Transaction log entry */
  1108.     if (cmarg2 != NULL) {               /* Check for alternate name */
  1109.         if (*cmarg2 != '\0') {
  1110.             strcpy((char *)srvcmd,cmarg2); /* Got one, use it. */
  1111.         }
  1112.     } else cmarg2 = "";
  1113. /*
  1114.   NOTE: Much of this code should be moved to opena(), where the file is
  1115.   actually opened, AFTER we have received the Attribute packet(s).  That
  1116.   way, if the file is mail, or is being sent to the printer, we don't have
  1117.   to fuss with collision options, etc, but instead we just pipe the data
  1118.   straight into lpr or mail (in UNIX anyway), and then we can also have
  1119.   nice subject lines for mail messages by using whatever is in the file
  1120.   header packet data field, whether it's a legal filename or not.
  1121. */
  1122.     if ((int)strlen((char *)srvcmd) > XNAMLEN) /* Watch out for overflow */
  1123.       *(srvcmd + XNAMLEN - 1) = NUL;
  1124.  
  1125.     xp = xname;                /* OK to proceed. */
  1126.     if (fncnv && !*cmarg2)
  1127.       zrtol((char *)srvcmd,xp);        /* convert name to local form */
  1128.     else                /* otherwise, */
  1129.       strcpy(xname,(char *)srvcmd);    /* use it literally */
  1130.     cmarg2 = "";            /* Remove alternate name */
  1131.     debug(F110,"rcvfil as",xname,0);
  1132.  
  1133. #ifdef COMMENT                /* Old code... */
  1134.     if (warn) {                /* File collision avoidance? */
  1135.     if (zchki(xname) != -1) {    /* Yes, file exists? */
  1136.         znewn(xname,&xp);        /* Yes, make new name. */
  1137.         strcpy(xname,xp);
  1138.         debug(F110," exists, new name ",xname,0);
  1139.         }
  1140.     }
  1141. #endif /* COMMENT */
  1142.  
  1143. /* Filename collision action section. */
  1144.  
  1145.     if (
  1146. #ifdef UNIX
  1147.     strcmp(xname,"/dev/null") &&    /* It's not the null device? */
  1148. #endif /* UNIX */
  1149.     (zchki(xname) != -1)        /* File of same name exists? */
  1150.     ) {                
  1151.     debug(F111,"rcvfil exists",xname,fncact);
  1152.     switch (fncact) {        /* Yes, do what user said. */
  1153.       case XYFX_A:            /* Append */
  1154.         debug(F100,"rcvfil append","",0);
  1155.         break;
  1156.       case XYFX_Q:            /* Query (Ask) */
  1157.         break;            /* not yet implemented */
  1158.       case XYFX_B:            /* Backup (rename old file) */
  1159.         znewn(xname,&xp);        /* Get new unique name */
  1160.         debug(F110,"rcvfil backup",xname,0);
  1161.         debug(F110,"rcvfil backup",xp,0);
  1162.         if (zrename(xname,xp) < 0) {
  1163.         debug(F110,"rcvfil rename fails",xname,0);
  1164.         return(0);
  1165.         }
  1166.         break;
  1167.       case XYFX_D:            /* Discard (refuse new file) */
  1168.         discard = 1;
  1169.         debug(F101,"rcvfil discard","",discard);
  1170.         break;            /* not yet implemented */
  1171.       case XYFX_R:            /* Rename new file */
  1172.         znewn(xname,&xp);        /* Make new name. */
  1173.         strcpy(xname,xp);
  1174.         debug(F110,"rcvfil rename",xname,0);
  1175.       case XYFX_X:            /* Replace old file */
  1176.         debug(F100,"rcvfil overwrite","",0);
  1177.         break;
  1178.       case XYFX_U:            /* Refuse if older */
  1179.         debug(F100,"rcvfil update","",0);
  1180.         break;            /* Not here, we don't have */
  1181.                     /* the attribute packet yet. */
  1182.       default:
  1183.         debug(F101,"rcvfil bad collision action","",fncact);
  1184.         break;
  1185.     }
  1186.     }
  1187.     debug(F110,"rcvfil: xname",xname,0);
  1188.     screen(SCR_AN,0,0l,xname);        /* Display it */
  1189.     strcpy(n,xname);            /* Return pointer to actual name. */
  1190.  
  1191. #ifndef NOICP
  1192. #ifndef MAC
  1193. /* Why not Mac? */
  1194.     strcpy(fspec,xname);        /* Here too for \v(filespec) */
  1195. #endif /* MAC */
  1196. #endif /* NOICP */
  1197.     debug(F110,"rcvfil: n",n,0);
  1198.     ffc = 0L;                /* Init per-file counters */
  1199.     fsecs = gtimer();            /* Time this file started */
  1200.     filcnt++;
  1201.     intmsg(filcnt);
  1202.     return(1);                /* Always succeeds */
  1203. }
  1204.  
  1205.  
  1206. /*  R E O F  --  Receive End Of File packet for incoming file */
  1207.  
  1208. /*
  1209.   Closes the received file.
  1210.   Returns:
  1211.     0 on success.
  1212.    -1 if file could not be closed.
  1213.     2 if disposition was mail, mail was sent, but temp file not deleted.
  1214.     3 if disposition was print, file was printed, but not deleted.
  1215.    -2 if disposition was mail and mail could not be sent
  1216.    -3 if disposition was print and file could not be printed
  1217. */
  1218. int
  1219. reof(f,yy) char *f; struct zattr *yy; {
  1220.     int x;
  1221.     char *p;
  1222.     char c;
  1223.  
  1224.     debug(F111,"reof fncact",f,fncact);
  1225.     debug(F101,"reof discard","",discard);
  1226.     success = 1;            /* Assume status is OK */
  1227.     lsstate = 0;            /* Cancel locking-shift state */
  1228.     if (
  1229. #ifdef COMMENT
  1230. /*
  1231.   If the discard flag is set, for whatever reason, we discard it, right?
  1232. */
  1233.     (fncact == XYFX_D || fncact == XYFX_U) &&
  1234. #endif /* COMMENT */
  1235.     discard != 0) {       /* SET FILE COLLISION DISCARD or UPDATE */
  1236.  
  1237.     debug(F101,"reof discarding","",0);
  1238.     discard = 0;            /* We never opened it, */
  1239.     return(0);            /* so we won't close it. */
  1240.     }
  1241.     if (cxseen == 0) cxseen = (*rdatap == 'D');    /* Got cancel directive? */
  1242.     success = (cxseen || czseen) ? 0 : 1; /* Set SUCCESS flag appropriately */
  1243.     x = clsof(cxseen || czseen);    /* Close the file (resets cxseen) */
  1244.     if (x < 0) success = 0;        /* If failure to close, FAIL */
  1245.     if (atcapu) zstime(f,yy,0);        /* Set file creation date */
  1246.  
  1247. /* Handle dispositions from attribute packet... */
  1248.  
  1249. #ifndef NOFRILLS
  1250.     if (yy->disp.len != 0) {
  1251.     p = yy->disp.val;
  1252.     c = *p++;
  1253.     if (c == 'M') {            /* Mail to user. */
  1254.         x = zmail(p,filnam);    /* Do the system's mail command */
  1255.         if (x < 0) success = 0;    /* Remember status */
  1256.         tlog(F110,"mailed",filnam,0L);
  1257.         tlog(F110," to",p,0L);
  1258.         zdelet(filnam);        /* Delete the file */
  1259.     } else if (c == 'P') {        /* Print the file. */
  1260.         x = zprint(p,filnam);    /* Do the system's print command */
  1261.         if (x < 0) success = 0;    /* Remember status */
  1262.         tlog(F110,"printed",filnam,0L);
  1263.         tlog(F110," with options",p,0L);
  1264. #ifndef VMS
  1265.         if (zdelet(filnam) && x == 0) x = 3; /* Delete the file */
  1266. #endif /* VMS */
  1267.     }
  1268.     }
  1269. #endif /* NOFRILLS */
  1270.     debug(F101,"reof returns","",x);
  1271.     *filnam = '\0';
  1272.     return(x);
  1273. }
  1274.  
  1275. /*  R E O T  --  Receive End Of Transaction  */
  1276.  
  1277. VOID
  1278. reot() {
  1279.     cxseen = czseen = discard = 0;    /* Reset interruption flags */
  1280.     tstats();
  1281. }
  1282.  
  1283. /*  S F I L E -- Send File header or teXt header packet  */
  1284.  
  1285. /*  Call with x nonzero for X packet, zero for F packet  */
  1286. /*  Returns 1 on success, 0 on failure                   */
  1287.  
  1288. int
  1289. sfile(x) int x; {
  1290. #ifdef pdp11
  1291. #define PKTNL 64
  1292. #else
  1293. #define PKTNL 256
  1294. #endif /* pdp11 */
  1295.     char pktnam[PKTNL+1];        /* Local copy of name */
  1296.     char *s;
  1297.  
  1298.     lsstate = 0;            /* Cancel locking-shift state */
  1299.     if (nxtpkt() < 0) return(0);    /* Bump packet number, get buffer */
  1300.     if (x == 0) {            /* F-Packet setup */
  1301.  
  1302.         if (*cmarg2 != '\0') {        /* If we have a send-as name, */
  1303.         strncpy(pktnam,cmarg2,PKTNL); /* copy it literally, */
  1304.         cmarg2 = "";        /* and blank it out for next time. */
  1305.         } else {            /* Otherwise use actual file name: */
  1306.         if (fncnv) {        /* If converting names, */
  1307.             zltor(filnam,pktnam);    /* convert it to common form, */
  1308.         } else {            /* otherwise, */
  1309.             strncpy(pktnam,filnam,PKTNL); /* copy it literally. */
  1310.             }
  1311.         }
  1312.         debug(F110,"sfile",filnam,0);    /* Log debugging info */
  1313.         debug(F110," pktnam",pktnam,0);
  1314.         if (openi(filnam) == 0)     /* Try to open the file */
  1315.       return(0);         
  1316.         s = pktnam;            /* Name for packet data field */
  1317.  
  1318.     } else {                /* X-packet setup */
  1319.  
  1320.         debug(F110,"sxpack",cmdstr,0);    /* Log debugging info */
  1321.         s = cmdstr;            /* Name for data field */
  1322.     }
  1323.  
  1324.     encstr((CHAR *)s);            /* Encode the name into encbuf[]. */
  1325.                     /* Send the F or X packet */
  1326.     spack((char) (x ? 'X' : 'F'), pktnum, size, encbuf+7);
  1327.  
  1328.     if (x == 0) {            /* Display for F packet */
  1329.         if (displa) {            /* Screen */
  1330.         screen(SCR_FN,'F',(long)pktnum,filnam);
  1331.         screen(SCR_AN,0,0l,pktnam);
  1332.         screen(SCR_FS,0,fsize,"");
  1333.         }
  1334.         tlog(F110,"Sending",filnam,0L);    /* Transaction log entry */
  1335.         tlog(F110," as",pktnam,0L);
  1336.     if (binary) {            /* Log file mode in transaction log */
  1337.         tlog(F101," mode: binary","",(long) binary);
  1338.     } else {            /* If text mode, check character set */
  1339.         tlog(F100," mode: text","",0L);
  1340. #ifndef NOCSETS
  1341.         tlog(F110," file character set",fcsinfo[fcharset].name,0L);
  1342.         if (tcharset == TC_TRANSP)
  1343.           tlog(F110," xfer character set","transparent",0L);
  1344.         else
  1345.           tlog(F110," xfer character set",tcsinfo[tcharset].name,0L);
  1346. #endif /* NOCSETS */
  1347.     }
  1348.     } else {                /* Display for X-packet */
  1349.  
  1350.         screen(SCR_XD,'X',(long)pktnum,cmdstr);    /* Screen */
  1351.         tlog(F110,"Sending from:",cmdstr,0L);    /* Transaction log */
  1352.     }
  1353.     intmsg(++filcnt);            /* Count file, give interrupt msg */
  1354.     first = 1;                /* Init file character lookahead. */
  1355.     ffc = 0L;                /* Init file character counter. */
  1356.     fsecs = gtimer();            /* Time this file started */
  1357.     debug(F101,"SFILE fsecs","",fsecs);
  1358.     return(1);
  1359. }
  1360.  
  1361. /*  S D A T A -- Send a data packet */
  1362.  
  1363. /*
  1364.   Returns -1 if no data to send (end of file).  If there is data, a data
  1365.   packet is sent, and sdata() returns 1.
  1366.  
  1367.   For window size greater than 1, keep sending data packets until window
  1368.   is full or characters start to appear from the other Kermit, whichever
  1369.   happens first.
  1370.  
  1371.   In the windowing case, when there is no more data left to send (or when
  1372.   sending has been interrupted), sdata() does nothing and returns 0 each time
  1373.   it is called until the current packet number catches up to the last data
  1374.   packet that was sent.
  1375. */
  1376.  
  1377. int
  1378. sdata() {
  1379.     int i, x, len;
  1380.     
  1381.     debug(F101,"sdata entry, first","",first);
  1382.     debug(F101," drain","",drain);
  1383.  
  1384. /* The "drain" flag is used with window size > 1.  It means we have sent  */
  1385. /* our last data packet.  If called and drain is not zero, then we return */
  1386. /* 0 as if we had sent an empty data packet, until all data packets have  */
  1387. /* been ACK'd, then then we can finally return -1 indicating EOF, so that */
  1388. /* the protocol can switch to seof state.  This is a kludge, but at least */
  1389. /* it's localized...  */
  1390.  
  1391.     if (first == 1) drain = 0;        /* Start of file, init drain flag. */
  1392.  
  1393.     if (drain) {            /* If draining... */
  1394.     debug(F101,"sdata draining, winlo","",winlo);
  1395.     if (winlo == pktnum)        /* If all data packets are ACK'd */
  1396.       return(-1);            /* return EOF indication */
  1397.     else                /* otherwise */
  1398.       return(0);            /* pretend we sent a data packet. */
  1399.     }
  1400.     debug(F101,"sdata sbufnum","",sbufnum);
  1401.     for (i = sbufnum; i > 0; i--) {
  1402.         debug(F101,"sdata countdown","",i);
  1403.     x = nxtpkt();            /* Get next pkt number and buffer */
  1404.     debug(F101,"sdata packet","",pktnum);
  1405.     if (x < 0) return(0);
  1406. /***    dumpsbuf(); */
  1407.     if (cxseen || czseen) {        /* If interrupted, done. */
  1408.         if (wslots > 1) {
  1409.         drain = 1;
  1410.         debug(F101,"sdata cx/zseen, drain","",cxseen);
  1411.         return(0);
  1412.         } else {
  1413.         return(-1);
  1414.         }
  1415.     }
  1416. #ifdef COMMENT
  1417.     if (spsiz > 94)            /* Fill the packet's data buffer */
  1418.       len = getpkt(spsiz-bctl-6,1);    /* long packet */
  1419.     else                /*  or */
  1420.       len = getpkt(spsiz-bctl-3,1);    /* short packet */
  1421. #else
  1422.     len = getpkt(spsiz,1);
  1423. #endif /* COMMENT */
  1424.     if (len == 0) {            /* Done if no data. */
  1425.         if (pktnum == winlo) return(-1);
  1426.         drain = 1;            /* But can't return -1 until all */
  1427.         debug(F101,"sdata eof, drain","",drain);
  1428.         return(0);            /* ACKs are drained. */
  1429.     }
  1430.     spack('D',pktnum,len,data);    /* Send the data packet. */
  1431.     x = ttchk();            /* Peek at input buffer. */
  1432.     debug(F101,"sdata ttchk","",x);    /* ACKs waiting, maybe?  */
  1433.     if (x) return(1);        /* Yes, stop sending data packets */
  1434.     }                    /* and go try to read the ACKs. */
  1435.     return(1);
  1436. }
  1437.  
  1438.  
  1439. /*  S E O F -- Send an End-Of-File packet */
  1440.  
  1441. /*  Call with a string pointer to character to put in the data field, */
  1442. /*  or else a null pointer or "" for no data.  */
  1443.  
  1444. /*
  1445.   There are two "send-eof" functions.  seof() is used to send the normal eof
  1446.   packet at the end of a file's data (even if the file has no data), or when
  1447.   a file transfer is interrupted.  sxeof() is used to send an EOF packet that
  1448.   occurs because of attribute refusal.  The difference is purely a matter of
  1449.   buffer allocation and packet sequence number management.  Both functions
  1450.   act as "front ends" to the common send-eof function, szeof().
  1451. */
  1452.  
  1453. /* Code common to both seof() and sxeof() */
  1454.  
  1455. int
  1456. szeof(s) CHAR *s; {
  1457.     lsstate = 0;            /* Cancel locking-shift state */
  1458.     if ((s != NULL) && (*s != '\0')) {
  1459.     spack('Z',pktnum,1,s);
  1460.     tlog(F100," *** interrupted, sending discard request","",0L);
  1461.     } else {
  1462.     spack('Z',pktnum,0,(CHAR *)"");
  1463.     }
  1464.     discard = 0;            /* Turn off per-file discard flag */
  1465.     return(0);
  1466. }
  1467.  
  1468. int
  1469. seof(s) CHAR *s; {
  1470.  
  1471. /*
  1472.   ckcpro.w, before calling seof(), sets window size back to 1 and then calls
  1473.   window(), which clears out the old buffers.  This is OK because the final
  1474.   data packet for the file has been ACK'd.  However, sdata() has already
  1475.   called nxtpkt(), which set the new value of pktnum which seof() will use.
  1476.   So all we need to do here is is allocate a new send-buffer.
  1477. */
  1478.     if (getsbuf(pktnum) < 0) {    /* Get a buffer for packet n */
  1479.     debug(F101,"seof can't get s-buffer","",pktnum);
  1480.     return(-1);
  1481.     }
  1482.     return(szeof(s));
  1483. }
  1484.  
  1485. /*
  1486.   Version of seof() to be called when sdata() has not been called before.  The
  1487.   difference is that this version calls nxtpkt() to allocate a send-buffer and
  1488.   get the next packet number.
  1489. */
  1490. int
  1491. sxeof(s) CHAR *s; {
  1492.     int x;
  1493.     x = nxtpkt();            /* Get next pkt number and buffer */
  1494.     if (x < 0)
  1495.       debug(F101,"sxeof nxtpkt fails","",pktnum);
  1496.     else
  1497.       debug(F101,"sxeof packet","",pktnum);
  1498.     return(szeof(s));
  1499. }
  1500.  
  1501. /*  S E O T -- Send an End-Of-Transaction packet */
  1502.  
  1503. int
  1504. seot() {
  1505.     if (nxtpkt() < 0) return(-1);    /* Bump packet number, get buffer */
  1506.     spack('B',pktnum,0,(CHAR *)"");    /* Send the EOT packet */
  1507.     cxseen = czseen = discard = 0;    /* Reset interruption flags */
  1508.     tstats();                /* Log timing info */
  1509.     return(0);
  1510. }
  1511.  
  1512. /*   R P A R -- Fill the data array with my send-init parameters  */
  1513.  
  1514.  
  1515. CHAR dada[20];                /* Use this instead of data[]. */
  1516.                     /* To avoid some kind of wierd */
  1517.                     /* addressing foulup in spack()... */
  1518.                     /* (which might be fixed now...) */
  1519.  
  1520. CHAR *
  1521. rpar() {
  1522.     if (rpsiz > MAXPACK)        /* Biggest normal packet I want. */
  1523.       dada[0] = tochar(MAXPACK);    /* If > 94, use 94, but specify */
  1524.     else                /* extended packet length below... */
  1525.       dada[0] = tochar(rpsiz);        /* else use what the user said. */
  1526.     dada[1] = tochar(chktimo(pkttim,0)); /* When I want to be timed out */
  1527.     dada[2] = tochar(mypadn);        /* How much padding I need (none) */
  1528.     dada[3] = ctl(mypadc);        /* Padding character I want */
  1529.     dada[4] = tochar(eol);        /* End-Of-Line character I want */
  1530.     dada[5] = '#';            /* Control-Quote character I send */
  1531.     switch (rqf) {            /* 8th-bit prefix */
  1532.     case -1:
  1533.     case  1: if (parity) ebq = sq = '&'; break;
  1534.     case  0:
  1535.     case  2: break;
  1536.     }
  1537.     debug(F000,"rpar 8bq sq","",sq);
  1538.     debug(F000,"rpar 8bq ebq","",ebq);
  1539.     if (lscapu == 2)            /* LOCKING-SHIFT FORCED */
  1540.       dada[6] = 'N';            /* means no single-shift */
  1541.     else
  1542.       dada[6] = sq;
  1543.     dada[7] = (bctr == 4) ? 'B' : bctr + '0'; /* Block check type */
  1544.     if (rptflg)                /* Run length encoding */
  1545.         dada[8] = rptq;            /* If receiving, agree. */
  1546.     else
  1547.         dada[8] = '~';         
  1548.     /* CAPAS mask */
  1549.     dada[9] = tochar((lscapr ? lscapb : 0) | /* Locking shifts */
  1550.              (atcapr ? atcapb : 0) | /* Attribute packets */
  1551.              (lpcapr ? lpcapb : 0) | /* Long packets */
  1552.              (swcapr ? swcapb : 0)); /* Sliding windows */
  1553.     dada[10] = tochar(swcapr ? wslotr : 1);  /* Window size */
  1554.     rpsiz = urpsiz - 1;            /* Long packets ... */
  1555.     dada[11] = tochar(rpsiz / 95);    /* Long packet size, big part */
  1556.     dada[12] = tochar(rpsiz % 95);    /* Long packet size, little part */
  1557.     dada[13] = '\0';            /* Terminate the init string */
  1558. #ifdef DEBUG
  1559.     if (deblog) {
  1560.     debug(F110,"rpar",dada,0);
  1561.     rdebu(dada,(int)strlen((char *)dada));
  1562.     }
  1563. #endif /* DEBUG */
  1564.     strcpy((char *)myinit,(char *)dada);
  1565.     return(dada);            /* Return pointer to string. */
  1566. }
  1567.  
  1568. int
  1569. spar(s) CHAR *s; {            /* Set parameters */
  1570.     int x, y, lpsiz;
  1571.  
  1572.     debug(F110,"entering spar",s,0);
  1573.  
  1574.     s--;                /* Line up with field numbers. */
  1575.  
  1576. /* Limit on size of outbound packets */
  1577.     x = (rln >= 1) ? xunchar(s[1]) : 80;
  1578.     lpsiz = spsizr;            /* Remember what they SET. */
  1579.     if (spsizf) {            /* SET-command override? */
  1580.     if (x < spsizr) spsiz = x;    /* Ignore LEN unless smaller */
  1581.     } else {                /* otherwise */
  1582.     spsiz = (x < 10) ? 80 : x;    /* believe them if reasonable */
  1583.     }
  1584.     spmax = spsiz;            /* Remember maximum size */
  1585.  
  1586. /* Timeout on inbound packets */
  1587.     if (timef) {
  1588.     timint = rtimo;            /* SET SEND TIMEOUT value overrides */
  1589.     } else {                /* Otherwise use requested value, */
  1590.     x = (rln >= 2) ? xunchar(s[2]) : rtimo; /* if it is legal. */
  1591.     timint = (x < 0) ? rtimo : x;
  1592.     }
  1593.     timint = chktimo(timint,timef);    /* Adjust if necessary */
  1594.  
  1595. /* Outbound Padding */
  1596.     npad = 0; padch = '\0';
  1597.     if (rln >= 3) {
  1598.     npad = xunchar(s[3]);
  1599.     if (rln >= 4) padch = ctl(s[4]); else padch = 0;
  1600.     }
  1601.     if (npad) {
  1602.     int i;
  1603.     for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
  1604.     }
  1605.  
  1606. /* Outbound Packet Terminator */
  1607.     seol = (rln >= 5) ? xunchar(s[5]) : CR;
  1608.     if ((seol < 2) || (seol > 31)) seol = CR;
  1609.  
  1610. /* Control prefix */
  1611.     x = (rln >= 6) ? s[6] : '#';
  1612.     myctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
  1613.  
  1614. /* 8th-bit prefix */
  1615.     rq = (rln >= 7) ? s[7] : 0;
  1616.     if (rq == 'Y') rqf = 1;
  1617.       else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
  1618.         else rqf = 0;
  1619.     debug(F000,"spar 8bq rq","",rq);
  1620.     debug(F000,"spar 8bq sq","",sq);
  1621.     debug(F000,"spar 8bq ebq","",ebq);
  1622.     debug(F101,"spar 8bq rqf","",rqf);
  1623.     switch (rqf) {
  1624.     case 0: ebqflg = 0; break;
  1625.     case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
  1626.     case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
  1627.     }
  1628.     if (lscapu == 2) {     /* No single-shifts if LOCKING-SHIFT FORCED */
  1629.     ebqflg = 0;
  1630.     ebq = 'N';
  1631.     }
  1632.  
  1633. /* Block check */
  1634.     x = 1;
  1635.     if (rln >= 8) {
  1636.     if (s[8] == 'B') x = 4;
  1637.     else x = s[8] - '0';
  1638.     if ((x < 1) || (x > 4)) x = 1;
  1639.     }
  1640.     bctr = x;
  1641.  
  1642. /* Repeat prefix */
  1643.     if (rln >= 9) {
  1644.     rptq = s[9]; 
  1645.     rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
  1646.     } else rptflg = 0;
  1647.  
  1648. /* Capabilities */
  1649.     atcapu = lpcapu = swcapu = 0;    /* Assume none of these */
  1650.     if (lscapu != 2) lscapu = 0;    /* Assume no LS unless forced. */
  1651.     y = 11;                /* Position of next field, if any */
  1652.     if (rln >= 10) {
  1653.         x = xunchar(s[10]);
  1654.     debug(F101,"spar capas","",x);
  1655.         atcapu = (x & atcapb) && atcapr;
  1656.     lpcapu = (x & lpcapb) && lpcapr;
  1657.     swcapu = (x & swcapb) && swcapr;
  1658.     debug(F101,"spar lscapu","",lscapu);
  1659.     debug(F101,"spar lscapr","",lscapr);
  1660.     debug(F101,"spar ebqflg","",ebqflg);
  1661.     if (lscapu != 2) lscapu = ((x & lscapb) && lscapr && ebqflg) ? 1 : 0;
  1662.     debug(F101,"spar swcapr","",swcapr);
  1663.     debug(F101,"spar swcapu","",swcapu);
  1664.     debug(F101,"spar lscapu","",lscapu);
  1665.     for (y = 10; (xunchar(s[y]) & 1) && (rln >= y); y++) ;
  1666.     debug(F101,"spar y","",y);
  1667.     }
  1668.  
  1669. /* Long Packets */
  1670.     debug(F101,"spar lpcapu","",lpcapu);
  1671.     if (lpcapu) {
  1672.         if (rln > y+1) {
  1673.         x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
  1674.         debug(F101,"spar lp len","",x);
  1675.         if (spsizf) {        /* If overriding negotiations */
  1676.         spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
  1677.         } else {                     /* otherwise */
  1678.         spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
  1679.         }
  1680.         if (spsiz < 10) spsiz = 80;    /* Be defensive... */
  1681.     }
  1682.     }
  1683.     /* (PWP) save current send packet size for optimal packet size calcs */
  1684.     spmax = spsiz;
  1685.     debug(F101,"spar lp spmax","",spmax);
  1686.     timint = chktimo(timint,timef);    /* Recalculate the packet timeout! */
  1687.     
  1688. /* Sliding Windows... */
  1689.  
  1690.     if (swcapr) {            /* Only if requested... */
  1691.         if (rln > y) {            /* See what other Kermit says */
  1692.         x = xunchar(s[y+1]);
  1693.         debug(F101,"spar window","",x);
  1694.         wslotn = (x > MAXWS) ? MAXWS : x;
  1695. /*
  1696.   wslotn = negotiated size (from other Kermit's S or I packet).
  1697.   wslotr = requested window size (from this Kermit's SET WINDOW command).
  1698. */
  1699.         if (wslotn > wslotr)    /* Use the smaller of the two */
  1700.           wslotn = wslotr;
  1701.         if (wslotn < 1)        /* Watch out for bad negotiation */
  1702.           wslotn = 1;
  1703.         if (wslotn > 1)
  1704.           swcapu = 1; /* We do windows... */
  1705.         debug(F101,"spar window after adjustment","",x);
  1706.     } else {            /* No window size specified. */
  1707.         wslotn = 1;            /* We don't do windows... */
  1708.         debug(F101,"spar window","",x);
  1709.         swcapu = 0;
  1710.         debug(F101,"spar no windows","",wslotn);
  1711.     }
  1712.     }
  1713.  
  1714. /* Now recalculate packet length based on number of windows.   */
  1715. /* The nogotiated number of window slots will be allocated,    */
  1716. /* and the maximum packet length will be reduced if necessary, */
  1717. /* so that a windowful of packets can fit in the big buffer.   */
  1718.  
  1719.     if (wslotn > 1) {            /* Shrink to fit... */
  1720.     x = adjpkl(spsiz,wslotn,bigsbsiz);
  1721.     if (x < spsiz) {
  1722.         spsiz = spmax = x;
  1723.         debug(F101,"spar sending, redefine spsiz","",spsiz);
  1724.     }
  1725.     }
  1726.  
  1727. /* Record parameters in debug log */
  1728. #ifdef DEBUG
  1729.     if (deblog) sdebu(rln);
  1730. #endif /* DEBUG */
  1731.     numerrs = 0;            /* Start counting errors here. */
  1732.     return(0);
  1733. }
  1734.  
  1735. /*  G N F I L E  --  Get name of next file to send  */
  1736. /*
  1737.   Expects global sndsrc to be:
  1738.    -1: next filename to be obtained by calling znext().
  1739.     0: no next file name
  1740.     1: (or greater) next filename to be obtained from **cmlist.
  1741.   Returns:
  1742.     1, with name of next file in filnam.
  1743.     0, no more files, with filnam set to empty string.
  1744.    -1, file not found
  1745.    -2, file is not readable
  1746.    -3, read access denied
  1747.    -4, cancelled
  1748.    -5, too many files match wildcard
  1749. */
  1750.  
  1751. int
  1752. gnfile() {
  1753.     int x; long y;
  1754.     int retcode = 0;
  1755.  
  1756.     debug(F101,"gnfile sndsrc","",sndsrc);
  1757.     fsize = -1L;            /* Initialize file size */
  1758.     if (sndsrc == 0) {            /* It's not really a file */
  1759.     if (nfils > 0) {        /* It's a pipe, or stdin */
  1760.         strcpy(filnam, *cmlist);    /* Copy its "name" */
  1761.         nfils = 0;            /* There is no next file */
  1762.         return(1);            /* OK this time */
  1763.     } else return(0);        /* but not next time */
  1764.     }
  1765.  
  1766. /* If file group interruption (C-Z) occurred, fail.  */
  1767.  
  1768.     if (czseen) {
  1769.     tlog(F100,"Transaction cancelled","",0L);
  1770.         debug(F100,"gnfile czseen","",0);
  1771.     return(-4);
  1772.     }
  1773.  
  1774. /* Loop through file list till we find a readable, sendable file */
  1775.  
  1776.     y = -1L;                /* Loop exit (file size) variable */
  1777.     while (y < 0L) {            /* Keep trying till we get one... */
  1778.     if (sndsrc > 0) {        /* File list in cmlist */
  1779.         debug(F101,"gnfile nfils","",nfils);
  1780.         if (nfils-- > 0) {        /* Still some left? */
  1781.         strcpy(filnam,*cmlist++);
  1782.         debug(F111,"gnfile cmlist filnam",filnam,nfils);
  1783.         if (!clfils) {        /* Expand only if not from cmdline */
  1784.             x = zxpand(filnam);
  1785.             debug(F101,"gnfile zxpand","",x);
  1786.             if (x == 1) {
  1787.             znext(filnam);
  1788.             goto gotnam;
  1789.             }
  1790.             if (x == 0) {
  1791.             retcode = -1; /* None match */
  1792.             continue;
  1793.             }
  1794.             if (x < 0) return(-5); /* Too many to expand */
  1795.             sndsrc = -1;    /* Change send-source to znext() */
  1796.         }
  1797.         } else {            /* We're out of files. */
  1798.         debug(F101,"gnfile done","",nfils);
  1799.         *filnam = '\0';
  1800.         return(retcode);
  1801.         }
  1802.     }
  1803.  
  1804. /* Otherwise, step to next element of internal wildcard expansion list. */
  1805.  
  1806.     if (sndsrc < 0) {
  1807.         x = znext(filnam);
  1808.         debug(F111,"gnfile znext",filnam,x);
  1809.         if (x == 0) {        /* If no more, */
  1810.         sndsrc = 1;        /* go back to list */
  1811.         continue;
  1812.         }
  1813.     }
  1814.  
  1815. /* Get here with a filename. */
  1816.  
  1817. gotnam:
  1818.     if (sndsrc) {
  1819.         y = zchki(filnam);        /* Check if file readable */
  1820.         retcode = (int) y;        /* Possible return code */
  1821.         if (y == -1L) {        /* If not found */
  1822.         debug(F110,"gnfile skipping:",filnam,0);
  1823.         tlog(F111,filnam,"not sent, reason",(long)y);
  1824.         screen(SCR_ST,ST_SKIP,0l,filnam);
  1825.         continue;
  1826.         } else if (y < 0) {
  1827.         continue;
  1828.         } else {
  1829.         fsize = y;
  1830.         return(1);
  1831.         }
  1832.     } else return(1);        /* sndsrc is 0... */
  1833.     }
  1834.     *filnam = '\0';            /* Should never get here */
  1835.     return(0);
  1836. }
  1837.  
  1838.  
  1839. /*  S N D H L P  --  Routine to send builtin help  */
  1840.  
  1841. int
  1842. sndhlp() {
  1843. #ifndef NOSERVER
  1844.     nfils = 0;                /* No files, no lists. */
  1845.     xflg = 1;                /* Flag we must send X packet. */
  1846.     strcpy(cmdstr,"help text");        /* Data for X packet. */
  1847.     first = 1;                /* Init getchx lookahead */
  1848.     memstr = 1;                /* Just set the flag. */
  1849.     memptr = hlptxt;            /* And the pointer. */
  1850.     if (binary) {            /* If file mode is binary, */
  1851.     savmod = binary;        /*  remember to restore it later. */
  1852.     binary = 0;            /*  turn it back to text for this, */
  1853.     }
  1854.     return(sinit());
  1855. #else
  1856.     return(0);
  1857. #endif /* NOSERVER */
  1858. }
  1859.  
  1860. #ifdef OS2
  1861. /*  S N D S P A C E -- send disk space message  */
  1862. int
  1863. sndspace(int drive) {
  1864. #ifndef NOSERVER
  1865.     static char spctext[64];
  1866.     if (drive)
  1867.       sprintf(spctext, " Drive %c: %ldK free\n", drive, 
  1868.           zdskspace(drive - 'A' + 1) / 1024L);
  1869.     else
  1870.       sprintf(spctext, " Free space: %ldK\n", zdskspace(0)/1024L);
  1871.     nfils = 0;            /* No files, no lists. */
  1872.     xflg = 1;            /* Flag we must send X packet. */
  1873.     strcpy(cmdstr,"free space");/* Data for X packet. */
  1874.     first = 1;            /* Init getchx lookahead */
  1875.     memstr = 1;            /* Just set the flag. */
  1876.     memptr = spctext;        /* And the pointer. */
  1877.     if (binary) {        /* If file mode is binary, */
  1878.         savmod = binary;    /*  remember to restore it later. */
  1879.         binary = 0;        /*  turn it back to text for this, */
  1880.     }
  1881.     return(sinit());
  1882. #else
  1883.     return(0);
  1884. #endif /* NOSERVER */
  1885. }
  1886. #endif /* OS2 */
  1887.  
  1888. /*  C W D  --  Change current working directory  */
  1889.  
  1890. /*
  1891.  String passed has first byte as length of directory name, rest of string
  1892.  is name.  Fails if can't connect, else ACKs (with name) and succeeds. 
  1893. */
  1894.  
  1895. int
  1896. cwd(vdir) char *vdir; {
  1897.     char *cdd, *zgtdir(), *dirp;
  1898.  
  1899.     vdir[xunchar(*vdir) + 1] = '\0';    /* Terminate string with a null */
  1900.     dirp = vdir+1;
  1901.     tlog(F110,"Directory requested: ",dirp,0L);
  1902.     if (zchdir(dirp)) {        /* Try to change */
  1903.     cdd = zgtdir();        /* Get new working directory. */
  1904.     debug(F110,"cwd",cdd,0);
  1905.     encstr((CHAR *)cdd);
  1906.     ack1((CHAR *)(encbuf+7));
  1907.     tlog(F110,"Changed directory to",cdd,0L);
  1908.     return(1); 
  1909.     } else {
  1910.     debug(F110,"cwd failed",dirp,0);
  1911.     tlog(F110,"Failed to change directory to",dirp,0L);
  1912.     return(0);
  1913.     }
  1914. }
  1915.  
  1916.  
  1917. /*  S Y S C M D  --  Do a system command  */
  1918.  
  1919. /*  Command string is formed by concatenating the two arguments.  */
  1920.  
  1921. int
  1922. syscmd(prefix,suffix) char *prefix, *suffix; {
  1923.     char *cp;
  1924.  
  1925.     if (prefix == NULL || *prefix == '\0') return(0);
  1926.  
  1927.     for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
  1928.     while (*cp++ = *suffix++) ;        /* copy suffix */
  1929.  
  1930.     debug(F110,"syscmd",cmdstr,0);
  1931.     if (zxcmd(ZIFILE,cmdstr) > 0) {
  1932.     debug(F110,"syscmd zxcmd ok",cmdstr,0);
  1933.     nfils = sndsrc = 0;        /* Flag that input is from stdin */
  1934.     xflg = hcflg = 1;        /* And special flags for pipe */
  1935.     if (binary) {            /* If file mode is binary, */
  1936.         savmod = binary;        /*  remember to restore it later. */
  1937.         binary = 0;            /*  turn it back to text for this, */
  1938.     }
  1939.     return (sinit());        /* Send S packet */
  1940.     } else {
  1941.     debug(F100,"syscmd zxcmd failed",cmdstr,0);
  1942.     return(0);
  1943.     }
  1944. }
  1945.  
  1946. /*  R E M S E T  --  Remote Set  */
  1947. /*  Called by server to set variables as commanded in REMOTE SET packets.  */
  1948. /*  Returns 1 on success, 0 on failure.  */
  1949.  
  1950. int
  1951. remset(s) char *s; {
  1952.     int len, i, x, y;
  1953.     char *p;
  1954.  
  1955.     len = xunchar(*s++);        /* Length of first field */
  1956.     p = s + len;            /* Pointer to second length field */
  1957.     *p++ = '\0';            /* Zero out second length field */
  1958.     x = atoi(s);            /* Value of first field */
  1959.     debug(F111,"remset",s,x);
  1960.     debug(F110,"remset",p,0);
  1961.     switch (x) {            /* Do the right thing */
  1962.       case 132:                /* Attributes (all, in) */
  1963.     atcapr = atoi(p);
  1964.     return(1);
  1965.       case 133:                /* File length attributes */
  1966.       case 233:                /* IN/OUT combined */
  1967.       case 148:                /* Both kinds of lengths */
  1968.       case 248:
  1969.     atleni = atleno = atoi(p);
  1970.     return(1);
  1971.       case 134:                /* File Type (text/binary) */
  1972.       case 234:
  1973.     attypi = attypo = atoi(p);
  1974.     return(1);
  1975.       case 135:                /* File creation date */
  1976.       case 235:
  1977.     atdati = atdato = atoi(p);
  1978.     return(1);
  1979.       case 139:                /* File Blocksize */
  1980.       case 239:
  1981.     atblki = atblko = atoi(p);
  1982.     return(1);
  1983.       case 141:                /* Encoding / Character Set */
  1984.       case 241:
  1985.     atenci = atenco = atoi(p);
  1986.     return(1);
  1987.       case 142:                /* Disposition */
  1988.       case 242:
  1989.     atdisi = atdiso = atoi(p);
  1990.     return(1);
  1991.       case 145:                /* System ID */
  1992.       case 245:
  1993.     atsidi = atsido = atoi(p);
  1994.     return(1);
  1995.       case 147:                /* System-Dependent Info */
  1996.       case 247:
  1997.     atsysi = atsyso = atoi(p);
  1998.     return(1);
  1999.       case 232:                /* Attributes (all, out) */
  2000.     atcapr = atoi(p);
  2001.     return(1);
  2002.       case 300:                /* File type (text, binary) */
  2003.     binary = atoi(p);
  2004.     return(1);
  2005.       case 301:                /* File name conversion */
  2006.     fncnv = 1 - atoi(p);        /* (oops) */
  2007.     return(1);
  2008.       case 302:                /* File name collision */
  2009.     x = atoi(p);
  2010.     if (x == XYFX_R) warn = 1;    /* Rename */
  2011.     if (x == XYFX_X) warn = 0;    /* Replace */
  2012.     fncact = x;
  2013.     return(1);
  2014.       case 310:                /* Incomplete File Disposition */
  2015.     keep = atoi(p);            /* Keep, Discard */
  2016.     return(1);
  2017.       case 311:                /* Blocksize */
  2018.     fblksiz = atoi(p);
  2019.     return(1);
  2020.       case 312:                /* Record Length */
  2021.     frecl = atoi(p);
  2022.     return(1);
  2023.       case 313:                /* Record format */
  2024.     frecfm = atoi(p);
  2025.     return(1);
  2026.       case 314:                /* File organization */
  2027.     forg = atoi(p);
  2028.     return(1);
  2029.       case 315:                /* File carriage control */
  2030.     fcctrl = atoi(p);
  2031.     return(1);
  2032.       case 400:                /* Block check */
  2033.     y = atoi(p);
  2034.     if (y < 5 && y > 0) {
  2035.         bctr = y;
  2036.         return(1);
  2037.     } else if (*p == 'B') {
  2038.         bctr = 4;
  2039.         return(1);
  2040.     }
  2041.     return(0);
  2042.       case 401:                /* Receive packet-length */
  2043.     urpsiz = atoi(p);
  2044.     if (urpsiz > MAXRP) urpsiz = MAXRP;
  2045.     urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
  2046.     return(1);
  2047.       case 402:                /* Receive timeout */
  2048.     y = atoi(p);            /* Client is telling us */
  2049.     if (y > -1 && y < 999) {    /* the timeout that it wants */
  2050.         pkttim = chktimo(y,timef);    /* us to tell it to use. */
  2051.         return(1);
  2052.     } else return(0);
  2053.       case 403:                /* Retry limit */
  2054.     y = atoi(p);
  2055.     if (y > -1 && y < 95) {
  2056.         maxtry = y;
  2057.         return(1);
  2058.     } else return(0);
  2059.       case 404:                /* Server timeout */
  2060.     y = atoi(p);
  2061.     if (y < 0) return(0);
  2062.     srvtim = y;
  2063.     return(1);
  2064.  
  2065. #ifndef NOCSETS
  2066.       case 405:                /* Transfer character set */
  2067.     for (i = 0; i < ntcsets; i++) { 
  2068.         if (!strcmp(tcsinfo[i].designator,p)) break;
  2069.     }
  2070.     debug(F101,"remset xfer charset lookup","",i);
  2071.     if (i == ntcsets) return(0);
  2072.     tcharset = tcsinfo[i].code;    /* if known, use it */
  2073.     if (tcharset == TC_TRANSP)
  2074.       rx = NULL;
  2075.     else
  2076.       rx = xlr[tcharset][fcharset];    /* translation function */
  2077.     return(1);
  2078. #endif /* NOCSETS */
  2079.  
  2080.       case 406:                /* Window slots */
  2081.     y = atoi(p);
  2082.     if (y == 0) y = 1;
  2083.     if (y < 1 && y > 31) return(0);
  2084.     wslotr = y;
  2085.     swcapr = 1;
  2086.     urpsiz = adjpkl(urpsiz,wslots,bigrbsiz);
  2087.     return(1);
  2088.       default:                /* Anything else... */
  2089.     return(0);
  2090.     }
  2091. }
  2092.  
  2093. /* Adjust packet length based on number of window slots and buffer size */
  2094.  
  2095. int
  2096. adjpkl(pktlen,slots,bufsiz) int pktlen, slots, bufsiz; {
  2097.     debug(F101,"adjpkl len","",pktlen);
  2098.     debug(F101,"adjpkl slots","",slots);
  2099.     debug(F101,"adjpkl bufsiz","",bufsiz);
  2100.     if (((pktlen + 6) * slots) > bufsiz)
  2101.       pktlen = (bufsiz / slots) - 6;
  2102.     debug(F101,"adjpkl new len","",pktlen);
  2103.     return(pktlen);
  2104. }
  2105.