#ifdef RCS
static char rcsid[]="$Id: netstuff.c,v 1.1.1.1 2000/11/13 02:42:45 holsta Exp $";
#endif
/******************************************************************************
 *                    Internetting Cooperating Programmers
 * ----------------------------------------------------------------------------
 *
 *  ____    PROJECT
 * |  _ \  __ _ _ __   ___ ___ _ __ 
 * | | | |/ _` | '_ \ / __/ _ \ '__|
 * | |_| | (_| | | | | (_|  __/ |   
 * |____/ \__,_|_| |_|\___\___|_|   the IRC bot
 *
 * All files in this archive are subject to the GNU General Public License.
 *
 * $Source: /cvsroot/dancer/dancer/src/netstuff.c,v $
 * $Revision: 1.1.1.1 $
 * $Date: 2000/11/13 02:42:45 $
 * $Author: holsta $
 * $State: Exp $
 * $Locker:  $
 *
 * ---------------------------------------------------------------------------
 *****************************************************************************/

/*
 * Lowlevel socket handling. Primarily based on IPC primer 4.2.
 */

#include <sys/param.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#if defined(AMIGA) && !defined(__GNUC__)
# include <sys/errno.h>
# include <sys/ioctl.h>
# include <sys/utsname.h>
#else
# ifdef HAVE_YP_MASTER
#  include <rpcsvc/ypclnt.h>
# endif
#endif

#include "dancer.h"
#include "trio.h"
#include "strio.h"
#include "function.h"
#include "user.h"
#include "server.h"
#include "transfer.h"
#include "netstuff.h"
#include "link.h"

#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif

#ifndef INADDR_NONE
#define INADDR_NONE -1
#endif

/* --- Global ----------------------------------------------------- */

extern bool restart;
extern bool cleanup;
extern bool chat;
extern char nameserver[];
extern char dancer_myhost[];
extern time_t lastevent;
extern int serverSocket;
extern itemident *current;
extern itemclient *clientHead;

char myhost[MAXHOSTNAMELEN];
ulong myipaddrnum = 0;
time_t now = 0;
int linkSocket = -1;
fd_set rdset;
fd_set wrset;
struct sockaddr_in linkaddr;
struct sockaddr_in fromaddr;
itemclient *client = NULL;


/* --- GetHost ---------------------------------------------------- */

struct hostent *GetHost(char *hostname)
{
  static struct hostent he;
  static char name[MAXHOSTNAMELEN];
  static char *aliaslist[1], *addrlist[2];
  static struct in_addr addrentry;
  struct hostent *hp;
  ulong in;

  snapshot;
  in = inet_addr(hostname);
  if (INADDR_NONE == in) {
    hp = gethostbyname(hostname);
    if (NULL == hp)
      Debug("gethostbyname(2) failed for %s (%s)", hostname, StrError(errno));
  }
  else {
    aliaslist[0] = NULL;
    addrentry.s_addr = in;
    addrlist[0] = (char *)&addrentry;
    addrlist[1] = NULL;

    he.h_name = StrCopyMax(name, sizeof(name), MakeIP(ntohl(in)));
    he.h_aliases = aliaslist;
    he.h_addrtype = AF_INET;
    he.h_length = sizeof(struct in_addr);
    he.h_addr_list = addrlist;

    hp = &he;
  }
  return hp;
}

/* --- MakeIP ----------------------------------------------------- */

char *MakeIP(ulong num)
{
#ifdef HAVE_INET_NTOA
  struct in_addr in;

  snapshot;
  in.s_addr = htonl(num);
  return inet_ntoa(in);
#else
  static char addr[MINIBUFFER];
  unsigned char *paddr;

  snapshot;
  num = htonl(num);  /* htonl() added to avoid endian probs */
  paddr = (unsigned char *)&num;
  StrFormatMax(addr, sizeof(addr), "%u.%u.%u.%u",
               paddr[0], paddr[1], paddr[2], paddr[3]);
  return addr;
#endif
}

/* --- CloseConnection -------------------------------------------- */

void CloseConnection(int s)
{
  snapshot;
  if (0 <= s) {
    FD_CLR(s, &rdset);
    FD_CLR(s, &wrset);
    close(s);
  }
}

