SRI-NOSC/mmdf/dialdir/dlopen.c

Compare this file to the similar file:
Show the results in this format:

# include  "rm.h"
# include  "rmerr.h"
# include  "rmenv.h"




/*
 *     Local convenience definitions
 */

# define  FATAL        1          /*  error has no recovery or retry  */
# define  NONFATAL     2          /*  error with success possible with retry  */

# define  PORTRAW   0341          /*  mode of port when interpreting script  */
# define  PORTCONN  0301          /*  port mode during protocol  */




/*  globals for 'dlopen'  */

  struct
    {
    int  o_sline;                 /*  number of current line in script file  */
    int  o_nqueue;                /*  number of characters in 'o_inque'  */
    char  o_slave[LSLAVNAM];      /*  slave startup string  */
    char  o_canon[30];            /*  translated canonical phone number  */
    char  o_inque[PUSHBACK];      /*  queue for pushed back input characters  */
    char  o_portnm[64];           /*  name of dial out port  */
    char  o_linebuf[MAXLINE];     /*  line buffer for script file  */
    char  *o_inqpt;               /*  pointer to 'o_inque'  */
    struct iobuf  o_sbuff;        /*  io buffer for script file  */
    }  d_open;

  extern struct rmenv  rmenv;     /*  protocol environment structure  */
  extern char dialdev[]; /* dialing device name */





/*
 *      routine which is called to establish a connection with the other
 *      side.
 */

dlopen(scriptfile, port, logfile, tranfile, debugf, ttylog)
  char  *scriptfile, *port, *logfile, *tranfile;
  int  debugf, ttylog;
    {
    extern int  errno;
    register int  result;
    char  msgbuff[MAXMESG];

/*  set up defaults  */

    rmenv.d_linelgh = MAXMESG;
    rmenv.d_window = WINDOW;

/*  start logging and save the port name  */

    result = d_strtlog(logfile, tranfile, debugf, ttylog);
    if (result < 0)
      return(result);

    cpstr(port, d_open.o_portnm);

/*  try to open script file  */

    if (fopen(scriptfile, &d_open.o_sbuff) < 0)
      {
      d_log("***** couldn't open script file - errno %d", errno);
      return(EUSER);
      }

/*  now interpret it  */

    result = d_script();
    if (result < 0)
      return(result);

/*  write the slave startup string on the port and look for a RUN reply  */

    alarm(MATCHTIM);
    result = write(rmenv.d_portfd, d_open.o_slave, length(d_open.o_slave));
    alarm (0);
    if (result < 0)
      {
      d_log("***** error writing slave startup string on port - errno %d",
            errno);
      return(ESYSTEM);
      }
    result = d_initrecv();
    if (result < 0)
      return(result);

    result = d_initsend();
    if (result < 0)
      return(result);

    return(OK);
    }




/*
 *     this routine is called to close the port and cause the line to
 *     be hung up
 */

dlclose()
    {

    if (close(rmenv.d_portfd) < 0)
      {
      d_log("***** error closing port - errno %d", errno);
      return(ESYSTEM);
      }

    return(OK);
    }




/*
 *     this routine reads the script file and interprets it
 */

