#define I_SYS
#define I_ERRNO
#define I_GETOPT
#define I_STRING
#define I_SOCKET
#define I_IOCTL
#include "includes.h"

#include <sys/wait.h>
#include <sys/stat.h>
#include <signal.h>

#include "debug.h"


/*
 *
 * main file. Calls everything else. ;)
 * 
 * basically consists of select() and then calls things based on the select().
 *
 */
/*------------------------------------------------------------------------*/
/* truely global vars. Used everywhere. */
unsigned long current_time = 0;
int do_shutdown	 = 0;
int term_debug = 0;
int compressing = 1;
int onetime_term_socket = -1;
/*------------------------------------------------------------------------*/
/* Various global variables. Note that most of these vars are local to    */
/* this file. Where possible (i.e. where it doesn't impinge efficency) 	  */
/* this is enforced */
int remote = 0;

struct Client clients[MAX_CLIENTS];
int num_clients = 0;
int baudrate =   2400;
int bytes_left = 1024; /* bytes availiable to send this second.. */
int fudge_flow = 0; /* should we generate periodic control-Q's */
int byte_shift = 0; /* So we can map less frequently uses section down to */
                    /* 0-32 */
int window_size = 3; /* A convenient number. 9600 baud users should probly */
				/* go to 2. */
unsigned long packet_timeout = 70; /* wait 3.5 seconds for a packet to time out */
int do_forceing = 1; /* weather or not to automatically transmit packets */
				/* if the window is full, and the out */
				/* buffer is empty. */
int write_noise = 0; /* whether we should print out all the the serial stuff */
				/* we get that we don't understand.. */

int seven_bit_in = 0;		/* Are we on a line that ignores the */
				/* top bit. */
int in_mask = 255;
int seven_bit_out = 0;
int out_mask = 255;
int breakout_char = '0';

int stat_modem_in = 0,
  stat_modem_out = 0,
  stat_cooked_in = 0,
  stat_cooked_out = 0,
  stat_rare_out = 0;

#ifdef SHAREDIR
extern int share;
char *share_p;
#endif
char *home_p;

int rshtype = 1;  /* Default to allow rsh and use login shell */
char ownroot[128] = "";

char escapes[256];
char ignores[256];

int modem_in = 0, modem_out = 1;
/*------------------------------------------------------------------------*/
/* module function prototypes */

void main_loop(int);
void main_init(void);
void do_link_in(void);
void do_link_out(void);
void clear_buffers(struct Client *cl);
/*------------------------------------------------------------------------*/
/* main. */

void main_init(void) {
  int i;
  for (i = 0; i < MAX_CLIENTS;++i) {
    clients[i].fd = -1;
    clients[i].state = -1;
    clients[i].in_buff.data = NULL;
    clients[i].out_buff.data = NULL;
    clients[i].in_buff.alloced = 0;
    clients[i].out_buff.alloced = 0;
  }
}
				/* In case of sudden death, do some */
				/* minimal clean up. */
void sig_quit(int dummy) {
  set_block(0);
  set_block(1);
  terminal_restore(0);
  terminal_restore(1);
  set_block(modem_in);
  set_block(modem_out);
  exit(0);
}
				/* Drop a core. */
void sig_core(int dummy) {
  set_block(0);
  set_block(1);
  terminal_restore(0);
  terminal_restore(1);
  set_block(modem_in);
  set_block(modem_out);
  abort();
}
				/* We ignore this signal. There was */
				/* some problem with it on linux. A */
				/* bit odd, and I can't track it down. */
				/* I suspect it is a bad shell. So we */
				/* just ignore it. */
void sig_ignore(int dummy) {
  signal(SIGALRM, sig_ignore);
  signal(SIGPIPE, sig_ignore);
}

