--- hybrid-angel/src/s_user.c	Mon Dec 10 15:49:09 2001
+++ ircd-hybrid-7beta9/src/s_conf.c	Sun Dec  2 10:00:56 2001
@@ -1,11 +1,8 @@
 /************************************************************************
- *   IRC - Internet Relay Chat, src/s_user.c
+ *   IRC - Internet Relay Chat, src/s_conf.c
  *   Copyright (C) 1990 Jarkko Oikarinen and
  *                      University of Oulu, Computing Center
  *
- *   See file AUTHORS in IRC package for additional names of
- *   the programmers. 
- *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
  *   the Free Software Foundation; either version 1, or (at your option)
@@ -20,1325 +17,2684 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *  $Id: s_user.c,v 7.172 2001/12/02 12:11:41 leeh Exp $
+ *  (C) 1988 University of Oulu,Computing Center and Jarkko Oikarinen"
+ *
+ *  $Id: s_conf.c,v 7.278 2001/12/02 15:00:56 leeh Exp $
  */
 
 #include <sys/types.h>
-#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
 
-#include <string.h>
 #include <stdio.h>
+#include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <time.h>
 #include <fcntl.h>
 #include <assert.h>
-#include <time.h>
-#include <limits.h>
 
+#include "config.h"
+#include "ircd_defs.h"
 #include "tools.h"
-#include "s_user.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include "resv.h"
+#include "s_stats.h"
 #include "channel.h"
-#include "channel_mode.h"
 #include "class.h"
 #include "client.h"
 #include "common.h"
-#include "fdlist.h"
+#include "event.h"
 #include "hash.h"
 #include "irc_string.h"
 #include "ircd.h"
 #include "list.h"
 #include "listener.h"
-#include "motd.h"
-#include "ircd_handler.h"
-#include "msg.h"
+#include "hostmask.h"
+#include "modules.h"
 #include "numeric.h"
+#include "fdlist.h"
 #include "s_bsd.h"
-#include "s_conf.h"
 #include "s_log.h"
-#include "s_serv.h"
-#include "s_stats.h"
-#include "scache.h"
 #include "send.h"
-#include "supported.h"
-#include "whowas.h"
-#include "md5.h"
+#include "s_gline.h"
+#include "s_debug.h"
+#include "fileio.h"
 #include "memory.h"
-#include "packet.h"
 
-static int valid_hostname(const char* hostname);
-static int valid_username(const char* username);
-static void report_and_set_user_flags( struct Client *, struct ConfItem * );
-static int check_X_line(struct Client *client_p, struct Client *source_p);
-void user_welcome(struct Client *source_p);
-static int introduce_client(struct Client *client_p, struct Client *source_p,
-			    struct User *user, char *nick);
-int oper_up( struct Client *source_p, struct ConfItem *aconf );
+struct config_server_hide ConfigServerHide;
 
+extern int yyparse(); /* defined in y.tab.c */
+extern int lineno;
+extern char linebuf[];
+int scount = 0;       /* used by yyparse(), etc */
 
-/* table of ascii char letters to corresponding bitmask */
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned int) 0xffffffff)
+#endif
 
-struct flag_item
-{
-  int mode;
-  char letter;
-};
 
-static struct flag_item user_modes[] =
+/* internally defined functions */
+
+static void lookup_confhost(struct ConfItem* aconf);
+static int  SplitUserHost(struct ConfItem *aconf);
+
+static void     set_default_conf(void);
+static void     validate_conf(void);
+static void     read_conf(FBFILE*);
+static void     clear_out_old_conf(void);
+static void     flush_deleted_I_P(void);
+static void     expire_tklines(dlink_list *);
+static int 	is_attached(struct Client *client_p, struct ConfItem *aconf);
+
+FBFILE* conf_fbfile_in;
+char    conf_line_in[256];
+struct ConfItem* yy_aconf;
+extern char yytext[];
+
+/* address of class 0 conf */
+static struct   Class* class0;
+
+static  int     verify_access(struct Client *client_p, const char *username);
+static  int     attach_iline(struct Client *, struct ConfItem *);
+
+static void clear_special_conf(struct ConfItem **);
+
+/* usually, with hash tables, you use a prime number...
+ * but in this case I am dealing with ip addresses, not ascii strings.
+ */
+
+#define IP_HASH_SIZE 0x1000
+
+typedef struct ip_entry
 {
-  {FLAGS_ADMIN, 'a'},
-  {FLAGS_BOTS,  'b'},
-  {FLAGS_CCONN, 'c'},
-  {FLAGS_DEBUG, 'd'},
-  {FLAGS_FULL,  'f'},
-  {FLAGS_CALLERID, 'g'},
-  {FLAGS_INVISIBLE, 'i'},
-  {FLAGS_SKILL, 'k'},
-  {FLAGS_LOCOPS, 'l'},
-  {FLAGS_NCHANGE, 'n'},
-  {FLAGS_OPER, 'o'},
-  {FLAGS_REJ, 'r'},
-  {FLAGS_SERVNOTICE, 's'},
-  {FLAGS_UNAUTH, 'u'},
-  {FLAGS_WALLOP, 'w'},
-  {FLAGS_EXTERNAL, 'x'},
-  {FLAGS_SPY, 'y'},
-  {FLAGS_OPERWALL, 'z'},
-  {0, 0}
-};
+#ifndef IPV6
+  u_int32_t ip;
+#else
+  struct irc_inaddr ip;
+#endif
+  int        count;
+#ifdef PACE_CONNECT
+  time_t last_attempt;
+#endif
+  struct ip_entry *next;
+} IP_ENTRY;
 
-/* memory is cheap. map 0-255 to equivalent mode */
+static IP_ENTRY *ip_hash_table[IP_HASH_SIZE];
 
-int user_modes_from_c_to_bitmask[] =
-{ 
-  /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x0F */
-  /* 0x10 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1F */
-  /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2F */
-  /* 0x30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x3F */
-  0,            /* @ */
-  0,            /* A */
-  0,            /* B */
-  0,            /* C */
-  0,            /* D */
-  0,            /* E */
-  0,            /* F */
-  0,            /* G */
-  0,            /* H */
-  0,            /* I */
-  0,            /* J */
-  0,            /* K */
-  0,            /* L */
-  0,            /* M */
-  0,            /* N */
-  0,            /* O */
-  0,            /* P */
-  0,            /* Q */
-  0,            /* R */
-  0,            /* S */
-  0,            /* T */
-  0,            /* U */
-  0,            /* V */
-  0,            /* W */
-  0,            /* X */
-  0,            /* Y */
-  0,            /* Z 0x5A */
-  0, 0, 0, 0, 0, /* 0x5F */ 
-  /* 0x60 */       0,
-  FLAGS_ADMIN,  /* a */
-  FLAGS_BOTS,   /* b */
-  FLAGS_CCONN,  /* c */
-  FLAGS_DEBUG,  /* d */
-  0,            /* e */
-  FLAGS_FULL,   /* f */
-  FLAGS_CALLERID,  /* g */
-  0,            /* h */
-  FLAGS_INVISIBLE, /* i */
-  0,            /* j */
-  FLAGS_SKILL,  /* k */
-  FLAGS_LOCOPS, /* l */
-  0,            /* m */
-  FLAGS_NCHANGE, /* n */
-  FLAGS_OPER,   /* o */
-  0,               /* p */
-  0,            /* q */
-  FLAGS_REJ,    /* r */
-  FLAGS_SERVNOTICE, /* s */
-  0,            /* t */
-  FLAGS_UNAUTH, /* u */
-  0,            /* v */
-  FLAGS_WALLOP, /* w */
-  FLAGS_EXTERNAL, /* x */
-  FLAGS_SPY,    /* y */
-  FLAGS_OPERWALL, /* z 0x7A */
-  0,0,0,0,0,     /* 0x7B - 0x7F */
-
-  /* 0x80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9F */
-  /* 0x90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9F */
-  /* 0xA0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xAF */
-  /* 0xB0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xBF */
-  /* 0xC0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xCF */
-  /* 0xD0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xDF */
-  /* 0xE0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xEF */
-  /* 0xF0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  /* 0xFF */
-};
+static int hash_ip(struct irc_inaddr *);
+
+static IP_ENTRY *find_or_add_ip(struct irc_inaddr*);
+
+/* general conf items link list root */
+struct ConfItem* ConfigItemList = NULL;
+
+/* conf xline link list root */
+struct ConfItem        *x_conf = ((struct ConfItem *)NULL);
+
+/* conf uline link list root */
+struct ConfItem        *u_conf = ((struct ConfItem *)NULL);
 
 /*
- * show_lusers -
- *
- * inputs	- pointer to client
- * output	-
- * side effects	- display to client user counts etc.
+ * conf_dns_callback - called when resolver query finishes
+ * if the query resulted in a successful search, hp will contain
+ * a non-null pointer, otherwise hp will be null.
+ * if successful save hp in the conf item it was called with
  */
-int show_lusers(struct Client *source_p) 
+static void conf_dns_callback(void* vptr, adns_answer *reply)
 {
-  if(!ConfigServerHide.hide_servers || IsOper(source_p))
-    sendto_one(source_p, form_str(RPL_LUSERCLIENT), me.name, source_p->name,
-              (Count.total-Count.invisi), Count.invisi, Count.server);
-  else
-    sendto_one(source_p, form_str(RPL_LUSERCLIENT), me.name, source_p->name,
-              (Count.total-Count.invisi), Count.invisi, 1);
-  if (Count.oper > 0)
-    sendto_one(source_p, form_str(RPL_LUSEROP), me.name, source_p->name,
-               Count.oper);
+  struct ConfItem *aconf = (struct ConfItem *) vptr;
 
-  if (Count.unknown > 0)
-    sendto_one(source_p, form_str(RPL_LUSERUNKNOWN), me.name, source_p->name,
-               Count.unknown);
+  if (reply->status == adns_s_ok)
+  {
+#ifdef IPV6
+    copy_s_addr(IN_ADDR(aconf->ipnum),
+                reply->rrs.addr->addr.inet6.sin6_addr.s6_addr);
+#else
+    copy_s_addr(IN_ADDR(aconf->ipnum),
+                reply->rrs.addr->addr.inet.sin_addr.s_addr);
+#endif
+    MyFree(reply);
+  }
 
-  if (Count.chan > 0)
-    sendto_one(source_p, form_str(RPL_LUSERCHANNELS),
-               me.name, source_p->name, Count.chan);
+  MyFree(aconf->dns_query);
+  aconf->dns_query = NULL;
+}
 
-  if(!ConfigServerHide.hide_servers || IsOper(source_p))
+/*
+ * conf_dns_lookup - do a nameserver lookup of the conf host
+ * if the conf entry is currently doing a ns lookup do nothing, otherwise
+ * set the conf_dns_pending flag
+ */
+void conf_dns_lookup(struct ConfItem* aconf)
+{
+  if (!aconf->dns_pending)
     {
-      sendto_one(source_p, form_str(RPL_LUSERME),
-                 me.name, source_p->name, Count.local, Count.myserver);
-      sendto_one(source_p, form_str(RPL_LOCALUSERS), me.name, source_p->name,
-                 Count.local, Count.max_loc);
+      aconf->dns_query = MyMalloc(sizeof(struct DNSQuery));
+      aconf->dns_query->ptr = aconf;
+      aconf->dns_query->callback = conf_dns_callback;
+      adns_gethost(aconf->host, aconf->aftype, aconf->dns_query);
+      aconf->dns_pending = 1;
     }
+}
 
-  sendto_one(source_p, form_str(RPL_GLOBALUSERS), me.name, source_p->name,
-             Count.total, Count.max_tot);
-
-  if(!ConfigServerHide.hide_servers || IsOper(source_p))
-    sendto_one(source_p, form_str(RPL_STATSCONN), me.name, source_p->name,
-               MaxConnectionCount, MaxClientCount, Count.totalrestartcount);
-
-  if (Count.local > MaxClientCount)
-    MaxClientCount = Count.local;
-
-  if ((Count.local + Count.myserver) > MaxConnectionCount)
-    MaxConnectionCount = Count.local + Count.myserver; 
+/*
+ * make_conf
+ *
+ * inputs	- none
+ * output	- pointer to new conf entry
+ * side effects	- none
+ */
+struct ConfItem* 
+make_conf()
+{
+  struct ConfItem* aconf;
 
-  return 0;
+  aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem));
+  memset(aconf, 0, sizeof(*aconf));
+  aconf->status       = CONF_ILLEGAL;
+  aconf->aftype       = AF_INET;
+  return (aconf);
 }
 
 /*
- * show_isupport
+ * delist_conf
  *
- * inputs	- pointer to client
- * output	- 
- * side effects	- display to client what we support (for them)
+ * inputs	- pointer to conf item to delist
+ * output	- none
+ * side effects	- remove conf item from ConfigItemList
  */
-void show_isupport(struct Client *source_p) 
+static void 
+delist_conf(struct ConfItem* aconf)
 {
-  char isupportbuffer[512];
+  if (aconf == ConfigItemList)
+  {
+    ConfigItemList = ConfigItemList->next;
+  }
+  else
+    {
+      struct ConfItem* bconf;
 
-  ircsprintf(isupportbuffer,FEATURES,FEATURESVALUES);
-  sendto_one(source_p, form_str(RPL_ISUPPORT), me.name, source_p->name, 
-  	     isupportbuffer);
-  return;
+      /* jdc -- "for ();" is evil; Semicolon-o-Death.  Use while(). */
+      bconf = ConfigItemList;
+      while (aconf != bconf->next)
+      {
+        bconf = bconf->next;
+      }
+      bconf->next = aconf->next;
+    }
+  aconf->next = NULL;
 }
 