/* --- SetSockOpt ------------------------------------------------- */

void SetSockOpt(int s)
{
  struct linger l;

  snapshot;
  l.l_onoff = l.l_linger = 0;

  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 0, 0);
  setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
  setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&l, sizeof(l));
}

/* --- Connect ---------------------------------------------------- */

void Blocking(int s)
{
#if !defined(AMIGA) || defined(__GNUC__)
  int flags;

  snapshot;
  flags = fcntl(s, F_GETFL, 0);
#ifdef NBLOCK_BSD
  fcntl(s, F_SETFL, flags & (~FNDELAY));
#else
  fcntl(s, F_SETFL, flags & (~O_NONBLOCK));
#endif
#else
  snapshot;
  IoctlSocket(s, FIONBIO, 1L);
#endif
}

void NonBlocking(int s)
{
#if !defined(AMIGA) || defined(__GNUC__)
  int flags;

  snapshot;
  flags = fcntl(s, F_GETFL, 0);
#ifdef NBLOCK_BSD
  fcntl(s, F_SETFL, flags | FNDELAY);
#else
  fcntl(s, F_SETFL, flags | O_NONBLOCK);
#endif
#else
  snapshot;
  IoctlSocket(s, FIONBIO, 0L);
#endif
}

void Connected(itemclient *c)
{
  snapshot;
  c->status = CL_CONNECTED;
  SetSockOpt(c->socket);
  FD_CLR(c->socket, &wrset);
  FD_SET(c->socket, &rdset);
  Blocking(c->socket);
  Logf(LOGCLIENT, "Connection accepted at socket %d", c->socket);
}

int Connect(int s, void *psa)
{
  struct sockaddr_in sa;

  snapshot;
  memset(&sa, 0, sizeof(sa));
  sa.sin_family = ((struct sockaddr_in *)psa)->sin_family;
  sa.sin_port = htons((unsigned short)0);

  /* Bind to INADDR_ANY to allow connections to any local interface */
  sa.sin_addr.s_addr = (0 == myipaddrnum) ? htonl(INADDR_ANY) :
                                            htonl(myipaddrnum);

  if (-1 == bind(s, (struct sockaddr *)&sa, sizeof(sa))) {
    Debug("bind(2) failed on socket %d (%s), myhost = %s, myipaddrnum = %lu",
          s, StrError(errno), myhost, myipaddrnum);
  }
  return connect(s, (struct sockaddr *)psa, sizeof(struct sockaddr_in));
}

/* Non-blocking connect */

bool ConnectNB(itemclient *c)
{
  snapshot;
  FD_SET(c->socket, &wrset);
  NonBlocking(c->socket);

  if (-1 == Connect(c->socket, &c->addr)) {
    /* connect() failed */
    c->status = CL_CONNECTING;
    return ((EINPROGRESS == errno) || (EAGAIN == errno) || (EWOULDBLOCK == errno));
  }
  Connected(c);
  return TRUE;
}

/* --- OpenConnection --------------------------------------------- */

int OpenServerConnection(char *hostname, int port)
{
  snapshot;
  return OpenConnection(hostname, port);
}

itemclient *OpenClientConnection(char *from, char *uhost, itemuser *user,
                                 char *hostname, int port)
{
  struct hostent *hp;
  itemclient *c;

  snapshot;
  hp = GetHost(hostname);
  if (hp) {
    c = AddClient(from, uhost, user, -1);
    if (c) {
      memcpy((char *)&c->addr.sin_addr, hp->h_addr, hp->h_length);
      c->addr.sin_family = hp->h_addrtype;
      c->addr.sin_port = htons((unsigned short)port);

      c->socket = socket(hp->h_addrtype, SOCK_STREAM, 0);
      if (0 <= c->socket) {
        if (ConnectNB(c)) {
          c->linksort = OUT_CHAT; /* Mark this as chat */
          return c;
        }
      }
      RemoveClient(c);
    }
  }
  return NULL;
}

