diff -uNrd -x CVS ircd-ratbox-cvs/contrib/Makefile.in ratbox-devel/contrib/Makefile.in
--- ircd-ratbox-cvs/contrib/Makefile.in	Thu Jun 17 19:18:34 2004
+++ ratbox-devel/contrib/Makefile.in	Tue Jul 27 11:22:27 2004
@@ -44,7 +44,8 @@
   spy_trace_notice.c		\
   spy_whois_notice.c            \
   spy_whois_notice_global.c	\
-  example_module.c
+  example_module.c		\
+  m_monitor-4.c
 
 OBJS = ${SRCS:.c=.so}
 
diff -uNrd -x CVS ircd-ratbox-cvs/contrib/m_monitor-4.c ratbox-devel/contrib/m_monitor-4.c
--- ircd-ratbox-cvs/contrib/m_monitor-4.c	Wed Dec 31 19:00:00 1969
+++ ratbox-devel/contrib/m_monitor-4.c	Sat Apr 10 21:26:49 2004
@@ -0,0 +1,1030 @@
+/*
+ *  m_monitor.c: Implements tcm/Sentinel-like user searching functionality
+ *
+ *  Copyright 2003-2004 by W. Campbell
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *
+ *  1.Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer. 
+ *  2.Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution. 
+ *  3.The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ *  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  $Id$
+ *
+ * Revision 1:  Commands ULIST and TESTMASK
+ * Revision 2:  Command NLIST
+ * Revision 3:  TESTMASK split off into its own module
+ *              Merge the regex and match versions into a single module,
+ *                with the options handled by getopt().
+ *              Command GLIST
+ * Revision 4:  Compliance with OPERSPY, Removed Hybrid support, added
+ *                Ratbox 2 support.
+ */
+
+/* List of ircd includes from ../include/ */
+#include "stdinc.h"
+#include "client.h"
+#include "common.h"     /* FALSE bleah */
+#include "ircd.h"
+#include "irc_string.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_log.h"
+#include "s_serv.h"
+#include "send.h"
+#include "msg.h"
+#include "parse.h"
+#include "modules.h"
+#include <regex.h>
+
+#ifdef MAPI_RATBOX
+
+#include "s_newconf.h"
+
+#else
+
+#include "handlers.h"
+
+#define report_operspy(x, y, z)		log_operspy((x), (y), (z))
+#endif
+
+static int mo_ulist(struct Client *client_p, struct Client *source_p,
+                     int parc, char *parv[]);
+static int mo_nlist(struct Client *client_p, struct Client *source_p,
+                     int parc, char *parv[]);
+static int mo_glist(struct Client *client_p, struct Client *source_p,
+                     int parc, char *parv[]);
+
+static void ul_usage(struct Client *source_p);
+static void nl_usage(struct Client *source_p);
+static void gl_usage(struct Client *source_p);
+
+/* ULIST handlers */
+static void ul_local_match(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim);
+static void ul_local_regex(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim, unsigned int flags);
+static void ul_global_match(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim);
+static void ul_global_regex(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim, unsigned int flags);
+
+/* NLIST handlers */
+static void nl_local_match(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim);
+static void nl_local_regex(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim, unsigned int flags);
+static void nl_global_match(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim);
+static void nl_global_regex(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim, unsigned int flags);
+
+/* GLIST handlers */
+static void gl_local_match(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim);
+static void gl_local_regex(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim, unsigned int flags);
+static void gl_global_match(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim);
+static void gl_global_regex(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim, unsigned int flags);
+
+#ifdef MAPI_RATBOX
+struct Message ulist_msgtab =
+{
+  "ULIST", 0, 0, 0, MFLG_SLOW,
+  { mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, { mo_ulist, 2 } }
+};
+
+struct Message nlist_msgtab =
+{
+  "NLIST", 0, 0, 0, MFLG_SLOW,
+  { mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, { mo_nlist, 2 } }
+};
+
+struct Message glist_msgtab =
+{
+  "GLIST", 0, 0, 0, MFLG_SLOW,
+  { mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, { mo_glist, 2 } }
+};
+
+mapi_clist_av1 xlist_clist[] =
+{
+  &ulist_msgtab,
+  &nlist_msgtab,
+  &glist_msgtab,
+  NULL
+};
+
+DECLARE_MODULE_AV1(xlist, NULL, NULL, xlist_clist, NULL, NULL, "$Revision$");
+
+#else /* Ratbox 1.x */
+
+struct Message ulist_msgtab = {
+  "ULIST", 0, 0, 2, 0, MFLG_SLOW, 0,
+  {m_unregistered, m_not_oper, m_ignore, mo_ulist}
+};
+
+struct Message nlist_msgtab = {
+  "NLIST", 0, 0, 2, 0, MFLG_SLOW, 0,
+  {m_unregistered, m_not_oper, m_ignore, mo_nlist}
+};
+
+struct Message glist_msgtab = {
+  "GLIST", 0, 0, 2, 0, MFLG_SLOW, 0,
+  {m_unregistered, m_not_oper, m_ignore, mo_glist}
+};
+
+#ifndef STATIC_MODULES
+void
+_modinit(void)
+{
+  mod_add_cmd(&ulist_msgtab);
+  mod_add_cmd(&nlist_msgtab);
+  mod_add_cmd(&glist_msgtab);
+}
+
+void
+_moddeinit(void)
+{
+  mod_del_cmd(&ulist_msgtab);
+  mod_del_cmd(&nlist_msgtab);
+  mod_del_cmd(&glist_msgtab);
+}
+
+const char *_version = "Hwy v.3 ($Revision$)";
+#endif /* STATIC_MODULES */
+
+#endif /* MAPI_RATBOX */
+
+#define UL_GLOBAL	0x00000001
+#define UL_LOCAL	0x00000002
+#define UL_MATCH	0x00000004
+#define UL_REGEX	0x00000008
+#define UL_INSEN	0x00000010
+#define UL_SENS		0x00000020
+
+/*
+** mo_ulist
+** Syntax:  ULIST [-l|-g] [-m|-r] [-i|-s] [-x limit] user@host
+** Defaults:  local scope, limit to 0, match() variant, case insensitive (re)
+*/
+static int mo_ulist(struct Client *client_p, struct Client *source_p,
+                    int parc, char *parv[])
+{		 
+  int lim = 0;
+  char *pattern;
+  unsigned int flags = UL_LOCAL|UL_MATCH|UL_INSEN;
+  char c;
+
+  opterr = 0; /* Disable error reporting (since it goes to STDERR) */
+  optind = 1; /* Always restore the index to the start of the parameters */
+  while ( (c = getopt(parc, parv, "lgmrisx:")) != -1)
+  {
+    switch (c)
+    {
+      case 'l':
+        flags &= ~UL_GLOBAL;
+        flags |= UL_LOCAL;
+        break;
+      case 'g':
+        flags &= ~UL_LOCAL;
+        flags |= UL_GLOBAL;
+        break;
+      case 'm':
+        flags &= ~UL_REGEX;
+        flags |= UL_MATCH;
+        break;
+      case 'r':
+        flags &= ~UL_MATCH;
+        flags |= UL_REGEX;
+        break;
+      case 'i':
+        flags &= ~UL_SENS;
+        flags |= UL_INSEN;
+        break;
+      case 's':
+        flags &= ~UL_INSEN;
+        flags |= UL_SENS;
+        break;
+      case 'x':
+        lim = atoi(optarg);
+        break;
+      case '?': /* Returned on a syntax error from getopt() */
+      default:
+        ul_usage(source_p);
+        return 0;
+        break;
+    }
+  }
+
+  /* This extracts the pointer to the pattern, which is placed after all
+  ** all of the arguments to the ULIST command.
+  */
+  parc -= optind;
+  parv += optind;
+
+  if (parc < 1)
+  {
+    ul_usage(source_p);
+    return 0;
+  }
+
+  pattern = parv[0];
+
+  /* Send the information to the proper handlers */
+  if (flags & UL_LOCAL)
+  {
+    if (flags & UL_MATCH)
+    {
+      ul_local_match(client_p, source_p, pattern, lim);
+    }
+    else /* UL_REGEX */
+    {
+      ul_local_regex(client_p, source_p, pattern, lim, flags);
+    }
+  }
+  else /* UL_GLOBAL */
+  {
+    if (flags & UL_MATCH)
+    {
+      ul_global_match(client_p, source_p, pattern, lim);
+    }
+    else /* UL_REGEX */
+    {
+      ul_global_regex(client_p, source_p, pattern, lim, flags);
+    }
+  }
+
+  return 0;
+}
+
+static void ul_local_match(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim)
+{
+  dlink_node *dl;
+  struct Client *target_p;
+  char *hostname;
+  int count = 0;
+
+  hostname = strchr(pattern, '@');
+  if (hostname == NULL)
+  {
+    sendto_one(source_p, ":%s NOTICE %s :Error in /ULIST, please use an '@' "
+               "character in the pattern", me.name, source_p->name);
+    return;
+  }
+  *hostname = '\0';
+  hostname++;
+
+  DLINK_FOREACH(dl, lclient_list.head)
+  {
+    target_p = dl->data;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :ULIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    if (match(pattern, target_p->username) && match(hostname, target_p->host))
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of ULIST.", me.name, source_p->name);
+}
+
+static void ul_local_regex(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim, unsigned int flags)
+{
+  int retval;
+  dlink_node *dl;
+  struct Client *target_p;
+  regex_t reg;
+  int count = 0;
+  char userhost[USERLEN + HOSTLEN + 3];
+
+  if (flags & UL_INSEN)
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+  }
+  else
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_NOSUB);
+  }
+
+  if (retval != 0)
+  {
+    char errbuf[BUFSIZE];
+    regerror(retval, &reg, errbuf, BUFSIZE);
+    sendto_one(source_p, ":%s NOTICE %s :ULIST regular expression error: %s",
+               me.name, source_p->name, errbuf);
+    regfree(&reg);
+    return;
+  }
+
+  DLINK_FOREACH(dl, lclient_list.head)
+  {
+    target_p = dl->data;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :ULIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    snprintf(userhost, sizeof(userhost), "%s@%s", target_p->username,
+             target_p->host);
+    /* Using no flags here */
+    if (regexec(&reg, userhost, 0, NULL, 0) == 0)
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of ULIST.", me.name, source_p->name);
+  regfree(&reg);
+}
+
+static void ul_global_match(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim)
+{
+  dlink_node *dl;
+  struct Client *target_p;
+  char *hostname;
+  int count = 0;
+  char osbuffer[BUFSIZE];
+
+  hostname = strchr(pattern, '@');
+  if (hostname == NULL)
+  {
+    sendto_one(source_p, ":%s NOTICE %s :Error in /ULIST, please use an '@' "
+               "character in the pattern", me.name, source_p->name);
+    return;
+  }
+  *hostname = '\0';
+  hostname++;
+
+  snprintf(osbuffer, sizeof(osbuffer), "[GLOBAL][MATCH] %s@%s", pattern,
+           hostname);
+  report_operspy(source_p, "ULIST", osbuffer);
+
+  DLINK_FOREACH(dl, global_client_list.head)
+  { 
+    target_p = dl->data;
+
+    if (!IsPerson(target_p))
+      continue;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :ULIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    if (match(pattern, target_p->username) && match(hostname, target_p->host))
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of ULIST.", me.name, source_p->name);
+}
+
+static void ul_global_regex(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim, unsigned int flags)
+{
+  int retval;
+  dlink_node *dl;
+  struct Client *target_p;
+  regex_t reg;
+  int count = 0;
+  char userhost[USERLEN + HOSTLEN + 3];
+  char osbuffer[BUFSIZE];
+
+  if (flags & UL_INSEN)
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+  }
+  else
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_NOSUB);
+  }
+
+  if (retval != 0)
+  {
+    char errbuf[BUFSIZE];
+    regerror(retval, &reg, errbuf, BUFSIZE);
+    sendto_one(source_p, ":%s NOTICE %s :ULIST regular expression error: %s",
+               me.name, source_p->name, errbuf);
+    regfree(&reg);
+    return;
+  }
+
+  snprintf(osbuffer, sizeof(osbuffer), "[GLOBAL][REGEX]%s %s",
+           (flags & UL_INSEN) ? "[INSENS]" : "[SENS]", pattern);
+  report_operspy(source_p, "ULIST", osbuffer);
+
+  DLINK_FOREACH(dl, global_client_list.head)
+  {
+    target_p = dl->data;
+
+    if (!IsPerson(target_p))
+      continue;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :ULIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    snprintf(userhost, sizeof(userhost), "%s@%s", target_p->username,
+             target_p->host);
+    /* Using no flags here */
+    if (regexec(&reg, userhost, 0, NULL, 0) == 0)
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of ULIST.", me.name, source_p->name);
+  regfree(&reg);
+}
+
+static void ul_usage(struct Client *source_p)
+{
+  sendto_one(source_p, ":%s NOTICE %s :Syntax:  /ULIST [-l|-g] [-m|-r] [-i|-s] "
+                       "[-x limit] pattern", me.name, source_p->name);
+}
+
+/*
+** mo_nlist
+** Syntax:  NLIST [-l|-g] [-m|-r] [-i|-s] [-x limit] user@host
+** Defaults:  local scope, limit to 0, match() variant, case sensitive (re)
+*/
+static int mo_nlist(struct Client *client_p, struct Client *source_p,
+                    int parc, char *parv[])
+{		 
+  int lim = 0;
+  char *pattern;
+  unsigned int flags = UL_LOCAL|UL_MATCH|UL_SENS;
+  char c;
+
+  opterr = 0; /* Disable error reporting (since it goes to STDERR) */
+  optind = 1; /* Always restore the index to the start of the parameters */
+  while ( (c = getopt(parc, parv, "lgmrisx:")) != -1)
+  {
+    switch (c)
+    {
+      case 'l':
+        flags &= ~UL_GLOBAL;
+        flags |= UL_LOCAL;
+        break;
+      case 'g':
+        flags &= ~UL_LOCAL;
+        flags |= UL_GLOBAL;
+        break;
+      case 'm':
+        flags &= ~UL_REGEX;
+        flags |= UL_MATCH;
+        break;
+      case 'r':
+        flags &= ~UL_MATCH;
+        flags |= UL_REGEX;
+        break;
+      case 'i':
+        flags &= ~UL_SENS;
+        flags |= UL_INSEN;
+        break;
+      case 's':
+        flags &= ~UL_INSEN;
+        flags |= UL_SENS;
+        break;
+      case 'x':
+        lim = atoi(optarg);
+        break;
+      case '?': /* Returned on a syntax error from getopt() */
+      default:
+        nl_usage(source_p);
+        return 0;
+        break;
+    }
+  }
+
+  /* This extracts the pointer to the pattern, which is placed after all
+  ** all of the arguments to the ULIST command.
+  */
+  parc -= optind;
+  parv += optind;
+
+  if (parc < 1)
+  {
+    nl_usage(source_p);
+    return 0;
+  }
+
+  pattern = parv[0];
+
+  /* Send the information to the proper handlers */
+  if (flags & UL_LOCAL)
+  {
+    if (flags & UL_MATCH)
+    {
+      nl_local_match(client_p, source_p, pattern, lim);
+    }
+    else /* UL_REGEX */
+    {
+      nl_local_regex(client_p, source_p, pattern, lim, flags);
+    }
+  }
+  else /* UL_GLOBAL */
+  {
+    if (flags & UL_MATCH)
+    {
+      nl_global_match(client_p, source_p, pattern, lim);
+    }
+    else /* UL_REGEX */
+    {
+      nl_global_regex(client_p, source_p, pattern, lim, flags);
+    }
+  }
+
+  return 0;
+}
+
+static void nl_local_match(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim)
+{
+  dlink_node *dl;
+  struct Client *target_p;
+  int count = 0;
+
+  DLINK_FOREACH(dl, lclient_list.head)
+  {
+    target_p = dl->data;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :NLIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    if (match(pattern, target_p->name))
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of NLIST.", me.name, source_p->name);
+}
+
+static void nl_local_regex(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim, unsigned int flags)
+{
+  int retval;
+  dlink_node *dl;
+  struct Client *target_p;
+  regex_t reg;
+  int count = 0;
+
+  if (flags & UL_INSEN)
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+  }
+  else
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_NOSUB);
+  }
+
+  if (retval != 0)
+  {
+    char errbuf[BUFSIZE];
+    regerror(retval, &reg, errbuf, BUFSIZE);
+    sendto_one(source_p, ":%s NOTICE %s :NLIST regular expression error: %s",
+               me.name, source_p->name, errbuf);
+    regfree(&reg);
+    return;
+  }
+
+  DLINK_FOREACH(dl, lclient_list.head)
+  {
+    target_p = dl->data;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :NLIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    /* Using no flags here */
+    if (regexec(&reg, target_p->name, 0, NULL, 0) == 0)
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of NLIST.", me.name, source_p->name);
+  regfree(&reg);
+}
+
+static void nl_global_match(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim)
+{
+  dlink_node *dl;
+  struct Client *target_p;
+  int count = 0;
+
+  report_operspy(source_p, "NLIST [GLOBAL][MATCH]", pattern);
+
+  DLINK_FOREACH(dl, global_client_list.head)
+  { 
+    target_p = dl->data;
+
+    if (!IsPerson(target_p))
+      continue;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :NLIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    if (match(pattern, target_p->name))
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of NLIST.", me.name, source_p->name);
+}
+
+static void nl_global_regex(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim, unsigned int flags)
+{
+  int retval;
+  dlink_node *dl;
+  struct Client *target_p;
+  regex_t reg;
+  int count = 0;
+  char osbuffer[BUFSIZE];
+
+  if (flags & UL_INSEN)
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+  }
+  else
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_NOSUB);
+  }
+
+  if (retval != 0)
+  {
+    char errbuf[BUFSIZE];
+    regerror(retval, &reg, errbuf, BUFSIZE);
+    sendto_one(source_p, ":%s NOTICE %s :NLIST regular expression error: %s",
+               me.name, source_p->name, errbuf);
+    regfree(&reg);
+    return;
+  }
+
+  snprintf(osbuffer, BUFSIZE, "[GLOBAL][REGEX]%s %s",
+           (flags & UL_INSEN) ? "[INSENS]" : "[SENS]", pattern);
+  report_operspy(source_p, "NLIST", osbuffer);
+
+  DLINK_FOREACH(dl, global_client_list.head)
+  {
+    target_p = dl->data;
+
+    if (!IsPerson(target_p))
+      continue;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :NLIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    /* Using no flags here */
+    if (regexec(&reg, target_p->name, 0, NULL, 0) == 0)
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of NLIST.", me.name, source_p->name);
+  regfree(&reg);
+}
+
+static void nl_usage(struct Client *source_p)
+{
+  sendto_one(source_p, ":%s NOTICE %s :Syntax:  /NLIST [-l|-g] [-m|-r] [-i|-s] "
+                       "[-x limit] pattern", me.name, source_p->name);
+}
+
+/*
+** mo_glist
+** Syntax:  NLIST [-l|-g] [-m|-r] [-i|-s] [-x limit] user@host
+** Defaults:  local scope, limit to 0, match() variant, case insensitive (re)
+*/
+static int mo_glist(struct Client *client_p, struct Client *source_p,
+                    int parc, char *parv[])
+{		 
+  int lim = 0;
+  char *pattern;
+  unsigned int flags = UL_LOCAL|UL_MATCH|UL_INSEN;
+  char c;
+
+  opterr = 0; /* Disable error reporting (since it goes to STDERR) */
+  optind = 1; /* Always restore the index to the start of the parameters */
+  while ( (c = getopt(parc, parv, "lgmrisx:")) != -1)
+  {
+    switch (c)
+    {
+      case 'l':
+        flags &= ~UL_GLOBAL;
+        flags |= UL_LOCAL;
+        break;
+      case 'g':
+        flags &= ~UL_LOCAL;
+        flags |= UL_GLOBAL;
+        break;
+      case 'm':
+        flags &= ~UL_REGEX;
+        flags |= UL_MATCH;
+        break;
+      case 'r':
+        flags &= ~UL_MATCH;
+        flags |= UL_REGEX;
+        break;
+      case 'i':
+        flags &= ~UL_SENS;
+        flags |= UL_INSEN;
+        break;
+      case 's':
+        flags &= ~UL_INSEN;
+        flags |= UL_SENS;
+        break;
+      case 'x':
+        lim = atoi(optarg);
+        break;
+      case '?': /* Returned on a syntax error from getopt() */
+      default:
+        nl_usage(source_p);
+        return 0;
+        break;
+    }
+  }
+
+  /* This extracts the pointer to the pattern, which is placed after all
+  ** all of the arguments to the ULIST command.
+  */
+  parc -= optind;
+  parv += optind;
+
+  if (parc < 1)
+  {
+    gl_usage(source_p);
+    return 0;
+  }
+
+  pattern = parv[0];
+
+  /* Send the information to the proper handlers */
+  if (flags & UL_LOCAL)
+  {
+    if (flags & UL_MATCH)
+    {
+      gl_local_match(client_p, source_p, pattern, lim);
+    }
+    else /* UL_REGEX */
+    {
+      gl_local_regex(client_p, source_p, pattern, lim, flags);
+    }
+  }
+  else /* UL_GLOBAL */
+  {
+    if (flags & UL_MATCH)
+    {
+      gl_global_match(client_p, source_p, pattern, lim);
+    }
+    else /* UL_REGEX */
+    {
+      gl_global_regex(client_p, source_p, pattern, lim, flags);
+    }
+  }
+
+  return 0;
+}
+
+static void gl_local_match(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim)
+{
+  dlink_node *dl;
+  struct Client *target_p;
+  int count = 0;
+
+  DLINK_FOREACH(dl, lclient_list.head)
+  {
+    target_p = dl->data;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :GLIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    if (match(pattern, target_p->info))
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of GLIST.", me.name, source_p->name);
+}
+
+static void gl_local_regex(struct Client *client_p, struct Client *source_p,
+                           char *pattern, int lim, unsigned int flags)
+{
+  int retval;
+  dlink_node *dl;
+  struct Client *target_p;
+  regex_t reg;
+  int count = 0;
+
+  if (flags & UL_INSEN)
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+  }
+  else
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_NOSUB);
+  }
+
+  if (retval != 0)
+  {
+    char errbuf[BUFSIZE];
+    regerror(retval, &reg, errbuf, BUFSIZE);
+    sendto_one(source_p, ":%s NOTICE %s :GLIST regular expression error: %s",
+               me.name, source_p->name, errbuf);
+    regfree(&reg);
+    return;
+  }
+
+  DLINK_FOREACH(dl, lclient_list.head)
+  {
+    target_p = dl->data;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :GLIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    /* Using no flags here */
+    if (regexec(&reg, target_p->info, 0, NULL, 0) == 0)
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of GLIST.", me.name, source_p->name);
+  regfree(&reg);
+}
+
+static void gl_global_match(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim)
+{
+  dlink_node *dl;
+  struct Client *target_p;
+  int count = 0;
+
+  report_operspy(source_p, "GLIST [GLOBAL][MATCH]", pattern);
+
+  DLINK_FOREACH(dl, global_client_list.head)
+  { 
+    target_p = dl->data;
+
+    if (!IsPerson(target_p))
+      continue;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :GLIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    if (match(pattern, target_p->info))
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of GLIST.", me.name, source_p->name);
+}
+
+static void gl_global_regex(struct Client *client_p, struct Client *source_p,
+                            char *pattern, int lim, unsigned int flags)
+{
+  int retval;
+  dlink_node *dl;
+  struct Client *target_p;
+  regex_t reg;
+  int count = 0;
+  char osbuffer[BUFSIZE];
+
+  if (flags & UL_INSEN)
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+  }
+  else
+  {
+    retval = regcomp(&reg, pattern, REG_EXTENDED|REG_NOSUB);
+  }
+
+  if (retval != 0)
+  {
+    char errbuf[BUFSIZE];
+    regerror(retval, &reg, errbuf, BUFSIZE);
+    sendto_one(source_p, ":%s NOTICE %s :GLIST regular expression error: %s",
+               me.name, source_p->name, errbuf);
+    regfree(&reg);
+    return;
+  }
+
+  snprintf(osbuffer, sizeof(osbuffer), "[GLOBAL][REGEX]%s %s",
+           (flags & UL_INSEN) ? "[INSENS]" : "[SENS]", pattern);
+  report_operspy(source_p, "GLIST", osbuffer);
+
+  DLINK_FOREACH(dl, global_client_list.head)
+  {
+    target_p = dl->data;
+
+    if (!IsPerson(target_p))
+      continue;
+
+    if ((lim > 0) && (count == lim))
+    {
+      sendto_one(source_p, ":%s NOTICE %s :GLIST limit reached, %d clients "
+                 "shown", me.name, source_p->name, count);
+      return;
+    }
+    /* Using no flags here */
+    if (regexec(&reg, target_p->info, 0, NULL, 0) == 0)
+    {
+      count++;
+      sendto_one(source_p, ":%s NOTICE %s :User %d: %s (%s@%s) [%s]",
+                 me.name, source_p->name, count, target_p->name,
+                 target_p->username, target_p->host, target_p->user->server);
+    }
+  }
+  sendto_one(source_p, ":%s NOTICE %s :End of GLIST.", me.name, source_p->name);
+  regfree(&reg);
+}
+
+static void gl_usage(struct Client *source_p)
+{
+  sendto_one(source_p, ":%s NOTICE %s :Syntax:  /GLIST [-l|-g] [-m|-r] [-i|-s] "
+                       "[-x limit] pattern", me.name, source_p->name);
+}
diff -uNrd -x CVS ircd-ratbox-cvs/doc/example.conf ratbox-devel/doc/example.conf
--- ircd-ratbox-cvs/doc/example.conf	Mon Jul 26 12:04:16 2004
+++ ratbox-devel/doc/example.conf	Tue Jul 27 10:26:47 2004
@@ -259,6 +259,8 @@
          *                                     USE WITH CAUTION.
 	 * no_tilde     (old - flag)  | don't prefix ~ to username if no ident
 	 * need_ident   (old + flag)  | require ident for user in this class