void sig_child(int dummy) {
  int p, i;
#if defined(SVR4) || defined(DYNIXPTX)
  int stat_loc;

  p = waitpid((pid_t)-1, &stat_loc, WNOHANG);
#else
  p = wait3(0, WNOHANG, 0);
#endif /* SVR4 */
#ifndef SYSV
  signal(SIGCHLD, sig_child);
#endif /* SYSV */

  if (p < 1) return;
  DEBUG_MAIN(stderr, "%s:sig child kicked\n", term_server);
  for (i = 0; i < MAX_CLIENTS;++i) {
    if (clients[i].pid == p && clients[i].state > 0) {
#if 0 /* ++kay: let term read until EOF */
      clients[i].state = 2;
#endif
      return;
    }
  }
  /* Hmm. child that we don't know about died!?!?! */
  if (dummy)
    dummy = 0;
}

void read_rc(char *p) {
  FILE *f;
  char file[200];
  int i;

  home_p = getenv( "TERMDIR" );
  if (!home_p) home_p = getenv( "HOME" );

#ifdef SHAREDIR

#ifndef USERSHARE
  share_p = getenv( "TERMSHARE" );
#endif
  if (!share_p) share_p = SHAREDIR;

  if(share == -1){
    char *e;
    e=getenv("TERMMODE");
    if(e!=NULL){
      share=atoi(e);
      if(share<0||share>1) share = -1;
    };
    if(share == -1)
#ifndef USERSHARE
      share = (getgid() != getegid() || getuid() != geteuid());
#else
      share = 1;
#endif
  };

#ifndef USERSHARE
  if(!share){
#endif
#endif
    setegid(getgid());
    seteuid(getuid());
#ifdef SHAREDIR
#ifndef USERSHARE
  }
#endif
  if(share || !home_p){
    if (!p)
      sprintf(file, "%s/termrc", share_p);
    else if (p[0])
      sprintf(file, "%s/termrc.%s", share_p, p);
    else
      return;
  }else{
#else
    if (!home_p) return;
#endif
  if (!p)
    sprintf(file, "%s/.term/termrc", home_p);
  else if (p[0])
    sprintf(file, "%s/.term/termrc.%s", home_p, p);
  else
    return;
#ifdef SHAREDIR
  }
#endif

  f = fopen(file, "r");
  if (!f) return;
  
  while (!feof(f)) {
    fgets(file, 200, f);
				/* skip blank lines + comments. */
    if (!file[0] || file[0] == '\n' || file[0] == '#')
      continue;			
				/* compression on/off */
    if (!strncmp(file, "compress ", 9)) {
      if (!strncmp(file + 9, "off", 3))
	compressing = 0;
    }
				/* Handle setting the breakout */
				/* character.  */
    else if (!strncmp(file, "breakout ",9 )) {
      breakout_char = atoi(file + 9);
    }
    else if (!strncmp(file, "remote", 6)) {
      remote = 1;
    }
    else if (!strncmp(file, "chdir ", 6)) {
	file[strlen(file) -1 ] = '\0';
      chdir(file + 6);
    }
				/* any special characters to be escapeing */
    else if (!strncmp(file, "escape ", 7)) {	/* If it is an escape.. */
      char *p;
      int j;
      
      i = atoi(file + 7);	/* get the number following. */
      if (i < 0 || i > 255) {	/* check for sanity. */
	fprintf(stderr, "Invalid escape %d in termrc\n", i);
	continue;
      }

      if ((p = strchr(file+7, '-')) != NULL) { /* See if this is a */
					     /* range.. */
	while (*++p == ' ');	/* skip whitespace. Note that it */
				/* automatically skips the '-'. */
	j = atoi(p);		/* if it is, then get the second number. */
	if (j < 0 || j > 255) {	/* sanity check again. */
	  fprintf(stderr, "Invalid range limit %d in termrc\n", j);
	  continue;
	}
	for (;i != j; i = (i+1) & 255) /* Ok. mark all the characters */
				/* in the range as being escaped. */
	  escapes[i] = 1;   
      }
      else escapes[i] = 1;	/* else just set the one character as */
				/* to be escaped. */
    }
    else if (!strncmp(file, "ignore ", 7)) {	/* If it is an escape.. */
      char *p;
      int j;
      
      i = atoi(file + 7);	/* get the number following. */
      if (i < 0 || i > 255) {	/* check for sanity. */
	fprintf(stderr, "Invalid ignore %d in termrc\n", i);
	continue;
      }

      if ((p = strchr(file+7, '-')) != NULL) { /* See if this is a */
					     /* range.. */
	while (*++p == ' ');	/* skip whitespace. Note that it */
				/* automatically skips the '-'. */
	j = atoi(p);		/* if it is, then get the second number. */
	if (j < 0 || j > 255) {	/* sanity check again. */
	  fprintf(stderr, "Invalid range limit %d in termrc\n", j);
	  continue;
	}
	for (;i != j; i = (i+1) & 255) /* Ok. mark all the characters */
				/* in the range as being escaped. */
	  ignores[i] = 1;   
      }
      else ignores[i] = 1;	/* else just set the one character as */
				/* to be escaped. */
    }
    /* The baudrate */
    else if (!strncmp(file, "baudrate ", 9)) {
      i = atoi(file + 9);
      if (i < 300 && i) i = 300;
      baudrate = i;
    }
    else if (!strncmp(file, "shift ", 6)) {
      byte_shift = atoi(file + 6);
      if (byte_shift < 0 || byte_shift > 255) {
	fprintf(stderr, "Invalid shift %d\n", byte_shift);
	byte_shift = 0;
      }
    }

    else if (!strncmp(file, "window ", 7)) {
      window_size = atoi(file +7 );
      if (window_size < 1 || window_size > 14) {
	fprintf(stderr, "Invalid window size %d. Must be in [1..14]\n", window_size);
	window_size = 3;
      }
    }
    
    else if (!strncmp(file, "timeout ", 8)) {
      packet_timeout = atoi(file + 8);
      if (packet_timeout < 10 || packet_timeout > 1000) {
	fprintf(stderr, "Invalid timeout value (%lu). Must be in [10..1000]\n", packet_timeout);
	packet_timeout = 50;
      }
    }
    
    else if (!strncmp(file, "force on", 8)) {
      do_forceing = 1;
    }
    else if (!strncmp(file, "noise on", 8)) {
      write_noise = 1;
    } 
    else if (!strncmp(file, "sevenbit", 8)) {
      extern int tok_byte_mask_in, tok_byte_width_in, 
        tok_byte_mask_out, tok_byte_width_out;
      seven_bit_in = 1;
      seven_bit_out = 1;
      in_mask = out_mask = 127;
      tok_byte_mask_in = tok_byte_mask_out = 127;
      tok_byte_width_in = tok_byte_width_out = 7;
    }
    else if (!(strncmp(file, "seven_out", 9))) {
      extern int tok_byte_mask_out, tok_byte_width_out;
      seven_bit_out = 1;
      out_mask = 127;
      tok_byte_mask_out = 127;
      tok_byte_width_out = 7;
    }
    else if (!(strncmp(file, "seven_in", 8))) {
      extern int tok_byte_mask_in, tok_byte_width_in;
      seven_bit_in = 1;
      in_mask = 127;
      tok_byte_mask_in = 127;
      tok_byte_width_in = 7;
    }

    /* Should we generate flow control characters ?? */
    else if (!strncmp(file, "flowcontrol ", 12)) {
      fudge_flow = atoi(file+12);
      if (fudge_flow < 0) fudge_flow = 0;
    }else if (!strncmp(file, "login off", 9)) {
      rshtype = -1;
    }else if (!strncmp(file, "denyrsh on", 10)) {
      rshtype = 0;
    }else if (!strncmp(file, "chroot ", 7)) {
      strncpy(ownroot, file+7, 128);
    }
    else {
#ifdef SHAREDIR
      if(!share) {
#endif
        fprintf(stderr, "Unrecognized line in ~/.term/termrc.\r\n");
#ifdef SHAREDIR
      }else{
        fprintf(stderr, "Unrecognized line in %s/termrc.\r\n",share_p);
    }
#endif
      fprintf(stderr, "'%s'\r\n", file);
    }
  }
  if(f!=NULL) fclose(f);
}