int OpenConnection(char *hostname, int port)
{
  struct hostent *hp;
  struct sockaddr_in sa;
  struct linger l;
  int s;

  snapshot;
  hp = GetHost(hostname);
  if (hp) {
    memset((char *)&sa, 0, sizeof(sa));
    memcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length);
    sa.sin_family = hp->h_addrtype;
    sa.sin_port = htons((unsigned short)port);

    s = socket(hp->h_addrtype, SOCK_STREAM, 0);
    if (0 <= s) {
      if (0 <= Connect(s, &sa)) {
        SetSockOpt(s);
        FD_SET(s, &rdset);
        return s;
      }
      else {
        CloseConnection(s);
        Debug("connect(2) failed on socket %d (%s)", s, StrError(errno));
      }
    }
    else
      Debug("socket(2) failed for %s (%s)", hostname, StrError(errno));
  }
  return -1;
}

/* --- OpenListener ----------------------------------------------- */

itemclient *OpenListener(char *from, char *userhost, itemuser *user)
{
  struct sockaddr_in sa;
  struct hostent *hp;
  itemclient *c;
  int size;

  snapshot;
  hp = GetHost(myhost);
  if (hp) {
    c = AddClient(from, userhost, user, -1);
    if (c) {
      c->socket = socket(hp->h_addrtype, SOCK_STREAM, 0);
      if (0 <= c->socket) {
        memset((char *)&sa, 0, sizeof(sa));
        memcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length);
        sa.sin_family = AF_INET;
        sa.sin_addr.s_addr = INADDR_ANY;
        sa.sin_port = htons((unsigned short)0);
        size = sizeof(sa);

        if (0 <= bind(c->socket, (struct sockaddr *)&sa, size)) {
          if (0 <= listen(c->socket, 1)) {
            c->status = CL_LISTENING;
            FD_SET(c->socket, &rdset);

            /* Re-using sa */
            size = sizeof(&c->addr);
            getsockname(c->socket, (struct sockaddr *)&c->addr, &size);
            return c;
          }
          else
            Debug("listen(2) failed on socket %d (%s)", c->socket, StrError(errno));
        }
        else
          Debug("bind(2) failed on socket %d (%s)", c->socket, StrError(errno));
      }
      else
        Debug("socket(2) failed (%s)", StrError(errno));

      RemoveClient(c);
    }
  }
  return NULL;
}

/* ---OpenLink ---------------------------------------------------- */

int OpenLink(void)
{
  int s, size;

  snapshot;
  s = socket(AF_INET, SOCK_DGRAM, 0);
  if (0 <= s) {
    size = sizeof(linkaddr);
    memset((char *)&linkaddr, 0, size);
    linkaddr.sin_family = AF_INET;
    linkaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    linkaddr.sin_port = htons((unsigned short)0);

    if (0 <= bind(s, (struct sockaddr *)&linkaddr, size)) {
      FD_SET(s, &rdset);
      getsockname(s, (struct sockaddr *)&linkaddr, &size);
      return s;
    }
/*  close(s); ? */
  }
  return -1;
}

/* --- Outgoing --------------------------------------------------- */