+/*
+ * free_conf
+ *
+ * inputs	- pointer to conf to free
+ * output	- none
+ * side effects	-
+ */
+void free_conf(struct ConfItem* aconf)
+{
+  assert(aconf != NULL);
+  assert(!(aconf->status & CONF_CLIENT) ||
+         (aconf->host && strcmp(aconf->host, "NOMATCH")) ||
+         (aconf->clients == -1));
+  delete_adns_queries(aconf->dns_query);
+  MyFree(aconf->host);
+  if (aconf->passwd)
+    memset(aconf->passwd, 0, strlen(aconf->passwd));
+  MyFree(aconf->passwd);
+  if (aconf->spasswd)
+    memset(aconf->spasswd, 0, strlen(aconf->spasswd));
+  MyFree(aconf->spasswd);
+  MyFree(aconf->name);
+  MyFree(aconf->className);
+  MyFree(aconf->user);
+#ifdef HAVE_LIBCRYPTO
+  if (aconf->rsa_public_key)        { RSA_free(aconf->rsa_public_key); }
+  if (aconf->rsa_public_key_file)   { MyFree(aconf->rsa_public_key_file); }
+#endif
+  MyFree((char*) aconf);
+}
 
 /*
-** register_local_user
-**      This function is called when both NICK and USER messages
-**      have been accepted for the client, in whatever order. Only
-**      after this, is the USER message propagated.
-**
-**      NICK's must be propagated at once when received, although
-**      it would be better to delay them too until full info is
-**      available. Doing it is not so simple though, would have
-**      to implement the following:
-**
-**      (actually it has been implemented already for a while) -orabidoo
-**
-**      1) user telnets in and gives only "NICK foobar" and waits
-**      2) another user far away logs in normally with the nick
-**         "foobar" (quite legal, as this server didn't propagate
-**         it).
-**      3) now this server gets nick "foobar" from outside, but
-**         has already the same defined locally. Current server
-**         would just issue "KILL foobar" to clean out dups. But,
-**         this is not fair. It should actually request another
-**         nick from local user or kill him/her...
-*/
-
-int register_local_user(struct Client *client_p, struct Client *source_p, 
-			char *nick, char *username)
-{
-  struct ConfItem*  aconf;
-  struct User*     user = source_p->user;
-  char        tmpstr2[IRCD_BUFSIZE];
-  char	      ipaddr[HOSTIPLEN];
-  int  status;
-  dlink_node *ptr;
-  dlink_node *m;
-  char *id;
-  assert(0 != source_p);
-  assert(0 != source_p->localClient);
-  assert(source_p->username != username);
+ * remove all conf entries from the client except those which match
+ * the status field mask.
+ */
+void det_confs_butmask(struct Client* client_p, int mask)
+{
+  dlink_node *dlink;
+  dlink_node *link_next;
+  struct ConfItem *aconf;
 
-  user->last = CurrentTime;
-  /* Straight up the maximum rate of flooding... */
-  source_p->localClient->allow_read = MAX_FLOOD_PER_SEC_I;
+  for (dlink = client_p->localClient->confs.head; dlink; dlink = link_next)
+  {
+    link_next = dlink->next;
+    aconf = dlink->data;
 
-  /* pointed out by Mortiis, never be too careful */
-  if(strlen(username) > USERLEN)
-    username[USERLEN] = '\0';
+    if ((aconf->status & mask) == 0)
+    {
+      detach_conf(client_p, aconf);
+    }
+  }
+}
 
-  if( ( status = check_client(client_p, source_p, username )) < 0 )
-    return(CLIENT_EXITED);
+static struct LinkReport {
+  int conf_type;
+  int rpl_stats;
+  int conf_char;
+} report_array[] = {
+  { CONF_SERVER,           RPL_STATSCLINE, 'C'},
+  { CONF_LEAF,             RPL_STATSLLINE, 'L'},
+  { CONF_OPERATOR,         RPL_STATSOLINE, 'O'},
+  { CONF_HUB,              RPL_STATSHLINE, 'H'},
+  { 0, 0, '\0' }
+};
 
-  if(!valid_hostname(source_p->host))
-    {
-      sendto_one(source_p,":%s NOTICE %s :*** Notice -- You have an illegal character in your hostname", 
-		 me.name, source_p->name );
+/*
+ * report_configured_links
+ *
+ * inputs	- pointer to client to report to
+ *		- type of line to report
+ * output	- NONE
+ * side effects	-
+ */
+void 
+report_configured_links(struct Client* source_p, int mask)
+{
+  struct ConfItem*   tmp;
+  struct LinkReport* p;
+  char*              host;
+  char*              pass;
+  char*              user;
+  char*              name;
+  char*		     classname;
+  int                port;
+
+  for (tmp = ConfigItemList; tmp; tmp = tmp->next) {
+    if (tmp->status & mask)
+      {
+        for (p = &report_array[0]; p->conf_type; p++)
+          if (p->conf_type == tmp->status)
+            break;
+	    
+        if(p->conf_type == 0)
+	  return;
+
+        get_printable_conf(tmp, &name, &host, &pass, &user, &port,&classname);
+
+        if(mask & CONF_SERVER)
+          {
+            char c;
+	    char buf[20];
+	    char *s = buf;
+	    
+	    buf[0] = 0;
+            c = p->conf_char;
+	    
+	    if (tmp->flags & CONF_FLAGS_ALLOW_AUTO_CONN)
+	      *s++ = 'A';
+	    if (tmp->flags & CONF_FLAGS_CRYPTLINK)
+	      *s++ = 'C';
+	    if (tmp->flags & CONF_FLAGS_LAZY_LINK)
+	      *s++ = 'L';
+	    if (tmp->flags & CONF_FLAGS_COMPRESSED)
+	      *s++ = 'Z';
+	    if (tmp->fakename)
+	      *s++ = 'M';
+	    
+	    if (!buf[0])
+              *s++ = '*';
+	      
+	    *s++ = 0;
+            /* Allow admins to see actual ips */
+            if(IsOperAdmin(source_p))
+              sendto_one(source_p, form_str(p->rpl_stats), me.name,
+                         source_p->name, c,
+                         host,
+			 buf,
+                         name,
+                         port,
+                         classname,
+                         oper_flags_as_string((int)tmp->hold));
+            else
+              sendto_one(source_p, form_str(p->rpl_stats), me.name,
+                         source_p->name, c,
+                         "*@127.0.0.1",
+			 buf,
+                         name,
+                         port,
+                         classname);
+
+          }
+        else if(mask & (CONF_OPERATOR))
+          {
+            /* Don't allow non opers to see oper privs */
+            if(IsOper(source_p))
+              sendto_one(source_p, form_str(p->rpl_stats), me.name,
+                         source_p->name,
+                         p->conf_char,
+                         user, host, name,
+                         oper_privs_as_string((struct Client *)NULL,port),
+                         classname,
+                         oper_flags_as_string((int)tmp->hold));
+            else
+              sendto_one(source_p, form_str(p->rpl_stats), me.name,
+                         source_p->name, p->conf_char,
+                         user, host, name,
+                         "0",
+                         classname,
+                         "");
+          }
+        else
+          sendto_one(source_p, form_str(p->rpl_stats), me.name,
+                     source_p->name, p->conf_char,
+                     host, name, port,
+                     classname);
+      }
+  }
+}
 
-      strncpy(source_p->host,source_p->localClient->sockhost,HOSTIPLEN+1);
-    }
+/*
+ * report_specials - report special conf entries
+ *
+ * inputs       - struct Client pointer to client to report to
+ *              - int flags type of special struct ConfItem to report
+ *              - int numeric for struct ConfItem to report
+ * output       - none
+ * side effects -
+ */
+void 
+report_specials(struct Client* source_p, int flags, int numeric)
+{
+  struct ConfItem* this_conf;
+  struct ConfItem* aconf;
+  char*            name;
+  char*            host;
+  char*            pass;
+  char*            user;
+  char*       classname;
+  int              port;
+
+  if (flags & CONF_XLINE)
+    this_conf = x_conf;
+  else if (flags & CONF_ULINE)
+    this_conf = u_conf;
+  else return;
+
+  for (aconf = this_conf; aconf; aconf = aconf->next)
+    if (aconf->status & flags)
+      {
+        get_printable_conf(aconf, &name, &host, &pass,
+                           &user, &port, &classname);
+
+        sendto_one(source_p, form_str(numeric),
+                   me.name,
+                   source_p->name,
+                   name,
+                   pass);
+      }
+}
 
-  ptr = source_p->localClient->confs.head;
-  aconf = ptr->data;
+/*
+ * check_client
+ *
+ * inputs	- pointer to client
+ * output	- 0 = Success
+ * 		  NOT_AUTHORIZED (-1) = Access denied (no I line match)
+ * 		  SOCKET_ERROR   (-2) = Bad socket.
+ * 		  I_LINE_FULL    (-3) = I-line is full
+ *		  TOO_MANY       (-4) = Too many connections from hostname
+ * 		  BANNED_CLIENT  (-5) = K-lined
+ * side effects - Ordinary client access check.
+ *		  Look for conf lines which have the same
+ * 		  status as the flags passed.
+ */
+int 
+check_client(struct Client *client_p, struct Client *source_p, char *username)
+{
+  static char     sockname[HOSTLEN + 1];
+  int             i;
+ 
+  ClearAccess(source_p);
 
-  if (aconf == NULL)
+  if ((i = verify_access(source_p, username)))
     {
-      (void)exit_client(client_p, source_p, &me, "*** Not Authorized");
-      return(CLIENT_EXITED);
+      ilog(L_INFO, "Access denied: %s[%s]", source_p->name, sockname);
     }
 
-  if (!IsGotId(source_p))
+  switch( i )
     {
-      if (IsNeedIdentd(aconf))
-	{
-	  ServerStats->is_ref++;
-	  sendto_one(source_p,
-		     ":%s NOTICE %s :*** Notice -- You need to install identd to use this server",
-		     me.name, client_p->name);
-	  (void)exit_client(client_p, source_p, &me, "Install identd");
-	  return(CLIENT_EXITED);
-	}
-      else
-	strncpy_irc(source_p->username, username, USERLEN);
-
-      if (IsNoTilde(aconf))
-	{
-	  strncpy_irc(source_p->username, username, USERLEN);
-	}
-      else
-	{
-	  *source_p->username = '~';
-	  strncpy_irc(&source_p->username[1], username, USERLEN - 1);
-	}
-      source_p->username[USERLEN] = '\0';
-    }
+    case SOCKET_ERROR:
+      (void)exit_client(client_p, source_p, &me, "Socket Error");
+      break;
 
-  /* password check */
-  if (!BadPtr(aconf->passwd) && !(IsConfDoSpoofIp(aconf)) &&
-      strcmp(source_p->localClient->passwd, aconf->passwd))
-    {
+    case TOO_MANY:
+      sendto_realops_flags(FLAGS_FULL, L_ALL, 
+                           "Too many on IP for %s (%s).",
+			   get_client_name(source_p, SHOW_IP),
+			   source_p->localClient->sockhost);
+			   
+      ilog(L_INFO,"Too many connections on IP from %s.",
+	   get_client_name(source_p, SHOW_IP));
+      
       ServerStats->is_ref++;
-      sendto_one(source_p, form_str(ERR_PASSWDMISMATCH),
-		 me.name, source_p->name);
-      (void)exit_client(client_p, source_p, &me, "Bad Password");
-      return(CLIENT_EXITED);
-    }
-  memset(source_p->localClient->passwd,0, sizeof(source_p->localClient->passwd));
+      (void)exit_client(client_p, source_p, &me, 
+			"No more connections allowed on that IP" );
+      break;
 
-  /* report if user has &^>= etc. and set flags as needed in source_p */
-  report_and_set_user_flags(source_p, aconf);
-  
-  /* Limit clients */
-  /*
-   * We want to be able to have servers and F-line clients
-   * connect, so save room for "buffer" connections.
-   * Smaller servers may want to decrease this, and it should
-   * probably be just a percentage of the MAXCLIENTS...
-   *   -Taner
-   */
-  /* Except "F:" clients */
-  if ( ( (Count.local + 1) >= (GlobalSetOptions.maxclients+MAX_BUFFER)
-	 ||
-	 (Count.local +1) >= (GlobalSetOptions.maxclients - 5) )
-       &&
-       !(IsExemptLimits(source_p)) )
-    {
+    case I_LINE_FULL:
       sendto_realops_flags(FLAGS_FULL, L_ALL,
-			   "Too many clients, rejecting %s[%s].",
-			   nick, source_p->host);
+                           "I-line is full for %s (%s).",
+			   get_client_name(source_p, SHOW_IP),
+			   source_p->localClient->sockhost);
 			   
+      ilog(L_INFO,"Too many connections from %s.",
+	   get_client_name(source_p, SHOW_IP));
+      
       ServerStats->is_ref++;
-      (void)exit_client(client_p, source_p, &me,
-			"Sorry, server is full - try later");
-      return(CLIENT_EXITED);
-    }
+      (void)exit_client(client_p, source_p, &me, 
+		"No more connections allowed in your connection class" );
+      break;
 
-  /* valid user name check */
-
-  if (!valid_username(source_p->username))
+    case NOT_AUTHORIZED:
     {
-      sendto_realops_flags(FLAGS_REJ, L_ALL,
-                           "Invalid username: %s (%s@%s)",
-			   nick, source_p->username, source_p->host);
+      static char ipaddr[HOSTIPLEN];
       ServerStats->is_ref++;
-      ircsprintf(tmpstr2, "Invalid username [%s]", source_p->username);
-      (void)exit_client(client_p, source_p, &me, tmpstr2);
-      return(CLIENT_EXITED);
+      /* jdc - lists server name & port connections are on */
+      /*       a purely cosmetical change */
+      inetntop(source_p->localClient->aftype, &IN_ADDR(source_p->localClient->ip), ipaddr, HOSTIPLEN);
+      sendto_realops_flags(FLAGS_UNAUTH, L_ALL,
+			   "Unauthorised client connection from %s [%s] on [%s/%u].",
+			   get_client_name(source_p, SHOW_IP),
+			   ipaddr,
+			   source_p->localClient->listener->name,
+			   source_p->localClient->listener->port);
+			   
+      ilog(L_INFO,
+	  "Unauthorized client connection from %s on [%s/%u].",
+	  get_client_name(source_p, SHOW_IP),
+	  source_p->localClient->listener->name,
+	  source_p->localClient->listener->port);
+	  
+      (void)exit_client(client_p, source_p, &me,
+			"You are not authorized to use this server");
+      break;
     }
+    case BANNED_CLIENT:
+      (void)exit_client(client_p,client_p, &me, "*** Banned ");
+      ServerStats->is_ref++;
+      break;
 
-  /* end of valid user name check */
-  
-  if ((status = check_X_line(client_p,source_p)) < 0)
-    return status;
-
-  if (source_p->user->id[0] == '\0') 
-    {
-      for (id = id_get(); find_id(id); id = id_get())
-        ;
-      strcpy(source_p->user->id, id);
-      add_to_id_hash_table(id, source_p);
-      id = id_get();
-      strcpy(user->id_key, id);
-    }
-
-  inetntop(source_p->localClient->aftype, &IN_ADDR(source_p->localClient->ip), 
-  				ipaddr, HOSTIPLEN);
-  sendto_realops_flags(FLAGS_CCONN, L_ALL,
-		       "Client connecting: %s (%s@%s) [%s] {%s} [%s]",
-		       nick, source_p->username, source_p->host,
-		       ipaddr,
-		       get_client_class(source_p), source_p->info);
-  
-  if ((++Count.local) > Count.max_loc)
-    {
-      Count.max_loc = Count.local;
-      if (!(Count.max_loc % 10))
-	sendto_realops_flags(FLAGS_ALL, L_ALL,
-	                     "New Max Local Clients: %d",
-			     Count.max_loc);
+    case 0:
+    default:
+      break;
     }
-
-  SetClient(source_p);
-
-  /* XXX source_p->servptr is &me, since local client */
-  source_p->servptr = find_server(user->server);
-  add_client_to_llist(&(source_p->servptr->serv->users), source_p);
-
-  /* Increment our total user count here */
-  if (++Count.total > Count.max_tot)
-    Count.max_tot = Count.total;
-  source_p->localClient->allow_read = MAX_FLOOD_PER_SEC_I;
-
-  Count.totalrestartcount++;
-  user_welcome(source_p);
-
-  m = dlinkFind(&unknown_list, source_p);
-
-  assert(m != NULL);
-  dlinkDelete(m, &unknown_list);
-  dlinkAdd(source_p, m, &lclient_list);
-
-  return (introduce_client(client_p, source_p, user, nick));
+  return(i);
 }
 
 /*
- * register_remote_user
+ * verify_access
  *
- * inputs
- * output
- * side effects	- This function is called when a remote client
- *		  is introduced by a server.
+ * inputs	- pointer to client to verify
+ *		- pointer to proposed username
+ * output	- 0 if success -'ve if not
+ * side effect	- find the first (best) I line to attach.
  */
