Author: Isomer <isomer@coders.net>
[ircu2.10.12-pk.git] / ircd / m_stats.c
index 291f1c79a47e6060fdd71721e82bbe8cf6ad4674..abbf54cc735bc0cb7d1b50aa720abf3839123a95 100644 (file)
@@ -90,6 +90,7 @@
 /*
  * XXX - ack!!!
  */
+#include "s_stats.h"
 #include "channel.h"
 #include "class.h"
 #include "client.h"
 #include <stdlib.h>
 #include <string.h>
 
-/*
- * m_stats - generic message handler
- *
- *    parv[0] = sender prefix
- *    parv[1] = statistics selector (defaults to Message frequency)
- *    parv[2] = target server (current server defaulted, if omitted)
- * And 'stats l' and 'stats' L:
- *    parv[3] = server mask ("*" defaulted, if omitted)
- * Or for stats p,P:
- *    parv[3] = port mask (returns p-lines when its port is matched by this)
- * Or for stats k,K,i and I:
- *    parv[3] = [user@]host.name  (returns which K/I-lines match this)
- *           or [user@]host.mask  (returns which K/I-lines are mmatched by this)
- *              (defaults to old reply if ommitted, when local or Oper)
- *              A remote mask (something containing wildcards) is only
- *              allowed for IRC Operators.
- * Or for stats M:
- *    parv[3] = time param
- *    parv[4] = time param 
- *    (see report_memleak_stats() in runmalloc.c for details)
- *
- * This function is getting really ugly. -Ghostwolf
- */
-int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
-{
-  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
-      "RcveM RcveKBytes :Open since";
-  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
-  struct Message *mptr;
-  struct Client *acptr;
-  struct Gline* gline;
-  struct ConfItem *aconf;
-  char stat = parc > 1 ? parv[1][0] : '\0';
-  int i;
-
-/* m_stats is so obnoxiously full of special cases that the different
- * hunt_server() possiblites were becoming very messy. It now uses a
- * switch() so as to be easier to read and update as params change. 
- * -Ghostwolf 
- */
-  switch (stat)
-  {
-      /* open to all, standard # of params */
-    case 'U':
-    case 'u':
-    {
-      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-
-      /* open to all, varying # of params */
-    case 'k':
-    case 'K':
-    case 'i':
-    case 'I':
-    case 'p':
-    case 'P':
-    {
-      if (parc > 3)
-      {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      else
-      {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      break;
-    }
-
-      /* oper only, varying # of params */
-    case 'l':
-    case 'L':
-    case 'M':
-    {
-      if (parc == 4)
-      {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      else if (parc > 4)
-      {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
-            parv) != HUNTED_ISME)
-          return 0;
-      }
-      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
 
-      /* oper only, standard # of params */
-    default:
-    {
-      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
+int report_klines(struct Client* sptr, char* mask, int limit_query)
+{
+  int   wilds = 0;
+  int   count = 3;
+  char* user  = 0;
+  char* host;
+  const struct DenyConf* conf;
+
+  if (EmptyString(mask)) {
+    if (limit_query)
+      return need_more_params(sptr, "STATS K");
+    else
+      report_deny_list(sptr);
+    return 1;
   }
 
-  switch (stat)
-  {
-    case 'L':
-    case 'l':
-    {
-      int doall = 0, wilds = 0;
-      char *name = "*";
-      if (parc > 3 && *parv[3])
-      {
-        char *p;
-        name = parv[3];
-        wilds = (*name == '*' || *name == '?');
-        for (p = name + 1; *p; ++p)
-          if ((*p == '*' || *p == '?') && p[-1] != '\\')
-          {
-            wilds = 1;
-            break;
-          }
-      }
-      else
-        doall = 1;
-      /*
-       * Send info about connections which match, or all if the
-       * mask matches me.name.  Only restrictions are on those who
-       * are invisible not being visible to 'foreigners' who use
-       * a wild card based search to list it.
-       */
-      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
-      for (i = 0; i <= HighestFd; i++)
-      {
-        if (!(acptr = LocalClientArray[i]))
-          continue;
-        /* Don't return clients when this is a request for `all' */
-        if (doall && IsUser(acptr))
-          continue;
-        /* Don't show invisible people to unauthorized people when using
-         * wildcards  -- Is this still needed now /stats is oper only ? 
-         * Yeah it is -- non opers can /stats l, just not remotely.
-         */
-        if (IsInvisible(acptr) && (doall || wilds) &&
-            !(MyConnect(sptr) && IsOper(sptr)) &&
-            !IsAnOper(acptr) && (acptr != sptr))
-          continue;
-        /* Only show the ones that match the given mask - if any */
-        if (!doall && wilds && match(name, acptr->name))
-          continue;
-        /* Skip all that do not match the specific query */
-        if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
-          continue;
-        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
-                   acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
-                   (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
-                   CurrentTime - acptr->firsttime);
-      }
-      break;
-    }
-    case 'C':
-    case 'c':
-      report_configured_links(sptr, CONF_SERVER);
-      break;
-    case 'G':
-    case 'g': /* send glines */
-      gline_remove_expired(TStime());
-      for (gline = GlobalGlineList; gline; gline = gline->next) {
-        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
-                   sptr->name, 'G', gline->name, gline->host,
-                   gline->expire, gline->reason);
-      }
-      break;
-    case 'H':
-    case 'h':
-      break;
-    case 'I':
-    case 'i':
-    case 'K':
-    case 'k':                   /* display CONF_IPKILL as well
-                                   as CONF_KILL -Kev */
-    {
-      int wilds, count;
-      char *user, *host, *p;
-      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
-      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
-      {
-        report_configured_links(sptr, conf_status);
-        break;
-      }
-      if (parc < 4 || *parv[3] == '\0')
-        return need_more_params(sptr,
-                        (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
-
-      wilds = 0;
-      for (p = parv[3]; *p; p++)
-      {
-        if (*p == '\\')
-        {
-          if (!*++p)
-            break;
-          continue;
-        }
-        if (*p == '?' || *p == '*')
-        {
-          wilds = 1;
-          break;
-        }
-      }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
-      {
-        wilds = 0;
-        count = 3;
-      }
-      else
-        count = 1000;
-
-      if (conf_status == CONF_CLIENT)
-      {
-        user = 0;            /* Not used, but to avoid compiler warning. */
+  if (!limit_query) {
+    wilds = string_has_wildcards(mask);
+    count = 1000;
+  }
 
-        host = parv[3];
-      }
-      else
-      {
-        if ((host = strchr(parv[3], '@')))
-        {
-          user = parv[3];
-          *host++ = 0;;
-        }
-        else
-        {
-          user = 0;
-          host = parv[3];
-        }
-      }
-      for (aconf = GlobalConfList; aconf; aconf = aconf->next)
-      {
-        if ((aconf->status & conf_status))
-        {
-          if (conf_status == CONF_KLINE)
-          {
-            if ((!wilds && ((user || aconf->host[1]) &&
-                !match(aconf->host, host) &&
-                (!user || !match(aconf->name, user)))) ||
-                (wilds && !mmatch(host, aconf->host) &&
-                (!user || !mmatch(user, aconf->name))))
-            {
-              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
-                  sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
-                  aconf->port, get_conf_class(aconf));
-              if (--count == 0)
-                break;
-            }
-          }
-          else if (conf_status == CONF_CLIENT)
-          {
-            if ((!wilds && (!match(aconf->host, host) ||
-                !match(aconf->name, host))) ||
-                (wilds && (!mmatch(host, aconf->host) ||
-                !mmatch(host, aconf->name))))
-            {
-              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
-                  sptr->name, 'I', aconf->host, aconf->name,
-                  aconf->port, get_conf_class(aconf));
-              if (--count == 0)
-                break;
-            }
-          }
-        }
-      }
-      break;
-    }
-    case 'M':
-#if !defined(NDEBUG)
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
-          me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
-#endif
+  if ((host = strchr(mask, '@'))) {
+    user = mask;
+    *host++ = '\0';
+  }
+  else {
+    host = mask;
+  }
 
-#if 0
-#ifdef MEMSIZESTATS
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
-          me.name, parv[0], get_mem_size(), get_alloc_cnt());
-#endif
-#ifdef MEMLEAKSTATS
-      report_memleak_stats(sptr, parc, parv);
-#endif
-#if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
-      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
-          "is not enabled on this server", me.name, parv[0]);
-#endif
-#endif /* 0 */
-      break;
-    case 'm':
-      for (mptr = msgtab; mptr->cmd; mptr++)
-        if (mptr->count)
-          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
-              me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
-      break;
-    case 'o':
-    case 'O':
-      report_configured_links(sptr, CONF_OPS);
-      break;
-    case 'p':
-    case 'P':
-      /*
-       * show listener ports
-       * show hidden ports to opers, if there are more than 3 parameters,
-       * interpret the fourth parameter as the port number, limit non-local
-       * or non-oper results to 8 ports.
-       */ 
-      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, 
-                 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
-      break;
-    case 'R':
-    case 'r':
-#ifdef DEBUGMODE
-      send_usage(sptr, parv[0]);
-#endif
-      break;
-    case 'D':
-      report_configured_links(sptr, CONF_CRULEALL);
-      break;
-    case 'd':
-      report_configured_links(sptr, CONF_CRULE);
-      break;
-    case 't':
-      tstats(sptr, parv[0]);
-      break;
-    case 'T':
-      report_configured_links(sptr, CONF_TLINES);
-      break;
-    case 'U':
-      report_configured_links(sptr, CONF_UWORLD);
-      break;
-    case 'u':
+  for (conf = conf_get_deny_list(); conf; conf = conf->next) {
+    if ((!wilds && ((user || conf->hostmask) &&
+       !match(conf->hostmask, host) &&
+       (!user || !match(conf->usermask, user)))) ||
+       (wilds && !mmatch(host, conf->hostmask) &&
+       (!user || !mmatch(user, conf->usermask))))
     {
-      time_t nowr;
-
-      nowr = CurrentTime - me.since;
-      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
-          nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
-      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
-          max_connection_count, max_client_count);
-      break;
+      send_reply(sptr, RPL_STATSKLINE, (conf->ip_kill) ? 'k' : 'K',
+                 conf->hostmask, conf->message, conf->usermask);
+      if (--count == 0)
+       return 1;
     }
-    case 'W':
-    case 'w':
-      calc_load(sptr);
-      break;
-    case 'X':
-    case 'x':
-#ifdef  DEBUGMODE
-      send_listinfo(sptr, parv[0]);
-#endif
-      break;
-    case 'Y':
-    case 'y':
-      report_classes(sptr);
-      break;
-    case 'Z':
-    case 'z':
-      count_memory(sptr, parv[0]);
-      break;
-    default:
-      stat = '*';
-      break;
   }
-  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
-  return 0;
+  /* send_reply(sptr, RPL_ENDOFSTATS, stat); */
+  return 1;
 }
 
+
 /*
- * ms_stats - server message handler
+ * m_stats - generic message handler
  *
  *    parv[0] = sender prefix
  *    parv[1] = statistics selector (defaults to Message frequency)
@@ -520,109 +193,30 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
  *
  * This function is getting really ugly. -Ghostwolf
  */
-int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
-      "RcveM RcveKBytes :Open since";
-  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
   struct Message *mptr;
   struct Client *acptr;
-  struct Gline* gline;
   struct ConfItem *aconf;
   char stat = parc > 1 ? parv[1][0] : '\0';
+  const char **infotext = statsinfo;
   int i;
 
-/* m_stats is so obnoxiously full of special cases that the different
- * hunt_server() possiblites were becoming very messy. It now uses a
- * switch() so as to be easier to read and update as params change. 
- * -Ghostwolf 
- */
-  switch (stat)
-  {
-      /* open to all, standard # of params */
-    case 'U':
-    case 'u':
-    {
-      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-
-      /* open to all, varying # of params */
-    case 'k':
-    case 'K':
-    case 'i':
-    case 'I':
-    case 'p':
-    case 'P':
-    {
-      if (parc > 3)
-      {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      else
-      {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      break;
-    }
-
-      /* oper only, varying # of params */
-    case 'l':
-    case 'L':
-    case 'M':
-    {
-      if (parc == 4)
-      {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      else if (parc > 4)
-      {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
-            parv) != HUNTED_ISME)
-          return 0;
-      }
-      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-
-      /* oper only, standard # of params */
-    default:
-    {
-      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-  }
+  if (hunt_stats(cptr, sptr, parc, parv, stat) != HUNTED_ISME)
+    return 0;
 
   switch (stat)
   {
     case 'L':
     case 'l':
     {
-      int doall = 0, wilds = 0;
+      int doall = 0;
+      int wilds = 0;
       char *name = "*";
-      if (parc > 3 && *parv[3])
-      {
-        char *p;
+
+      if (parc > 3 && !EmptyString(parv[3])) {
         name = parv[3];
-        wilds = (*name == '*' || *name == '?');
-        for (p = name + 1; *p; ++p)
-          if ((*p == '*' || *p == '?') && p[-1] != '\\')
-          {
-            wilds = 1;
-            break;
-          }
+        wilds = string_has_wildcards(name);
       }
       else
         doall = 1;
@@ -632,7 +226,8 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
        * are invisible not being visible to 'foreigners' who use
        * a wild card based search to list it.
        */
-      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
+      send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ "
+                 "SendM SendKBytes RcveM RcveKBytes :Open since");
       for (i = 0; i <= HighestFd; i++)
       {
         if (!(acptr = LocalClientArray[i]))
@@ -640,11 +235,8 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
         /* Don't return clients when this is a request for `all' */
         if (doall && IsUser(acptr))
           continue;
-        /* Don't show invisible people to unauthorized people when using
-         * wildcards  -- Is this still needed now /stats is oper only ? */
-        if (IsInvisible(acptr) && (doall || wilds) &&
-            !(MyConnect(sptr) && IsOper(sptr)) &&
-            !IsAnOper(acptr) && (acptr != sptr))
+        /* Don't show invisible people to non opers unless they know the nick */
+        if (IsInvisible(acptr) && (doall || wilds) && !IsAnOper(acptr) && (acptr != sptr))
           continue;
         /* Only show the ones that match the given mask - if any */
         if (!doall && wilds && match(name, acptr->name))
@@ -652,144 +244,80 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
         /* Skip all that do not match the specific query */
         if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
           continue;
-        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
-            acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
-            (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
-            CurrentTime - acptr->firsttime);
+        send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO,
+                   "%s %u %u %u %u %u :%Tu", (*acptr->name) ? acptr->name : "<unregistered>",
+                   (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
+                   (int)acptr->sendK, (int)acptr->receiveM,
+                   (int)acptr->receiveK, CurrentTime - acptr->firsttime);
       }
       break;
     }
     case 'C':
     case 'c':
-      if (IsAnOper(sptr))
-        report_configured_links(sptr, CONF_SERVER);
+      report_configured_links(sptr, CONF_SERVER);
       break;
     case 'G':
     case 'g': /* send glines */
-      gline_remove_expired(TStime());
-      for (gline = GlobalGlineList; gline; gline = gline->next) {
-        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
-                   sptr->name, 'G', gline->name, gline->host,
-                   gline->expire, gline->reason);
-      }
+      gline_stats(sptr);
       break;
     case 'H':
     case 'h':
       report_configured_links(sptr, CONF_HUB | CONF_LEAF);
       break;
+    case 'K':
+    case 'k':    /* display CONF_IPKILL as well as CONF_KILL -Kev */
+      if (0 == report_klines(sptr, (parc == 4) ? parv[3] : 0, 0))
+        return 0;
+      break;
     case 'I':
     case 'i':
-    case 'K':
-    case 'k':                   /* display CONF_IPKILL as well
-                                   as CONF_KILL -Kev */
     {
-      int wilds, count;
-      char *user, *host, *p;
-      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
-      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
-      {
-        report_configured_links(sptr, conf_status);
+      int wilds = 0;
+      int count = 1000;
+      char* host;
+
+      if (parc < 4) {
+        report_configured_links(sptr, CONF_CLIENT);
         break;
       }
-      if (parc < 4 || *parv[3] == '\0')
-        return need_more_params(sptr,
-                        (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
+      if (EmptyString(parv[3]))
+        return need_more_params(sptr, "STATS I");
 
-      wilds = 0;
-      for (p = parv[3]; *p; p++)
-      {
-        if (*p == '\\')
-        {
-          if (!*++p)
-            break;
-          continue;
-        }
-        if (*p == '?' || *p == '*')
-        {
-          wilds = 1;
-          break;
-        }
-      }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
-      {
-        wilds = 0;
-        count = 3;
-      }
-      else
-        count = 1000;
+      host = parv[3];
+      wilds = string_has_wildcards(host);
 
-      if (conf_status == CONF_CLIENT)
-      {
-        user = 0;            /* Not used, but to avoid compiler warning. */
-
-        host = parv[3];
-      }
-      else
-      {
-        if ((host = strchr(parv[3], '@')))
-        {
-          user = parv[3];
-          *host++ = 0;;
-        }
-        else
-        {
-          user = 0;
-          host = parv[3];
-        }
-      }
-      for (aconf = GlobalConfList; aconf; aconf = aconf->next)
-      {
-        if ((aconf->status & conf_status))
-        {
-          if (conf_status == CONF_KLINE)
-          {
-            if ((!wilds && ((user || aconf->host[1]) &&
-                !match(aconf->host, host) &&
-                (!user || !match(aconf->name, user)))) ||
-                (wilds && !mmatch(host, aconf->host) &&
-                (!user || !mmatch(user, aconf->name))))
-            {
-              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
-                  sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
-                  aconf->port, get_conf_class(aconf));
-              if (--count == 0)
-                break;
-            }
-          }
-          else if (conf_status == CONF_CLIENT)
-          {
-            if ((!wilds && (!match(aconf->host, host) ||
-                !match(aconf->name, host))) ||
-                (wilds && (!mmatch(host, aconf->host) ||
-                !mmatch(host, aconf->name))))
-            {
-              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
-                  sptr->name, 'I', aconf->host, aconf->name,
-                  aconf->port, get_conf_class(aconf));
-              if (--count == 0)
-                break;
-            }
-          }
-        }
+      for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+       if (CONF_CLIENT == aconf->status) {
+         if ((!wilds && (!match(aconf->host, host) ||
+             !match(aconf->name, host))) ||
+             (wilds && (!mmatch(host, aconf->host) ||
+             !mmatch(host, aconf->name))))
+         {
+           send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, aconf->name,
+                      aconf->port, get_conf_class(aconf));
+           if (--count == 0)
+             break;
+         }
+       }
       }
       break;
     }
     case 'M':
 #if !defined(NDEBUG)
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
-          me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
+      send_reply(sptr, RPL_STATMEMTOT, fda_get_byte_count(),
+                 fda_get_block_count());
 #endif
 
 #if 0
 #ifdef MEMSIZESTATS
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT), /* XXX DEAD */
           me.name, parv[0], get_mem_size(), get_alloc_cnt());
 #endif
 #ifdef MEMLEAKSTATS
       report_memleak_stats(sptr, parc, parv);
 #endif
 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
-      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
+      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring " /* XXX DEAD */
           "is not enabled on this server", me.name, parv[0]);
 #endif
 #endif /* 0 */
@@ -797,8 +325,8 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     case 'm':
       for (mptr = msgtab; mptr->cmd; mptr++)
         if (mptr->count)
-          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
-              me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
+          send_reply(sptr, RPL_STATSCOMMANDS, mptr->cmd, mptr->count,
+                     mptr->bytes);
       break;
     case 'o':
     case 'O':
@@ -809,11 +337,9 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       /*
        * show listener ports
        * show hidden ports to opers, if there are more than 3 parameters,
-       * interpret the fourth parameter as the port number, limit non-local
-       * or non-oper results to 8 ports.
+       * interpret the fourth parameter as the port number.
        */ 
-      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, 
-                 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
+      show_ports(sptr, 0, (parc > 3) ? atoi(parv[3]) : 0, 100);
       break;
     case 'R':
     case 'r':
@@ -822,16 +348,16 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 #endif
       break;
     case 'D':
-      report_configured_links(sptr, CONF_CRULEALL);
+      report_crule_list(sptr, CRULE_ALL);
       break;
     case 'd':
-      report_configured_links(sptr, CONF_CRULE);
+      report_crule_list(sptr, CRULE_MASK);
       break;
     case 't':
       tstats(sptr, parv[0]);
       break;
     case 'T':
-      report_configured_links(sptr, CONF_TLINES);
+      report_motd_list(sptr);
       break;
     case 'U':
       report_configured_links(sptr, CONF_UWORLD);
@@ -841,10 +367,9 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       time_t nowr;
 
       nowr = CurrentTime - me.since;
-      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
-          nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
-      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
-          max_connection_count, max_client_count);
+      send_reply(sptr, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24,
+                 (nowr / 60) % 60, nowr % 60);
+      send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count);
       break;
     }
     case 'W':
@@ -854,6 +379,7 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     case 'X':
     case 'x':
 #ifdef  DEBUGMODE
+      class_send_meminfo(sptr);
       send_listinfo(sptr, parv[0]);
 #endif
       break;
@@ -867,14 +393,16 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       break;
     default:
       stat = '*';
+      while (*infotext)
+        sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, *infotext++);
       break;
   }