void Outgoing(char *from, char linksort, char *opts)
{
  char buffer[BIGBUFFER];
  char buffer2[BIGBUFFER];
  itemclient *c;

  snapshot;
  if (NULL == from)
    from = current->nick;

  if (OUT_LINK == linksort) {
    SendCtcpf(from, "DCC LINK UDP %lu %u",
              myipaddrnum, htons(linkaddr.sin_port));
  }
  else if (OUT_CHAT == linksort) {
    c = OpenListener(from, current->host, current->user);
    if (c) {
      SendCtcpf(from, "DCC CHAT chat %lu %u",
                myipaddrnum, htons(c->addr.sin_port));
      c->linksort = linksort;
    }
    else
      ReplyCtcp(from, "ERRMSG Unable to establish connection");
  }
#ifdef BAGDER
  else if (OUT_SEND == linksort) {
    char *ptr;
    bool uselocal = TRUE;
    int file;

    while ('/' == *opts)
      opts++;

    StrFormatMax(buffer, sizeof(buffer), "%s/%s", DCC_FILEPATH, opts);
    StrFormatMax(buffer2, sizeof(buffer2), "%s/%s", DCC_FILECACHE, opts);
    /*      StrCopy(buffer2, buffer); */
    ptr = buffer2 + StrLength(DCC_FILECACHE) + 1;
    while (*ptr) {
      if ('/' == *ptr)
        *ptr = '_';
      ptr++;
    }

    /* Things done here:
       1) Check if the file is in the cache, and use that if it is
       2) - fetch the file from the primary site and write it in the
            cache dir, start DCCing as soon as the file grows
            (timout the wait in X seconds, 20<X<60 seconds)
            and continue until the fetch signals DONE (even if some
            reads may not give new data due to slow ftp fetch)
          - when the ftp is done (the Exec() job is complete), the
            client should get noted
          - file existance and size should be checked, 0 bytes means
            failed ftp => abort DCC (retry next ftp site when multiple
            ones are supported)
            */

    /* First out, check for the file in the cache */
    file = open(buffer2, O_RDONLY);
    if (-1 == file) {
      /* Not in the cache, we need to get it from the ftp site */
      int s; /* to read the file from */

      /* Get the file from the FTP server, we lock this synchronously at
         least for a start, all the way until we start downloading the
         file, which will be done as a receiving socket as on additional
         socket client */
      if (!ftpget(site, buffer, &s, &size)) {
        /* we got a file size and a socket back, use them both */
        itemclient *k = AddClient(from, NULL, NULL, s);
        if (k) {
          file = open(temporary, O_RDONLY);
        }
      }
    }

    if (0 <= file) {
      /* Add this download to the cache */
      CacheAdd(buffer2);
    }

    if (file > 0) {
      char *filebuffer = malloc(CLF_FILEBUFFER);

      if (buffer &&
          (c = OpenListener(from, current->host, current->user))) {
        char *filepart;

        c->file = file;
        c->linksort = linksort;
        c->lasttime = time(NULL);
        c->filebuffer = filebuffer;

        if (uselocal)
          /* if this is a local file, it is considered complete already */
          c->fileflags |= CLF_FILECOMPLETE;

        filepart = StrIndexLast(buffer, '/');
        if (filepart)
          filepart++;
        else
          filepart = buffer;

        /* That silly AmIRC client requires a file length parameter! */
        SendCtcpf(from, "DCC SEND %s %lu %u -1", filepart,
                  myipaddrnum, htons(c->addr.sin_port));
        fprintf(stderr, "DCC SEND %s %lu %u -1\n", filepart,
                myipaddrnum, htons(c->addr.sin_port));
      }
      else
        ReplyCtcp(from, "ERRMSG Unable to establish connection");
    }
    else
      ReplyCtcp(from, "ERRMSG Unable to get the specified file");
  }
#endif
}

/* --- Alive ------------------------------------------------------ */

bool Alive(int s)
{
  struct sockaddr name;
  int namelen;

  snapshot;
  namelen = sizeof(name);
  if (-1 == getpeername(s, &name, &namelen)) {
    if (ENOTCONN == errno) {
      errno = 0;
      return FALSE;
    }
  }
  return TRUE;
}

/* --- ReadSocket ------------------------------------------------- */

int ReadSocket(int s, char *buffer, size_t buffer_size)
{
  char c;
  int i = 0;

  snapshot;
  do {
    if (1 > read(s, &c, 1))
      return 0;
    if (i < (buffer_size - 1))
      buffer[i++] = c;
  } while (c != '\n');
  buffer[i] = (char)0;

#ifdef DBUG
  fprintf(stderr, "%d < %s", s, buffer);
#endif

  return i;
}

static int ReadFileSendSocket(int s, char *buffer)
{
  char c;
  int i = 0;

  snapshot;
  do {
    if (read(s, &c, 1) < 1)
      return 0;
    buffer[i++] = c;
  } while (i < 4); /* This *IS* always 4-bytes as "defined" in the crappy
                      DCC SEND standard */
  return i;
}

static int WriteFileSendSocket(itemclient *c)
{
  int n;

  snapshot;
  if (c->filesent == c->fileacked) {
    n = read(c->file, c->filebuffer, CLF_FILEBUFFER);
    if (n > 0) {
      int err = write(c->socket, c->filebuffer, n);
      c->filesent += n;
      fprintf(stderr, "write() returned %d - sent %d bytes\n", err, c->filesent);
    }
    return n;
  }
  return 1; /* Don't terminate now */
}

