#define I_IOCTL
#define I_ERRNO
#define I_TYPES
#define I_STAT
#define I_STRING
#define I_CTYPE
#define I_INET
#define I_LIMITS
#define I_STROPT
#define I_POLL
#include "includes.h"

#include "debug.h"

#define BUFF_INC_SIZE 1024
#define MAX_BUFF 32767

char *term_strherror(int);

int termerrno = 0;

int share = -1;

/*------------------------------------------------------------------------*/
/* Do a partial read into the buffer. */
static int do_read_into_buff(int fd, struct Buffer *b, int size) {
  int r = 0, t;

  

  if (!size || size > b->alloced - 1 - b->size) 
    size = b->alloced - 1 - b->size;

  termerrno = 0;
  t = b->alloced - b->start;
  if (t > size) t = size;
#ifdef SVR3 /* System Vr3 doesn't restart system calls */
  while ((r = read(fd, b->data + b->start, t)) == -1 && errno == EINTR);
#else
  r = read(fd, b->data + b->start, t);
#endif
  if (r <= 0)  {
    if (!r) termerrno = 1;
    else 
#ifndef SVR4
      if (errno != ERR_BLOCK)
#endif /* SVR4 */
        termerrno = errno + 1;
    return r;
  }
  DEBUG_LL(stderr, "%s: d_r_i_b: read1 from %d (%d) did %d\n", 
	   term_server, fd, t, r);
  
  b->start += r;
  b->size += r;
  SANITY(b->start <= b->alloced);
  if (b->start == b->alloced)
    b->start = 0;
  size -= r;
  if (!size || b->start != 0) return r;
  
  t = b->alloced - b->start;
  if (t > size) t = size;
 
#ifdef SVR3                   /* System Vr3 doesn't restart system calls */
  while ((t = read(fd, b->data + b->start, t)) == -1 && errno == EINTR);
#else
  t = read(fd, b->data + b->start, t);
#endif
  if (t <= 0) {
    if (!t) termerrno = 1;
    else if(errno != ERR_BLOCK)
      termerrno = errno+1;
    return r;
  }
  DEBUG_LL(stderr, "%s: d_r_i_b: read2 from %d (%d) did %d\n", 
	   term_server, fd, t, t);
  
  b->start += t;
  b->size += t;
  if (b->start == b->alloced)
    b->start = 0;
  size -= t;
  r += t;
  return r;
}

static int inc_buffer(struct Buffer *b, int do_move) {
  if( (b->data == NULL) || (b->alloced == 0)) {
    if( (b->data = (un_char *)malloc((1+BUFF_INC_SIZE)*sizeof(un_char))) == NULL){
      perror("Term: malloc()");
      return -1;
    }
    b->alloced = BUFF_INC_SIZE + 1;
    b->size=0;
  }else if(b->alloced >= MAX_BUFF) {
    DEBUG_UDP(stderr,"%s:%s",term_server,"Term: max buffer\n");
    return -1;
  }else if ((b->data = (un_char *)realloc(b->data, sizeof(un_char)*
     (((b->alloced+BUFF_INC_SIZE) < 0 || (b->alloced+BUFF_INC_SIZE > MAX_BUFF))) ?
      MAX_BUFF : b->alloced+BUFF_INC_SIZE)) == NULL) {
    perror("%Term: realloc");
    return -1;
  }else { 
    b->alloced += BUFF_INC_SIZE;
    if (b->alloced > MAX_BUFF || b->alloced < BUFF_INC_SIZE)
      b->alloced = MAX_BUFF;
  }
  if (!b->size) b->start=b->end=0;

	/* It took me ages to realize this is what is being done here! */

	/* OK, we use buffers as a continuous loop.  So when we reach the eob */
	/* (end of buffer) we just continue on at the bob (beginning of buffer). */
	/* So if we want to increase the size of the buffer while it is in use */
	/* we must take data at the eob and move it to the new eob so we have */
	/* more space where we need it in the mob (middle of buffer). */

	/* This means "start" is where we can start adding more data to the */
	/* buffer, and "end" is where we last ended removing the data. */

  if ( do_move && (b->end > b->start)) {    /* curses. need to move data. */
    int i; char *new_eob, *old_eob;
    new_eob = (caddr_t)b->data + b->alloced - 1;
    old_eob = (caddr_t)b->data + b->alloced - BUFF_INC_SIZE - 1;
    for (i = b->alloced - BUFF_INC_SIZE - b->end; i > 0; --i)
      *new_eob-- = *old_eob--;
    b->end += BUFF_INC_SIZE;
  }
  return 0;
}