-  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
+  send_reply(sptr, RPL_ENDOFSTATS, stat);
   return 0;
 }
 
 /*
- * mo_stats - oper message handler
+ * ms_stats - server message handler
  *
  *    parv[0] = sender prefix
  *    parv[1] = statistics selector (defaults to Message frequency)
@@ -896,109 +424,29 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
  *
  * This function is getting really ugly. -Ghostwolf
  */
-int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
-      "RcveM RcveKBytes :Open since";
-  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
   struct Message *mptr;
   struct Client *acptr;
-  struct Gline* gline;
   struct ConfItem *aconf;
   char stat = parc > 1 ? parv[1][0] : '\0';
   int i;
 
-/* m_stats is so obnoxiously full of special cases that the different
- * hunt_server() possiblites were becoming very messy. It now uses a
- * switch() so as to be easier to read and update as params change. 
- * -Ghostwolf 
- */
-  switch (stat)
-  {
-      /* open to all, standard # of params */
-    case 'U':
-    case 'u':
-    {
-      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-
-      /* open to all, varying # of params */
-    case 'k':
-    case 'K':
-    case 'i':
-    case 'I':
-    case 'p':
-    case 'P':
-    {
-      if (parc > 3)
-      {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      else
-      {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      break;
-    }
-
-      /* oper only, varying # of params */
-    case 'l':
-    case 'L':
-    case 'M':
-    {
-      if (parc == 4)
-      {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      else if (parc > 4)
-      {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
-            parv) != HUNTED_ISME)
-          return 0;
-      }
-      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-
-      /* oper only, standard # of params */
-    default:
-    {
-      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-  }
+  if (hunt_stats(cptr, sptr, parc, parv, stat) != HUNTED_ISME)
+    return 0;
 
   switch (stat)
   {
     case 'L':
     case 'l':
     {
-      int doall = 0, wilds = 0;
+      int doall = 0;
+      int wilds = 0;
       char *name = "*";
-      if (parc > 3 && *parv[3])
-      {
-        char *p;
+
+      if (parc > 3 && !EmptyString(parv[3])) {
         name = parv[3];
-        wilds = (*name == '*' || *name == '?');
-        for (p = name + 1; *p; ++p)
-          if ((*p == '*' || *p == '?') && p[-1] != '\\')
-          {
-            wilds = 1;
-            break;
-          }
+        wilds = string_has_wildcards(name);
       }
       else
         doall = 1;
@@ -1008,7 +456,8 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
        * are invisible not being visible to 'foreigners' who use
        * a wild card based search to list it.
        */
-      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
+      send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ "
+                 "SendM SendKBytes RcveM RcveKBytes :Open since");
       for (i = 0; i <= HighestFd; i++)
       {
         if (!(acptr = LocalClientArray[i]))
@@ -1017,21 +466,20 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
         if (doall && IsUser(acptr))
           continue;
         /* Don't show invisible people to unauthorized people when using
-         * wildcards  -- Is this still needed now /stats is oper only ? */
-        if (IsInvisible(acptr) && (doall || wilds) &&
-            !(MyConnect(sptr) && IsOper(sptr)) &&
-            !IsAnOper(acptr) && (acptr != sptr))
-          continue;
+         * wildcards  -- Is this still needed now /stats is oper only ? 
+         * Not here, because ms_stats is specifically a remote command, 
+         * thus the check was removed. -Ghostwolf */
         /* Only show the ones that match the given mask - if any */
         if (!doall && wilds && match(name, acptr->name))
           continue;
         /* Skip all that do not match the specific query */
         if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
           continue;
-        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
-            acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
-            (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
-            CurrentTime - acptr->firsttime);
+        send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO,
+                   "%s %u %u %u %u %u :%Tu", acptr->name,
+                   (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
+                   (int)acptr->sendK, (int)acptr->receiveM,
+                   (int)acptr->receiveK, CurrentTime - acptr->firsttime);
       }
       break;
     }
@@ -1041,130 +489,70 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       break;
     case 'G':
     case 'g': /* send glines */
-      gline_remove_expired(TStime());
-      for (gline = GlobalGlineList; gline; gline = gline->next) {
-        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
-                   sptr->name, 'G', gline->name, gline->host,
-                   gline->expire, gline->reason);
-      }
+      gline_stats(sptr);
       break;
     case 'H':
     case 'h':
       report_configured_links(sptr, CONF_HUB | CONF_LEAF);
       break;
+    case 'K':
+    case 'k':    /* display CONF_IPKILL as well as CONF_KILL -Kev */
+      if (0 == report_klines(sptr, (parc > 3) ? parv[3] : 0, !IsOper(sptr)))
+        return 0;
+      break;
     case 'I':
     case 'i':
-    case 'K':
-    case 'k':                   /* display CONF_IPKILL as well
-                                   as CONF_KILL -Kev */
     {
-      int wilds, count;
-      char *user, *host, *p;
-      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
-      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
-      {
-        report_configured_links(sptr, conf_status);
+      int   wilds = 0;
+      int   count = 3;
+      char* host;
+
+      if (parc < 4 && IsOper(sptr)) {
+        report_configured_links(sptr, CONF_CLIENT);
         break;
       }
-      if (parc < 4 || *parv[3] == '\0')
-        return need_more_params(sptr,
-                        (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
+      if (parc < 4 || EmptyString(parv[3]))
+        return need_more_params(sptr, "STATS I");
 
-      wilds = 0;
-      for (p = parv[3]; *p; p++)
-      {
-        if (*p == '\\')
-        {
-          if (!*++p)
-            break;
-          continue;
-        }
-        if (*p == '?' || *p == '*')
-        {
-          wilds = 1;
-          break;
-        }
-      }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
-      {
-        wilds = 0;
-        count = 3;
-      }
-      else
+      if (IsOper(sptr)) {
+        wilds = string_has_wildcards(parv[3]);
         count = 1000;
+      }
 
-      if (conf_status == CONF_CLIENT)
-      {
-        user = 0;            /* Not used, but to avoid compiler warning. */
+      host = parv[3];
 
-        host = parv[3];
-      }
-      else
-      {
-        if ((host = strchr(parv[3], '@')))
-        {
-          user = parv[3];
-          *host++ = 0;;
-        }
-        else
-        {
-          user = 0;
-          host = parv[3];
-        }
-      }
-      for (aconf = GlobalConfList; aconf; aconf = aconf->next)
-      {
-        if ((aconf->status & conf_status))
-        {
-          if (conf_status == CONF_KLINE)
-          {
-            if ((!wilds && ((user || aconf->host[1]) &&
-                !match(aconf->host, host) &&
-                (!user || !match(aconf->name, user)))) ||
-                (wilds && !mmatch(host, aconf->host) &&
-                (!user || !mmatch(user, aconf->name))))
-            {
-              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
-                  sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
-                  aconf->port, get_conf_class(aconf));
-              if (--count == 0)
-                break;
-            }
-          }
-          else if (conf_status == CONF_CLIENT)
-          {
-            if ((!wilds && (!match(aconf->host, host) ||
-                !match(aconf->name, host))) ||
-                (wilds && (!mmatch(host, aconf->host) ||
-                !mmatch(host, aconf->name))))
-            {
-              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
-                  sptr->name, 'I', aconf->host, aconf->name,
-                  aconf->port, get_conf_class(aconf));
-              if (--count == 0)
-                break;
-            }
-          }
-        }
+      for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+       if (CONF_CLIENT == aconf->status) {
+         if ((!wilds && (!match(aconf->host, host) ||
+             !match(aconf->name, host))) ||
+             (wilds && (!mmatch(host, aconf->host) ||
+             !mmatch(host, aconf->name))))
+         {
+           send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, aconf->name,
+                      aconf->port, get_conf_class(aconf));
+           if (--count == 0)
+             break;
+         }
+       }
       }
       break;
     }
     case 'M':
 #if !defined(NDEBUG)
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
-          me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
+      send_reply(sptr, RPL_STATMEMTOT, fda_get_byte_count(),
+                 fda_get_block_count());
 #endif
 
 #if 0
 #ifdef MEMSIZESTATS
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT), /* XXX DEAD */
           me.name, parv[0], get_mem_size(), get_alloc_cnt());
 #endif
 #ifdef MEMLEAKSTATS
       report_memleak_stats(sptr, parc, parv);
 #endif
 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
-      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
+      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring " /* XXX DEAD */
           "is not enabled on this server", me.name, parv[0]);
 #endif
 #endif /* 0 */
@@ -1172,8 +560,8 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     case 'm':
       for (mptr = msgtab; mptr->cmd; mptr++)
         if (mptr->count)
-          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
-              me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
+          send_reply(sptr, RPL_STATSCOMMANDS, mptr->cmd, mptr->count,
+                     mptr->bytes);
       break;
     case 'o':
     case 'O':
@@ -1187,8 +575,7 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
        * interpret the fourth parameter as the port number, limit non-local
        * or non-oper results to 8 ports.
        */ 
-      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, 
-                 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
+      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, IsOper(sptr) ? 100 : 8);
       break;
     case 'R':
     case 'r':