+	 * restricted (not the old one)| clients may only join one specified
+	 *                            |  channel.
 	 */
 	flags = kline_exempt, exceed_limit;
 	
@@ -578,6 +580,11 @@
 
 	/* burst topicwho: when bursting topics, also burst the topic setter */
 	burst_topicwho = yes;
+
+	/* restricted_channel: the channel restricted clients are allowed to
+	 * join.  They are not allowed to join any others.
+	 */
+	restricted_channel = "#lobby";
 };
 
 
diff -uNrd -x CVS ircd-ratbox-cvs/include/client.h ratbox-devel/include/client.h
--- ircd-ratbox-cvs/include/client.h	Mon Jul 19 18:04:32 2004
+++ ratbox-devel/include/client.h	Tue Jul 27 09:21:42 2004
@@ -393,6 +393,7 @@
 #define FLAGS2_FLOODDONE        0x10000000
 #define FLAGS2_EXEMPTSPAMBOT	0x20000000
 #define FLAGS2_EXEMPTSHIDE	0x40000000
+#define FLAGS2_RESTRICTED	0x80000000
 
 #define SEND_UMODES  (UMODE_INVISIBLE | UMODE_OPER | UMODE_WALLOP | \
                       UMODE_ADMIN)
@@ -499,6 +500,9 @@
 
 #define IsFloodDone(x)          ((x)->flags2 & FLAGS2_FLOODDONE)
 #define SetFloodDone(x)         ((x)->flags2 |= FLAGS2_FLOODDONE)