/*-----------------------------------------------------------------------*/

#ifndef O_NONBLOCK
#define O_NONBLOCK FNDELAY
#endif

void set_nonblock(int fd) {
  int val = 1;		/* Checker V0.5 needs assignment even if !USE_IOCTL */
#ifdef USE_IOCTL
  ioctl(fd, FIONBIO, &val);
#else
  val = fcntl(fd, F_GETFL);
  if (!(val & O_NONBLOCK))
    fcntl (fd, F_SETFL, val | O_NONBLOCK);
#endif
}

int set_block(int fd) { 
  int val = 0;		/* Checker V0.5 needs assignment even if !USE_IOCTL */
#ifdef USE_IOCTL
  ioctl(fd, FIONBIO, &val);
  return 1;
#else
  val = fcntl(fd, F_GETFL);
  if (val & O_NONBLOCK)
    fcntl (fd, F_SETFL, val & ~O_NONBLOCK);
  return !(val & O_NONBLOCK);
#endif
}

/* Read from a file-descriptor into a ring buffer. Read at most size bytes */
int read_into_buff(int fd, struct Buffer *b, int z) {
  int ret, l = 0, size;

  if (! b->alloced) inc_buffer(b,0);
 
  if ((size = z) > b->alloced - 1 - b->size) inc_buffer(b,1); 

  if (!size)
    size = b->alloced - 1 - b->size;

  do {
    ret = do_read_into_buff(fd, b, size);
    if (ret < 1) break;
    l += ret;
    size -= ret;
    if (!z && !termerrno && !size && b->alloced < PIPE_BUFFER) {
      if (inc_buffer(b,1) < 0) 
        termerrno = 1;
      else
        size = b->alloced - 1 - b->size;
    }
  } while (!termerrno && size);
  if (!b->size) b->start=b->end=0;
  if (!l) return ret;
  return l;
}

#ifdef hcx
/* Under HCX/UX 5.1 (at least), writes of 256 bytes or more can return */
/* a -1 with errno == EAGAIN, but actually write the data successfully. */
#undef _POSIX_PIPE_BUF
#define _POSIX_PIPE_BUF 128
#endif

/*------------------------------------------------------------------------*/
/* Write from ring buffer to file descriptor. Write at most size bytes    */

int internal_write_from_buff(int fd, struct Buffer *b, int size, int async) {
  int r = 0, t, i;

  SANITY(b->size <= b->alloced);
  if (!size) size = b->size;
  if (size > b->size) size = b->size;

  while (size > 0) {	/* We use a loop in case there is a maximum block size */
    t = b->alloced - b->end;
    if (t > size) t = size;
    if (t > _POSIX_PIPE_BUF) t = _POSIX_PIPE_BUF;

    i = write(fd, b->data + b->end, t);

    if (i <= 0) {
      if (!i) termerrno = 1;
#ifdef SVR3
      else if (i == -1 && errno == EINTR) continue;
#endif
      else if (errno != ERR_BLOCK)
        termerrno = errno+1;
      return r;
    }
    DEBUG_LL(stderr, "%s: d_w_f_b: write from %d (%d) did %d\n", 
	   term_server, fd, t, i);

    r += i;

    b->end += i;
    b->size -= i;
    size -= i;
    SANITY(size <= b->size);

    SANITY(b->end <= b->alloced);
    if (b->end == b->alloced) b->end = 0;
    if (i != t && async)
      break;
  };
  if (!b->size) b->start=b->end=0;
  return r;
}

int write_from_buff(int fd, struct Buffer *b, int size) {
  return internal_write_from_buff(fd, b, size, 0);
}

int write_from_buff_async(int fd, struct Buffer *b, int size) {
  return internal_write_from_buff(fd, b, size, 1);
}