@@ -1197,16 +584,16 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 #endif
       break;
     case 'D':
-      report_configured_links(sptr, CONF_CRULEALL);
+      report_crule_list(sptr, CRULE_ALL);
       break;
     case 'd':
-      report_configured_links(sptr, CONF_CRULE);
+      report_crule_list(sptr, CRULE_MASK);
       break;
     case 't':
       tstats(sptr, parv[0]);
       break;
     case 'T':
-      report_configured_links(sptr, CONF_TLINES);
+      report_motd_list(sptr);
       break;
     case 'U':
       report_configured_links(sptr, CONF_UWORLD);
@@ -1216,10 +603,9 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       time_t nowr;
 
       nowr = CurrentTime - me.since;
-      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
-          nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
-      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
-          max_connection_count, max_client_count);
+      send_reply(sptr, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24,
+                 (nowr / 60) % 60, nowr % 60);
+      send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count);
       break;
     }
     case 'W':
@@ -1229,6 +615,7 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     case 'X':
     case 'x':
 #ifdef  DEBUGMODE
+      class_send_meminfo(sptr);
       send_listinfo(sptr, parv[0]);
 #endif
       break;
@@ -1244,13 +631,12 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       stat = '*';
       break;
   }
-  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
+  send_reply(sptr, RPL_ENDOFSTATS, stat);
   return 0;
 }
 