void main(int argc, char *argv[]) 
{
  extern char *optarg;
  extern int optind, opterr;
  
  int s, c, i;
  char protected_directory[109];
#ifdef SHAREDIR
  char symbolic_link[109];
  int umask_old;
#endif
  char sock_unix[109];
  fprintf(stderr, "Term version: %s\r\n", VERSION);

  /* initalize character escapeing. */
  for (i = 0; i < 256;i++) {
    ignores[i] = 0;
    escapes[i] = 0;
  }

  escapes['^'] = 1;

  main_init();

#ifdef SHAREDIR
  while ((c = getopt (argc, argv, "ac:d:f:l:n:ors:t:v:w:P:S:")) !=EOF)
    switch(c) {
    case 'S':
      share =(!strcmp(optarg,"on"));
      break;
  };optind=1;   
#endif

  if (!term_server) {
    term_server = "";
  }

  /* read in the termrc file. */
  read_rc(0);

#ifdef SHAREDIR
  if(share)
    fprintf(stderr, "Using shared mode.\r\n");
#endif

  /* then check env variables. */
  setbuf(stderr, 0);
  if (getenv("BAUDRATE")) {
    baudrate = atoi(getenv("BAUDRATE"));
    if ( baudrate < 300 && baudrate)
      baudrate = 300;
  }
  /* Then check command line options */
  /*
    The code to parse the command line was written by the
    one and only Muhammad Saggaf. If you have any question
    A
    about Linux, networking, Unix, or life in general, 
    don't ask him mate! :). Chances are he doesn't know the 
    answer.
    */
  
  opterr = 0;
  
  while ((c = getopt (argc, argv, "ac:d:f:l:n:ors:t:v:w:P:S:")) !=EOF)
    switch(c) {
    case 'a':
      {
	extern int tok_byte_mask_out, tok_byte_width_out,
	  tok_byte_mask_in, tok_byte_width_in;
	tok_byte_mask_out = tok_byte_mask_in = 127;
	tok_byte_width_out = tok_byte_width_in = 7;

	seven_bit_in = seven_bit_out = 1;
	in_mask = out_mask = 127;
	break;
      }
    case 'f': 
      fudge_flow = atoi(optarg);
      if (fudge_flow < 0) fudge_flow = 0;
      break;
    case 'l':
      i = open(optarg, O_RDWR | O_CREAT | O_TRUNC, 0644);
      if (i < 0) {
	perror("open");
	fprintf(stderr, "Unable to open log file %s\r\n", optarg);
	break;
      }
      if (i != 2) {
	close(2);		/* Just to make sure.. */
	dup2(i, 2);
	close(i);
      }
      break;
    case 'o': do_forceing = 1; break;      
    case 'r': remote = 1; break;
    case 't':
      packet_timeout = atoi(optarg);
      if (packet_timeout < 10 || packet_timeout > 1000) {
	fprintf(stderr, "Invalid timeout value (%lu).\r\n", packet_timeout);
	packet_timeout = 50;
      }
      break;
    case 'v':

				/* add a device to the list. */
      i = open(optarg, O_RDWR);
      if (i < 0) {
	perror("open");
	fprintf(stderr,"Unable to open modem device %s\r\n", optarg);
	break;
      }
      if(modem_in>=0) close(modem_in);
      if(modem_out>=0) close(modem_out);
      modem_in = i;
      modem_out = i;
      break;
    case 'w':
      window_size = atoi(optarg);
      if (window_size < 1 || window_size > 14) {
	fprintf(stderr, "Invalid window size %d\r\n", window_size);
	window_size = 3;
      }
      break;
    case 'd': 
      term_debug = atoi(optarg);
      fprintf(stderr, "Debugging = %x\n", term_debug);
      break;
    case 'c':
      if (!strcmp(optarg, "off"))
	compressing = 0;
      break;
    case 'n':
      if (!strcmp(optarg, "on"))
	write_noise = 1;
      else write_noise = 0;
      break;
    case 's':
      baudrate = atoi(optarg);
      if (baudrate < 300 && baudrate) {
	fprintf(stderr, "baudrate set too low. Reset to 300\r\n");
	baudrate = 300;
      }
      break;
    case 'S':
      break;
    default:
      fprintf(stderr, "unrecognized or incomplete argument '%s'. Exiting\r\n",  argv[optind-1]);
      exit(-1);
    }
  
  if (optind < argc)
    term_server = argv[optind];
  
  for (s = 0; s < MAX_CLIENTS;++s) {
    clients[s].fd = -1;
  }

  if (!term_server) {
    term_server = "";
  }
				/* Read in a specific termrc. */
  read_rc(term_server);

#ifdef SHAREDIR
  if(!share){
#endif
    if(!home_p) home_p = "/tmp";
    sprintf(protected_directory,"%s/.term", home_p);
    mkdir(protected_directory, 0700);
    sprintf(sock_unix,"%s/socket%s",protected_directory,term_server);
#ifdef SHAREDIR
  }else{

/* set the protection to be explicitly what I define below */
    umask_old=umask(0);

/* If the needed directories don't exist, create them */
    sprintf(protected_directory,"%s/tmp",share_p);
    mkdir(protected_directory,0777);

/* It seems that the protection on sock_unix is ignored, so we need a 
   a protected directory. */
    sprintf(protected_directory,"%s/%s%s", protected_directory,"private",term_server);
    sprintf(sock_unix,"%s/socket",protected_directory);

/* Remove any old sockets */
    unlink(sock_unix);

/* Create a link to "." as ".term" for backwards compatability */
    sprintf(symbolic_link,"%s/.term",share_p);
    symlink("./tmp/private",symbolic_link);

/* Remove and recreate the private directory, so we can be sure we can see it */
    rmdir(protected_directory);
#ifndef USERSHARE
    mkdir(protected_directory, 0770|S_ISGID);
#else
    mkdir(protected_directory, 0700|S_ISUID);
#endif
  
/* Restore the mask to what the user wants to use with tupload. */
    umask(umask_old);
  }
#endif
  
  if ((s = bind_unix(sock_unix)) < 0) {
    exit(1);
  }
  /* init modules */
  
  serial_init();
  compress_init();
  update_time();
  
#ifdef SYSV
  sigset(SIGCHLD, sig_child);
#else
  signal(SIGCHLD, sig_child);
#endif /* SYSV */
  signal(SIGHUP, sig_quit);
  signal(SIGPIPE, sig_ignore);
  signal(SIGINT, sig_quit);
  signal(SIGQUIT, sig_quit);
  signal(SIGIOT, sig_core);
  signal(SIGSEGV, sig_core);
  signal(SIGALRM, sig_ignore);

  terminal_save(0);
  set_nonblock(s);
  set_nonblock(modem_in);
  set_nonblock(modem_out);
  terminal_raw(modem_in);
  terminal_raw(modem_out);

  if (ownroot[0]) {
    if (!chroot(ownroot))
      perror("chroot");
  }
  
  main_loop(s);

  set_block(modem_in);
  set_block(modem_out);
  terminal_restore(0);
  terminal_restore(1);

  set_block(s);
}

