home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / convergent / ctfns.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  24KB  |  839 lines

  1. char *fnsv = "Protocol support functions CTOS Version-1.01, Fall 1987";
  2.  
  3. /*  C K F N S  --  System-independent Kermit protocol support functions...  */
  4.  
  5. /*  ...Part 1 (others moved to ckfns2 to make this module small enough) */
  6.  
  7. /* Modification - Joel Dunn, 9/21/87
  8.    zchki returns an integer filesize, thus
  9.    it had problems for >32K.  Converted size
  10.    to Kbytes
  11. */
  12.  
  13. /*
  14.  System-dependent primitives defined in:
  15.  
  16.    ckx???.c -- terminal i/o
  17.    cxz???.c -- file i/o, directory structure
  18.  
  19. */
  20.  
  21. #include "ctermi.h"            /* Symbol definitions for Kermit */
  22.  
  23. /* Externals from ckmain.c */
  24.  
  25. extern int spsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg, capas;
  26.  
  27. extern int pktnum, prvpkt, sndtyp, fsize, bctr, bctu,
  28.   size, osize, maxsize, spktl, nfils, stdouf, warn, timef;
  29.  
  30. extern int parity, speed, turn, turnch, 
  31.  delaytime, displa, pktlog, tralog, seslog, xflg, mypadn;
  32.  
  33. extern long filcnt, ffc, flci, flco, tlci, tlco, tfc;
  34.  
  35. extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
  36.  
  37. extern char padch, mypadc, reol, eol, ctlq, myctlq, sstate, *hlptxt;
  38.  
  39. extern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, 
  40.  mystch;
  41.  
  42. extern char *cmarg, *cmarg2, **cmlist;
  43. char *strcpy();
  44.  
  45. /* Variables local to this module */
  46.  
  47. static char *memptr;            /* Pointer for memory strings */
  48.  
  49. static char cmdstr[100];        /* Unix system command string */
  50.  
  51. static int  sndsrc;            /* Flag for where to send from: */
  52.                     /* -1: name in cmdata */
  53.                     /*  0: stdin          */
  54.                     /* >0: list in cmlist */
  55.  
  56. static int  memstr,            /* Flag for input from memory string */
  57.      t,                    /* Current character */
  58.      next;                /* Next character */
  59.  
  60. /*  E N C S T R  --  Encode a string from memory. */
  61.  
  62. /*  Call this instead of getpkt() if source is a string, rather than a file. */
  63.  
  64. encstr(s) char* s; {
  65.     int m; char *p;
  66.  
  67.     m = memstr; p = memptr;        /* Save these. */
  68.  
  69.     memptr = s;                /* Point to the string. */
  70.     memstr = 1;                /* Flag memory string as source. */
  71.     next = -1;                /* Initialize character lookahead. */
  72.     getpkt(spsiz);            /* Fill a packet from the string. */
  73.     memstr = m;                /* Restore memory string flag */
  74.     memptr = p;                /* and pointer */
  75.     next = -1;                /* Put this back as we found it. */
  76.     debug(F111,"encstr",data,size);
  77. }
  78.  
  79. /* E N C O D E - Kermit packet encoding procedure */
  80.  
  81. encode(a) int a; {            /* The current character */
  82.     int a7;                /* Low order 7 bits of character */
  83.     int b8;                /* 8th bit of character */
  84.     
  85.     if (rptflg)    {            /* Repeat processing? */
  86.         if (a == next) {        /* Got a run... */
  87.         if (++rpt < 94)        /* Below max, just count */
  88.                 return;
  89.         else if (rpt == 94) {    /* Reached max, must dump */
  90.                 data[size++] = rptq;
  91.                 data[size++] = tochar(rpt);
  92.                 rpt = 0;
  93.         }
  94.         } else if (rpt == 1) {        /* Run broken, only 2? */
  95.             rpt = 0;            /* Yes, reset repeat flag & count. */
  96.         encode(a);            /* Do the character twice. */
  97.         if (size <= maxsize) osize = size;
  98.         rpt = 0;
  99.         encode(a);
  100.         return;
  101.     } else if (rpt > 1) {        /* More than two */
  102.             data[size++] = rptq;    /* Insert the repeat prefix */
  103.             data[size++] = tochar(++rpt); /* and count. */
  104.             rpt = 0;            /* Reset repeat counter. */
  105.         }
  106.     }
  107.     a7 = a & 0177;            /* Isolate ASCII part */
  108.     b8 = a & 0200;            /* and 8th (parity) bit. */
  109.  
  110.     if (ebqflg && b8) {            /* Do 8th bit prefix if necessary. */
  111.         data[size++] = ebq;
  112.         a = a7;
  113.     }
  114.     if ((a7 < SP) || (a7==DEL))    {    /* Do control prefix if necessary */
  115.         data[size++] = myctlq;
  116.     a = ctl(a);
  117.     }
  118.     if (a7 == myctlq)            /* Prefix the control prefix */
  119.         data[size++] = myctlq;
  120.  
  121.     if ((rptflg) && (a7 == rptq))    /* If it's the repeat prefix, */
  122.         data[size++] = myctlq;        /* quote it if doing repeat counts. */
  123.  
  124.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th bit prefix */
  125.         data[size++] = myctlq;        /* if doing 8th-bit prefixes */
  126.  
  127.     data[size++] = a;            /* Finally, insert the character */
  128.     data[size] = '\0';            /* itself, and mark the end. */
  129. }
  130.  
  131. /* D E C O D E  --  Kermit packet decoding procedure */
  132.  
  133. /* Call with string to be decoded and an output function. */
  134.  
  135. decode(buf,fn) char *buf; int (*fn)(); {
  136.     unsigned int a, a7, b8;        /* Low order 7 bits, and the 8th bit */
  137.  
  138.     rpt = 0;
  139.  
  140.     while ((a = *buf++) != '\0') {
  141.     if (rptflg) {            /* Repeat processing? */
  142.         if (a == rptq) {        /* Yes, got a repeat prefix? */
  143.         rpt = unchar(*buf++);    /* Yes, get the repeat count, */
  144.         a = *buf++;        /* and get the prefixed character. */
  145.         }
  146.     }
  147.     b8 = 0;                /* Check high order "8th" bit */
  148.     if (ebqflg) {            /* 8th-bit prefixing? */
  149.         if (a == ebq) {        /* Yes, got an 8th-bit prefix? */
  150.         b8 = 0200;        /* Yes, remember this, */
  151.         a = *buf++;        /* and get the prefixed character. */
  152.         }
  153.     }
  154.     if (a == ctlq) {        /* If control prefix, */
  155.         a  = *buf++;        /* get its operand. */
  156.         a7 = a & 0177;        /* Only look at low 7 bits. */
  157.         if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */
  158.         a = ctl(a);            /* if in control range. */
  159.     }                       
  160.  
  161.     a |= b8;            /* OR in the 8th bit */
  162.     if (rpt == 0) rpt = 1;        /* If no repeats, then one */
  163.     for (; rpt > 0; rpt--) {    /* Output the char RPT times */
  164.         if (a == CR && !binary) break; /* But skip CR if binary. */
  165.         ffc++, tfc++;        /* Count the character */
  166.         (*fn)(a);            /* Send it to the output function. */
  167.     }
  168.     }
  169. }
  170.  
  171.  
  172. /*  Output functions passed to 'decode':  */
  173.  
  174. putsrv(c) char c; {     /*  Put character in server command buffer  */
  175.     *srvptr++ = c;
  176.     *srvptr = '\0';    /* Make sure buffer is null-terminated */
  177. }
  178.  
  179. puttrm(c) char c; {     /*  Output character to console.  */
  180.     conoc(c);
  181. }
  182.  
  183. putfil(c) char c; {    /*  Output char to file. */
  184.     zchout(ZOFILE,c);
  185. }
  186.  
  187. /*  G E T P K T -- Fill a packet data field  */
  188.  
  189. /*
  190.  Gets characters from the current source -- file or memory string.
  191.  Encodes the data into the packet, filling the packet optimally.
  192.  
  193.  Uses global variables:
  194.  t     -- current character.
  195.  next  -- next character.
  196.  data  -- the packet data buffer.
  197.  size  -- number of characters in the data buffer.
  198.  
  199. Returns the size as value of the function, and also sets global size,
  200. and fills (and null-terminates) the global data array.
  201.  
  202. Before calling getpkt the first time for a given source (file or string),
  203. set the variable 'next' to -1.
  204. */
  205.  
  206. getpkt(maxsize) int maxsize; {        /* Fill one packet buffer */
  207.     int i;                /* Loop index. */
  208.  
  209.     static char leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' };
  210.  
  211.     if (next < 0) t = getch();        /* Get first character of file. */
  212.  
  213.     /* Do any leftovers */
  214.  
  215.     for (size = 0; (data[size] = leftover[size]) != '\0'; size++)
  216.         ;
  217.     *leftover = '\0';
  218.  
  219.     /* Now fill up the rest of the packet. */
  220.  
  221.     while(t >= 0) {            /* Until EOF... */
  222.     next = getch();            /* Get next character for lookahead. */
  223.     osize = size;            /* Remember current position. */
  224.         encode(t);            /* Encode the current character. */
  225.         t = next;            /* Next is now current. */
  226.  
  227.     if (size == maxsize)         /* If the packet is exactly full, */
  228.             return(size);        /* and return. */
  229.  
  230.     if (size > maxsize) {        /* If too big, save some for next. */
  231.         for (i = 0; (leftover[i] = data[osize+i]) != '\0'; i++)
  232.             ;
  233.         size = osize;        /* Return truncated packet. */
  234.         data[size] = '\0';
  235.         return(size);
  236.     }
  237.     }
  238.     return(size);            /* Return any partial final buffer. */
  239. }
  240.  
  241. /*  G E T C H  -- Get the next character from file (or pipe). */
  242.  
  243. /*  Convert newlines to CRLFs if newline/CRLF mapping is being done. */
  244.  
  245. getch()    {                /* Get next character */
  246.     int a, x;                /* The character to return. */
  247.     static int b = 0;            /* A character to remember. */
  248.     
  249.     if (b > 0) {            /* Do we have a newline saved? */
  250.     b = 0;                /* Yes, return that. */
  251.     return('\n');
  252.     }
  253.  
  254.     if (memstr)                /* Try to get the next character */
  255.         x = ((a = *memptr++) == '\0');    /* from the appropriate source, */
  256.     else                /* memory or the current file. */
  257.         x = ((a = zchin(ZIFILE)) < 0 );
  258.  
  259.     if (x)
  260.         return(-1);            /* No more, return -1 for EOF. */
  261.     else {                /* Otherwise, read the next char. */
  262.     ffc++, tfc++;            /* Count it. */
  263.     if (a == '\n' && !binary) {    /* If nl and we must do nl-CRLF */
  264.         b = a;            /* mapping, save the nl, */
  265.         return(CR);            /* and return a CR. */
  266.     } else return(a);        /* General case, return the char. */
  267.     }
  268. }
  269.  
  270.  
  271. /*  C A N N E D  --  Check if current file transfer cancelled */
  272.  
  273. canned(buf) char *buf; {
  274.     if (*buf == 'X') cxseen = 1;
  275.     if (*buf == 'Z') czseen = 1;
  276.     debug(F101,"canned: cxseen","",cxseen);
  277.     debug(F101," czseen","",czseen);
  278.     return((czseen || cxseen) ? 1 : 0);
  279. }
  280.  
  281. /*  T I N I T  --  Initialize a transaction  */
  282.  
  283. tinit() {
  284.     xflg = 0;                /* reset x-packet flag */
  285.     memstr = 0;                /* reset memory-string flag */
  286.     memptr = NULL;            /*  and pointer */
  287.     bctu = 1;                /* reset block check type to 1 */
  288.     filcnt = 0;                /* reset file counter */
  289.     tfc = tlci = tlco = 0;        /* reset character counters */
  290.     prvpkt = -1;            /* reset packet number */
  291.     pktnum = 0;
  292.     if (server) {            /* If acting as server, */
  293.     timint = 30;            /* use 30 second timeout, */
  294.     nack();                /* send a NAK */
  295.     }
  296. }
  297.  
  298.  
  299. /*  R I N I T  --  Respond to S packet  */
  300.  
  301. rinit(d) char *d; {
  302.     char *tp;
  303.     ztime(&tp);
  304.     tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */
  305.     tfc = tlci = tlco = 0;
  306.     spar(d);
  307.     rpar(d);
  308.     ack1(d);
  309. }
  310.  
  311. /*  S I N I T  --  Make sure file exists, then send Send-Init packet */
  312.  
  313. sinit() {
  314.     int x; char *tp;
  315.  
  316.     sndsrc = nfils;            /* Where to look for files to send */
  317.     ztime(&tp);
  318.     tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */
  319.     debug(F101,"sinit: sndsrc","",sndsrc);
  320.     if (sndsrc < 0) {            /* Must expand from 'send' command */
  321.     nfils = zxpand(cmarg);        /* Look up literal name. */
  322.     if (nfils < 0) {
  323.         screen(2,0l,"?Too many files");
  324.         return(0);
  325.         } else if (nfils == 0) {    /* If none found, */
  326.         char xname[100];        /* convert the name. */
  327.         zrtol(cmarg,xname);
  328.         nfils = zxpand(xname);     /* Look it up again. */
  329.     }
  330.     if (nfils < 1) {        /* If no match, report error. */
  331.         if (server) 
  332.             errpkt("File not found");
  333.         else
  334.         screen(2,0l,"?File not found");
  335.         return(0);
  336.     }
  337.     x = gnfile();            /* Position to first file. */
  338.     if (x < 1) {
  339.         if (!server) 
  340.             screen(2,0l,"?No readable file to send");
  341.             else
  342.             errpkt("No readable file to send");
  343.         return(0);
  344.         } 
  345.     } else if (sndsrc > 0) {        /* Command line arglist -- */
  346.     x = gnfile();            /* Get the first file from it. */
  347.     if (x < 1) return(0);        /* (if any) */
  348.     } else if (sndsrc == 0) {        /* stdin or memory always exist... */
  349.     cmarg2 = "";            /* No alternate name */
  350.     strcpy(filnam,"stdin");        /* If F packet, filnam is used. */
  351.     tlog(F110,"Sending from",cmdstr,0l); /* If X packet, cmdstr is used. */
  352.     }
  353.  
  354.     debug(F101,"sinit: nfils","",nfils);
  355.     debug(F110," filnam",filnam,0);
  356.     debug(F110," cmdstr",cmdstr,0);
  357.     ttflui();                /* Flush input buffer. */
  358.     x = rpar(data);            /* Send a Send-Init packet. */
  359.     if (!local && !server) delay(delaytime * 10);
  360.     spack('S',pktnum,x,data);
  361.     return(1);
  362. }
  363.  
  364. sipkt() {
  365.     int x;
  366.     x = rpar(data);            /* Send an I-Packet. */
  367.     spack('I',pktnum,x,data);
  368. }
  369.  
  370. /*  R C V F I L -- Receive a file  */
  371.  
  372. rcvfil() {
  373.     int x;
  374.     ffc = flci = flco = 0;        /* Init per-file counters */
  375.     srvptr = srvcmd;            /* Decode packet data. */
  376.     decode(data,putsrv);
  377.     screen(0,0l,srvcmd);            /* Update screen */
  378.     screen(1,0l,"=> ");
  379.     tlog(F110,"Receiving",srvcmd,0l);    /* Transaction log entry */
  380.     if (cmarg2 != NULL) {               /* Check for alternate name */
  381.         if (*cmarg2 != '\0') {
  382.             strcpy(srvcmd,cmarg2);    /* Got one, use it. */
  383.         *cmarg2 = '\0';
  384.         }
  385.     }
  386.     x = openo(srvcmd,filnam);        /* Try to open it */
  387.     if (x) {
  388.     tlog(F110," as",filnam,0l);
  389.     screen(2,0l,filnam);
  390.     intmsg(++filcnt);
  391.     } else {
  392.         tlog(F110,"Failure to open",filnam,0l);
  393.     screen(2,0l,"*** error");
  394.     }
  395.     return(x);                /* Pass on return code from openo */
  396. }
  397.  
  398. /*  R E O F  --  Receive End Of File  */
  399.  
  400. reof() {
  401.  
  402.     if (cxseen == 0) cxseen = (*data == 'D');
  403.     clsof();
  404.     if (cxseen || czseen) {
  405.     tlog(F100," *** Discarding","",0l);
  406.     } else {
  407.     tlog(F100," end of file","",0l);
  408.     tlog(F101,"  file characters        ","",ffc);
  409.     tlog(F101,"  communication line in  ","",flci);
  410.     tlog(F101,"  communication line out ","",flco);
  411.     }
  412. }
  413.  
  414. /*  R E O T  --  Receive End Of Transaction  */
  415.  
  416. reot() {
  417.     char *tp;
  418.     cxseen = czseen = 0; 
  419.     ztime(&tp);
  420.     tlog(F110,"End of transaction",tp,0l);
  421.     if (filcnt > 1) {
  422.     tlog(F101," files","",filcnt);
  423.     tlog(F101," total file characters   ","",tfc);
  424.     tlog(F101," communication line in   ","",tlci);
  425.     tlog(F101," communication line out  ","",tlco);
  426.     }
  427. }
  428.  
  429. /*  S F I L E -- Send File header packet for global "filnam" */
  430.  
  431. sfile() {
  432.     char pktnam[100];            /* Local copy of name */
  433.  
  434.     if (fncnv) {
  435.     if (*cmarg2 != '\0') {        /* If we have a send-as name, */
  436.         zltor(cmarg2,pktnam);    /* convert it to common form, */
  437.         cmarg2 = "";        /* and blank it out for next time, */
  438.     } else zltor(filnam,pktnam);    /* otherwise use the real file name. */
  439.     } else {
  440.     if (*cmarg2 != '\0')        /* Same as above, but without */
  441.         strcpy(pktnam,cmarg2);    /* name conversion */
  442.         else strcpy(filnam,pktnam);
  443.     }
  444.  
  445.     debug(F110,"sfile",filnam,0);
  446.     if (openi(filnam) == 0)         /* Try to open the file */
  447.     return(0);         
  448.  
  449.     rpt = flci = flco = ffc = 0;    /* OK, Init counters, etc. */
  450.     encstr(pktnam);            /* Encode the name. */
  451.     nxtpkt(&pktnum);            /* Increment the packet number */
  452.     ttflui();                /* Clear pending input */
  453.     spack('F',pktnum,size,data);     /* Send the F packet */
  454.     if (displa) {
  455.     screen(0,(long)pktnum,filnam);    /* Update screen */
  456.     screen(1,0l,"=> ");
  457.     screen(1,0l,pktnam);
  458.     screen(3,(long)fsize,", size in Kbytes");
  459.     intmsg(++filcnt);        /* Count file, give interrupt msg */
  460.     }
  461.     tlog(F110,"Sending",filnam,0l);    /* Transaction log entry */
  462.     tlog(F110," as",pktnam,0l);
  463.     next = -1;                /* Init file character lookahead. */
  464.     return(1);
  465. }
  466.  
  467.  
  468. /* Send an X Packet -- Like SFILE, but with Text rather than File header */
  469.  
  470. sxpack() {                /* Send an X packet */
  471.     debug(F110,"sxpack",cmdstr,0);
  472.     encstr(cmdstr);            /* Encode any data. */
  473.     rpt = flci = flco = ffc = 0;    /* Init counters, etc. */
  474.     next = -1;                /* Init file character lookahead. */
  475.     nxtpkt(&pktnum);            /* Increment the packet number */
  476.     spack('X',pktnum,size,data);    /* No incrementing pktnum */
  477.     screen(0,(long)pktnum,cmdstr);        /* Update screen. */
  478.     intmsg(++filcnt);
  479.     tlog(F110,"Sending from:",cmdstr,0l);
  480.     return(1);
  481. }
  482.  
  483. /*  S D A T A -- Send a data packet */
  484.  
  485. sdata() {
  486.     int len;
  487.     if (cxseen || czseen) return(0);    /* If interrupted, done. */
  488.     if ((len = getpkt(spsiz-chklen-3)) == 0) return(0); /* If no data, done. */
  489.     nxtpkt(&pktnum);            /* Increment the packet number */
  490.     spack('D',pktnum,len,data);        /* Send the packet */
  491.     return(1);
  492. }
  493.  
  494.  
  495. /*  S E O F -- Send an End-Of-File packet */
  496.  
  497. seof() {
  498.     nxtpkt(&pktnum);            /* Increment the packet number */
  499.     if (czseen || cxseen) {
  500.     spack('Z',pktnum,1,"D");
  501.     tlog(F100," *** interrupted, sending discard request","",0l);
  502.     } else {
  503.     spack('Z',pktnum,0,"");
  504.     tlog(F100," end of file","",0l);
  505.     tlog(F101,"  file characters        ","",ffc);
  506.     tlog(F101,"  communication line in  ","",flci);
  507.     tlog(F101,"  communication line out ","",flco);
  508.     }
  509. }
  510.  
  511.  
  512. /*  S E O T -- Send an End-Of-Transaction packet */
  513.  
  514. seot() {
  515.     char *tp;
  516.     nxtpkt(&pktnum);            /* Increment the packet number */
  517.     spack('B',pktnum,0,"");
  518.     cxseen = czseen = 0; 
  519.     ztime(&tp);
  520.     tlog(F110,"End of transaction",tp,0l);
  521.     if (filcnt > 1) {
  522.     tlog(F101," files","",filcnt);
  523.     tlog(F101," total file characters   ","",tfc);
  524.     tlog(F101," communication line in   ","",tlci);
  525.     tlog(F101," communication line out  ","",tlco);
  526.     }
  527. }
  528.  
  529. /*   R P A R -- Fill the data array with my send-init parameters  */
  530.  
  531. rpar(data) char data[]; {
  532.     data[0] = tochar(spsiz);        /* Biggest packet I can receive */
  533.     data[1] = tochar(URTIME);        /* When I want to be timed out */
  534.     data[2] = tochar(mypadn);        /* How much padding I need (none) */
  535.     data[3] = ctl(mypadc);        /* Padding character I want */
  536.     data[4] = tochar(reol);    /* End-Of-Line character I want to receive*/
  537.     data[5] = CTLQ;            /* Control-Quote character I send */
  538.     if (ebqflg) data[6] = ebq = '&';
  539.         else data[6] = 'Y';        /* 8-bit quoting */
  540.     data[7] = bctr + '0';        /* Block check type */
  541.     data[8] = MYRPTQ;            /* Do repeat counts */
  542.     data[9] = '\0';
  543.     return(9);                /* Return the length. */
  544. }
  545.  
  546. /*   S P A R -- Get the other system's Send-Init parameters.  */
  547.  
  548. spar(data) char data[]; {
  549.     int len, x, savlen;
  550.  
  551.     len = strlen(data);                /* Number of fields */
  552.     savlen = len;
  553.  
  554.     spsiz = (len-- > 0) ? unchar(data[0]) : DSPSIZ;     /* Packet size */
  555.     if (spsiz < 10) spsiz = DSPSIZ;
  556.  
  557.     x = (len-- > 0) ? unchar(data[1]) : DMYTIM;    /* Timeout */
  558.     if (!timef) {            /* Only use if not overridden */
  559.     timint = x;
  560.     if (timint < 0) timint = DMYTIM;
  561.     }
  562.  
  563.     npad = 0; padch = '\0';                        /* Padding */
  564.     if (len-- > 0) {
  565.     npad = unchar(data[2]);
  566.     if (len-- > 0) padch = ctl(data[3]); else padch = 0;
  567.     }
  568.  
  569.     eol = (len-- > 0) ? unchar(data[4]) : '\r';            /* Terminator  */
  570.     if ((eol < 2) || (eol > 037)) eol = '\r';
  571.  
  572.     ctlq = (len-- > 0) ? data[5] : CTLQ;                /* Control prefix */
  573.  
  574.     if (len-- > 0) {                            /* 8th-bit prefix */
  575.     ebq = data[6];
  576.     if ((ebq > 040 && ebq < 0100) || (ebq > 0140 && ebq < 0177)) {
  577.         ebqflg = 1;
  578.     } else if (parity && (ebq == 'Y')) {
  579.         ebqflg = 1;
  580.         ebq = '&';
  581.     } else if (ebq == 'N') {
  582.         ebqflg = 0;
  583.     } else ebqflg = 0;
  584.     } else ebqflg = 0;
  585.  
  586.     chklen = 1;                                /* Block check */
  587.     if (len-- > 0) {
  588.     chklen = data[7] - '0';
  589.     if ((chklen < 1) || (chklen > 3)) chklen = 1;
  590.     }
  591.     bctr = chklen;
  592.  
  593.     if (len-- > 0) {                            /* Repeat prefix */
  594.     rptq = data[8]; 
  595.     rptflg = ((rptq > 040 && rptq < 0100) || (rptq > 0140 && rptq < 0177));
  596.     } else rptflg = 0;
  597.  
  598.     if (deblog) sdebu(savlen);
  599. }
  600.  
  601. /*  S D E B U  -- Record spar results in debugging log  */
  602.  
  603. sdebu(len) int len; {
  604.     debug(F111,"spar: data",data,len);
  605.     debug(F101," spsiz ","",spsiz);
  606.     debug(F101," timint","",timint);
  607.     debug(F101," npad  ","",npad);
  608.     debug(F101," padch ","",padch);
  609.     debug(F101," eol   ","",eol);
  610.     debug(F101," ctlq  ","",ctlq);
  611.     debug(F101," ebq   ","",ebq);
  612.     debug(F101," ebqflg","",ebqflg);
  613.     debug(F101," chklen","",chklen);
  614.     debug(F101," rptq  ","",rptq);
  615.     debug(F101," rptflg","",rptflg);
  616. }
  617.  
  618. /*  G N F I L E  --  Get the next file name from a file group.  */
  619.  
  620. /*  Returns 1 if there's a next file, 0 otherwise  */
  621.  
  622. gnfile() {
  623.     int x, y;
  624.  
  625. /* If file group interruption (C-Z) occured, fail.  */
  626.  
  627.     debug(F101,"gnfile: czseen","",czseen);
  628.  
  629.     if (czseen) {
  630.     tlog(F100,"Transaction cancelled","",0l);
  631.     return(0);
  632.     }
  633.  
  634. /* If input was stdin or memory string, there is no next file.  */
  635.  
  636.     if (sndsrc == 0) return(0);
  637.  
  638. /* If file list comes from command line args, get the next list element. */
  639.  
  640.     y = -1;
  641.     while (y < 0) {            /* Keep trying till we get one... */
  642.  
  643.     if (sndsrc > 0) {
  644.         if (nfils-- > 0) {
  645.         strcpy(filnam,*cmlist++);
  646.         debug(F111,"gnfile: cmlist filnam",filnam,nfils);
  647.         } else {
  648.         *filnam = '\0';
  649.         debug(F101,"gnfile cmlist: nfils","",nfils);
  650.         return(0);
  651.         }
  652.     }
  653.  
  654. /* Otherwise, step to next element of internal wildcard expansion list. */
  655.  
  656.     if (sndsrc < 0) {
  657.         x = znext(filnam);
  658.         debug(F111,"gnfile znext: filnam",filnam,x);
  659.         if (x == 0) return(0);
  660.     }
  661.  
  662. /* Get here with a filename. */
  663.  
  664.     y = zchki(filnam);        /* Check if file readable */
  665.     if (y < 0) {
  666.         debug(F110,"gnfile skipping:",filnam,0);
  667.         tlog(F111,filnam,"not sent, reason",(long)y);
  668.         screen(0,0l,"Skipping");
  669.         screen(2,0l,filnam);
  670.     } else fsize = y;
  671.     }        
  672.     return(1);
  673. }
  674.  
  675. /*  O P E N I  --  Open an existing file for input  */
  676.  
  677. openi(name) char *name; {
  678.     int x, filno;
  679.     if (memstr) return(1);        /* Just return if file is memory. */
  680.  
  681.     debug(F110,"openi",name,0);
  682.     debug(F101," sndsrc","",sndsrc);
  683.  
  684.     filno = (sndsrc == 0) ? ZSTDIO : ZIFILE;    /* ... */
  685.  
  686.     debug(F101," file number","",filno);
  687.  
  688.     if (zopeni(filno,name)) {        /* Otherwise, try to open it. */
  689.     debug(F110," ok",name,0);
  690.         return(1);
  691.     } else {                /* If not found, */
  692.     char xname[100];        /* convert the name */
  693.     zrtol(name,xname);        /* to local form and then */
  694.     debug(F110," zrtol:",xname,0);
  695.     x = zopeni(filno,xname);    /* try opening it again. */
  696.     debug(F101," zopeni","",x);
  697.     if (x) {
  698.         debug(F110," ok",xname,0);
  699.         return(1);            /* It worked. */
  700.         } else {
  701.         screen(2,0l,"Can't open file");  /* It didn't work. */
  702.         tlog(F110,xname,"could not be opened",0l);
  703.         debug(F110," openi failed",xname,0);
  704.         return(0);
  705.         }
  706.     }
  707. }
  708.  
  709. /*  O P E N O  --  Open a new file for output.  */
  710.  
  711. /*  Returns actual name under which the file was opened in string 'name2'. */
  712.  
  713. openo(name,name2) char *name, *name2; {
  714.     char xname[100], *xp;
  715.  
  716.     if (stdouf)                /* Receiving to stdout? */
  717.     return(zopeno(ZSTDIO,""));
  718.  
  719.     debug(F110,"openo: name",name,0);
  720.  
  721.     xp = xname;
  722.     if (fncnv)                /* If desired, */
  723.         zrtol(name,xp);            /* convert name to local form */
  724.     else                /* otherwise, */
  725.         strcpy(xname,name);        /* use it literally */
  726.  
  727.     debug(F110,"openo: xname",xname,0);
  728.  
  729.     if (warn) {                /* File collision avoidance? */
  730.     if (zchki(xname) != -1) {    /* Yes, file exists? */
  731.         znewn(xname,&xp);        /* Yes, make new name. */
  732.         strcpy(xname,xp);
  733.         debug(F110," exists, new name ",xname,0);
  734.         }
  735.     }
  736.     if (zopeno(ZOFILE,xname) == 0) {    /* Try to open the file */
  737.     debug(F110,"openo failed",xname,0);
  738.     tlog(F110,"Failure to open",xname,0l);
  739.     return(0);
  740.     } else {
  741.     strcpy(name2,xname);
  742.     debug(F110,"openo ok, name2",name2,0);
  743.     return(1);
  744.     }
  745. }
  746.  
  747. /*  O P E N T  --  Open the terminal for output, in place of a file  */
  748.  
  749. opent() {
  750.     ffc = tfc = 0;
  751.     return(zopeno(ZCTERM,""));
  752. }
  753.  
  754. /*  C L S I F  --  Close the current input file. */
  755.  
  756. clsif() {
  757.     if (memstr) {            /* If input was memory string, */
  758.     memstr = 0;            /* indicate no more. */
  759.     } else if (hcflg) {
  760.     zclosf();            /* If host cmd close fork, */
  761.     } else zclose(ZIFILE);        /* else close input file. */
  762.  
  763.     screen(1,0l," [OK]");
  764.     hcflg = cxseen = 0;            /* Reset flags. */
  765. }
  766.  
  767.  
  768. /*  C L S O F  --  Close an output file.  */
  769.  
  770. clsof() {
  771.     zclose(ZOFILE);            /* Close it. */
  772.     if (czseen || cxseen) {
  773.     zdelet(filnam);           /* Delete it if interrupted. */
  774.     debug(F100,"Discarded","",0);
  775.     tlog(F100,"Discarded","",0l);
  776.     screen(1,0l," [Discarded]");
  777.     } else {
  778.     debug(F100,"Closed","",0);
  779.     screen(1,0l," [OK]");
  780.     }
  781.     cxseen = 0;
  782. }
  783.  
  784. /*  S N D H L P  --  Routine to send builtin help  */
  785.  
  786. sndhlp() {
  787.     nfils = 0;                /* No files, no lists. */
  788.     xflg = 1;                /* Flag we must send X packet. */
  789.     strcpy(cmdstr,"help text");        /* Data for X packet. */
  790.     next = -1;                /* Init getch lookahead */
  791.     memstr = 1;                /* Just set the flag. */
  792.     memptr = hlptxt;            /* And the pointer. */
  793.     return(sinit());
  794. }
  795.  
  796.  
  797. /*  C W D  --  Change current working directory  */
  798.  
  799. /*
  800.  String passed has first byte as length of directory name, rest of string
  801.  is name.  Fails if can't connect, else ACKs (with name) and succeeds. 
  802. */
  803.  
  804. cwd(vdir) char *vdir; {
  805.     vdir[unchar(*vdir) + 1] = '\0';    /* End with a null */
  806.     if (zchdir(vdir+1)) {
  807.     encstr(vdir+1);
  808.     ack1(data);
  809.     tlog(F110,"Changed directory to",vdir+1,0l);
  810.     return(1); 
  811.     } else {
  812.     tlog(F110,"Failed to change directory to",vdir+1,0l);
  813.     return(0);
  814.     }
  815. }
  816.  
  817.  
  818. /*  S Y S C M D  --  Do a system command  */
  819.  
  820. /*  Command string is formed by concatenating the two arguments.  */
  821.  
  822. syscmd(prefix,suffix) char *prefix, *suffix; {
  823.     char *cp;
  824.  
  825.     for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
  826.     while (*cp++ = *suffix++) ;
  827.  
  828.     debug(F110,"syscmd",cmdstr,0);
  829.     if (zxcmd(cmdstr) > 0) {
  830.     debug(F100,"zxcmd ok","",0);
  831.     nfils = sndsrc = 0;        /* Flag that input from stdin */
  832.     xflg = hcflg = 1;        /* And special flags for pipe */
  833.     return (sinit());        /* Send S packet */
  834.     } else {
  835.     debug(F100,"zxcmd failed","",0);
  836.     return(0);
  837.     }
  838. }
  839.