#include "ufk.h"
#include <sgtty.h>
#include <signal.h>
#include <setjmp.h>
#include <stat.h>
#include <modes.h>

#define R_CHUNK_SIZE  50          /* Number of characters to read at a time */

char lastchar,
     cons_set;
jmp_buf env, popenv;
struct sgttyb old_mode, new_mode,
              old_c_mode, new_c_mode;

/*
 * Open communication port
 */

open_port(setcons,check_only)
char setcons,
     check_only;
{
   int opnint();
   char tmpprt[20];
   struct stat buf;

   sprintf(tmpprt,"/dev/tty%02d",ttyslot()); /* Get controlling terminal */
   if ((strcmp(tty_descr,"Remote") == 0) ||
       (strcmp(tty_descr,tmpprt) == 0))
      remote = TRUE;
   else
   {
      remote = FALSE;
      strcpy(tmpprt,tty_descr);
   }
   if (stat(tmpprt,&buf))
      return (NULL);                         /* unable to obtain status */
   if ((buf.st_mode & S_IFMT) != S_IFCHR)
      return (NULL);                         /* Not a character device */
   if (!check_only)                          /* Real open */
   {
      if (!port_open || remote)
      {
         if (setjmp(popenv))
            return (NULL);                      /* Interrupted during open */
         signal(SIGINT,opnint);                 /* Catch ctrl-C interrupt */
         ttyfd = open(tmpprt,2);
         if (ttyfd == ERROR)
         {
            signal(SIGINT,SIG_DFL);             /* Default kbd interrupt */
            return(NULL);
         }
         signal(SIGINT,SIG_IGN);                /* Ignore kbd interrupt */
         gtty(ttyfd,&old_mode);                 /* Get old characteristics */
         gtty(ttyfd,&new_mode);                 /* Get copy */
         new_mode.sg_speed &= ~0x1c;            /* Mask old config bits */
         new_mode.sg_speed |= (config << 2);    /* Set new configuration */
         new_mode.sg_flag |= RAW;               /* Set raw mode */
         new_mode.sg_flag &= ~(ECHO|CRMOD);     /* No echo, no auto lf */
         stty(ttyfd,&new_mode);                 /* Set new parameters */
         port_open = TRUE;                      /* Flag it's open now */
      }
      cons_set = FALSE;
      if (!remote)
      {
         if (call_baud)                      /* Only the first time ... */
         {
            baud(tmpprt,speed);              /* set baudrate */
            call_baud = FALSE;               /* Don't set it anymore */
         }
         if (setcons && !nooutput)
         {
            cons_set = TRUE;                 /* Console set as well */
            gtty(0,&old_c_mode);             /* Get console characteristics */
            gtty(0,&new_c_mode);             /* Get copy */
            new_c_mode.sg_flag |= RAW;       /* Set raw mode */
            new_c_mode.sg_flag &= ~(ECHO|CRMOD); /* No echo, no auto lf */
            stty(0,&new_c_mode);             /* Set new console parameters */
         }
      }
      purgeline(ttyfd);                      /* eat old input */
      aborted = FALSE;
      port_open = TRUE;                      /* Mark port open */
   }
   return (TRUE);                            /* valid port found */
}

opnint()
{
   longjmp(popenv,TRUE);                  /* timeout during port open */
}

/*
 * Close communication port
 */

close_port(scrflag,real_close)
int scrflag,
    real_close;
{
   if (!remote && cons_set)
      stty(0,&old_c_mode);
   if ((real_close || remote) && port_open)
   {
      stty(ttyfd,&old_mode);
      close(ttyfd);
      signal(SIGINT,SIG_DFL);                /* Restore keyboard interrupt */
      port_open = FALSE;
   }
   if (scrflag)
      posit(0,23);
   curs_on();                                /* Re-enable cursor */
}

/*
 * read data from port
 */