/*-----------------------------------------------------------------------*/
void check_client(int cl, int ret) {
  DEBUG_MAIN(stderr, "%s: term_errno == %d\n", term_server, term_errno);
  if (!term_errno) return;
  if (clients[cl].state == 3 ) {
    DEBUG_FP(stderr, "%s:truncating out_buff\n", term_server);
    clients[cl].out_buff.size = 0;
    clients[cl].out_buff.start = clients[cl].out_buff.end;
    return;
  }
#if 0
  if (ret < 0)
    perror("client gave this");
#endif
				/* Ok. Close the descriptor. */
  if(clients[cl].fd>=0) close(clients[cl].fd);
  clients[cl].fd = -1;
				/* And go to state 2. */
  clients[cl].state = 2;
}

int new_client(void) {
  int j;

  for (j = remote; j < MAX_CLIENTS;j+=2)
    if (clients[j].fd < 0 && clients[j].state < 0) break;

  if (j == MAX_CLIENTS) return -1; /* not maximum clients */

  DEBUG_FP(stderr, "%s: new client %d.\n", term_server, j);
  
  clear_buffers(&clients[j]);
  
  clients[j].type = T_SMART | T_RDFILE | T_WRFILE;
  clients[j].dump_count = 0;
  clients[j].cl_type = CL_SOCKET;
  clients[j].compress = compressing;
  clients[j].state = 1;
  clients[j].c_state = 0;
  clients[j].number = j;
  clients[j].priority = 0;
  clients[j].name[0] = 0;
  return j;
}
/*------------------------------------------------------------------------*/
/* Main loop. Hangs around waiting for things to get ready, and calls to  */
/* approroprite routines. 						  */