-int register_remote_user(struct Client *client_p, struct Client *source_p, 
-			 char *nick, char *username)
+static int 
+verify_access(struct Client* client_p, const char* username)
 {
-  struct User*     user = source_p->user;
-  struct Client *target_p;
-  
-  assert(0 != source_p);
-  assert(source_p->username != username);
-
-  user->last = CurrentTime;
-
-  /* pointed out by Mortiis, never be too careful */
-  if(strlen(username) > USERLEN)
-    username[USERLEN] = '\0';
-
-  strncpy_irc(source_p->username, username, USERLEN);
-
-  SetClient(source_p);
-
-  /* Increment our total user count here */
-  if (++Count.total > Count.max_tot)
-    Count.max_tot = Count.total;
-
-  source_p->servptr = find_server(user->server);
-
-  if (source_p->servptr == NULL)
-    {
-      sendto_realops_flags(FLAGS_ALL, L_ALL,"Ghost killed: %s on invalid server %s",
-			   source_p->name, source_p->user->server);
-
-      kill_client(client_p, source_p, "%s (Server doesn't exist)",
-		  me.name);
-
-#if 0
-      sendto_one(client_p,":%s KILL %s :%s (Ghosted, %s doesn't exist)",
-                 me.name, source_p->name, me.name, user->server);
-#endif
-      source_p->flags |= FLAGS_KILLED;
-      return exit_client(NULL, source_p, &me, "Ghost");
+  struct ConfItem* aconf;
+  struct ConfItem* gkill_conf;
+  char       non_ident[USERLEN + 1];
+  if (IsGotId(client_p))
+    {
+      aconf = find_address_conf(client_p->host,client_p->username,
+				&client_p->localClient->ip,
+				client_p->localClient->aftype);
     }
-
-  add_client_to_llist(&(source_p->servptr->serv->users), source_p);
-
-  if ((target_p = find_server(user->server)) && target_p->from != source_p->from)
+  else
     {
-      sendto_realops_flags(FLAGS_DEBUG, L_ALL,
-			   "Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
-			   client_p->name, nick, source_p->username,
-			   source_p->host, user->server,
-			   target_p->name, target_p->from->name);
-      kill_client(client_p, source_p,
-		 "%s (NICK from wrong direction (%s != %s))",
-		  me.name,
-		  user->server,
-		  target_p->from->name);
-
-      source_p->flags |= FLAGS_KILLED;
-      return exit_client(source_p, source_p, &me,
-			 "USER server wrong direction");
-      
+      non_ident[0] = '~';
+      strncpy_irc(&non_ident[1],username, USERLEN - 1);
+      non_ident[USERLEN] = '\0';
+      aconf = find_address_conf(client_p->host,non_ident,
+				&client_p->localClient->ip,
+				client_p->localClient->aftype);
     }
-  /*
-   * Super GhostDetect:
-   * If we can't find the server the user is supposed to be on,
-   * then simply blow the user away.        -Taner
-   */
-  if (!target_p)
+
+  if (aconf != NULL)
     {
-      kill_client(client_p, source_p, "%s GHOST (no server found)",
-                  me.name);
-#if 0
-      sendto_one(client_p,
-		 ":%s KILL %s :%s GHOST (no server %s on the net)",
-		 me.name,
-		 source_p->name, me.name, user->server);
-#endif
-      sendto_realops_flags(FLAGS_ALL, L_ALL, "No server %s for user %s[%s@%s] from %s",
-			   user->server, source_p->name, source_p->username,
-			   source_p->host, source_p->from->name);
-      source_p->flags |= FLAGS_KILLED;
-      return exit_client(source_p, source_p, &me, "Ghosted Client");
+      if (aconf->status & CONF_CLIENT)
+	{
+	  if (aconf->flags & CONF_FLAGS_REDIR)
+	    {
+	      sendto_one(client_p, form_str(RPL_REDIR), me.name, client_p->name,
+			 aconf->name ? aconf->name : "", aconf->port);
+	      return(NOT_AUTHORIZED);
+	    }
+	  if (ConfigFileEntry.glines)
+	    {
+	      if (!IsConfExemptKline(aconf))
+		{
+		  if (IsGotId(client_p))
+		    gkill_conf = find_gkill(client_p, client_p->username);
+		  else
+		    gkill_conf = find_gkill(client_p, non_ident);
+		  if (gkill_conf)
+		    {
+		      sendto_one(client_p, ":%s NOTICE %s :*** G-lined", me.name,
+				 client_p->name);
+		      sendto_one(client_p, ":%s NOTICE %s :*** Banned %s",
+				 me.name, client_p->name, gkill_conf->passwd);
+		      return(BANNED_CLIENT);
+		    }
+		}
+	    }
+	  if (IsConfDoIdentd(aconf))
+	    SetNeedId(client_p);
+	  if (IsConfRestricted(aconf))
+	    SetRestricted(client_p);
+	  /* Thanks for spoof idea amm */
+	  if (IsConfDoSpoofIp(aconf))
+	    {
+	      if (IsConfSpoofNotice(aconf))
+		{
+		  sendto_realops_flags(FLAGS_ALL, L_ADMIN,
+				       "%s spoofing: %s as %s", client_p->name,
+				       client_p->host, aconf->name);
+		}
+	      strncpy_irc(client_p->host, aconf->name, HOSTLEN);
+	      SetIPSpoof(client_p);
+	      SetIPHidden(client_p);
+	    }
+	  return(attach_iline(client_p, aconf));
+	}
+      else if (aconf->status & CONF_KILL)
+	{
+	  if (ConfigFileEntry.kline_with_reason)
+	    {
+	      sendto_one(client_p, ":%s NOTICE %s :*** Banned %s",
+			 me.name,client_p->name,aconf->passwd);
+	    }
+	  return(BANNED_CLIENT);
+	}
     }
-
-  return (introduce_client(client_p, source_p, user, nick));
+ return(NOT_AUTHORIZED);
 }
 
 /*
- * introduce_clients
+ * attach_iline
  *
- * inputs	-
+ * inputs	- client pointer
+ *		- conf pointer
  * output	-
- * side effects - This common function introduces a client to the rest
- *		  of the net, either from a local client connect or
- *		  from a remote connect.
+ * side effects	- do actual attach
  */
-static int
-introduce_client(struct Client *client_p, struct Client *source_p,
-		 struct User *user, char *nick)
+static 
+int attach_iline(struct Client *client_p, struct ConfItem *aconf)
 {
-  dlink_node *server_node;
-  struct Client *server;
-  static char ubuf[12];
+  IP_ENTRY *ip_found;
+  ip_found = find_or_add_ip(&client_p->localClient->ip);
 
-  send_umode(NULL, source_p, 0, SEND_UMODES, ubuf);
+  SetIpHash(client_p);
+  ip_found->count++;
 
-  if (!*ubuf)
+  /* only check it if its non zero */
+  if ( aconf->c_class /* This should never non NULL *grin* */ &&
+       ConfConFreq(aconf) && ip_found->count > ConfConFreq(aconf))
     {
-      ubuf[0] = '+';
-      ubuf[1] = '\0';
+      if(!IsConfExemptLimits(aconf))
+        return TOO_MANY; /* Already at maximum allowed ip#'s */
+      else
+        {
+          sendto_one(client_p,
+       ":%s NOTICE %s :*** :I: line is full, but you have an >I: line!",
+                     me.name,client_p->name);
+        }
     }
 
+  return (attach_conf(client_p, aconf) );
+}
 
-  /* arghhh one could try not introducing new nicks to ll leafs
-   * but then you have to introduce them "on the fly" in SJOIN
-   * not fun.
-   * Its not going to cost much more bandwidth to simply let new
-   * nicks just ride on through.
-   */
+/* link list of free IP_ENTRY's */
 
-  /*
-   * We now introduce nicks "on the fly" in SJOIN anyway --
-   * you _need_ to if you aren't going to burst everyone initially.
-   *
-   * Only send to non CAP_LL servers, unless we're a lazylink leaf,
-   * in that case just send it to the uplink.
-   * -davidt
-   * rewritten to cope with UIDs .. eww eww eww --is
-   */
-  
-  if (!ServerInfo.hub && uplink && IsCapable(uplink,CAP_LL)
-      && client_p != uplink) 
-    {
-      if (IsCapable(uplink, CAP_UID) && HasID(source_p))
-	{
-	  sendto_one(uplink, "CLIENT %s %d %lu %s %s %s %s %s :%s",
-		     nick,
-		     source_p->hopcount+1,
-		     (unsigned long) source_p->tsinfo,
-		     ubuf,
-		     source_p->username, source_p->host, user->server,
-		     user->id, source_p->info);
-	}
-      else
-	{
-	  sendto_one(uplink, "NICK %s %d %lu %s %s %s %s :%s",
-		     nick,
-		     source_p->hopcount+1,
-		     (unsigned long) source_p->tsinfo,
-		     ubuf,
-		     source_p->username, source_p->host, user->server,
-		     source_p->info);
-	}
-    }
-  else
-    {
-      for (server_node = serv_list.head; server_node; server_node = server_node->next)
-	{
-	  server = (struct Client *) server_node->data;
-		  
-	  if (IsCapable(server, CAP_LL) || server == client_p)
-	    continue;
-		  
-	  if (IsCapable(server, CAP_UID) && HasID(source_p))
-	    sendto_one(server, "CLIENT %s %d %lu %s %s %s %s %s :%s",
-		       nick,
-		       source_p->hopcount+1,
-		       (unsigned long) source_p->tsinfo,
-		       ubuf,
-		       source_p->username, source_p->host, user->server,
-		       user->id, source_p->info);
-	  else
-	    sendto_one(server, "NICK %s %d %lu %s %s %s %s :%s",
-		       nick,
-		       source_p->hopcount+1,
-		       (unsigned long) source_p->tsinfo,
-		       ubuf,
-		       source_p->username, source_p->host, user->server,
-		       source_p->info);
-	}
+static IP_ENTRY *free_ip_entries;
+
+/*
+ * clear_ip_hash_table()
+ *
+ * input                - NONE
+ * output               - NONE
+ * side effects         - clear the ip hash table
+ *
+ */
+
+void 
+clear_ip_hash_table()
+{
+  void *block_IP_ENTRIES;        /* block of IP_ENTRY's */
+  IP_ENTRY *new_IP_ENTRY;        /* new IP_ENTRY being made */
+  IP_ENTRY *last_IP_ENTRY;        /* last IP_ENTRY in chain */
+  int size;
+  int n_left_to_allocate = MAXCONNECTIONS;
+
+  size = sizeof(IP_ENTRY) + (sizeof(IP_ENTRY) & (sizeof(void*) - 1) );
+
+  block_IP_ENTRIES = (void *)MyMalloc((size * n_left_to_allocate));  
+
+  free_ip_entries = (IP_ENTRY *)block_IP_ENTRIES;
+  last_IP_ENTRY = free_ip_entries;
+
+  /* *shudder* pointer arithmetic */
+  while(--n_left_to_allocate)
+    {
+      block_IP_ENTRIES = (void *)((unsigned long)block_IP_ENTRIES + 
+                        (unsigned long) size);
+      new_IP_ENTRY = (IP_ENTRY *)block_IP_ENTRIES;
+      last_IP_ENTRY->next = new_IP_ENTRY;
+      new_IP_ENTRY->next = (IP_ENTRY *)NULL;
+      last_IP_ENTRY = new_IP_ENTRY;
     }
-  
-  if (ubuf[1])
-    send_umode_out(client_p, source_p, 0);
-  return 0;
+  memset((void *)ip_hash_table, 0, sizeof(ip_hash_table));
 }
 
 /* 
- * valid_hostname - check hostname for validity
+ * find_or_add_ip()
+ *
+ * inputs       - client_p
+ *              - name
  *
- * Inputs       - pointer to user
- * Output       - YES if valid, NO if not
- * Side effects - NONE
+ * output       - pointer to an IP_ENTRY element
+ * side effects -
  *
- * NOTE: this doesn't allow a hostname to begin with a dot and
- * will not allow more dots than chars.
+ * If the ip # was not found, a new IP_ENTRY is created, and the ip
+ * count set to 0.
+ * XXX: Broken for IPv6
  */
-static int valid_hostname(const char* hostname)
-{
-  const char* p     = hostname;
 
-  assert(0 != p);
-
-  if ('.' == *p)
-    return NO;
+static IP_ENTRY *
+find_or_add_ip(struct irc_inaddr *ip_in)
+{
+  int hash_index;
+  IP_ENTRY *ptr, *newptr;
 
-  while (*p)
-    {
-      if (!IsHostChar(*p))
-        return NO;
-      p++;
-    }
-  return (YES);
+  for(ptr = ip_hash_table[hash_index = hash_ip(ip_in)]; ptr;
+      ptr = ptr->next)
+  {
+   if(!memcmp(&ptr->ip, ip_in, sizeof(*ip_in)))
+   {
+    return(ptr);
+   }
+  }
+  if ( (ptr = ip_hash_table[hash_index]) != (IP_ENTRY *)NULL )
+    {
+      if( free_ip_entries == (IP_ENTRY *)NULL)
+	outofmemory();
+
+      newptr = ip_hash_table[hash_index] = free_ip_entries;
+      free_ip_entries = newptr->next;
+
+      memcpy(&newptr->ip, ip_in, sizeof(*ip_in));
+      newptr->count = 0;
+#ifdef PACE_CONNECT
+      newptr->last_attempt = 0;
+#endif      
+      newptr->next = ptr;
+      return(newptr);
+    }
+
+  if( free_ip_entries == (IP_ENTRY *)NULL)
+    outofmemory();
+
+  ptr = ip_hash_table[hash_index] = free_ip_entries;
+  free_ip_entries = ptr->next;
+  memcpy(&ptr->ip, ip_in, sizeof(*ip_in));
+  ptr->count = 0;
+  ptr->next = (IP_ENTRY *)NULL;
+  return (ptr);
 }
 
 /* 
- * valid_username - check username for validity
+ * remove_one_ip
  *
- * Inputs       - pointer to user
- * Output       - YES if valid, NO if not
- * Side effects - NONE
+ * inputs        - unsigned long IP address value
+ * output        - NONE
+ * side effects  - ip address listed, is looked up in ip hash table
+ *                 and number of ip#'s for that ip decremented.
+ *                 if ip # count reaches 0, the IP_ENTRY is returned
+ *                 to the free_ip_enties link list.
+ * XXX: Broken for IPV6
+ */
+
+void 
+remove_one_ip(struct irc_inaddr *ip_in)
+{
+  IP_ENTRY *ptr, **lptr;
+  int hash_index = hash_ip(ip_in);
+  for (lptr = ip_hash_table+hash_index, ptr = *lptr;
+       ptr;
+       lptr=&ptr->next, ptr=*lptr)
+  {
+#ifndef IPV6
+   if (ptr->ip != PIN_ADDR(ip_in))
+    continue;
+#else
+   if (memcmp(&IN_ADDR(ptr->ip), &PIN_ADDR(ip_in),
+              sizeof(struct irc_inaddr)))
+    continue;
+#endif
+  if (ptr->count != 0)
+   ptr->count--;
+#ifndef PACE_CONNECT
+  if (ptr->count != 0)
+   continue;
+#else
+  if (ptr->count != 0 ||
+      (CurrentTime-ptr->last_attempt)<=ConfigFileEntry.throttle_time)
+   continue;
+#endif
+  *lptr = ptr->next;
+  ptr->next = free_ip_entries;
+  free_ip_entries = ptr;
+  return;
+ }
+}
+
+/*
+ * hash_ip()
  * 
- * Absolutely always reject any '*' '!' '?' '@' in an user name
- * reject any odd control characters names.
- * Allow '.' in username to allow for "first.last"
- * style of username
+ * input        - pointer to an irc_inaddr
+ * output       - integer value used as index into hash table
+ * side effects - hopefully, none
  */
-static int valid_username(const char* username)
+
+static int 
+hash_ip(struct irc_inaddr *addr)
 {
-  int dots = 0;
-  const char *p = username;
+#ifndef IPV6
+  int hash;
+  u_int32_t ip;
+
+  ip = ntohl(PIN_ADDR(addr));
+  hash = ((ip >> 12) + ip) & (IP_HASH_SIZE-1);
+  return(hash);
+#else
+  unsigned int hash = 0;
+  char *ip = (char *) &PIN_ADDR(addr);
+
+  while (*ip)
+    { 
+      hash = (hash << 4) - (hash + (unsigned char)*ip++);
+    }
+
+  return(hash & (IP_HASH_SIZE - 1));
+#endif
+}
 
-  assert(0 != p);
+/*
+ * count_ip_hash
+ *
+ * inputs        - pointer to counter of number of ips hashed 
+ *               - pointer to memory used for ip hash
+ * output        - returned via pointers input
+ * side effects  - NONE
+ *
+ * number of hashed ip #'s is counted up, plus the amount of memory
+ * used in the hash.
+ */
 
-  if ('~' == *p)
-    ++p;
+void 
+count_ip_hash(int *number_ips_stored,u_long *mem_ips_stored)
+{
+  IP_ENTRY *ip_hash_ptr;
+  int i;
 
-  /* reject usernames that don't start with an alphanum
-   * i.e. reject jokers who have '-@somehost' or '.@somehost'
-   * or "-hi-@somehost", "h-----@somehost" would still be accepted.
-   */
-  if (!IsAlNum(*p))
-    return NO;
+  *number_ips_stored = 0;
+  *mem_ips_stored = 0;
 
-  while (*++p)
+  for(i = 0; i < IP_HASH_SIZE ;i++)
     {
-      if((*p == '.') && ConfigFileEntry.dots_in_ident)
+      ip_hash_ptr = ip_hash_table[i];
+      while(ip_hash_ptr)
         {
-          dots++;
-          if(dots > ConfigFileEntry.dots_in_ident)
-            return NO;
-          if(!IsUserChar(p[1]))
-            return NO;
+          *number_ips_stored = *number_ips_stored + 1;
+          *mem_ips_stored = *mem_ips_stored +
+             sizeof(IP_ENTRY);
+
+          ip_hash_ptr = ip_hash_ptr->next;
         }
-      else if (!IsUserChar(*p))
-        return NO;
     }
-  return YES;
 }
 
-/* report_and_set_user_flags
+/*
+ * iphash_stats()
  *
- * Inputs       - pointer to source_p
- *              - pointer to aconf for this user
- * Output       - NONE
- * Side effects -
- * Report to user any special flags they are getting, and set them.
+ * inputs        - 
+ * output        -
+ * side effects        -
  */
-
-static void 
-report_and_set_user_flags(struct Client *source_p,struct ConfItem *aconf)
+void 
+iphash_stats(struct Client *client_p, struct Client *source_p,
+		  int parc, char *parv[],FBFILE* out)
 {
-  /* If this user is being spoofed, tell them so */
-  if(IsConfDoSpoofIp(aconf))
-    {
-      sendto_one(source_p,
-                 ":%s NOTICE %s :*** Spoofing your IP. congrats.",
-                 me.name,source_p->name);
-    }
-
-  /* If this user is in the exception class, Set it "E lined" */
-  if(IsConfExemptKline(aconf))
+  IP_ENTRY *ip_hash_ptr;
+  int i;
+  int collision_count;
+  char result_buf[256];
+
+  if(out == NULL)
+    sendto_one(source_p,":%s NOTICE %s :*** hash stats for iphash",
+               me.name,client_p->name);
+  else
     {
-      SetExemptKline(source_p);
-      sendto_one(source_p,
-         ":%s NOTICE %s :*** You are exempt from K/D/G lines. congrats.",
-                 me.name,source_p->name);
+      (void)sprintf(result_buf,"*** hash stats for iphash\n");
+      (void)fbputs(result_buf,out);
     }
 
-  /* If this user is exempt from user limits set it F lined" */
-  if(IsConfExemptLimits(aconf))
+  for(i = 0; i < IP_HASH_SIZE ;i++)
     {
-      SetExemptLimits(source_p);
-      sendto_one(source_p,
-                 ":%s NOTICE %s :*** You are exempt from user limits. congrats.",
-                 me.name,source_p->name);
-    }
+      ip_hash_ptr = ip_hash_table[i];
 
-  /* If this user is exempt from idle time outs */
-  if(IsConfIdlelined(aconf))
-    {
-      SetIdlelined(source_p);
-      sendto_one(source_p,
-         ":%s NOTICE %s :*** You are exempt from idle limits. congrats.",
-                 me.name,source_p->name);
+      collision_count = 0;
+      while(ip_hash_ptr)
+        {
+          collision_count++;
+          ip_hash_ptr = ip_hash_ptr->next;
+        }
+      if(collision_count)
+        {
+          if(out == NULL)
+            {
+              sendto_one(source_p,":%s NOTICE %s :Entry %d (0x%X) Collisions %d",
+                         me.name,client_p->name,i,i,collision_count);
+            }
+          else
+            {
+              (void)sprintf(result_buf,"Entry %d (0x%X) Collisions %d\n",
+                            i,i,collision_count);
+              (void)fbputs(result_buf,out);
+            }
+        }
     }
 }
 
-
 /*
- * do_local_user
+ * detach_conf
  *
- * inputs	-
- * output	-
- * side effects -
+ * inputs	- pointer to client to detach
+ * 		- pointer to conf item to detach
+ * output	- 0 for success, -1 for failure
+ * side effects	- Disassociate configuration from the client.
+ *		  Also removes a class from the list if marked for deleting.
  */
-int do_local_user(char* nick, struct Client* client_p, struct Client* source_p,
-		  char* username, char *host, char *server, char *realname)
+int 
+detach_conf(struct Client* client_p,struct ConfItem* aconf)
 {
-  unsigned int oflags;
-  struct User* user;
-
-  assert(0 != source_p);
-  assert(source_p->username != username);
-
-  user = make_user(source_p);
+  dlink_node *ptr;
 
-  oflags = source_p->flags;
+  if(aconf == NULL)
+    return -1;
 
-  if (!IsUnknown(source_p))
+  for( ptr = client_p->localClient->confs.head; ptr; ptr = ptr->next )
     {
-      sendto_one(source_p, form_str(ERR_ALREADYREGISTRED), me.name, nick);
-      return 0;
-    }
-  source_p->flags |= FLAGS_INVISIBLE;
-
-  if (!(oflags & FLAGS_INVISIBLE) && IsInvisible(source_p))
-    Count.invisi++;
-  /*
-   * don't take the clients word for it, ever
-   *  strncpy_irc(user->host, host, HOSTLEN); 
-   */
-  user->server = me.name;
+      if (ptr->data == aconf)
+        {
+          if ((aconf) && (ClassPtr(aconf)))
+            {
+              if (aconf->status & CONF_CLIENT_MASK)
+                {
+                  if (ConfLinks(aconf) > 0)
+                    --ConfLinks(aconf);
+                }
+              if (ConfMaxLinks(aconf) == -1 && ConfLinks(aconf) == 0)
+                {
+                  free_class(ClassPtr(aconf));
+                  ClassPtr(aconf) = NULL;
+                }
+            }
+          if (aconf && !--aconf->clients && IsIllegal(aconf))
+            {
+              free_conf(aconf);
+            }
+	  dlinkDelete(ptr, &client_p->localClient->confs);
+          free_dlink_node(ptr);
+          return 0;
+        }
+    }
+  return -1;
+}
+
+/*
+ * is_attached
+ *
+ * inputs	- pointer to client to check
+ * 		- pointer to conf item to check
+ * output	- 1 if attached, 0 if not
+ * side effects	- 
+ */
+static int 
+is_attached(struct Client *client_p, struct ConfItem *aconf)
+{
+  dlink_node *ptr=NULL;
+
+  for (ptr = client_p->localClient->confs.head; ptr; ptr = ptr->next)
+    if (ptr->data == aconf)
+      break;
+  
+  return (ptr) ? 1 : 0;
+}
+
+/*
+ * attach_conf
+ * 
+ * inputs	- client pointer
+ * 		- conf pointer
+ * output	-
+ * side effects - Associate a specific configuration entry to a *local*
+ *                client (this is the one which used in accepting the
+ *                connection). Note, that this automatically changes the
+ *                attachment if there was an old one...
+ */
+int 
+attach_conf(struct Client *client_p,struct ConfItem *aconf)
+{
+  dlink_node *lp;
+
+  if (is_attached(client_p, aconf))
+    {
+      return 1;
+    }
+  if (IsIllegal(aconf))
+    {
+      return(NOT_AUTHORIZED);
+    }
+
+  if ( (aconf->status & CONF_OPERATOR) == 0 )
+    {
+      if ((aconf->status & CONF_CLIENT) &&
+          ConfLinks(aconf) >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0)
+        {
+          if (!IsConfExemptLimits(aconf))
+            {
+              return(I_LINE_FULL); 
+            }
+          else
+            {
+              send(client_p->fd,
+                   "NOTICE FLINE :I: line is full, but you have an >I: line!\n",
+                   56, 0);
+              SetExemptLimits(client_p);
+            }
+
+        }
+    }
+
+  lp = make_dlink_node();
+
+  dlinkAdd(aconf, lp, &client_p->localClient->confs);
+
+  aconf->clients++;
+  if (aconf->status & CONF_CLIENT_MASK)
+    ConfLinks(aconf)++;
+  return 0;
+}
+
+/*
+ * attach_confs - Attach all possible CONF lines to a client
+ * if the name passed matches that for the conf file (for non-C/N lines) 
+ * or is an exact match (C/N lines only).  The difference in behaviour 
+ * is to stop C:*::* and N:*::*.
+ * returns count of conf entries attached if successful, 0 if none are found
+ *
+ * NOTE: this will allow C:::* and N:::* because the match mask is the
+ * conf line and not the name
+ */
+int 
+attach_confs(struct Client* client_p, const char* name, int statmask)
+{
+  struct ConfItem* tmp;
+  int              conf_counter = 0;
+  
+  for (tmp = ConfigItemList; tmp; tmp = tmp->next)
+    {
+      if ((tmp->status & statmask) && !IsIllegal(tmp) &&
+          tmp->name && match(tmp->name, name))
+        {
+          if (-1 < attach_conf(client_p, tmp))
+            ++conf_counter;
+        }
+      else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
+               tmp->name && !irccmp(tmp->name, name))
+        {
+          if (-1 < attach_conf(client_p, tmp))
+            ++conf_counter;
+        }
+    }
+  return conf_counter;
+}
+
+/*
+ * attach_connect_block
+ *
+ * inputs	- pointer to server to attach
+ * 		- name of server
+ *		- hostname of server
+ * output	- true (1) if both are found, otherwise return false (0)
+ * side effects - find connect block and attach them to connecting client
+ */
+int 
+attach_connect_block(struct Client *client_p,
+		     const char* name,
+		     const char* host)
+{
+  struct ConfItem* ptr;
+
+  assert(client_p != NULL);
+  assert(host != NULL);
+
+  for (ptr = ConfigItemList; ptr; ptr = ptr->next)
+    {
+     if (IsIllegal(ptr))
+       continue;
+     if (ptr->status != CONF_SERVER)
+       continue;
+     if ((match(name, ptr->name) == 0) || (match(ptr->host, host) == 0))
+       continue;
+     attach_conf(client_p, ptr);
+     return -1;
+    }
+  return 0;
+}
+
+/*
+ * find_conf_exact
+ *
+ * inputs	- pointer to name to find
+ *		- pointer to username to find
+ *		- pointer to host to find
+ *		- int mask of type of conf to find
+ * output	- NULL or pointer to conf found
+ * side effects	- find a conf entry which matches the hostname
+ *		  and has the same name.
+ */
+struct ConfItem* 
+find_conf_exact(const char* name, const char* user, 
+		const char* host, int statmask)
+{
+  struct ConfItem *tmp;
+
+  for (tmp = ConfigItemList; tmp; tmp = tmp->next)
+    {
+      if (!(tmp->status & statmask) || !tmp->name || !tmp->host ||
+          irccmp(tmp->name, name))
+        continue;
+      /*
+      ** Accept if the *real* hostname (usually sockethost)
+      ** socket host) matches *either* host or name field
+      ** of the configuration.
+      */
+      if (!match(tmp->host, host) || !match(tmp->user,user)
+          || irccmp(tmp->name, name) )
+        continue;
+      if (tmp->status & CONF_OPERATOR)
+        {
+          if (tmp->clients < ConfMaxLinks(tmp))
+            return tmp;
+          else
+            continue;
+        }
+      else
+        return tmp;
+    }
+  return NULL;
+}
+
+/*
+ * find_conf_name
+ *
+ * inputs	- pointer to conf link list to search
+ *		- pointer to name to find
+ *		- int mask of type of conf to find
+ * output	- NULL or pointer to conf found
+ * side effects	- find a conf entry which matches the name
+ *		  and has the given mask.
+ */
+struct ConfItem* 
+find_conf_name(dlink_list *list, const char* name, int statmask)
+{
+  dlink_node *ptr;
+  struct ConfItem* aconf;
+  
+  for (ptr = list->head; ptr; ptr = ptr->next)
+    {
+      aconf = ptr->data;
+      if ((aconf->status & statmask) && aconf->name && 
+          (!irccmp(aconf->name, name) || match(aconf->name, name)))
+        return aconf;
+    }
+  return NULL;
+}
 
-  strncpy_irc(source_p->info, realname, REALLEN);
+/*
+ * find_conf_host
+ *
+ * inputs	- pointer to conf link list to search
+ *		- pointer to host to find
+ *		- int mask of type of conf to find
+ * output	- NULL or pointer to conf found
+ * side effects	- find a conf entry which matches the name
+ *		  and has the given mask.
+ */
+struct ConfItem* 
+find_conf_host(dlink_list *list, const char* host, int statmask)
+{
+  dlink_node *ptr;
+  struct ConfItem *aconf;
+  
+  for (ptr = list->head; ptr; ptr = ptr->next)
+    {
+      aconf = ptr->data;
+      if (aconf->status & statmask && aconf->host && match(aconf->host, host))
+        return aconf;
+    }
+  return NULL;
+}
+
+/*
+ * find_conf_ip
+ *
+ * inputs	- pointer to conf link list to search
+ *		- pointer to ip to match on
+ *		- pointer to username to match on
+ *		- int mask of type of conf to find
+ * output	- NULL or pointer to conf found
+ * side effects	- find a conf entry which matches the ip/name
+ *		  and has the given mask.
+ *
+ */
+struct ConfItem *
+find_conf_ip(dlink_list *list, char *ip, char *user, int statmask)
+{
+  dlink_node *ptr;
+  struct ConfItem *aconf;
   
-  if (source_p->name[0])
-    /* NICK already received, now I have USER... */
-    return register_local_user(client_p, source_p, source_p->name, username);
+  for (ptr = list->head; ptr; ptr = ptr->next)
+    {
+      aconf = ptr->data;
+
+      if (!(aconf->status & statmask))
+        continue;
+
+      if (!match(aconf->user, user))
+        {
+          continue;
+        }
+/* XXX: broken for IPv6 */
+      if (!memcmp((void *)&IN_ADDR(aconf->ipnum), (void *)ip, sizeof(struct in_addr)))
+        return aconf;
+    }
+  return ((struct ConfItem *)NULL);
+}
+
+/*
+ * find_conf_by_name
+ *
+ * inputs	- pointer to name to match on
+ *		- int mask of type of conf to find
+ * output	- NULL or pointer to conf found
+ * side effects	- find a conf entry which matches the name
+ *		  and has the given mask.
+ *
+ */
+struct ConfItem* 
+find_conf_by_name(const char* name, int status)
+{
+  struct ConfItem* conf;
+  assert(name != NULL);
+ 
+  for (conf = ConfigItemList; conf; conf = conf->next)
+    {
+      if (conf->status == status && conf->name &&
+          match(name, conf->name))
+#if 0
+          (match(name, conf->name) || match(conf->name, name)))
+#endif
+        return conf;
+    }
+  return NULL;
+}
+
+/*
+ * find_conf_by_host
+ *
+ * inputs	- pointer to hostname to match on
+ *		- int mask of type of conf to find
+ * output	- NULL or pointer to conf found
+ * side effects	- find a conf entry which matches the host
+ *		  and has the given mask.
+ *
+ */
+struct ConfItem* 
+find_conf_by_host(const char* host, int status)
+{
+  struct ConfItem* conf;
+  assert(host != NULL);
+ 
+  for (conf = ConfigItemList; conf; conf = conf->next)
+    {
+      if (conf->status == status && conf->host &&
+          match(host, conf->host))
+#if 0
+          (match(host, conf->host) || match(conf->host, host)))
+#endif
+        return conf;
+    }
+  return NULL;
+}
+
+/*
+ * find_conf_entry
+ *
+ * inputs	- pointer to conf item to search on
+ *		- int mask of type of conf to find
+ * output	- NULL or pointer to conf found
+ * side effects - looks for a match on all given fields.
+ */
+struct ConfItem *
+find_conf_entry(struct ConfItem *aconf, int mask)
+{
+  struct ConfItem *bconf;
+
+  for (bconf = ConfigItemList, mask &= ~CONF_ILLEGAL; bconf; 
+       bconf = bconf->next)
+    {
+      if (!(bconf->status & mask) || (bconf->port != aconf->port))
+        continue;
+      
+      if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) ||
+          (BadPtr(aconf->host) && !BadPtr(bconf->host)))
+        continue;
+
+      if (!BadPtr(bconf->host) && irccmp(bconf->host, aconf->host))
+        continue;
+
+      if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
+          (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
+        continue;
+
+      if (!BadPtr(bconf->passwd) &&
+          irccmp(bconf->passwd, aconf->passwd))
+      continue;
+
+      if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
+          (BadPtr(aconf->name) && !BadPtr(bconf->name)))
+        continue;
+
+      if (!BadPtr(bconf->name) && irccmp(bconf->name, aconf->name))
+        continue;
+      break;
+    }
+  return bconf;
+}
+
+/*
+ * find_x_conf
+ *
+ * inputs       - pointer to char string to find
+ * output       - NULL or pointer to found struct ConfItem
+ * side effects - looks for a match on name field
+ */
+struct ConfItem *
+find_x_conf(char *to_find)
+{
+  struct ConfItem *aconf;
+
+  for (aconf = x_conf; aconf; aconf = aconf->next)
+    {
+      if (BadPtr(aconf->name))
+          continue;
+
+      if(match(aconf->name,to_find))
+        return(aconf);
+
+    }
+  return(NULL);
+}
+
+/*
+ * find_u_conf
+ *
+ * inputs       - pointer to servername
+ *		- pointer to user of oper
+ *		- pointer to host of oper
+ * output       - NULL or pointer to found struct ConfItem
+ * side effects - looks for a matches on all fields
+ */
+int 
+find_u_conf(char *server,char *user,char *host)
+{
+  struct ConfItem *aconf;
+
+  for (aconf = u_conf; aconf; aconf = aconf->next)
+    {
+      if (BadPtr(aconf->name))
+          continue;
+
+      if(match(aconf->name,server))
+	{
+	  if (BadPtr(aconf->user) || BadPtr(aconf->host))
+	    return YES;
+	  if(match(aconf->user,user) && match(aconf->host,host))
+	    return YES;
+
+	}
+    }
+  return NO;
+}
+
+
+/*
+ * clear_special_conf
+ * 
+ * inputs       - pointer to pointer of root of special conf link list
+ * output       - none
+ * side effects - clears given special conf lines
+ */
+static void 
+clear_special_conf(struct ConfItem **this_conf)
+{
+  struct ConfItem *aconf;
+  struct ConfItem *next_aconf;
+
+  for (aconf = *this_conf; aconf; aconf = next_aconf)
+    {
+      next_aconf = aconf->next;
+      free_conf(aconf);
+    }
+  *this_conf = (struct ConfItem *)NULL;
+  return;
+}
+
+/*
+ * rehash
+ *
+ * Actual REHASH service routine. Called with sig == 0 if it has been called
+ * as a result of an operator issuing this command, else assume it has been
+ * called as a result of the server receiving a HUP signal.
+ */
+int rehash(int sig)
+{
+  if (sig)
+    {
+      sendto_realops_flags(FLAGS_ALL, L_ALL,
+			   "Got signal SIGHUP, reloading ircd conf. file");
+    }
+
+  restart_resolver();
+  /* don't close listeners until we know we can go ahead with the rehash */
+  read_conf_files(NO);
+
+  if (ServerInfo.description != NULL)
+    {
+      strncpy_irc(me.info, ServerInfo.description, REALLEN);
+    }
+
+  flush_deleted_I_P();
+  check_klines();
+  return 0;
+}
+
+/*
+ * set_default_conf()
+ *
+ * inputs	- NONE
+ * output	- NONE
+ * side effects	- Set default values here.
+ *		  This is called **PRIOR** to parsing the
+ *		  configuration file.  If you want to do some validation
+ *		  of values later, put them in validate_conf().
+ */
+
+#define YES     1
+#define NO      0
+#define UNSET  -1
+
+static void 
+set_default_conf(void)
+{
+  class0 = find_class("default");       /* which one is the default class ? */
+
+#ifdef HAVE_LIBCRYPTO
+  ServerInfo.rsa_private_key = NULL;
+  ServerInfo.rsa_private_key_file = NULL;
+#endif
+
+  /* ServerInfo.name is not rehashable */
+  /* ServerInfo.name = ServerInfo.name; */
+  ServerInfo.description = NULL;
+  DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT);
+  DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT);
+
+  memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip));
+  ServerInfo.specific_ipv4_vhost = 0;
+  memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
+  ServerInfo.specific_ipv6_vhost = 0;
+
+  ServerInfo.max_clients = MAX_CLIENTS;  /* XXX - these don't seem to */
+  ServerInfo.max_buffer = MAX_BUFFER;    /*       actually do anything! */
+  /* Don't reset hub, as that will break lazylinks */
+  /* ServerInfo.hub = NO; */
+  ServerInfo.dns_host.sin_addr.s_addr = 0;
+  ServerInfo.dns_host.sin_port = 0;
+  AdminInfo.name = NULL;
+  AdminInfo.email = NULL;
+  AdminInfo.description = NULL;
+
+  set_log_level(L_NOTICE);
+
+  ConfigFileEntry.failed_oper_notice = YES;
+  ConfigFileEntry.anti_nick_flood = NO;
+  ConfigFileEntry.max_nick_time = 20;
+  ConfigFileEntry.max_nick_changes = 5;
+  ConfigFileEntry.max_accept = 20;
+  ConfigFileEntry.anti_spam_exit_message_time = 0;
+  ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
+  ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
+  ConfigFileEntry.kline_with_reason = YES;
+  ConfigFileEntry.client_exit = YES;
+  ConfigFileEntry.kline_with_connection_closed = NO;
+  ConfigFileEntry.warn_no_nline = YES;
+  ConfigFileEntry.non_redundant_klines = YES;
+  ConfigFileEntry.stats_o_oper_only = NO;
+  ConfigFileEntry.stats_k_oper_only = 1; /* masked */
+  ConfigFileEntry.stats_i_oper_only = 1; /* masked */
+  ConfigFileEntry.stats_P_oper_only = NO;
+  ConfigFileEntry.pace_wait = 10;
+  ConfigFileEntry.caller_id_wait = 60;
+  ConfigFileEntry.whois_wait = 0;
+  ConfigFileEntry.short_motd = NO;
+  ConfigFileEntry.no_oper_flood = NO;
+  ConfigFileEntry.fname_userlog[0] = '\0';
+  ConfigFileEntry.fname_foperlog[0] = '\0';
+  ConfigFileEntry.fname_operlog[0] = '\0';
+  ConfigFileEntry.glines = NO;
+  ConfigFileEntry.use_egd = NO;
+  /* don't reset msglocale setting -- we'd overwrite then env string */
+  ConfigFileEntry.gline_time = 12 * 3600;
+  ConfigFileEntry.idletime = 0;
+  ConfigFileEntry.dots_in_ident = 0;
+  ConfigFileEntry.maximum_links = MAXIMUM_LINKS_DEFAULT;
+  ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
+  DupString(ConfigFileEntry.servlink_path, SLPATH);
+  ConfigFileEntry.egdpool_path = NULL;
+  
+#ifdef HAVE_LIBCRYPTO
+  /* jdc -- This is our default value for a cipher.  According to the
+   *        CRYPTLINK document (doc/cryptlink.txt), BF/128 must be supported
+   *        under all circumstances if cryptlinks are enabled.  So,
+   *        this will be our default.
+   *
+   *        NOTE: I apologise for the hard-coded value of "1" (BF/128).
+   *              This should be moved into a find_cipher() routine.
+   */
+  ConfigFileEntry.default_cipher_preference = &CipherTable[1];
+#endif
+#ifdef HAVE_LIBZ
+  ConfigFileEntry.compression_level = 0;
+#endif
+
+  ConfigFileEntry.oper_umodes = FLAGS_LOCOPS | FLAGS_SERVNOTICE |
+    FLAGS_OPERWALL | FLAGS_WALLOP;
+  ConfigFileEntry.oper_only_umodes = FLAGS_DEBUG;
+  ConfigFileEntry.throttle_time = 10;
+
+  ConfigChannel.vchans_oper_only = NO;
+
+  ConfigChannel.use_except  = YES;
+  /* ConfigChannel.use_halfops = YES; */ /* Don't set, as this can't
+                                            be changed at runtime */
+  ConfigChannel.use_invex   = NO;
+  ConfigChannel.use_knock   = YES;
+  ConfigChannel.use_vchans = NO;
+  ConfigChannel.knock_delay = 300;
+  ConfigChannel.knock_delay_channel = 60;
+  ConfigChannel.max_chans_per_user = 15;
+  ConfigChannel.maxbans = 25;
+
+  /* 60 * 30 = 1800 = 30 minutes */
+  ConfigChannel.persist_time = 1800;
+
+  ConfigServerHide.flatten_links = 0;
+  ConfigServerHide.hide_servers = 0;
+  ConfigServerHide.disable_remote = 0;
+  ConfigServerHide.links_delay = 300;
+  ConfigServerHide.hidden = 0;
+  ConfigServerHide.allow_hidden = 1;
+
+  ConfigFileEntry.min_nonwildcard = 4;
+  ConfigFileEntry.default_floodcount = 8;
+  ConfigFileEntry.client_flood = CLIENT_FLOOD_DEFAULT;
+}
+#undef YES
+#undef NO
+
+/*
+ * read_conf() 
+ *
+ *
+ * inputs       - file descriptor pointing to config file to use
+ * output       - None
+ * side effects	- Read configuration file.
+ */
+static void 
+read_conf(FBFILE* file)
+{
+  scount = lineno = 0;
+
+  set_default_conf(); /* Set default values prior to conf parsing */
+  yyparse();          /* Load the values from the conf */
+  validate_conf();    /* Check to make sure some values are still okay. */
+                      /* Some global values are also loaded here. */
+  check_class();      /* Make sure classes are valid */
+}
+
+static void 
+validate_conf(void)
+{
+  if(ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN)
+    ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
+
+  if(ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN)
+    ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
+
+  if(ConfigFileEntry.servlink_path == NULL)
+    DupString(ConfigFileEntry.servlink_path, SLPATH);
+
+  if(ServerInfo.network_name == NULL)
+    DupString(ServerInfo.network_name,NETWORK_NAME_DEFAULT);
+
+  if(ServerInfo.network_desc == NULL)
+    DupString(ServerInfo.network_desc,NETWORK_DESC_DEFAULT);
+
+  if ((ConfigFileEntry.client_flood < CLIENT_FLOOD_MIN) ||
+      (ConfigFileEntry.client_flood > CLIENT_FLOOD_MAX))
+     ConfigFileEntry.client_flood = CLIENT_FLOOD_MAX;
+
+  /* Hasn't been set yet, so set it now */
+  if(ConfigChannel.use_halfops == -1)
+    ConfigChannel.use_halfops = 1;
+  
+  GlobalSetOptions.idletime = (ConfigFileEntry.idletime * 60);
+}
+
+/*
+ * conf_add_conf
+ * Inputs	- ConfItem
+ * Output	- none
+ * Side effects	- add given conf to link list
+ */
+void 
+conf_add_conf(struct ConfItem *aconf)
+{
+  (void)collapse(aconf->host);
+  (void)collapse(aconf->user);
+  Debug((DEBUG_NOTICE,
+	 "Read Init: (%d) (%s) (%s) (%s) (%d) (%d)",
+	 aconf->status, 
+	 aconf->host ? aconf->host : "<NULL>",
+	 aconf->passwd ? aconf->passwd : "<NULL>",
+	 aconf->user ? aconf->user : "<NULL>",
+	 aconf->port,
+	 aconf->c_class ? ConfClassType(aconf): 0 ));
+
+  aconf->next = ConfigItemList;
+  ConfigItemList = aconf;
+}
+
+/*
+ * SplitUserHost
+ *
+ * inputs	- struct ConfItem pointer
+ * output	- return 1/0 true false or -1 for error
+ * side effects - splits user@host found in a name field of conf given
+ *		  stuff the user into ->user and the host into ->host
+ */
+static int 
+SplitUserHost(struct ConfItem *aconf)
+{
+  char *p;
+  char *new_user;
+  char *new_host;
+
+  if ( (p = strchr(aconf->host, '@')) )
+    {
+      *p = '\0';
+      DupString(new_user, aconf->host);
+      MyFree(aconf->user);
+      aconf->user = new_user;
+      p++;
+      DupString(new_host,p);
+      MyFree(aconf->host);
+      aconf->host = new_host;
+    }
+  else
+    {
+      DupString(aconf->user, "*");
+    }
+  return(1);
+}
+
+/*
+ * lookup_confhost - start DNS lookups of all hostnames in the conf
+ * line and convert an IP addresses in a.b.c.d number for to IP#s.
+ *
+ */
+static void 
+lookup_confhost(struct ConfItem* aconf)
+{
+  if (BadPtr(aconf->host) || BadPtr(aconf->name))
+    {
+      ilog(L_ERROR, "Host/server name error: (%s) (%s)",
+          aconf->host, aconf->name);
+      return;
+    }
+
+  if (strchr(aconf->host, '*') || strchr(aconf->host, '?'))
+    return;
+  /*
+  ** Do name lookup now on hostnames given and store the
+  ** ip numbers in conf structure.
+  */
+  if (inetpton(DEF_FAM, aconf->host, &IN_ADDR(aconf->ipnum)) <= 0)
+    {
+      conf_dns_lookup(aconf);
+    }
+}
+
+/*
+ * conf_connect_allowed (untested)
+ */
+int 
+conf_connect_allowed(struct irc_inaddr *addr, int aftype)
+{
+#ifdef PACE_CONNECT
+  IP_ENTRY *ip_found;
+#endif
+  struct ConfItem *aconf = find_dline(addr, aftype);
+ 
+  /* DLINE exempt also gets you out of static limits/pacing... */
+  if (aconf && (aconf->status & CONF_EXEMPTDLINE))
+    return 0;
+ 
+  if (aconf)
+    return BANNED_CLIENT;
+
+#ifdef PACE_CONNECT
+  ip_found = find_or_add_ip(addr);
+  if ((CurrentTime - ip_found->last_attempt) <
+      ConfigFileEntry.throttle_time)
+    {
+      ip_found->last_attempt = CurrentTime;
+      ip_found->count--;
+      return TOO_FAST;
+    }
+  ip_found->last_attempt = CurrentTime;
+#endif
+  return 0;
+}
+
+/*
+ * find_kill
+ *
+ * inputs	- pointer to client structure
+ * output	- pointer to struct ConfItem if found
+ * side effects	- See if this user is klined already,
+ *		  and if so, return struct ConfItem pointer
+ */
+struct ConfItem *
+find_kill(struct Client* client_p)
+{
+  struct ConfItem *aconf;
+  assert(client_p != NULL);
+  aconf = find_address_conf(client_p->host, client_p->username,
+			    &client_p->localClient->ip,
+			    client_p->localClient->aftype);
+  if (aconf == NULL)
+    return aconf;
+  if(aconf->status & CONF_KILL)
+    return aconf;
+  return NULL;
+}
+
+/* add_temp_kline
+ *
+ * inputs        - pointer to struct ConfItem
+ * output        - none
+ * Side effects  - links in given struct ConfItem into 
+ *                 temporary kline link list
+ */
+void
+add_temp_kline(struct ConfItem *aconf)
+{
+  dlink_node *kill_node;
+  kill_node = make_dlink_node();
+  dlinkAdd(aconf, kill_node, &temporary_klines);
+  aconf->flags |= CONF_FLAGS_TEMPORARY;
+  add_conf_by_address(aconf->host, CONF_KILL, aconf->user, aconf);
+}
+
+/*
+ * cleanup_tklines
+ *
+ * inputs       - NONE
+ * output       - NONE
+ * side effects - call function to expire tklines
+ *                This is an event started off in ircd.c
+ */
+void
+cleanup_tklines(void *notused)
+{
+  expire_tklines(&temporary_klines);
+}
+
+/*
+ * expire_tklines
+ *
+ * inputs       - tkline list pointer
+ * output       - NONE
+ * side effects - expire tklines
+ */
+static void
+expire_tklines(dlink_list *tklist)
+{
+  dlink_node *kill_node;
+  dlink_node *next_node;
+  struct ConfItem *kill_ptr;
+  for (kill_node = tklist->head; kill_node; kill_node = next_node)
+    {
+      kill_ptr = kill_node->data;
+      next_node = kill_node->next;
+
+      if (kill_ptr->hold <= CurrentTime)
+	{
+	  delete_one_address_conf(kill_ptr->host, kill_ptr);
+	  dlinkDelete(kill_node, tklist);
+	  free_dlink_node(kill_node);
+	}
+    }
+}
+
+/*
+ * oper_privs_as_string
+ *
+ * inputs        - pointer to client_p or NULL
+ * output        - pointer to static string showing oper privs
+ * side effects  -
+ * return as string, the oper privs as derived from port
+ * also, set the oper privs if given client_p non NULL
+ */
+
+char *
+oper_privs_as_string(struct Client *client_p,int port)
+{
+  static char privs_out[16];
+  char *privs_ptr;
+
+  privs_ptr = privs_out;
+  *privs_ptr = '\0';
+
+  if(port & CONF_OPER_GLINE)
+    {
+      if(client_p)
+        SetOperGline(client_p);
+      *privs_ptr++ = 'G';
+    }
+  else
+    *privs_ptr++ = 'g';
+
+  if(port & CONF_OPER_K)
+    {
+      if(client_p)
+        SetOperK(client_p);
+      *privs_ptr++ = 'K';
+    }
+  else
+    *privs_ptr++ = 'k';
+
+  if(port & CONF_OPER_N)
+    {
+      if(client_p)
+        SetOperN(client_p);
+      *privs_ptr++ = 'N';
+    }
+
+  if(port & CONF_OPER_GLOBAL_KILL)
+    {
+      if(client_p)
+        SetOperGlobalKill(client_p);
+      *privs_ptr++ = 'O';
+    }
+  else
+    *privs_ptr++ = 'o';
+
+  if(port & CONF_OPER_REMOTE)
+    {
+      if(client_p)
+        SetOperRemote(client_p);
+      *privs_ptr++ = 'R';
+    }
+  else
+    *privs_ptr++ = 'r';
+  
+  if(port & CONF_OPER_UNKLINE)
+    {
+      if(client_p)
+        SetOperUnkline(client_p);
+      *privs_ptr++ = 'U';
+    }
+  else
+    *privs_ptr++ = 'u';
+
+  if(port & CONF_OPER_REHASH)
+    {
+      if(client_p)
+        SetOperRehash(client_p);
+      *privs_ptr++ = 'H';
+    }
+  else
+    *privs_ptr++ = 'h';
+
+  if(port & CONF_OPER_DIE)
+    {
+      if(client_p)
+        SetOperDie(client_p);
+      *privs_ptr++ = 'D';
+    }
   else
+    *privs_ptr++ = 'd';
+
+  if (port & CONF_OPER_ADMIN)
     {
-      if (!IsGotId(source_p)) 
-        {
-          /*
-           * save the username in the client
-           */
-          strncpy_irc(source_p->username, username, USERLEN);
-        }
+      if (client_p)
+	SetOperAdmin(client_p);
+      *privs_ptr++ = 'A';
     }
-  return 0;
+  else
+    *privs_ptr++ = 'a';
+  
+  *privs_ptr = '\0';
+
+  return(privs_out);
 }
 
