
/*
 * usage: term [-s speed] [-l line] [-e escape-char] [-c callscript]
 * Robert de Bath, rd103925@mayday.cix.co.uk
 * [ small change by M.Andreoli ]

 *      defaults:
 *              speed:  Higest of 115200, 38400 and 2400
 *              line :  /dev/ttyS1
 *              escape: ~
 *                      escape char may be specified as three octal digits
 *
 *      term escapes:
 *              escape-. or escape-CTRLD        terminate
 *              escape-!                        escape to shell
 *              escape-#                        send break
 *              escape-escape                   send escape char
 */

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <setjmp.h>

#ifdef V7
# include <sgtty.h>
#else
# if defined(__linux__) || defined(HAVE_TERMIOS)
#  include <termios.h>
#  ifndef HAVE_TERMIOS
#   define HAVE_TERMIOS
#  endif
# else
#  include <termio.h>
# endif
# ifndef SYSV
#  define SYSV
# endif
#endif

#define XSCRIPT
#define XLOGFILE
#define XCHARXLATE

#ifdef B115200
#define SPEED B115200           /* default speed */
#else
#ifdef B38400
#define SPEED B38400            /* default speed */
#else
#define SPEED B2400             /* default speed */
#endif
#endif

#define LINE    "/dev/ttyS1"    /* the default line  */
#define ESC     '~'             /* default esc char  */
#define EOT     '\004'          /* ^D */

#ifndef R_OK            /* access() modes */
#define R_OK 4
#define W_OK 2
#endif

char esc[2] = { ESC, '\0' };

extern void s_line();      /* set & save line characteristics   */
extern void r_line();      /* reset saved  line characteristics */

int wr_pid = 0;            /* writer process id */
int line_fd;               /* comm line file desc        */
int tty_fd;                /* console   file desc        */
char line_device[64];

#ifdef __STDC__
#define sigtype void
#else
#define sigtype int
#endif

sigtype cleanup();
sigtype open_timeout();

#ifdef CHARXLATE
int Termtype = 2;
#else
int Termtype = 0;
#endif
int Bit_mask = 0xFF;       /* Strip high bit from line */
int Parity = 0;            /* Add parity to line */

#ifdef LOGFILE
FILE * lfile = 0;
char   logfname[64] = "tty/ttylog%d";
char   ltbuf[10240];
char * ltptr = 0;
#endif

#ifdef SCRIPT
int in_script = 0;
char script_name[128];
char script_args[128];
struct script_sv
{
   struct script_sv * next;
   FILE * scrfd;
   char script_args[128];
}
   * saved_sc = 0;

int verbose = 0;
#endif

sigtype cleanup()
{
   int status;
   r_line();
   if( wr_pid ) kill(wr_pid, SIGTERM);
   wait(&status);
#ifdef LOGFILE
   if( lfile ) fclose(lfile);
   lfile = 0;
#endif
   if( wr_pid ) fprintf(stderr, "Disconnected\r\n");
   exit(0);
}