/* --- WriteSocket ------------------------------------------------ */

inline void WriteSocket(int s, char *msg)
{
  snapshot;

#ifdef DBUG
  fprintf(stderr, "%d > %s\n", s, msg);
#endif

  write(s, msg, StrLength(msg));
  write(s, "\n", 1);
}

void WriteSocketf(int s, char *format, ...)
{
  char buffer[MAXLINE-2]; /* CR-LF, max 510 chars / line */
  va_list args;

  snapshot;

  va_start(args, format);
  trio_vsnprintf(buffer, sizeof(buffer), format, args);
  va_end(args);

  WriteSocket(s, buffer);
}

/* --- WriteNick -------------------------------------------------- */

inline void WriteNick(char *nick, char *msg)
{
  snapshot;
  WriteSocketf(serverSocket, "NOTICE %s :%s", nick, msg);
}

/* --- WriteServer ------------------------------------------------ */

void WriteServer(char *format, ...)
{
  static char buffer[MAXLINE-2];
  va_list args;

  snapshot;

  va_start(args, format);
  trio_vsnprintf(buffer, sizeof(buffer), format, args);
  va_end(args);

  WriteSocket(serverSocket, buffer);
}

/* --- HandleSockets ---------------------------------------------- */

void HandleSockets(fd_set *readset, fd_set *writeset)
{
  extern itemexec *execHead;
  char buffer[MAXLINE];
  int s;
  itemclient *c, *next;
  itemexec *px, *pxx;

  snapshot;

  /* --- Server messages --- */

  if (FD_ISSET(serverSocket, readset)) {
    if (0 < ReadSocket(serverSocket, buffer, sizeof(buffer))) {
      ParseServer(buffer);
    }
    else {
/* This is never reached? see ReadSocket() */
      /* Error or EOF from server */
      Debug("EOF from server (%s)", StrError(errno));
      DisconnectServ("EOF from server (%s)", StrError(errno));
      restart = cleanup = TRUE;
    }
  }

#ifdef BREESE
  /* --- Link bots --- */

  if (FD_ISSET(linkSocket, readset)) {
    if (0 < ReadLink(buffer))
      LinkParse(buffer);
  }
#endif

  /* --- Dcc clients --- */

  for (c = First(clientHead); c; c = next) {
    next = Next(c);

    if (FD_ISSET(c->socket, readset)) {
      /* To make sure we won't handle the same socket twice (CUT command) */
      FD_CLR(c->socket, readset);

      if (CL_LISTENING == c->status) {
        int size = sizeof(struct sockaddr_in);

        /* If we got something on a listen connection go ahead and accept it */
        s = accept(c->socket, (struct sockaddr *)&c->addr, &size);
        switch (s) {

          case -1:
            Debug("accept(2) failed on socket %d (%s)", c->socket, StrError(errno));
            RemoveClient(c);
            break;

          default:
            CloseConnection(c->socket);
            c->socket = s;
            c->status = CL_CONNECTED;

            FD_SET(c->socket, &rdset);
            if (OUT_SEND == c->linksort) {
              FD_SET(c->socket, &wrset);
              fprintf(stderr, "File sending initiated, here it should come...\n");
            }

            Logf(LOGCLIENT, "Connection accepted at socket %d", c->socket);
            break;

        }
        continue; /* for */
      }
      else {
        /* Message on a normal client connection */
        client = c;

        if (OUT_SEND == c->linksort) {
          /* This is a file sending socket, we might/should receive ACKs on
             this. */
          unsigned int ack;
          unsigned int networkack;

          s = ReadFileSendSocket(c->socket, (char *)&networkack);
          ack = ntohl(networkack);
          c->fileacked = ack; /* this many bytes acknowledged from the peer */
          fprintf(stderr, "=> GOT ACK %d\n", ack);
        }
        else {
          s = ReadSocket(c->socket, buffer, sizeof(buffer));
        }

        switch (s) {

          case -1: /* Read error on client */
/* This is never reached? see ReadSocket() & ReadFileSendSocket() */
            Debug("Error on client (%s)", StrError(errno));
            break;

          case 0: /* EOF from client */
            RemoveClient(c);
            continue; /* for */

          default:
            if (OUT_CHAT == c->linksort) {
              DccCommand(buffer);

              /*
               * This dirty hack is needed because some commands may remove
               * ANY client. Get rid of the hack and the FD_CLRs.
               */
              for (next = First(clientHead); next; next = Next(next)) {
                if (FD_ISSET(next->socket, readset) ||
                    FD_ISSET(next->socket, writeset))
                  break;
              }
              continue; /* for */
            }
            /* else got file data */
            break;
        }
      }
    }

    /*
     * Write signal is only received when a non-blocking connection is
     * established.
     */
    if (FD_ISSET(c->socket, writeset)) {
      /* To make sure we won't handle the same socket twice (CUT command) */
      FD_CLR(c->socket, writeset);

      if (CL_CONNECTING == c->status) {
        /*
         * Re-issue connect() to get the error.
         * Better to use getsockopt(SOL_ERROR)?
         */
        errno = 0;

        connect(c->socket, (struct sockaddr *)&c->addr, sizeof(struct sockaddr_in));
        switch (errno) {

          case EXIT_SUCCESS:
          case EISCONN:
            Connected(c);
            break;

          default:
            ReplyCtcpf(c->ident->nick, "ERRMSG Unable to establish connection (%s)",
                       StrError(errno));
            Logf(LOGCLIENT, "Connection failed for %s on socket %d (%s)",
                 c->ident->nick, c->socket, StrError(errno));
            RemoveClient(c);
            break;

        }
      }
      else if (OUT_SEND == c->linksort) {
        /* fprintf(stderr, "sending file\n"); */
        if ((0 >= WriteFileSendSocket(c)) &&
            (c->fileflags & CLF_FILECOMPLETE)) {
          /* We couldn't read and the file is considered complete */
          fprintf(stderr, "sending file done, %d bytes written!\n",
                  c->filesent);
          RemoveClient(c);
        }
      }
    }
  }

  /* --- Shell commands --- */

  for (px = First(execHead); px; px = pxx) {
    pxx = Next(px);
    if (FD_ISSET(px->socket, readset))
      GotExec(px); /* May DeleteEntry(px) */
  }

  lastevent = time(NULL);
}