-/*
- * do_remote_user
+
+/* oper_flags_as_string
  *
- * inputs	-
- * output	-
+ * inputs        - oper flags as bit mask
+ * output        - oper flags as as string
  * side effects -
+ *
  */
-int do_remote_user(char* nick, struct Client* client_p, struct Client* source_p,
-		   char* username, char *host, char *server, char *realname,
-		   char *id)
+char *
+oper_flags_as_string(int flags)
 {
-  unsigned int oflags;
-  struct User* user;
+  /* This MUST be extended if we add any more modes... -Hwy */
+  static char flags_out[18];
+  char *flags_ptr;
+
+  flags_ptr = flags_out;
+  *flags_ptr = '\0';
+
+  if(flags & FLAGS_INVISIBLE)
+    *flags_ptr++ = 'i';
+  if(flags & FLAGS_WALLOP)
+    *flags_ptr++ = 'w';
+  if(flags & FLAGS_SERVNOTICE)
+    *flags_ptr++ = 's';
+  if(flags & FLAGS_CCONN)
+    *flags_ptr++ = 'c';
+  if(flags & FLAGS_REJ)
+    *flags_ptr++ = 'r';
+  if(flags & FLAGS_SKILL)
+    *flags_ptr++ = 'k';
+  if(flags & FLAGS_FULL)
+    *flags_ptr++ = 'f';
+  if(flags & FLAGS_SPY)
+    *flags_ptr++ = 'y';
+  if(flags & FLAGS_DEBUG)
+    *flags_ptr++ = 'd';
+  if(flags & FLAGS_NCHANGE)
+    *flags_ptr++ = 'n';
+  if(flags & FLAGS_ADMIN)
+    *flags_ptr++ = 'a';
+  if(flags & FLAGS_EXTERNAL)
+    *flags_ptr++ = 'x';
+  if(flags & FLAGS_UNAUTH)
+    *flags_ptr++ = 'u';
+  if(flags & FLAGS_BOTS)
+    *flags_ptr++ = 'b';
+  if(flags & FLAGS_LOCOPS)
+    *flags_ptr++ = 'l';
+  if(flags & FLAGS_CALLERID)
+    *flags_ptr++ = 'g';
+  *flags_ptr = '\0';
 
-  assert(0 != source_p);
-  assert(source_p->username != username);
+  return(flags_out);
+}
 
