Author: Isomer <isomer@coders.net>
[ircu2.10.12-pk.git] / ircd / m_stats.c
index 98daef7dad69b09f37d3af09dd3520626ea3aa32..ca9f39d209bd2da48e4630bd88a38395c9fe04e0 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>
 
-/*
- *  Help info displayed when user provides no stats parameter. --Gte 
- */
-const char *statsinfo[] = {
-    "The following statistics are available:",
-    "U - Service server & nick jupes information.",
-    "u - Current uptime & highest connection count.",
-    "p - Listening ports.",
-    "i - Connection authorisation lines.",
-    "y - Connection classes.",
-    "c - Remote server connection lines.",
-    "h - Hubs information (Oper only).",
-    "d - Dynamic routing configuration.", 
-    "l - Current connections information.",
-    "g - Global bans (G-lines).",
-    "k - Local bans (K-Lines).",
-    "o - Operator information.", 
-    "m - Message usage information.",
-    "t - Local connection statistics (Total SND/RCV, etc).", 
-    "w - Userload statistics.",
-    "M - Memory allocation & leak monitoring.", 
-    "z - Memory/Structure allocation information.",
-    "r - System resource usage (Debug only).", 
-    "x - List usage information (Debug only).",
-    0,
-};
 
 /*
  * m_stats - generic message handler
@@ -173,89 +148,15 @@ const char *statsinfo[] = {
  */
 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)
   {
@@ -284,7 +185,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]))
@@ -292,13 +194,8 @@ 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 ? 
-         * Yeah it is -- non opers can /stats l, just not remotely.
-         */
-        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))
@@ -306,10 +203,11 @@ int m_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;
     }
@@ -319,15 +217,11 @@ 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 'I':
     case 'i':
@@ -338,14 +232,11 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       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)
+      if (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++)
@@ -362,13 +253,8 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
           break;
         }
       }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
-      {
-        wilds = 0;
-        count = 3;
-      }
-      else
-        count = 1000;
+
+      count = 1000;
 
       if (conf_status == CONF_CLIENT)
       {
@@ -401,9 +287,10 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                 (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));
+             send_reply(sptr, RPL_STATSKLINE,
+                        (aconf->status & CONF_KILL) ? 'K' : 'k', aconf->host,
+                        aconf->passwd, aconf->name, aconf->port,
+                        get_conf_class(aconf));
               if (--count == 0)
                 break;
             }
@@ -415,9 +302,8 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                 (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));
+             send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, aconf->name,
+                        aconf->port, get_conf_class(aconf));
               if (--count == 0)
                 break;
             }
@@ -428,20 +314,20 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     }
     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 */
@@ -449,8 +335,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':
@@ -461,11 +347,9 @@ int m_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':
@@ -493,10 +377,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':
@@ -519,10 +402,11 @@ int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       break;
     default:
       stat = '*';
-      while (*infotext) sendto_one(sptr, ":%s NOTICE %s :%s", me.name, parv[0], *infotext++); 
+      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;
 }
 
@@ -551,88 +435,14 @@ int m_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)
   {
@@ -661,7 +471,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]))
@@ -670,37 +481,30 @@ int ms_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;
     }
     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':
@@ -715,7 +519,7 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       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)
+      if (IsOper(sptr) && parc < 4)
       {
         report_configured_links(sptr, conf_status);
         break;
@@ -739,7 +543,7 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
           break;
         }
       }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
+      if (!IsOper(sptr))
       {
         wilds = 0;
         count = 3;
@@ -778,9 +582,10 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                 (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));
+             send_reply(sptr, RPL_STATSKLINE,
+                        (aconf->status & CONF_KILL) ? 'K' : 'k', aconf->host,
+                        aconf->passwd, aconf->name, aconf->port,
+                        get_conf_class(aconf));
               if (--count == 0)
                 break;
             }
@@ -792,9 +597,8 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                 (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));
+             send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, aconf->name,
+                        aconf->port, get_conf_class(aconf));
               if (--count == 0)
                 break;
             }
@@ -805,20 +609,20 @@ int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     }
     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 */
@@ -826,8 +630,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':
@@ -841,8 +645,7 @@ int ms_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':
@@ -870,10 +673,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':
@@ -898,7 +700,7 @@ int ms_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;
 }
 
@@ -927,89 +729,15 @@ int ms_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';
   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)
   {
@@ -1038,7 +766,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]))
@@ -1046,22 +775,17 @@ int mo_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, (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;
     }
