home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / archimedes / arcfns.c < prev    next >
C/C++ Source or Header  |  1993-04-30  |  31KB  |  1,041 lines

  1. /* -> c.ckcfns
  2.  */
  3.  
  4. char *fnsv = "Arthur-Kermit functions (based on C-Kermit 4C(039)) 19 Dec 85";
  5.  
  6. /*  C K C F N S  --  System-independent Kermit protocol support functions.  */
  7.  
  8. /*  ...Part 1 (others moved to ckcfn2 to make this module small enough) */
  9. /*
  10.  Author: Frank da Cruz (SY.FDC@CU20B),
  11.  Columbia University Center for Computing Activities, January 1985.
  12.  Copyright (C) 1985, Trustees of Columbia University in the City of New York.
  13.  Permission is granted to any individual or institution to use, copy, or
  14.  redistribute this software so long as it is not sold for profit, provided
  15.  this copyright notice is retained. 
  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.  
  24. #include "ckcdeb.h"         /* Debug formats, typedefs, etc. */
  25. #include "ckcker.h"         /* Symbol definitions for Kermit */
  26.  
  27.  
  28. #ifdef ANSI
  29. #include <string.h>
  30. #include "ckafio.h"
  31. #include "ckatio.h"
  32. #include "ckuusr.h"
  33. #include "ckamis.h"
  34. #endif
  35.  
  36. #ifndef NULL
  37. #define NULL 0
  38. #endif
  39.  
  40. /* Externals from ckcmai.c */
  41. extern int spsiz, rpsiz, timint, rtimo, npad, chklen, ebq, ebqflg, rpt, rptq,
  42.  rptflg, capas;
  43. extern int pktnum, prvpkt, sndtyp, bctr, bctu,
  44.  size, osize, maxsize, spktl, nfils, stdouf, warn, timef;
  45. extern int parity, speed, turn, turnch, 
  46.  delay, displa, pktlog, tralog, seslog, xflg, mypadn;
  47. extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize;
  48. extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
  49. extern char padch, mypadc, eol, ctlq, myctlq, sstate, *hlptxt;
  50. extern char filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr, 
  51.  mystch;
  52. extern char *cmarg, *cmarg2, **cmlist;
  53.  
  54. #ifndef ANSI
  55. long zchki();
  56. #endif
  57.  
  58. #ifndef ANSI
  59. char *strcpy();
  60. #endif
  61.  
  62. #ifdef ANSI
  63. extern int getpkt( int );
  64. extern int getch( void );
  65. extern int gnfile( void );
  66. extern int openo( char *, char * );
  67. extern int openi( char * );
  68. extern int rpar( char[] );
  69. extern void spar( char[] );
  70. extern void clsof( void );
  71. extern void sdebu( int );
  72.  
  73. /* Declarations for functions defined in c.ckcfn2 */
  74. extern void nack( void );
  75. extern void ack1( char * );
  76. extern void errpkt( char * );
  77. extern void spack( char, int, int, char * );
  78. extern void nxtpkt( int * );
  79. #endif
  80.  
  81. /* Variables local to this module */
  82.  
  83. static char *memptr;            /* Pointer for memory strings */
  84.  
  85. static char cmdstr[100];        /* Unix system command string */
  86.  
  87. static int  sndsrc;         /* Flag for where to send from: */
  88.                     /* -1: name in cmdata */
  89.                     /*  0: stdin          */
  90.                     /* >0: list in cmlist */
  91.  
  92. static int  memstr,         /* Flag for input from memory str. */
  93.      t,                 /* Current character */
  94.      next;              /* Next character */
  95.  
  96. /*  E N C S T R  --  Encode a string from memory. */
  97.  
  98. /*  Call this instead of getpkt() if source is a string, rather than a file */
  99.  
  100. #ifdef ANSI
  101. void
  102. #endif
  103. encstr(s) char* s; {
  104.     int m; char *p;
  105.  
  106.     m = memstr; p = memptr;     /* Save these. */
  107.     memptr = s;             /* Point to the string. */
  108.     memstr = 1;             /* Flag memory string as source. */
  109.     next = -1;              /* Initialize character lookahead. */
  110.     getpkt(spsiz);          /* Fill a packet from the string. */
  111.     memstr = m;             /* Restore memory string flag */
  112.     memptr = p;             /* and pointer */
  113.     next = -1;              /* Put this back as we found it. */
  114. }
  115.  
  116. /* E N C O D E - Kermit packet encoding procedure */
  117.  
  118. #ifdef ANSI
  119. void
  120. #endif
  121. encode(a) int a; {          /* The current character */
  122.     int a7;             /* Low order 7 bits of character */
  123.     int b8;             /* 8th bit of character */
  124.  
  125.     if (rptflg) {           /* Repeat processing? */
  126.         if (a == next) {        /* Got a run... */
  127.         if (++rpt < 94)     /* Below max, just count */
  128.                 return;
  129.         else if (rpt == 94) {   /* Reached max, must dump */
  130.                 data[size++] = rptq;
  131.                 data[size++] = tochar(rpt);
  132.                 rpt = 0;
  133.         }
  134.         } else if (rpt == 1) {      /* Run broken, only 2? */
  135.             rpt = 0;            /* Yes, reset repeat flag & count. */
  136.         encode(a);          /* Do the character twice. */
  137.         if (size <= maxsize) osize = size;
  138.         rpt = 0;
  139.         encode(a);
  140.         return;
  141.     } else if (rpt > 1) {       /* More than two */
  142.             data[size++] = rptq;    /* Insert the repeat prefix */
  143.             data[size++] = tochar(++rpt); /* and count. */
  144.             rpt = 0;            /* Reset repeat counter. */
  145.         }
  146.     }
  147.     a7 = a & 0177;          /* Isolate ASCII part */
  148.     b8 = a & 0200;          /* and 8th (parity) bit. */
  149.  
  150.     if (ebqflg && b8) {         /* Do 8th bit prefix if necessary. */
  151.         data[size++] = ebq;
  152.         a = a7;
  153.     }
  154.     if ((a7 < SP) || (a7==DEL)) {   /* Do control prefix if necessary */
  155.         data[size++] = myctlq;
  156.     a = ctl(a);
  157.     }
  158.     if (a7 == myctlq)           /* Prefix the control prefix */
  159.         data[size++] = myctlq;
  160.  
  161.     if ((rptflg) && (a7 == rptq))   /* If it's the repeat prefix, */
  162.         data[size++] = myctlq;      /* quote it if doing repeat counts. */
  163.  
  164.     if ((ebqflg) && (a7 == ebq))    /* Prefix the 8th bit prefix */
  165.         data[size++] = myctlq;      /* if doing 8th-bit prefixes */
  166.  
  167.     data[size++] = a;           /* Finally, insert the character */
  168.     data[size] = '\0';          /* itself, and mark the end. */
  169. }
  170.  
  171. /* D E C O D E  --  Kermit packet decoding procedure */
  172.  
  173. /* Call with string to be decoded and an output function. */
  174. /* Returns 0 on success, -1 on failure (e.g. disk full).  */
  175.  
  176. #ifdef ANSI
  177. int
  178. #endif
  179. decode(buf,fn) char *buf; int (*fn)(); {
  180.     unsigned int a, a7, b8;     /* Low order 7 bits and the 8th bit */
  181.  
  182.     rpt = 0;                /* Initialize repeat count. */
  183.     while ((a = *buf++) != '\0') {
  184.     if (rptflg) {           /* Repeat processing? */
  185.         if (a == rptq) {        /* Yes, got a repeat prefix? */
  186.         rpt = unchar(*buf++);   /* Yes, get the repeat count, */
  187.         a = *buf++;     /* and get the prefixed character. */
  188.         }
  189.     }
  190.     b8 = 0;             /* Check high order "8th" bit */
  191.     if (ebqflg) {           /* 8th-bit prefixing? */
  192.         if (a == ebq) {     /* Yes, got an 8th-bit prefix? */
  193.         b8 = 0200;      /* Yes, remember this, */
  194.         a = *buf++;     /* and get the prefixed character. */
  195.         }
  196.     }
  197.     if (a == ctlq) {        /* If control prefix, */
  198.         a  = *buf++;        /* get its operand. */
  199.         a7 = a & 0177;      /* Only look at low 7 bits. */
  200.         if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') /* Uncontrollify */
  201.         a = ctl(a);         /* if in control range. */
  202.     }
  203.     a |= b8;            /* OR in the 8th bit */
  204.     if (rpt == 0) rpt = 1;      /* If no repeats, then one */
  205. #ifdef NLCHAR
  206.     if (!binary) {          /* If in text mode, */
  207.         if (a == CR) continue;  /* discard carriage returns, */
  208.             if (a == LF) a = NLCHAR; /* convert LF to system's newline. */
  209.         }
  210. #endif
  211.     for (; rpt > 0; rpt--) {    /* Output the char RPT times */
  212.         ffc++, tfc++;       /* Count the character */
  213.         if ((*fn)(a) < 0) return(-1); /* Send it to the output fn. */
  214.     }
  215.     }
  216.     return(0);
  217. }
  218.  
  219.  
  220. /*  Output functions passed to 'decode':  */
  221.  
  222. #ifdef ANSI
  223. int
  224. #endif
  225. putsrv(c) char c; {     /*  Put character in server command buffer  */
  226.     *srvptr++ = c;
  227.     *srvptr = '\0'; /* Make sure buffer is null-terminated */
  228.     return(0);
  229. }
  230.  
  231. #ifdef ANSI
  232. int
  233. #endif
  234. puttrm(c) char c; {     /*  Output character to console.  */
  235.     conoc(c);
  236.     return(0);
  237. }
  238.  
  239. #ifdef ANSI
  240. int
  241. #endif
  242. putfil(c) char c; {         /*  Output char to file. */
  243.     if (zchout(ZOFILE,c) < 0) {
  244.     czseen = 1;             /* If write error... */
  245.     debug(F101,"putfil zchout write error, setting czseen","",1);
  246.     return(-1);
  247.     }
  248.     return(0);
  249. }
  250.  
  251. /*  G E T P K T -- Fill a packet data field  */
  252.  
  253. /*
  254.  Gets characters from the current source -- file or memory string.
  255.  Encodes the data into the packet, filling the packet optimally.
  256.  
  257.  Uses global variables:
  258.  t     -- current character.
  259.  next  -- next character.
  260.  data  -- the packet data buffer.
  261.  size  -- number of characters in the data buffer.
  262.  
  263. Returns the size as value of the function, and also sets global size,
  264. and fills (and null-terminates) the global data array.
  265.  
  266. Before calling getpkt the first time for a given source (file or string),
  267. set the variable 'next' to -1.
  268. */
  269.  
  270. #ifdef ANSI
  271. int
  272. #endif
  273. getpkt(maxsize) int maxsize; {      /* Fill one packet buffer */
  274.     int i;              /* Loop index. */
  275.  
  276.     static char leftover[6] = { '\0', '\0', '\0', '\0', '\0', '\0' };
  277.  
  278.     debug(F101,"getpkt, entering with next","",next);
  279.     debug(F101," t","",t);
  280.  
  281.     if (next < 0) {     /* If first time through, */
  282.     t = getch();        /* get first character of file, */
  283.     *leftover = '\0';       /* discard any interrupted leftovers. */
  284.     }
  285.     /* Do any leftovers */
  286.     for (size = 0; (data[size] = leftover[size]) != '\0'; size++);
  287.     *leftover = '\0';
  288.     /* Now fill up the rest of the packet. */
  289.     rpt = 0;                /* Clear out any old repeat count. */
  290.     while(t >= 0) {         /* Until EOF... */
  291.     next = getch();         /* Get next character for lookahead.*/
  292.     osize = size;           /* Remember current position. */
  293.         encode(t);          /* Encode the current character. */
  294.         t = next;           /* Next is now current. */
  295.     next = 0;           /* No more next. */
  296.     if (size == maxsize) {      /* If the packet is exactly full, */
  297.         debug(F101,"getpkt exact fit","",size);
  298.             return(size);       /* and return. */
  299.     }
  300.     if (size > maxsize) {       /* If too big, save some for next. */
  301.         for (i = 0; (leftover[i] = data[osize+i]) != '\0'; i++);
  302.         debug(F111,"getpkt leftover",leftover,size);
  303.         debug(F101," osize","",osize);
  304.         size = osize;       /* Return truncated packet. */
  305.         data[size] = '\0';
  306.         return(size);
  307.     }
  308.     }
  309.     debug(F101,"getpkt eof/eot","",size);
  310.     return(size);           /* Return any partial final buffer. */
  311. }
  312.  
  313. /*  G E T C H  -- Get the next character from file (or pipe). */
  314.  
  315. /*
  316.  On systems like Unix, the Macintosh, etc, that use a single character
  317.  (NLCHAR, defined in ckcdeb.h) to separate lines in text files, and
  318.  when in text/ascii mode (binary == 0), this function maps the newline
  319.  character to CRLF.  If NLCHAR is not defined, then this mapping is
  320.  not done, even in text mode.
  321. */
  322.  
  323. #ifdef ANSI
  324. int
  325. #endif
  326. getch() {               /* Get next character */
  327.     int x; CHAR a;          /* The character to return. */
  328.     static int b = 0;           /* A character to remember. */
  329.     
  330.     if (b > 0) {            /* Do we have a LF saved? */
  331.     b = 0;              /* Yes, return that. */
  332.     return(LF);
  333.     }
  334.  
  335.     if (memstr)             /* Try to get the next character */
  336.         x = ((a = *memptr++) == '\0');  /* from the appropriate source, */
  337.     else                /* memory or the current file. */
  338. #ifdef ANSI
  339.         x = (zchin(ZIFILE,(char*)&a) == -1);
  340. #else
  341.         x = (zchin(ZIFILE,&a) == -1);
  342. #endif
  343.  
  344.     if (x)
  345.         return(-1);         /* No more, return -1 for EOF. */
  346.     else {              /* Otherwise, read the next char. */
  347.     ffc++, tfc++;           /* Count it. */
  348. #ifdef NLCHAR
  349.     if (!binary && (a == NLCHAR)) { /* If nl and we must do nl-CRLF */
  350.         b = 1;          /* mapping, remember a linefeed, */
  351.         return(CR);         /* and return a carriage return. */
  352.     } else return(a);       /* General case, return the char. */
  353. #else
  354.         return(a);
  355. #endif
  356.     }
  357. }
  358.  
  359. /*  C A N N E D  --  Check if current file transfer cancelled */
  360.  
  361. #include <stdio.h>
  362.  
  363. #ifdef ANSI
  364. int
  365. #endif
  366. canned(buf) char *buf; {
  367.     if (*buf == 'X') cxseen = 1;
  368.     if (*buf == 'Z') czseen = 1;
  369.     debug(F101,"canned: cxseen","",cxseen);
  370.     debug(F101," czseen","",czseen);
  371.     return((czseen || cxseen) ? 1 : 0);
  372. }
  373.  
  374. /*  T I N I T  --  Initialize a transaction  */
  375.  
  376. #ifdef ANSI
  377. void
  378. #endif
  379. tinit() {
  380.     xflg = 0;               /* Reset x-packet flag */
  381.     memstr = 0;             /* Reset memory-string flag */
  382.     memptr = NULL;          /*  and pointer */
  383.     bctu = 1;               /* Reset block check type to 1 */
  384.     filcnt = 0;             /* Reset file counter */
  385.     tfc = tlci = tlco = 0;      /* Reset character counters */
  386.     prvpkt = -1;            /* Reset packet number */
  387.     pktnum = 0;
  388.     cxseen = czseen = 0;        /* Reset interrupt flags */
  389.     *filnam = '\0';         /* Clear file name */
  390.     if (server) {           /* If acting as server, */
  391.     timint = 30;            /* Use 30 second timeout, */
  392.     nack();             /* Send first NAK */
  393.     }
  394. }
  395.  
  396. /*  R I N I T  --  Respond to S packet  */
  397.  
  398. #ifdef ANSI
  399. void
  400. #endif
  401. rinit(d) char *d; {
  402.     char *tp;
  403.     ztime(&tp);
  404.     tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */
  405.     tfc = tlci = tlco = 0;
  406.     spar(d);
  407.     rpar(d);
  408.     ack1(d);
  409. }
  410.  
  411. /*  S I N I T  --  Make sure file exists, then send Send-Init packet */
  412.  
  413. #ifdef ANSI
  414. int
  415. #endif
  416. sinit() {
  417.     int x; char *tp;
  418.  
  419.     sndsrc = nfils;         /* Where to look for files to send */
  420.     ztime(&tp);
  421.     tlog(F110,"Transaction begins",tp,0l); /* Make transaction log entry */
  422.     debug(F101,"sinit: sndsrc","",sndsrc);
  423.     if (sndsrc < 0) {           /* Must expand from 'send' command */
  424.     nfils = zxpand(cmarg);      /* Look up literal name. */
  425.     if (nfils < 0) {
  426.         screen(SCR_EM,0,0l,"Too many files");
  427.         return(0);
  428.         } else if (nfils == 0) {    /* If none found, */
  429.         char xname[100];        /* convert the name. */
  430.         zrtol(cmarg,xname);
  431.         nfils = zxpand(xname);  /* Look it up again. */
  432.     }
  433.     if (nfils < 1) {        /* If no match, report error. */
  434.         if (server) 
  435.             errpkt("File not found");
  436.         else
  437.         screen(SCR_EM,0,0l,"File not found");
  438.         return(0);
  439.     }
  440.     x = gnfile();           /* Position to first file. */
  441.     if (x < 1) {
  442.         if (!server) 
  443.             screen(SCR_EM,0,0l,"No readable file to send");
  444.             else
  445.             errpkt("No readable file to send");
  446.         return(0);
  447.         } 
  448.     } else if (sndsrc > 0) {        /* Command line arglist -- */
  449.     x = gnfile();           /* Get the first file from it. */
  450.     if (x < 1) return(0);       /* (if any) */
  451.     } else if (sndsrc == 0) {       /* stdin or memory always exist... */
  452.     cmarg2 = "";            /* No alternate name */
  453.     strcpy(filnam,"stdin");     /* If F packet, filnam is used. */
  454.     tlog(F110,"Sending from",cmdstr,0l); /* If X packet, cmdstr is used */
  455.     }
  456.     debug(F101,"sinit: nfils","",nfils);
  457.     debug(F110," filnam",filnam,0);
  458.     debug(F110," cmdstr",cmdstr,0);
  459.  
  460.     ttflui();               /* Flush input buffer. */
  461.     x = rpar(data);         /* Send a Send-Init packet. */
  462.     if (!local && !server) sleep(delay);
  463.     spack('S',pktnum,x,data);
  464.     return(1);
  465. }
  466.  
  467. #ifdef ANSI
  468. void
  469. #endif
  470. sipkt() {
  471.     int x;
  472.     ttflui();               /* Flush pending input. */
  473.     x = rpar(data);         /* Send an I-Packet. */
  474.     spack('I',pktnum,x,data);
  475. }
  476.  
  477. /*  R C V F I L -- Receive a file  */
  478.  
  479. #include <stdio.h>
  480.  
  481. #ifdef ANSI
  482. int
  483. #endif
  484. rcvfil() {
  485.     int x, oldcnv;
  486.  
  487.     ffc = flci = flco = 0;      /* Init per-file counters */
  488.     srvptr = srvcmd;            /* Decode file name from packet. */
  489.     decode(data,&putsrv); /*BUG - add & */
  490.     screen(SCR_FN,0,0l,srvcmd);     /* Put it on screen */
  491.     tlog(F110,"Receiving",srvcmd,0l);   /* Transaction log entry */
  492.     oldcnv = fncnv;
  493.     if (cmarg2 != NULL) {               /* Check for alternate name */
  494.         if (*cmarg2 != '\0') {
  495.             fncnv = 0; /* Don't translate filename on open - take
  496.                           the name as supplied verbatim */
  497.             strcpy(srvcmd,cmarg2);  /* Got one, use it. */
  498.         *cmarg2 = '\0';
  499.         }
  500.     }
  501.     x = openo(srvcmd,filnam);       /* Try to open it */
  502.     fncnv = oldcnv;
  503.     if (x) {
  504.     tlog(F110," as",filnam,0l);
  505.  
  506.     screen(SCR_AN,0,0l,filnam);
  507.     intmsg(++filcnt);
  508.     } else {
  509.         tlog(F110,"Failure to open",filnam,0l);
  510.     screen(SCR_EM,0,0l,"Can't open file");
  511.     }
  512.     return(x);              /* Pass on return code from openo */
  513. }
  514.  
  515. /*  R E O F  --  Receive End Of File  */
  516.  
  517. #ifdef ANSI
  518. void
  519. #endif
  520. reof() {
  521.     if (cxseen == 0) cxseen = (*data == 'D');
  522.     clsof();
  523.     if (cxseen || czseen) {
  524.     tlog(F100," *** Discarding","",0l);
  525.     } else {
  526.     tlog(F100," end of file","",0l);
  527.     tlog(F101,"  file characters        ","",ffc);
  528.     tlog(F101,"  communication line in  ","",flci);
  529.     tlog(F101,"  communication line out ","",flco);
  530.     }
  531. }
  532.  
  533. /*  R E O T  --  Receive End Of Transaction  */
  534.  
  535. #ifdef ANSI
  536. void
  537. #endif
  538. reot() {
  539.     char *tp;
  540.     cxseen = czseen = 0; 
  541.     ztime(&tp);
  542.     tlog(F110,"End of transaction",tp,0l);
  543.     if (filcnt > 1) {
  544.     tlog(F101," files","",filcnt);
  545.     tlog(F101," total file characters   ","",tfc);
  546.     tlog(F101," communication line in   ","",tlci);
  547.     tlog(F101," communication line out  ","",tlco);
  548.     }
  549. }
  550.  
  551. /*  S F I L E -- Send File header packet for global "filnam" */
  552.  
  553. #include <stdio.h>
  554.  
  555.  
  556. #ifdef ANSI
  557. int
  558. #endif
  559. sfile( x )
  560. int x;
  561. {
  562.  
  563.     char pktnam[100];           /* Local copy of name */
  564.     char *s;
  565.  
  566.   if( x == 0 )          /* F-packet set-up */
  567.   {
  568.     if (*cmarg2 != '\0') {      /* If we have a send-as name, */
  569.     strcpy(pktnam,cmarg2);      /* copy it literally, */
  570.     cmarg2 = "";            /* and blank it out for next time. */
  571.     } else {                /* Otherwise use actual file name: */
  572.     if (fncnv) {            /* If converting names, */
  573.         zltor(filnam,pktnam);   /* convert it to common form, */
  574.     } else {            /* otherwise, */
  575.         strcpy(pktnam,filnam);  /* copy it literally. */
  576.         }
  577.     }
  578.     debug(F110,"sfile",filnam,0);
  579.     debug(F110," pktnam",pktnam,0);
  580.     if (openi(filnam) == 0)         /* Try to open the file */
  581.     return(0);      
  582.  
  583.     s = pktnam;
  584.  
  585.  }  else  {             /* X-packet set-up */
  586.  
  587.     debug( F110, "sxpack", cmdstr, 0 );
  588.     s = cmdstr;
  589.  
  590.  }
  591.  
  592.     flci = flco = ffc = 0;      /* OK, Init counters, etc. */
  593.     encstr(pktnam);         /* Encode the name. */
  594.     nxtpkt(&pktnum);            /* Increment the packet number */
  595.     ttflui();               /* Clear pending input */
  596.  
  597.     spack( x ? 'X' : 'F',pktnum,size,data);    /* Send the F or X packet */
  598.  
  599.   if( x == 0 )
  600.   {
  601.     if (displa) {
  602.     screen(SCR_FN,'F',(long)pktnum,filnam); /* Update screen */
  603.     screen(SCR_AN,0,0l,pktnam);
  604.     screen(SCR_FS,0,(long)fsize,"");
  605.  
  606.     }
  607.     tlog(F110,"Sending",filnam,0l); /* Transaction log entry */
  608.     tlog(F110," as",pktnam,0l);
  609.  
  610.   }  else  {
  611.  
  612.     screen( SCR_XD, 'X', (long)pktnum,cmdstr); /* screen */
  613.     tlog(F110,"sending from:",cmdstr,0L);
  614.   }
  615.     intmsg(++filcnt);       /* Count file, give interrupt msg */
  616.     next = -1;              /* Init file character lookahead. */
  617.     return(1);
  618. }
  619.  
  620. /* Send an X Packet -- Like SFILE, but with Text rather than File header */
  621.  
  622. #ifdef ANSI
  623. int
  624. #endif
  625. sxpack() {              /* Send an X packet */
  626.     debug(F110,"sxpack",cmdstr,0);
  627.     encstr(cmdstr);         /* Encode any data. */
  628.     rpt = flci = flco = ffc = 0;    /* Init counters, etc. */
  629.     next = -1;              /* Init file character lookahead. */
  630.     nxtpkt(&pktnum);            /* Increment the packet number */
  631.     spack('X',pktnum,size,data);    /* No incrementing pktnum */
  632.     screen(SCR_XD,'X',(long)pktnum,cmdstr); /* Update screen. */
  633.     intmsg(++filcnt);
  634.     tlog(F110,"Sending from:",cmdstr,0l);
  635.     return(1);
  636. }
  637.  
  638. /*  S D A T A -- Send a data packet */
  639.  
  640. #ifdef ANSI
  641. int
  642. #endif
  643. sdata() {
  644.     int len;
  645.     if (cxseen || czseen) return(-1);   /* If interrupted, done. */
  646.     if ((len = getpkt(spsiz-chklen-3)) == 0) return(-1); /* If no data, done.*/
  647.     nxtpkt(&pktnum);            /* Increment the packet number */
  648.     spack('D',pktnum,len,data);     /* Send the packet */
  649.     return(len);
  650. }
  651.  
  652. /*  S E O F -- Send an End-Of-File packet */
  653.  
  654. #ifdef ANSI
  655. void
  656. #endif
  657. seof() {
  658.     nxtpkt(&pktnum);            /* Increment the packet number */
  659.     if (czseen || cxseen) {
  660.     spack('Z',pktnum,1,"D");
  661.     cxseen = 0;         /* Clear this now */
  662.     tlog(F100," *** interrupted, sending discard request","",0l);
  663.     } else {
  664.     spack('Z',pktnum,0,"");
  665.     tlog(F100," end of file","",0l);
  666.     tlog(F101,"  file characters        ","",ffc);
  667.     tlog(F101,"  communication line in  ","",flci);
  668.     tlog(F101,"  communication line out ","",flco);
  669.     }
  670. }
  671.  
  672. /*  S E O T -- Send an End-Of-Transaction packet */
  673.  
  674. #ifdef ANSI
  675. void
  676. #endif
  677. seot() {
  678.     char *tp;
  679.     nxtpkt(&pktnum);            /* Increment the packet number */
  680.     spack('B',pktnum,0,"");
  681.     cxseen = czseen = 0; 
  682.     ztime(&tp);
  683.     tlog(F110,"End of transaction",tp,0l);
  684.     if (filcnt > 1) {
  685.     tlog(F101," files","",filcnt);
  686.     tlog(F101," total file characters   ","",tfc);
  687.     tlog(F101," communication line in   ","",tlci);
  688.     tlog(F101," communication line out  ","",tlco);
  689.     }
  690. }
  691.  
  692. /*   R P A R -- Fill the data array with my send-init parameters  */
  693.  
  694. #ifdef ANSI
  695. int
  696. #endif
  697. rpar(data) char data[]; {
  698.     data[0] = tochar(rpsiz);        /* Biggest packet I can receive */
  699.     data[1] = tochar(rtimo);        /* When I want to be timed out */
  700.     data[2] = tochar(mypadn);       /* How much padding I need (none) */
  701.     data[3] = ctl(mypadc);      /* Padding character I want */
  702.     data[4] = tochar(eol);      /* End-Of-Line character I want */
  703.     data[5] = CTLQ;         /* Control-Quote character I send */
  704.     if (ebqflg) data[6] = ebq = '&';
  705.         else data[6] = 'Y';     /* 8-bit quoting */
  706.     data[7] = bctr + '0';       /* Block check type */
  707.     data[8] = MYRPTQ;           /* Do repeat counts */
  708.     data[9] = '\0';
  709.     return(9);              /* Return the length. */
  710. }
  711.  
  712. /*   S P A R -- Get the other system's Send-Init parameters.  */
  713.  
  714. #ifdef ANSI
  715. void
  716. #endif
  717. spar(data) char data[]; {
  718.     int len, x;
  719.  
  720.     len = strlen(data);             /* Number of fields */
  721.  
  722.     spsiz = (len-- > 0) ? unchar(data[0]) : DSPSIZ;     /* Packet size */
  723.     if (spsiz < 10) spsiz = DSPSIZ;
  724.  
  725.     x = (len-- > 0) ? unchar(data[1]) : DMYTIM; /* Timeout */
  726.     if (!timef) {           /* Only use if not overridden */
  727.     timint = x;
  728.     if (timint < 0) timint = DMYTIM;
  729.     }
  730.  
  731.     npad = 0; padch = '\0';                     /* Padding */
  732.     if (len-- > 0) {
  733.     npad = unchar(data[2]);
  734.     if (len-- > 0) padch = ctl(data[3]); else padch = 0;
  735.     }
  736.  
  737.     eol = (len-- > 0) ? unchar(data[4]) : '\r';         /* Terminator  */
  738.     if ((eol < 2) || (eol > 037)) eol = '\r';
  739.  
  740.     ctlq = (len-- > 0) ? data[5] : CTLQ;                /* Control prefix */
  741.  
  742.     if (len-- > 0) {                            /* 8th-bit prefix */
  743.     ebq = data[6];
  744.     if ((ebq > 040 && ebq < 0100) || (ebq > 0140 && ebq < 0177)) {
  745.         ebqflg = 1;
  746.     } else if (parity && (ebq == 'Y')) {
  747.         ebqflg = 1;
  748.         ebq = '&';
  749.     } else if (ebq == 'N') {
  750.         ebqflg = 0;
  751.     } else ebqflg = 0;
  752.     } else ebqflg = 0;
  753.  
  754.     chklen = 1;                             /* Block check */
  755.     if (len-- > 0) {
  756.     chklen = data[7] - '0';
  757.     if ((chklen < 1) || (chklen > 3)) chklen = 1;
  758.     }
  759.     bctr = chklen;
  760.  
  761.     if (len-- > 0) {                            /* Repeat prefix */
  762.     rptq = data[8]; 
  763.     rptflg = ((rptq > 040 && rptq < 0100) ||
  764.                   (rptq > 0140 && rptq < 0177));
  765.     } else rptflg = 0;
  766.  
  767.     if (deblog) sdebu(len);
  768. }
  769.  
  770. /*  S D E B U  -- Record spar results in debugging log  */
  771.  
  772. #ifdef ANSI
  773. void
  774. #endif
  775. sdebu(len) int len; {
  776.     debug(F111,"spar: data",data,len);
  777.     debug(F101," spsiz ","",spsiz);
  778.     debug(F101," timint","",timint);
  779.     debug(F101," npad  ","",npad);
  780.     debug(F101," padch ","",padch);
  781.     debug(F101," eol   ","",eol);
  782.     debug(F101," ctlq  ","",ctlq);
  783.     debug(F101," ebq   ","",ebq);
  784.     debug(F101," ebqflg","",ebqflg);
  785.     debug(F101," chklen","",chklen);
  786.     debug(F101," rptq  ","",rptq);
  787.     debug(F101," rptflg","",rptflg);
  788. }
  789.  
  790. /*  G N F I L E  --  Get the next file name from a file group.  */
  791.  
  792. /*  Returns 1 if there's a next file, 0 otherwise  */
  793.  
  794. #ifdef ANSI
  795. int
  796. #endif
  797. gnfile() {
  798.     int x; long y;
  799.  
  800.     /* If file group interruption (C-Z) occured, fail.  */
  801.     debug(F101,"gnfile: czseen","",czseen);
  802.     if (czseen) {
  803.     tlog(F100,"Transaction cancelled","",0l);
  804.     return(0);
  805.     }
  806.  
  807.     /* If input was stdin or memory string, there is no next file.  */
  808.     if (sndsrc == 0) return(0);
  809.  
  810.     /* If file list comes from command line args, get the next list element.*/
  811.     y = -1;
  812.     while (y < 0) {         /* Keep trying till we get one... */
  813.     if (sndsrc > 0) {
  814.         if (nfils-- > 0) {
  815.         strcpy(filnam,*cmlist++);
  816.         debug(F111,"gnfile: cmlist filnam",filnam,nfils);
  817.         } else {
  818.         *filnam = '\0';
  819.         debug(F101,"gnfile cmlist: nfils","",nfils);
  820.         return(0);
  821.         }
  822.     }
  823.  
  824. /* Otherwise, step to next element of internal wildcard expansion list. */
  825.     if (sndsrc < 0) {
  826.         x = znext(filnam);
  827.         debug(F111,"gnfile znext: filnam",filnam,x);
  828.         if (x == 0) return(0);
  829.     }
  830.  
  831.         /* Get here with a filename. */
  832.     y = zchki(filnam);      /* Check if file readable */
  833.     if (y < 0) {
  834.         debug(F110,"gnfile skipping:",filnam,0);
  835.         tlog(F111,filnam,"not sent, reason",(long)y);
  836.         screen(SCR_ST,ST_SKIP,0l,filnam);
  837.     } else fsize = y;
  838.     }       
  839.     return(1);
  840. }
  841.  
  842. /*  O P E N I  --  Open an existing file for input  */
  843.  
  844. #ifdef ANSI
  845. int
  846. #endif
  847. openi(name) char *name; {
  848.     int x, filno;
  849.     
  850.     if (memstr) return(1);      /* Just return if file is memory. */
  851.  
  852.     debug(F110,"openi",name,0);
  853.     debug(F101," sndsrc","",sndsrc);
  854.  
  855.     filno = (sndsrc == 0) ? ZSTDIO : ZIFILE;    /* ... */
  856.     debug(F101," file number","",filno);
  857.     if (zopeni(filno,name)) {       /* Otherwise, try to open it. */
  858.     debug(F110," ok",name,0);
  859.         return(1);
  860.     } else {                /* If not found, */
  861.     char xname[100];        /* convert the name */
  862.     zrtol(name,xname);      /* to local form and then */
  863.     debug(F110," zrtol:",xname,0);
  864.     x = zopeni(filno,xname);    /* try opening it again. */
  865.     debug(F101," zopeni","",x);
  866.     if (x) {
  867.         debug(F110," ok",xname,0);
  868.         return(1);          /* It worked. */
  869.         } else {
  870.         screen(SCR_EM,0,0l,"Can't open file");  /* It didn't work. */
  871.         tlog(F110,xname,"could not be opened",0l);
  872.         debug(F110," openi failed",xname,0);
  873.         return(0);
  874.         }
  875.     }
  876. }
  877.  
  878. /*  O P E N O  --  Open a new file for output.  */
  879.  
  880. /*  Returns actual name under which the file was opened in string 'name2'. */
  881.  
  882. #ifdef ANSI
  883. int
  884. #endif
  885. openo(name,name2) char *name, *name2; {
  886.     char xname[100], *xp;
  887.  
  888.     if (stdouf)             /* Receiving to stdout? */
  889.     return(zopeno(ZSTDIO,""));
  890.  
  891.     debug(F110,"openo: name",name,0);
  892.     if (cxseen || czseen) {     /* If interrupted, get out before */
  893.     debug(F100," open cancelled","",0); /* destroying existing file. */
  894.     return(1);          /* Pretend to succeed. */
  895.     }
  896.     xp = xname;             /* OK to proceed. */
  897.     if (fncnv) {            /* If desired, */
  898. /***** This one is the special case exempted elsewhere by tweaking fncnv ****/
  899.         zrtol(name,xp);         /* convert name to local form */
  900.     } else              /* otherwise, */
  901.         strcpy(xname,name);     /* use it literally */
  902.  
  903.     debug(F110,"openo: xname",xname,0);
  904.  
  905.     if (warn) {             /* File collision avoidance? */
  906.     if (zchki(xname) != -1) {   /* Yes, file exists? */
  907.         znewn(xname,&xp);       /* Yes, make new name. */
  908.         strcpy(xname,xp);
  909.         debug(F110," exists, new name ",xname,0);
  910.         }
  911.     }
  912.     if (zopeno(ZOFILE,xname) == 0) {    /* Try to open the file */
  913.     debug(F110,"openo failed",xname,0);
  914.     tlog(F110,"Failure to open",xname,0l);
  915.     return(0);
  916.     } else {
  917.     strcpy(name2,xname);
  918.     debug(F110,"openo ok, name2",name2,0);
  919.     return(1);
  920.     }
  921. }
  922.  
  923. /*  O P E N T  --  Open the terminal for output, in place of a file  */
  924.  
  925. #ifdef ANSI
  926. int
  927. #endif
  928. opent() {
  929.     ffc = tfc = 0;
  930.     return(zopeno(ZCTERM,""));
  931. }
  932.  
  933. /*  C L S I F  --  Close the current input file. */
  934.  
  935. #ifdef ANSI
  936. void
  937. #endif
  938. clsif() {
  939.     if (memstr) {           /* If input was memory string, */
  940.     memstr = 0;         /* indicate no more. */
  941.     } else zclose(ZIFILE);      /* else close input file. */
  942.  
  943.     if (czseen || cxseen) 
  944.         screen(SCR_ST,ST_DISC,0l,"");
  945.     else
  946.         screen(SCR_ST,ST_OK,0l,"");
  947.     cxseen = hcflg = 0;         /* Reset flags, */
  948.     *filnam = '\0';         /* and current file name */
  949. }
  950.  
  951. /*  C L S O F  --  Close an output file.  */
  952.  
  953. #ifdef ANSI
  954. void
  955. #endif
  956. clsof() {
  957.     zclose(ZOFILE);         /* Close it. */
  958.     if (czseen || cxseen) {
  959.     if (*filnam) zdelet(filnam);    /* Delete it if interrupted. */
  960.     debug(F100,"Discarded","",0);
  961.     tlog(F100,"Discarded","",0l);
  962.     screen(SCR_ST,ST_DISC,0l,"");
  963.     } else {
  964.     debug(F100,"Closed","",0);
  965.     screen(SCR_ST,ST_OK,0l,"");
  966.     }
  967.     cxseen = 0;             /* Reset file interruption flag */
  968.     *filnam = '\0';         /* and current file name. */
  969. }
  970.  
  971. /*  S N D H L P  --  Routine to send builtin help  */
  972.  
  973. #ifdef ANSI
  974. int
  975. #endif
  976. sndhlp() {
  977.     nfils = 0;              /* No files, no lists. */
  978.     xflg = 1;               /* Flag we must send X packet. */
  979.     strcpy(cmdstr,"help text");     /* Data for X packet. */
  980.     next = -1;              /* Init getch lookahead */
  981.     memstr = 1;             /* Just set the flag. */
  982.     memptr = hlptxt;            /* And the pointer. */
  983.     return(sinit());
  984. }
  985.  
  986.  
  987. /*  C W D  --  Change current working directory  */
  988.  
  989. /*
  990.  String passed has first byte as length of directory name, rest of string
  991.  is name.  Fails if can't connect, else ACKs (with name) and succeeds. 
  992. */
  993.  
  994. #ifdef ANSI
  995. int
  996. #endif
  997. cwd(vdir) char *vdir; {
  998.     vdir[unchar(*vdir) + 1] = '\0'; /* End with a null */
  999.     if (zchdir(vdir+1)) {
  1000.     encstr(vdir+1);
  1001.     ack1(data);
  1002.     tlog(F110,"Changed directory to",vdir+1,0l);
  1003.     return(1); 
  1004.     } else {
  1005.     tlog(F110,"Failed to change directory to",vdir+1,0l);
  1006.     return(0);
  1007.     }
  1008. }
  1009.  
  1010.  
  1011. /*  S Y S C M D  --  Do a system command  */
  1012.  
  1013. /*  Command string is formed by concatenating the two arguments.  */
  1014.  
  1015. #ifdef ANSI
  1016. int
  1017. #endif
  1018. syscmd(prefix,suffix) char *prefix, *suffix; {
  1019.     char *cp;
  1020.  
  1021.     if (prefix == NULL || *prefix == '\0') return(0);
  1022.  
  1023.     for (cp = cmdstr; *prefix != '\0'; *cp++ = *prefix++) ;
  1024. #ifdef ANSI
  1025.     while ( (*cp++ = *suffix++) != '\0' ) ;
  1026. #else
  1027.     while (*cp++ = *suffix++) ;
  1028. #endif
  1029.     debug(F110,"syscmd",cmdstr,0);
  1030.  
  1031.     if (zopeni(ZSYSFN,cmdstr) > 0) {
  1032.     debug(F100,"syscmd zopeni ok",cmdstr,0);
  1033.     nfils = sndsrc = 0;     /* Flag that input from stdin */
  1034.     xflg = hcflg = 1;       /* And special flags for pipe */
  1035.     return (sinit());       /* Send S packet */
  1036.     } else {
  1037.     debug(F100,"syscmd zopeni failed",cmdstr,0);
  1038.     return(0);
  1039.     }
  1040. }
  1041.