-  user = make_user(source_p);
 
-  oflags = source_p->flags;
+/* const char* get_oper_name(struct Client *client_p)
+ * Input: A client to find the active oper{} name for.
+ * Output: The nick!user@host{oper} of the oper.
+ *         "oper" is server name for remote opers
+ * Side effects: None.
+ */
+char*
+get_oper_name(struct Client *client_p)
+{
+  dlink_node *cnode;
 
-  /*
-   * coming from another server, take the servers word for it
-   */
-  user->server = find_or_add(server);
-  strncpy_irc(source_p->host, host, HOSTLEN); 
-  strncpy_irc(source_p->info, realname, REALLEN);
-  if (id)
-	  strcpy(source_p->user->id, id);
-  
-#if 0
-  /* XXX dont do this (talk to is-) */
-  /* if it has no ID, set the ID to the nick just in case */
-  if (!id)
-	  strcpy(source_p->user->id, nick);
-#endif
+  /* +5 for !,@,{,} and null */
+  static char buffer[NICKLEN+USERLEN+HOSTLEN+HOSTLEN+5];
 
-  return register_remote_user(client_p, source_p, source_p->name, username);
+  if (MyConnect(client_p))
+    {
+      for (cnode=client_p->localClient->confs.head; cnode; cnode=cnode->next)
+	if (((struct ConfItem*)cnode->data)->status & CONF_OPERATOR)
+	  {
+	    ircsprintf(buffer, "%s!%s@%s{%s}", client_p->name,
+		       client_p->username, client_p->host,
+		       ((struct ConfItem*)cnode->data)->name);
+	    return buffer;
+	  }
+      /* Probably should assert here for now. If there is an oper out there 
+       * with no oper{} conf attached, it would be good for us to know...
+       */
+      assert(0); /* Oper without oper conf! */
+    }
+  ircsprintf(buffer, "%s!%s@%s{%s}", client_p->name,
+	     client_p->username, client_p->host, client_p->servptr->name);
+  return buffer;
 }
 
 /*
- * user_mode - set get current users mode
+ * get_printable_conf
+ *
+ * inputs        - struct ConfItem
+ *
+ * output         - name 
+ *                - host
+ *                - pass
+ *                - user
+ *                - port
  *
- * m_umode() added 15/10/91 By Darren Reed.
- * parv[0] - sender
- * parv[1] - username to change mode for
- * parv[2] - modes to change
+ * side effects        -
+ * Examine the struct struct ConfItem, setting the values
+ * of name, host, pass, user to values either
+ * in aconf, or "<NULL>" port is set to aconf->port in all cases.
  */