@@ -1071,12 +795,7 @@ 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':
@@ -1091,14 +810,11 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       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)
+      if (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++)
@@ -1115,13 +831,8 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
           break;
         }
       }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
-      {
-        wilds = 0;
-        count = 3;
-      }
-      else
-        count = 1000;
+
+      count = 1000;
 
       if (conf_status == CONF_CLIENT)
       {
@@ -1154,9 +865,10 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                 (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));
+             send_reply(sptr, RPL_STATSKLINE,
+                        (aconf->status & CONF_KILL) ? 'K' : 'k', aconf->host,
+                        aconf->passwd, aconf->name, aconf->port,
+                        get_conf_class(aconf));
               if (--count == 0)
                 break;
             }
@@ -1168,9 +880,8 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
                 (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));
+             send_reply(sptr, RPL_STATSILINE, 'I', aconf->host, aconf->name,
+                        aconf->port, get_conf_class(aconf));
               if (--count == 0)
                 break;
             }
@@ -1181,20 +892,20 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
     }
     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 */
@@ -1202,8 +913,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':
@@ -1217,8 +928,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, 1, (parc > 3) ? atoi(parv[3]) : 0, 100);
       break;
     case 'R':
     case 'r':
@@ -1246,10 +956,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':
@@ -1272,10 +981,11 @@ int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
       break;
     default:
       stat = '*';
-      while (*infotext) sendto_one(sptr, ":%s NOTICE %s :%s", me.name, parv[0], *infotext++);
+      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;
 }
 
@@ -1326,7 +1036,7 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     case 'U':
     case 'u':
     {
-      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv) /* XXX DEAD */
           != HUNTED_ISME)
         return 0;
       break;
@@ -1342,13 +1052,13 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     {
       if (parc > 3)
       {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv) /* XXX DEAD */
             != HUNTED_ISME)
           return 0;
       }
       else
       {
-        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv) /* XXX DEAD */
             != HUNTED_ISME)
           return 0;
       }
@@ -1362,17 +1072,17 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     {
       if (parc == 4)
       {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv) /* XXX DEAD */
             != HUNTED_ISME)
           return 0;
       }
       else if (parc > 4)
       {
-        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc, /* XXX DEAD */
             parv) != HUNTED_ISME)
           return 0;
       }
-      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv) /* XXX DEAD */
           != HUNTED_ISME)
         return 0;
       break;
@@ -1381,7 +1091,7 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
       /* oper only, standard # of params */
     default:
     {
-      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv) /* XXX DEAD */
           != HUNTED_ISME)
         return 0;
       break;
@@ -1415,7 +1125,7 @@ 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]);
+      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]); /* XXX DEAD */
       for (i = 0; i <= HighestFd; i++)
       {
         if (!(acptr = LocalClientArray[i]))
@@ -1435,7 +1145,7 @@ int m_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],
+        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0], /* XXX DEAD */
                    acptr->name,
                    (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
                    (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
@@ -1451,7 +1161,7 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     case 'g': /* send glines */
       gline_remove_expired(TStime());
       for (gline = GlobalGlineList; gline; gline = gline->next) {
-        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
+        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name, /* XXX DEAD */
                    sptr->name, 'G', gline->name, gline->host,
                    gline->expire, gline->reason);
       }
@@ -1532,7 +1242,7 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
                 (wilds && !mmatch(host, aconf->host) &&
                 (!user || !mmatch(user, aconf->name))))
             {
-              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
+              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name, /* XXX DEAD */
                   sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
                   aconf->port, get_conf_class(aconf));
               if (--count == 0)
@@ -1546,7 +1256,7 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
                 (wilds && (!mmatch(host, aconf->host) ||
                 !mmatch(host, aconf->name))))
             {
-              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
+              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name, /* XXX DEAD */
                   sptr->name, 'I', aconf->host, aconf->name,
                   aconf->port, get_conf_class(aconf));
               if (--count == 0)
@@ -1559,20 +1269,20 @@ int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
     }
     case 'M':
 #if !defined(NDEBUG)
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT), /* XXX DEAD */
           me.name, parv[0], 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 */
@@ -1580,7 +1290,7 @@ 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),
+          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS), /* XXX DEAD */
               me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
       break;
     case 'o':
@@ -1624,9 +1334,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],
+      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0], /* XXX DEAD */
                  nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
-      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
+      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0], /* XXX DEAD */
                  max_connection_count, max_client_count);
       break;
     }
@@ -1652,7 +1362,9 @@ int m_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);
+  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat); /* XXX DEAD */
   return 0;
 }
 #endif /* 0 */
+
+