ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_stats.c
(Generate patch)

Comparing:
ircd-hybrid-7.3/modules/m_stats.c (file contents), Revision 1127 by michael, Sun Feb 27 11:05:40 2011 UTC vs.
ircd-hybrid/trunk/modules/m_stats.c (file contents), Revision 1968 by michael, Wed May 8 14:59:15 2013 UTC

# Line 24 | Line 24
24  
25   #include "stdinc.h"
26   #include "list.h"        /* dlink_node/dlink_list */
27 – #include "balloc.h"
28 – #include "handlers.h"    /* m_pass prototype */
27   #include "client.h"      /* Client */
30 – #include "common.h"      /* TRUE/FALSE */
28   #include "irc_string.h"  
29   #include "ircd.h"        /* me */
30   #include "listener.h"    /* show_ports */
31   #include "s_gline.h"
32 < #include "ircd_handler.h"
33 < #include "msg.h"         /* Message */
32 > #include "conf.h"
33 > #include "conf_class.h"
34   #include "hostmask.h"
35   #include "numeric.h"     /* ERR_xxx */
36   #include "send.h"        /* sendto_one */
37   #include "fdlist.h"      /* PF and friends */
38   #include "s_bsd.h"       /* highest_fd */
42 – #include "s_conf.h"      /* AccessItem, report_configured_links */
39   #include "s_misc.h"      /* serv_info */
40   #include "s_serv.h"      /* hunt_server */
41   #include "s_user.h"      /* show_opers */
42   #include "event.h"       /* events */
43   #include "dbuf.h"
44 + #include "hook.h"
45   #include "parse.h"
46   #include "modules.h"
50 – #include "hook.h"
47   #include "resv.h"  /* report_resv */
48   #include "whowas.h"
49   #include "watch.h"
50 + #include "irc_res.h"
51  
55 – static void do_stats(struct Client *, int, char **);
56 – static void m_stats(struct Client *, struct Client *, int, char *[]);
57 – static void mo_stats(struct Client *, struct Client *, int, char *[]);
58 – static void ms_stats(struct Client *, struct Client *, int, char *[]);
52  
53 < struct Message stats_msgtab = {
61 <  "STATS", 0, 0, 2, 0, MFLG_SLOW, 0,
62 <  { m_unregistered, m_stats, ms_stats, m_ignore, mo_stats, m_ignore }
63 < };
53 > const char *from, *to;
54  
55 < const char *_version = "$Revision$";
56 < static struct Callback *stats_cb;
55 > static const struct shared_flags
56 > {
57 >  const unsigned int type;
58 >  const unsigned char letter;
59 > } flag_table[] = {
60 >  { SHARED_KLINE,   'K' },
61 >  { SHARED_UNKLINE, 'U' },
62 >  { SHARED_XLINE,   'X' },
63 >  { SHARED_UNXLINE, 'Y' },
64 >  { SHARED_RESV,    'Q' },
65 >  { SHARED_UNRESV,  'R' },
66 >  { SHARED_LOCOPS,  'L' },
67 >  { SHARED_DLINE,   'D' },
68 >  { SHARED_UNDLINE, 'E' },
69 >  { 0, '\0' }
70 > };
71  
72 < static void *
73 < va_stats(va_list args)
72 > /*
73 > * inputs       - pointer to client requesting confitem report
74 > *              - ConfType to report
75 > * output       - none
76 > * side effects -
77 > */
78 > static void
79 > report_confitem_types(struct Client *source_p, enum maskitem_type type)
80   {
81 <  struct Client *source_p = va_arg(args, struct Client *);
82 <  int parc = va_arg(args, int);
83 <  char **parv = va_arg(args, char **);
81 >  dlink_node *ptr = NULL, *dptr = NULL;
82 >  struct MaskItem *conf = NULL;
83 >  const struct ClassItem *class = NULL;
84 >  const struct shared_flags *shared = NULL;
85 >  char buf[12];
86 >  char *p = NULL;
87  
88 <  do_stats(source_p, parc, parv);
89 <  return NULL;
90 < }
88 >  switch (type)
89 >  {
90 >  case CONF_XLINE:
91 >    DLINK_FOREACH(ptr, xconf_items.head)
92 >    {
93 >      conf = ptr->data;
94  
95 < void
96 < _modinit(void)
97 < {
98 <  stats_cb = register_callback("doing_stats", va_stats);
99 <  mod_add_cmd(&stats_msgtab);
100 < }
95 >      sendto_one(source_p, form_str(RPL_STATSXLINE),
96 >                 me.name, source_p->name,
97 >                 conf->until ? 'x': 'X', conf->count,
98 >                 conf->name, conf->reason);
99 >    }
100 >    break;
101  
102 < void
103 < _moddeinit(void)
104 < {
105 <  mod_del_cmd(&stats_msgtab);
106 <  uninstall_hook(stats_cb, va_stats);
91 < }
102 >  case CONF_ULINE:
103 >    shared = flag_table;
104 >    DLINK_FOREACH(ptr, uconf_items.head)
105 >    {
106 >      conf = ptr->data;
107  
108 < static char *parse_stats_args(int, char **, int *, int *);
94 < static void stats_L(struct Client *, char *, int, int, char);
95 < static void stats_L_list(struct Client *s, char *, int, int, dlink_list *, char);
96 <
97 < static void stats_dns_servers(struct Client *);
98 < static void stats_connect(struct Client *);
99 < static void stats_deny(struct Client *);
100 < static void stats_tdeny(struct Client *);
101 < static void stats_exempt(struct Client *);
102 < static void stats_events(struct Client *);
103 < static void stats_pending_glines(struct Client *);
104 < static void stats_glines(struct Client *);
105 < static void stats_gdeny(struct Client *);
106 < static void stats_hubleaf(struct Client *);
107 < static void stats_auth(struct Client *);
108 < static void stats_tklines(struct Client *);
109 < static void stats_klines(struct Client *);
110 < static void stats_messages(struct Client *);
111 < static void stats_oper(struct Client *);
112 < static void stats_operedup(struct Client *);
113 < static void stats_ports(struct Client *);
114 < static void stats_resv(struct Client *);
115 < static void stats_usage(struct Client *);
116 < static void stats_tstats(struct Client *);
117 < static void stats_uptime(struct Client *);
118 < static void stats_shared(struct Client *);
119 < static void stats_servers(struct Client *);
120 < static void stats_gecos(struct Client *);
121 < static void stats_class(struct Client *);
122 < static void stats_memory(struct Client *);
123 < static void stats_servlinks(struct Client *);
124 < static void stats_ltrace(struct Client *, int, char **);
125 < static void stats_ziplinks(struct Client *);
126 <
127 < /* This table contains the possible stats items, in order:
128 < * /stats name,  function to call, operonly? adminonly? /stats letter
129 < * case only matters in the stats letter column.. -- fl_ */
130 < static const struct StatsStruct
131 < {
132 <  const unsigned char letter;
133 <  void (*handler)();
134 <  const unsigned int need_oper;
135 <  const unsigned int need_admin;
136 < } stats_cmd_table[] = {
137 <  /* letter     function            need_oper need_admin */
138 <  { 'a',        stats_dns_servers,      1,      1,      },
139 <  { 'A',        stats_dns_servers,      1,      1,      },
140 <  { 'c',        stats_connect,          1,      0,      },
141 <  { 'C',        stats_connect,          1,      0,      },
142 <  { 'd',        stats_tdeny,            1,      0,      },
143 <  { 'D',        stats_deny,             1,      0,      },
144 <  { 'e',        stats_exempt,           1,      0,      },
145 <  { 'E',        stats_events,           1,      1,      },
146 <  { 'f',        fd_dump,                1,      1,      },
147 <  { 'F',        fd_dump,                1,      1,      },
148 <  { 'g',        stats_pending_glines,   1,      0,      },
149 <  { 'G',        stats_glines,           1,      0,      },
150 <  { 'h',        stats_hooks,            1,      1,      },
151 <  { 'H',        stats_hubleaf,          1,      0,      },
152 <  { 'i',        stats_auth,             0,      0,      },
153 <  { 'I',        stats_auth,             0,      0,      },
154 <  { 'k',        stats_tklines,          0,      0,      },
155 <  { 'K',        stats_klines,           0,      0,      },
156 <  { 'l',        stats_ltrace,           1,      0,      },
157 <  { 'L',        stats_ltrace,           1,      0,      },
158 <  { 'm',        stats_messages,         0,      0,      },
159 <  { 'M',        stats_messages,         0,      0,      },
160 <  { 'o',        stats_oper,             0,      0,      },
161 <  { 'O',        stats_oper,             0,      0,      },
162 <  { 'p',        stats_operedup,         0,      0,      },
163 <  { 'P',        stats_ports,            0,      0,      },
164 <  { 'q',        stats_resv,             1,      0,      },
165 <  { 'Q',        stats_resv,             1,      0,      },
166 <  { 'r',        stats_usage,            1,      0,      },
167 <  { 'R',        stats_usage,            1,      0,      },
168 <  { 't',        stats_tstats,           1,      0,      },
169 <  { 'T',        stats_tstats,           1,      0,      },
170 <  { 'u',        stats_uptime,           0,      0,      },
171 <  { 'U',        stats_shared,           1,      0,      },
172 <  { 'v',        stats_servers,          1,      0,      },
173 <  { 'V',        stats_gdeny,            1,      0,      },
174 <  { 'x',        stats_gecos,            1,      0,      },
175 <  { 'X',        stats_gecos,            1,      0,      },
176 <  { 'y',        stats_class,            1,      0,      },
177 <  { 'Y',        stats_class,            1,      0,      },
178 <  { 'z',        stats_memory,           1,      0,      },
179 <  { 'Z',        stats_ziplinks,         1,      0,      },
180 <  { '?',        stats_servlinks,        0,      0,      },
181 <  { '\0',       NULL,                   0,      0,      }
182 < };
108 >      p = buf;
109  
110 < const char *from, *to;
110 >      *p++ = 'c';
111 >      for (; shared->type; ++shared)
112 >        if (shared->type & conf->flags)
113 >          *p++ = shared->letter;
114 >        else
115 >          *p++ = ToLower(shared->letter);
116 >
117 >      sendto_one(source_p, form_str(RPL_STATSULINE),
118 >                 me.name, source_p->name, conf->name,
119 >                 conf->user?conf->user: "*",
120 >                 conf->host?conf->host: "*", buf);
121 >    }
122  
123 < static void
124 < do_stats(struct Client *source_p, int parc, char **parv)
125 < {
126 <  char statchar = *parv[1];
190 <  int i;
123 >    shared = flag_table;
124 >    DLINK_FOREACH(ptr, cluster_items.head)
125 >    {
126 >      conf = ptr->data;
127  
128 <  if (statchar == '\0')
193 <  {
194 <    sendto_one(source_p, form_str(RPL_ENDOFSTATS),
195 <               from, to, '*');
196 <    return;
197 <  }
128 >      p = buf;
129  
130 <  for (i = 0; stats_cmd_table[i].handler; i++)
131 <  {
132 <    if (stats_cmd_table[i].letter == statchar)
130 >      *p++ = 'C';
131 >      for (; shared->type; ++shared)
132 >        if (shared->type & conf->flags)
133 >          *p++ = shared->letter;
134 >        else
135 >          *p++ = ToLower(shared->letter);
136 >
137 >      sendto_one(source_p, form_str(RPL_STATSULINE),
138 >                 me.name, source_p->name, conf->name,
139 >                 "*", "*", buf);
140 >    }
141 >
142 >    break;
143 >
144 >  case CONF_OPER:
145 >    DLINK_FOREACH(ptr, oconf_items.head)
146      {
147 <      /* The stats table says what privs are needed, so check --fl_ */
204 <      if ((stats_cmd_table[i].need_admin && !IsAdmin(source_p)) ||
205 <          (stats_cmd_table[i].need_oper && !IsOper(source_p)))
206 <      {
207 <        sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
208 <                   from, to);
209 <        break;
210 <      }
147 >      conf = ptr->data;
148  
149 <      /* Blah, stats L needs the parameters, none of the others do.. */
150 <      if (statchar == 'L' || statchar == 'l')
151 <        stats_cmd_table[i].handler(source_p, parc, parv);
149 >      /* Don't allow non opers to see oper privs */
150 >      if (HasUMode(source_p, UMODE_OPER))
151 >        sendto_one(source_p, form_str(RPL_STATSOLINE),
152 >                   me.name, source_p->name, 'O', conf->count, conf->user, conf->host,
153 >                   conf->name, oper_privs_as_string(conf->port),
154 >                   conf->class ? conf->class->name : "<default>");
155        else
156 <        stats_cmd_table[i].handler(source_p);
156 >        sendto_one(source_p, form_str(RPL_STATSOLINE),
157 >                   me.name, source_p->name, 'O', conf->count, conf->user, conf->host,
158 >                   conf->name, "0",
159 >                   conf->class ? conf->class->name : "<default>");
160 >    }
161 >    break;
162  
163 <      break;
163 >  case CONF_CLASS:
164 >    DLINK_FOREACH(ptr, class_get_list()->head)
165 >    {
166 >      class = ptr->data;
167 >      sendto_one(source_p, form_str(RPL_STATSYLINE),
168 >                 me.name, source_p->name, 'Y',
169 >                 class->name, class->ping_freq,
170 >                 class->con_freq,
171 >                 class->max_total, class->max_sendq,
172 >                 class->max_recvq,
173 >                 class->ref_count,
174 >                 class->number_per_cidr, class->cidr_bitlen_ipv4,
175 >                 class->number_per_cidr, class->cidr_bitlen_ipv6,
176 >                 class->active ? "active" : "disabled");
177      }
178 <  }
178 >    break;
179  
180 <  sendto_one(source_p, form_str(RPL_ENDOFSTATS),
181 <             from, to, statchar);
182 < }
180 >  case CONF_SERVICE:
181 >    DLINK_FOREACH(ptr, service_items.head)
182 >    {
183 >      conf = ptr->data;
184 >      sendto_one(source_p, form_str(RPL_STATSSERVICE),
185 >                 me.name, source_p->name, 'S', "*", conf->name, 0, 0);
186 >    }
187 >    break;
188  
189 < /*
190 < * m_stats()
191 < *      parv[0] = sender prefix
192 < *      parv[1] = stat letter/command
193 < *      parv[2] = (if present) server/mask in stats L
231 < *
232 < * This will search the tables for the appropriate stats letter/command,
233 < * if found execute it.  
234 < */
235 < static void
236 < m_stats(struct Client *client_p, struct Client *source_p,
237 <        int parc, char *parv[])
238 < {
239 <  static time_t last_used = 0;
189 >  case CONF_SERVER:
190 >    DLINK_FOREACH(ptr, server_items.head)
191 >    {
192 >      p = buf;
193 >      conf = ptr->data;
194  
195 <  /* Is the stats meant for us? */
242 <  if (!ConfigFileEntry.disable_remote)
243 <    if (hunt_server(client_p,source_p,":%s STATS %s :%s",2,parc,parv) != HUNTED_ISME)
244 <      return;
195 >      buf[0] = '\0';
196  
197 <  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
198 <  {
199 <    from = me.id;
200 <    to = source_p->id;
201 <  }
202 <  else
252 <  {
253 <    from = me.name;
254 <    to = source_p->name;
255 <  }
197 >      if (IsConfAllowAutoConn(conf))
198 >        *p++ = 'A';
199 >      if (IsConfSSL(conf))
200 >        *p++ = 'S';
201 >      if (buf[0] == '\0')
202 >        *p++ = '*';
203  
204 <  /* Check the user is actually allowed to do /stats, and isnt flooding */
258 <  if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
259 <  {
260 <    sendto_one(source_p,form_str(RPL_LOAD2HI),
261 <               from, to);
262 <    return;
263 <  }
204 >      *p = '\0';
205  
206 <  last_used = CurrentTime;
206 >      /*
207 >       * Allow admins to see actual ips unless hide_server_ips is enabled
208 >       */
209 >      if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN))
210 >        sendto_one(source_p, form_str(RPL_STATSCLINE),
211 >                   me.name, source_p->name, 'C', conf->host,
212 >                   buf, conf->name, conf->port,
213 >                   conf->class ? conf->class->name : "<default>");
214 >        else
215 >          sendto_one(source_p, form_str(RPL_STATSCLINE),
216 >                     me.name, source_p->name, 'C',
217 >                     "*@127.0.0.1", buf, conf->name, conf->port,
218 >                     conf->class ? conf->class->name : "<default>");
219 >    }
220 >    break;
221 >
222 >  case CONF_HUB:
223 >    DLINK_FOREACH(ptr, server_items.head)
224 >    {
225 >      conf = ptr->data;
226 >
227 >      DLINK_FOREACH(dptr, conf->hub_list.head)
228 >        sendto_one(source_p, form_str(RPL_STATSHLINE), me.name,
229 >                   source_p->name, 'H', dptr->data, conf->name, 0, "*");
230 >    }
231 >
232 >    DLINK_FOREACH(ptr, server_items.head)
233 >    {
234 >      conf = ptr->data;
235 >
236 >      DLINK_FOREACH(dptr, conf->leaf_list.head)
237 >        sendto_one(source_p, form_str(RPL_STATSLLINE), me.name,
238 >                   source_p->name, 'L', dptr->data, conf->name, 0, "*");
239 >    }
240 >
241 >    break;
242  
243 <  execute_callback(stats_cb, source_p, parc, parv);
243 >  default:
244 >    break;
245 >  }
246   }
247  
248 < /*
271 < * mo_stats()
272 < *      parv[0] = sender prefix
273 < *      parv[1] = stat letter/command
274 < *      parv[2] = (if present) server/mask in stats L, or target
248 > /* report_resv()
249   *
250 < * This will search the tables for the appropriate stats letter,
251 < * if found execute it.  
250 > * inputs       - pointer to client pointer to report to.
251 > * output       - NONE
252 > * side effects - report all resvs to client.
253   */
254   static void
255 < mo_stats(struct Client *client_p, struct Client *source_p,
281 <         int parc, char *parv[])
255 > report_resv(struct Client *source_p)
256   {
257 <  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
258 <                  parc, parv) != HUNTED_ISME)
285 <     return;
257 >  dlink_node *ptr = NULL;
258 >  struct MaskItem *conf = NULL;
259  
260 <  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
260 >  DLINK_FOREACH(ptr, resv_channel_list.head)
261    {
262 <    from = me.id;
263 <    to = source_p->id;
262 >    conf = ptr->data;
263 >    sendto_one(source_p, form_str(RPL_STATSQLINE),
264 >               me.name, source_p->name,
265 >               conf->until ? 'q' : 'Q', conf->count,
266 >               conf->name, conf->reason);
267    }
268 <  else
268 >
269 >  DLINK_FOREACH(ptr, nresv_items.head)
270    {
271 <    from = me.name;
272 <    to = source_p->name;
271 >    conf = ptr->data;
272 >    sendto_one(source_p, form_str(RPL_STATSQLINE),
273 >               me.name, source_p->name,
274 >               conf->until ? 'q' : 'Q', conf->count,
275 >               conf->name, conf->reason);
276    }
297 –
298 –  execute_callback(stats_cb, source_p, parc, parv);
277   }
278  
279   /*
# Line 306 | Line 284 | mo_stats(struct Client *client_p, struct
284   * -avalon
285   */
286   static void
287 < send_usage(struct Client *source_p)
287 > stats_usage(struct Client *source_p, int parc, char *parv[])
288   {
289    struct rusage rus;
290    time_t secs;
# Line 333 | Line 311 | send_usage(struct Client *source_p)
311    if (secs == 0)
312      secs = 1;
313  
314 <  rup = (CurrentTime - me.since) * hzz;
314 >  rup = (CurrentTime - me.localClient->since) * hzz;
315  
316    if (rup == 0)
317      rup = 1;
318  
319    sendto_one(source_p,
320 <             ":%s %d %s R :CPU Secs %d:%d User %d:%d System %d:%d",
320 >             ":%s %d %s R :CPU Secs %d:%02d User %d:%02d System %d:%02d",
321               me.name, RPL_STATSDEBUG, source_p->name, (int)(secs/60), (int)(secs%60),
322               (int)(rus.ru_utime.tv_sec/60), (int)(rus.ru_utime.tv_sec%60),
323               (int)(rus.ru_stime.tv_sec/60), (int)(rus.ru_stime.tv_sec%60));
# Line 362 | Line 340 | send_usage(struct Client *source_p)
340   }
341  
342   static void
343 < count_memory(struct Client *source_p)
343 > stats_memory(struct Client *source_p, int parc, char *parv[])
344   {
345    const dlink_node *gptr = NULL;
346    const dlink_node *dlink = NULL;
# Line 389 | Line 367 | count_memory(struct Client *source_p)
367    unsigned int safelist_count = 0;
368    uint64_t safelist_memory = 0;
369  
392 –  uint64_t away_memory = 0;       /* memory used by aways           */
370    uint64_t wwm = 0;               /* whowas array memory used       */
371    uint64_t conf_memory = 0;       /* memory used by conf lines      */
372    uint64_t mem_ips_stored;        /* memory used by ip address hash */
# Line 428 | Line 405 | count_memory(struct Client *source_p)
405      {
406        ++users_counted;
407  
408 <      if (target_p->away != NULL)
432 <      {
408 >      if (target_p->away[0])
409          ++aways_counted;
434 –        away_memory += strlen(target_p->away) + 1;
435 –      }
410      }
411    }
412  
# Line 447 | Line 421 | count_memory(struct Client *source_p)
421      channel_members += dlink_list_length(&chptr->members);
422      channel_invites += dlink_list_length(&chptr->invites);
423  
424 <    if (chptr->topic != NULL)
424 >    if (chptr->topic[0])
425        ++topic_count;
426  
427      channel_bans += dlink_list_length(&chptr->banlist);
# Line 515 | Line 489 | count_memory(struct Client *source_p)
489    }
490   #endif
491    /* count up all classes */
492 <  class_count = dlink_list_length(&class_items);
492 >  class_count = dlink_list_length(class_get_list());
493  
494    count_whowas_memory(&wwu, &wwm);
495    watch_count_memory(&watch_list_headers, &watch_list_memory);
496  
497 <  sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%u) entries %d(%u)",
497 >  sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%llu) entries %d(%u)",
498               me.name, RPL_STATSDEBUG, source_p->name, watch_list_headers,
499               watch_list_memory, watch_list_entries,
500               watch_list_entries * sizeof(dlink_node) * 2);
# Line 529 | Line 503 | count_memory(struct Client *source_p)
503               me.name, RPL_STATSDEBUG, source_p->name, users_counted,
504               (users_counted * sizeof(struct Client)));
505  
506 <  sendto_one(source_p, ":%s %d %s z :User aways %u(%llu)",
506 >  sendto_one(source_p, ":%s %d %s z :User aways %u",
507               me.name, RPL_STATSDEBUG, source_p->name,
508 <             aways_counted, away_memory);
508 >             aways_counted);
509  
510    sendto_one(source_p, ":%s %d %s z :Attached confs %u(%llu)",
511               me.name, RPL_STATSDEBUG, source_p->name,
# Line 541 | Line 515 | count_memory(struct Client *source_p)
515    sendto_one(source_p, ":%s %d %s z :Resv channels %u(%lu) nicks %u(%lu)",
516               me.name, RPL_STATSDEBUG, source_p->name,
517               dlink_list_length(&resv_channel_list),
518 <             dlink_list_length(&resv_channel_list) * sizeof(struct ResvChannel),
518 >             dlink_list_length(&resv_channel_list) * sizeof(struct MaskItem),
519               dlink_list_length(&nresv_items),
520 <             dlink_list_length(&nresv_items) * sizeof(struct MatchItem));
520 >             dlink_list_length(&nresv_items) * sizeof(struct MaskItem));
521  
522    sendto_one(source_p, ":%s %d %s z :Classes %u(%llu)",
523               me.name, RPL_STATSDEBUG, source_p->name,
524               class_count, (unsigned long long)(class_count * sizeof(struct ClassItem)));
525  
526 <  sendto_one(source_p, ":%s %d %s z :Channels %uu(%llu) Topics %u(%u)",
526 >  sendto_one(source_p, ":%s %d %s z :Channels %u(%llu) Topics %u(%u)",
527               me.name, RPL_STATSDEBUG, source_p->name,
528               dlink_list_length(&global_channel_list),
529               channel_memory, topic_count, topic_count *
# Line 614 | Line 588 | count_memory(struct Client *source_p)
588               me.name, RPL_STATSDEBUG, source_p->name, remote_client_count,
589               remote_client_memory_used);
590  
617 –  block_heap_report_stats(source_p);
618 –
591    sendto_one(source_p,
592               ":%s %d %s z :TOTAL: %llu",
593               me.name, RPL_STATSDEBUG, source_p->name,
# Line 629 | Line 601 | stats_dns_servers(struct Client *source_
601   }
602  
603   static void
604 < stats_connect(struct Client *source_p)
604 > stats_connect(struct Client *source_p, int parc, char *parv[])
605   {
606 <  report_confitem_types(source_p, SERVER_TYPE, 0);
606 >  report_confitem_types(source_p, CONF_SERVER);
607   }
608  
609   /* stats_deny()
# Line 641 | Line 613 | stats_connect(struct Client *source_p)
613   * side effects - client is given dline list.
614   */
615   static void
616 < stats_deny(struct Client *source_p)
616 > stats_deny(struct Client *source_p, int parc, char *parv[])
617   {
618 <  struct AddressRec *arec;
619 <  struct ConfItem *conf;
620 <  struct AccessItem *aconf;
621 <  int i;
618 >  struct MaskItem *conf;
619 >  dlink_node *ptr = NULL;
620 >  unsigned int i = 0;
621 >
622  
623 <  for (i = 0; i < ATABLE_SIZE; i++)
623 >  for (i = 0; i < ATABLE_SIZE; ++i)
624    {
625 <    for (arec = atable[i]; arec; arec=arec->next)
625 >    DLINK_FOREACH(ptr, atable[i].head)
626      {
627 <      if (arec->type == CONF_DLINE)
656 <      {
657 <        aconf = arec->aconf;
627 >      struct AddressRec *arec = ptr->data;
628  
629 <        /* dont report a tdline as a dline */
630 <        if (aconf->flags & CONF_FLAGS_TEMPORARY)
661 <          continue;
629 >      if (arec->type != CONF_DLINE)
630 >        continue;
631  
632 <        conf = unmap_conf_item(aconf);
632 >      conf = arec->conf;
633  
634 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
635 <                   from, to, 'D', aconf->host, aconf->reason,
636 <                   aconf->oper_reason);
637 <      }
634 >      /* dont report a tdline as a dline */
635 >      if (conf->until)
636 >        continue;
637 >
638 >      sendto_one(source_p, form_str(RPL_STATSDLINE),
639 >                 from, to, 'D', conf->host, conf->reason);
640      }
641    }
642   }
# Line 677 | Line 648 | stats_deny(struct Client *source_p)
648   * side effects - client is given dline list.
649   */
650   static void
651 < stats_tdeny(struct Client *source_p)
651 > stats_tdeny(struct Client *source_p, int parc, char *parv[])
652   {
653 <  struct AddressRec *arec;
654 <  struct ConfItem *conf;
655 <  struct AccessItem *aconf;
656 <  int i;
653 >  struct MaskItem *conf = NULL;
654 >  dlink_node *ptr = NULL;
655 >  unsigned int i = 0;
656 >
657  
658 <  for (i = 0; i < ATABLE_SIZE; i++)
658 >  for (i = 0; i < ATABLE_SIZE; ++i)
659    {
660 <    for (arec = atable[i]; arec; arec=arec->next)
660 >    DLINK_FOREACH(ptr, atable[i].head)
661      {
662 <      if (arec->type == CONF_DLINE)
692 <      {
693 <        aconf = arec->aconf;
662 >      struct AddressRec *arec = ptr->data;
663  
664 <        /* dont report a permanent dline as a tdline */
665 <        if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
697 <          continue;
664 >      if (arec->type != CONF_DLINE)
665 >        continue;
666  
667 <        conf = unmap_conf_item(aconf);
667 >      conf = arec->conf;
668  
669 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
670 <                   from, to, 'd', aconf->host, aconf->reason,
671 <                   aconf->oper_reason);
672 <      }
669 >      /* dont report a permanent dline as a tdline */
670 >      if (!conf->until)
671 >        continue;
672 >
673 >      sendto_one(source_p, form_str(RPL_STATSDLINE),
674 >                 from, to, 'd', conf->host, conf->reason);
675      }
676    }
677   }
# Line 713 | Line 683 | stats_tdeny(struct Client *source_p)
683   * side effects - client is given list of exempt blocks
684   */
685   static void
686 < stats_exempt(struct Client *source_p)
686 > stats_exempt(struct Client *source_p, int parc, char *parv[])
687   {
688 <  struct AddressRec *arec;
689 <  struct ConfItem *conf;
690 <  struct AccessItem *aconf;
721 <  int i;
688 >  struct MaskItem *conf;
689 >  dlink_node *ptr = NULL;
690 >  unsigned int i = 0;
691  
692    if (ConfigFileEntry.stats_e_disabled)
693    {
# Line 727 | Line 696 | stats_exempt(struct Client *source_p)
696      return;
697    }
698  
699 <  for (i = 0; i < ATABLE_SIZE; i++)
699 >
700 >  for (i = 0; i < ATABLE_SIZE; ++i)
701    {
702 <    for (arec = atable[i]; arec; arec=arec->next)
702 >    DLINK_FOREACH(ptr, atable[i].head)
703      {
704 <      if (arec->type == CONF_EXEMPTDLINE)
735 <      {
736 <        aconf = arec->aconf;
704 >      struct AddressRec *arec = ptr->data;
705  
706 <        conf = unmap_conf_item(aconf);
706 >      if (arec->type != CONF_EXEMPT)
707 >        continue;
708  
709 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
710 <                   from, to, 'e', aconf->host,
711 <                   aconf->reason, aconf->oper_reason);
712 <      }
709 >      conf = arec->conf;
710 >
711 >      sendto_one(source_p, form_str(RPL_STATSDLINE), from, to, 'e',
712 >                 conf->host, "");
713      }
714    }
715   }
716  
717   static void
718 < stats_events(struct Client *source_p)
718 > stats_events(struct Client *source_p, int parc, char *parv[])
719   {
720    show_events(source_p);
721   }
# Line 758 | Line 727 | stats_events(struct Client *source_p)
727   * side effects - client is shown list of pending glines
728   */
729   static void
730 < stats_pending_glines(struct Client *source_p)
730 > stats_pending_glines(struct Client *source_p, int parc, char *parv[])
731   {
732    const dlink_node *dn_ptr = NULL;
733    const struct gline_pending *glp_ptr = NULL;
# Line 847 | Line 816 | stats_pending_glines(struct Client *sour
816   * side effects - client is shown list of glines
817   */
818   static void
819 < stats_glines(struct Client *source_p)
819 > stats_glines(struct Client *source_p, int parc, char *parv[])
820   {
821 <  struct AddressRec *arec = NULL;
822 <  int i = 0;
821 >  dlink_node *ptr = NULL;
822 >  unsigned int i = 0;
823  
824    if (!ConfigFileEntry.glines)
825    {
# Line 859 | Line 828 | stats_glines(struct Client *source_p)
828      return;
829    }
830  
831 <  for (; i < ATABLE_SIZE; ++i)
831 >  for (i = 0; i < ATABLE_SIZE; ++i)
832    {
833 <    for (arec = atable[i]; arec; arec = arec->next)
833 >    DLINK_FOREACH(ptr, atable[i].head)
834      {
835 +      const struct AddressRec *arec = ptr->data;
836 +
837        if (arec->type == CONF_GLINE)
838        {
839 <        const struct AccessItem *aconf = arec->aconf;
839 >        const struct MaskItem *conf = arec->conf;
840  
841          sendto_one(source_p, form_str(RPL_STATSKLINE),
842 <                   from, to, "G",
843 <                   aconf->host ? aconf->host : "*",
844 <                   aconf->user ? aconf->user : "*",
845 <                   aconf->reason ? aconf->reason : "No reason", "" );
842 >                   from, to, 'G',
843 >                   conf->host ? conf->host : "*",
844 >                   conf->user ? conf->user : "*",
845 >                   conf->reason ? conf->reason : CONF_NOREASON);
846        }
847      }
848    }
849   }
850  
851 < /* stats_gdeny()
851 > static void
852 > stats_hubleaf(struct Client *source_p, int parc, char *parv[])
853 > {
854 >  report_confitem_types(source_p, CONF_HUB);
855 > }
856 >
857 > /*
858 > * show_iline_prefix()
859   *
860 < * input        - client pointer
861 < * outputs      - none
862 < * side effects - client is shown gline ACL
860 > * inputs       - pointer to struct Client requesting output
861 > *              - pointer to struct MaskItem
862 > *              - name to which iline prefix will be prefixed to
863 > * output       - pointer to static string with prefixes listed in ascii form
864 > * side effects - NONE
865   */
866 < static void
867 < stats_gdeny(struct Client *source_p)
866 > static const char *
867 > show_iline_prefix(const struct Client *sptr, const struct MaskItem *conf)
868   {
869 <  if (!ConfigFileEntry.glines)
870 <  {
871 <    sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
872 <               from, to);
873 <    return;
874 <  }
869 >  static char prefix_of_host[USERLEN + 15];
870 >  char *prefix_ptr = prefix_of_host;
871 >
872 >  if (IsConfWebIRC(conf))
873 >    *prefix_ptr++ = '<';
874 >  if (IsNoTilde(conf))
875 >    *prefix_ptr++ = '-';
876 >  if (IsLimitIp(conf))
877 >    *prefix_ptr++ = '!';
878 >  if (IsNeedIdentd(conf))
879 >    *prefix_ptr++ = '+';
880 >  if (!IsNeedPassword(conf))
881 >    *prefix_ptr++ = '&';
882 >  if (IsConfExemptResv(conf))
883 >    *prefix_ptr++ = '$';
884 >  if (IsNoMatchIp(conf))
885 >    *prefix_ptr++ = '%';
886 >  if (IsConfDoSpoofIp(conf))
887 >    *prefix_ptr++ = '=';
888 >  if (MyOper(sptr) && IsConfExemptKline(conf))
889 >    *prefix_ptr++ = '^';
890 >  if (MyOper(sptr) && IsConfExemptGline(conf))
891 >    *prefix_ptr++ = '_';
892 >  if (MyOper(sptr) && IsConfExemptLimits(conf))
893 >    *prefix_ptr++ = '>';
894 >  if (IsConfCanFlood(conf))
895 >    *prefix_ptr++ = '|';
896 >
897 >  strlcpy(prefix_ptr, conf->user, USERLEN+1);
898  
899 <  report_confitem_types(source_p, GDENY_TYPE, 0);
899 >  return prefix_of_host;
900   }
901  
902   static void
903 < stats_hubleaf(struct Client *source_p)
903 > report_auth(struct Client *client_p, int parc, char *parv[])
904   {
905 <  report_confitem_types(source_p, HUB_TYPE, 0);
906 <  report_confitem_types(source_p, LEAF_TYPE, 0);
905 >  struct MaskItem *conf = NULL;
906 >  dlink_node *ptr = NULL;
907 >  unsigned int i;
908 >
909 >
910 >  for (i = 0; i < ATABLE_SIZE; ++i)
911 >  {
912 >    DLINK_FOREACH(ptr, atable[i].head)
913 >    {
914 >      struct AddressRec *arec = ptr->data;
915 >
916 >      if (arec->type != CONF_CLIENT)
917 >        continue;
918 >
919 >      conf = arec->conf;
920 >
921 >      if (!MyOper(client_p) && IsConfDoSpoofIp(conf))
922 >        continue;
923 >
924 >      /* We are doing a partial list, based on what matches the u@h of the
925 >       * sender, so prepare the strings for comparing --fl_
926 >       */
927 >      if (ConfigFileEntry.hide_spoof_ips)
928 >        sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
929 >                   client_p->name, 'I',
930 >                   conf->name == NULL ? "*" : conf->name,
931 >                   show_iline_prefix(client_p, conf),
932 >                   IsConfDoSpoofIp(conf) ? "255.255.255.255" :
933 >                   conf->host, conf->port,
934 >                   conf->class ? conf->class->name : "<default>");
935 >
936 >      else
937 >        sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
938 >                   client_p->name, 'I',
939 >                   conf->name == NULL ? "*" : conf->name,
940 >                   show_iline_prefix(client_p, conf),
941 >                   conf->host, conf->port,
942 >                   conf->class ? conf->class->name : "<default>");
943 >    }
944 >  }
945   }
946  
947   static void
948 < stats_auth(struct Client *source_p)
948 > stats_auth(struct Client *source_p, int parc, char *parv[])
949   {
950    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
951 <  if ((ConfigFileEntry.stats_i_oper_only == 2) && !IsOper(source_p))
951 >  if ((ConfigFileEntry.stats_i_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
952      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
953                 from, to);
954  
955    /* If unopered, Only return matching auth blocks */
956 <  else if ((ConfigFileEntry.stats_i_oper_only == 1) && !IsOper(source_p))
956 >  else if ((ConfigFileEntry.stats_i_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
957    {
958 <    struct ConfItem *conf;
918 <    struct AccessItem *aconf;
958 >    struct MaskItem *conf;
959  
960      if (MyConnect(source_p))
961 <      aconf = find_conf_by_address(source_p->host,
961 >      conf = find_conf_by_address(source_p->host,
962                                     &source_p->localClient->ip,
963                                     CONF_CLIENT,
964                                     source_p->localClient->aftype,
965                                     source_p->username,
966 <                                   source_p->localClient->passwd);
966 >                                   source_p->localClient->passwd, 1);
967      else
968 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
969 <                                   0, source_p->username, NULL);
968 >      conf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
969 >                                   0, source_p->username, NULL, 1);
970  
971 <    if (aconf == NULL)
971 >    if (conf == NULL)
972        return;
973  
934 –    conf = unmap_conf_item(aconf);
935 –
974      sendto_one(source_p, form_str(RPL_STATSILINE), from,
975                 to, 'I',
976 <               "*", show_iline_prefix(source_p, aconf, aconf->user),
977 <               aconf->host, aconf->port,
978 <               aconf->class_ptr ? aconf->class_ptr->name : "<default>");
976 >               "*", show_iline_prefix(source_p, conf),
977 >               conf->host, conf->port,
978 >               conf->class ? conf->class->name : "<default>");
979    }
980    /* They are opered, or allowed to see all auth blocks */
981    else
982 <    report_auth(source_p);
982 >    report_auth(source_p, 0, NULL);
983   }
984  
985 + /* report_Klines()
986 + * Inputs: Client to report to,
987 + *         type(==0 for perm, !=0 for temporary)
988 + *         mask
989 + * Output: None
990 + * Side effects: Reports configured K(or k)-lines to client_p.
991 + */
992   static void
993 < stats_tklines(struct Client *source_p)
993 > report_Klines(struct Client *client_p, int tkline)
994 > {
995 >  struct MaskItem *conf = NULL;
996 >  unsigned int i = 0;
997 >  char c = '\0';
998 >  dlink_node *ptr = NULL;
999 >
1000 >  if (tkline)
1001 >    c = 'k';
1002 >  else
1003 >    c = 'K';
1004 >
1005 >  for (i = 0; i < ATABLE_SIZE; ++i)
1006 >  {
1007 >    DLINK_FOREACH(ptr, atable[i].head)
1008 >    {
1009 >      struct AddressRec *arec = ptr->data;
1010 >
1011 >      if (arec->type != CONF_KLINE)
1012 >        continue;
1013 >
1014 >      conf = arec->conf;
1015 >
1016 >      if ((!tkline && conf->until) ||
1017 >          (tkline && !conf->until))
1018 >        continue;
1019 >
1020 >      if (HasUMode(client_p, UMODE_OPER))
1021 >        sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1022 >                   client_p->name, c, conf->host, conf->user,
1023 >                   conf->reason);
1024 >      else
1025 >        sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1026 >                   client_p->name, c, conf->host, conf->user,
1027 >                   conf->reason);
1028 >    }
1029 >  }
1030 > }
1031 >
1032 > static void
1033 > stats_tklines(struct Client *source_p, int parc, char *parv[])
1034   {
950 –  struct ConfItem *conf;
1035    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1036 <  if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
1036 >  if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1037      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1038                 from, to);
1039  
1040    /* If unopered, Only return matching klines */
1041 <  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
1041 >  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1042    {
1043 <    struct AccessItem *aconf;
1043 >    struct MaskItem *conf = NULL;
1044  
1045      if (MyConnect(source_p))
1046 <      aconf = find_conf_by_address(source_p->host,
1047 <                                   &source_p->localClient->ip,
1048 <                                   CONF_KILL,
1046 >      conf = find_conf_by_address(source_p->host,
1047 >                                  &source_p->localClient->ip,
1048 >                                   CONF_KLINE,
1049                                     source_p->localClient->aftype,
1050 <                                   source_p->username, NULL);
1050 >                                   source_p->username, NULL, 1);
1051      else
1052 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
1053 <                                   0, source_p->username, NULL);
1052 >      conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1053 >                                   0, source_p->username, NULL, 1);
1054  
1055 <    if (aconf == NULL)
1055 >    if (!conf)
1056        return;
1057  
1058      /* dont report a permanent kline as a tkline */
1059 <    if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
1059 >    if (!conf->until)
1060        return;
1061  
978 –    conf = unmap_conf_item(aconf);
979 –
1062      sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1063 <               to, "k", aconf->host, aconf->user, aconf->reason, "");
1063 >               to, 'k', conf->host, conf->user, conf->reason);
1064    }
1065    /* Theyre opered, or allowed to see all klines */
1066    else {
1067      report_Klines(source_p, 1);
986 –    report_confitem_types(source_p, RKLINE_TYPE, 1);
1068    }
1069   }
1070  
1071   static void
1072 < stats_klines(struct Client *source_p)
1072 > stats_klines(struct Client *source_p, int parc, char *parv[])
1073   {
1074    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1075 <  if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
1075 >  if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1076      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1077                 from, to);
1078  
1079    /* If unopered, Only return matching klines */
1080 <  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
1080 >  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1081    {
1082 <    struct AccessItem *aconf;
1082 >    struct MaskItem *conf = NULL;
1083  
1084      /* search for a kline */
1085      if (MyConnect(source_p))
1086 <      aconf = find_conf_by_address(source_p->host,
1086 >      conf = find_conf_by_address(source_p->host,
1087                                     &source_p->localClient->ip,
1088 <                                   CONF_KILL,
1088 >                                   CONF_KLINE,
1089                                     source_p->localClient->aftype,
1090 <                                   source_p->username, NULL);
1090 >                                   source_p->username, NULL, 0);
1091      else
1092 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
1093 <                                   0, source_p->username, NULL);
1092 >      conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1093 >                                   0, source_p->username, NULL, 0);
1094  
1095 <    if (aconf == NULL)
1095 >    if (!conf)
1096        return;
1097  
1098      /* dont report a tkline as a kline */
1099 <    if (aconf->flags & CONF_FLAGS_TEMPORARY)
1099 >    if (conf->until)
1100        return;
1101        
1102      sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1103 <               to, "K", aconf->host, aconf->user, aconf->reason,
1023 <               aconf->oper_reason);
1103 >               to, 'K', conf->host, conf->user, conf->reason);
1104    }
1105    /* Theyre opered, or allowed to see all klines */
1106 <  else {
1106 >  else
1107      report_Klines(source_p, 0);
1028 –    report_confitem_types(source_p, RKLINE_TYPE, 0);
1029 –  }
1108   }
1109  
1110   static void
1111 < stats_messages(struct Client *source_p)
1111 > stats_messages(struct Client *source_p, int parc, char *parv[])
1112   {
1113    report_messages(source_p);
1114   }
1115  
1116   static void
1117 < stats_oper(struct Client *source_p)
1117 > stats_oper(struct Client *source_p, int parc, char *parv[])
1118   {
1119 <  if (!IsOper(source_p) && ConfigFileEntry.stats_o_oper_only)
1119 >  if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_o_oper_only)
1120      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1121                 from, to);
1122    else
1123 <    report_confitem_types(source_p, OPER_TYPE, 0);
1123 >    report_confitem_types(source_p, CONF_OPER);
1124   }
1125  
1126   /* stats_operedup()
# Line 1052 | Line 1130 | stats_oper(struct Client *source_p)
1130   * side effects - client is shown a list of active opers
1131   */
1132   static void
1133 < stats_operedup(struct Client *source_p)
1133 > stats_operedup(struct Client *source_p, int parc, char *parv[])
1134   {
1135    dlink_node *ptr;
1136  
# Line 1060 | Line 1138 | stats_operedup(struct Client *source_p)
1138    {
1139      const struct Client *target_p = ptr->data;
1140  
1141 <    if (IsOperHidden(target_p) && !IsOper(source_p))
1141 >    if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
1142        continue;
1143  
1144 <    if (MyClient(source_p) && IsOper(source_p))
1145 <      sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %d",
1144 >    if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
1145 >      sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %u",
1146                   from, RPL_STATSDEBUG, to,
1147 <                 IsAdmin(target_p) ?
1070 <                 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
1147 >                 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1148                   oper_privs_as_string(target_p->localClient->operflags),
1149                   target_p->name, target_p->username, target_p->host,
1150 <                 (int)(CurrentTime - target_p->localClient->last));
1150 >                 idle_time_get(source_p, target_p));
1151      else
1152 <      sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
1152 >      sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %u",
1153                   from, RPL_STATSDEBUG, to,
1154 <                 IsAdmin(target_p) ?
1078 <                 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
1154 >                 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1155                   target_p->name, target_p->username, target_p->host,
1156 <                 (int)(CurrentTime - target_p->localClient->last));
1156 >                 idle_time_get(source_p, target_p));
1157    }
1158  
1159 <  sendto_one(source_p, ":%s %d %s p :%lu OPER(s)",
1159 >  sendto_one(source_p, ":%s %d %s p :%u OPER(s)",
1160               from, RPL_STATSDEBUG, to, dlink_list_length(&oper_list));
1161   }
1162  
1163   static void
1164 < stats_ports(struct Client *source_p)
1164 > stats_ports(struct Client *source_p, int parc, char *parv[])
1165   {
1166 <  if (!IsOper(source_p) && ConfigFileEntry.stats_P_oper_only)
1166 >  if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_P_oper_only)
1167      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1168                 from, to);
1169    else
# Line 1095 | Line 1171 | stats_ports(struct Client *source_p)
1171   }
1172  
1173   static void
1174 < stats_resv(struct Client *source_p)
1174 > stats_resv(struct Client *source_p, int parc, char *parv[])
1175   {
1176    report_resv(source_p);
1177   }
1178  
1179   static void
1180 < stats_usage(struct Client *source_p)
1180 > stats_service(struct Client *source_p, int parc, char *parv[])
1181   {
1182 <  send_usage(source_p);
1182 >  report_confitem_types(source_p, CONF_SERVICE);
1183   }
1184  
1185   static void
1186 < stats_tstats(struct Client *source_p)
1186 > stats_tstats(struct Client *source_p, int parc, char *parv[])
1187   {
1188    const struct Client *target_p = NULL;
1189    const dlink_node *ptr = NULL;
1114 –  struct ServerStatistics *sp;
1190    struct ServerStatistics tmp;
1191 +  struct ServerStatistics *sp = &tmp;
1192  
1117 –  sp = &tmp;
1193    memcpy(sp, &ServerStats, sizeof(struct ServerStatistics));
1194  
1195    /*
# Line 1130 | Line 1205 | stats_tstats(struct Client *source_p)
1205  
1206      sp->is_sbs += target_p->localClient->send.bytes;
1207      sp->is_sbr += target_p->localClient->recv.bytes;
1208 <    sp->is_sti += CurrentTime - target_p->firsttime;
1208 >    sp->is_sti += CurrentTime - target_p->localClient->firsttime;
1209    }
1210  
1211    sp->is_cl += dlink_list_length(&local_client_list);
# Line 1141 | Line 1216 | stats_tstats(struct Client *source_p)
1216  
1217      sp->is_cbs += target_p->localClient->send.bytes;
1218      sp->is_cbr += target_p->localClient->recv.bytes;
1219 <    sp->is_cti += CurrentTime - target_p->firsttime;
1219 >    sp->is_cti += CurrentTime - target_p->localClient->firsttime;
1220    }
1221  
1222    sp->is_ni += dlink_list_length(&unknown_list);
# Line 1178 | Line 1253 | stats_tstats(struct Client *source_p)
1253   }
1254  
1255   static void
1256 < stats_uptime(struct Client *source_p)
1256 > stats_uptime(struct Client *source_p, int parc, char *parv[])
1257   {
1258 <  time_t now = CurrentTime - me.since;
1258 >  time_t now = CurrentTime - me.localClient->since;
1259 >
1260    sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
1261 <             now/86400, (now/3600)%24, (now/60)%60, now%60);
1262 <  if (!ConfigFileEntry.disable_remote || IsOper(source_p))
1261 >             now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
1262 >
1263 >  if (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER))
1264       sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
1265 <                MaxConnectionCount, MaxClientCount, Count.totalrestartcount);
1265 >                Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount);
1266   }
1267  
1268   static void
1269 < stats_shared(struct Client *source_p)
1269 > stats_shared(struct Client *source_p, int parc, char *parv[])
1270   {
1271 <  report_confitem_types(source_p, ULINE_TYPE, 0);
1271 >  report_confitem_types(source_p, CONF_ULINE);
1272   }
1273  
1274   /* stats_servers()
# Line 1201 | Line 1278 | stats_shared(struct Client *source_p)
1278   * side effects - client is shown lists of who connected servers
1279   */
1280   static void
1281 < stats_servers(struct Client *source_p)
1281 > stats_servers(struct Client *source_p, int parc, char *parv[])
1282   {
1283    dlink_node *ptr = NULL;
1284  
# Line 1212 | Line 1289 | stats_servers(struct Client *source_p)
1289      sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
1290                 from, RPL_STATSDEBUG, to, target_p->name,
1291                 (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1292 <               "*", "*", (int)(CurrentTime - target_p->lasttime));
1292 >               "*", "*", (int)(CurrentTime - target_p->localClient->lasttime));
1293    }
1294  
1295    sendto_one(source_p, ":%s %d %s v :%u Server(s)",
# Line 1220 | Line 1297 | stats_servers(struct Client *source_p)
1297   }
1298  
1299   static void
1300 < stats_gecos(struct Client *source_p)
1224 < {
1225 <  report_confitem_types(source_p, XLINE_TYPE, 0);
1226 <  report_confitem_types(source_p, RXLINE_TYPE, 0);
1227 < }
1228 <
1229 < static void
1230 < stats_class(struct Client *source_p)
1231 < {
1232 <  report_confitem_types(source_p, CLASS_TYPE, 0);
1233 < }
1234 <
1235 < static void
1236 < stats_memory(struct Client *source_p)
1300 > stats_gecos(struct Client *source_p, int parc, char *parv[])
1301   {
1302 <  count_memory(source_p);
1302 >  report_confitem_types(source_p, CONF_XLINE);
1303   }
1304  
1305   static void
1306 < stats_ziplinks(struct Client *source_p)
1306 > stats_class(struct Client *source_p, int parc, char *parv[])
1307   {
1308 <  dlink_node *ptr = NULL;
1245 <  unsigned int sent_data = 0;
1246 <
1247 <  DLINK_FOREACH(ptr, serv_list.head)
1248 <  {
1249 <    const struct Client *target_p = ptr->data;
1250 <
1251 <    if (IsCapable(target_p, CAP_ZIP))
1252 <    {
1253 <      /* we use memcpy(3) and a local copy of the structure to
1254 <       * work around a register use bug on GCC on the SPARC.
1255 <       * -jmallett, 04/27/2002
1256 <       */
1257 <      struct ZipStats zipstats;
1258 <
1259 <      memcpy(&zipstats, &target_p->localClient->zipstats, sizeof(zipstats));
1260 <
1261 <      sendto_one(source_p, ":%s %d %s Z :ZipLinks stats for %s send[%.2f%% "
1262 <                 "compression (%llu bytes data/%llu bytes wire)] recv[%.2f%% "
1263 <                 "compression (%llu bytes data/%llu bytes wire)]",
1264 <                 from, RPL_STATSDEBUG, to, target_p->name,
1265 <                 zipstats.out_ratio, zipstats.out, zipstats.out_wire,
1266 <                 zipstats.in_ratio,  zipstats.in,  zipstats.in_wire);
1267 <      ++sent_data;
1268 <    }
1269 <  }
1270 <
1271 <  sendto_one(source_p, ":%s %d %s Z :%u ziplink(s)",
1272 <             from, RPL_STATSDEBUG, to, sent_data);
1308 >  report_confitem_types(source_p, CONF_CLASS);
1309   }
1310  
1311   static void
1312 < stats_servlinks(struct Client *source_p)
1312 > stats_servlinks(struct Client *source_p, int parc, char *parv[])
1313   {
1314    uint64_t sendB = 0, recvB = 0;
1315    time_t uptime = 0;
1316    dlink_node *ptr = NULL;
1317  
1318 <  if (ConfigServerHide.flatten_links && !IsOper(source_p))
1318 >  if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
1319    {
1320      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1321                 from, to);
# Line 1290 | Line 1326 | stats_servlinks(struct Client *source_p)
1326    {
1327      struct Client *target_p = ptr->data;
1328  
1329 +    if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
1330 +      if (!HasUMode(source_p, UMODE_OPER))
1331 +        continue;
1332 +
1333      sendB += target_p->localClient->send.bytes;
1334      recvB += target_p->localClient->recv.bytes;
1335  
1336      /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
1337      sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1338                 from, to,
1339 <               get_client_name(target_p, IsAdmin(source_p) ? SHOW_IP : MASK_IP),
1339 >               get_client_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
1340                 dbuf_length(&target_p->localClient->buf_sendq),
1341                 target_p->localClient->send.messages,
1342                 target_p->localClient->send.bytes >> 10,
1343                 target_p->localClient->recv.messages,
1344                 target_p->localClient->recv.bytes >> 10,
1345 <               (unsigned)(CurrentTime - target_p->firsttime),
1346 <               (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since): 0,
1347 <               IsOper(source_p) ? show_capabilities(target_p) : "TS");
1345 >               (unsigned)(CurrentTime - target_p->localClient->firsttime),
1346 >               (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since): 0,
1347 >               HasUMode(source_p, UMODE_OPER) ? show_capabilities(target_p) : "TS");
1348    }
1349  
1350    sendB >>= 10;
# Line 1319 | Line 1359 | stats_servlinks(struct Client *source_p)
1359               from, RPL_STATSDEBUG, to,
1360               _GMKv(recvB), _GMKs(recvB));
1361  
1362 <  uptime = (CurrentTime - me.since);
1362 >  uptime = (CurrentTime - me.localClient->since);
1363  
1364    sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
1365               from, RPL_STATSDEBUG, to,
# Line 1335 | Line 1375 | stats_servlinks(struct Client *source_p)
1375               (float)uptime));
1376   }
1377  
1378 < static void
1379 < stats_ltrace(struct Client *source_p, int parc, char *parv[])
1378 > /* parse_stats_args()
1379 > *
1380 > * inputs       - arg count
1381 > *              - args
1382 > *              - doall flag
1383 > *              - wild card or not
1384 > * output       - pointer to name to use
1385 > * side effects -
1386 > * common parse routine for m_stats args
1387 > *
1388 > */
1389 > static char *
1390 > parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1391   {
1392 <  int doall = 0;
1342 <  int wilds = 0;
1343 <  char *name = NULL;
1344 <  char statchar;
1392 >  char *name;
1393  
1394 <  if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1394 >  if (parc > 2)
1395    {
1396 <    statchar = parv[1][0];
1396 >    name = parv[2];
1397  
1398 <    stats_L(source_p, name, doall, wilds, statchar);
1399 <  }
1400 <  else
1401 <    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1354 <               from, to, "STATS");
1355 < }
1398 >    if (!irccmp(name, from))
1399 >      *doall = 2;
1400 >    else if (!match(name, from))
1401 >      *doall = 1;
1402  
1403 < /*
1358 < * ms_stats - STATS message handler
1359 < *      parv[0] = sender prefix
1360 < *      parv[1] = statistics selector (defaults to Message frequency)
1361 < *      parv[2] = server name (current server defaulted, if omitted)
1362 < */
1363 < static void
1364 < ms_stats(struct Client *client_p, struct Client *source_p,
1365 <         int parc, char *parv[])
1366 < {
1367 <  if (hunt_server(client_p,source_p,":%s STATS %s :%s",2,parc,parv)!=HUNTED_ISME)
1368 <    return;
1403 >    *wilds = has_wildcards(name);
1404  
1405 <  if (IsClient(source_p))
1406 <    mo_stats(client_p, source_p, parc, parv);
1372 < }
1405 >    return name;
1406 >  }
1407  
1408 < /*
1375 < * stats_L
1376 < *
1377 < * inputs       - pointer to client to report to
1378 < *              - doall flag
1379 < *              - wild card or not
1380 < * output       - NONE
1381 < * side effects -
1382 < */
1383 < static void
1384 < stats_L(struct Client *source_p,char *name,int doall,
1385 <        int wilds,char statchar)
1386 < {
1387 <  stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1388 <  stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1389 <  stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1408 >  return NULL;
1409   }
1410  
1411   static void
# Line 1406 | Line 1425 | stats_L_list(struct Client *source_p,cha
1425    {
1426      target_p = ptr->data;
1427  
1428 <    if (IsInvisible(target_p) && (doall || wilds) &&
1429 <        !(MyConnect(source_p) && IsOper(source_p)) &&
1430 <        !IsOper(target_p) && (target_p != source_p))
1428 >    if (HasUMode(target_p, UMODE_INVISIBLE) && (doall || wilds) &&
1429 >        !(MyConnect(source_p) && HasUMode(source_p, UMODE_OPER)) &&
1430 >        !HasUMode(target_p, UMODE_OPER) && (target_p != source_p))
1431        continue;
1432 <    if (!doall && wilds && !match(name, target_p->name))
1432 >    if (!doall && wilds && match(name, target_p->name))
1433        continue;
1434      if (!(doall || wilds) && irccmp(name, target_p->name))
1435        continue;
1436  
1437      /* This basically shows ips for our opers if its not a server/admin, or
1438       * its one of our admins.  */
1439 <    if(MyClient(source_p) && IsOper(source_p) &&
1440 <       (IsAdmin(source_p) ||
1441 <       (!IsServer(target_p) && !IsAdmin(target_p) &&
1439 >    if(MyClient(source_p) && HasUMode(source_p, UMODE_OPER) &&
1440 >       (HasUMode(source_p, UMODE_ADMIN) ||
1441 >       (!IsServer(target_p) && !HasUMode(target_p, UMODE_ADMIN) &&
1442         !IsHandshake(target_p) && !IsConnecting(target_p))))
1443      {
1444        sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1445 <                 from, to,
1445 >                 from, to,
1446                   (IsUpper(statchar)) ?
1447                   get_client_name(target_p, SHOW_IP) :
1448                   get_client_name(target_p, HIDE_IP),
# Line 1432 | Line 1451 | stats_L_list(struct Client *source_p,cha
1451                   target_p->localClient->send.bytes>>10,
1452                   target_p->localClient->recv.messages,
1453                   target_p->localClient->recv.bytes>>10,
1454 <                 (unsigned)(CurrentTime - target_p->firsttime),
1455 <                 (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1454 >                 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1455 >                 (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1456                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1457      }
1458      else
1459      {
1460        /* If its a hidden ip, an admin, or a server, mask the real IP */
1461 <      if(IsIPSpoof(target_p) || IsServer(target_p) || IsAdmin(target_p)
1461 >      if(IsIPSpoof(target_p) || IsServer(target_p) || HasUMode(target_p, UMODE_ADMIN)
1462           || IsHandshake(target_p) || IsConnecting(target_p))
1463          sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1464                     from, to,
1465 <                   get_client_name(target_p, MASK_IP),
1466 <                   dbuf_length(&target_p->localClient->buf_sendq),
1467 <                   target_p->localClient->send.messages,
1468 <                   target_p->localClient->send.bytes>>10,
1469 <                   target_p->localClient->recv.messages,
1470 <                   target_p->localClient->recv.bytes>>10,
1471 <                   (unsigned)(CurrentTime - target_p->firsttime),
1472 <                   (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1473 <                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1465 >                   get_client_name(target_p, MASK_IP),
1466 >                   dbuf_length(&target_p->localClient->buf_sendq),
1467 >                   target_p->localClient->send.messages,
1468 >                   target_p->localClient->send.bytes>>10,
1469 >                   target_p->localClient->recv.messages,
1470 >                   target_p->localClient->recv.bytes>>10,
1471 >                   (unsigned)(CurrentTime - target_p->localClient->firsttime),
1472 >                   (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1473 >                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1474        else /* show the real IP */
1475          sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1476                     from, to,
1477 <                   (IsUpper(statchar)) ?
1478 <                   get_client_name(target_p, SHOW_IP) :
1479 <                   get_client_name(target_p, HIDE_IP),
1480 <                   dbuf_length(&target_p->localClient->buf_sendq),
1481 <                   target_p->localClient->send.messages,
1482 <                   target_p->localClient->send.bytes>>10,
1483 <                   target_p->localClient->recv.messages,
1484 <                   target_p->localClient->recv.bytes>>10,
1485 <                   (unsigned)(CurrentTime - target_p->firsttime),
1486 <                   (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1487 <                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1477 >                   (IsUpper(statchar)) ?
1478 >                   get_client_name(target_p, SHOW_IP) :
1479 >                   get_client_name(target_p, HIDE_IP),
1480 >                   dbuf_length(&target_p->localClient->buf_sendq),
1481 >                   target_p->localClient->send.messages,
1482 >                   target_p->localClient->send.bytes>>10,
1483 >                   target_p->localClient->recv.messages,
1484 >                   target_p->localClient->recv.bytes>>10,
1485 >                   (unsigned)(CurrentTime - target_p->localClient->firsttime),
1486 >                   (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1487 >                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1488      }
1489    }
1490   }
1491  
1492 < /* parse_stats_args()
1492 > /*
1493 > * stats_L
1494   *
1495 < * inputs       - arg count
1496 < *              - args
1497 < *              - doall flag
1498 < *              - wild card or not
1499 < * output       - pointer to name to use
1500 < * side effects -
1501 < * common parse routine for m_stats args
1495 > * inputs       - pointer to client to report to
1496 > *              - doall flag
1497 > *              - wild card or not
1498 > * output       - NONE
1499 > * side effects -
1500 > */
1501 > static void
1502 > stats_L(struct Client *source_p,char *name,int doall,
1503 >        int wilds,char statchar)
1504 > {
1505 >  stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1506 >  stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1507 >  stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1508 > }
1509 >
1510 > static void
1511 > stats_ltrace(struct Client *source_p, int parc, char *parv[])
1512 > {
1513 >  int doall = 0;
1514 >  int wilds = 0;
1515 >  char *name = NULL;
1516 >  char statchar;
1517 >
1518 >  if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1519 >  {
1520 >    statchar = parv[1][0];
1521 >
1522 >    stats_L(source_p, name, doall, wilds, statchar);
1523 >  }
1524 >  else
1525 >    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1526 >               from, to, "STATS");
1527 > }
1528 >
1529 > static const struct StatsStruct
1530 > {
1531 >  const unsigned char letter;
1532 >  void (*handler)();
1533 >  const unsigned int need_oper;
1534 >  const unsigned int need_admin;
1535 > } stats_cmd_table[] = {
1536 >  /* letter     function            need_oper need_admin */
1537 >  { 'a',        stats_dns_servers,      1,      1       },
1538 >  { 'A',        stats_dns_servers,      1,      1       },
1539 >  { 'c',        stats_connect,          1,      0       },
1540 >  { 'C',        stats_connect,          1,      0       },
1541 >  { 'd',        stats_tdeny,            1,      0       },
1542 >  { 'D',        stats_deny,             1,      0       },
1543 >  { 'e',        stats_exempt,           1,      0       },
1544 >  { 'E',        stats_events,           1,      1       },
1545 >  { 'f',        fd_dump,                1,      1       },
1546 >  { 'F',        fd_dump,                1,      1       },
1547 >  { 'g',        stats_pending_glines,   1,      0       },
1548 >  { 'G',        stats_glines,           1,      0       },
1549 >  { 'h',        stats_hooks,            1,      1       },
1550 >  { 'H',        stats_hubleaf,          1,      0       },
1551 >  { 'i',        stats_auth,             0,      0       },
1552 >  { 'I',        stats_auth,             0,      0       },
1553 >  { 'k',        stats_tklines,          0,      0       },
1554 >  { 'K',        stats_klines,           0,      0       },
1555 >  { 'l',        stats_ltrace,           1,      0       },
1556 >  { 'L',        stats_ltrace,           1,      0       },
1557 >  { 'm',        stats_messages,         0,      0       },
1558 >  { 'M',        stats_messages,         0,      0       },
1559 >  { 'o',        stats_oper,             0,      0       },
1560 >  { 'O',        stats_oper,             0,      0       },
1561 >  { 'p',        stats_operedup,         0,      0       },
1562 >  { 'P',        stats_ports,            0,      0       },
1563 >  { 'q',        stats_resv,             1,      0       },
1564 >  { 'Q',        stats_resv,             1,      0       },
1565 >  { 'r',        stats_usage,            1,      0       },
1566 >  { 'R',        stats_usage,            1,      0       },
1567 >  { 's',        stats_service,          1,      0       },
1568 >  { 'S',        stats_service,          1,      0       },
1569 >  { 't',        stats_tstats,           1,      0       },
1570 >  { 'T',        stats_tstats,           1,      0       },
1571 >  { 'u',        stats_uptime,           0,      0       },
1572 >  { 'U',        stats_shared,           1,      0       },
1573 >  { 'v',        stats_servers,          1,      0       },
1574 >  { 'x',        stats_gecos,            1,      0       },
1575 >  { 'X',        stats_gecos,            1,      0       },
1576 >  { 'y',        stats_class,            1,      0       },
1577 >  { 'Y',        stats_class,            1,      0       },
1578 >  { 'z',        stats_memory,           1,      0       },
1579 >  { '?',        stats_servlinks,        0,      0       },
1580 >  { '\0',       NULL,                   0,      0       }
1581 > };
1582 >
1583 > static void
1584 > do_stats(struct Client *source_p, int parc, char *parv[])
1585 > {
1586 >  const struct StatsStruct *tab = stats_cmd_table;
1587 >  const char statchar = *parv[1];
1588 >
1589 >  if (statchar == '\0')
1590 >  {
1591 >    sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1592 >               from, to, '*');
1593 >    return;
1594 >  }
1595 >
1596 >  for (; tab->handler; ++tab)
1597 >  {
1598 >    if (tab->letter == statchar)
1599 >    {
1600 >      /* The stats table says what privs are needed, so check --fl_ */
1601 >      if ((tab->need_admin && !HasUMode(source_p, UMODE_ADMIN)) ||
1602 >          (tab->need_oper && !HasUMode(source_p, UMODE_OPER)))
1603 >      {
1604 >        sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1605 >                   from, to);
1606 >        break;
1607 >      }
1608 >
1609 >      sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE,
1610 >                           "STATS %c requested by %s (%s@%s) [%s]",
1611 >                           statchar, source_p->name, source_p->username,
1612 >                           source_p->host, source_p->servptr->name);
1613 >      tab->handler(source_p, parc, parv);
1614 >      break;
1615 >    }
1616 >  }
1617 >
1618 >  sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1619 >             from, to, statchar);
1620 > }
1621 >
1622 > /*
1623 > * m_stats()
1624 > *      parv[0] = sender prefix
1625 > *      parv[1] = stat letter/command
1626 > *      parv[2] = (if present) server/mask in stats L
1627   *
1628 + * This will search the tables for the appropriate stats letter/command,
1629 + * if found execute it.  
1630   */
1631 < static char *
1632 < parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1631 > static void
1632 > m_stats(struct Client *client_p, struct Client *source_p,
1633 >        int parc, char *parv[])
1634   {
1635 <  char *name;
1635 >  static time_t last_used = 0;
1636  
1637 <  if (parc > 2)
1637 >  /* Is the stats meant for us? */
1638 >  if (!ConfigFileEntry.disable_remote)
1639 >    if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1640 >                    parc, parv) != HUNTED_ISME)
1641 >      return;
1642 >
1643 >  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1644    {
1645 <    name = parv[2];
1645 >    from = me.id;
1646 >    to = source_p->id;
1647 >  }
1648 >  else
1649 >  {
1650 >    from = me.name;
1651 >    to = source_p->name;
1652 >  }
1653  
1654 <    if (!irccmp(name, from))
1655 <      *doall = 2;
1656 <    else if (match(name, from))
1657 <      *doall = 1;
1654 >  /* Check the user is actually allowed to do /stats, and isnt flooding */
1655 >  if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
1656 >  {
1657 >    sendto_one(source_p,form_str(RPL_LOAD2HI),
1658 >               from, to);
1659 >    return;
1660 >  }
1661  
1662 <    if (strchr(name, '*') ||
1663 <        strchr(name, '?'))
1664 <      *wilds = 1;
1662 >  last_used = CurrentTime;
1663 >
1664 >  do_stats(source_p, parc, parv);
1665 > }
1666 >
1667 > /*
1668 > * mo_stats()
1669 > *      parv[0] = sender prefix
1670 > *      parv[1] = stat letter/command
1671 > *      parv[2] = (if present) server/mask in stats L, or target
1672 > *
1673 > * This will search the tables for the appropriate stats letter,
1674 > * if found execute it.  
1675 > */
1676 > static void
1677 > mo_stats(struct Client *client_p, struct Client *source_p,
1678 >         int parc, char *parv[])
1679 > {
1680 >  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1681 >                  parc, parv) != HUNTED_ISME)
1682 >     return;
1683  
1684 <    return(name);
1684 >  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1685 >  {
1686 >    from = me.id;
1687 >    to = source_p->id;
1688    }
1689    else
1690 <    return(NULL);
1690 >  {
1691 >    from = me.name;
1692 >    to = source_p->name;
1693 >  }
1694 >
1695 >  do_stats(source_p, parc, parv);
1696   }
1697 +
1698 + /*
1699 + * ms_stats - STATS message handler
1700 + *      parv[0] = sender prefix
1701 + *      parv[1] = statistics selector (defaults to Message frequency)
1702 + *      parv[2] = server name (current server defaulted, if omitted)
1703 + */
1704 + static void
1705 + ms_stats(struct Client *client_p, struct Client *source_p,
1706 +         int parc, char *parv[])
1707 + {
1708 +  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1709 +                  parc, parv) != HUNTED_ISME)
1710 +    return;
1711 +
1712 +  if (IsClient(source_p))
1713 +    mo_stats(client_p, source_p, parc, parv);
1714 + }
1715 +
1716 + static struct Message stats_msgtab = {
1717 +  "STATS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
1718 +  { m_unregistered, m_stats, ms_stats, m_ignore, mo_stats, m_ignore }
1719 + };
1720 +
1721 + static void
1722 + module_init(void)
1723 + {
1724 +  mod_add_cmd(&stats_msgtab);
1725 + }
1726 +
1727 + static void
1728 + module_exit(void)
1729 + {
1730 +  mod_del_cmd(&stats_msgtab);
1731 + }
1732 +
1733 + struct module module_entry = {
1734 +  .node    = { NULL, NULL, NULL },
1735 +  .name    = NULL,
1736 +  .version = "$Revision$",
1737 +  .handle  = NULL,
1738 +  .modinit = module_init,
1739 +  .modexit = module_exit,
1740 +  .flags   = 0
1741 + };

Diff Legend

– Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)