+
+#define IsRestricted(x)		((x)->flags2 & FLAGS2_RESTRICTED)
+#define SetRestricted(x)	((x)->flags2 |= FLAGS2_RESTRICTED)
 
 /*
  * definitions for get_client_name
diff -uNrd -x CVS ircd-ratbox-cvs/include/config.h ratbox-devel/include/config.h
--- ircd-ratbox-cvs/include/config.h	Thu Jul 29 12:55:16 2004
+++ ratbox-devel/include/config.h	Sat Jul 31 11:15:26 2004
@@ -133,7 +133,7 @@
  * If this is undefined, opers will be allowed to see the real IP of spoofed
  * users in /trace etc.  If this is defined they will be shown a masked IP.
  */
-#define HIDE_SPOOF_IPS
+#undef HIDE_SPOOF_IPS
 
 /* TS6_ONLY
  *
diff -uNrd -x CVS ircd-ratbox-cvs/include/patchlevel.h ratbox-devel/include/patchlevel.h
--- ircd-ratbox-cvs/include/patchlevel.h	Sat Jul 31 11:07:43 2004
+++ ratbox-devel/include/patchlevel.h	Sat Jul 31 11:15:55 2004
@@ -31,6 +31,6 @@
 # define PL_SUFFIX "[vms]"
 #endif
 
-#define PATCHLEVEL   "ircd-ratbox-2.0.0" PL_SUFFIX
+#define PATCHLEVEL   "ircd-ratbox-2.0.0+botbay1" PL_SUFFIX
 
 #endif
diff -uNrd -x CVS ircd-ratbox-cvs/include/s_conf.h ratbox-devel/include/s_conf.h
--- ircd-ratbox-cvs/include/s_conf.h	Sat Jul 24 21:20:18 2004
+++ ratbox-devel/include/s_conf.h	Tue Jul 27 09:53:22 2004
@@ -115,6 +115,7 @@
 #define CONF_FLAGS_EXEMPTFLOOD          0x00004000
 #define CONF_FLAGS_EXEMPTSPAMBOT	0x00008000
 #define CONF_FLAGS_EXEMPTSHIDE		0x00010000
+#define CONF_FLAGS_RESTRICTED		0x00020000
 /* server flags */
 #define CONF_FLAGS_ALLOW_AUTO_CONN      0x00040000
 #define CONF_FLAGS_LAZY_LINK            0x00080000