int add_to_buffer(struct Buffer *B, un_char c) {

  if (! B->alloced) B->size=0;
  if (B->size >= B->alloced - 2) {
    
    DEBUG_LL (stderr, "%s:add_to_buffer:growing buffer from %d, %d\n",
	     term_server, B->size, B->alloced);

    if( inc_buffer(B,(B->alloced > 0)) < 0) {
      termerrno = 1;
      return -1;
    }
  }
  B->data[B->start++] = (c);
  if (B->start == B->alloced) B->start = 0;
  B->size++;
  return 0;
}

int get_from_buffer(struct Buffer *b) {
  un_char c;
  if (b->size < 1)
    return -1;
  c = b->data[b->end++];
  --b->size;
  if (b->end >= b->alloced)
    b->end = 0;
  if (!b->size) b->start=b->end=0;
  return (int) c&255;
}
/*-----------------------------------------------------------------------*/

	/* KLUDGE. suns always need stderr, so ignore the config.h if */
	/* it says otherwise. This is mostly just a sanity check */
#if !defined(NO_STRERROR) && !defined(_LIBC)
char *strerror(int errno) {
  extern char *sys_errlist[];
  
  return sys_errlist[errno];
}
#endif

	/* This is to allow easy checking of effective access */
int eaccess(char *pathname, int mode){
  struct stat file_status;
  int m;

  if(stat(pathname,&file_status) == -1) return -1;
  if(! mode) return 0;

  if(file_status.st_uid == geteuid())
    m = mode << 6;
  else if ( file_status.st_gid == getegid())
    m = mode << 3;
  else
    m = mode;

  return  - ((file_status.st_mode & m) != m) ; 
}

	/* This tests whether we are in shared mode */
void set_share_mode(int priv, int share_new){
  char *e;
  static int share_old = -2;

  share = share_new;
  if (share_old == -2) {
    e = getenv("TERMMODE");
    if (e) 
      share_old = atoi(e);
    if(share_old < 0 || share_old > 2) share_old = -1;
  }

  if (share_old != share) {
#ifdef _POSIX_SAVED_IDS
    if (savedeid  >= 0) {
      if (share > 1) 
        setgid(savedeid);
      else if (share > 0)
        setgid(savedeid);
      savedeid = -1;
    }
#endif
    if (share < 0) share = share_old;
  }

  if (share < 0) {
    share = (getgid() != getegid());
    if (! share)
      share = (getuid() != geteuid() && getuid()) ? 2 : -1;
  }

  if (! share) {
    if (getgid() != getegid()) 
      setgid(getgid());
    else if (geteuid() != 0 && geteuid() != getuid())
      setuid(getuid());
  }
#ifdef _POSIX_SAVED_IDS
  else if (share > 0 && savedeid < 0){
    if ( share == 2 ) {
      savedeid = geteuid();
      setuid(getuid());
    }else {
      savedeid = getegid();
      setgid(getgid());
    }
  }
#endif

  if (share != share_old) 
    share_old = share;
  
  if (priv) {
#ifdef _POSIX_SAVED_IDS
    savedeid = -1;
#endif
    if (geteuid() && geteuid() != getuid()) setuid(getuid());
    if (getegid() && getegid() != getgid()) setgid(getgid());
  }
}

char *str_version(long unsigned int version){
  static char v[25];
  if(version%100 < 50 )	/* These are bug fix releases */
    sprintf(v, "%lu.%lu.%lu",(version/10000),
      (version/100)%100,version%100);
  else if(version%100 < 77 ) 	/* These are alpha releases */
    sprintf(v, "%lu.%lu%c (alpha)",(version/10000),
      (version/100)%100,'a'+(char)((version-51)%100));
  else if(version%100 < 90 ) 	/* These are alpha releases */
    sprintf(v, "%lu.%lu%c%c (alpha)\r\n",(version/10000),
      (version/100)%100,'z','a'+(char)((version-77)%100));
  else
    sprintf(v, "alpha pre-release of %lu.%02lu pl %02lu",(version/10000),
      1+(version/100)%100,version%10);
  return v;
}

	/* This is an unreliable protocol.  So in the case of errors */
	/* we must just try to continue the best we can. */