-int user_mode(struct Client *client_p, struct Client *source_p, int parc, char *parv[])
+
+void 
+get_printable_conf(struct ConfItem *aconf, char **name, char **host,
+                           char **pass, char **user,int *port,char **classname)
 {
-  int   flag;
-  int   i;
-  char  **p, *m;
-  struct Client *target_p;
-  int   what, setflags;
-  int   badflag = NO;		/* Only send one bad flag notice */
-  char  buf[BUFSIZE];
-  dlink_node *ptr;
-  struct ConfItem *aconf;
+  static  char        null[] = "<NULL>";
+  static  char        zero[] = "default";
 
-  what = MODE_ADD;
+  *name = BadPtr(aconf->name) ? null : aconf->name;
+  *host = BadPtr(aconf->host) ? null : aconf->host;
+  *pass = BadPtr(aconf->passwd) ? null : aconf->passwd;
+  *user = BadPtr(aconf->user) ? null : aconf->user;
+  *classname = BadPtr(aconf->className) ? zero : aconf->className;
+  *port = (int)aconf->port;
+}
 
-  if (parc < 2)
-    {
-      sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
-                 me.name, parv[0], "MODE");
-      return 0;
-    }
+/*
+ * read_conf_files
+ *
+ * inputs       - cold start YES or NO
+ * output       - none
+ * side effects - read all conf files needed, ircd.conf kline.conf etc.
+ */
+void 
+read_conf_files(int cold)
+{
+  FBFILE *file;
+  const char *filename, *kfilename, *dfilename; /* kline or conf filename */
+
+  conf_fbfile_in = NULL;
+
+  filename = get_conf_name(CONF_TYPE);
 
-  if ((target_p = find_person(parv[1])) == NULL)
+  if ((conf_fbfile_in = fbopen(filename,"r")) == NULL)
     {
-      if (MyConnect(source_p))
-        sendto_one(source_p, form_str(ERR_NOSUCHCHANNEL),
-                   me.name, parv[0], parv[1]);
-      return 0;
+      if(cold)
+        {
+          ilog(L_CRIT, "Failed in reading configuration file %s", filename);
+          exit(-1);
+        }
+      else
+        {
+          sendto_realops_flags(FLAGS_ALL, L_ALL,
+			       "Can't open file '%s' - aborting rehash!",
+			       filename );
+          return;
+        }
     }
 
-  /* Dont know why these were commented out..
-   * put them back using new sendto() funcs
-   */
+  if (cold)
+  {
+    /* set to 'undefined' */
+    ConfigChannel.use_halfops = -1;
+  }
+  else
+  {
+    clear_out_old_conf();
+  }
+
+  read_conf(conf_fbfile_in);
+  fbclose(conf_fbfile_in);
 
-  if (IsServer(source_p))
+  kfilename = get_conf_name(KLINE_TYPE);
+  if (irccmp(filename, kfilename))
     {
-       sendto_realops_flags(FLAGS_ALL, L_ADMIN, "*** Mode for User %s from %s",
-                            parv[1], source_p->name);
-       return 0;
+      if((file = fbopen(kfilename,"r")) == NULL)
+        {
+	  if (cold)
+	    ilog(L_ERROR, "Failed reading kline file %s", filename);
+	  else
+	    sendto_realops_flags(FLAGS_ALL, L_ALL,
+				 "Can't open %s file klines could be missing!",
+				 kfilename);
+	}
+      else
+	{
+	  parse_k_file(file);
+	  fbclose(file);
+	}
     }
 
-  if (source_p != target_p || target_p->from != source_p->from)
+  dfilename = get_conf_name(DLINE_TYPE);
+  if (irccmp(filename, dfilename) && irccmp(kfilename, dfilename))
     {
-       sendto_one(source_p, form_str(ERR_USERSDONTMATCH), me.name, parv[0]);
-       return 0;
+      if ((file = fbopen(dfilename,"r")) == NULL)
+	{
+	  if(cold)
+	    ilog(L_ERROR, "Failed reading dline file %s", dfilename);
+	  else
+	    sendto_realops_flags(FLAGS_ALL, L_ALL,
+				 "Can't open %s file dlines could be missing!",
+				 dfilename);
+	}
+      else
+	{
+	  parse_d_file(file);
+	  fbclose(file);
+	}
     }
+}
 