#ifndef HAVE_GETDTABLESIZE

/* This is typically done for HPUX systems */

#include <sys/resource.h>

#ifndef FD_SETSIZE
#define FD_SETSIZE 64
#endif

int getdtablesize(void)
{
  struct rlimit rlp;

  snapshot;
  if (0 == getrlimit(RLIMIT_NOFILE, &rlp)) {
    return rlp.rlim_cur;
  }
  return FD_SETSIZE;
}
#endif

/* --- EventLoop -------------------------------------------------- */

void EventLoop(void)
{
  static struct timeval stamp;
  struct timeval curtime, dt;
  long diff;
  int fdsize;
  fd_set rtmpset, wtmpset;

  snapshot;
  gettimeofday(&stamp, NULL);

  while (!cleanup) {
    client = NULL;
    chat = FALSE;

    /* Calculate the timeout value */
    gettimeofday(&curtime, NULL);
    if (curtime.tv_usec > stamp.tv_usec)
      curtime.tv_usec += MILLION;

    diff = RTIMER - (MILLION * (curtime.tv_sec - stamp.tv_sec)) -
                               (curtime.tv_usec - stamp.tv_usec);

    if (diff > 0) {
      dt.tv_sec  = diff / MILLION;
      dt.tv_usec = diff % MILLION;

      fdsize = getdtablesize();
      if (fdsize > FD_SETSIZE)
        fdsize = FD_SETSIZE;

      rtmpset = rdset;
      wtmpset = wrset;
      errno = 0;

      /*
       * We are not expecting any out-of-band messages,
       * so the exceptfds argument is set to NULL
       */
      switch (select(fdsize, &rtmpset, &wtmpset, NULL, &dt)) {

        case -1: /* Ignore errors and interrupts */
          if (EINTR == errno)
            continue;
          Debug("select(2) failed (%s)", StrError(errno));
          cleanup = TRUE;
          restart = FALSE;
          break;

        case 0: /* select(2) timeout */
          gettimeofday(&stamp, NULL);
          now = stamp.tv_sec;
          TimeEvents();
          break;

        default: /* Data on socket */
          now = time(NULL);
          HandleSockets(&rtmpset, &wtmpset);
          break;

      }
    }
    else { /* Timeout overdue, activate immediately */
      gettimeofday(&stamp, NULL);
      now = stamp.tv_sec;
      TimeEvents();
    }
  }
}