@@ -137,6 +138,7 @@
 #define IsConfExemptFlood(x)    ((x)->flags & CONF_FLAGS_EXEMPTFLOOD)
 #define IsConfExemptSpambot(x)	((x)->flags & CONF_FLAGS_EXEMPTSPAMBOT)
 #define IsConfExemptShide(x)	((x)->flags & CONF_FLAGS_EXEMPTSHIDE)
+#define IsConfRestricted(x)	((x)->flags & CONF_FLAGS_RESTRICTED)
 #define IsConfIdlelined(x)      ((x)->flags & CONF_FLAGS_IDLE_LINED)
 #define IsConfDoIdentd(x)       ((x)->flags & CONF_FLAGS_DO_IDENTD)
 #define IsConfDoSpoofIp(x)      ((x)->flags & CONF_FLAGS_SPOOF_IP)
@@ -239,6 +241,7 @@
 #ifdef IPV6
 	int fallback_to_ip6_int;
 #endif
+	char restricted_channel[LOC_CHANNELLEN];
 };
 
 struct config_channel_entry
diff -uNrd -x CVS ircd-ratbox-cvs/include/send.h ratbox-devel/include/send.h
--- ircd-ratbox-cvs/include/send.h	Mon Mar 15 12:58:00 2004
+++ ratbox-devel/include/send.h	Tue Jul 27 10:35:18 2004
@@ -74,6 +74,8 @@
 extern void kill_client_serv_butone(struct Client *one, struct Client *source_p, 
 				    const char *pattern, ...) AFP(3, 4);
 