void main(argc, argv)
int argc;
char **argv;
{
   int done, status;
   int speed = SPEED;
   extern char *optarg;
   extern int optind;
   extern int getopt(), conv_speed(), conv_esc(), access();

   strcpy(line_device, LINE);
   while((status = getopt(argc, argv,"s:l:e:rdm7pv")) != EOF)
   {
      switch(status)
      {
      case 's':
         if((speed = conv_speed(optarg)) == EOF)
         {
            fprintf(stderr,"%s: invalid speed\n", optarg);
            exit(1);
         }
         break;
      case 'l':
         strncpy(line_device, optarg, sizeof(line_device));
         if(access(line_device, R_OK|W_OK) == -1)
         {
            perror(optarg);
            exit(2);
         }
         break;

      case 'e': esc[0] = conv_esc(optarg); break;
      case 'p': Parity = 1; /* FALL */
      case '7': Bit_mask = 0x7F; break;
      case 'd': Termtype = 1; break;
#ifdef CHARXLATE
      case 'r': Termtype = 0; break;
#endif
#ifdef SCRIPT
      case 'v': verbose++; break;
#endif
      default:
         fprintf(stderr,
             "usage: %s [-s speed] [-l line] [-e escape-char]\n", *argv);
         exit(3);
      }
   }
   if( optind < argc )
   {
      fprintf(stderr,
             "usage: %s [-s speed] [-l line] [-e escape-char]\n", *argv);
      exit(3);
   }


   signal(SIGALRM, open_timeout);
   alarm(5);
#ifdef O_NDELAY
   if((line_fd = open(line_device, O_RDWR|O_NDELAY)) < 0)
#else
   if((line_fd = open(line_device, O_RDWR)) < 0)
#endif
   {
      perror(line_device);
      exit(4);
   }
#ifdef O_NDELAY
   s_line(speed);
   {
      int fd = line_fd;
      if((line_fd = open(line_device, O_RDWR)) < 0)
      {
         perror(line_device);
         exit(4);
      }
      close(fd);
   }
#endif
   alarm(0);
   signal(SIGALRM, SIG_DFL);

   tty_fd = fileno(stdin);

   signal(SIGINT, SIG_IGN);
   signal(SIGQUIT, SIG_IGN);
   signal(SIGTERM, SIG_IGN);

   s_line(speed);

   signal(SIGTERM, cleanup);

#ifdef SCRIPT
   if( in_script )
      fprintf(stderr, "Running script\r\n");
   else
#endif
      fprintf(stderr, "Connected to modem!\r\n");
      fprintf(stderr, "reset with ATZ, volume with ATL1, ATL2,...\r\n");
      fprintf(stderr, "call with ATDTnumber, exit with ~.\r\n");
      fprintf(stderr, "\r\n");

   signal(SIGCHLD, cleanup);
   fork_writer(); /* launch writer process */
   read_tty();
   cleanup();
}

sigtype open_timeout()
{
   fprintf(stderr, "Cannot open port -- No carrier\n");
   cleanup();
}

typedef struct
{
   char *str;
   int  spd;
} vspeeds;

static vspeeds valid_speeds[] =
{
   { "300",  B300  },
   { "1200", B1200 },
   { "2400", B2400 },
   { "4800", B4800 },
   { "9600", B9600 },
#ifdef B19200
   { "19200", B19200 },
#endif
#ifdef B38400
   { "38400", B38400 },
#endif
#ifdef B57600
   { "57600", B57600 },
#endif
#ifdef B115200
   { "115200", B115200 },
#endif
   { (char *)0, 0 }
};

/*
 * given a desired speed string, if valid return its Bspeed value
 * else EOF
 */
int conv_speed(s)
register char *s;
{
   register vspeeds *p = &valid_speeds[0];

   if(*s == 0) return EOF;

   for(; p->str != (char *)0; p++)
      if(strncmp(s, p->str, strlen(s)) == 0)
         return p->spd;
   return EOF;
}

/*
 * convert given string to char
 *      string maybe a char, or octal digits
 */
