home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / ek / eksw / src / unixio.c < prev   
C/C++ Source or Header  |  2020-01-01  |  27KB  |  1,011 lines

  1. #define SIMULATED_RTT 0
  2.  
  3. /*
  4.  * Sample system-dependent communications i/o routines for embedded
  5.  * Kermit. 
  6.  */
  7.  
  8. /*
  9.  * Author: Frank da Cruz. Copyright (C) 1995, 2004, Trustees of Columbia
  10.  * University in the City of New York. All rights reserved. 
  11.  * For license see kermit.c.
  12.  */
  13.  
  14. /*
  15.  * The sample i/o routines for UNIX that provide packet i/o functions on
  16.  * the console (login) device. Copy this file, rename it appropriately,
  17.  * and replace the contents of each routine appropriately for your
  18.  * platform.
  19.  * 
  20.  * Device i/o:
  21.  * 
  22.  * int devopen() Communications device - open int pktmode() Communications 
  23.  * device - enter/exit packet mode int readpkt() Communications device -
  24.  * read a packet int tx_data() Communications device - send data int
  25.  * devclose() Communications device - close int inchk() Communications
  26.  * device - check if bytes are ready to read
  27.  * 
  28.  * File i/o:
  29.  * 
  30.  * int openfile() File - open for input or output ULONG fileinfo() Get
  31.  * input file modtime and size int readfile() Input file - read data int
  32.  * writefile() Output file - write data int closefile() Input or output
  33.  * file - close
  34.  * 
  35.  * Full definitions below, prototypes in kermit.h.
  36.  * 
  37.  * These routines must handle speed setting, parity, flow control, file
  38.  * i/o, and similar items without the kermit() routine knowing anything
  39.  * about it. If parity is in effect, these routines must add it to
  40.  * outbound characters and strip it from inbound characters. 
  41.  */
  42. #include <stdio.h>
  43. #include <stdlib.h>             // for rand(), exit()
  44. #include <unistd.h>             // for read(), write()
  45. #include <sys/stat.h>
  46. #include <time.h>
  47. #include <errno.h>
  48. #ifndef O_WRONLY
  49. #include <sys/file.h>
  50. #endif /* O_WRONLY */
  51.  
  52. #include <sys/select.h>
  53. #include <termio.h>             /* for settty(), gettty() args */
  54. #include <fcntl.h>              /* for open() args */
  55. #include <string.h>             /* for str...() */
  56.  
  57. #include "sys/time.h"           // for gettimeofday()
  58.  
  59. #ifdef X_OK
  60. #undef X_OK
  61. #endif /* X_OK */
  62.  
  63. #include "./cdefs.h"
  64. #include "./debug.h"
  65. #include "./platform.h"
  66. #include "./kermit.h"
  67.  
  68. UCHAR o_buf[OBUFLEN + 8];       /* File output buffer */
  69. UCHAR i_buf[IBUFLEN + 8];       /* File output buffer */
  70.  
  71. /*
  72.  * In this example, the output file is unbuffered to ensure that every
  73.  * output byte is commited.  The input file, however, is buffered for
  74.  * speed. This is just one of many possible implmentation choices,
  75.  * invisible to the Kermit protocol module. 
  76.  */
  77. static int ttyfd = -1;
  78. static int ofile = -1;          /* File descriptors */
  79. static FILE *ifile = (FILE *) 0;        /* and pointers */
  80.  
  81. static FILE *ttyfp = 0;
  82.  
  83. void
  84. fprintf_date (FILE * fp)
  85. {
  86.    struct timeval tvnow;
  87.    struct timezone tz;
  88.    struct tm tmnow;
  89.  
  90.    gettimeofday (&tvnow, &tz);
  91.    localtime_r (&tvnow.tv_sec, &tmnow);
  92.  
  93. # if 0
  94.    fprintf (fp, "%04d-%02d-%02d %02d:%02d:%02d.%06ld ",
  95.             tmnow.tm_year + 1900,
  96.             tmnow.tm_mon + 1,
  97.             tmnow.tm_mday,
  98.             tmnow.tm_hour, tmnow.tm_min, tmnow.tm_sec, tvnow.tv_usec);
  99. # else
  100.    fprintf (fp, "%02d:%02d:%02d.%03ld ",
  101.             tmnow.tm_hour, tmnow.tm_min, tmnow.tm_sec, tvnow.tv_usec / 1000);
  102. # endif
  103.  
  104. }
  105.  
  106. /*
  107.  * Debugging 
  108.  */
  109.  
  110. #ifdef DEBUG
  111. static FILE *dp = (FILE *) 0;   /* Debug log */
  112. static int xdebug = 0;          /* Debugging on/off */
  113. static int tdebug = 0;
  114.  
  115. int
  116. dodebug (int fc, UCHAR * label, UCHAR * sval, long nval)
  117. {
  118.    if (fc != DB_OPN && fc != DB_OPNT && !xdebug)
  119.       return (-1);
  120.    if (!label)
  121.       label = (UCHAR *) "";
  122.  
  123.    switch (fc)
  124.    {                            /* Function code */
  125.    case DB_OPNT:
  126.       tdebug = 1;
  127.    case DB_OPN:                /* Open debug log */
  128.       xdebug = 1;
  129.  
  130. //              fprintf(stderr,"DODEBUG fc=%d xdebug=%d tdebug=%d\n",
  131. //                      fc,xdebug,tdebug);
  132. //              if(label)
  133. //                      fprintf(stderr,"DODEBUG label=[%s]\n",label); 
  134.  
  135.       if (!*label)
  136.          dp = stderr;
  137.       else
  138.       {
  139.          if (dp)
  140.             fclose (dp);
  141.          dp = fopen ((char *) label, "wt");
  142.          if (!dp)
  143.          {
  144.             dp = stderr;
  145.          }
  146.          else
  147.          {
  148.             setbuf (dp, (char *) 0);    // cause dp to be unbuffered
  149.          }
  150.       }
  151.       if (tdebug)
  152.          fprintf_date (dp);
  153.       if (*label)
  154.       {
  155.          fprintf (dp, "DEBUG LOG OPEN: %s\n", label);
  156.       }
  157.       else
  158.       {
  159.          fprintf (dp, "DEBUG LOG OPEN: %s\n", "stderr");
  160.       }
  161.       return (0);
  162.    case DB_MSG:                /* Write a message */
  163.       if (dp)
  164.       {
  165.          if (tdebug)
  166.             fprintf_date (dp);
  167.          fprintf (dp, "%s\n", (char *) label);
  168.       }
  169.       return (0);
  170.    case DB_CHR:                /* Write label and character */
  171.       if (dp)
  172.       {
  173.          if (tdebug)
  174.             fprintf_date (dp);
  175.          if (nval > 32 && nval < 127)
  176.          {
  177.             fprintf (dp, "%s=[%c]\n", (char *) label, (char) nval);
  178.          }
  179.          else
  180.          {
  181.             fprintf (dp, "%s=[%d decimal]\n", (char *) label, (char) nval);
  182.          }
  183.       }
  184.       return (0);
  185.    case DB_PKT:                /* Log a packet */
  186.       if (!dp)
  187.          return (0);
  188.       if (sval)
  189.       {
  190.          int i;
  191.          if (tdebug)
  192.             fprintf_date (dp);
  193.          fprintf (dp, "%s[", (char *) label);
  194.          for (i = 0; sval[i] != 0; i++)
  195.          {
  196.             int c = sval[i];
  197.             if (c >= 32 && c < 127)
  198.                fprintf (dp, "%c", c);
  199.             else if (c == '\\')
  200.                fprintf (dp, "\\\\");
  201.             else if (c == 0x0d)
  202.                fprintf (dp, "\\r");
  203.             else if (c == 0x0a)
  204.                fprintf (dp, "\\n");
  205. //          else if (c == '^')
  206. //             fprintf (dp, "\\^");
  207. //          else if (c >= 1 && c <= 26)
  208. //             fprintf (dp, "^%c",c + 64);
  209.             else
  210.                fprintf (dp, "[%02x]", c);
  211.          }
  212.          fprintf (dp, "]\n");
  213.       }
  214.       else
  215.       {
  216.          if (tdebug)
  217.             fprintf_date (dp);
  218.          fprintf (dp, "%s=%ld\n", (char *) label, nval);
  219.       }
  220.       return (0);
  221.  
  222.    case DB_HEX:                /* Log data in hex */
  223.       if (!dp)
  224.          return (0);
  225.       if (sval)
  226.       {
  227.          int i;
  228.          if (tdebug)
  229.             fprintf_date (dp);
  230.          fprintf (dp, "%s[", (char *) label);
  231.          for (i = 0; i < nval; i++)
  232.          {
  233.             int c = sval[i];
  234.             if (i > 0)
  235.                fprintf (dp, " ");
  236.             fprintf (dp, "%02x", c);
  237.          }
  238.          fprintf (dp, "]\n");
  239.          fprintf (dp, "  i=%d, nval=%ld\n", i, nval);
  240.       }
  241.       else
  242.       {
  243.          if (tdebug)
  244.             fprintf_date (dp);
  245.          fprintf (dp, "%s=%ld\n", (char *) label, nval);
  246.       }
  247.       return (0);
  248.  
  249.    case DB_LOG:                /* Write label and string or number */
  250.       if (tdebug)
  251.          fprintf_date (dp);
  252.       if (sval && dp)
  253.          fprintf (dp, "%s[%s]\n", (char *) label, sval);
  254.       else
  255.          fprintf (dp, "%s=%ld\n", (char *) label, nval);
  256.       return (0);
  257.    case DB_CLS:                /* Close debug log */
  258.       if (dp)
  259.       {
  260.          fclose (dp);
  261.          dp = (FILE *) 0;
  262.       }
  263.       xdebug = 0;
  264.    }
  265.    return (-1);
  266. }
  267. #endif /* DEBUG */
  268.  
  269. /*
  270.  * D E V O P E N -- Open communications device 
  271.  */
  272. /*
  273.  * 
  274.  * Call with: string pointer to device name.  This routine should get the
  275.  * current device settings and save them so devclose() can restore them.
  276.  * It should open the device.  If the device is a serial port, devopen()
  277.  * set the speed, stop bits, flow control, etc. Returns: 0 on failure, 1
  278.  * on success. 
  279.  */
  280.  
  281. int
  282. devopen (char *ttyname, long baud)
  283. {
  284.    static struct termios settty;
  285.    int ret;
  286.    int baudflag;
  287.  
  288.    ttyfp = 0;
  289.  
  290.    if (strcmp (ttyname, "stdin") == 0)
  291.    {
  292.       ttyfd = 0;
  293.       ttyfp = stdin;
  294.       return (1);
  295.    }
  296.  
  297.    switch (baud)
  298.    {
  299.    case 2400:
  300.       baudflag = B2400;
  301.       break;
  302.    case 4800:
  303.       baudflag = B4800;
  304.       break;
  305.    case 9600:
  306.       baudflag = B9600;
  307.       break;
  308.    case 19200:
  309.       baudflag = B19200;
  310.       break;
  311.    case 38400:
  312.       baudflag = B38400;
  313.       break;
  314.    case 57600:
  315.       baudflag = B57600;
  316.       break;
  317.    case 115200:
  318.       baudflag = B115200;
  319.       break;
  320.    default:
  321.       fprintf (stderr, "unimplemented baud=%ld\n", baud);
  322.       return (-1);
  323.       break;
  324.    }
  325.  
  326.    if ((ttyfd = open (ttyname, O_RDWR | O_NDELAY)) < 0)
  327.    {
  328.       perror ("devopen(): serial port open failed");
  329.       fprintf (stderr, "ttyname=\"%s\"\n", ttyname);
  330.       return (-1);
  331.    }
  332.  
  333.    settty.c_iflag = 0;
  334.    settty.c_oflag = 0;
  335.    settty.c_cflag = 0;
  336.    settty.c_lflag = 0;
  337.  
  338.    cfmakeraw (&settty);
  339.  
  340.    settty.c_cflag |= CLOCAL;    /* ignore modem control lines */
  341.    settty.c_cflag &= ~CRTSCTS;  /* no flow control */
  342.    settty.c_cflag |= CREAD;     // added June 21, 2002 per new tty driver
  343.  
  344.    cfsetispeed (&settty, baudflag);
  345.    cfsetospeed (&settty, baudflag);
  346.  
  347.    ret = tcsetattr (ttyfd, TCSANOW, &settty);
  348.    if (ret < 0)
  349.    {
  350.       perror ("devopen(): tcsetattr() serial port failed");
  351.       fprintf (stderr, "ttyname=\"%s\"\n", ttyname);
  352.       return (-1);
  353.    }
  354.  
  355.    if ((ttyfp = fdopen (ttyfd, "r+")) == 0)
  356.    {
  357.       fprintf (stderr, "fdopen(ttyfd) failed\n");
  358.       return (-1);
  359.    }
  360.  
  361.    return (1);
  362. }
  363.  
  364. /*
  365.  * P K T M O D E -- Put communications device into or out of packet mode 
  366.  */
  367. /*
  368.  * Call with: 0 to put in normal (cooked) mode, 1 to put in packet (raw)
  369.  * mode. For a "dumb i/o device" like an i/o port that does not have a
  370.  * login attached to it, this routine can usually be a no-op. Returns: 0
  371.  * on failure, 1 on success. 
  372.  */
  373. int
  374. pktmode (short on)
  375. {
  376.    if (ttyfd < 0)               /* Device must be open */
  377.       return (0);
  378.    if (ttyfd == 0)
  379.       system (on ? "stty raw -echo" : "stty sane");     /* Crude but effective */
  380.    return (1);
  381. }
  382.  
  383.  
  384. /*
  385.  * D E V S E T T I N G S 
  386.  */
  387.  
  388. int
  389. devsettings (char *s)
  390. {
  391.    /*
  392.     * Get current device settings, save them for devrestore() 
  393.     */
  394.    /*
  395.     * Parse string s, do whatever it says, e.g. "9600;8N1" 
  396.     */
  397.    if (!pktmode (ON))           /* And put device in packet mode */
  398.       return (0);
  399.    return (1);
  400. }
  401.  
  402. /*
  403.  * D E V R E S T O R E 
  404.  */
  405.  
  406. int
  407. devrestore (void)
  408. {
  409.    /*
  410.     * Put device back as we found it 
  411.     */
  412.    pktmode (OFF);
  413.    return (1);
  414. }
  415.  
  416.  
  417. /*
  418.  * D E V C L O S E -- Closes the current open communications device 
  419.  */
  420. /*
  421.  * Call with: nothing Closes the device and puts it back the way it was
  422.  * found by devopen(). Returns: 0 on failure, 1 on success. 
  423.  */
  424. int
  425. devclose (void)
  426. {
  427.    if (ttyfd > 0)               // ttyfd == 0 when device == "stdin"
  428.    {
  429.       fclose (ttyfp);
  430.       close (ttyfd);            // may be superfluous
  431.    }
  432.    ttyfd = -1;
  433.    ttyfp = 0;
  434.    return (1);
  435. }
  436.  
  437. /*
  438.  * I N C H K -- Check if input waiting 
  439.  */
  440.  
  441. /*
  442.  * Check if input is waiting to be read, needed for sliding windows.  This
  443.  * sample version simply looks in the stdin buffer (which is not portable
  444.  * even among different Unixes).  If your platform does not provide a way
  445.  * to look at the device input buffer without blocking and without actually
  446.  * reading from it, make this routine return (-1).  On success, returns the
  447.  * numbers of characters waiting to be read, i.e. that can be safely read
  448.  * without blocking. 
  449.  */
  450. int
  451. inchk (struct k_data *k)
  452. {
  453.    int n;
  454.    FILE *ttyfp = 0;
  455.  
  456.    if (ttyfd < 0)               /* Device must be open */
  457.       return (0);
  458.  
  459.    if (ttyfd == 0)
  460.    {
  461.       ttyfp = stdin;
  462.    }
  463.    else
  464.    {
  465.    }
  466.  
  467. #ifdef _IO_file_flags           /* Linux */
  468.    n = ttyfp->_IO_read_end - ttyfp->_IO_read_ptr;
  469. #else
  470. #ifdef AIX                      /* AIX */
  471.    n = ttyfp->_cnt;
  472. #else
  473. #ifdef SunOS                    /* Solaris and SunOS */
  474.    n = ttyfp->_cnt;
  475. #else
  476. #ifdef HPUX                     /* HPUX */
  477.    n = ttyfp->__cnt;
  478. #else
  479.    n = -1;
  480. #endif /* HPUX */
  481. #endif /* SunOS */
  482. #endif /* AIX */
  483. #endif /* _IO_file_flags */
  484.  
  485.    return (n);
  486. }
  487.  
  488. /*
  489.  * R E A D P K T -- Read a Kermit packet from the communications device 
  490.  */
  491. /*
  492.  * Call with: k - Kermit struct pointer p - pointer to read buffer len -
  493.  * length of read buffer
  494.  * 
  495.  * When reading a packet, this function looks for start of Kermit packet
  496.  * (k->r_soh), then reads everything between it and the end of the packet
  497.  * (k->r_eom) into the indicated buffer.  Returns the number of bytes
  498.  * read, or: 0 - timeout or other possibly correctable error; -1 - fatal
  499.  * error, such as loss of connection, or no buffer to read into. 
  500.  */
  501.  
  502. int
  503. readpkt (struct k_data *k, UCHAR * p, int len, int fc)
  504. {
  505.    int x = 0, n;
  506.    short flag;
  507.    UCHAR c;
  508.  
  509.    /*
  510.     * Although it is not be needed in many cases,
  511.     * timeout is implemented in this sample because Iridium modems seem
  512.     * to get stuck occasionally and C-Kermit timeout action from the
  513.     * other end of the
  514.     * connection doesn't seem to be able to break the deadlock.
  515.     */
  516.  
  517. #ifdef F_CTRLC
  518.    short ccn;
  519.    ccn = 0;
  520. #endif /* F_CTRLC */
  521.  
  522.    debug (DB_LOG, "READPKT ttyfd", 0, ttyfd);
  523.    debug (DB_LOG, "  unused len", 0, len);
  524.    debug (DB_LOG, "  used k->r_maxlen", 0, k->r_maxlen);
  525.    debug (DB_LOG, "  k->r_timo", 0, k->r_timo);
  526.    debug (DB_LOG, "  ttyfd", 0, ttyfd);
  527.  
  528.    if (ttyfd < 0 || !p)
  529.    {                            /* Device not open or no buffer */
  530.       debug (DB_MSG, "READPKT FAIL", 0, 0);
  531.       return (-1);
  532.    }
  533.    flag = n = 0;                /* Init local variables */
  534.  
  535. //  p2 = (char *) p;
  536.  
  537.    while (1)
  538.    {
  539.       // x = getchar(); /* Replace this with real i/o */
  540.  
  541.       fd_set readfds;
  542.       int nfds = ttyfd + 1;
  543.       int selret;
  544.       struct timeval timeout;
  545.       struct timeval tmosv;
  546.  
  547.       FD_ZERO (&readfds);
  548.       FD_SET (ttyfd, &readfds);
  549.  
  550.       timeout.tv_sec = k->r_timo;
  551.       timeout.tv_usec = 0;
  552.       tmosv = timeout;
  553.  
  554.       if ((selret = select (nfds, &readfds, 0, 0, &timeout)) < 0)
  555.       {
  556.          debug (DB_LOG, "READPKT selret", 0, selret);
  557.          return (-1);
  558.       }
  559.  
  560.       if (selret == 0)
  561.       {
  562.          debug (DB_LOG, "READPKT timed out k->r_timo", 0, k->r_timo);
  563.          return (0);            // indicate timeout to calling prog
  564.       }
  565.  
  566.  
  567.       if (selret > 0)
  568.       {                         // something's available
  569.  
  570.          if (FD_ISSET (ttyfd, &readfds))
  571.          {
  572.             char kar;
  573.             int nread;
  574.             if ((nread = read (ttyfd, &kar, 1)) != 1)
  575.             {
  576.                debug (DB_LOG, "READPKT ttyfd", 0, ttyfd);
  577.                debug (DB_LOG, "  nread", 0, nread);
  578.                return (-1);
  579.             }
  580.             x = kar;
  581.          }
  582.       }
  583. //    debug(DB_LOG,"READPKT x",0,x);
  584.  
  585.       c = (k->parity) ? x & 0x7f : x & 0xff;    /* Strip parity */
  586.  
  587. #ifdef F_CTRLC
  588.       /*
  589.        * In remote mode only: three consecutive ^C's to quit 
  590.        */
  591.       if (k->remote && c == (UCHAR) 3)
  592.       {
  593.          if (++ccn > 2)
  594.          {
  595.             debug (DB_MSG, "READPKT ^C^C^C", 0, 0);
  596.             return (-1);
  597.          }
  598.       }
  599.       else
  600.       {
  601.          ccn = 0;
  602.       }
  603. #endif /* F_CTRLC */
  604.  
  605.       if (!flag && c != k->r_soh)       /* No start of packet yet */
  606.          continue;              /* so discard these bytes. */
  607.       if (c == k->r_soh)
  608.       {                         /* Start of packet */
  609.          flag = 1;              /* Remember */
  610.          continue;              /* But discard. */
  611.       }
  612.       else if (c == k->r_eom    /* Packet terminator */
  613.                || c == '\012'   /* 1.3: For HyperTerminal */
  614.          )
  615.       {
  616.          *p = NUL;              /* Terminate for printing */
  617.          debug (DB_LOG, "READPKT return", 0, n);
  618. //        debug (DB_PKT, "RPKT", p2, n);
  619.          return (n);
  620.       }
  621.       else
  622.       {                         /* Contents of packet */
  623.          if (n++ > k->r_maxlen) /* Check length */
  624.          {
  625.             debug (DB_MSG, "READPKT return=0", 0, 0);
  626.             return (0);
  627.          }
  628.          else
  629.             *p++ = x & 0xff;
  630.       }
  631.    }
  632.    debug (DB_MSG, "READPKT FAIL (end)", 0, 0);
  633.    return (-1);
  634. }
  635.  
  636. /*
  637.  * T X _ D A T A -- Writes n bytes of data to communication device.  
  638.  */
  639. /*
  640.  * Call with: k = pointer to Kermit struct. p = pointer to data to
  641.  * transmit. n = length. Returns: X_OK on success. X_ERROR on failure to
  642.  * write - i/o error. 
  643.  */
  644. int
  645. tx_data (struct k_data *k, UCHAR * p, int n)
  646. {
  647.    int x;
  648.    int max = 10;                /* Loop breaker */
  649.    long usecs;
  650.  
  651.    debug (DB_LOG, "TX_DATA write n=", 0, n);
  652.  
  653.    usleep (k->send_pause_us);
  654.  
  655. #if SIMULATED_RTT > 0
  656.    sleep (SIMULATED_RTT);
  657. #endif
  658.    while (n > 0)
  659.    {                            /* Keep trying till done */
  660.       x = write (ttyfd, p, n);
  661.       max--;
  662.       debug (DB_LOG, "TX_DATA write x=", 0, x);
  663.       if (x == -1 && max > 0)
  664.       {
  665.          usecs = k->s_maxlen * (10000000L / k->baud);
  666.          debug (DB_LOG, "TX_DATA sleeping usecs", 0, usecs);
  667.          usleep (usecs);
  668.          continue;
  669.       }
  670.       if (x < 0 || max < 1)     /* Errors are fatal */
  671.       {
  672.          debug (DB_LOG, "TX_DATA X_ERROR, max", 0, max);
  673.          return (X_ERROR);
  674.       }
  675.       n -= x;
  676.       p += x;
  677.    }
  678.    return (X_OK);               /* Success */
  679. }
  680.  
  681. /*
  682.  * O P E N F I L E -- Open output file 
  683.  */
  684. /*
  685.  * Call with: Pointer to filename. Size in bytes. Creation date in format
  686.  * yyyymmdd hh:mm:ss, e.g. 19950208 14:00:00 Mode: 1 = read, 2 = create, 3 
  687.  * = append. Returns: X_OK on success. X_ERROR on failure, including
  688.  * rejection based on name, size, or date. 
  689.  */
  690. int
  691. openfile (struct k_data *k, UCHAR * s, int mode)
  692. {
  693.    debug (DB_LOG, "OPENFILE ", s, 0);
  694.    debug (DB_LOG, "  mode", 0, mode);
  695.  
  696.    switch (mode)
  697.    {
  698.    case 1:                     /* Read */
  699.       if (!(ifile = fopen ((char *) s, "r")))
  700.       {
  701.          debug (DB_LOG, "openfile read error", s, 0);
  702.          return (X_ERROR);
  703.       }
  704.       k->s_first = 1;           /* Set up for getkpt */
  705.       k->zinbuf[0] = '\0';      /* Initialize buffer */
  706.       k->zinptr = k->zinbuf;    /* Set up buffer pointer */
  707.       k->zincnt = 0;            /* and count */
  708.       debug (DB_LOG, "openfile read ok", s, 0);
  709.       return (X_OK);
  710.  
  711.    case 2:                     /* Write (create) */
  712.       ofile = creat ((char *) s, 0644);
  713.       if (ofile < 0)
  714.       {
  715.          debug (DB_LOG, "openfile write error", s, 0);
  716.          return (X_ERROR);
  717.       }
  718.       debug (DB_LOG, "openfile write ok", s, 0);
  719.       return (X_OK);
  720.  
  721. #ifdef COMMENT
  722.    case 3:                     /* Append (not used) */
  723.       ofile = open (s, O_WRONLY | O_APPEND);
  724.       if (ofile < 0)
  725.       {
  726.          debug (DB_LOG, "openfile append error", s, 0);
  727.          return (X_ERROR);
  728.       }
  729.       debug (DB_LOG, "openfile append ok", s, 0);
  730.       return (X_OK);
  731. #endif /* COMMENT */
  732.  
  733.    default:
  734.       return (X_ERROR);
  735.    }
  736. }
  737.  
  738. /*
  739.  * F I L E I N F O -- Get info about existing file 
  740.  */
  741. /*
  742.  * Call with: Pointer to filename Pointer to buffer for date-time string
  743.  * Length of date-time string buffer (must be at least 18 bytes) Pointer
  744.  * to int file type: 0: Prevailing type is text. 1: Prevailing type is
  745.  * binary. Transfer mode (0 = auto, 1 = manual): 0: Figure out whether
  746.  * file is text or binary and return type. 1: (nonzero) Don't try to
  747.  * figure out file type. Returns: X_ERROR on failure. 0L or greater on
  748.  * success == file length. Date-time string set to yyyymmdd hh:mm:ss
  749.  * modtime of file. If date can't be determined, first byte of buffer is
  750.  * set to NUL. Type set to 0 (text) or 1 (binary) if mode == 0. 
  751.  */
  752. #ifdef F_SCAN
  753. #define SCANBUF 1024
  754. #define SCANSIZ 49152
  755. #endif /* F_SCAN */
  756.  
  757. ULONG
  758. fileinfo (struct k_data * k,
  759.           UCHAR * filename, UCHAR * buf, int buflen, short *type, short mode)
  760. {
  761.    struct stat statbuf;
  762.    struct tm *timestamp, *localtime ();
  763.  
  764. #ifdef F_SCAN
  765.    FILE *fp;                    /* File scan pointer */
  766.    char inbuf[SCANBUF];         /* and buffer */
  767. #endif /* F_SCAN */
  768.  
  769.    debug (DB_MSG, "FILEINFO", 0, 0);
  770.  
  771.    if (!buf)
  772.       return (X_ERROR);
  773.    buf[0] = '\0';
  774.    if (buflen < 18)
  775.       return (X_ERROR);
  776.    if (stat ((char *) filename, &statbuf) < 0)
  777.       return (X_ERROR);
  778.    timestamp = localtime (&(statbuf.st_mtime));
  779.    sprintf ((char *) buf, "%04d%02d%02d %02d:%02d:%02d",
  780.             timestamp->tm_year + 1900,
  781.             timestamp->tm_mon + 1,
  782.             timestamp->tm_mday,
  783.             timestamp->tm_hour, timestamp->tm_min, timestamp->tm_sec);
  784. #ifdef F_SCAN
  785.    /*
  786.     * Here we determine if the file is text or binary if the transfer
  787.     * mode is not forced.  This is an extremely crude sample, which
  788.     * diagnoses any file that contains a control character other than HT, 
  789.     * LF, FF, or CR as binary. A more thorough content analysis can be
  790.     * done that accounts for various character sets as well as various
  791.     * forms of Unicode (UTF-8, UTF-16, etc). Or the diagnosis could be
  792.     * based wholly or in part on the filename. etc etc.  Or the
  793.     * implementation could skip this entirely by not defining F_SCAN
  794.     * and/or by always calling this routine with type set to -1. 
  795.     */
  796.    if (!mode)
  797.    {                            /* File type determination requested */
  798.       int isbinary = 1;
  799.       fp = fopen (filename, "r");       /* Open the file for scanning */
  800.       if (fp)
  801.       {
  802.          int n = 0, count = 0;
  803.          char c, *p;
  804.  
  805.          debug (DB_LOG, "fileinfo scan ", filename, 0);
  806.  
  807.          isbinary = 0;
  808.          while (count < SCANSIZ && !isbinary)
  809.          {                      /* Scan this much */
  810.             n = fread (inbuf, 1, SCANBUF, fp);
  811.             if (n == EOF || n == 0)
  812.                break;
  813.             count += n;
  814.             p = inbuf;
  815.             while (n--)
  816.             {
  817.                c = *p++;
  818.                if (c < 32 || c == 127)
  819.                {
  820.                   if (c != 9 && /* Tab */
  821.                       c != 10 &&        /* LF */
  822.                       c != 12 &&        /* FF */
  823.                       c != 13)
  824.                   {             /* CR */
  825.                      isbinary = 1;
  826.                      debug (DB_MSG, "fileinfo BINARY", 0, 0);
  827.                      break;
  828.                   }
  829.                }
  830.             }
  831.          }
  832.          fclose (fp);
  833.          *type = isbinary;
  834.       }
  835.    }
  836. #endif /* F_SCAN */
  837.  
  838.    return ((ULONG) (statbuf.st_size));
  839. }
  840.  
  841.  
  842. /*
  843.  * R E A D F I L E -- Read data from a file 
  844.  */
  845.  
  846. int
  847. readfile (struct k_data *k)
  848. {
  849.  
  850.    if (!k->zinptr)
  851.    {
  852. #ifdef DEBUG
  853.       debug (DB_MSG, "READFILE ZINPTR NOT SET", 0, 0);
  854. #endif /* DEBUG */
  855.       return (X_ERROR);
  856.    }
  857.    if (k->zincnt < 1)
  858.    {                            /* Nothing in buffer - must refill */
  859.       if (k->binary)
  860.       {                         /* Binary - just read raw buffers */
  861.          k->dummy = 0;
  862.          if (k->zinlen != 512)
  863.          {
  864.             debug (DB_LOG, "READFILE should be 512, zinlen", 0, k->zinlen);
  865.             return (-1);
  866.          }
  867.          k->zincnt = fread (k->zinbuf, 1, k->zinlen, ifile);
  868.          debug (DB_LOG, "READFILE binary ok zincnt", 0, k->zincnt);
  869.       }
  870.       else
  871.       {                         /* Text mode needs LF/CRLF handling */
  872.          int c;                 /* Current character */
  873.          for (k->zincnt = 0; (k->zincnt < (k->zinlen - 2)); (k->zincnt)++)
  874.          {
  875.             if ((c = getc (ifile)) == EOF)
  876.                break;
  877.             if (c == '\n')      /* Have newline? */
  878.                k->zinbuf[(k->zincnt)++] = '\r'; /* Insert CR */
  879.             k->zinbuf[k->zincnt] = c;
  880.          }
  881. #ifdef DEBUG
  882.          k->zinbuf[k->zincnt] = '\0';
  883.          debug (DB_LOG, "READFILE text ok zincnt", 0, k->zincnt);
  884. #endif /* DEBUG */
  885.       }
  886.       k->zinbuf[k->zincnt] = '\0';      /* Terminate. */
  887.       if (k->zincnt == 0)       /* Check for EOF */
  888.          return (-1);
  889.       k->zinptr = k->zinbuf;    /* Not EOF - reset pointer */
  890.    }
  891.    (k->zincnt)--;               /* Return first byte. */
  892.  
  893.    debug (DB_LOG, "READFILE exit zincnt", 0, k->zincnt);
  894.    debug (DB_LOG, "READFILE exit zinptr", 0, k->zinptr);
  895.    return (*(k->zinptr)++ & 0xff);
  896. }
  897.  
  898.  
  899. /*
  900.  * W R I T E F I L E -- Write data to file 
  901.  */
  902. /*
  903.  * Call with: Kermit struct String pointer Length Returns: X_OK on success
  904.  * X_ERROR on failure, such as i/o error, space used up, etc 
  905.  */
  906. int
  907. writefile (struct k_data *k, UCHAR * s, int n)
  908. {
  909.    int rc;
  910.    rc = X_OK;
  911.  
  912.    debug (DB_LOG, "WRITEFILE n", 0, n);
  913.    debug (DB_LOG, "WRITEFILE k->binary", 0, k->binary);
  914.  
  915.    if (k->binary)
  916.    {                            /* Binary mode, just write it */
  917.       debug (DB_HEX, "WHEX", s, n);
  918.       if (write (ofile, s, n) != n)
  919.          rc = X_ERROR;
  920.    }
  921.    else
  922.    {                            /* Text mode, skip CRs */
  923.       UCHAR *p, *q;
  924.       int i;
  925.       q = s;
  926.  
  927.       while (1)
  928.       {
  929.          for (p = q, i = 0; ((*p) && (*p != (UCHAR) 13)); p++, i++);
  930.          if (i > 0)
  931.             if (write (ofile, q, i) != i)
  932.                rc = X_ERROR;
  933.          if (!*p)
  934.             break;
  935.          q = p + 1;
  936.       }
  937.    }
  938.    return (rc);
  939. }
  940.  
  941. /*
  942.  * C L O S E F I L E -- Close output file 
  943.  */
  944. /*
  945.  * Mode = 1 for input file, mode = 2 or 3 for output file.
  946.  * 
  947.  * For output files, the character c is the character (if any) from the Z
  948.  * packet data field.  If it is D, it means the file transfer was canceled
  949.  * in midstream by the sender, and the file is therefore incomplete.  This
  950.  * routine should check for that and decide what to do.  It should be
  951.  * harmless to call this routine for a file that that is not open. 
  952.  */
  953. int
  954. closefile (struct k_data *k, UCHAR c, int mode)
  955. {
  956.    int rc = X_OK;               /* Return code */
  957.  
  958.    debug (DB_LOG, "closefile mode", 0, mode);
  959.    debug (DB_CHR, "closefile c", 0, c);
  960.  
  961.    switch (mode)
  962.    {
  963.    case 1:                     /* Closing input file */
  964.       if (!ifile)               /* If not not open */
  965.          break;                 /* do nothing but succeed */
  966.       debug (DB_LOG, "closefile (input)", k->filename, 0);
  967.       if (fclose (ifile) < 0)
  968.          rc = X_ERROR;
  969.       ifile = (FILE *) 0;
  970.       break;
  971.    case 2:                     /* Closing output file */
  972.    case 3:
  973.       if (ofile < 0)            /* If not open */
  974.          break;                 /* do nothing but succeed */
  975.       debug (DB_LOG, "closefile (output) name", k->filename, 0);
  976.       debug (DB_LOG, "closefile (output) keep", 0, k->ikeep);
  977.       if (close (ofile) < 0)
  978.       {                         /* Try to close */
  979.          rc = X_ERROR;
  980.       }
  981.       else if ((k->ikeep == 0) &&       /* Don't keep incomplete files */
  982.                (c == 'D'))
  983.       {                         /* This file was incomplete */
  984.          if (k->filename)
  985.          {
  986.             debug (DB_LOG, "deleting incomplete", k->filename, 0);
  987.             unlink ((char *) (k->filename));    /* Delete it. */
  988.          }
  989.       }
  990.       break;
  991.    default:
  992.       rc = X_ERROR;
  993.    }
  994.    return (rc);
  995. }
  996.  
  997. #ifdef DEBUG
  998. int
  999. xerror ()
  1000. {
  1001.    unsigned int x;
  1002.    extern int errorrate;        /* Fix this - NO EXTERNS */
  1003.    if (!errorrate)
  1004.       return (0);
  1005.    x = rand () % 100;           /* Fix this - NO C LIBRARY */
  1006.    debug (DB_LOG, "RANDOM", 0, x);
  1007.    debug (DB_LOG, "ERROR", 0, (x < errorrate));
  1008.    return (x < errorrate);
  1009. }
  1010. #endif /* DEBUG */
  1011.