+extern void report_snotice(char *format, ...) AFP(1,2);
+
 #define L_ALL 	0
 #define L_OPER 	1
 #define L_ADMIN	2
diff -uNrd -x CVS ircd-ratbox-cvs/modules/Makefile.in ratbox-devel/modules/Makefile.in
--- ircd-ratbox-cvs/modules/Makefile.in	Thu Jun 17 19:18:48 2004
+++ ratbox-devel/modules/Makefile.in	Tue Jul 27 11:22:58 2004
@@ -85,6 +85,7 @@
   m_restart.c \
   m_resv.c \
   m_set.c \
+  m_snotice.c \
   m_stats.c \
   m_svinfo.c \
   m_tb.c \
diff -uNrd -x CVS ircd-ratbox-cvs/modules/core/m_join.c ratbox-devel/modules/core/m_join.c
--- ircd-ratbox-cvs/modules/core/m_join.c	Sat Jul 24 21:29:21 2004
+++ ratbox-devel/modules/core/m_join.c	Tue Jul 27 10:09:39 2004
@@ -117,6 +117,23 @@
 			continue;
 		}
 
+		/* If the client is restricted, not an oper, and is trying
+		 * to join something not listed as the restricted_channel,
+		 * deny it.
+		 */
+		if(IsRestricted(source_p) && !IsOper(source_p) && (ConfigFileEntry.restricted_channel[0] != '\0'))
+		{
+			if (irccmp(ConfigFileEntry.restricted_channel, name) != 0)
+			{
+				sendto_one_numeric(source_p, ERR_BADCHANNAME,
+					form_str(ERR_BADCHANNAME), name);
+				sendto_realops_flags(UMODE_SPY, L_ALL,
+					"Restricted user %s (%s@%s) is attempting to join %s",
+					source_p->name, source_p->username, source_p->host, name);
+				continue;
+			}
+		}
+
 		/* see if its resv'd */
 		if((aconf = hash_find_resv(name)) && (!IsOper(source_p) || !ConfigChannel.no_oper_resvs))
 		{
diff -uNrd -x CVS ircd-ratbox-cvs/modules/core/m_server.c ratbox-devel/modules/core/m_server.c
--- ircd-ratbox-cvs/modules/core/m_server.c	Mon Mar 29 07:40:21 2004
+++ ratbox-devel/modules/core/m_server.c	Tue Jul 27 11:19:11 2004
@@ -90,6 +90,8 @@
 	{
 		sendto_realops_flags(UMODE_ALL, L_ALL, "Link %s dropped, non-TS server",
 				     get_server_name(client_p, HIDE_IP));
+		report_snotice("Link %s dropped, non-TS server",
+				get_server_name(client_p, HIDE_IP));
 		exit_client(client_p, client_p, client_p, "Non-TS server");
 		return 0;
 	}
@@ -112,6 +114,8 @@
 					"No entry for servername %s",
 					get_server_name(client_p, HIDE_IP),
 					name);
+			report_snotice("Unauthorised server connection attempt from %s: No entry for servername %s",
+					get_server_name(client_p, HIDE_IP), name);
 
 			ilog(L_SERVER, "Access denied, No N line for server %s",
 			     log_client_name(client_p, SHOW_IP));