-#if 0
 /*
- * m_stats
+ * mo_stats - oper message handler
  *
  *    parv[0] = sender prefix
  *    parv[1] = statistics selector (defaults to Message frequency)
@@ -1272,90 +658,17 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
  *
  * This function is getting really ugly. -Ghostwolf
  */
-int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
 {
-  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
-      "RcveM RcveKBytes :Open since";
-  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
-  struct Message *mptr;
-  struct Client *acptr;
-  struct Gline* gline;
-  struct ConfItem *aconf;
-  char stat = parc > 1 ? parv[1][0] : '\0';
-  int i;
+  struct Message*  mptr;
+  struct Client*   acptr;
+  struct ConfItem* aconf;
+  char             stat = parc > 1 ? parv[1][0] : '\0';
+  const char**     infotext = statsinfo;
+  int              i;
 
-/* m_stats is so obnoxiously full of special cases that the different
- * hunt_server() possiblites were becoming very messy. It now uses a
- * switch() so as to be easier to read and update as params change. 
- * -Ghostwolf 
- */
-  switch (stat)
-  {
-      /* open to all, standard # of params */
-    case 'U':
-    case 'u':
-    {
-      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-
-      /* open to all, varying # of params */
-    case 'k':
-    case 'K':
-    case 'i':
-    case 'I':
-    case 'p':
-    case 'P':
-    {
-      if (parc > 3)
-      {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      else
-      {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      break;
-    }
-
-      /* oper only, varying # of params */
-    case 'l':
-    case 'L':
-    case 'M':
-    {
-      if (parc == 4)
-      {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
-            != HUNTED_ISME)
-          return 0;
-      }
-      else if (parc > 4)
-      {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
-            parv) != HUNTED_ISME)
-          return 0;
-      }
-      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-
-      /* oper only, standard # of params */
-    default:
-    {
-      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
-          != HUNTED_ISME)
-        return 0;
-      break;
-    }
-  }
+  if (hunt_stats(cptr, sptr, parc, parv, stat) != HUNTED_ISME)
+    return 0;
 
   switch (stat)
   {
@@ -1363,18 +676,10 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     case 'l':
     {
       int doall = 0, wilds = 0;
-      char *name = "*";
-      if (parc > 3 && *parv[3])
-      {
-        char *p;
+      char* name = "*";
+      if (parc > 3 && !EmptyString(parv[3])) {
         name = parv[3];
-        wilds = (*name == '*' || *name == '?');
-        for (p = name + 1; *p; ++p)
-          if ((*p == '*' || *p == '?') && p[-1] != '\\')
-          {
-            wilds = 1;
-            break;
-          }
+        wilds = string_has_wildcards(name);
       }
       else
         doall = 1;
@@ -1384,7 +689,8 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
        * are invisible not being visible to 'foreigners' who use
        * a wild card based search to list it.
        */
-      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
+      send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ "
+                 "SendM SendKBytes RcveM RcveKBytes :Open since");
       for (i = 0; i <= HighestFd; i++)
       {
         if (!(acptr = LocalClientArray[i]))
@@ -1392,23 +698,17 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
         /* Don't return clients when this is a request for `all' */
         if (doall && IsUser(acptr))
           continue;
-        /* Don't show invisible people to unauthorized people when using
-         * wildcards  -- Is this still needed now /stats is oper only ? */
-        if (IsInvisible(acptr) && (doall || wilds) &&
-            !(MyConnect(sptr) && IsOper(sptr)) &&
-            !IsAnOper(acptr) && (acptr != sptr))
-          continue;
         /* Only show the ones that match the given mask - if any */
         if (!doall && wilds && match(name, acptr->name))
           continue;
         /* Skip all that do not match the specific query */
         if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
           continue;
-        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
-                   acptr->name,
+        send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO,
+                   "%s %u %u %u %u %u :%Tu", acptr->name,
                    (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
-                   (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
-                   CurrentTime - acptr->firsttime);
+                   (int)acptr->sendK, (int)acptr->receiveM,
+                   (int)acptr->receiveK, CurrentTime - acptr->firsttime);
       }
       break;
     }
@@ -1418,130 +718,66 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
       break;
     case 'G':
     case 'g': /* send glines */
-      gline_remove_expired(TStime());
-      for (gline = GlobalGlineList; gline; gline = gline->next) {
-        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
-                   sptr->name, 'G', gline->name, gline->host,
-                   gline->expire, gline->reason);
-      }
+      gline_stats(sptr);
       break;
     case 'H':
     case 'h':
       report_configured_links(sptr, CONF_HUB | CONF_LEAF);
       break;
+    case 'K':
+    case 'k':    /* display CONF_IPKILL as well as CONF_KILL -Kev */
+      if (0 == report_klines(sptr, (parc > 3) ? parv[3] : 0, 0))
+        return 0;
+      break;
     case 'I':
     case 'i':
-    case 'K':
-    case 'k':                   /* display CONF_IPKILL as well
-                                   as CONF_KILL -Kev */
-    {
-      int wilds, count;
-      char *user, *host, *p;
-      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
-      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
-      {
-        report_configured_links(sptr, conf_status);
-        break;
-      }
-      if (parc < 4 || *parv[3] == '\0')
-        return need_more_params(sptr,
-                        (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
-
-      wilds = 0;
-      for (p = parv[3]; *p; p++)
-      {
-        if (*p == '\\')
-        {
-          if (!*++p)
-            break;
-          continue;
-        }
-        if (*p == '?' || *p == '*')
-        {
-          wilds = 1;
-          break;
-        }
-      }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
       {
-        wilds = 0;
-        count = 3;
-      }
-      else
-        count = 1000;
-
-      if (conf_status == CONF_CLIENT)
-      {
-        user = 0;            /* Not used, but to avoid compiler warning. */
-
-        host = parv[3];
-      }
-      else
-      {
-        if ((host = strchr(parv[3], '@')))
-        {
-          user = parv[3];
-          *host++ = 0;;
-        }
-        else
-        {
-          user = 0;
-          host = parv[3];
-        }
-      }
-      for (aconf = GlobalConfList; aconf; aconf = aconf->next)
-      {
-        if ((aconf->status & conf_status))
-        {
-          if (conf_status == CONF_KLINE)
-          {
-            if ((!wilds && ((user || aconf->host[1]) &&
-                !match(aconf->host, host) &&
-                (!user || !match(aconf->name, user)))) ||
-                (wilds && !mmatch(host, aconf->host) &&
-                (!user || !mmatch(user, aconf->name))))
-            {
-              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
-                  sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
-                  aconf->port, get_conf_class(aconf));
-              if (--count == 0)
-                break;
-            }
-          }
-          else if (conf_status == CONF_CLIENT)
-          {
-            if ((!wilds && (!match(aconf->host, host) ||
-                !match(aconf->name, host))) ||
-                (wilds && (!mmatch(host, aconf->host) ||
-                !mmatch(host, aconf->name))))
-            {
-              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
-                  sptr->name, 'I', aconf->host, aconf->name,
-                  aconf->port, get_conf_class(aconf));
-              if (--count == 0)
-                break;
-            }
-          }
-        }
+       int   wilds = 0;
+       int   count = 1000;
+       char* host;
+
+       if (parc < 4) {
+         report_configured_links(sptr, CONF_CLIENT);
+         break;
+       }
+        if (EmptyString(parv[3]))
+          return need_more_params(sptr, "STATS I");
+
+       host = parv[3];
+       wilds = string_has_wildcards(host);
+
+       for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+         if (CONF_CLIENT == aconf->status) {
+           if ((!wilds && (!match(aconf->host, host) ||
+               !match(aconf->name, host))) ||
+               (wilds && (!mmatch(host, aconf->host) ||
+               !mmatch(host, aconf->name))))
+           {
+             send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, aconf->name,
+                        aconf->port, get_conf_class(aconf));
+             if (--count == 0)
+               break;
+           }
+         }
+       }
       }
       break;