+/*
+ * clear_out_old_conf
+ *
+ * inputs       - none
+ * output       - none
+ * side effects - Clear out the old configuration
+ */
+static 
+void clear_out_old_conf(void)
+{
+  struct ConfItem **tmp = &ConfigItemList;
+  struct ConfItem *tmp2;
+  struct Class    *cltmp;
 
-  if (parc < 3)
+  /*
+   * We only need to free anything allocated by yyparse() here.
+   * Reseting structs, etc, is taken care of by set_default_conf().
+   */
+  while ((tmp2 = *tmp))
+  {
+    if (tmp2->clients)
+    {
+      /*
+       ** Configuration entry is still in use by some
+       ** local clients, cannot delete it--mark it so
+       ** that it will be deleted when the last client
+       ** exits...
+       */
+      if (!(tmp2->status & CONF_CLIENT))
+      {
+        *tmp = tmp2->next;
+        tmp2->next = NULL;
+      }
+      else
+        tmp = &tmp2->next;
+      tmp2->status |= CONF_ILLEGAL;
+    }
+    else
     {
-      m = buf;
-      *m++ = '+';
-
-      for (i = 0; user_modes[i].letter && (m - buf < BUFSIZE - 4);i++)
-        if (source_p->umodes & user_modes[i].mode)
-          *m++ = user_modes[i].letter;
-      *m = '\0';
-      sendto_one(source_p, form_str(RPL_UMODEIS), me.name, parv[0], buf);
-      return 0;
+      *tmp = tmp2->next;
+      free_conf(tmp2);
     }
+  }
 
-  /* find flags already set for user */
-  setflags = source_p->umodes;
-  
   /*
-   * parse mode change string(s)
+   * don't delete the class table, rather mark all entries
+   * for deletion. The table is cleaned up by check_class. - avalon
    */
-  for (p = &parv[2]; p && *p; p++ )
-    for (m = *p; *m; m++)
-      switch(*m)
-        {
-        case '+' :
-          what = MODE_ADD;
-          break;
-        case '-' :
-          what = MODE_DEL;
-          break;        
-
-        case 'o' :
-          if(what == MODE_ADD)
-            {
-              if(IsServer(client_p) && !IsOper(source_p))
-                {
-                  ++Count.oper;
-                  SetOper(source_p);
-                }
-            }
-          else
-            {
-	      /* Only decrement the oper counts if an oper to begin with
-               * found by Pat Szuta, Perly , perly@xnet.com 
-               */
-
-              if(!IsOper(source_p))
-                break;
-
-              ClearOper(source_p);
-	      source_p->umodes &= ~ConfigFileEntry.oper_only_umodes;
-			  
-              Count.oper--;
-
-              if (MyConnect(source_p))
-                {
-                  dlink_node *dm;
-
-		  ptr = source_p->localClient->confs.head;
-		  aconf = ptr->data;
-                  detach_conf(source_p,aconf);
-
-                  source_p->flags2 &= ~(FLAGS2_OPER_GLOBAL_KILL|
-                                    FLAGS2_OPER_REMOTE|
-                                    FLAGS2_OPER_UNKLINE|
-                                    FLAGS2_OPER_GLINE|
-                                    FLAGS2_OPER_N|
-                                    FLAGS2_OPER_K|
-                                    FLAGS2_OPER_ADMIN);
-
-		  dm = dlinkFind(&oper_list,source_p);
-		  if(dm != NULL)
-		    {
-		      dlinkDelete(dm,&oper_list);
-		      free_dlink_node(dm);
-		    }
-
-		  /*
-		    20001216:
-		    reattach to "old" iline
-		    - einride
-		  */
-		  remove_one_ip(&source_p->localClient->ip);
-		  check_client(source_p->servptr, source_p, source_p->username);
-                }
-            }
-          break;
-
-          /* we may not get these,
-           * but they shouldnt be in default
-           */
-        case ' ' :
-        case '\n' :
-        case '\r' :
-        case '\t' :
-          break;
-
-        default :
-          if( (flag = user_modes_from_c_to_bitmask[(unsigned char)*m]))
-            {
-              if (MyConnect(source_p) && !IsOper(source_p) &&
-                 (ConfigFileEntry.oper_only_umodes & flag))
-                {
-                  badflag = YES;
-                }
-              else
-                {
-                  if (what == MODE_ADD)
-                    source_p->umodes |= flag;
-                  else
-                    source_p->umodes &= ~flag;  
-                }
-            }
-          else
-            {
-              if (MyConnect(source_p))
-                badflag = YES;
-            }
-          break;
-        }
-
-  if(badflag)
-    sendto_one(source_p, form_str(ERR_UMODEUNKNOWNFLAG), me.name, parv[0]);
+  assert(ClassList != NULL);
+  for (cltmp = ClassList->next; cltmp; cltmp = cltmp->next)
+    MaxLinks(cltmp) = -1;
+
+  clear_out_address_conf();
+  clear_special_conf(&x_conf);
+  clear_special_conf(&u_conf);
+
+  /* clean out module paths */
+#ifndef STATIC_MODULES
+  mod_clear_paths();
+#endif
 
-  if ((source_p->umodes & FLAGS_NCHANGE) && !IsOperN(source_p))
-    {
-      sendto_one(source_p,":%s NOTICE %s :*** You need oper and N flag for +n",
-                 me.name,parv[0]);
-      source_p->umodes &= ~FLAGS_NCHANGE; /* only tcm's really need this */
-    }
+  /* clean out ServerInfo */
+  MyFree(ServerInfo.description);
+  ServerInfo.description = NULL;
+  MyFree(ServerInfo.network_name);
+  ServerInfo.network_name = NULL;
+  MyFree(ServerInfo.network_desc);
+  ServerInfo.network_desc = NULL;
+#ifdef HAVE_LIBCRYPTO
+  if (ServerInfo.rsa_private_key != NULL)
+  {
+    RSA_free(ServerInfo.rsa_private_key);
+    ServerInfo.rsa_private_key = NULL;
+  }
+  if (ServerInfo.rsa_private_key_file != NULL)
+  {
+    MyFree(ServerInfo.rsa_private_key_file);
+    ServerInfo.rsa_private_key_file = NULL;
+  }
+#endif
 
-  if (MyConnect(source_p) && (source_p->umodes & FLAGS_ADMIN) && !IsOperAdmin(source_p))
-    {
-      sendto_one(source_p,":%s NOTICE %s :*** You need oper and A flag for +a",
-                 me.name, parv[0]);
-      source_p->umodes &= ~FLAGS_ADMIN;
-    }
+  /* clean out old resvs from the conf */
+  clear_conf_resv();
 
+  /* clean out AdminInfo */
+  MyFree(AdminInfo.name);
+  AdminInfo.name = NULL;
+  MyFree(AdminInfo.email);
+  AdminInfo.email = NULL;
+  MyFree(AdminInfo.description);
+  AdminInfo.description = NULL;
+
+  /* operator{} and class{} blocks are freed above */
+  /* clean out listeners */
+  close_listeners();
 
-  if (!(setflags & FLAGS_INVISIBLE) && IsInvisible(source_p))
-    ++Count.invisi;
-  if ((setflags & FLAGS_INVISIBLE) && !IsInvisible(source_p))
-    --Count.invisi;
-  /*
-   * compare new flags with old flags and send string which
-   * will cause servers to update correctly.
+  /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{}, exempt{}
+   * and gecos{} blocks are freed above too
    */
-  send_umode_out(client_p, source_p, setflags);
 
-  return 0;
+  /* clean out general */
+  MyFree(ConfigFileEntry.servlink_path);
+  ConfigFileEntry.servlink_path = NULL;
+#ifdef HAVE_LIBCRYPTO
+  ConfigFileEntry.default_cipher_preference = NULL;
+#endif /* HAVE_LIBCRYPTO */
+
+  /* OK, that should be everything... */
 }
-        
+
 /*
- * send the MODE string for user (user) to connection client_p
- * -avalon
+ * flush_deleted_I_P
+ *
+ * inputs       - none
+ * output       - none
+ * side effects - This function removes I/P conf items
  */
-void send_umode(struct Client *client_p, struct Client *source_p, int old, 
-		int sendmask,  char *umode_buf)
+
+static 
+void flush_deleted_I_P(void)
 {
-  int   i;
-  int flag;
-  char  *m;
-  int   what = 0;
+  struct ConfItem **tmp = &ConfigItemList;
+  struct ConfItem *tmp2;
 
   /*
-   * build a string in umode_buf to represent the change in the user's
-   * mode between the new (source_p->flag) and 'old'.
+   * flush out deleted I and P lines although still in use.
    */
-  m = umode_buf;
-  *m = '\0';
-
-  for (i = 0; user_modes[i].letter; i++ )
+  for (tmp = &ConfigItemList; (tmp2 = *tmp); )
     {
-      flag = user_modes[i].mode;
-
-      if (MyClient(source_p) && !(flag & sendmask))
-        continue;
-      if ((flag & old) && !(source_p->umodes & flag))
-        {
-          if (what == MODE_DEL)
-            *m++ = user_modes[i].letter;
-          else
-            {
-              what = MODE_DEL;
-              *m++ = '-';
-              *m++ = user_modes[i].letter;
-            }
-        }
-      else if (!(flag & old) && (source_p->umodes & flag))
+      if (!(tmp2->status & CONF_ILLEGAL))
+        tmp = &tmp2->next;
+      else
         {
-          if (what == MODE_ADD)
-            *m++ = user_modes[i].letter;
-          else
-            {
-              what = MODE_ADD;
-              *m++ = '+';
-              *m++ = user_modes[i].letter;
-            }
+          *tmp = tmp2->next;
+          tmp2->next = NULL;
+          if (!tmp2->clients)
+            free_conf(tmp2);
         }
     }
-  *m = '\0';
-  if (*umode_buf && client_p)
-    sendto_one(client_p, ":%s MODE %s :%s",
-               source_p->name, source_p->name, umode_buf);
 }
 
 /*
- * send_umode_out
+ * WriteKlineOrDline
  *
- * inputs	-
- * output	- NONE
- * side effects - Only send ubuf out to servers that know about this client
+ * inputs       - kline or dline type flag
+ *              - client pointer to report to
+ *              - user name of target
+ *              - host name of target
+ *              - reason for target
+ *              - time_t cur_time
+ * output       - NONE
+ * side effects - This function takes care of
+ *                finding right kline or dline conf file, writing
+ *                the right lines to this file, 
+ *                notifying the oper that their kline/dline is in place
+ *                notifying the opers on the server about the k/d line
+ *                forwarding the kline onto the next U lined server
+ *                
  */
-void send_umode_out(struct Client *client_p,
-		    struct Client *source_p,
-		    int old)
+void 
+WriteKlineOrDline( KlineType type,
+		   struct Client *source_p,
+		   char *user,
+		   char *host,
+		   const char *reason,
+		   const char *current_date,
+		   time_t cur_time)
 {
-  struct Client *target_p;
-  char buf[BUFSIZE];
-  dlink_node *ptr;
-
-  send_umode(NULL, source_p, old, SEND_UMODES, buf);
+  char buffer[1024];
+  FBFILE *out;
+  const char *filename;         /* filename to use for kline */
+
+  filename = get_conf_name(type);
+
+  if(type == DLINE_TYPE)
+    {
+      sendto_realops_flags(FLAGS_ALL, L_ALL,
+			   "%s added D-Line for [%s] [%s]",
+			   get_oper_name(source_p), host, reason);
+      sendto_one(source_p, ":%s NOTICE %s :Added D-Line [%s] to %s",
+		 me.name, source_p->name, host, filename);
 
-  for(ptr = serv_list.head; ptr; ptr = ptr->next)
+    }
+  else
     {
-      target_p = ptr->data;
+      sendto_realops_flags(FLAGS_ALL, L_ALL,
+			   "%s added K-Line for [%s@%s] [%s]",
+			   get_oper_name(source_p), user, host, reason);
+      sendto_one(source_p, ":%s NOTICE %s :Added K-Line [%s@%s]",
+		 me.name, source_p->name, user, host);
+    }
+
+  if ( (out = fbopen(filename, "a")) == NULL )
+    {
+      sendto_realops_flags(FLAGS_ALL, L_ALL,
+			   "*** Problem opening %s ", filename);
+      return;
+    }
+
+  if(type==KLINE_TYPE)
+    ircsprintf(buffer, "\"%s\",\"%s\",\"%s %s\",\"%s\",%ld\n",
+               user,
+	       host,
+               reason,
+	       current_date,
+	       get_oper_name(source_p),
+               (long) cur_time);
+  else
+    ircsprintf(buffer, "\"%s\",\"%s %s\",\"%s\",%ld\n",
+               host,
+               reason,
+	       current_date,
+	       get_oper_name(source_p),
+               (long) cur_time);
 
-      if((target_p != client_p) && (target_p != source_p) && (*buf))
-        {
-          if((!(ServerInfo.hub && IsCapable(target_p, CAP_LL)))
-             || (target_p->localClient->serverMask &
-                 source_p->lazyLinkClientExists))
-            sendto_one(target_p, ":%s MODE %s :%s",
-                       source_p->name, source_p->name, buf);
-        }
+
+  if (fbputs(buffer,out) == -1)
+    {
+      sendto_realops_flags(FLAGS_ALL, L_ALL,
+			   "*** Problem writing to %s",filename);
+      fbclose(out);
+      return;
     }
+      
+  fbclose(out);
 
-  if (client_p && MyClient(client_p))
-    send_umode(client_p, source_p, old, ALL_UMODES, buf);
+  if(type==KLINE_TYPE)
+    ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]",
+        source_p->name, user, host, reason);
+  else
+    ilog(L_TRACE, "%s added D-Line for [%s] [%s]",
+           get_oper_name(source_p), host, reason);
 }
 