int recvfrom_into_buff(struct Client *cl) {
  struct sockaddr_in from_addr;
  int r = 0, i, fd, type;
  struct Buffer *b;
  static un_char *from = NULL;
  static size_t alloced = 0;
  unsigned int avail = 0, len, hdr = 0, t;
  unsigned long lhost, *host;
  unsigned int lport, *port;

  host = &cl->udp_host;
  port = (unsigned int *)&cl->udp_port;

  fd = cl->fd;
  b = &cl->in_buff;
  type = cl->udp_type;

  termerrno = 0;

  DEBUG_UDP(stderr,"%s# recvfrom_i_b called.\n",term_server);

#ifndef FIONREAD
  /*
   * System V release 3 doesn't have an FIONREAD even on sockets, but
   * in looking at the code it looks like a select here just to tell
   * if there is any data available is sufficient.  Size is always set
   * to PIPE_BUFFER or greater so I suspect if I just read PIPE_BUFFER I'll
   * be OK.  It might require bumping PIPE_BUFFER  up to the maximum message
   * size.
   */
  {
    struct pollfd fds[2];
    int status;
    
    fds[0].fd = fd;
    fds[0].events = POLLIN | POLLPRI | POLLERR | POLLHUP;
    fds[0].revents = 0;
   
    errno = 0;
    status = -1;
    while (status == -1) {
      status = poll(fds, 1L, 2);
      if (errno != EAGAIN)
      break;
    }

    if (status == -1) {
      perror("ERROR in poll request");
      return 0;
    }

    if (fds[0].revents & POLLIN | POLLPRI)
      avail = PIPE_BUFFER;
    else
      return 0;
  }
#else
  if( ioctl( fd, FIONREAD, &avail) < 0)  return 0;
#endif
  if (avail < PIPE_BUFFER) avail = PIPE_BUFFER;

  if( type & UDP_T_RECADDHDR) hdr = HEADER_SIZE; else hdr = 0;

  if ( ! from) {
    from = (un_char *)malloc(sizeof(un_char)*BUFF_INC_SIZE);
    alloced = BUFF_INC_SIZE;
  }
  SANITY(alloced);

  while ( from && (avail+hdr) > alloced && alloced < MAX_BUFF) {
    from = (un_char *)realloc(from,sizeof(un_char)*
     ((alloced+BUFF_INC_SIZE > MAX_BUFF) ?
      MAX_BUFF : alloced+BUFF_INC_SIZE));
    alloced += BUFF_INC_SIZE;
    break;
  }
  if (alloced > MAX_BUFF) alloced = MAX_BUFF;
  avail = alloced;

  if (! from) {		/* OK, this seems like a reasonable exception... */
    alloced = 0;
    termerrno = 1;
    return -1;
  }

  len = sizeof(from_addr);
  if ((i = recvfrom(fd, from+hdr+2, avail, 0,
         (struct sockaddr *)&from_addr, (int *)&len)) < 0) {
    DEBUG_UDP(stderr,"recvfrom %d : %s\n", avail,strerror(errno)); 
    				/* We failed, thats tuff, we should still */
				/* Leave the socket open to try again... */
    free(from);
    from = NULL;
    alloced = 0;
    return 0;
  }
  SANITY(avail <= alloced);

  DEBUG_UDP(stderr,"%s# recvfrom()'d: host %lx, port %d.\n", term_server, 
                    (long)ntohl(from_addr.sin_addr.s_addr), 
                    ntohs(from_addr.sin_port));

  DEBUG_UDP(stderr,"# state 1: avail %d, avail+hdr %d, i %d, b->size %d.\n",
                    avail, avail+hdr, i, b->size);

  avail = i + hdr + 2;
  lhost = ntohl(from_addr.sin_addr.s_addr);
  lport = ntohs(from_addr.sin_port);
  if (type & UDP_T_RECADDHDR) {
    from[2] = (lhost>>24)&255;
    from[3] = (lhost>>16)&255;
    from[4] = (lhost>>8)&255;
    from[5] = lhost&255;
    from[6] = (lport>>8)&255;
    from[7] = lport&255;
  }

  if ( ! *host || ! *port ) {
    *host = lhost;
    *port = lport;
  }

  while( avail > (b->alloced - b->size) && b->alloced < MAX_BUFF) { /* +HEADER_SIZE just to make sure... */
    if( inc_buffer(b,1) < 0) {
      termerrno = 1; 	/* Our buffer is gone, so we have no choice but to */
			/* report this error. */
      return -1;
    }
  }

	/* If necessary, truncate the message, and store the size */

  if ( avail > (b->alloced - b->size) ) avail = b->alloced - b->size;
  from[0] = (avail>>8)&255;
  from[1] = avail & 255;

	/* We must be careful here, since there is no guarantee that the */
	/* available memory in the buffer is continuous!! */

	/* The first chunk. */

  t = b->alloced - b->start;
  if( t > avail) t = avail; /* do it ALL at once */

  DEBUG_UDP(stderr,"%s# state 2: t %d, avail+hdr+2 %d.\n", term_server, t, avail);

  memcpy( b->data + b->start, from, t); /* bugger checking the return code... */

  b->start += t;
  if( b->start == b->alloced)
    b->start = 0;
  b->size += t;


  DEBUG_UDP(stderr,"%s# state 3: b->start %d, b->size %d.\n", term_server, 
    b->start, b->size);

  if (t == avail) { /* all done, return */
    DEBUG_UDP(stderr,"%s# return 1 (%d) - all done.\n", term_server, t);
    return (int) t;
  }

	/* The memory wasn't continuous, so now we need to get the rest. */

  r = avail - t;

  DEBUG_UDP(stderr,"%s# round 2: r %d.\n", term_server,r);

  SANITY(b->start == 0);
  memcpy( b->data, from + t, r); /* b->start needed? */

  b->start += r;
  SANITY(b->start < b->alloced);
  b->size += r;

  DEBUG_UDP(stderr,"%s# state 3: r %d, b->start %d, b->size %d.\n", term_server,
    r, b->start, b->size);
  DEBUG_UDP(stderr,"%s# return 2 (%d) - all done.\n", term_server, avail+hdr);

	/* Now we are really done. */

  return (int) avail;
}