@@ -127,6 +131,8 @@
 				"Unauthorised server connection attempt from %s: "
 				"Bad password for server %s", 
 				get_server_name(client_p, HIDE_IP), name);
+		report_snotice("Unauthorised server connection attempt from %s: Bad password for server %s",
+				get_server_name(client_p, HIDE_IP), name);
 
 		ilog(L_SERVER, "Access denied, invalid password for server %s",
 		     log_client_name(client_p, SHOW_IP));
@@ -141,6 +147,8 @@
 				     "Unauthorised server connection attempt from %s: "
 				     "Invalid host for server %s", 
 				     get_server_name(client_p, HIDE_IP), name);
+		report_snotice("Unauthorised server connection attempt from %s: Invalid host for server %s",
+				get_server_name(client_p, HIDE_IP), name);
 
 		ilog(L_SERVER, "Access denied, invalid host for server %s",
 		     log_client_name(client_p, SHOW_IP));
@@ -155,6 +163,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Invalid servername %s from %s",
 				     name, get_server_name(client_p, HIDE_IP));
+		report_snotice("Invalid servername %s from %s",
+				name, get_server_name(client_p, HIDE_IP));
 		ilog(L_SERVER, "Access denied, invalid servername from %s",
 		     log_client_name(client_p, SHOW_IP));
 
@@ -180,6 +190,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Attempt to re-introduce server %s from %s",
 				     name, get_server_name(client_p, HIDE_IP));
+		report_snotice("Attempt to re-introduce server %s from %s",
+				name, get_server_name(client_p, HIDE_IP));
 
 		sendto_one(client_p, "ERROR :Server already exists.");
 		exit_client(client_p, client_p, client_p, "Server Exists");
@@ -192,6 +204,9 @@
 				     "Attempt to re-introduce SID %s from %s%s",
 				     client_p->id, name,
 				     get_server_name(client_p, HIDE_IP));
+		report_snotice("Attempt to re-introduce SID %s from %s%s",
+				client_p->id, name,
+				get_server_name(client_p, HIDE_IP));
 
 		sendto_one(client_p, "ERROR :SID already exists.");
 		exit_client(client_p, client_p, client_p, "SID Exists");
@@ -266,6 +281,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s cancelled, server %s already exists",
 				     get_server_name(client_p, SHOW_IP), name);
+		report_snotice("Link %s cancelled, server %s already exists",
+				get_server_name(client_p, SHOW_IP), name);
 
 		exit_client(client_p, client_p, &me, "Server Exists");
 		return 0;
@@ -286,6 +303,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s cancelled: Server/nick collision on %s",
 				     get_server_name(client_p, HIDE_IP), name);
+		report_snotice("Link %s cancelled: Server/nick collision on %s",
+				get_server_name(client_p, HIDE_IP), name);
 		exit_client(client_p, client_p, client_p, "Nick as Server");
 		return 0;
 	}
@@ -350,6 +369,8 @@
 		/* OOOPs nope can't HUB */
 		sendto_realops_flags(UMODE_ALL, L_ALL, "Non-Hub link %s introduced %s.",
 				     get_server_name(client_p, HIDE_IP), name);
+		report_snotice("Non-Hub link %s introduced %s.",
+				get_server_name(client_p, HIDE_IP), name);
 
 		exit_client(NULL, client_p, &me, "No matching hub_mask.");
 		return 0;
@@ -362,6 +383,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s introduced leafed server %s.",
 				     get_server_name(client_p, HIDE_IP), name);
+		report_snotice("Link %s introduced leafed server %s.",
+				get_server_name(client_p, HIDE_IP), name);
 
 		exit_client(NULL, client_p, &me, "Leafed Server.");
 		return 0;
@@ -374,6 +397,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s introduced server with invalid servername %s",
 				     get_server_name(client_p, HIDE_IP), name);
+		report_snotice("Link %s introduced server with invalid servername %s",
+				get_server_name(client_p, HIDE_IP), name);
 
 		exit_client(NULL, client_p, &me, "Invalid servername introduced.");
 		return 0;
@@ -434,6 +459,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s cancelled, server %s already exists",
 				     get_server_name(client_p, SHOW_IP), parv[1]);
+		report_snotice("Link %s cancelled, server %s already exists",
+				get_server_name(client_p, SHOW_IP), parv[1]);
 		exit_client(NULL, client_p, &me, "Server Exists");
 		return 0;
 	}
@@ -445,6 +472,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s cancelled, SID %s already exists",
 				     get_server_name(client_p, SHOW_IP), parv[3]);
+		report_snotice("Link %s cancelled, SID %s already exists",
+				get_server_name(client_p, SHOW_IP), parv[3]);
 		exit_client(NULL, client_p, &me, "Server Exists");
 		return 0;
 	}
@@ -455,6 +484,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s cancelled, servername %s invalid",
 				     get_server_name(client_p, SHOW_IP), parv[1]);
+		report_snotice("Link %s cancelled, servername %s invalid",
+				get_server_name(client_p, SHOW_IP), parv[1]);
 		exit_client(NULL, client_p, &me, "Bogus server name");
 		return 0;
 	}
@@ -466,6 +497,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s cancelled, SID %s invalid",
 				     get_server_name(client_p, SHOW_IP), parv[3]);
+		report_snotice("Link %s cancelled, SID %s invalid",
+				get_server_name(client_p, SHOW_IP), parv[3]);
 		exit_client(NULL, client_p, &me, "Bogus SID");
 		return 0;
 	}
@@ -495,6 +528,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Non-Hub link %s introduced %s.",
 				     get_server_name(client_p, SHOW_IP), parv[1]);
+		report_snotice("Non-Hub link %s introduced %s",
+				get_server_name(client_p, SHOW_IP), parv[1]);
 		exit_client(NULL, client_p, &me, "No matching hub_mask.");
 		return 0;
 	}
@@ -506,6 +541,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s introduced leafed server %s.",
 				     get_server_name(client_p, SHOW_IP), parv[1]);
+		report_snotice("Link %s introduced leafed server %s.",
+				get_server_name(client_p, SHOW_IP), parv[1]);
 		exit_client(NULL, client_p, &me, "Leafed Server.");
 		return 0;
 	}
diff -uNrd -x CVS ircd-ratbox-cvs/modules/core/m_squit.c ratbox-devel/modules/core/m_squit.c
--- ircd-ratbox-cvs/modules/core/m_squit.c	Mon Mar 15 12:58:06 2004
+++ ratbox-devel/modules/core/m_squit.c	Tue Jul 27 11:20:36 2004
@@ -88,6 +88,9 @@
 					     "Received SQUIT %s from %s (%s)",
 					     found_squit->target_p->name,
 					     get_client_name(source_p, HIDE_IP), comment);
+			report_snotice("Received SQUIT %s from %s (%s)",
+					found_squit->target_p->name,
+					get_client_name(source_p, HIDE_IP), comment);
 			ilog(L_SERVER, "Received SQUIT %s from %s (%s)",
 			     found_squit->target_p->name, log_client_name(source_p, HIDE_IP),
 			     comment);