-    }
     case 'M':
 #if !defined(NDEBUG)
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
-          me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
+      send_reply(sptr, RPL_STATMEMTOT, fda_get_byte_count(),
+                 fda_get_block_count());
 #endif
 
 #if 0
 #ifdef MEMSIZESTATS
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT), /* XXX DEAD */
           me.name, parv[0], get_mem_size(), get_alloc_cnt());
 #endif
 #ifdef MEMLEAKSTATS
       report_memleak_stats(sptr, parc, parv);
 #endif
 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
-      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
+      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring " /* XXX DEAD */
           "is not enabled on this server", me.name, parv[0]);
 #endif
 #endif /* 0 */
@@ -1549,8 +785,8 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     case 'm':
       for (mptr = msgtab; mptr->cmd; mptr++)
         if (mptr->count)
-          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
-              me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
+          send_reply(sptr, RPL_STATSCOMMANDS, mptr->cmd, mptr->count,
+                     mptr->bytes);
       break;
     case 'o':
     case 'O':
@@ -1564,8 +800,7 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
        * interpret the fourth parameter as the port number, limit non-local
        * or non-oper results to 8 ports.
        */ 
-      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, 
-                 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
+      show_ports(sptr, 1, (parc > 3) ? atoi(parv[3]) : 0, 100);
       break;
     case 'R':
     case 'r':