/* ------------------------------------------------------------------------------
 * send to_from_buff() 
 * basically, transfer from Buffer *b to the array *to and returns the number of
 * chars send.
 *
 * also, take care of the header... header is the first HEADER_SIZE bytes of the
 * packet telling host/port to sendto()'it (or host/port it was recvfrom()''ed)
 * ans the size of the packet, INCLUDING header.
 *
 */


	/* This is an unreliable protocol.  So in the case of errors */
	/* we must just try to continue the best we can.  If we are able */
	/* to try another message, we shouldn't return an error. */

int sendto_from_buff(struct Client *cl) {
  int type, *port;
  int r=0, t, i;
  struct Buffer *b;
  unsigned long int *host;
  unsigned long int lhost;
  unsigned short int lport;
  struct sockaddr_in toaddr_in;
  static un_char *to = NULL;
  static size_t alloced = 0;

  b = &cl->out_buff;
  type = cl->udp_type;
  host = &cl->udp_host;
  port = &cl->udp_port;

  termerrno = 0; /* this sucker cost be around 2 hours of debugging! :) */

  DEBUG_UDP(stderr,"%s@ sendto_from_buff called.\n",term_server);
  DEBUG_UDP(stderr,"%s@b->size %u b->end %d\n",term_server,
    b->size, b->end);

	/* If we don't have the header yet we can't do anything. */
  if ( ! b->alloced || b->size < 2 ) {
    DEBUG_UDP(stderr,"%s@only have one udp byte.\n",term_server);
    cl->udp_size=b->size;
    return 0;
  }
  cl->udp_size =
    (b->data[b->end]<<8) +
    (b->data[(b->end + 1) % b->alloced]&255);

  if (cl->udp_size < HEADER_SIZE+2 || cl->udp_size > MAX_BUFF) {
    DEBUG_UDP(stderr,"%s@ term invalid udp packet size.\n",term_server);
    cl->udp_size=b->size=b->start=b->end=0;
    termerrno = 1; 	/* OK, once we have an internal error like this */
    return -1;		/* we are doomed. */
  }

  if (b->size < cl->udp_size) { 
    DEBUG_UDP(stderr,"%s@udp message is not complete yet. %d/%d\n",
      term_server, b->size, cl->udp_size);
    return 0;	/* I'll be back. */
  }

  if (b->size - 2 < HEADER_SIZE) {
    DEBUG_UDP(stderr,"%s@term udp packet is too small.\n",term_server);
    cl->udp_size=b->size=b->start=b->end=0;
    termerrno = 1; 	/* OK, once we have an internal error like this */
    return -1;		/* we are doomed. */
  }
  b->size -= 2;
  b->end = (b->end + 2) % b->alloced;
  cl->udp_size -= 2;

  if (! to) {
    to = (un_char *)malloc(sizeof(un_char)*BUFF_INC_SIZE);
    alloced = BUFF_INC_SIZE;
  }
  SANITY(alloced);

  while (to && cl->udp_size > alloced && alloced < MAX_BUFF) {
    to = (un_char *)realloc(to,sizeof(un_char)*
     ((alloced+BUFF_INC_SIZE > MAX_BUFF) ?
      MAX_BUFF : alloced+BUFF_INC_SIZE));
    alloced += BUFF_INC_SIZE;
  }

  if (! to) {		/* Not much we can do if we are out of memory! */
    DEBUG_UDP(stderr,"%s@ allocation failure.\n",term_server);
    alloced = 0;
    termerrno = 1;
    return -1;
  }

  if (alloced > MAX_BUFF) alloced = MAX_BUFF;
  SANITY(alloced >= BUFF_INC_SIZE);

  if ( cl->udp_size > alloced ) cl->udp_size = alloced;	/* Anyone sending too large  of a */
					/* udp message deserves what they get. */
  t = cl->udp_size;
  if (t > b->alloced - b->end) t = b->alloced - b->end;

  DEBUG_UDP(stderr,"@ 1st chunk: t %d, b->end %d\n",t,b->end);
  SANITY(to && b->data);
  memcpy(to, b->data + b->end, t);

  b->size -= t;
  b->end = (b->end + t) % b->alloced;

  if ((r = cl->udp_size - t) > 0) {
    SANITY(r <= b->size);
    SANITY(b->end == 0);
    DEBUG_UDP(stderr,"@ 2nd chunk: r %d , b->end %d\n",r,b->end);
    memcpy (to + t, b->data, r);
    b->size -= r;
    b->end = (b->end + r) % b->alloced;
    t += r;
  } 
  
  if (!b->size) b->start=b->end=0;

  lhost = (to[0]<<24)+(to[1]<<16)+(to[2]<<8)+(to[3]);
  lport = (to[4]<<8)+(to[5]);
  DEBUG_UDP(stderr,"%s@message from %lx, %u\n",term_server,lhost,lport);

  if ( !(type & UDP_T_SENDIGNOREHDR) && (lhost || lport)) {
    /* don't ignore header, therefore put it in *host *port for sendto()'ing */
    DEBUG_UDP(stderr,"%s@ changing: from *host, *port %lx, %u to ",
      term_server, *host, *port);
    *host = lhost;
    *port = lport;
    DEBUG_UDP(stderr,"%lx, %u\n",*host, *port);
  }

  toaddr_in.sin_family = AF_INET;
  toaddr_in.sin_addr.s_addr = htonl(*host);
  toaddr_in.sin_port = htons(*port);
  if (toaddr_in.sin_addr.s_addr == INADDR_ANY ||
       toaddr_in.sin_addr.s_addr == inet_addr("127.0.0.254"))
    toaddr_in.sin_addr.s_addr = inet_addr("127.0.0.1");

  if( type & UDP_T_SENDSTRIPHDR) /* strip header before sending? */
    i = sendto(cl->fd, to + HEADER_SIZE, t - HEADER_SIZE, 0,
               (struct sockaddr *)&toaddr_in, sizeof(toaddr_in));
  else
    i = sendto(cl->fd, to, t, 0,
               (struct sockaddr *)&toaddr_in, sizeof(toaddr_in));

  cl->udp_size = 0;
  DEBUG_UDP(stderr,"%s@b->size %u b->end %d\n",
    term_server, b->size, b->end);

  if (i < 0) {
    DEBUG_UDP(stderr,"%s@ return 2.5 (%d) %lx, %u - sendto() failed.\n",
      term_server, i, *host, *port);
    *host = 0;	/* This unbinds the socket... */
    *port = 0;
    return t + 2;	/* Another error.  Tuff luck. */
  }

  DEBUG_UDP(stderr,"%s@ return 3 (%d) - did sendto(): host %lx, port %u, i %d\n",
    term_server, t, *host, *port, i);

  return t + 2;
}