@@ -136,6 +139,8 @@
 		sendto_wallops_flags(UMODE_WALLOP, &me,
 				     "Remote SQUIT %s from %s (%s)",
 				     target_p->name, source_p->name, comment);
+		report_snotice("Remote SQUIT %s from %s (%s)",
+				target_p->name, source_p->name, comment);
 
 		sendto_server(NULL, NULL, NOCAPS, NOCAPS,
 			      ":%s WALLOPS :Remote SQUIT %s from %s (%s)",
diff -uNrd -x CVS ircd-ratbox-cvs/modules/m_snotice.c ratbox-devel/modules/m_snotice.c
--- ircd-ratbox-cvs/modules/m_snotice.c	Wed Dec 31 19:00:00 1969
+++ ratbox-devel/modules/m_snotice.c	Tue Jul 27 10:57:08 2004
@@ -0,0 +1,61 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, m_snotice.c
+ *   Copyright (C) 2004 Jeremy Johnston
+ *
+ *   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)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id: example_module.c,v 1.10 2004/03/30 00:53:55 leeh Exp $
+ */
+
+/* List of ircd includes from ../include/ */
+#include "stdinc.h"
+#include "modules.h"
+#include "hook.h"
+#include "client.h"
+#include "ircd.h"
+#include "send.h"
+#include "s_conf.h"
+#include "sprintf_irc.h"
+#include "s_serv.h"
+
+static int mencap_snotice (struct Client *, struct Client *, int, const char **);
+
+struct Message snotice_msgtab = {
+    "SNOTICE",
+    0,
+    0,
+    0,
+    MFLG_SLOW,
+    {
+	mg_ignore,
+	mg_ignore,
+	mg_ignore,
+	mg_ignore,
+	{mencap_snotice, 2},
+	mg_ignore
+    }
+};
+
+mapi_clist_av1 snotice_clist[] = { &snotice_msgtab, NULL };
+
+DECLARE_MODULE_AV1(snotice, NULL, NULL, snotice_clist, NULL, NULL, "$Revision: 1.0 $");
+
+static int mencap_snotice (struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
+{
+    sendto_realops_flags(UMODE_SERVNOTICE, L_ALL,
+                         "SNOTICE from %s:  %s", source_p->name, parv[1]);
+    return 0;
+}
+
diff -uNrd -x CVS ircd-ratbox-cvs/modules/m_svinfo.c ratbox-devel/modules/m_svinfo.c
--- ircd-ratbox-cvs/modules/m_svinfo.c	Sun Apr  4 22:37:58 2004
+++ ratbox-devel/modules/m_svinfo.c	Tue Jul 27 10:45:59 2004
@@ -32,6 +32,7 @@
 #include "send.h"
 #include "s_conf.h"
 #include "s_log.h"
+#include "s_serv.h"
 #include "msg.h"
 #include "parse.h"
 #include "modules.h"
@@ -70,6 +71,8 @@
 		sendto_realops_flags(UMODE_ALL, L_ALL,
 				     "Link %s dropped, wrong TS protocol version (%s,%s)",
 				     get_server_name(source_p, SHOW_IP), parv[1], parv[2]);
+		report_snotice("Link %s dropped, wrong TS protocol version (%s,%s)",
+				   get_server_name(source_p, SHOW_IP), parv[1], parv[2]);
 		exit_client(source_p, source_p, source_p, "Incompatible TS version");
 		return 0;
 	}
@@ -88,6 +91,9 @@
 				     " (my TS=%ld, their TS=%ld, delta=%d)",
 				     get_server_name(source_p, SHOW_IP),
 				     (long) CurrentTime, (long) theirtime, deltat);
+		report_snotice("Link %s dropped, excessive TS delta (my TS=%ld, their TS=%ld, delta=%d)",
+				get_server_name(source_p, SHOW_IP),
+				(long) CurrentTime, (long) theirtime, deltat);
 		ilog(L_SERVER,
 		     "Link %s dropped, excessive TS delta"
 		     " (my TS=%ld, their TS=%ld, delta=%d)",
@@ -102,6 +108,8 @@
 				     "Link %s notable TS delta"
 				     " (my TS=%ld, their TS=%ld, delta=%d)",
 				     source_p->name, (long) CurrentTime, (long) theirtime, deltat);
+		report_snotice("Link %s notable TS delta (my TS=%ld, their TS=%ld, delta=%d)",
+				   source_p->name, (long) CurrentTime, (long) theirtime, deltat);
 	}
 
 	return 0;
diff -uNrd -x CVS ircd-ratbox-cvs/src/client.c ratbox-devel/src/client.c
--- ircd-ratbox-cvs/src/client.c	Sat Jul 24 11:14:45 2004
+++ ratbox-devel/src/client.c	Tue Jul 27 10:41:42 2004
@@ -1207,9 +1207,13 @@
  	 	dlinkDelete(ptr, &abort_list);
 
  	 	if(IsAnyServer(abt->client))
+		{
  	 	 	sendto_realops_flags(UMODE_ALL, L_ALL,
   	 	 	                     "Closing link to %s: %s",
    	 	 	                     get_server_name(abt->client, HIDE_IP), abt->notice);
+			report_snotice("Closing link to %s: %s",
+				get_server_name(abt->client, HIDE_IP), abt->notice);
+		}
 
 		/* its no longer on abort list */
  	 	exit_client(abt->client, abt->client, &me, abt->notice);
@@ -1454,6 +1458,8 @@
 	sendto_realops_flags(UMODE_ALL, L_ALL, "%s was connected"
 			     " for %ld seconds.  %d/%d sendK/recvK.",
 			     source_p->name, CurrentTime - source_p->firsttime, sendk, recvk);
+	report_snotice("%s was connected for %ld seconds.  %d/%d sendK/recvK.",
+		source_p->name, CurrentTime - source_p->firsttime, sendk, recvk);
 
 	ilog(L_SERVER, "%s was connected for %ld seconds.  %d/%d sendK/recvK.",
 	     source_p->name, CurrentTime - source_p->firsttime, sendk, recvk);
@@ -2113,6 +2119,9 @@
 					     "Server %s closed the connection",
 					     get_server_name(client_p, SHOW_IP));
 
+			report_snotice("Server %s closed the connection",
+				get_server_name(client_p, SHOW_IP));
+
 			ilog(L_SERVER, "Server %s closed the connection",
 			     log_client_name(client_p, SHOW_IP));
 		}
@@ -2130,6 +2139,11 @@
 				     (connected / 86400 == 1) ? "" : "s",
 				     (connected % 86400) / 3600,
 				     (connected % 3600) / 60, connected % 60);
+		report_snotice("%s had been connected for %d day%s, %2d:%02d:%02d",
+			client_p->name, connected / 86400,
+			(connected / 86400 == 1) ? "" : "s",
+			(connected % 86400) / 3600,
+			(connected % 3600) / 60, connected % 60);
 	}
 
 	if(error == 0)