d_script()
    {
    register int  nfields, result;
    char  *fields[MAXFIELDS], sendbuff[MAXLINE];

/*  read in lines from the script file and break them up into fields.  */
/*  a 0 return from the 'parselin' function indicates that a blank     */
/*  line was encountered, which we'll ignore                           */

    while (1)
      {
      nfields = parselin(fields, d_open.o_linebuf, &d_open.o_sbuff, MAXLINE, MAXFIELDS);
      d_open.o_sline++;

      switch (nfields)
        {
        case  0:

            continue;

        case  -1:

            d_serror("unexpected eof");
            return(EUSER);

        case  -2:

            d_serror("line too long");
            return(EUSER);

        case  -3:

            d_serror("too many fields on line");
            return(EUSER);

        case  -4:

            d_serror("quoted string not closed");
            return(EUSER);
        }

/*  now use the code character in field 0 to determine function  */

      switch (*fields[0])
        {

/*  get phone number and dial it  */

        case  'p':

            if (nfields != 2)
              {
              d_serror("2 fields expected for 'p'");
              return(EUSER);
              }

            result = d_illchar(fields[1], d_open.o_canon);
            if (result < 0)
              return(result);

            result = d_dodial(d_open.o_canon);
            if (result < 0)
              return(result);

            continue;

/*  get startup string for slave process  */

        case  'u':

            if (nfields != 2)
              {
              d_serror("2 fields expected for 'u'");
              return(EUSER);
              }

            if (d_canon(fields[1], d_open.o_slave) < 0)
              {
              d_serror("canonical string error");
              return(EUSER);
              }

            continue;

/*  send string to remote system  */

        case  's':
        case  't':

            if (nfields != 2)
              {
              d_serror("2 fields expected for 's' or 't'");
              return(EUSER);
              }

            if (d_canon(fields[1], sendbuff) < 0)
              {
              d_serror("canonical string error");
              return(EUSER);
              }

            d_dbglog("script: sending '%s'", fields[1]);

            result = d_strout(sendbuff);
            if (result < 0)
              return(result);

            continue;

/*  watch for string from remote system  */

        case  'r':

            result = d_strwatch(fields, nfields);
            if (result < 0)
              return(result);

            continue;

/*  pause in script interpretation to do the file transfers  */

        case  'g':

            if ((result = d_chgport(PORTCONN)) < 0)
              return(result);

            d_log("script pause - starting protocol");
            return(OK);

/*  unrecognized script command character  */

        default:

            d_serror("unrecognized script command character");
            return(EUSER);
        }
      }
    }




/*
 *     routine which manages the dialing.  it forks off the dialer and then
 *     trys to open the port.  if the open completes without error, we have
 *     a successful connection.  if the call was interrupted by a signal,
 *     die quietly.
 */

d_dodial(number)
  char  *number;
    {
    extern int  errno;
    register int  result;
    int pid;
    int  status;

/*  spawn the dialer  */

    result = d_dialer(number, &pid);
    if (result < 0)
      return(result);

/*  try to open the dialer.  if there's and error and it's and interrupt,  */
/*  then the dialer may have had a problem.  check for the right signal    */
    alarm(MATCHTIM);
    rmenv.d_portfd = open(d_open.o_portnm, 2);
    alarm (0);
    if (rmenv.d_portfd < 0)
      if (errno != UEINTR)
        {
	kill (pid, 9);
        d_log("error opening port '%s' errno %d", d_open.o_portnm, errno);
        return(ESYSTEM);
        }

      else
        {
	alarm(MATCHTIM);
	while ((result = waita(&status)) != pid && result != -1);
	alarm (0);
        if (status.hibyte == SIGIOT)
          {
          d_log("dial failed");
          return(ESYSTEM);
          }
        else
          {
          d_log("signal %d interrupted port open call", status.hibyte);
          return(ESYSTEM);
          }
        }

    else
      if ((result = d_setport(PORTRAW)) < 0)
        {
	alarm(MATCHTIM);
	while ((result = waita(&status)) != pid && result != -1);
	alarm (0);
        return(result);
        }

/*  collect the dead child  */

	alarm(MATCHTIM);
	while ((result = waita(&status)) != pid && result != -1);
	alarm (0);
    d_log("connection established");
    }




/*
 *     this routine spawns a child process to open the acu and do the
 *     actual dialing of the number.  the argument string must have the
 *     exact format to be passed to the dialer including tandem dialing
 *     indiactors
 */

d_dialer(number, pid)
  char  *number;
  int *pid;     /* so caller can do wait        */
    {
    extern int  errno;
    extern  d_iotcatch();
    register int  result, try;
    int  parentpid;

    parentpid = getpid();
    signal(SIGIOT, d_iotcatch);

/*  fork so dial process can proceed in parallel  */

/*    d_dbglog("dialer: calling number '%s'", number);*/
    d_dbglog("dialer: calling number");

    *pid = tryfork();

    if (*pid < 0)
      {
      d_log("couldn't fork for dialer");
      return(ESYSTEM);
      }

/*  parent just returns and child does actual dialing  */

    if (*pid)
      return(0);

    for (try = 0; try < NDIALS; try++)
      {
      d_log("Dialing...");
      result = d_realdial(number);

      if (result == FATAL)
        break;

      if (try < (NDIALS - 1))
        sleep(DIALTIME);
      }

/*  we can't get through, so we should signal our parents and die  */

    kill(parentpid, SIGIOT);
    exit (-1);
    }




