home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / CKPM5X_S.ZIP / CKCFNS.C < prev    next >
C/C++ Source or Header  |  1990-03-02  |  45KB  |  1,381 lines

  1. char *fnsv = "C-Kermit functions, 4F(058) 14 Jul 89";
  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, 1989, Trustees of Columbia University in the City of New 
  12.  York.  Permission is granted to any individual or institution to use, copy, or
  13.  redistribute this software so long as it is not sold for profit, provided this
  14.  copyright notice is retained. 
  15. */
  16. /*
  17.  System-dependent primitives defined in:
  18.  
  19.    ck?tio.c -- terminal i/o
  20.    cx?fio.c -- file i/o, directory structure
  21. */
  22. #include "ckcsym.h"            /* Once needed this for Mac... */
  23. #include "ckcasc.h"            /* ASCII symbols */
  24. #include "ckcdeb.h"            /* Debug formats, typedefs, etc. */
  25. #include "ckcker.h"            /* Symbol definitions for Kermit */
  26. #include "ckcxla.h"
  27.  
  28. #ifndef NULL
  29. #define NULL 0
  30. #endif
  31.  
  32. /* Externals from ckcmai.c */
  33. extern int spsiz, spmax, rpsiz, timint, srvtim, rtimo, npad, ebq, ebqflg,
  34.  rpt, rptq, rptflg, capas, keep;
  35. extern int pktnum, prvpkt, sndtyp, bctr, bctu, fmask,
  36.  size, osize, maxsize, spktl, nfils, stdouf, warn, timef, spsizf;
  37. extern int parity, speed, turn, turnch, network,
  38.  delay, displa, pktlog, tralog, seslog, xflg, mypadn;
  39. extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize;
  40. extern int tsecs;
  41. extern int spackets, rpackets, timeouts, retrans, crunched, wmax;
  42. extern int deblog, hcflg, binary, savmod, fncnv, local, server, cxseen, czseen;
  43. extern int nakstate;
  44. extern int rq, rqf, sq, wslots, wslotsn, wslotsr, winlo, urpsiz, rln;
  45. extern int atcapr, atcapb, atcapu;
  46. extern int lpcapr, lpcapb, lpcapu;
  47. extern int swcapr, swcapb, swcapu;
  48. extern int bsave, bsavef;
  49. extern int sseqtbl[];
  50. extern int numerrs;
  51. extern int rptn;
  52. extern int tcharset, fcharset;
  53. extern int maxtry, ntcsets;
  54. extern struct csinfo tcsinfo[];
  55. extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate;
  56. extern CHAR filnam[], *recpkt, *data, srvcmd[], padbuf[], stchr, mystch;
  57. extern CHAR encbuf[];
  58. extern CHAR *srvptr;
  59. extern CHAR *rdatap;
  60. extern char *cmarg, *cmarg2, *hlptxt, **cmlist;
  61. char *strcpy();
  62. CHAR *rpar();
  63. long zchki();
  64.  
  65. /* International character sets */
  66.  
  67. /* Pointers to translation functions */
  68. extern CHAR (*xlr[MAXTCSETS+1][MAXFCSETS+1])();    
  69. extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();    
  70. CHAR (*rx)();                /* Input translation function */
  71. CHAR (*sx)();                /* Output translation function */
  72.  
  73. /* Windowing things */
  74.  
  75. extern int rseqtbl[];            /* Rec'd-packet sequence # table */
  76.  
  77. /* (PWP) external def. of things used in buffered file input and output */
  78.  
  79. extern CHAR zinbuffer[], zoutbuffer[];
  80. extern CHAR *zinptr, *zoutptr;
  81. extern int zincnt, zoutcnt;
  82.  
  83. /* Variables defined in this module, but shared by ckcfn3, to which */
  84. /* several functions have been moved... */
  85.  
  86. int sndsrc;                /* Flag for where to send from: */
  87.                     /* -1: name in cmdata */
  88.                     /*  0: stdin          */
  89.                     /* >0: list in cmlist */
  90.  
  91. int n_len;            /* (PWP) packet encode-ahead length (& flag) */
  92.                 /* if < 0, no pre-encoded data */
  93.  
  94. int  memstr;                /* Flag for input from memory string */
  95.  
  96. /* Variables local to this module */
  97.  
  98. static char *memptr;            /* Pointer for memory strings */
  99.  
  100. static char cmdstr[100];        /* Unix system command string */
  101.  
  102. static int drain;            /* For draining stacked-up ACKs. */
  103.  
  104. static int first;            /* Flag for first char from input */
  105. static CHAR t,                /* Current character */
  106.     next;                /* Next character */
  107.  
  108. #ifdef datageneral
  109. extern int quiet;
  110. #endif
  111.  
  112. /*  E N C S T R  --  Encode a string from memory. */
  113.  
  114. /*  Call this instead of getpkt() if source is a string, rather than a file. */
  115.  
  116. #define ENCBUFL 200
  117. CHAR encbuf[ENCBUFL];            /* Because getpkt always writes */
  118.                     /* into "data", but when this */
  119.                     /* function is called, "data" might */
  120.                     /* might not be allocated. */
  121. encstr(s) char* s; {
  122.     int m; char *p;
  123.     CHAR *dsave;
  124.  
  125.     if ((m = strlen(s)) > ENCBUFL) {
  126.     debug(F111,"encstr string too long for buffer",s,ENCBUFL);
  127.     s[ENCBUFL] = '\0';
  128.     }
  129.     if (m > spsiz-bctu-3) {
  130.     debug(F111,"encstr string too long for packet",s,spsiz-bctu-3);
  131.     s[spsiz-bctu-3] = '\0';
  132.     }
  133.     m = memstr; p = memptr;        /* Save these. */
  134.  
  135.     memptr = s;                /* Point to the string. */
  136.     memstr = 1;                /* Flag memory string as source. */
  137.     first = 1;                /* Initialize character lookahead. */
  138.     dsave = data;            /* Boy is this ugly... */
  139.     data = encbuf;            /* Boy is this ugly... */
  140.     getpkt(spsiz-bctu-3);        /* Fill a packet from the string. */
  141.     data = dsave;            /* (sorry...) */
  142.     memstr = m;                /* Restore memory string flag */
  143.     memptr = p;                /* and pointer */
  144.     first = 1;                /* Put this back as we found it. */
  145. }
  146.  
  147. /* E N C O D E - Kermit packet encoding procedure */
  148.  
  149. encode(a) CHAR a; {            /* The current character */
  150.     int a7;                /* Low order 7 bits of character */
  151.     int b8;                /* 8th bit of character */
  152.  
  153.     if (!binary) a = (*sx)(a);        /* Translate. */
  154.  
  155.     if (rptflg)    {                   /* Repeat processing? */
  156.         if (a == next && (first == 0)) { /* Got a run... */
  157.         if (++rpt < 94)        /* Below max, just count */
  158.                 return;
  159.         else if (rpt == 94) {    /* Reached max, must dump */
  160.                 data[size++] = rptq;
  161.                 data[size++] = tochar(rpt);
  162.         rptn += rpt;        /* Count, for stats */
  163.                 rpt = 0;
  164.         }
  165.         } else if (rpt == 1) {        /* Run broken, only 2? */
  166.             rpt = 0;            /* Yes, reset repeat flag & count. */
  167.         encode(a);            /* Do the character twice. */
  168.         if (size <= maxsize) osize = size;
  169.         rpt = 0;
  170.         encode(a);
  171.         return;
  172.     } else if (rpt > 1) {        /* More than two */
  173.             data[size++] = rptq;    /* Insert the repeat prefix */
  174.             data[size++] = tochar(++rpt); /* and count. */
  175.         rptn += rpt;
  176.             rpt = 0;            /* Reset repeat counter. */
  177.         }
  178.     }
  179.     a7 = a & 0177;            /* Isolate ASCII part */
  180.     b8 = a & 0200;            /* and 8th (parity) bit. */
  181.  
  182.     if (ebqflg && b8) {            /* Do 8th bit prefix if necessary. */
  183.         data[size++] = ebq;
  184.         a = a7;
  185.     }
  186.     if ((a7 < SP) || (a7==DEL))    {    /* Do control prefix if necessary */
  187.         data[size++] = myctlq;
  188.     a = ctl(a);
  189.     }
  190.     if (a7 == myctlq)            /* Prefix the control prefix */
  191.         data[size++] = myctlq;
  192.  
  193.     if ((rptflg) && (a7 == rptq))    /* If it's the repeat prefix, */
  194.         data[size++] = myctlq;        /* quote it if doing repeat counts. */
  195.  
  196.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th bit prefix */
  197.         data[size++] = myctlq;        /* if doing 8th-bit prefixes */
  198.  
  199.     data[size++] = a;            /* Finally, insert the character */
  200.     data[size] = '\0';            /* itself, and mark the end. */
  201. }
  202.  
  203. /*  Output functions passed to 'decode':  */
  204.  
  205. putsrv(c) register char c; {     /*  Put character in server command buffer  */
  206.     *srvptr++ = c;
  207.     *srvptr = '\0';    /* Make sure buffer is null-terminated */
  208.     return(0);
  209. }
  210.  
  211. puttrm(c) register char c; {     /*  Output character to console.  */
  212.     conoc(c);
  213.     return(0);
  214. }
  215.  
  216. putfil(c) register char c; {            /*  Output char to file. */
  217.     if (zchout(ZOFILE, c & fmask) < 0) {
  218.     czseen = 1;               /* If write error... */
  219.     debug(F101,"putfil zchout write error, setting czseen","",1);
  220.     return(-1);
  221.     }
  222.     return(0);
  223. }
  224.  
  225. /* D E C O D E  --  Kermit packet decoding procedure */
  226.  
  227. /* Call with string to be decoded and an output function. */
  228. /* Returns 0 on success, -1 on failure (e.g. disk full).  */
  229.  
  230. decode(buf,fn) register CHAR *buf; register int (*fn)(); {
  231.     register unsigned int a, a7, b8;    /* Low order 7 bits, and the 8th bit */
  232.     int x;
  233.  
  234.     rpt = 0;                /* Initialize repeat count. */
  235.  
  236.     while ((a = *buf++) != '\0') {
  237.     if (rptflg) {            /* Repeat processing? */
  238.         if (a == rptq) {        /* Yes, got a repeat prefix? */
  239.         rpt = xunchar(*buf++);    /* Yes, get the repeat count, */
  240.         rptn += rpt;
  241.         a = *buf++;        /* and get the prefixed character. */
  242.         }
  243.     }
  244.     b8 = 0;                /* Check high order "8th" bit */
  245.     if (ebqflg) {            /* 8th-bit prefixing? */
  246.         if (a == ebq) {        /* Yes, got an 8th-bit prefix? */
  247.         b8 = 0200;        /* Yes, remember this, */
  248.         a = *buf++;        /* and get the prefixed character. */
  249.         }
  250.     }
  251.     if (a == ctlq) {        /* If control prefix, */
  252.         a  = *buf++;        /* get its operand. */
  253.         a7 = a & 0177;        /* Only look at low 7 bits. */
  254.         if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */
  255.           a = ctl(a);        /* if in control range. */
  256.     }
  257.     a |= b8;            /* OR in the 8th bit */
  258.     if (rpt == 0) rpt = 1;        /* If no repeats, then one */
  259. #ifdef NLCHAR
  260.     if (!binary) {            /* If in text mode, */
  261.         if (a == CR) continue;    /* discard carriage returns, */
  262.             if (a == LF) a = NLCHAR;     /* convert LF to system's newline. */
  263.         }
  264. #endif
  265.     if (!binary) a = (*rx)(a);    /* Translate */
  266.  
  267.     if (fn == putfil) { /* (PWP) speedup via buffered output and a macro */
  268.         for (; rpt > 0; rpt--) {    /* Output the char RPT times */
  269.         if ((x = zmchout(a)) < 0) { /* zmchout is a macro */
  270.             debug(F101,"decode zmchout","",x);
  271.             return(-1);
  272.         }
  273.         ffc++;            /* Count the character */
  274.         }
  275.     } else {            /* Not to the file */
  276.         for (; rpt > 0; rpt--) {    /* Output the char RPT times */
  277.         if ((*fn)(a) < 0) return(-1); /* Send to output function. */
  278.         }
  279.     }
  280.     }
  281.     return(0);
  282. }
  283.  
  284. /*  G E T P K T -- Fill a packet data field  */
  285.  
  286. /*
  287.  Gets characters from the current source -- file or memory string.
  288.  Encodes the data into the packet, filling the packet optimally.
  289.  Set first = 1 when calling for the first time on a given input stream
  290.  (string or file).
  291.  
  292.  Uses global variables:
  293.  t     -- current character.
  294.  first -- flag: 1 to start up, 0 for input in progress, -1 for EOF.
  295.  next  -- next character.
  296.  data  -- pointer to the packet data buffer.
  297.  size  -- number of characters in the data buffer.
  298.  memstr - flag that input is coming from a memory string instead of a file.
  299.  memptr - pointer to string in memory.
  300.  (*sx)()  character set translation function
  301.  
  302. Returns the size as value of the function, and also sets global "size",
  303. and fills (and null-terminates) the global data array.  Returns 0 upon eof.
  304.  
  305. Rewritten by Paul W. Placeway (PWP) of Ohio State University, March 1989.
  306. Incorporates old getchx() and encode() inline to eliminate function calls,
  307. uses buffered input for much-improved efficiency, and clears up some
  308. confusion with line termination (CRLF vs LF vs CR).
  309. */
  310.  
  311. getpkt(bufmax) int bufmax; {        /* Fill one packet buffer */
  312.     register CHAR rt = t, rnext = next; /* register shadows of the globals */
  313.     register CHAR *dp, *odp, *p1, *p2;    /* pointers... */
  314.     register int x;            /* Loop index. */
  315.     register int a7;            /* Low 7 bits of character */
  316.     static CHAR leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' };
  317.  
  318.     if (first == 1) {        /* If first time thru...  */
  319.     first = 0;        /* remember, */
  320.     *leftover = '\0';       /* discard any interrupted leftovers, */
  321.     /* get first character of file into t, watching out for null file */
  322.     if (memstr) {
  323.         if ((rt = *memptr++) == '\0') { /* end of string ==> EOF */
  324.         first = -1;
  325.             size = 0;
  326.         debug(F100,"getpkt: empty string","",0);
  327.         return (0);
  328.         }
  329.     } else {
  330.         if ((x = zminchar()) == -1) { /* End of file */
  331.         first = -1;
  332.         debug(F100,"getpkt: empty file","",0);
  333.             size = 0;
  334.         return(0);
  335.         }
  336.         ffc++;            /* Count a file character */
  337.         rt = x;
  338.         debug(F101,"getpkt zminchar","",rt);
  339.     }
  340.     debug(F101,"getpkt about to call translate function","",rt);
  341.     if (!binary) rt = (*sx)(rt);    /* Translate */
  342.     debug(F101," translate function returns","",rt);
  343.     rt &= fmask;            /* bytesize mask */
  344.  
  345.     /* PWP: handling of NLCHAR is done later (in the while loop)... */
  346.  
  347.     } else if ((first == -1) && (*leftover == '\0')) /* EOF from last time? */
  348.         return(size = 0);
  349.  
  350.     /* Do any leftovers */
  351.  
  352.     dp = data;
  353.     for (p1 = leftover; (*dp = *p1) != '\0'; p1++, dp++) /* copy leftovers */
  354.         ;
  355.     *leftover = '\0';
  356.     if (first == -1) 
  357.       return(size = (dp - data));    /* Handle final leftovers */
  358.   
  359.     /* Now fill up the rest of the packet. */
  360.     rpt = 0;                /* Clear out any old repeat count. */
  361.     while (first > -1) {        /* Until EOF... */
  362.     if (memstr) {            /* get next character */
  363.         if ((rnext = *memptr++) == '\0') { /* end of string ==> EOF */
  364.         first = -1;        /* Flag eof for next time. */
  365.         } else {
  366.         if (!binary) rnext = (*sx)(rnext); /* Translate */
  367.         rnext &= fmask;        /* Bytesize mask. */
  368.         }
  369.     } else {
  370.         if ((x = zminchar()) == -1) { /* End of file */
  371.         first = -1;        /* Flag eof for next time. */
  372.         } else {
  373.         if (!binary) x = (*sx)(x); /* Translate */
  374.         rnext = x & fmask;    /* Bytesize mask. */
  375.         ffc++;            /* Count it */
  376.         }
  377.     }
  378.  
  379.     /* PWP: handling of NLCHAR is done in a bit...  */
  380.  
  381.     odp = dp;            /* Remember current position. */
  382.  
  383.     /* PWP: the encode() procedure, in-line (for speed) */
  384.     if (rptflg) {            /* Repeat processing? */
  385.         if (
  386. #ifdef NLCHAR
  387.         /*
  388.          * PWP: this is a bit esoteric, so bear with me.
  389.          * If the next char is really CRLF, then we cannot
  390.          * be doing a repeat (unless CR,CR,LF which becomes
  391.          * "~ <n-1> CR CR LF", which is OK but not most efficient).
  392.          * I just plain don't worry about this case.  The actual
  393.          * conversion from NL to CRLF is done after the rptflg if...
  394.          */
  395.         (binary || (rnext != NLCHAR)) &&
  396. #endif /* NLCHAR */
  397.         rt == rnext && (first == 0)) { /* Got a run... */
  398.         if (++rpt < 94) {    /* Below max, just count */
  399.             continue;        /* go back and get another */
  400.         }
  401.         else if (rpt == 94) {    /* Reached max, must dump */
  402.             *dp++ = rptq;
  403.             *dp++ = tochar(rpt);
  404.             rptn += rpt;
  405.             rpt = 0;
  406.         }
  407.         } else if (rpt == 1) {    /* Run broken, only 2? */
  408.         /* 
  409.          * PWP: Must encode two characters.  This is handled
  410.          * later, with a bit of blue smoke and mirrors, after
  411.          * the first character is encoded.
  412.          */
  413.         } else if (rpt > 1) {    /* More than two */
  414.         *dp++ = rptq;        /* Insert the repeat prefix */
  415.         *dp++ = tochar(++rpt);    /* and count. */
  416.         rptn += rpt;
  417.         rpt = 0;        /* Reset repeat counter. */
  418.         }
  419.     }
  420.  
  421. #ifdef NLCHAR
  422.     /*
  423.      * PWP: even more esoteric NLCHAR handling.  Remember, at
  424.      * this point t may still be the _system_ NLCHAR.  If so,
  425.      * we do it here.
  426.      */
  427.     if (!binary && (rt == NLCHAR)) {
  428.         *dp++ = myctlq;        /* just put in the encoding directly */
  429.         *dp++ = 'M';        /* == ctl(CR) */
  430.         if ((dp-data) <= maxsize) odp = dp;    /* check packet bounds */
  431.         rt = LF;
  432.     }
  433. #endif
  434.  
  435.     /* meta control stuff fixed by fdc */
  436.     a7 = rt & 0177;            /* Low 7 bits of character */
  437.     if (ebqflg && (rt & 0200)) {    /* Do 8th bit prefix if necessary. */
  438.         *dp++ = ebq;
  439.         rt = a7;
  440.     }
  441.     if ((a7 < SP) || (a7 == DEL)) { /* Do control prefix if necessary */
  442.         *dp++ = myctlq;
  443.         rt = ctl(rt);
  444.     }
  445.     if (a7 == myctlq)        /* Prefix the control prefix */
  446.         *dp++ = myctlq;
  447.  
  448.     if ((rptflg) && (a7 == rptq))    /* If it's the repeat prefix, */
  449.         *dp++ = myctlq;        /* quote it if doing repeat counts. */
  450.  
  451.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th bit prefix */
  452.         *dp++ = myctlq;        /* if doing 8th-bit prefixes */
  453.  
  454.     *dp++ = rt;            /* Finally, insert the character */
  455.     
  456.     if (rpt == 1) {            /* Exactly two copies? */
  457.         rpt = 0;
  458.         p2 = dp;            /* save current size temporarily */
  459.         for (p1 = odp; p1 < p2; p1++) /* copy the old chars over again */
  460.         *dp++ = *p1;
  461.         if ((p2-data) <= maxsize) odp = p2; /* check packet bounds */
  462.     }
  463.     rt = rnext;            /* Next is now current. */
  464.     if ((dp-data) >= bufmax) {    /* If too big, save some for next. */
  465.         size = (dp-data);
  466.         *dp = '\0';            /* mark (current) the end. */
  467.         if ((dp-data) > bufmax) {    /* if packet is overfull */
  468.         for (p1 = leftover, p2=odp; (*p1 = *p2) != '\0'; p1++,p2++)
  469.             ;
  470.         debug(F111,"getpkt leftover",leftover,size);
  471.         debug(F101," osize","",(odp-data));
  472.         size = (odp-data);    /* Return truncated packet. */
  473.         *odp = '\0';        /* mark real end */
  474.         } else {            /* If the packet is exactly full, */
  475.         debug(F101,"getpkt exact fit","",size);
  476.         }
  477.         t = rt; next = rnext;    /* save for next time */
  478.         return(size);
  479.     }
  480.     }                    /* Otherwise, keep filling. */
  481.     size = (dp-data);
  482.     *dp = '\0';                /* mark (current) the end. */
  483.     debug(F111,"getpkt eof/eot",data,size); /* Fell thru before packet full, */
  484.     return(size);             /* return partially filled last packet. */
  485. }
  486.  
  487. /*  T I N I T  --  Initialize a transaction  */
  488.  
  489. extern struct pktinfo s_pkt[];        /* arrays of pktinfo structures */
  490. extern struct pktinfo r_pkt[];        /* for sent and received packets */
  491.  
  492. tinit() {
  493.     int x; CHAR *y;
  494.  
  495.     rx = xlr[tcharset][fcharset];    /* Input translation function */
  496.     sx = xls[tcharset][fcharset];    /* Output translation function */
  497.  
  498.     xflg = 0;                /* Reset x-packet flag */
  499.     rqf = -1;                /* Reset 8th-bit-quote request flag */
  500.     memstr = 0;                /* Reset memory-string flag */
  501.     memptr = NULL;            /*  and pointer */
  502.     n_len = -1;                /* No encoded-ahead data */
  503.     bctu = 1;                /* Reset block check type to 1 */
  504.     ebq = ebqflg = 0;            /* Reset 8th-bit quoting stuff */
  505.     if (savmod) {            /* If global file mode was saved, */
  506.         binary = 1;            /*  restore it, */
  507.     savmod = 0;            /*  unsave it. */
  508.     }
  509.     pktnum = 0;                /* Initial packet number */
  510.     cxseen = czseen = 0;        /* Reset interrupt flags */
  511.     *filnam = '\0';            /* Clear file name */
  512.     spktl = 0;                /* And its length */
  513.     nakstate = 0;            /* Assume not in a NAK'ing state */
  514.     numerrs = 0;            /* Transmission error counter */
  515.     timeouts = retrans = 0;        /* Statistics counters */
  516.     spackets = rpackets = 0;        /*  ... */
  517.     crunched = 0;            /*  ... */
  518.     wmax = 1;                /*  ... */
  519.     if (server)             /* If acting as server, */
  520.       timint = srvtim;            /* Use server timeout interval. */
  521.     wslots = 1;                /* One window slot */
  522.     winlo = 0;                /* Packet 0 is at window-low */
  523.     x = mksbuf(wslots);            /* Make a 1-slot send-packet buffer */
  524.     if (x < 0) return(x);
  525.     x = getsbuf(0);            /* Allocate first send-buffer. */
  526.     if (x < 0) return(x);
  527.     debug(F100,"tinit getsbuf","",0);
  528.     dumpsbuf();
  529.     x = mkrbuf(1);            /* & a 1-slot receive-packet buffer. */
  530.     if (x < 0) return(x);
  531.     return(0);
  532. }
  533.  
  534. pktinit() {                /* Initialize packet sequence */
  535.     pktnum = 0;                /* number & window low. */
  536.     winlo = 0;
  537. }
  538.  
  539. /*  R I N I T  --  Respond to S or I packet  */
  540.  
  541. rinit(d) char *d; {
  542.     char *tp;
  543.     ztime(&tp);
  544.     tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */
  545.     if (binary)
  546.       tlog(F100,"Global file mode = binary","",0l);
  547.     else
  548.       tlog(F100,"Global file mode = text","",0l);
  549.     filcnt = 0;                /* Init file counter */
  550.     spar(d);
  551.     ack1(rpar());
  552. #ifdef datageneral
  553.     if ((local) && (!quiet))            /* Only do this if local & not quiet */
  554.         consta_mt();                    /* Start the asynch read task */
  555. #endif
  556. }
  557.  
  558.  
  559. /*  R E S E T C  --  Reset per-transaction character counters */
  560.  
  561. resetc() {
  562.     rptn = 0;                /* Repeat counts */
  563.     flci = flco = 0;
  564.     tfc = tlci = tlco = 0;    /* Total file chars, line chars in & out */
  565. }
  566.  
  567. /*  S I N I T  --  Make sure file exists, then send Send-Init packet */
  568.  
  569. sinit() {
  570.     int x; char *tp;
  571.  
  572.     filcnt = 0;
  573.     sndsrc = nfils;            /* Where to look for files to send */
  574.  
  575.     ztime(&tp);
  576.     tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */
  577.     debug(F101,"sinit: sndsrc","",sndsrc);
  578.     if (sndsrc < 0) {            /* Must expand from 'send' command */
  579. #ifdef DTILDE
  580.     char *tnam, *tilde_expand();    /* May have to expand tildes */
  581.     tnam = tilde_expand(cmarg);    /* Try to expand tilde. */
  582.     if (*tnam != '\0') cmarg = tnam;
  583. #endif
  584.     nfils = zxpand(cmarg);        /* Look up literal name. */
  585.     if (nfils < 0) {
  586.         if (server)
  587.           errpkt("Too many files");
  588.         else
  589.           screen(SCR_EM,0,0l,"Too many files");
  590.         return(0);
  591.         } else if (nfils == 0) {    /* If none found, */
  592.         char xname[100];        /* convert the name. */
  593.         zrtol(cmarg,xname);
  594.         nfils = zxpand(xname);     /* Look it up again. */
  595.     }
  596.     if (nfils < 1) {        /* If no match, report error. */
  597.         if (server) 
  598.             errpkt("File not found");
  599.         else
  600.         screen(SCR_EM,0,0l,"File not found");
  601.         return(0);
  602.     }
  603.     x = gnfile();            /* Position to first file. */
  604.     if (x < 1) {
  605.         if (!server) 
  606.             screen(SCR_EM,0,0l,"No readable file to send");
  607.             else
  608.             errpkt("No readable file to send");
  609.         return(0);
  610.         } 
  611.     } else if (sndsrc > 0) {        /* Command line arglist -- */
  612.     x = gnfile();            /* Get the first file from it. */
  613.     if (x < 1) return(0);        /* (if any) */
  614.     } else if (sndsrc == 0) {        /* stdin or memory always exist... */
  615.     if ((cmarg2 != NULL) && (*cmarg2)) {
  616.         strcpy(filnam,cmarg2);    /* If F packet, "as" name is used */
  617.         cmarg2 = "";        /* if provided, */
  618.         } else                /* otherwise */
  619.         strcpy(filnam,"stdin");    /* just use this. */
  620.     }
  621.     debug(F101,"sinit: nfils","",nfils);
  622.     debug(F110," filnam",filnam,0);
  623.     debug(F110," cmdstr",cmdstr,0);
  624.     ttflui();                /* Flush input buffer. */
  625.     if (!local && !server) sleep(delay);
  626. #ifdef datageneral
  627.     if ((local) && (!quiet))            /* Only do this if local & not quiet */
  628.         consta_mt();                    /* Start the asynch read task */
  629. #endif
  630.     freerbuf(rseqtbl[0]);        /* Free the buffer the GET came in. */
  631.     sipkt('S');                /* Send the Send-Init packet. */
  632.     return(1);
  633. }
  634.  
  635. sipkt(c) char c; {            /* Send S or I packet. */
  636.     CHAR *rp;
  637.     ttflui();                /* Flush pending input. */
  638.     rp = rpar();            /* Get parameters. */
  639.     spack(c,pktnum,strlen(rp),rp);
  640. }
  641.  
  642. /*  R C V F I L -- Receive a file  */
  643.  
  644. /*
  645.   Incoming filename is in data field of F packet.
  646.   This function decodes it into the srvcmd buffer, substituting an
  647.   alternate "as-name", if one was given.
  648.   Finally, it does any requested transformations (like converting to
  649.   lowercase) then if a file of the same name already exists, makes
  650.   a new unique name.
  651. */
  652. rcvfil(n) char *n; {
  653.     char xname[100], *xp;        /* Buffer for constructing name */
  654. #ifdef DTILDE
  655.     char *dirp, *tilde_expand();
  656. #endif
  657.  
  658.     srvptr = srvcmd;            /* Decode file name from packet. */
  659.     decode(rdatap,putsrv);
  660.     if (*srvcmd == '\0')        /* Watch out for null F packet. */
  661.         strcpy(srvcmd,"NONAME");
  662. #ifdef DTILDE
  663.     dirp = tilde_expand(srvcmd);    /* Expand tilde, if any. */
  664.     if (*dirp != '\0') strcpy(srvcmd,dirp);
  665. #endif
  666.     screen(SCR_FN,0,0l,srvcmd);        /* Put it on screen */
  667.     tlog(F110,"Receiving",srvcmd,0l);    /* Transaction log entry */
  668.     if (cmarg2 != NULL) {               /* Check for alternate name */
  669.         if (*cmarg2 != '\0') {
  670.             strcpy(srvcmd,cmarg2);    /* Got one, use it. */
  671.         *cmarg2 = '\0';
  672.         }
  673.     }
  674.     xp = xname;                /* OK to proceed. */
  675.     if (fncnv)                /* If desired, */
  676.         zrtol(srvcmd,xp);        /* convert name to local form */
  677.     else                /* otherwise, */
  678.         strcpy(xname,srvcmd);        /* use it literally */
  679.  
  680.     if (warn) {                /* File collision avoidance? */
  681.     if (zchki(xname) != -1) {    /* Yes, file exists? */
  682.         znewn(xname,&xp);        /* Yes, make new name. */
  683.         strcpy(xname,xp);
  684.         debug(F110," exists, new name ",xname,0);
  685.         }
  686.     }
  687.     debug(F110,"rcvfil: xname",xname,0);
  688.     strcpy(n,xname);            /* Return pointer to actual name. */
  689.     debug(F110,"rcvfil: n",n,0);
  690.     ffc = 0;                /* Init per-file counters */
  691.     filcnt++;
  692.     return(1);                /* Always succeeds */
  693. }
  694.  
  695. /*  R E O F  --  Receive End Of File  */
  696.  
  697. reof(f,yy) char *f; struct zattr *yy; {
  698.     int x;
  699.     char *p;
  700.     char c;
  701.  
  702.     if (cxseen == 0) cxseen = (*rdatap == 'D');    /* Got discard directive? */
  703.     x = clsof(cxseen | czseen);
  704.     if (atcapu) zstime(f,yy);        /* Set file creation date */
  705.     if (cxseen || czseen) {
  706.     tlog(F100," *** Discarding","",0l);
  707.     cxseen = 0;
  708.     } else {
  709.     fstats();
  710.  
  711. /* Handle dispositions from attribute packet... */
  712.  
  713.     if (yy->disp.len != 0) {
  714.         p = yy->disp.val;
  715.         c = *p++;
  716.         if (c == 'M') {        /* Mail to user. */
  717.         zmail(p,filnam);    /* Do the system's mail command */
  718.         tlog(F110,"mailed",filnam,0l);
  719.         tlog(F110," to",p,0l);
  720.         zdelet(filnam);        /* Delete the file */
  721.         } else if (c == 'P') {    /* Print the file. */
  722.         zprint(p,filnam);    /* Do the system's print command */
  723.         tlog(F110,"printed",filnam,0l);
  724.         tlog(F110," with options",p,0l);
  725.         zdelet(filnam);        /* Delete the file */
  726.         }
  727.     }
  728.     }
  729.     *filnam = '\0';
  730.     return(x);
  731. }
  732.  
  733. /*  R E O T  --  Receive End Of Transaction  */
  734.  
  735. reot() {
  736.     cxseen = czseen = 0;        /* Reset interruption flags */
  737.     tstats();
  738. }
  739.  
  740. /*  S F I L E -- Send File header or teXt header packet  */
  741.  
  742. /*  Call with x nonzero for X packet, zero for F packet  */
  743. /*  Returns 1 on success, 0 on failure                   */
  744.  
  745. sfile(x) int x; {
  746.     char pktnam[100];            /* Local copy of name */
  747.     char *s;
  748.  
  749.     if (nxtpkt() < 0) return(0);    /* Bump packet number, get buffer */
  750.     if (x == 0) {            /* F-Packet setup */
  751.  
  752.         if (*cmarg2 != '\0') {        /* If we have a send-as name, */
  753.         strcpy(pktnam,cmarg2);    /* copy it literally, */
  754.         cmarg2 = "";        /* and blank it out for next time. */
  755.         } else {            /* Otherwise use actual file name: */
  756.         if (fncnv) {        /* If converting names, */
  757.             zltor(filnam,pktnam);    /* convert it to common form, */
  758.         } else {            /* otherwise, */
  759.             strcpy(pktnam,filnam);    /* copy it literally. */
  760.             }
  761.         }
  762.         debug(F110,"sfile",filnam,0);    /* Log debugging info */
  763.         debug(F110," pktnam",pktnam,0);
  764.         if (openi(filnam) == 0)     /* Try to open the file */
  765.         return(0);         
  766.         s = pktnam;            /* Name for packet data field */
  767.  
  768.     } else {                /* X-packet setup */
  769.  
  770.         debug(F110,"sxpack",cmdstr,0);    /* Log debugging info */
  771.         s = cmdstr;            /* Name for data field */
  772.     }
  773.  
  774.     encstr(s);                /* Encode the name into encbuf[]. */
  775.     spack(x ? 'X' : 'F', pktnum, size, encbuf); /* Send the F or X packet */
  776.  
  777.     if (x == 0) {            /* Display for F packet */
  778.         if (displa) {            /* Screen */
  779.         screen(SCR_FN,'F',(long)pktnum,filnam);
  780.         screen(SCR_AN,0,0l,pktnam);
  781.         screen(SCR_FS,0,(long)fsize,"");
  782.         }
  783.         tlog(F110,"Sending",filnam,0l);    /* Transaction log entry */
  784.         tlog(F110," as",pktnam,0l);
  785.  
  786.     } else {                /* Display for X-packet */
  787.  
  788.         screen(SCR_XD,'X',(long)pktnum,cmdstr);    /* Screen */
  789.         tlog(F110,"Sending from:",cmdstr,0l);    /* Transaction log */
  790.     }
  791.     intmsg(++filcnt);            /* Count file, give interrupt msg */
  792.     first = 1;                /* Init file character lookahead. */
  793.     n_len = -1;            /* (PWP) Init the packet encode-ahead length */
  794.     ffc = 0;                /* Init file character counter. */
  795.     return(1);
  796. }
  797.  
  798. /*  S D A H E A D -- (PWP) Encode the next data packet to send */
  799.  
  800. sdahead() {    
  801.     if (spsiz > MAXPACK)         /* see the logic in ckcfn2.c, spack() */
  802.     n_len = getpkt(spsiz-bctu-5);    /* long packet size */
  803.     else
  804.     n_len = getpkt(spsiz-bctu-2);    /* short packet size */
  805. }
  806.  
  807. /*  S D A T A -- Send a data packet */
  808.  
  809. /*  Return -1 if no data to send, else send packet and return length  */
  810.  
  811. sdata() {
  812.     int i,p,len;
  813.     int xx, yy;
  814.     
  815.     debug(F101,"sdata entry, first","",first);
  816.     debug(F101," drain","",drain);
  817.  
  818.     if (first == 1) drain = 0;        /* Try to explain this... */
  819.     if (drain) {
  820.     debug(F101,"sdata draining, winlo","",winlo);
  821.     debug(F101," winlo","",winlo);
  822.     if (winlo == pktnum) return(-1); else return(0);
  823.     }
  824.  
  825.     for (i = 0; i < wslots; i++) {    /* Send as many as possible. */
  826.     int k,x;
  827.     CHAR *y;
  828.  
  829.     x = nxtpkt();            /* Get next pkt number and buffer */
  830.     debug(F101,"sdata packet","",pktnum);
  831.     if (x < 0) {
  832. #ifdef COMMENT
  833.         debug(F101,"sdata nxtpkt failed, resending","",winlo);
  834.         x = resend(winlo);        /* Try to resend window-low. */
  835.         if (x < 0) doexit(BAD_EXIT); /* Fatal if can't. */
  836. #endif
  837.         return(0);
  838.     }
  839.     dumpsbuf();
  840.  
  841.     if (cxseen || czseen) {        /* If interrupted, done. */
  842.         return(-1);
  843.     }    
  844.     if (spsiz > 94)            /* Fill a packet data buffer */
  845.       len = getpkt(spsiz-bctu-6);    /* long packet */
  846.     else                /*  or */
  847.       len = getpkt(spsiz-bctu-3);    /* short packet */
  848.     if (len == 0) {            /* Done if no data. */
  849.         if (pktnum == winlo) return(-1);
  850.         drain = 1;            /* But can't return -1 until all */
  851.         debug(F101,"sdata eof, drain","",drain);
  852.         return(0);            /* ACKs are drained. */
  853.     }
  854.     spack('D',pktnum,len,data);    /* Send the packet */
  855.     x = ttchk();
  856.     debug(F101,"sdata ttchk","",x);    /* Any ACKs waiting? */
  857.     if (x) return(0);        /* ??? */
  858.     }    
  859.  
  860. /* comment out next statement if it causes problems... */
  861. #ifdef COMMENT
  862.     if (len > 0)            /* if we got data last time */
  863.     sdahead();            /* encode more now */
  864. #endif
  865.     return(len);
  866. }
  867.  
  868.  
  869. /*  S E O F -- Send an End-Of-File packet */
  870.  
  871. /*  Call with a string pointer to character to put in the data field, */
  872. /*  or else a null pointer or "" for no data.  */
  873.  
  874. seof(s) char *s; {
  875.  
  876.     /* NOTE, we don't call nextpkt() here because it was already called */
  877.     /* by sdata() when it got the end of file condition, and so did not */
  878.     /* use the packet number it had just allocated. */
  879.  
  880.     if ((s != NULL) && (*s != '\0')) {
  881.     spack('Z',pktnum,1,s);
  882.     tlog(F100," *** interrupted, sending discard request","",0l);
  883.     } else {
  884.     spack('Z',pktnum,0,"");
  885.     fstats();
  886.     }
  887. }
  888.  
  889. /*
  890.   Special version of seof() to be called when sdata() has not been called
  891.   before.  The difference is that this version calls nxpkt().  For example,
  892.   when a file that is about to be sent has been refused by the attribute
  893.   mechanism.
  894. */
  895.  
  896. sxeof(s) char *s; {
  897.     int x;
  898.     x = nxtpkt();            /* Get next pkt number and buffer */
  899.     if (x < 0)
  900.       debug(F101,"sxeof nxtpkt fails","",pktnum);
  901.     else
  902.       debug(F101,"sxeof packet","",pktnum);
  903.     seof(s);
  904. }
  905.  
  906. /*  S E O T -- Send an End-Of-Transaction packet */
  907.  
  908. seot() {
  909.     if (nxtpkt() < 0) return(-1);    /* Bump packet number, get buffer */
  910.     spack('B',pktnum,0,"");        /* Send the EOT packet */
  911.     cxseen = czseen = 0;        /* Reset interruption flags */
  912.     tstats();                /* Log timing info */
  913.     return(0);
  914. }
  915.  
  916. /*   R P A R -- Fill the data array with my send-init parameters  */
  917.  
  918.  
  919. static CHAR dada[20];            /* Use this instead of data[]. */
  920.                     /* To avoid some kind of wierd */
  921.                     /* addressing foulup in spack()... */
  922.  
  923. CHAR *
  924. rpar() {
  925.     int cps;
  926.  
  927. /* The following bit is in case user's timeout is shorter than the amount */
  928. /* of time it would take to receive a packet of the negotiated size. */
  929.  
  930.     if (speed > 0 && !network) {    /* First recompute timeout */
  931.     cps = speed / 10;        /* Characters per second */
  932.     if (cps * rtimo < spsiz) {
  933.         rtimo = (spsiz / cps) + 1;
  934.         debug(F101,"rpar new rtimo","",rtimo);
  935.     }
  936.     }
  937.     if (rpsiz > MAXPACK)        /* Biggest normal packet I want. */
  938.       dada[0] = tochar(MAXPACK);    /* If > 94, use 94, but specify */
  939.     else                /* extended packet length below... */
  940.       dada[0] = tochar(rpsiz);        /* else use what the user said. */
  941.     dada[1] = tochar(rtimo);        /* When I want to be timed out */
  942.     dada[2] = tochar(mypadn);        /* How much padding I need (none) */
  943.     dada[3] = ctl(mypadc);        /* Padding character I want */
  944.     dada[4] = tochar(eol);        /* End-Of-Line character I want */
  945.     dada[5] = '#';            /* Control-Quote character I send */
  946.     switch (rqf) {            /* 8th-bit prefix */
  947.     case -1:
  948.     case  1: if (parity) ebq = sq = '&'; break;
  949.     case  0:
  950.     case  2: break;
  951.     }
  952.     dada[6] = sq;
  953.     dada[7] = bctr + '0';        /* Block check type */
  954.     if (rptflg)                /* Run length encoding */
  955.         dada[8] = rptq;            /* If receiving, agree. */
  956.     else
  957.         dada[8] = '~';         
  958.  
  959.     dada[9] = tochar((atcapr?atcapb:0)|(lpcapr?lpcapb:0)|(swcapr?swcapb:0));
  960.     dada[10] = tochar(swcapr ? wslotsr : 0); /* Window size */
  961.     rpsiz = urpsiz;            /* Long packets ... */
  962.     dada[11] = tochar(rpsiz / 95);    /* Long packet size, big part */
  963.     dada[12] = tochar(rpsiz % 95);    /* Long packet size, little part */
  964.     dada[13] = '\0';            /* Terminate the init string */
  965.     if (deblog) {
  966.     debug(F110,"rpar",dada,0);
  967.     rdebu(strlen(dada));
  968.     }
  969.     return(dada);            /* Return pointer to string. */
  970. }
  971.  
  972. spar(s) char *s; {            /* Set parameters */
  973.     int x, y, cps, lpsiz;
  974.  
  975. debug(F110,"entering spar",s,0);
  976.  
  977.     s--;                /* Line up with field numbers. */
  978.  
  979. /* Limit on size of outbound packets */
  980.     x = (rln >= 1) ? xunchar(s[1]) : 80;
  981.     lpsiz = spsiz;            /* Remember what they SET. */
  982.     if (spsizf) {            /* SET-command override? */
  983.     if (x < spsiz) spsiz = x;    /* Ignore LEN unless smaller */
  984.     } else {                /* otherwise */
  985.     spsiz = (x < 10) ? 80 : x;    /* believe them if reasonable */
  986.     }
  987.  
  988. /* Timeout on inbound packets */
  989.     if (!timef) {            /* Only if not SET-cmd override */
  990.     x = (rln >= 2) ? xunchar(s[2]) : 5;
  991.     timint = (x < 0) ? 5 : x;
  992.     }
  993.     if (speed > 0 && !network) {    /* If comm line speed known, */
  994.     cps = speed / 10;        /* adjust for packet length */
  995.     if (cps * timint < urpsiz) {    /* if timeout to short for packet. */
  996.         timint = (urpsiz / cps) + 1;
  997.         debug(F101,"spar new timint","",timint);
  998.     }
  999.     }
  1000.  
  1001. /* Outbound Padding */
  1002.     npad = 0; padch = '\0';
  1003.     if (rln >= 3) {
  1004.     npad = xunchar(s[3]);
  1005.     if (rln >= 4) padch = ctl(s[4]); else padch = 0;
  1006.     }
  1007.     if (npad) {
  1008.     int i;
  1009.     for (i = 0; i < npad; i++) padbuf[i] = dopar(padch);
  1010.     }
  1011.  
  1012. /* Outbound Packet Terminator */
  1013.     seol = (rln >= 5) ? xunchar(s[5]) : '\r';
  1014.     if ((seol < 2) || (seol > 31)) seol = '\r';
  1015.  
  1016. /* Control prefix */
  1017.     x = (rln >= 6) ? s[6] : '#';
  1018.     myctlq = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
  1019.  
  1020. /* 8th-bit prefix */
  1021.     rq = (rln >= 7) ? s[7] : 0;
  1022.     if (rq == 'Y') rqf = 1;
  1023.       else if ((rq > 32 && rq < 63) || (rq > 95 && rq < 127)) rqf = 2;
  1024.         else rqf = 0;
  1025.     switch (rqf) {
  1026.     case 0: ebqflg = 0; break;
  1027.     case 1: if (parity) { ebqflg = 1; ebq = '&'; } break;
  1028.     case 2: if (ebqflg = (ebq == sq || sq == 'Y')) ebq = rq;
  1029.     }
  1030.  
  1031. /* Block check */
  1032.     x = 1;
  1033.     if (rln >= 8) {
  1034.     x = s[8] - '0';
  1035.     if ((x < 1) || (x > 3)) x = 1;
  1036.     }
  1037.     bctr = x;
  1038.  
  1039. /* Repeat prefix */
  1040.     if (rln >= 9) {
  1041.     rptq = s[9]; 
  1042.     rptflg = ((rptq > 32 && rptq < 63) || (rptq > 95 && rptq < 127));
  1043.     } else rptflg = 0;
  1044.  
  1045. /* Capabilities */
  1046.     atcapu = lpcapu = swcapu = 0;
  1047.     if (rln >= 10) {
  1048.         x = xunchar(s[10]);
  1049.     debug(F101,"spar capas","",x);
  1050.         atcapu = (x & atcapb) && atcapr;
  1051.     lpcapu = (x & lpcapb) && lpcapr;
  1052.     swcapu = (x & swcapb) && swcapr;
  1053.     debug(F101,"spar swcapr","",swcapr);
  1054.     debug(F101,"spar swcapu","",swcapu);
  1055.     for (y = 10; (xunchar(s[y]) & 1) && (rln >= y); y++) ;
  1056.     debug(F101,"spar y","",y);
  1057.     }
  1058.  
  1059. /* Long Packets */
  1060.     if (lpcapu) {
  1061.         if (rln > y+1) {
  1062.         x = xunchar(s[y+2]) * 95 + xunchar(s[y+3]);
  1063.         if (spsizf) {        /* If overriding negotiations */
  1064.         spsiz = (x < lpsiz) ? x : lpsiz; /* do this, */
  1065.         } else {                     /* otherwise */
  1066.         spsiz = (x > MAXSP) ? MAXSP : x; /* do this. */
  1067.         }
  1068.         if (spsiz < 10) spsiz = 80;    /* Be defensive... */
  1069.     }
  1070.     }
  1071.     /* (PWP) save current send packet size for optimal packet size calcs */
  1072.     spmax = spsiz;
  1073.     
  1074. /* Sliding Windows... */
  1075. /* This should be fixed to settle on the lower of what the user asked for */
  1076. /* in the 'set window' command and how many slots the other Kermit said.  */
  1077.  
  1078.     if (swcapr) {            /* Only if requested... */
  1079.         if (rln > y) {            /* See what other Kermit says */
  1080.         x = xunchar(s[y+1]);
  1081.         debug(F101,"spar window","",x);
  1082.         wslotsn = x > MAXWS ? MAXWS : x;
  1083.         if (wslotsn > wslotsr) wslotsn = wslotsr;
  1084.         if (wslotsn > 1) swcapu = 1; /* We do windows... */
  1085.     }
  1086.     else {
  1087.         wslotsn = 1;        /* We don't do windows... */
  1088.         swcapu = 0;
  1089.         debug(F101,"spar no windows","",wslotsn);
  1090.     }
  1091.     }
  1092.  
  1093. /* Now recalculate packet length based on number of windows.   */
  1094. /* The nogotiated number of window slots will be allocated,    */
  1095. /* and the maximum packet length will be reduced if necessary, */
  1096. /* so that a windowful of packets can fit in the big buffer.   */
  1097.  
  1098.     if (wslotsn > 1) {            /* Shrink to fit... */
  1099.     x = ( BIGSBUFSIZ / wslotsn ) - 1;
  1100.     if (x < spsiz) {
  1101.         spsiz = spmax = x;
  1102.         debug(F101,"spar sending, redefine spsiz","",spsiz);
  1103.     }
  1104.     }
  1105.  
  1106. /* Record parameters in debug log */
  1107.     if (deblog) sdebu(rln);
  1108.     numerrs = 0;            /* Start counting errors here. */
  1109.     return(0);
  1110. }
  1111.  
  1112. /*  G N F I L E  --  Get the next file name from a file group.  */
  1113.  
  1114. /*  Returns 1 if there's a next file, 0 otherwise  */
  1115.  
  1116. gnfile() {
  1117.     int x; long y;
  1118. #ifdef datageneral
  1119.     int dgfiles = 0;             /* Number of files expanded */
  1120.     static int dgnfils = -1;        /* Saved nfils value */
  1121. #endif
  1122.  
  1123. /* If file group interruption (C-Z) occured, fail.  */
  1124.  
  1125.     debug(F101,"gnfile: czseen","",czseen);
  1126.  
  1127.     if (czseen) {
  1128.     tlog(F100,"Transaction cancelled","",0l);
  1129.     return(0);
  1130.     }
  1131.  
  1132. /* If input was stdin or memory string, there is no next file.  */
  1133.  
  1134.     if (sndsrc == 0) return(0);
  1135.  
  1136. /* If file list comes from command line args, get the next list element. */
  1137.  
  1138.     y = -1;
  1139.     while (y < 0) {            /* Keep trying till we get one... */
  1140.  
  1141.     if (sndsrc > 0) {
  1142.         if (nfils-- > 0) {
  1143.  
  1144. #ifdef datageneral
  1145. /* The DG does not internally expand the file names when a string of */
  1146. /* filenames is given. So we must in this case. */
  1147.                 if (dgnfils == -1) {   /* This is executed first time only! */
  1148.                     strcpy(filnam,*cmlist++);
  1149.                 dgfiles = zxpand(filnam); /* Expand the string */
  1150.                     debug(F111,"gnfile:cmlist filnam (x-init)",filnam,dgfiles);
  1151.                     dgnfils = nfils + 1;
  1152.                     debug(F111,"gnfile:cmlist filnam (x-init)",filnam,dgnfils);
  1153.              } 
  1154.              x = znext(filnam);
  1155.              if (x > 0) {      /* Get the next file in the expanded list */
  1156.                 debug(F111,"gnfile znext: filnam (exp-x=)",filnam,x);
  1157.                     nfils = dgnfils;     /* The virtual number of files left */
  1158.                  }
  1159.              if (x == 0) {     /* Expand the next command argument */
  1160.                 if (dgnfils == 1) {
  1161.                      dgnfils = -1;   /* The last argument resets things */
  1162.                      *filnam = '\0';
  1163.                      debug(F101,"gnfile cmlist: nfils","",nfils);
  1164.                      return(0);
  1165.                 }
  1166.               
  1167.                     strcpy(filnam,*cmlist++);  /* Finish expanding last arg */
  1168.                 dgfiles = zxpand(filnam); /* Expand the string */
  1169.                     debug(F111,"gnfile: cmlist filnam (exp)",filnam,dgnfils);
  1170.                 x = znext(filnam);
  1171.                 debug(F111,"gnfile znext: filnam (exp)",filnam,x);
  1172.                 nfils = dgnfils--;
  1173.         } 
  1174. #else
  1175.         strcpy(filnam,*cmlist++);
  1176.         debug(F111,"gnfile: cmlist filnam",filnam,nfils);
  1177. #endif
  1178.         } else {
  1179.         *filnam = '\0';
  1180.         debug(F101,"gnfile cmlist: nfils","",nfils);
  1181.         return(0);
  1182.         }
  1183.     }
  1184.  
  1185. /* Otherwise, step to next element of internal wildcard expansion list. */
  1186.  
  1187.     if (sndsrc < 0) {
  1188.         x = znext(filnam);
  1189.         debug(F111,"gnfile znext: filnam",filnam,x);
  1190.         if (x == 0) return(0);
  1191.     }
  1192.  
  1193. /* Get here with a filename. */
  1194.  
  1195.     y = zchki(filnam);        /* Check if file readable */
  1196.     if (y < 0) {
  1197.         debug(F110,"gnfile skipping:",filnam,0);
  1198.         tlog(F111,filnam,"not sent, reason",(long)y);
  1199.         screen(SCR_ST,ST_SKIP,0l,filnam);
  1200.     } else fsize = y;
  1201.     }        
  1202.     return(1);
  1203. }
  1204.  
  1205. /*  S N D H L P  --  Routine to send builtin help  */
  1206.  
  1207. sndhlp() {
  1208.     nfils = 0;                /* No files, no lists. */
  1209.     xflg = 1;                /* Flag we must send X packet. */
  1210.     strcpy(cmdstr,"help text");        /* Data for X packet. */
  1211.     first = 1;                /* Init getchx lookahead */
  1212.     memstr = 1;                /* Just set the flag. */
  1213.     memptr = hlptxt;            /* And the pointer. */
  1214.     if (binary) {            /* If file mode is binary, */
  1215.     binary = 0;            /*  turn it back to text for this, */
  1216.     savmod = 1;            /*  remember to restore it later. */
  1217.     }
  1218.     return(sinit());
  1219. }
  1220.  
  1221.  
  1222. /*  C W D  --  Change current working directory  */
  1223.  
  1224. /*
  1225.  String passed has first byte as length of directory name, rest of string
  1226.  is name.  Fails if can't connect, else ACKs (with name) and succeeds. 
  1227. */
  1228.  
  1229. cwd(vdir) char *vdir; {
  1230.     char *cdd, *zgtdir();
  1231.     char *dirp;
  1232. #ifdef DTILDE
  1233.     char *tilde_expand();
  1234. #endif
  1235.  
  1236.     vdir[xunchar(*vdir) + 1] = '\0';    /* Terminate string with a null */
  1237.  
  1238.     dirp = vdir+1;
  1239. #ifdef DTILDE
  1240.     dirp = tilde_expand(vdir+1);    /* Attempt to expand tilde */
  1241.     if (*dirp == '\0') dirp = vdir+1;    /* in directory name. */
  1242. #endif
  1243.     tlog(F110,"Directory requested: ",dirp,01);
  1244.     if (zchdir(dirp)) {
  1245.     cdd = zgtdir();            /* Get new working directory. */
  1246.     tlog(F110,"Changed directory to ",cdd,01);
  1247.     encstr(cdd);
  1248.     ack1(encbuf);
  1249.     tlog(F110,"Changed directory to",cdd,0l);
  1250.     return(1); 
  1251.     } else {
  1252.     tlog(F110,"Failed to change directory to",dirp,0l);
  1253.     return(0);
  1254.     }
  1255. }
  1256.  
  1257.  
  1258. /*  S Y S C M D  --  Do a system command  */
  1259.  
  1260. /*  Command string is formed by concatenating the two arguments.  */
  1261.  
  1262. syscmd(prefix,suffix) char *prefix, *suffix; {
  1263.     char *cp;
  1264.  
  1265.     if (prefix == NULL || *prefix == '\0') return(0);
  1266.  
  1267. #ifdef datageneral
  1268. /* A kludge for now -- the real change needs to be done elsewhere... */
  1269.     {
  1270.     extern char *WHOCMD;
  1271.     if ((strcmp(prefix,WHOCMD) == 0) && (*suffix == 0))
  1272.       strcpy(suffix,"[!pids]");
  1273.     }
  1274. #endif
  1275.     for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
  1276.     while (*cp++ = *suffix++) ;
  1277.  
  1278.     debug(F110,"syscmd",cmdstr,0);
  1279.     if (zopeni(ZSYSFN,cmdstr) > 0) {
  1280.     debug(F100,"syscmd zopeni ok",cmdstr,0);
  1281.     nfils = sndsrc = 0;        /* Flag that input is from stdin */
  1282.     xflg = hcflg = 1;        /* And special flags for pipe */
  1283.     if (binary) {            /* If file mode is binary, */
  1284.         binary = 0;            /*  turn it back to text for this, */
  1285.         savmod = 1;            /*  remember to restore it later. */
  1286.     }
  1287.     return (sinit());        /* Send S packet */
  1288.     } else {
  1289.     debug(F100,"syscmd zopeni failed",cmdstr,0);
  1290.     return(0);
  1291.     }
  1292. }
  1293.  
  1294. /*  R E M S E T  --  Remote Set  */
  1295. /*  Called by server to set variables as commanded in REMOTE SET packets.  */
  1296. /*  Returns 1 on success, 0 on failure.  */
  1297.  
  1298. remset(s) char *s; {
  1299.     int len, i, x, y;
  1300.     char *p;
  1301.  
  1302.     len = xunchar(*s++);        /* Length of first field */
  1303.     p = s + len;            /* Pointer to second length field */
  1304.     len = xunchar(*p);            /* Length of second field */
  1305.     *p++ = '\0';            /* Zero out second length field */
  1306.     x = atoi(s);            /* Value of first field */
  1307.     debug(F111,"remset",s,x);
  1308.     debug(F110,"remset",p,0);
  1309.     switch (x) {            /* Do the right thing */
  1310.       case 132:                /* Attributes (all, in) */
  1311.     atcapr = atoi(p);
  1312.     return(1);
  1313.       case 232:                /* Attributes (all, out) */
  1314.     atcapr = atoi(p);
  1315.     return(1);
  1316.       case 300:                /* File type (text, binary) */
  1317.     binary = atoi(p);
  1318.     return(1);
  1319.       case 301:                /* File name conversion */
  1320.     fncnv = 1 - atoi(p);        /* (oops) */
  1321.     return(1);
  1322.       case 302:                /* File name collision */
  1323.     switch (atoi(p)) {
  1324.       case 0: warn = 1; return(1);    /* Rename */
  1325.       case 1: warn = 0; return(1);    /* Replace */
  1326.       default: return(0);
  1327.     }
  1328.       case 310:                /* Incomplete File Disposition */
  1329.     keep = atoi(p);            /* Keep, Discard */
  1330.     return(0);
  1331.       case 400:                /* Block check */
  1332.     y = atoi(p);
  1333.     if (y < 4 && y > 0) {
  1334.         bctr = y;
  1335.         return(1);
  1336.     } else return(0);
  1337.       case 401:                /* Receive packet-length */
  1338.     urpsiz = atoi(p);
  1339.     if ((urpsiz * wslotsr) > BIGRBUFSIZ) urpsiz = BIGRBUFSIZ / wslotsr - 1;
  1340.     return(1);
  1341.       case 402:                /* Receive timeout */
  1342.     y = atoi(p);
  1343.     if (y > -1 && y < 95) {
  1344.         timef = 1;
  1345.         timint = y;
  1346.         return(1);
  1347.     } else return(0);
  1348.       case 403:                /* Retry limit */
  1349.     y = atoi(p);
  1350.     if (y > -1 && y < 95) {
  1351.         maxtry = y;
  1352.         return(1);
  1353.     } else return(0);
  1354.       case 404:                /* Server timeout */
  1355.     y = atoi(p);
  1356.     if (y < 0) return(0);
  1357.     srvtim = y;
  1358.     return(1);
  1359.       case 405:                /* Transfer character set */
  1360.     for (i = 0; i < ntcsets; i++) { 
  1361.         if (!strcmp(tcsinfo[i].designator,p)) break;
  1362.     }
  1363.     debug(F101,"remset xfer charset lookup","",i);
  1364.     if (i == ntcsets) return(0);
  1365.     tcharset = tcsinfo[i].code;    /* if known, use it */
  1366.     rx = xlr[tcharset][fcharset];    /* translation function */
  1367.     return(1);
  1368.       case 406:                /* Window slots */
  1369.     y = atoi(p);
  1370.     if (y == 0) y = 1;
  1371.     if (y < 1 && y > 31) return(0);
  1372.     wslotsr = y;
  1373.     swcapr = 1;
  1374.     if ((urpsiz * wslotsr) > BIGRBUFSIZ) urpsiz = BIGRBUFSIZ / wslotsr - 1;
  1375.     return(1);
  1376.       default:                /* Anything else... */
  1377.     return(0);
  1378.     }
  1379. }
  1380.  
  1381.