diff -uNrd -x CVS ircd-ratbox-cvs/src/newconf.c ratbox-devel/src/newconf.c
--- ircd-ratbox-cvs/src/newconf.c	Sat Jul 24 21:20:23 2004
+++ ratbox-devel/src/newconf.c	Tue Jul 27 09:32:26 2004
@@ -445,6 +445,7 @@
 	{"no_tilde",		CONF_FLAGS_NO_TILDE	},
 	{"need_ident",		CONF_FLAGS_NEED_IDENTD	},
 	{"have_ident",		CONF_FLAGS_NEED_IDENTD	},
+	{"restricted",		CONF_FLAGS_RESTRICTED   },
 	{NULL, 0}
 };
 
@@ -2207,6 +2208,21 @@
 }
 
 static void
+conf_set_channel_restricted_channel(void *data)
+{
+        if(EmptyString((char *) data))
+        {
+                conf_report_error("Warning -- no channel listed.");
+		ConfigFileEntry.restricted_channel[0] = '\0';
+        }
+        else
+        {
+                strlcpy(ConfigFileEntry.restricted_channel, data,
+                        sizeof(ConfigFileEntry.restricted_channel));
+        }
+}
+
+static void
 conf_set_serverhide_flatten_links(void *data)
 {
 	ConfigServerHide.flatten_links = *(unsigned int *) data;
@@ -2644,6 +2660,7 @@
 	add_conf_item("channel", "no_join_on_split", CF_YESNO, conf_set_channel_no_join_on_split);
 	add_conf_item("channel", "no_oper_resvs", CF_YESNO, conf_set_channel_no_oper_resvs);
 	add_conf_item("channel", "burst_topicwho", CF_YESNO, conf_set_channel_burst_topicwho);
+	add_conf_item("channel", "restricted_channel", CF_QSTRING, conf_set_channel_restricted_channel);
 
 	add_top_conf("serverhide", NULL, NULL);
 	add_conf_item("serverhide", "flatten_links", CF_YESNO, conf_set_serverhide_flatten_links);
diff -uNrd -x CVS ircd-ratbox-cvs/src/restart.c ratbox-devel/src/restart.c
--- ircd-ratbox-cvs/src/restart.c	Mon Mar 15 12:58:08 2004
+++ ratbox-devel/src/restart.c	Tue Jul 27 10:42:03 2004
@@ -31,6 +31,7 @@
 #include "ircd.h"
 #include "send.h"
 #include "s_log.h"
+#include "s_serv.h"
 #include "client.h"		/* for FLAGS_ALL */
 #include "memory.h"
 
@@ -57,6 +58,7 @@
 	int i;
 
 	sendto_realops_flags(UMODE_ALL, L_ALL, "Restarting server...");
+	report_snotice("Restarting server...");
 
 	ilog(L_MAIN, "Restarting server...");
 	/*
diff -uNrd -x CVS ircd-ratbox-cvs/src/s_conf.c ratbox-devel/src/s_conf.c
--- ircd-ratbox-cvs/src/s_conf.c	Mon Jul 26 12:04:21 2004
+++ ratbox-devel/src/s_conf.c	Tue Jul 27 09:49:39 2004
@@ -765,6 +765,8 @@
 #ifdef IPV6
 	ConfigFileEntry.fallback_to_ip6_int = YES;
 #endif
+
+	ConfigFileEntry.restricted_channel[0] = '\0';
 }
 
 #undef YES
diff -uNrd -x CVS ircd-ratbox-cvs/src/s_serv.c ratbox-devel/src/s_serv.c
--- ircd-ratbox-cvs/src/s_serv.c	Tue Jul 20 15:51:04 2004
+++ ratbox-devel/src/s_serv.c	Tue Jul 27 10:43:24 2004
@@ -1124,6 +1124,9 @@
 			"Link with %s established: (%s) link",
 			get_server_name(client_p, SHOW_IP),
 			show_capabilities(client_p));
+	report_snotice("Link with %s established: (%s) link",
+			get_server_name(client_p, SHOW_IP),
+			show_capabilities(client_p));
 
 	ilog(L_SERVER, "Link with %s established: (%s) link",
 	     log_client_name(client_p, SHOW_IP), show_capabilities(client_p));
@@ -1654,6 +1657,7 @@
 		 * the others will.. --fl
 		 */
 		if(status == COMM_ERR_TIMEOUT)
+		{
 			sendto_realops_flags(UMODE_ALL, L_ALL,
 					"Error connecting to %s[%s]: %s",
 					client_p->name, 
@@ -1663,7 +1667,17 @@
 					client_p->host,
 #endif
 					comm_errstr(status));
+			report_snotice("Error connecting to %s[%s]: %s",
+					client_p->name,
+#ifdef HIDE_SERVERS_IPS
+                                        "255.255.255.255",
+#else
+                                        client_p->host,
+#endif
+                                        comm_errstr(status));
+		}
 		else
+		{
 			sendto_realops_flags(UMODE_ALL, L_ALL,
 					"Error connecting to %s[%s]: %s (%s)",
 					client_p->name,
@@ -1673,6 +1687,15 @@
 					client_p->host,
 #endif
 					comm_errstr(status), strerror(errno));
+			report_snotice("Error connecting to %s[%s]: %s (%s)",
+                                        client_p->name,
+#ifdef HIDE_SERVERS_IPS
+                                        "255.255.255.255",
+#else
+                                        client_p->host,
+#endif
+                                        comm_errstr(status), strerror(errno));
+		}
 
 		exit_client(client_p, client_p, &me, comm_errstr(status));
 		return;
diff -uNrd -x CVS ircd-ratbox-cvs/src/s_user.c ratbox-devel/src/s_user.c
--- ircd-ratbox-cvs/src/s_user.c	Tue Jul 20 11:47:29 2004
+++ ratbox-devel/src/s_user.c	Tue Jul 27 09:27:12 2004
@@ -759,6 +759,14 @@
 			   ":%s NOTICE %s :*** You are exempt from serverhiding.",
 			   me.name, source_p->name);
 	}
+
+	if(IsConfRestricted(aconf))
+	{
+		SetRestricted(source_p);
+		sendto_one(source_p,
+			   ":%s NOTICE %s :*** You are restricted.",
+			   me.name, source_p->name);
+	}
 }
 
 /*
diff -uNrd -x CVS ircd-ratbox-cvs/src/send.c ratbox-devel/src/send.c
--- ircd-ratbox-cvs/src/send.c	Sun Jun  6 20:39:45 2004
+++ ratbox-devel/src/send.c	Tue Jul 27 10:34:33 2004
@@ -1018,3 +1018,17 @@
 	linebuf_donebuf(&linebuf_id);
 	linebuf_donebuf(&linebuf_name);
 }
+
+void
+report_snotice(char *format, ...)
+{
+	va_list args;
+	char buffer[BUFSIZE];
+
+	va_start(args, format);
+	ircvsnprintf(buffer, sizeof(buffer), format, args);
+	va_end(args);
+
+	sendto_match_servs(&me, "*", CAP_ENCAP, NOCAPS,
+		"ENCAP * SNOTICE :%s", buffer);
+}