void main_loop(int socket) {
  struct timeval timeout;
  fd_set reads, writes, excepts;
  int i, j, k, empty = 1, csocket = -1;
  int max = 0;
  
  while (!do_shutdown) {


/* If the serial out buffer is empty, try and put something in it */
    if (bytes_left && !serial_out.size) {
      DEBUG_FP(stderr, "%s: doing serial out\n",
	       term_server);
      do_serial_out(0);
      if (!serial_out.size)
	do_link_out();
      if (!serial_out.size) 
	do_serial_out(0);
      DEBUG_FP(stderr, "%s:  serial out size %d\n",
	       term_server, serial_out.size);
    }
    
/* Set up client stuff */
/* We select to read if: */
/*	The input buffer is empty */
/* We select to write if: */
/*      The output buffer is not empty */
/*      We're waiting for a connection to complete (state == 5) */

    FD_ZERO(&reads);
    FD_ZERO(&writes);
    FD_ZERO(&excepts);
    
    if (p_in_num && empty)
      do_link_in();
    
    for (i = 0; i < MAX_CLIENTS;++i) {
				/* If it's closeing down, and the */
				/* buffers are empty, then kill it. */
      if ((clients[i].state == 3 || clients[i].state == 4) &&
	  !clients[i].in_buff.size && !clients[i].out_buff.size) {
	DEBUG_FP(stderr, "%s:real close %d %d\n", term_server , i,
		 clients[i].state);
	if(clients[i].fd>0) close(clients[i].fd);
	clients[i].fd = -1;
	if (clients[i].state == 3)
	  clients[i].state = -1; 
	else clients[i].state = 1;
	continue;
      }
				/* If it's a file, we don't need to */
				/* select() on it. */
      if (clients[i].cl_type == CL_FILE) continue;
      if (clients[i].fd < 0) continue; /* If it's not a file, and */
				       /* there is no fd, then no */
				       /* select(). */
      if (!clients[i].in_buff.size && (clients[i].type & T_RDFILE) &&
	  clients[i].state == 1) { 
	FD_SET(clients[i].fd, &reads);
      }
      if ((clients[i].out_buff.size && (clients[i].type & T_WRFILE)) ||
	  (clients[i].state == 5)) {
	FD_SET(clients[i].fd, &writes);
      }
      FD_SET(clients[i].fd, &excepts);
      if (max < clients[i].fd) max = clients[i].fd;
    }
    
/* Select for socket and modem */
/* We select read for socket if we aren't at the maxmimum number */
/* of clients */
    if (num_clients < MAX_CLIENTS) {
      FD_SET(socket, &reads);
      if (max < socket) max = socket;
      if(onetime_term_socket >=0){
        FD_SET(onetime_term_socket, &reads);
        if (max < onetime_term_socket) max = onetime_term_socket;
      };
    }

/* We select for read on the modem if the serial in buffer is empty */
    if (!serial_in.size) {
      FD_SET(modem_in, &reads);
      if (max < modem_in) max = modem_in;
    }

/* Now if there is anything in the serial out buffer, select for writing */

    if (serial_out.size && bytes_left) {
      DEBUG_FP(stderr, "%s: dso: fd set\n",
	       term_server);
      FD_SET(modem_out, &writes);
      if (max < modem_out) max = modem_out;
    }

				/* This is only for my own purposes. */

#if 0
/* Set the timeout value for select(). */
    timeout.tv_sec = 0;
    timeout.tv_usec = 20000; /* 0.02 seconds */
    select(0, 0, 0, 0, &timeout);
#endif

/* Set the timeout value for select(). */
    timeout.tv_sec = 0;
    timeout.tv_usec = 500000; /* 0.5 seconds */

/* do select() */	
    if (select(max+1, &reads, &writes, &excepts, &timeout) < 0) {
				/* This is perfectly normal. Things */
				/* that send signals will cause select */
				/* to exit with an error. */
#if 0
      perror("select");
#endif
      continue;
    }	

/* Update current_time. This is maintained in 20th s of a second */
    update_time();

/* start checking to see whats ready and whats not */
/* Can we read from modem  ?? */
    if (!serial_in.size && FD_ISSET(modem_in , &reads)) {
      j = read_into_buff(modem_in, &serial_in, 0);
      if ( j < 0 && errno != ERR_BLOCK) {
	perror("read from modem");
	return;
      }
      else stat_modem_in += j;
    }
    
    if (serial_in.size) 
      do_serial_in();

/* Ok. Can we write to modem ??? */
    if (FD_ISSET(modem_out, &writes) && bytes_left) {
      
      int t = bytes_left;
      if (t > serial_out.size)
	t = serial_out.size;
      DEBUG_FP(stderr, "%s: dso: write from buff\n",
	       term_server);
      j = write_from_buff(modem_out, &serial_out, t);
      if (j < 1 && term_errno != 1) {
	perror("write to modem");
	return;
      }	  
      else {
	stat_modem_out += j;
	if (baudrate)
	  bytes_left -= j;
      }
    }

/* test for new client */

    for(k=0;k<2;k++){
      switch (k){
        case 0:
          csocket = onetime_term_socket;
          break;
        case 1:
        default:
          csocket = socket;
          break;
      };
      if(csocket<0) continue;
      if (FD_ISSET(csocket, &reads)) { /* try for a connect. */

#if defined(NO_UNIX_DOMAIN) || defined(TERM_NFS_DIR)
        struct sockaddr_in dummy;
#else
        struct sockaddr_un dummy;
#endif

#if defined(STREAMS_PIPE) || defined(X_STREAMS_PIPE)
 	i = CheckClientConnection(csocket);
	if (i != -2) {			/* we have a streams pipe */
		if (i == -1) {
			fprintf(stderr, "can't add client\n");
			continue;
		} /* else fall through to add new client after "accept ..." */
	} else 		/* not a streams pipe */
#endif
        {
          int din = sizeof(dummy);
          i = accept(csocket , (struct sockaddr *) &dummy, &din);
        };
        if(!k){
          onetime_term_socket = -1;
          close(csocket);
        };
        
        if (i >= 0) { /* a new client */
	  j = new_client();
	  clients[j].fd = i;
	  clients[j].cl_type = CL_SOCKET;
	  set_nonblock(i);
        }
        else if (term_errno != 1) {
#if 0
	  perror("accept");
#endif
        }
      }
    };
/* test for data being read from clients */
    for (i = 0; i < MAX_CLIENTS;++i) {
      if (clients[i].fd < 0) continue;
      if (clients[i].in_buff.size) continue;
      switch (clients[i].cl_type) {
      case CL_CHILD:		/* fall through */
      case CL_SOCKET:		/* fall through */
#if defined(STREAMS_PIPE) || defined(X_STREAMS_PIPE)
      case CL_SPIPE:
#endif
	if (!FD_ISSET(clients[i].fd, &reads) &&
	    !FD_ISSET(clients[i].fd, &excepts))
	  continue;
				/* Fall through. */
      case CL_FILE:		
	if (!(clients[i].type & T_RDFILE)) continue;
	j = read_into_buff(clients[i].fd, &clients[i].in_buff, 0); 
	DEBUG_FP(stderr, "%s:read %d bytes from client %d\n",
		 term_server , j, i);
				/* Did this client start sending?? */
	DEBUG_FP(stderr, "%s:j %d, inf_buff.size %d\n",
		 term_server , j, clients[i].in_buff.size);

				/* Hmmm. Something errored. Lets take */
				/* a look... */
	if (j <= 0)
	  check_client(i, j);
	if (term_errno == 1)
	  check_client(i, j);
	break;
      case CL_BOUND:
	if (!FD_ISSET(clients[i].fd, &reads)) continue;
	{
	  un_char num[10]; int k;
				/* We have an accept ready... */
	  clients[i].type &= ~T_RDFILE; /* Don't try reading it untill */
				/* the accept is done. */
	  sprintf(num, "%d", i);
	  for (k =0 ;num[k];++k)
	    add_to_buffer(&clients[i].in_buff, num[k]);
	  add_to_buffer(&clients[i].in_buff, 0);
	}
	break;
      }
    } /* for clients loop */
    
#ifdef CONN_NONBLOCK
/* Test pending connections. */
    for (i = 0; i < MAX_CLIENTS; ++i) {
      if (clients[i].state == 5) {
	char	dummy;

	if (FD_ISSET(clients[i].fd, &writes)) {
	  ret_ok(&clients[i], 0);	/* safe to call from here? */
	  clients[i].state = 1;
	}
	else if (read(clients[i].fd, &dummy, 0) < 0) {
	  switch (errno) {
	  case ENOTCONN:	/* no status, but maybe timed out */
	    if (current_time >= clients[i].timeout) {
	      errno = ETIMEDOUT;
	      ret_fail(&clients[i], 0, 1, "connect() timed out");
	      perror("async connect()");
	      clients[i].state = 2;
	    }
	    break;
	  default:
	    ret_fail(&clients[i], 0, 1, "connect() timed out");
	    perror("async connect()");
	    clients[i].state = 2;
	    break;
	  }
	}
      }
    }
#endif

/* test for data being send to clients */
    empty = 1;
    for (i = 0; i < MAX_CLIENTS;++i) {
      if (clients[i].fd < 0) continue;
      if (!clients[i].out_buff.size) continue;
      switch (clients[i].cl_type) {
      case CL_CHILD:
      case CL_SOCKET:
#if defined(STREAMS_PIPE) || defined(X_STREAMS_PIPE)
      case CL_SPIPE:
#endif
	if  (!FD_ISSET(clients[i].fd, &writes)) continue;
      case CL_FILE:
	if (!(clients[i].type & T_WRFILE)) continue;
				/* something there! :) */
	j = write_from_buff(clients[i].fd, &clients[i].out_buff,0);
	DEBUG_FP(stderr, "%s:write %d bytes to client %d\n", 
		 term_server, j, i);
	if (j <= 0)
	  check_client(i, j);
	else stat_cooked_in += j;
	break;
      case CL_BOUND:
	break;
      }				/* switch */
    }				/* for clients loop */
    
  } /* while loop */
  
} /* function */