/*
 *     this routine does the real dialing and decoding of errors
 */
dlopsig ()
{
    signal (14, &dlopsig);
}
d_realdial(number)
  register char  *number;
    {
    register int  acu, flag, errsave;

/*  open the acu, and if we're successful write the number on it  */
    signal (14, &dlopsig);
    flag = 0;
    alarm(MATCHTIM);
/*    acu = open("/dev/acu13",2); */
	if(dialdev[0]==0){
		exit(0);
	}
    acu = open(dialdev,2);
    if (acu != -1)
      {
      flag = 1;
    alarm(MATCHTIM);
      if (write(acu,number,length(number)) != -1)
        exit();
      }
    alarm (0);

/*  handle all errors.  close the acu first so we can return with no  */
/*  extraneous open files to cause problems with retries              */

    errsave = errno;
    close(acu);

    switch (errsave)
      {
      case  UEBUSY:

          if (flag)
            d_log("That number is busy");
          else
            d_log("dialer in use");
          return(NONFATAL);

      case  UEDNPWR:

          d_log("dialer power off");
          return(FATAL);

      case  UEDNABAN:

          d_log("call abandoned");
          return(NONFATAL);

      case  UEDNDIG:

          d_log("internal error: bad digit to dialer");
          return(FATAL);

      default:

          d_log("system error #%d", errsave);
          return(FATAL);
      }
    }




/*
 *     routine to catch iot signals so they'll interrupt open calls to the
 *     port
 */

d_iotcatch()
    {

    signal(SIGIOT, d_iotcatch);
    }




/*
 *     this routine interprets the match string line and attempts to
 *     find the sequence in the input stream
 */

d_strwatch(fields, nfields)
  char  *fields[];
  int  nfields;
    {
    register int  timer, val;
    char  tbuff[80];

    if ((nfields < 2) || (nfields > 3))
      {
      d_serror("line format error");
      return(EUSER);
      }

    if (d_canon(fields[1], tbuff) < 0)
      {
      d_serror("string format error");
      return(EUSER);
      }

    if (length(tbuff) > PUSHBACK)
      {
      d_serror("match string too long");
      return(EUSER);
      }

/*  convert the time out value if one is given  */

    if (nfields == 3)
      {
      timer = atoi(fields[2]);

      if ((timer < 0) || (timer > 300))
        {
        d_serror("bad timeout value");
        return(ETIMEOUT);
        }
      }

    else
      timer = MATCHTIM;

/*  look for the string.  watch for interrupted calls from the alarm  */

    d_dbglog("strwatch: trying to match '%s'", tbuff);

    alarm(timer);
    while (1)
      {
      val = d_match(tbuff);

      if (val == -1)
        if (d_rawgetc() < 0)
          break;
        else
          continue;

      if (val == -2)
        break;

      alarm(0);
      return(OK);
      }

/*  alarm timeouts come here  */

    d_log("no match for '%s' after %d seconds", fields[2], timer);
    return(EUSER);
    }




/*
 *     routine to translate the external form of a startup string to an
 *     internal 'canonical' form
 */

d_canon(in,out)
  register char  *in,*out;
    {
    extern char  *d_escvalue();
    register int  value;
    char  c;

/*  check for obvious bad format  */

    if (*in++ != '"')
      return(-1);

/*  loop through all the characters.  lots of special cases  */

    while (1)
      {
      c = *in++;

      switch (c)
        {
        default:

            *out++ = c;
            continue;

        case  '\0':

            return(-1);

        case  '"':

            *out = '\0';
            return(0);

        case  '\\':

/*  handle the escapes  */

            c = *in++;

            switch (c)
              {
              case  '"':

                  *out++ = '"';
                  continue;

              case  '\0':

                  return(-1);

              case  '\\':

                  *out++ = '\\';
                  continue;

              case  'r':

                  *out++ = 015;
                  continue;

              case  'n':

                  *out++ = 012;
                  continue;

              case  't':

                  *out++ = 011;
                  continue;

              case  'x':

                  *out++ = 0377;
                  continue;

/*  allow the specification of characters by up to 3 octal digits after a  */
/*  backslash                                                              */

              default:

                  in = d_escvalue(--in,out++);

              }
        }
      }
    }




/*
 *     this routine does the translation of numerical escape sequences into
 *     a character with the given octal value
 */