/* This is grossly overly complicated because I try to convert invalid */
/* addresses to something recognizable */

char *sockaddr_to_sstr(struct sockaddr *addr, int trans) {
  return NULL;
}


void get_term_localaddr(unsigned long default_addr) {
  char hostname[sizeof(term_localhost)];
  struct hostent *hp;
  struct in_addr addr_in;

  if (term_localaddr != INADDR_ANY) return;

  memset(term_localhost,0,sizeof(term_localhost));
#if defined(SYSV) && !defined(DYNIXPTX)
  { struct utsname unam;
    uname(&unam);
    strcpy(hostname, unam.nodename); }
#else
  gethostname (hostname, sizeof(hostname));
#endif
  strcpy(term_localhost, hostname);
  if (hostname[0] >= '0' && hostname[0] <= '9') {
    addr_in.s_addr = inet_addr(hostname);
  }else {
    hp=host_lookup(hostname,0,AF_INET,0,NULL);
    if (!hp) {
      extern int h_errno;
      fprintf(stderr,"%s: gethostbyname: %s: %s\n",term_server, hostname,
        term_strherror(h_errno));
      addr_in.s_addr = default_addr;
      strcpy (term_localhost, "127.0.0.1");
    }else {
      memcpy(&addr_in, hp->h_addr, hp->h_length);
    }
  }
  term_localaddr = ntohl(addr_in.s_addr);
}