kread(dev,data,count)
int   dev,count;
char  *data;
{
   int   i, n, p, left,
         clkint();

   i = 0;                           /* Timeout counter */
   if (setjmp(env))
      if ((aborted && !(sflg || rflg)) || ((i += 2) >= timint))
  /* Return TIMOUT if aborted during inactive period, or after real timeout */
         return TIMEOUT;            /* Limit reached, timeout */
   signal(SIGALRM,clkint);          /* Setup timeout catch */
/* Due to the accuracy of the 'alarm' call one second can cause problems */
   alarm(2);                        /* Set two seconds timeout */
   read(dev,data,1);                /* Try to get first character */
   alarm(0);                        /* Got one character, reset timeout */
   if (count > 1)                   /* If more to do ... */
   {
      left = count - 1;             /* What's left to do */
      n = 1;                        /* Starting offset in data array */
      while (left > 0)              /* Until all has been done */
      {
         p = (left > R_CHUNK_SIZE ? R_CHUNK_SIZE : left); /* Read in chunks */
                                    /* of R_CHUNK_SIZE characters or less */
         i = timint;                /* so we will return at timeout */
         alarm(timint);             /* Set selected timeout */
         read(dev,&data[n],p);      /* Try to get the rest of the data */
         alarm(0);                  /* Got the rest, reset timeout */
         left -= R_CHUNK_SIZE;      /* Count down */
         n += R_CHUNK_SIZE;         /* Adjust next array index */
      }
   }
   lastchar = data[count-1];        /* get last entered character */
   if (rflg || sflg)
      chr_rec += count;             /* count chars if sending or receiving */
   if (!remote && !nooutput)
      check_abort();                /* check for abort or toggle debug */
   return NULL;                     /* normal termination */
}


clkint()
{
   check_abort();                   /* check for user abort after timeout */
   longjmp(env,TRUE);
}

/*
 * write characters to port
 */

kwrite(dev,data,count)
int   dev,count;
char  *data;
{
   if (count == 0)                  /* determine count if not given */
      count = strlen(data);
   write(dev,data,count);
   if (rflg || sflg)
      chr_sent += count;            /* count chars if sending or receiving */
}

/*
 * check for user abort
 */

check_abort()
{
   char c;
   struct sgttyb mode;

   if (!cflg)                             /* only when connect is inactive */
   {
      gtty(0,&mode);
      if (mode.sg_speed & INCHR)          /* if character available */
         read(0,&c,1);
      else
      {
         if (remote)
            c = lastchar;                 /* Only check typed character */
         else                             /* if remote */
            c = 0;
      }
      c &= 0177;                          /* strip parity */
      lastchar = 0;
      if ((c == ABORTX) || (c == ABORTZ))
      {                                   /* and if it's the abort char */
         aborted = c;                     /* flag abort */
         return c;
      }
      else if (c == TOGDBG)               /* Toggle debug ? */
      {
         if (debug)
         {
            debug = FALSE;                /* Switch off debug */
            if (dbgfil != ERROR)
            {
               fclose(dbgfil);            /* Close debug output file if open */
               dbgfil = ERROR;
            }
         }
         else
            debug = TRUE;                 /* Switch on debug */
         set_frame();                     /* Make new display frame */
         disp_params();                   /* With the current parameters */
      }
      else if (c == PANIC)
      {
         for (c = 0; c < 3; c++)
            beep();                       /* Ring the bell three times */
         kerm_exit();                     /* Get the hell out of here */
      }
      else if (dstop != NULL && c == dstop) /* Wait.... */
      {
         do
            read(0,&c,1);
         while ((c & 0177) != dstart);    /* Wait for start */
      }
   }
   return NULL;                           /* no abort */
}

/*
 * purge a line of input data
 */

purgeline(port)
int port;
{
   struct sgttyb mode;
   char c;

   while(TRUE)
   {
      gtty(port,&mode);
      if (mode.sg_speed & INCHR)       /* eat characters */
         read(port,&c,1);
      else
         break;
   }
}

/*
  send break
*/

send_break(port)
int port;                       /* Not used */
{
   do_break(tty_descr);         /* Use fixed string descriptor */
}


kdelay(time)
int time;
{
   int timdummy();

   if (time != 0)
   {
      signal(SIGALRM,timdummy);
      alarm(time);
      pause();
   }
}

timdummy()
{
}