char  *d_escvalue(string,out)
  register char  *string,*out;
    {
    register int  value;
    int  count;
    char  c;

    value = 0;
    c = *string++;

    if ((c < '0') || (c > '7'))
      {
      *out = c;
      return(string);
      }

    value = c & 07;

    for (count = 0; count <= 1; count++)
      {
      c = *string++;

      if ((c >= '0') && (c <= '9'))
        value = (value << 3) | (c & 07);
      else
        {
        *out = value;
        return(--string);
        }
      }

    *out = value;
    return(string);
    }




/*
 *     routine which checks for legal characters in a phone number, discards
 *     extraneous ones, and performs some mapping.  it complains about
 *     illegal ones and number longer than 20 digits or codes.
 */

d_illchar(string,outbuff)
  register char  *string,*outbuff;
    {
    register int  count;

    count = 0;

    while (*string)
      {

      if (count > 20)
        {
        d_serror("phone number too long");
        return(EUSER);
        }

      if ((*string >= '0') && (*string <= '9'))
        {
        *outbuff++ = *string++;
        count++;
        continue;
        }

      switch (*string)
        {
        case  '(':
        case  ')':
        case  '-':

            string++;
            continue;

        case  ':':

            *outbuff++ = '=';
            count++;
            string++;
            continue;

        default:
		*outbuff++ = *string++;
		count++;
		continue;

/*            d_serror("unknown character in phone number");
            return(EUSER); */
        }
      }

    return(0);
    }




/*
 *     this routine checks for a match between the string and the input
 *     stream.  what it dies is read characters from the input and compare
 *     them with the string.  if a match is not found, all the characters
 *     that have been read are pushed back.  if a match is read, the
 *     characters are eaten.  1 is returned on a match, -1 on failure.
 */

d_match(string)
  char  *string;
    {
    register int  c, val;

    if (*string == '\0')
      return(1);

    c = d_rawgetc();

    if (c < 0)
      return(c);

    if (c == *string)
      {
      val = d_match(++string);

      if (val < 0)
        {
        und_rawgetc(c);
        return(val);
        }
      else
        return(1);
      }

    else
      {
      und_rawgetc(c);
      return(-1);
      }
    }




/*
 *     this routine reads a character from the comm line and filters out the
 *     wierd ones.  this routine is called only during script interpretation.
 */

d_rawgetc()
    {
    extern int  errno;
    register int  result;
    char  c;

/*  if there's anything queued, use it first  */

    if (d_open.o_nqueue)
      {
      d_open.o_nqueue--;
      return(*d_open.o_inqpt--);
      }

/*  no such luck.  we have to do a read.  don't return anything wierd  */

    while (1)
      {
      result = read(rmenv.d_portfd, &c, 1);
      if (result == 0)
        return(ESYSTEM);

      if (result < 0)
        if (errno == UEINTR)
          return(ETIMEOUT);
        else
          return(ESYSTEM);


      c =& 0177;

      if (((c < 040) && (c != '\t') && (c != '\n')) || (c == 0177))
        continue;

/*  write it on the transcript file  */

      d_tscribe(&c, 1);
      return(c);
      }
    }




/*
 *      this returns a character to the input queue so he'll get read again
 */

und_rawgetc(c)
  char  c;
    {

/*  if none are currently queued, set things up  */

    if (d_open.o_nqueue == 0)
      {
      d_open.o_inqpt = d_open.o_inque;
      *d_open.o_inqpt = c;
      d_open.o_nqueue = 1;
      }

    else
      {
      *++d_open.o_inqpt = c;
      d_open.o_nqueue++;
      }
    }




/*
 *     routine which dumps a string on the port and also interprets the
 *     sleep characters
 */

d_strout(string)
  char  *string;
    {
    int result;

    while (*string)
      {
      if (*string == 0377)
        sleep(1);

      else
	{
	alarm(MATCHTIM);
	result = write(rmenv.d_portfd, string, 1);
	  alarm (0);
	if (result <= 0)
          {
          d_log("raw mode port write error");
          return(ESYSTEM);
          }
	}
      string++;
      }
    }




/*
 *     routine to log errors found while interpreting script file
 */

d_serror(message)
  char  *message;
    {

    d_log("***** Script %d: %s", d_open.o_sline, message);
    }