int conv_esc(s)
register char *s;
{
   register int val = 0;

   if(!isdigit(*s))
      return *s; /* ! octal */

   /* convert octal digs */
   do
   {
      if(*s > '7' || *s < '0')
      {
         fprintf(stderr,"escape char must be character/octal digits\n");
         exit(4);
      }
      val = (val << 3) + (*s++ - '0');
   } while(isdigit(*s));

   return val;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#ifdef V7
/* This is Version 7 unix code it should work on any unix machine */
/* If you believe that you'll believe anything :-) */

struct sgttyb tty_save, line_save, tty;
int tty_mode = -1;
int got_line = 0;

void s_line(speed)
{
   set_mode(2);
   if(!got_line)
   {
      got_line = 1;
      ioctl(line_fd, TIOCGETP, &line_save);
   }
   tty = line_save;
   tty.sg_ospeed  = speed;      /* Set new speed */
   tty.sg_ispeed  = speed;      /* Set new speed */
   tty.sg_flags  |= RAW;
   tty.sg_flags  &= ~ECHO;
   /* Parity doesn't appear to work with Xenix tty.sg_flags |= EVENP; */
   /* So xmit parity is done in software */
   ioctl(line_fd, TIOCSETP, &tty);
}

void r_line()
{
   set_mode(0);
   if(!got_line) return;
   ioctl(line_fd, TIOCSETP, &line_save);
}

set_mode(which)
int which;
{
    if( tty_mode == -1 )
    {
       if(ioctl(tty_fd, TIOCGETP, &tty))
       {
           perror("Unable to sense terminal");
           exit(1);
       }
       tty_save = tty;
       tty_mode = 0;
    }

    tty = tty_save;
    switch(which)
    {
    default: /* Normal cooked */
            which = 0;
            break;
    case 1: /* CBREAK */
            tty.sg_flags &= ~ECHO;
            tty.sg_flags |= CBREAK; /* Allow break & cr/nl mapping */
            break;
    case 2: /* RAW */
            tty.sg_flags &= ~ECHO;
            tty.sg_flags |= RAW;
            break;
    }
    if(ioctl(tty_fd, TIOCSETP, &tty))
    {
        perror("Unable to change terminal mode");
    }
    else tty_mode = which;
}
#endif
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#ifdef SYSV
/* This is System V unix code */

#ifdef HAVE_TERMIOS
struct termios tty_save, line_save, tty;
#else
struct termio tty_save, line_save, tty;
#endif
static int tty_mode = -1;
int got_line = 0;

void s_line(speed)
int speed;
{
   set_mode(2);
   if(!got_line)
   {
      got_line = 1;
#ifndef HAVE_TERMIOS
      ioctl(line_fd, TCGETA, &line_save);
#else
      tcgetattr(line_fd, &line_save);
#endif
   }
   tty = line_save;

   tty.c_iflag &= ~(IXON|IXANY|IXOFF|ISTRIP|INLCR|ICRNL|IGNCR|IUCLC);
   tty.c_oflag &= ~(OLCUC|ONLCR|OCRNL|ONOCR|ONLRET);
   tty.c_cflag &= ~(CBAUD|PARENB);
   tty.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHONL|ISIG);
#ifdef CBAUDEX
   tty.c_cflag &= ~(CBAUDEX);
#endif
   tty.c_cflag &= ~(CBAUD|PARENB);

   tty.c_iflag |= IXOFF;        /* X/Y modem will clear this */
   tty.c_cflag |= CLOCAL|(speed);

   tty.c_cc[VTIME] = 0;
   tty.c_cc[VMIN]  = 1;

#ifndef HAVE_TERMIOS
   ioctl(line_fd, TCSETA, &tty);
#else
   tcsetattr(line_fd, TCSANOW, &tty);
#endif
}

void r_line()
{
   set_mode(0);
   if(!got_line) return;
#ifndef HAVE_TERMIOS
   ioctl(line_fd, TCSETA, &line_save);
#else
   tcsetattr(line_fd, TCSANOW, &line_save);
#endif
}

set_mode(which)
int which;
{
    if( tty_mode == -1 )
    {
#ifndef HAVE_TERMIOS
       if(ioctl(tty_fd, TCGETA, &tty))
#else
       if(tcgetattr(tty_fd, &tty))
#endif
       {
           perror("Unable to sense terminal");
           exit(1);
       }
       tty_save = tty;
       tty_mode = 0;
    }

    tty = tty_save;
    switch(which)
    {
    case 0: /* Normal cooked */
            break;
    case 1: /* CBREAK */
            tty.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHONL);
            tty.c_lflag |= ICRNL|ISIG;
            tty.c_cc[VTIME] = 0;
            tty.c_cc[VMIN]  = 1;
            break;
    case 2: /* RAW */
            tty.c_oflag &= ~OPOST;
            tty.c_iflag &= ~(ICRNL|IGNCR|INLCR);
            tty.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHONL|ICRNL|ISIG);
            tty.c_cc[VTIME] = 0;
            tty.c_cc[VMIN]  = 1;
            break;
    }