-/* 
- * user_welcome
+/* get_conf_name
  *
- * inputs	- client pointer to client to welcome
- * output	- NONE
- * side effects	-
+ * inputs       - type of conf file to return name of file for
+ * output       - pointer to filename for type of conf
+ * side effects - none
  */
-void user_welcome(struct Client *source_p)
+const char *
+get_conf_name(KlineType type)
+{
+  if(type == CONF_TYPE)
+    {
+      return(ConfigFileEntry.configfile);
+    }
+  else if(type == KLINE_TYPE)
+    {
+      return(ConfigFileEntry.klinefile);
+    }
+
+  return(ConfigFileEntry.dlinefile);
+}
+
+/*
+ * conf_add_class
+ * inputs       - pointer to config item
+ * output       - NONE
+ * side effects - Add a class
+ *
+ */
+
+void 
+conf_add_class(struct ConfItem *aconf,int sendq)
 {
-  sendto_one(source_p, form_str(RPL_WELCOME), me.name, source_p->name, 
-             ServerInfo.network_name, source_p->name );
-  /* This is a duplicate of the NOTICE but see below...*/
-  sendto_one(source_p, form_str(RPL_YOURHOST), me.name, source_p->name,
-	     get_listener_name(source_p->localClient->listener), ircd_version);
-  
   /*
-  ** Don't mess with this one - IRCII needs it! -Avalon
+  ** If conf line is a class definition, create a class entry
   */
-  sendto_one(source_p,
-	     "NOTICE %s :*** Your host is %s, running version %s",
-	     source_p->name, get_listener_name(source_p->localClient->listener),
-	     ircd_version);
-  
-  sendto_one(source_p, form_str(RPL_CREATED),me.name,source_p->name,creation);
-  sendto_one(source_p, form_str(RPL_MYINFO), me.name, source_p->name,
-	     me.name, ircd_version);
-  
-  show_isupport(source_p);
-  
-  show_lusers(source_p);
+    /*
+    ** associate each conf line with a class by using a pointer
+    ** to the correct class record. -avalon
+    */
+  if (aconf->host)
+    {
+      add_class(aconf->host, atoi(aconf->passwd),
+		atoi(aconf->user), aconf->port,
+		sendq);
+    }
+}
+
+/*
+ * conf_add_class_to_conf
+ * inputs       - pointer to config item
+ * output       - NONE
+ * side effects - Add a class pointer to a conf 
+ */
 
-  if (ConfigFileEntry.short_motd)
+void 
+conf_add_class_to_conf(struct ConfItem *aconf)
+{
+  if(aconf->className == NULL)
     {
-      sendto_one(source_p,"NOTICE %s :*** Notice -- motd was last changed at %s",
-		 source_p->name,
-		 ConfigFileEntry.motd.lastChangedDate);
-      
-      sendto_one(source_p,
-		 "NOTICE %s :*** Notice -- Please read the motd if you haven't read it",
-		 source_p->name);
-    
-      sendto_one(source_p, form_str(RPL_MOTDSTART),
-		 me.name, source_p->name, me.name);
-    
-      sendto_one(source_p,
-		 form_str(RPL_MOTD),
-		 me.name, source_p->name,
-		 "*** This is the short motd ***"
-		 );
+      DupString(aconf->className,"default");
+      ClassPtr(aconf) = class0;
+      return;
+    }
+
+  ClassPtr(aconf) = find_class(aconf->className);
 
-      sendto_one(source_p, form_str(RPL_ENDOFMOTD),
-		 me.name, source_p->name);
+  if(ClassPtr(aconf) == class0)
+    {
+      sendto_realops_flags(FLAGS_ALL, L_ALL,
+	   "Warning *** Defaulting to default class for missing class \"%s\"",
+			   aconf->className);
+      MyFree(aconf->className);
+      DupString(aconf->className,"default");
+      return;
     }
-  else  
-    SendMessageFile(source_p, &ConfigFileEntry.motd);
 
-  if (IsRestricted(source_p))
+  if (ConfMaxLinks(aconf) < 0)
     {
-      sendto_one(source_p,form_str(ERR_RESTRICTED),
-		 me.name, source_p->name);
+      ClassPtr(aconf) = find_class(0);
+      MyFree(aconf->className);
+      DupString(aconf->className,"default");
+      return;
     }
 }
 
 /*
- * check_X_line
- * inputs	- pointer to client to test
- * outupt	- -1 if exiting 0 if ok
- * side effects	-
+ * conf_delist_old_conf
+ * inputs       - pointer to config item
+ * output       - NONE
+ * side effects - delist old conf (if present)
  */
-static int check_X_line(struct Client *client_p, struct Client *source_p)
-{
-  struct ConfItem *aconf;
-  char *reason;
 
-  if(IsOper(source_p))
-    return 0;
+void 
+conf_delist_old_conf(struct ConfItem *aconf)
+{
+  struct ConfItem *bconf;
 
-  if ((aconf = find_x_conf(source_p->info)))
+  if ((bconf = find_conf_entry(aconf, aconf->status)))
     {
-      if(aconf->passwd)
-	reason = aconf->passwd;
-      else
-	reason = "NONE";
-              
-      if(aconf->port)
+      delist_conf(bconf);
+      bconf->status &= ~CONF_ILLEGAL;
+      if (aconf->status == CONF_CLIENT)
 	{
-	  if (aconf->port == 1)
-	    {
-	      sendto_realops_flags(FLAGS_REJ, L_ALL,
-				   "X-line Rejecting [%s] [%s], user %s",
-				   source_p->info,
-				   reason,
-				   get_client_name(client_p, HIDE_IP));
-	    }
-	  ServerStats->is_ref++;      
-	  (void)exit_client(client_p, source_p, &me, "Bad user info");
-	  return (CLIENT_EXITED);
+	  ConfLinks(bconf) -= bconf->clients;
+	  ClassPtr(bconf) = ClassPtr(aconf);
+	  ConfLinks(bconf) += bconf->clients;
+	  bconf->flags = aconf->flags;
+	  if(bconf->flags & CONF_OPERATOR)
+	    bconf->port = aconf->port;
 	}
-      else
-	sendto_realops_flags(FLAGS_REJ, L_ALL,
-			     "X-line Warning [%s] [%s], user %s",
-			     source_p->info,
-			     reason,
-			     get_client_name(client_p, HIDE_IP));
+      free_conf(aconf);
+      aconf = bconf;
     }
-
-  return 0;
 }
 
+#define MAXCONFLINKS 150
+
 /*
- * oper_up
+ * conf_add_server
  *
- * inputs	- pointer to given client to oper
- *		- pointer to ConfItem to use
- * output	- none
- * side effects	-
- * Blindly opers up given source_p, using aconf info
- * all checks on passwords have already been done.
- * This could also be used by rsa oper routines. 
+ * inputs       - pointer to config item
+ *		- pointer to link count already on this conf
+ * output       - NONE
+ * side effects - Add a connect block
  */
-
-int oper_up( struct Client *source_p,
-                    struct ConfItem *aconf )
+int 
+conf_add_server(struct ConfItem *aconf, int lcount)
 {
-  int old = (source_p->umodes & ALL_UMODES);
-  char *operprivs=NULL;
-  dlink_node *ptr;
-  struct ConfItem *found_aconf;
-  dlink_node *m;
+  conf_add_class_to_conf(aconf);
 
-  SetOper(source_p);
-  if((int)aconf->hold)
+  if (lcount > MAXCONFLINKS || !aconf->host || !aconf->name)
     {
-      source_p->umodes |= ((int)aconf->hold & ALL_UMODES); 
-      if( !IsOperN(source_p) )
-	source_p->umodes &= ~FLAGS_NCHANGE;
-      
-      sendto_one(source_p, ":%s NOTICE %s :*** Oper flags set from conf",
-		 me.name,source_p->name);
+      sendto_realops_flags(FLAGS_ALL, L_ALL,"Bad connect block");
+      ilog(L_WARN, "Bad connect block");
+      return -1;
     }
-  else
+
+  if (BadPtr(aconf->passwd) && !(aconf->flags & CONF_FLAGS_CRYPTLINK))
     {
-      if(ConfigFileEntry.oper_umodes)
-        {
-          source_p->umodes |= ConfigFileEntry.oper_umodes & ALL_UMODES;
-        }
-      else
-        {
-          source_p->umodes |= (FLAGS_SERVNOTICE|FLAGS_OPERWALL|FLAGS_WALLOP|FLAGS_LOCOPS) & ALL_UMODES;
-        }
+      sendto_realops_flags(FLAGS_ALL, L_ALL,"Bad connect block, name %s",
+			   aconf->name);
+      ilog(L_WARN, "Bad connect block, host %s",aconf->name);
+      return -1;
+    }
+          
+  if( SplitUserHost(aconf) < 0 )
+    {
+      sendto_realops_flags(FLAGS_ALL, L_ALL,"Bad connect block, name %s",
+			   aconf->name);
+      ilog(L_WARN, "Bad connect block, name %s",aconf->name);
+      return -1;
     }
-	
-  SetIPHidden(source_p);
-  Count.oper++;
+  lookup_confhost(aconf);
+  return 0;
+}
 
-  SetExemptKline(source_p);
-      
-  m = make_dlink_node();
-  dlinkAdd(source_p,m,&oper_list);
+/*
+ * conf_add_d_conf
+ * inputs       - pointer to config item
+ * output       - NONE
+ * side effects - Add a d/D line
+ */
+void
+conf_add_d_conf(struct ConfItem *aconf)
+{
+  if (aconf->host == NULL)
+    return;
+
+  aconf->user = NULL;
+
+  /* XXX - Should 'd' ever be in the old conf? For new conf we don't
+   *       need this anyway, so I will disable it for now... -A1kmm
+   */
 
-  if(source_p->localClient->confs.head)
+  if (parse_netmask(aconf->host, NULL, NULL) == HM_HOST)
     {
-      ptr = source_p->localClient->confs.head;
-      if(ptr)
-	{
-	  found_aconf = ptr->data;
-	  if(found_aconf)
-	    operprivs = oper_privs_as_string(source_p,found_aconf->port);
-	}
+      ilog(L_WARN,"Invalid Dline %s ignored",aconf->host);
+      free_conf(aconf);
     }
   else
-    operprivs = "";
+    {
+      add_conf_by_address(aconf->host, CONF_DLINE, NULL, aconf);
+    }
+}
+
+/*
+ * conf_add_x_conf
+ * inputs       - pointer to config item
+ * output       - NONE
+ * side effects - Add a X line
+ */
+
+void 
+conf_add_x_conf(struct ConfItem *aconf)
+{
+  MyFree(aconf->user);
+  aconf->user = NULL;
+  aconf->name = aconf->host;
+  aconf->host = (char *)NULL;
+  aconf->next = x_conf;
+  x_conf = aconf;
+}
+
+/*
+ * conf_add_x_conf
+ * inputs       - pointer to config item
+ * output       - NONE
+ * side effects - Add an U line
+ */
+
+void 
+conf_add_u_conf(struct ConfItem *aconf)
+{
+  aconf->next = u_conf;
+  u_conf = aconf;
+}
+
+
+/*
+ * conf_add_fields
+ * inputs       - pointer to config item
+ *              - pointer to host_field
+ *		- pointer to pass_field
+ *              - pointer to user_field
+ *              - pointer to port_field
+ *		- pointer to class_field
+ * output       - NONE
+ * side effects - update host/pass/user/port fields of given aconf
+ */
+
+void 
+conf_add_fields(struct ConfItem *aconf,
+		char *host_field,
+		char *pass_field,
+		char *user_field,
+		char *port_field,
+		char *class_field)
+{
+  if(host_field)
+    DupString(aconf->host, host_field);
+  if(pass_field)
+    DupString(aconf->passwd, pass_field);
+  if(user_field)
+    DupString(aconf->user, user_field);
+  if(port_field)
+    aconf->port = atoi(port_field);
+  if(class_field)
+    DupString(aconf->className, class_field);
+}
+
+/*
+ * yyerror
+ *
+ * inputs	- message from parser
+ * output	- none
+ * side effects	- message to opers and log file entry is made
+ */
+void 
+yyerror(char *msg)
+{
+  char newlinebuf[BUFSIZE];
+
+  strip_tabs(newlinebuf, (const unsigned char *)linebuf, strlen(linebuf));
+
+  sendto_realops_flags(FLAGS_ALL, L_ALL,"%d: %s on line: %s",
+		       lineno + 1, msg, newlinebuf);
+
+  ilog(L_WARN, "%d: %s on line: %s",
+      lineno + 1, msg, newlinebuf);
+}
+
+int 
+conf_fbgets(char *lbuf,int max_size, FBFILE *fb)
+{
+  char* buff;
 
-  if (IsOperAdmin(source_p))
-    source_p->umodes |= FLAGS_ADMIN;
+  buff = fbgets(lbuf,max_size,fb);
 
+  if(!buff)
+    return 0;
+
+  return(strlen(lbuf));
+}
+
+int 
+conf_yy_fatal_error(char *msg)
+{
+#if 0
   sendto_realops_flags(FLAGS_ALL, L_ALL,
-		       "%s (%s@%s) is now an operator", source_p->name,
-		       source_p->username, source_p->host);
-  send_umode_out(source_p, source_p, old);
-  sendto_one(source_p, form_str(RPL_YOUREOPER), me.name, source_p->name);
-  sendto_one(source_p, ":%s NOTICE %s :*** Oper privs are %s", me.name,
-             source_p->name, operprivs);
-  SendMessageFile(source_p, &ConfigFileEntry.opermotd);
-  
-  return 1;
+		       "lexer barfed. lets leave it at that for now");
+#endif
+  return 0;
+}
+
+#ifdef PACE_CONNECT
+
+/* void flush_expired_ips(void *unused)
+ *
+ * inputs	- none.
+ * output	- none.
+ * side effects	- Deletes all IP address entries which should have expired.
+ */
+void
+flush_expired_ips(void *unused)
+{
+  int i;
+  time_t expire_before = CurrentTime - ConfigFileEntry.throttle_time;
+  IP_ENTRY *ie, **iee;
+
+  for (i=0; i<IP_HASH_SIZE; i++)
+    {
+      for (iee=ip_hash_table+i, ie=*iee; ie; ie=*iee)
+	{
+	  if (ie->count == 0 && ie->last_attempt <= expire_before)
+	    {
+	      *iee=ie->next;
+	      ie->next = free_ip_entries;
+	      free_ip_entries = ie;
+	    }
+	  else
+	    iee = &ie->next;
+	}
+      *iee = NULL;
+    }
 }
+#endif