@@ -1574,16 +809,16 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
 #endif
       break;
     case 'D':
-      report_configured_links(sptr, CONF_CRULEALL);
+      report_crule_list(sptr, CRULE_ALL);
       break;
     case 'd':
-      report_configured_links(sptr, CONF_CRULE);
+      report_crule_list(sptr, CRULE_MASK);
       break;
     case 't':
       tstats(sptr, parv[0]);
       break;
     case 'T':
-      report_configured_links(sptr, CONF_TLINES);
+      report_motd_list(sptr);
       break;
     case 'U':
       report_configured_links(sptr, CONF_UWORLD);
@@ -1593,10 +828,9 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
       time_t nowr;
 
       nowr = CurrentTime - me.since;
-      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
-                 nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
-      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
-                 max_connection_count, max_client_count);
+      send_reply(sptr, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24,
+                 (nowr / 60) % 60, nowr % 60);
+      send_reply(sptr, RPL_STATSCONN, max_connection_count, max_client_count);
       break;
     }
     case 'W':
@@ -1606,6 +840,7 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     case 'X':
     case 'x':
 #ifdef  DEBUGMODE
+      class_send_meminfo(sptr);
       send_listinfo(sptr, parv[0]);
 #endif
       break;
@@ -1619,9 +854,11 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
       break;
     default:
       stat = '*';
+      while (*infotext)
+        sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, *infotext++);
       break;
   }
-  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
+  send_reply(sptr, RPL_ENDOFSTATS, stat);
   return 0;
 }
-#endif /* 0 */
+