/* --- NetInit ---------------------------------------------------- */

void NetInit(void)
{
  char mydomain[MAXHOSTNAMELEN];
  char *problemsolver;
  struct hostent *hp;

  snapshot;

  FD_ZERO(&rdset);
  FD_ZERO(&wrset);

  /*
   * Getting the actual name@host has proved troublesome on many
   * machines, this ugly solution was added quickly to get Darxide
   * up and running quickly, and therefore this "feature" remains
   * undocumented until we have sorted out how to deal with it.
   */

  problemsolver = getenv("DANCER_MYHOST");
  if (NULL == problemsolver) {
    /* If the environment variable isn't set, try the config value if set */
    if (dancer_myhost[0])
      problemsolver = dancer_myhost;
  }

  if (problemsolver) {
    StrCopyMax(myhost, sizeof(myhost), problemsolver);
    myipaddrnum = (ulong)ntohl(inet_addr(myhost));
    if (0 == myipaddrnum)
      Logf(LOGDEBUG, "Failed to inet_addr() the host '%s'", myhost);
  }
  else {
  /*
   * If no host was set in the environment (can also happen if
   * started from cron) we'll try to get it ourselves. Changes
   * are that we only get 'host' and not 'host.domain'.
   */
#if defined(AMIGA) && !defined(__GNUC__)
    struct utsname utstmp;

    uname(&utstmp);
    StrCopyMax(myhost, sizeof(myhost), utstmp.nodename);
#else
    gethostname(myhost, sizeof(myhost));
#endif
  }

  if ((0 == myipaddrnum) && (hp = GetHost(myhost))) {
    /*
     * The IP# is needed for outgoing dcc chats
     */
    myipaddrnum = (ulong)ntohl(((struct in_addr *)hp->h_addr)->s_addr);

    /*
     * If our previous attempt to get the domain name along with
     * the host name failed, let's try to find the domain now.
     */
    if (NULL == StrIndex(myhost, '.')) {
      /* First we try an inverse DNS lookup */
      hp = GetHost(MakeIP(myipaddrnum));
      if (hp) {
        char *name;
        int i;

        for (i = 0, name = hp->h_name; name; name = hp->h_aliases[i++]) {
          if (StrIndex(name, '.')) {
            StrCopyMax(myhost, sizeof(myhost), name);
            break;
          }
        }
      }

#ifdef HAVE_GETDOMAINNAME
      if (NULL == StrIndex(myhost, '.')) {
        /*
         * One last desperate attempt. The name received from
         * getdomainname() isn't necessarily the full domain name.
         */
        getdomainname(mydomain, sizeof(mydomain));
        if (StrIndex(mydomain, '.')) {
          StrFormatAppendMax(myhost, sizeof(myhost), ".%s", mydomain);
        }
        else {
          /* The machine does not know and we have to ask the nameserver */
        }
#endif
      }
    }
  }

#if defined(HAVE_YP_GET_DEFAULT_DOMAIN) && defined(HAVE_YP_MASTER)
  if ((char)0 == nameserver[0]) {
    char *my_defaultdomain;
    char *my_nameserver;

    if (!yp_get_default_domain(&my_defaultdomain)) {
      if (!yp_master(my_defaultdomain, "hosts.byname", &my_nameserver))
        StrCopyMax(nameserver, MIDBUFFER, my_nameserver);
    }
  }
#endif

#ifdef BREESE
  memset((char *)&fromaddr, 0, sizeof(fromaddr));
  fromaddr.sin_family = AF_INET;
  linkSocket = OpenLink();
#endif
}

/* --- NetCleanup ------------------------------------------------- */

void NetCleanup(void)
{  
  snapshot;
  CloseConnection(linkSocket);
  CloseConnection(serverSocket);
}


syntax highlighted by Code2HTML, v. 0.9.1