char *sockaddr_to_str(struct sockaddr *addr, int trans) {
  struct sockaddr_in addr_in;
  static char portname[24];
  unsigned long int j;
  char *a,*p;

#define UC(y) (int) ((int) 0xff & (int) (y))
  memset(&addr_in,0,sizeof(struct sockaddr_in));
  memcpy(&addr_in,addr,sizeof(struct sockaddr_in));
  p = (char *)&addr_in.sin_port;

  if ( ! addr_in.sin_addr.s_addr || addr_in.sin_family != AF_INET ){
    struct hostent *hp;
    char hostname[259];

#if defined(SYSV) && !defined(DYNIXPTX)
    { struct utsname unam;
      uname(&unam);
      strcpy(hostname, unam.nodename); }
#else
    gethostname (hostname, sizeof(hostname));
#endif
    if (hostname[0] >= '0' && hostname[0] <= '9') {
      addr_in.sin_addr.s_addr = inet_addr(hostname);
    }else {
      hp=host_lookup(hostname,0,AF_INET,0,NULL);
      if (!hp) {
        herror ("Term: gethostbyname");
        addr_in.sin_addr.s_addr = INADDR_ANY;
      }else {
        memcpy(&addr_in.sin_addr, hp->h_addr, hp->h_length);
      }
    }
  };
  j = addr_in.sin_addr.s_addr;
  if ( trans && (! j || j == INADDR_ANY || j == inet_addr("127.0.0.1"))) 
    j = ( remote_term_version >= 20000 ) ?
      inet_addr("127.0.0.254") : inet_addr("127.0.0.1");
  a = (char *)&j;
  (void) sprintf(portname, "%u,%u,%u,%u,%u,%u",
           UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  return portname;
}

struct sockaddr *sstr_to_sockaddr(char *addr, unsigned long defaultaddr){
  return NULL;
}

struct sockaddr *str_to_sockaddr(char *addr, unsigned long defaultaddr){
  static struct sockaddr_in name_in;
  int j;
  char port[35], *u, *v;

  strncpy(port,addr,35);
  for(j=0;j<3;j++) *strchr(port,',')='.';
  u=strchr(port,',');
  *u='\0';
  v=strchr(++u,',');
  *v='\0';

  name_in.sin_addr.s_addr = inet_addr(port);
  if ( name_in.sin_addr.s_addr == INADDR_ANY
    || name_in.sin_addr.s_addr == inet_addr("127.0.0.1")
    || name_in.sin_addr.s_addr == inet_addr("127.0.0.254") )
    name_in.sin_addr.s_addr = defaultaddr;
    
  name_in.sin_family = AF_INET;
  name_in.sin_port = htons((atoi(u)<<8)+atoi(++v));
  return (struct sockaddr *)&name_in;
}   


struct sockaddr *make_sockaddr(unsigned int port, char *host,
     unsigned long defaulthost) {
  static struct sockaddr_in addr_in;
  struct hostent *hp;
  char *hostname=NULL, *colon;
  int s=259;

  memset(&addr_in,0,sizeof(addr_in)); 
  if (host) 
    s = (strlen(host)+1 < 259) ? 259 : strlen(host)+1;
 
  hostname = (char *)malloc(sizeof(char)*s);
  *hostname = '\0';
  if (host) {
    strcpy(hostname,host);
    if ((colon = strchr(hostname,':'))) *colon = '\0';
  }else if (defaulthost != INADDR_ANY) {
#if defined(SYSV) && !defined(DYNIXPTX)
    { struct utsname unam;
      uname(&unam);
      strcpy(hostname, unam.nodename);
    }
#else
    gethostname (hostname, sizeof(hostname));
#endif
  }

  addr_in.sin_family = AF_INET;
  if (! *hostname || ! strcmp(hostname,"localhost")
      || ! strcmp(hostname,"remotehost")
      || ! strcmp(hostname,"127.0.0.1")
      || ! strcmp(hostname,"127.0.0.254") ) {
    addr_in.sin_addr.s_addr = defaulthost;
  }else if (hostname[0] >= '0' && hostname[0] <= '9') {
    addr_in.sin_addr.s_addr = inet_addr(hostname);
  }else {
    hp=host_lookup(hostname,0,AF_INET,0,NULL);
    if (!hp) {
      if (host) {
	fprintf(stderr,"Term: gethostbyname ");
        herror (hostname);
        if (hostname) free(hostname);
        return NULL;
      }
      addr_in.sin_addr.s_addr = defaulthost;
      addr_in.sin_family = AF_INET;
    }else {
      memcpy(&addr_in.sin_addr, hp->h_addr, hp->h_length);
      addr_in.sin_family = hp->h_addrtype;
    }
  }

  if (hostname) free(hostname);
  addr_in.sin_port = htons(port);
  return (struct sockaddr *)&addr_in;
}


char *get_term_path(char **ptr) {
  int len;
  static char path[PATH_MAX];
  static char *home_p = NULL, *share_p = NULL;
  char *p = NULL;

  path[0] = '\0';

#define DEFAULT_PATH SHAREDIR ":/usr/local/lib/term:/usr/lib/term:/usr/etc:/etc"

  if (!home_p && !share) {
    *ptr = NULL;
    p = getenv( "TERMDIR" );
    if (!p) p = getenv( "HOME" );
    if (!p) p = "";

    home_p = (char *)malloc( sizeof(char) * (strlen(p)+strlen(DEFAULT_PATH)+2) ); 
    sprintf(home_p,"%s:%s",p,DEFAULT_PATH);
  }

  if (!share_p && share) {
    *ptr = NULL;
    p = getenv( "TERMSHARE" );
    if (!p) p = "";

    share_p = (char *)malloc( sizeof(char) * (strlen(p)+strlen(DEFAULT_PATH)+2) );
    sprintf(share_p,"%s:%s",p,DEFAULT_PATH);
  }

  if ( ! *ptr ) {
    if (share)
      p = share_p;
    else
      p = home_p;
  }else p = strchr(*ptr, ':');

  if (p) {
    char *q;

    while (*p == ':') p++;
    len = strlen(p) + 1;
    strncpy(path, p,(len > sizeof(path)) ? sizeof(path) : len);
    if ((q=strchr(path,':'))) *q = '\0';
  }

  *ptr = p;
  if (! *path)
    return NULL;
  return path;
}

#define CKSBUF 2048

/* Run a 16-bit CRC over the first nbytes of the given file
   Beware, this eats CPU...   -ot
*/
unsigned short file_crc(char *fname, long nbytes)
{
  char buf[CKSBUF];
  unsigned short sum = 0;
  int f, i, n = 0;

  if ((f = open(fname, O_RDONLY)) <0)
    return 0;
  while (nbytes>0) {
    if ((n = read(f, buf, nbytes<CKSBUF ? nbytes : CKSBUF)) <0) 
      return 0;
    if (!n)
      break;
    for (i=0; i<n; ++i)
      sum = update_crc(sum, (unsigned char) buf[i]);
    nbytes -= n;
  }
  close(f);
  if (nbytes) return 0;
  if (! sum) sum = 1;
  return sum;
}