#ifndef HAVE_TERMIOS
    if(ioctl(tty_fd, TCSETA, &tty))
#else
    if(tcsetattr(tty_fd, TCSANOW, &tty))
#endif
    {
        perror("Unable to change terminal mode");
    }
    else tty_mode = which;
}
#endif
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

fork_writer()
{
#ifdef LOGFILE
   if( lfile ) fflush(lfile);
#endif
   if (wr_pid = fork())
   {
      if (wr_pid == -1)
      {
         r_line();
         perror("Cannot fork writer");
         exit(0);
      }
      return;
   }
#ifdef LOGFILE
   if(lfile) fclose(lfile);
   lfile = 0;
#endif
   signal(SIGCHLD, SIG_DFL);
   write_tty();
   cleanup();
}

write_tty()
{
   char ch;
   char was_newline = 1;

   signal(SIGINT,  SIG_IGN);
   signal(SIGQUIT, SIG_IGN);
   signal(SIGTERM, cleanup);

   while (1) {
      read(0, &ch, 1);
      ch &= (char)0177;

      if (was_newline) {
         if (ch == esc[0]) {
            read(0, &ch, 1);
            ch &= (char)0177;

            switch (ch) {

            case EOT:
            case '.':
            case '>':
               read(0, &ch, 1);
               exit(0);

            case '!':
               /* tell reader to pause */
               kill(getppid(), SIGUSR1);
               /*do_shell(); */
               /* wake him up again */
               if( kill(getppid(), SIGUSR2) < 0 ) exit(0);
               ch = '\377';
               break;

            default:
               if(ch != esc[0])
               {
                  fprintf(stderr, "invalid command--use\
 \"~~\" to start a line with \"~\"\r\n");
               }

            }
         }
      }

      if (ch == '\r' || ch == '\004' || ch == '\003' || ch == '\177')
         was_newline = 1;
      else
         was_newline = 0;

      if( ch != '\377' )
      {
         int i;
         if( Parity )
         {
            ch &= 0x7F;
            for(i=0; i<7; i++) if( ch & (1<<i) ) ch ^= 0x80;
         }
         write(line_fd, &ch, 1);
      }
   }
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/


#define NCHRS 4096
static char chrs[NCHRS];

int alarm_delay = 0;
jmp_buf timebuf;
int is_in    = 0;

sigtype alarm_int() { if( is_in ) longjmp(timebuf, -1); }

char zmodem_buf[20];
char *zptr=zmodem_buf;

char z_request[]   =  "*\030B00";
char z_challange[] = "**\030B0e313233341821\r\n";
char z_charesp[]   =  "*\030B0331323334395b";

/* With this you become a SZModem ver 1.x
char z_challange[] = "**\030B0e534d4201053c\r\n";
char z_charesp[]   =  "*\030B03424d5301";
/* */

int paused = 0;

sigtype unpause_reader()
{
   paused = 0;
}

sigtype pause_reader()
{
   alarm(0); is_in = 0;

   write(2, "Paused\r\n", 8);
   signal(SIGUSR1, SIG_IGN);
   signal(SIGUSR2, unpause_reader);
#ifdef LOGFILE
   if( lfile ) fflush(lfile);
#endif
   paused = 1;
   while(paused) pause();
   signal(SIGUSR2, SIG_IGN);
   signal(SIGUSR1, pause_reader);
   write(2, "Continue\r\n", 10);
}

read_tty()
{
   register int i, n;
   register char *p;

   /* Child process */
   signal(SIGINT,  SIG_IGN);
   signal(SIGQUIT, SIG_IGN);
   signal(SIGTERM, cleanup);
   signal(SIGUSR1, pause_reader);

#ifdef SCRIPT
   if( in_script )
   {
      open_script(script_name);
      signal(SIGINT, cleanup);
      set_mode(1);
      alarm_delay = 2;
   }
#else
#ifdef LOGFILE
   open_logfile();
#endif
#endif

   for(;;)
   {
      if( alarm_delay )
      {
         signal(SIGALRM, alarm_int);
         alarm(2);
         if( setjmp(timebuf) == 0 )
         {
            is_in = 1;
            n = read(line_fd, chrs, (int)NCHRS);
            is_in = 0;
         }
         else
         {
            chrs[0] = 0xFF;
            n = 1;
         }
         alarm(0);
         signal(SIGALRM, SIG_DFL);
      }
      else
         n = read(line_fd, chrs, (int)NCHRS);
      if( n == 0 )
      {
         printf("Carrier Lost\r\n");
         break;
      }
      if( n > 0 )
      {
         for(i=0;i<n;i++)
         {
#ifdef SCRIPT
            if( !in_script || chrs[i] != '\377' )
            {
#endif
#ifdef LOGFILE
               if( lfile ) fputc(chrs[i], lfile);
               else if( ltptr && ltptr < ltbuf+sizeof(ltbuf) )
                  *ltptr++ = chrs[i];
#endif
               switch(Termtype)
               {
               case 1:  dumbch(chrs[i]&Bit_mask); break;
#ifdef CHARXLATE
               case 2:  outchar(chrs[i]&Bit_mask); break;
#endif
               default: putchar(chrs[i]&Bit_mask); break;
               }
#ifdef SCRIPT
            }
            if( in_script )
            {
               in_script = out_schar(chrs[i]);
               if( !in_script )
               {
                  close_script();
                  printf("\r\nScript completed\r\n");
                  alarm_delay = 0;
                  set_mode(2);
                  signal(SIGINT, SIG_IGN);
#ifdef LOGFILE
                  if( lfile == 0 ) open_logfile();
#endif
               }
            }
#endif
         }

         fflush(stdout);
         /* NOTE Zmodem needs an 8 bit channel this check is 8-bit */
         /* check_zmodem(chrs, n); */
      }
   }
#ifdef LOGFILE
   if( lfile ) fclose(lfile);
   lfile = 0;
#endif
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

dumbch(ch)
int ch;
{
static int cr_pend = 0;

   if( cr_pend )
   {
      if( ch == '\n' ) putchar('\r');
      else { putchar('^'); putchar('M'); }
      cr_pend = 0;
   }
   if( ch == '\r' )
      cr_pend = 1;
   else
   {
      if( ch & 0x80 )
         printf("M-");
      if( isprint(ch&0x7F) || ch == '\n' || ch == '\b' )
         putchar(ch&0x7F);
      else
      {
         putchar('^');
         putchar((ch ^ '@')&0x7F);
      }
   }
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

#ifdef SCRIPT

#define MAXMATCH 20   /* Max number of match strings at a time */
#define MATCHLEN 20   /* Max size of a match string */
static int starcount = 50;

static FILE * script_file;
static char buffer[MATCHLEN*3];
static int offset = sizeof(buffer)/2;
static check_match();
static clear_matchtab();
static read_matchset();
static char * get_item();
static vdisp();
static script_com();

static int timeout  = 0;
static long last_ok = 0;

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

out_schar(ch)
int ch;
{
   long now;
   int ok = 1;

   if( ch != 0 ) /* Completely ignore nuls */
   {
      if( ch != '\377' ) buffer[offset++] = (ch&0x7F);
      else               buffer[offset++] = '\377';
      if( offset == sizeof(buffer) )
      {
         offset = sizeof(buffer)/2;
         memcpy(buffer, buffer+sizeof(buffer)/2, sizeof(buffer)/2);
      }
      buffer[offset] = '\0';

      ok = check_match();
   }
   time(&now);
   if( timeout && now > last_ok + timeout )
   {
      printf("\r\nTimeout ... Script aborted\r\n");
      cleanup();
   }
   return ok;
}


#define VALIDREC        1       /* This record is available for matching */
#define ALTMATCH        2       /* Is an extra match record for prev line */
#define SCCOM           4       /* sendstr is a script command */
#define UXCOM           8       /* sendstr is a unix command */

static
struct matchrec
{
   char match[MATCHLEN];
   int  matchlen;
   int  maxcount;
   char * sendstr;
   int  flags;
}
   matchtab[MAXMATCH];

static int matcount;

static
check_match()
{
   struct matchrec * sptr;
   struct matchrec * mptr;
   extern int line_fd;
   int i,j;
   int checked_one;

Restart:
   sptr = matchtab;
   mptr = matchtab;
   checked_one = 0;

   for(i=0; i<matcount; i++, mptr++)
   {
      if( (mptr->flags & ALTMATCH) == 0 ) sptr = mptr;

      if( (sptr->flags & VALIDREC) == 0 ) continue;
      checked_one = 1;
      if( (mptr->matchlen == 0
           || ( buffer[offset-mptr->matchlen] == mptr->match[0]
              && strcmp(buffer+offset-mptr->matchlen, mptr->match) == 0 )
          )
        )
      {
         time(&last_ok);
         offset = sizeof(buffer)/2;
         memset(buffer, 0, sizeof(buffer));
         if( mptr->matchlen ) vdisp(0, "<Found>\r\n");
         if( sptr->flags & SCCOM )
            switch(script_com(sptr->sendstr))
            {
            case 0: break;
            case 1: close_script(); return 0;
            case 2: goto Restart;
            }
#if 0
         else if( sptr->flags & UXCOM )
#endif
         else
         {
            vdisp(0, "<Sending> '");
            if( line_fd )
            {
               /* Yes we want this ssslllooowww incase */
               /* the other end is stupid */
               /* Of course this isn't really that slow */
               char ch[2];
               ch[1] = '\0';
               for(i=0; sptr->sendstr[i]; i++)
               {
                  ch[0] = sptr->sendstr[i];
                  vdisp(1, ch);
                  if(*ch == '\377')
                     sleep(2);
                  else
                  {
                     write(line_fd, ch, 1);
#ifdef M_XENIX
                     nap(20);
#else
                     usleep(20000L);
#endif
                  }
               }
            }
            vdisp(0, "'\r\n");
         }
         time(&last_ok);
         if( sptr->maxcount )
         {
            if( --(sptr->maxcount) == 0 )
            {
               sptr->flags &= ~VALIDREC;
            }
         }
         else
         {
            read_matchset();
            goto Restart;   /* Incase this is a '- "Send"' line */
         }
         break;
      }
   }
   return checked_one;
}

static
clear_matchtab()
{
   int i;
   for(i=0; i<matcount; i++)
      if( matchtab[i].sendstr ) free(matchtab[i].sendstr);
   memset(matchtab, 0, sizeof(matchtab));
   matcount = 0;
}

static
read_matchset()
{
   char lbuf[128];
   char sbuf[128];
   char * p;
   int i;
   int saveptr;
   int keepgoing = 1;
   struct matchrec new;
   int wflg = 0;

   clear_matchtab();
   memset(&new, 0, sizeof(new));
   if( script_file == 0 ) return;

   while( keepgoing )
   {
      if( fgets(lbuf, sizeof(lbuf), script_file) == 0 )
      {
         struct script_sv *p = saved_sc;
         if( p == 0 ) break;
         fclose(script_file);
         script_file = p->scrfd;
         strcpy(script_args, p->script_args);
         saved_sc = p->next;
         free(p);
         continue;
      }
      p = lbuf;
      while( *p == ' ' || *p == '\t' ) p++;
      if( *p == '#' || *p == '\n' || *p == '\0' ) continue;
#ifdef VARS
      if( *p == '%' )
      if( *p == '$' )
#endif
      memset(&new, 0, sizeof(new));
      if( *p == '*' || *p == '?' )
      {
         if( *p == '?' ) new.maxcount = 1;
         else            new.maxcount = starcount;
         p++; while( *p == ' ' || *p == '\t' ) p++;
      }
      else
         keepgoing = 0;
      saveptr = matcount;
      do
      {
         if( *p == ',' ) p++;

         p = get_item(p, new.match, sizeof(new.match), 0);
         if( p == 0 )
         {
            fprintf(stderr, "Syntax error:%s", lbuf);
            goto next_line;
         }
         new.matchlen = strlen(new.match);
         if( new.matchlen )
         {
            if( wflg == 0 ) { vdisp(0, "<Waiting>"); wflg = 1; }
            vdisp(0, " '");
            vdisp(1, new.match);
            vdisp(0, "'");
         }
         while( *p == ' ' || *p == '\t' ) p++;
         if( matcount >= MAXMATCH )
            fprintf(stderr, "Too many match strings\r\n");
         else
         {
            matchtab[matcount] = new;
            matcount++;
            new.flags |= ALTMATCH;
         }
      }
      while( *p == ',');

      p = get_item(p, sbuf, sizeof(sbuf), 1);
      if( p == 0 )
      {
         fprintf(stderr, "Syntax error:%s", lbuf);
         goto next_line;
      }
      if( *sbuf != '"' )
      {
         matchtab[saveptr].sendstr = malloc(strlen(sbuf)+1);
         strcpy(matchtab[saveptr].sendstr, sbuf);
         matchtab[saveptr].flags |= SCCOM;
         while( (p = get_item(p, sbuf, sizeof(sbuf), 1)) != 0 )
         {
            matchtab[saveptr].sendstr = realloc(matchtab[saveptr].sendstr,
                     strlen(matchtab[saveptr].sendstr) + strlen(sbuf)+2);
            strcat(matchtab[saveptr].sendstr, " ");
            strcat(matchtab[saveptr].sendstr, sbuf);
         }
      }
      else
      {
         matchtab[saveptr].sendstr = malloc(strlen(sbuf));
         strcpy(matchtab[saveptr].sendstr, sbuf+1);
      }
      matchtab[saveptr].flags |= VALIDREC;

next_line: ;
   }
   if( wflg ) vdisp(0, "\r\n");
}

static char *
get_item(p, buf, szbuf, itype)
char * p;
char * buf;
int szbuf;
int itype;
{
   char stc;
   while( *p == ' ' || *p == '\t' ) p++;
   if( *p == '-' )
   {
      if( itype == 0 ) buf[0] = '\0'; else buf[0] = '"';
      buf[1] = '\0';
      p++; return p;
   }
   else if( ( itype == 0 && *p != '"' ) || *p == '\0' )
   {
      buf[0] = '\0'; return 0;
   }
   if( itype == 0 ) stc = *p++;
   else { *buf++ = stc = *p++; szbuf--; }
   while( *p )
   {
      if( stc == '"' && *p == '"' ) break;
      if( stc != '"' && (*p == ' ' || *p == '\t' || *p == '\n') ) break;
      if( szbuf < 2+(itype&1) ) { p++; continue; ; }
      szbuf--;
      if( *p == '\\' && p[1] )
      {
         switch(p[1])
         {
         case 'b': *buf++ = '\b'; break;
         case 'c': itype &= ~1; break;
         case 'd': *buf++ = '\377'; break;
         case 'f': *buf++ = '\f'; break;
         case 'n': *buf++ = '\n'; break;
         case 'r': *buf++ = '\r'; break;
         case 't': *buf++ = '\t'; break;
         case 'a':
            {
               char * q = script_args;
               while(*q) *buf++ = *q++;
            }
            break;
         default:  *buf++ = p[1]; break;
         }
         p+=2;
      }
      else
         *buf++ = *p++;
   }
   if( itype&1 && stc == '"' ) *buf++ = '\r';
   *buf = 0;
   if( *p ) p++;
   return p;
}


static vdisp(flg, str)
int flg;
char * str;
{
   if( verbose != 1 ) return;
   fflush(stdout);
   if( !flg ) fprintf(stderr, "%s", str);
   else while( *str )
   {
      int ch = *str++;
      ch &= 0xFF;
      if( ch >= ' ' && ch != 0x9B && ch != '\\' && ch != 0xFF)
         fputc(ch, stderr);
      else if( ch < ' ' )
         fprintf(stderr, "^%c", ch+'@');
      else if( ch == 0xFF )
         fprintf(stderr, "\\d");
      else
         fprintf(stderr, "\\0x%02x", ch);
   }
}
#endif

