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 1121 by michael, Sun Jan 9 11:03:03 2011 UTC vs.
ircd-hybrid/trunk/modules/m_stats.c (file contents), Revision 2174 by michael, Mon Jun 3 19:45:38 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 + #include "motd.h"
52  
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 *[]);
53  
54 < 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 < };
54 > const char *from, *to;
55  
56 < const char *_version = "$Revision$";
57 < static struct Callback *stats_cb;
56 > static const struct shared_flags
57 > {
58 >  const unsigned int type;
59 >  const unsigned char letter;
60 > } flag_table[] = {
61 >  { SHARED_KLINE,   'K' },
62 >  { SHARED_UNKLINE, 'U' },
63 >  { SHARED_XLINE,   'X' },
64 >  { SHARED_UNXLINE, 'Y' },
65 >  { SHARED_RESV,    'Q' },
66 >  { SHARED_UNRESV,  'R' },
67 >  { SHARED_LOCOPS,  'L' },
68 >  { SHARED_DLINE,   'D' },
69 >  { SHARED_UNDLINE, 'E' },
70 >  { 0, '\0' }
71 > };
72  
73 < static void *
74 < va_stats(va_list args)
73 > /*
74 > * inputs       - pointer to client requesting confitem report
75 > *              - ConfType to report
76 > * output       - none
77 > * side effects -
78 > */
79 > static void
80 > report_confitem_types(struct Client *source_p, enum maskitem_type type)
81   {
82 <  struct Client *source_p = va_arg(args, struct Client *);
83 <  int parc = va_arg(args, int);
84 <  char **parv = va_arg(args, char **);
82 >  dlink_node *ptr = NULL;
83 >  struct MaskItem *conf = 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);
157 <
158 <      break;
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 <  }
161 >    break;
162  
163 <  sendto_one(source_p, form_str(RPL_ENDOFSTATS),
164 <             from, to, statchar);
165 < }
163 >  case CONF_SERVICE:
164 >    DLINK_FOREACH(ptr, service_items.head)
165 >    {
166 >      conf = ptr->data;
167 >      sendto_one(source_p, form_str(RPL_STATSSERVICE),
168 >                 me.name, source_p->name, 'S', "*", conf->name, 0, 0);
169 >    }
170 >    break;
171  
172 < /*
173 < * m_stats()
174 < *      parv[0] = sender prefix
175 < *      parv[1] = stat letter/command
176 < *      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;
172 >  case CONF_SERVER:
173 >    DLINK_FOREACH(ptr, server_items.head)
174 >    {
175 >      p = buf;
176 >      conf = ptr->data;
177  
178 <  /* 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;
178 >      buf[0] = '\0';
179  
180 <  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
181 <  {
182 <    from = me.id;
183 <    to = source_p->id;
184 <  }
185 <  else
252 <  {
253 <    from = me.name;
254 <    to = source_p->name;
255 <  }
180 >      if (IsConfAllowAutoConn(conf))
181 >        *p++ = 'A';
182 >      if (IsConfSSL(conf))
183 >        *p++ = 'S';
184 >      if (buf[0] == '\0')
185 >        *p++ = '*';
186  
187 <  /* 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 <  }
187 >      *p = '\0';
188  
189 <  last_used = CurrentTime;
189 >      /*
190 >       * Allow admins to see actual ips unless hide_server_ips is enabled
191 >       */
192 >      if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN))
193 >        sendto_one(source_p, form_str(RPL_STATSCLINE),
194 >                   me.name, source_p->name, 'C', conf->host,
195 >                   buf, conf->name, conf->port,
196 >                   conf->class ? conf->class->name : "<default>");
197 >        else
198 >          sendto_one(source_p, form_str(RPL_STATSCLINE),
199 >                     me.name, source_p->name, 'C',
200 >                     "*@127.0.0.1", buf, conf->name, conf->port,
201 >                     conf->class ? conf->class->name : "<default>");
202 >    }
203 >    break;
204  
205 <  execute_callback(stats_cb, source_p, parc, parv);
205 >  default:
206 >    break;
207 >  }
208   }
209  
210 < /*
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
210 > /* report_resv()
211   *
212 < * This will search the tables for the appropriate stats letter,
213 < * if found execute it.  
212 > * inputs       - pointer to client pointer to report to.
213 > * output       - NONE
214 > * side effects - report all resvs to client.
215   */
216   static void
217 < mo_stats(struct Client *client_p, struct Client *source_p,
281 <         int parc, char *parv[])
217 > report_resv(struct Client *source_p)
218   {
219 <  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
220 <                  parc, parv) != HUNTED_ISME)
285 <     return;
219 >  dlink_node *ptr = NULL;
220 >  struct MaskItem *conf = NULL;
221  
222 <  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
222 >  DLINK_FOREACH(ptr, cresv_items.head)
223    {
224 <    from = me.id;
225 <    to = source_p->id;
224 >    conf = ptr->data;
225 >    sendto_one(source_p, form_str(RPL_STATSQLINE),
226 >               me.name, source_p->name,
227 >               conf->until ? 'q' : 'Q', conf->count,
228 >               conf->name, conf->reason);
229    }
230 <  else
230 >
231 >  DLINK_FOREACH(ptr, nresv_items.head)
232    {
233 <    from = me.name;
234 <    to = source_p->name;
233 >    conf = ptr->data;
234 >    sendto_one(source_p, form_str(RPL_STATSQLINE),
235 >               me.name, source_p->name,
236 >               conf->until ? 'q' : 'Q', conf->count,
237 >               conf->name, conf->reason);
238    }
297 –
298 –  execute_callback(stats_cb, source_p, parc, parv);
239   }
240  
241   /*
# Line 306 | Line 246 | mo_stats(struct Client *client_p, struct
246   * -avalon
247   */
248   static void
249 < send_usage(struct Client *source_p)
249 > stats_usage(struct Client *source_p, int parc, char *parv[])
250   {
251    struct rusage rus;
252    time_t secs;
# Line 333 | Line 273 | send_usage(struct Client *source_p)
273    if (secs == 0)
274      secs = 1;
275  
276 <  rup = (CurrentTime - me.since) * hzz;
276 >  rup = (CurrentTime - me.localClient->since) * hzz;
277  
278    if (rup == 0)
279      rup = 1;
280  
281    sendto_one(source_p,
282 <             ":%s %d %s R :CPU Secs %d:%d User %d:%d System %d:%d",
282 >             ":%s %d %s R :CPU Secs %d:%02d User %d:%02d System %d:%02d",
283               me.name, RPL_STATSDEBUG, source_p->name, (int)(secs/60), (int)(secs%60),
284               (int)(rus.ru_utime.tv_sec/60), (int)(rus.ru_utime.tv_sec%60),
285               (int)(rus.ru_stime.tv_sec/60), (int)(rus.ru_stime.tv_sec%60));
# Line 362 | Line 302 | send_usage(struct Client *source_p)
302   }
303  
304   static void
305 < count_memory(struct Client *source_p)
305 > stats_memory(struct Client *source_p, int parc, char *parv[])
306   {
307    const dlink_node *gptr = NULL;
308    const dlink_node *dlink = NULL;
# Line 389 | Line 329 | count_memory(struct Client *source_p)
329    unsigned int safelist_count = 0;
330    uint64_t safelist_memory = 0;
331  
392 –  uint64_t away_memory = 0;       /* memory used by aways           */
332    uint64_t wwm = 0;               /* whowas array memory used       */
333    uint64_t conf_memory = 0;       /* memory used by conf lines      */
334    uint64_t mem_ips_stored;        /* memory used by ip address hash */
# Line 428 | Line 367 | count_memory(struct Client *source_p)
367      {
368        ++users_counted;
369  
370 <      if (target_p->away != NULL)
432 <      {
370 >      if (target_p->away[0])
371          ++aways_counted;
434 –        away_memory += strlen(target_p->away) + 1;
435 –      }
372      }
373    }
374  
# Line 447 | Line 383 | count_memory(struct Client *source_p)
383      channel_members += dlink_list_length(&chptr->members);
384      channel_invites += dlink_list_length(&chptr->invites);
385  
386 <    if (chptr->topic != NULL)
386 >    if (chptr->topic[0])
387        ++topic_count;
388  
389      channel_bans += dlink_list_length(&chptr->banlist);
# Line 515 | Line 451 | count_memory(struct Client *source_p)
451    }
452   #endif
453    /* count up all classes */
454 <  class_count = dlink_list_length(&class_items);
454 >  class_count = dlink_list_length(class_get_list());
455  
456    count_whowas_memory(&wwu, &wwm);
457    watch_count_memory(&watch_list_headers, &watch_list_memory);
458  
459 <  sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%u) entries %d(%d)",
459 >  sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%llu) entries %d(%u)",
460               me.name, RPL_STATSDEBUG, source_p->name, watch_list_headers,
461               watch_list_memory, watch_list_entries,
462               watch_list_entries * sizeof(dlink_node) * 2);
# Line 529 | Line 465 | count_memory(struct Client *source_p)
465               me.name, RPL_STATSDEBUG, source_p->name, users_counted,
466               (users_counted * sizeof(struct Client)));
467  
468 <  sendto_one(source_p, ":%s %d %s z :User aways %u(%llu)",
468 >  sendto_one(source_p, ":%s %d %s z :User aways %u",
469               me.name, RPL_STATSDEBUG, source_p->name,
470 <             aways_counted, away_memory);
470 >             aways_counted);
471  
472    sendto_one(source_p, ":%s %d %s z :Attached confs %u(%llu)",
473               me.name, RPL_STATSDEBUG, source_p->name,
474               local_client_conf_count,
475               (unsigned long long)(local_client_conf_count * sizeof(dlink_node)));
476  
477 <  sendto_one(source_p, ":%s %d %s z :Resv channels %lu(%lu) nicks %lu(%lu)",
477 >  sendto_one(source_p, ":%s %d %s z :Resv channels %u(%lu) nicks %u(%lu)",
478               me.name, RPL_STATSDEBUG, source_p->name,
479 <             dlink_list_length(&resv_channel_list),
480 <             dlink_list_length(&resv_channel_list) * sizeof(struct ResvChannel),
479 >             dlink_list_length(&cresv_items),
480 >             dlink_list_length(&cresv_items) * sizeof(struct MaskItem),
481               dlink_list_length(&nresv_items),
482 <             dlink_list_length(&nresv_items) * sizeof(struct MatchItem));
482 >             dlink_list_length(&nresv_items) * sizeof(struct MaskItem));
483  
484    sendto_one(source_p, ":%s %d %s z :Classes %u(%llu)",
485               me.name, RPL_STATSDEBUG, source_p->name,
486               class_count, (unsigned long long)(class_count * sizeof(struct ClassItem)));
487  
488 <  sendto_one(source_p, ":%s %d %s z :Channels %lu(%llu) Topics %u(%d)",
488 >  sendto_one(source_p, ":%s %d %s z :Channels %u(%llu) Topics %u(%u)",
489               me.name, RPL_STATSDEBUG, source_p->name,
490               dlink_list_length(&global_channel_list),
491               channel_memory, topic_count, topic_count *
# Line 591 | Line 527 | count_memory(struct Client *source_p)
527  
528    totww = wwu * sizeof(struct Client) + wwm;
529  
530 +  motd_memory_count(source_p);
531    count_ip_hash(&number_ips_stored,&mem_ips_stored);
532    sendto_one(source_p, ":%s %d %s z :iphash %u(%llu)",
533               me.name, RPL_STATSDEBUG, source_p->name,
# Line 604 | Line 541 | count_memory(struct Client *source_p)
541  
542    local_client_memory_used = local_client_count*(sizeof(struct Client) + sizeof(struct LocalUser));
543    total_memory += local_client_memory_used;
544 <  sendto_one(source_p, ":%s %d %s z :Local client Memory in use: %d(%llu)",
544 >  sendto_one(source_p, ":%s %d %s z :Local client Memory in use: %u(%llu)",
545               me.name, RPL_STATSDEBUG, source_p->name, local_client_count,
546               local_client_memory_used);
547  
548    remote_client_memory_used = remote_client_count * sizeof(struct Client);
549    total_memory += remote_client_memory_used;
550 <  sendto_one(source_p, ":%s %d %s z :Remote client Memory in use: %d(%llu)",
550 >  sendto_one(source_p, ":%s %d %s z :Remote client Memory in use: %u(%llu)",
551               me.name, RPL_STATSDEBUG, source_p->name, remote_client_count,
552               remote_client_memory_used);
553  
617 –  block_heap_report_stats(source_p);
618 –
554    sendto_one(source_p,
555               ":%s %d %s z :TOTAL: %llu",
556               me.name, RPL_STATSDEBUG, source_p->name,
# Line 629 | Line 564 | stats_dns_servers(struct Client *source_
564   }
565  
566   static void
567 < stats_connect(struct Client *source_p)
567 > stats_connect(struct Client *source_p, int parc, char *parv[])
568   {
569 <  report_confitem_types(source_p, SERVER_TYPE, 0);
569 >  report_confitem_types(source_p, CONF_SERVER);
570   }
571  
572   /* stats_deny()
# Line 641 | Line 576 | stats_connect(struct Client *source_p)
576   * side effects - client is given dline list.
577   */
578   static void
579 < stats_deny(struct Client *source_p)
579 > stats_deny(struct Client *source_p, int parc, char *parv[])
580   {
581 <  struct AddressRec *arec;
582 <  struct ConfItem *conf;
583 <  struct AccessItem *aconf;
584 <  int i;
581 >  struct MaskItem *conf;
582 >  dlink_node *ptr = NULL;
583 >  unsigned int i = 0;
584 >
585  
586 <  for (i = 0; i < ATABLE_SIZE; i++)
586 >  for (i = 0; i < ATABLE_SIZE; ++i)
587    {
588 <    for (arec = atable[i]; arec; arec=arec->next)
588 >    DLINK_FOREACH(ptr, atable[i].head)
589      {
590 <      if (arec->type == CONF_DLINE)
656 <      {
657 <        aconf = arec->aconf;
590 >      struct AddressRec *arec = ptr->data;
591  
592 <        /* dont report a tdline as a dline */
593 <        if (aconf->flags & CONF_FLAGS_TEMPORARY)
661 <          continue;
592 >      if (arec->type != CONF_DLINE)
593 >        continue;
594  
595 <        conf = unmap_conf_item(aconf);
595 >      conf = arec->conf;
596  
597 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
598 <                   from, to, 'D', aconf->host, aconf->reason,
599 <                   aconf->oper_reason);
600 <      }
597 >      /* dont report a tdline as a dline */
598 >      if (conf->until)
599 >        continue;
600 >
601 >      sendto_one(source_p, form_str(RPL_STATSDLINE),
602 >                 from, to, 'D', conf->host, conf->reason);
603      }
604    }
605   }
# Line 677 | Line 611 | stats_deny(struct Client *source_p)
611   * side effects - client is given dline list.
612   */
613   static void
614 < stats_tdeny(struct Client *source_p)
614 > stats_tdeny(struct Client *source_p, int parc, char *parv[])
615   {
616 <  struct AddressRec *arec;
617 <  struct ConfItem *conf;
618 <  struct AccessItem *aconf;
685 <  int i;
616 >  struct MaskItem *conf = NULL;
617 >  dlink_node *ptr = NULL;
618 >  unsigned int i = 0;
619  
620 <  for (i = 0; i < ATABLE_SIZE; i++)
620 >
621 >  for (i = 0; i < ATABLE_SIZE; ++i)
622    {
623 <    for (arec = atable[i]; arec; arec=arec->next)
623 >    DLINK_FOREACH(ptr, atable[i].head)
624      {
625 <      if (arec->type == CONF_DLINE)
692 <      {
693 <        aconf = arec->aconf;
625 >      struct AddressRec *arec = ptr->data;
626  
627 <        /* dont report a permanent dline as a tdline */
628 <        if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
697 <          continue;
627 >      if (arec->type != CONF_DLINE)
628 >        continue;
629  
630 <        conf = unmap_conf_item(aconf);
630 >      conf = arec->conf;
631  
632 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
633 <                   from, to, 'd', aconf->host, aconf->reason,
634 <                   aconf->oper_reason);
635 <      }
632 >      /* dont report a permanent dline as a tdline */
633 >      if (!conf->until)
634 >        continue;
635 >
636 >      sendto_one(source_p, form_str(RPL_STATSDLINE),
637 >                 from, to, 'd', conf->host, conf->reason);
638      }
639    }
640   }
# Line 713 | Line 646 | stats_tdeny(struct Client *source_p)
646   * side effects - client is given list of exempt blocks
647   */
648   static void
649 < stats_exempt(struct Client *source_p)
649 > stats_exempt(struct Client *source_p, int parc, char *parv[])
650   {
651 <  struct AddressRec *arec;
652 <  struct ConfItem *conf;
653 <  struct AccessItem *aconf;
721 <  int i;
651 >  struct MaskItem *conf;
652 >  dlink_node *ptr = NULL;
653 >  unsigned int i = 0;
654  
655    if (ConfigFileEntry.stats_e_disabled)
656    {
# Line 727 | Line 659 | stats_exempt(struct Client *source_p)
659      return;
660    }
661  
662 <  for (i = 0; i < ATABLE_SIZE; i++)
662 >
663 >  for (i = 0; i < ATABLE_SIZE; ++i)
664    {
665 <    for (arec = atable[i]; arec; arec=arec->next)
665 >    DLINK_FOREACH(ptr, atable[i].head)
666      {
667 <      if (arec->type == CONF_EXEMPTDLINE)
735 <      {
736 <        aconf = arec->aconf;
667 >      struct AddressRec *arec = ptr->data;
668  
669 <        conf = unmap_conf_item(aconf);
669 >      if (arec->type != CONF_EXEMPT)
670 >        continue;
671  
672 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
673 <                   from, to, 'e', aconf->host,
674 <                   aconf->reason, aconf->oper_reason);
675 <      }
672 >      conf = arec->conf;
673 >
674 >      sendto_one(source_p, form_str(RPL_STATSDLINE), from, to, 'e',
675 >                 conf->host, "");
676      }
677    }
678   }
679  
680   static void
681 < stats_events(struct Client *source_p)
681 > stats_events(struct Client *source_p, int parc, char *parv[])
682   {
683    show_events(source_p);
684   }
# Line 758 | Line 690 | stats_events(struct Client *source_p)
690   * side effects - client is shown list of pending glines
691   */
692   static void
693 < stats_pending_glines(struct Client *source_p)
693 > stats_pending_glines(struct Client *source_p, int parc, char *parv[])
694   {
695    const dlink_node *dn_ptr = NULL;
696    const struct gline_pending *glp_ptr = NULL;
# Line 847 | Line 779 | stats_pending_glines(struct Client *sour
779   * side effects - client is shown list of glines
780   */
781   static void
782 < stats_glines(struct Client *source_p)
782 > stats_glines(struct Client *source_p, int parc, char *parv[])
783   {
784 <  struct AddressRec *arec = NULL;
785 <  int i = 0;
784 >  dlink_node *ptr = NULL;
785 >  unsigned int i = 0;
786  
787    if (!ConfigFileEntry.glines)
788    {
# Line 859 | Line 791 | stats_glines(struct Client *source_p)
791      return;
792    }
793  
794 <  for (; i < ATABLE_SIZE; ++i)
794 >  for (i = 0; i < ATABLE_SIZE; ++i)
795    {
796 <    for (arec = atable[i]; arec; arec = arec->next)
796 >    DLINK_FOREACH(ptr, atable[i].head)
797      {
798 +      const struct AddressRec *arec = ptr->data;
799 +
800        if (arec->type == CONF_GLINE)
801        {
802 <        const struct AccessItem *aconf = arec->aconf;
802 >        const struct MaskItem *conf = arec->conf;
803  
804          sendto_one(source_p, form_str(RPL_STATSKLINE),
805 <                   from, to, "G",
806 <                   aconf->host ? aconf->host : "*",
807 <                   aconf->user ? aconf->user : "*",
808 <                   aconf->reason ? aconf->reason : "No reason", "" );
805 >                   from, to, 'G',
806 >                   conf->host ? conf->host : "*",
807 >                   conf->user ? conf->user : "*",
808 >                   conf->reason ? conf->reason : CONF_NOREASON);
809        }
810      }
811    }
812   }
813  
880 – /* stats_gdeny()
881 – *
882 – * input        - client pointer
883 – * outputs      - none
884 – * side effects - client is shown gline ACL
885 – */
814   static void
815 < stats_gdeny(struct Client *source_p)
815 > stats_hubleaf(struct Client *source_p, int parc, char *parv[])
816   {
817 <  if (!ConfigFileEntry.glines)
817 >  const dlink_node *ptr = NULL, *dptr = NULL;
818 >
819 >  DLINK_FOREACH(ptr, server_items.head)
820    {
821 <    sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
822 <               from, to);
823 <    return;
821 >    const struct MaskItem *conf = ptr->data;
822 >
823 >    DLINK_FOREACH(dptr, conf->hub_list.head)
824 >      sendto_one(source_p, form_str(RPL_STATSHLINE), me.name,
825 >                 source_p->name, 'H', dptr->data, conf->name, 0, "*");
826    }
827  
828 <  report_confitem_types(source_p, GDENY_TYPE, 0);
828 >  DLINK_FOREACH(ptr, server_items.head)
829 >  {
830 >    const struct MaskItem *conf = ptr->data;
831 >
832 >    DLINK_FOREACH(dptr, conf->leaf_list.head)
833 >      sendto_one(source_p, form_str(RPL_STATSLLINE), me.name,
834 >                 source_p->name, 'L', dptr->data, conf->name, 0, "*");
835 >  }
836 > }
837 >
838 > /*
839 > * show_iline_prefix()
840 > *
841 > * inputs       - pointer to struct Client requesting output
842 > *              - pointer to struct MaskItem
843 > *              - name to which iline prefix will be prefixed to
844 > * output       - pointer to static string with prefixes listed in ascii form
845 > * side effects - NONE
846 > */
847 > static const char *
848 > show_iline_prefix(const struct Client *sptr, const struct MaskItem *conf)
849 > {
850 >  static char prefix_of_host[USERLEN + 15];
851 >  char *prefix_ptr = prefix_of_host;
852 >
853 >  if (IsConfWebIRC(conf))
854 >    *prefix_ptr++ = '<';
855 >  if (IsNoTilde(conf))
856 >    *prefix_ptr++ = '-';
857 >  if (IsLimitIp(conf))
858 >    *prefix_ptr++ = '!';
859 >  if (IsNeedIdentd(conf))
860 >    *prefix_ptr++ = '+';
861 >  if (!IsNeedPassword(conf))
862 >    *prefix_ptr++ = '&';
863 >  if (IsConfExemptResv(conf))
864 >    *prefix_ptr++ = '$';
865 >  if (IsNoMatchIp(conf))
866 >    *prefix_ptr++ = '%';
867 >  if (IsConfDoSpoofIp(conf))
868 >    *prefix_ptr++ = '=';
869 >  if (MyOper(sptr) && IsConfExemptKline(conf))
870 >    *prefix_ptr++ = '^';
871 >  if (MyOper(sptr) && IsConfExemptGline(conf))
872 >    *prefix_ptr++ = '_';
873 >  if (MyOper(sptr) && IsConfExemptLimits(conf))
874 >    *prefix_ptr++ = '>';
875 >  if (IsConfCanFlood(conf))
876 >    *prefix_ptr++ = '|';
877 >
878 >  strlcpy(prefix_ptr, conf->user, USERLEN+1);
879 >
880 >  return prefix_of_host;
881   }
882  
883   static void
884 < stats_hubleaf(struct Client *source_p)
884 > report_auth(struct Client *client_p, int parc, char *parv[])
885   {
886 <  report_confitem_types(source_p, HUB_TYPE, 0);
887 <  report_confitem_types(source_p, LEAF_TYPE, 0);
886 >  struct MaskItem *conf = NULL;
887 >  dlink_node *ptr = NULL;
888 >  unsigned int i;
889 >
890 >
891 >  for (i = 0; i < ATABLE_SIZE; ++i)
892 >  {
893 >    DLINK_FOREACH(ptr, atable[i].head)
894 >    {
895 >      struct AddressRec *arec = ptr->data;
896 >
897 >      if (arec->type != CONF_CLIENT)
898 >        continue;
899 >
900 >      conf = arec->conf;
901 >
902 >      if (!MyOper(client_p) && IsConfDoSpoofIp(conf))
903 >        continue;
904 >
905 >      /* We are doing a partial list, based on what matches the u@h of the
906 >       * sender, so prepare the strings for comparing --fl_
907 >       */
908 >      if (ConfigFileEntry.hide_spoof_ips)
909 >        sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
910 >                   client_p->name, 'I',
911 >                   conf->name == NULL ? "*" : conf->name,
912 >                   show_iline_prefix(client_p, conf),
913 >                   IsConfDoSpoofIp(conf) ? "255.255.255.255" :
914 >                   conf->host, conf->port,
915 >                   conf->class ? conf->class->name : "<default>");
916 >
917 >      else
918 >        sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
919 >                   client_p->name, 'I',
920 >                   conf->name == NULL ? "*" : conf->name,
921 >                   show_iline_prefix(client_p, conf),
922 >                   conf->host, conf->port,
923 >                   conf->class ? conf->class->name : "<default>");
924 >    }
925 >  }
926   }
927  
928   static void
929 < stats_auth(struct Client *source_p)
929 > stats_auth(struct Client *source_p, int parc, char *parv[])
930   {
931    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
932 <  if ((ConfigFileEntry.stats_i_oper_only == 2) && !IsOper(source_p))
932 >  if ((ConfigFileEntry.stats_i_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
933      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
934                 from, to);
935  
936    /* If unopered, Only return matching auth blocks */
937 <  else if ((ConfigFileEntry.stats_i_oper_only == 1) && !IsOper(source_p))
937 >  else if ((ConfigFileEntry.stats_i_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
938    {
939 <    struct ConfItem *conf;
918 <    struct AccessItem *aconf;
939 >    struct MaskItem *conf;
940  
941      if (MyConnect(source_p))
942 <      aconf = find_conf_by_address(source_p->host,
942 >      conf = find_conf_by_address(source_p->host,
943                                     &source_p->localClient->ip,
944                                     CONF_CLIENT,
945                                     source_p->localClient->aftype,
946                                     source_p->username,
947 <                                   source_p->localClient->passwd);
947 >                                   source_p->localClient->passwd, 1);
948      else
949 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
950 <                                   0, source_p->username, NULL);
949 >      conf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
950 >                                   0, source_p->username, NULL, 1);
951  
952 <    if (aconf == NULL)
952 >    if (conf == NULL)
953        return;
954  
934 –    conf = unmap_conf_item(aconf);
935 –
955      sendto_one(source_p, form_str(RPL_STATSILINE), from,
956                 to, 'I',
957 <               "*", show_iline_prefix(source_p, aconf, aconf->user),
958 <               aconf->host, aconf->port,
959 <               aconf->class_ptr ? aconf->class_ptr->name : "<default>");
957 >               "*", show_iline_prefix(source_p, conf),
958 >               conf->host, conf->port,
959 >               conf->class ? conf->class->name : "<default>");
960    }
961    /* They are opered, or allowed to see all auth blocks */
962    else
963 <    report_auth(source_p);
963 >    report_auth(source_p, 0, NULL);
964   }
965  
966 + /* report_Klines()
967 + * Inputs: Client to report to,
968 + *         type(==0 for perm, !=0 for temporary)
969 + *         mask
970 + * Output: None
971 + * Side effects: Reports configured K(or k)-lines to client_p.
972 + */
973   static void
974 < stats_tklines(struct Client *source_p)
974 > report_Klines(struct Client *client_p, int tkline)
975 > {
976 >  struct MaskItem *conf = NULL;
977 >  unsigned int i = 0;
978 >  char c = '\0';
979 >  dlink_node *ptr = NULL;
980 >
981 >  if (tkline)
982 >    c = 'k';
983 >  else
984 >    c = 'K';
985 >
986 >  for (i = 0; i < ATABLE_SIZE; ++i)
987 >  {
988 >    DLINK_FOREACH(ptr, atable[i].head)
989 >    {
990 >      struct AddressRec *arec = ptr->data;
991 >
992 >      if (arec->type != CONF_KLINE)
993 >        continue;
994 >
995 >      conf = arec->conf;
996 >
997 >      if ((!tkline && conf->until) ||
998 >          (tkline && !conf->until))
999 >        continue;
1000 >
1001 >      if (HasUMode(client_p, UMODE_OPER))
1002 >        sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1003 >                   client_p->name, c, conf->host, conf->user,
1004 >                   conf->reason);
1005 >      else
1006 >        sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1007 >                   client_p->name, c, conf->host, conf->user,
1008 >                   conf->reason);
1009 >    }
1010 >  }
1011 > }
1012 >
1013 > static void
1014 > stats_tklines(struct Client *source_p, int parc, char *parv[])
1015   {
950 –  struct ConfItem *conf;
1016    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1017 <  if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
1017 >  if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1018      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1019                 from, to);
1020  
1021    /* If unopered, Only return matching klines */
1022 <  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
1022 >  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1023    {
1024 <    struct AccessItem *aconf;
1024 >    struct MaskItem *conf = NULL;
1025  
1026      if (MyConnect(source_p))
1027 <      aconf = find_conf_by_address(source_p->host,
1028 <                                   &source_p->localClient->ip,
1029 <                                   CONF_KILL,
1027 >      conf = find_conf_by_address(source_p->host,
1028 >                                  &source_p->localClient->ip,
1029 >                                   CONF_KLINE,
1030                                     source_p->localClient->aftype,
1031 <                                   source_p->username, NULL);
1031 >                                   source_p->username, NULL, 1);
1032      else
1033 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
1034 <                                   0, source_p->username, NULL);
1033 >      conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1034 >                                   0, source_p->username, NULL, 1);
1035  
1036 <    if (aconf == NULL)
1036 >    if (!conf)
1037        return;
1038  
1039      /* dont report a permanent kline as a tkline */
1040 <    if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
1040 >    if (!conf->until)
1041        return;
1042  
978 –    conf = unmap_conf_item(aconf);
979 –
1043      sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1044 <               to, "k", aconf->host, aconf->user, aconf->reason, "");
1044 >               to, 'k', conf->host, conf->user, conf->reason);
1045    }
1046    /* Theyre opered, or allowed to see all klines */
1047    else {
1048      report_Klines(source_p, 1);
986 –    report_confitem_types(source_p, RKLINE_TYPE, 1);
1049    }
1050   }
1051  
1052   static void
1053 < stats_klines(struct Client *source_p)
1053 > stats_klines(struct Client *source_p, int parc, char *parv[])
1054   {
1055    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1056 <  if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
1056 >  if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1057      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1058                 from, to);
1059  
1060    /* If unopered, Only return matching klines */
1061 <  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
1061 >  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1062    {
1063 <    struct AccessItem *aconf;
1063 >    struct MaskItem *conf = NULL;
1064  
1065      /* search for a kline */
1066      if (MyConnect(source_p))
1067 <      aconf = find_conf_by_address(source_p->host,
1067 >      conf = find_conf_by_address(source_p->host,
1068                                     &source_p->localClient->ip,
1069 <                                   CONF_KILL,
1069 >                                   CONF_KLINE,
1070                                     source_p->localClient->aftype,
1071 <                                   source_p->username, NULL);
1071 >                                   source_p->username, NULL, 0);
1072      else
1073 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
1074 <                                   0, source_p->username, NULL);
1073 >      conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1074 >                                   0, source_p->username, NULL, 0);
1075  
1076 <    if (aconf == NULL)
1076 >    if (!conf)
1077        return;
1078  
1079      /* dont report a tkline as a kline */
1080 <    if (aconf->flags & CONF_FLAGS_TEMPORARY)
1080 >    if (conf->until)
1081        return;
1082        
1083      sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1084 <               to, "K", aconf->host, aconf->user, aconf->reason,
1023 <               aconf->oper_reason);
1084 >               to, 'K', conf->host, conf->user, conf->reason);
1085    }
1086    /* Theyre opered, or allowed to see all klines */
1087 <  else {
1087 >  else
1088      report_Klines(source_p, 0);
1028 –    report_confitem_types(source_p, RKLINE_TYPE, 0);
1029 –  }
1089   }
1090  
1091   static void
1092 < stats_messages(struct Client *source_p)
1092 > stats_messages(struct Client *source_p, int parc, char *parv[])
1093   {
1094    report_messages(source_p);
1095   }
1096  
1097   static void
1098 < stats_oper(struct Client *source_p)
1098 > stats_oper(struct Client *source_p, int parc, char *parv[])
1099   {
1100 <  if (!IsOper(source_p) && ConfigFileEntry.stats_o_oper_only)
1100 >  if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_o_oper_only)
1101      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1102                 from, to);
1103    else
1104 <    report_confitem_types(source_p, OPER_TYPE, 0);
1104 >    report_confitem_types(source_p, CONF_OPER);
1105   }
1106  
1107   /* stats_operedup()
# Line 1052 | Line 1111 | stats_oper(struct Client *source_p)
1111   * side effects - client is shown a list of active opers
1112   */
1113   static void
1114 < stats_operedup(struct Client *source_p)
1114 > stats_operedup(struct Client *source_p, int parc, char *parv[])
1115   {
1116    dlink_node *ptr;
1117  
# Line 1060 | Line 1119 | stats_operedup(struct Client *source_p)
1119    {
1120      const struct Client *target_p = ptr->data;
1121  
1122 <    if (IsOperHidden(target_p) && !IsOper(source_p))
1122 >    if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
1123        continue;
1124  
1125 <    if (MyClient(source_p) && IsOper(source_p))
1126 <      sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %d",
1125 >    if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
1126 >      sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %u",
1127                   from, RPL_STATSDEBUG, to,
1128 <                 IsAdmin(target_p) ?
1070 <                 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
1128 >                 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1129                   oper_privs_as_string(target_p->localClient->operflags),
1130                   target_p->name, target_p->username, target_p->host,
1131 <                 (int)(CurrentTime - target_p->localClient->last));
1131 >                 idle_time_get(source_p, target_p));
1132      else
1133 <      sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
1133 >      sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %u",
1134                   from, RPL_STATSDEBUG, to,
1135 <                 IsAdmin(target_p) ?
1078 <                 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
1135 >                 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1136                   target_p->name, target_p->username, target_p->host,
1137 <                 (int)(CurrentTime - target_p->localClient->last));
1137 >                 idle_time_get(source_p, target_p));
1138    }
1139  
1140 <  sendto_one(source_p, ":%s %d %s p :%lu OPER(s)",
1140 >  sendto_one(source_p, ":%s %d %s p :%u OPER(s)",
1141               from, RPL_STATSDEBUG, to, dlink_list_length(&oper_list));
1142   }
1143  
1144   static void
1145 < stats_ports(struct Client *source_p)
1145 > stats_ports(struct Client *source_p, int parc, char *parv[])
1146   {
1147 <  if (!IsOper(source_p) && ConfigFileEntry.stats_P_oper_only)
1147 >  if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_P_oper_only)
1148      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1149                 from, to);
1150    else
# Line 1095 | Line 1152 | stats_ports(struct Client *source_p)
1152   }
1153  
1154   static void
1155 < stats_resv(struct Client *source_p)
1155 > stats_resv(struct Client *source_p, int parc, char *parv[])
1156   {
1157    report_resv(source_p);
1158   }
1159  
1160   static void
1161 < stats_usage(struct Client *source_p)
1161 > stats_service(struct Client *source_p, int parc, char *parv[])
1162   {
1163 <  send_usage(source_p);
1163 >  report_confitem_types(source_p, CONF_SERVICE);
1164   }
1165  
1166   static void
1167 < stats_tstats(struct Client *source_p)
1167 > stats_tstats(struct Client *source_p, int parc, char *parv[])
1168   {
1169    const struct Client *target_p = NULL;
1170    const dlink_node *ptr = NULL;
1114 –  struct ServerStatistics *sp;
1171    struct ServerStatistics tmp;
1172 +  struct ServerStatistics *sp = &tmp;
1173  
1117 –  sp = &tmp;
1174    memcpy(sp, &ServerStats, sizeof(struct ServerStatistics));
1175  
1176    /*
# Line 1130 | Line 1186 | stats_tstats(struct Client *source_p)
1186  
1187      sp->is_sbs += target_p->localClient->send.bytes;
1188      sp->is_sbr += target_p->localClient->recv.bytes;
1189 <    sp->is_sti += CurrentTime - target_p->firsttime;
1189 >    sp->is_sti += CurrentTime - target_p->localClient->firsttime;
1190    }
1191  
1192    sp->is_cl += dlink_list_length(&local_client_list);
# Line 1141 | Line 1197 | stats_tstats(struct Client *source_p)
1197  
1198      sp->is_cbs += target_p->localClient->send.bytes;
1199      sp->is_cbr += target_p->localClient->recv.bytes;
1200 <    sp->is_cti += CurrentTime - target_p->firsttime;
1200 >    sp->is_cti += CurrentTime - target_p->localClient->firsttime;
1201    }
1202  
1203    sp->is_ni += dlink_list_length(&unknown_list);
# Line 1178 | Line 1234 | stats_tstats(struct Client *source_p)
1234   }
1235  
1236   static void
1237 < stats_uptime(struct Client *source_p)
1237 > stats_uptime(struct Client *source_p, int parc, char *parv[])
1238   {
1239 <  time_t now = CurrentTime - me.since;
1239 >  time_t now = CurrentTime - me.localClient->since;
1240 >
1241    sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
1242 <             now/86400, (now/3600)%24, (now/60)%60, now%60);
1243 <  if (!ConfigFileEntry.disable_remote || IsOper(source_p))
1242 >             now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
1243 >
1244 >  if (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER))
1245       sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
1246 <                MaxConnectionCount, MaxClientCount, Count.totalrestartcount);
1246 >                Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount);
1247   }
1248  
1249   static void
1250 < stats_shared(struct Client *source_p)
1250 > stats_shared(struct Client *source_p, int parc, char *parv[])
1251   {
1252 <  report_confitem_types(source_p, ULINE_TYPE, 0);
1252 >  report_confitem_types(source_p, CONF_ULINE);
1253   }
1254  
1255   /* stats_servers()
# Line 1201 | Line 1259 | stats_shared(struct Client *source_p)
1259   * side effects - client is shown lists of who connected servers
1260   */
1261   static void
1262 < stats_servers(struct Client *source_p)
1262 > stats_servers(struct Client *source_p, int parc, char *parv[])
1263   {
1264 <  struct Client *target_p;
1207 <  dlink_node *ptr;
1208 <  int j = 0;
1264 >  dlink_node *ptr = NULL;
1265  
1266    DLINK_FOREACH(ptr, serv_list.head)
1267    {
1268 <    target_p = ptr->data;
1213 <
1214 <    j++;
1268 >    const struct Client *target_p = ptr->data;
1269  
1270      sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
1271 <               from, RPL_STATSDEBUG, to,
1272 <               target_p->name,
1273 <               (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1220 <               "*", "*", (int)(CurrentTime - target_p->lasttime));
1271 >               from, RPL_STATSDEBUG, to, target_p->name,
1272 >               (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1273 >               "*", "*", (int)(CurrentTime - target_p->localClient->lasttime));
1274    }
1275  
1276 <  sendto_one(source_p, ":%s %d %s v :%d Server(s)",
1277 <             from, RPL_STATSDEBUG, to, j);
1225 < }
1226 <
1227 < static void
1228 < stats_gecos(struct Client *source_p)
1229 < {
1230 <  report_confitem_types(source_p, XLINE_TYPE, 0);
1231 <  report_confitem_types(source_p, RXLINE_TYPE, 0);
1232 < }
1233 <
1234 < static void
1235 < stats_class(struct Client *source_p)
1236 < {
1237 <  report_confitem_types(source_p, CLASS_TYPE, 0);
1276 >  sendto_one(source_p, ":%s %d %s v :%u Server(s)",
1277 >             from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
1278   }
1279  
1280   static void
1281 < stats_memory(struct Client *source_p)
1281 > stats_gecos(struct Client *source_p, int parc, char *parv[])
1282   {
1283 <  count_memory(source_p);
1283 >  report_confitem_types(source_p, CONF_XLINE);
1284   }
1285  
1286   static void
1287 < stats_ziplinks(struct Client *source_p)
1287 > stats_class(struct Client *source_p, int parc, char *parv[])
1288   {
1289 <  dlink_node *ptr = NULL;
1250 <  unsigned int sent_data = 0;
1289 >  const dlink_node *ptr = NULL;
1290  
1291 <  DLINK_FOREACH(ptr, serv_list.head)
1291 >  DLINK_FOREACH(ptr, class_get_list()->head)
1292    {
1293 <    const struct Client *target_p = ptr->data;
1255 <
1256 <    if (IsCapable(target_p, CAP_ZIP))
1257 <    {
1258 <      /* we use memcpy(3) and a local copy of the structure to
1259 <       * work around a register use bug on GCC on the SPARC.
1260 <       * -jmallett, 04/27/2002
1261 <       */
1262 <      struct ZipStats zipstats;
1293 >    const struct ClassItem *class = ptr->data;
1294  
1295 <      memcpy(&zipstats, &target_p->localClient->zipstats, sizeof(zipstats));
1296 <
1297 <      sendto_one(source_p, ":%s %d %s Z :ZipLinks stats for %s send[%.2f%% "
1298 <                 "compression (%llu bytes data/%llu bytes wire)] recv[%.2f%% "
1299 <                 "compression (%llu bytes data/%llu bytes wire)]",
1300 <                 from, RPL_STATSDEBUG, to, target_p->name,
1301 <                 zipstats.out_ratio, zipstats.out, zipstats.out_wire,
1302 <                 zipstats.in_ratio,  zipstats.in,  zipstats.in_wire);
1303 <      ++sent_data;
1304 <    }
1295 >    sendto_one(source_p, form_str(RPL_STATSYLINE),
1296 >               me.name, source_p->name, 'Y',
1297 >               class->name, class->ping_freq,
1298 >               class->con_freq,
1299 >               class->max_total, class->max_sendq,
1300 >               class->max_recvq,
1301 >               class->ref_count,
1302 >               class->number_per_cidr, class->cidr_bitlen_ipv4,
1303 >               class->number_per_cidr, class->cidr_bitlen_ipv6,
1304 >               class->active ? "active" : "disabled");
1305    }
1275 –
1276 –  sendto_one(source_p, ":%s %d %s Z :%u ziplink(s)",
1277 –             from, RPL_STATSDEBUG, to, sent_data);
1306   }
1307  
1308   static void
1309 < stats_servlinks(struct Client *source_p)
1309 > stats_servlinks(struct Client *source_p, int parc, char *parv[])
1310   {
1311    uint64_t sendB = 0, recvB = 0;
1312    time_t uptime = 0;
1313    dlink_node *ptr = NULL;
1314  
1315 <  if (ConfigServerHide.flatten_links && !IsOper(source_p))
1315 >  if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
1316    {
1317      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1318                 from, to);
# Line 1295 | Line 1323 | stats_servlinks(struct Client *source_p)
1323    {
1324      struct Client *target_p = ptr->data;
1325  
1326 +    if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
1327 +      if (!HasUMode(source_p, UMODE_OPER))
1328 +        continue;
1329 +
1330      sendB += target_p->localClient->send.bytes;
1331      recvB += target_p->localClient->recv.bytes;
1332  
1333      /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
1334      sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1335                 from, to,
1336 <               get_client_name(target_p, IsAdmin(source_p) ? SHOW_IP : MASK_IP),
1336 >               get_client_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
1337                 dbuf_length(&target_p->localClient->buf_sendq),
1338                 target_p->localClient->send.messages,
1339                 target_p->localClient->send.bytes >> 10,
1340                 target_p->localClient->recv.messages,
1341                 target_p->localClient->recv.bytes >> 10,
1342 <               (unsigned)(CurrentTime - target_p->firsttime),
1343 <               (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since): 0,
1344 <               IsOper(source_p) ? show_capabilities(target_p) : "TS");
1342 >               (unsigned)(CurrentTime - target_p->localClient->firsttime),
1343 >               (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since): 0,
1344 >               HasUMode(source_p, UMODE_OPER) ? show_capabilities(target_p) : "TS");
1345    }
1346  
1347    sendB >>= 10;
# Line 1324 | Line 1356 | stats_servlinks(struct Client *source_p)
1356               from, RPL_STATSDEBUG, to,
1357               _GMKv(recvB), _GMKs(recvB));
1358  
1359 <  uptime = (CurrentTime - me.since);
1359 >  uptime = (CurrentTime - me.localClient->since);
1360  
1361    sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
1362               from, RPL_STATSDEBUG, to,
# Line 1340 | Line 1372 | stats_servlinks(struct Client *source_p)
1372               (float)uptime));
1373   }
1374  
1375 < static void
1376 < stats_ltrace(struct Client *source_p, int parc, char *parv[])
1375 > /* parse_stats_args()
1376 > *
1377 > * inputs       - arg count
1378 > *              - args
1379 > *              - doall flag
1380 > *              - wild card or not
1381 > * output       - pointer to name to use
1382 > * side effects -
1383 > * common parse routine for m_stats args
1384 > *
1385 > */
1386 > static char *
1387 > parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1388   {
1389 <  int doall = 0;
1347 <  int wilds = 0;
1348 <  char *name = NULL;
1349 <  char statchar;
1389 >  char *name;
1390  
1391 <  if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1391 >  if (parc > 2)
1392    {
1393 <    statchar = parv[1][0];
1393 >    name = parv[2];
1394  
1395 <    stats_L(source_p, name, doall, wilds, statchar);
1396 <  }
1397 <  else
1398 <    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1359 <               from, to, "STATS");
1360 < }
1395 >    if (!irccmp(name, from))
1396 >      *doall = 2;
1397 >    else if (!match(name, from))
1398 >      *doall = 1;
1399  
1400 < /*
1363 < * ms_stats - STATS message handler
1364 < *      parv[0] = sender prefix
1365 < *      parv[1] = statistics selector (defaults to Message frequency)
1366 < *      parv[2] = server name (current server defaulted, if omitted)
1367 < */
1368 < static void
1369 < ms_stats(struct Client *client_p, struct Client *source_p,
1370 <         int parc, char *parv[])
1371 < {
1372 <  if (hunt_server(client_p,source_p,":%s STATS %s :%s",2,parc,parv)!=HUNTED_ISME)
1373 <    return;
1400 >    *wilds = has_wildcards(name);
1401  
1402 <  if (IsClient(source_p))
1403 <    mo_stats(client_p, source_p, parc, parv);
1377 < }
1402 >    return name;
1403 >  }
1404  
1405 < /*
1380 < * stats_L
1381 < *
1382 < * inputs       - pointer to client to report to
1383 < *              - doall flag
1384 < *              - wild card or not
1385 < * output       - NONE
1386 < * side effects -
1387 < */
1388 < static void
1389 < stats_L(struct Client *source_p,char *name,int doall,
1390 <        int wilds,char statchar)
1391 < {
1392 <  stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1393 <  stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1394 <  stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1405 >  return NULL;
1406   }
1407  
1408   static void
# Line 1411 | Line 1422 | stats_L_list(struct Client *source_p,cha
1422    {
1423      target_p = ptr->data;
1424  
1425 <    if (IsInvisible(target_p) && (doall || wilds) &&
1426 <        !(MyConnect(source_p) && IsOper(source_p)) &&
1427 <        !IsOper(target_p) && (target_p != source_p))
1425 >    if (HasUMode(target_p, UMODE_INVISIBLE) && (doall || wilds) &&
1426 >        !(MyConnect(source_p) && HasUMode(source_p, UMODE_OPER)) &&
1427 >        !HasUMode(target_p, UMODE_OPER) && (target_p != source_p))
1428        continue;
1429 <    if (!doall && wilds && !match(name, target_p->name))
1429 >    if (!doall && wilds && match(name, target_p->name))
1430        continue;
1431      if (!(doall || wilds) && irccmp(name, target_p->name))
1432        continue;
1433  
1434      /* This basically shows ips for our opers if its not a server/admin, or
1435       * its one of our admins.  */
1436 <    if(MyClient(source_p) && IsOper(source_p) &&
1437 <       (IsAdmin(source_p) ||
1438 <       (!IsServer(target_p) && !IsAdmin(target_p) &&
1436 >    if(MyClient(source_p) && HasUMode(source_p, UMODE_OPER) &&
1437 >       (HasUMode(source_p, UMODE_ADMIN) ||
1438 >       (!IsServer(target_p) && !HasUMode(target_p, UMODE_ADMIN) &&
1439         !IsHandshake(target_p) && !IsConnecting(target_p))))
1440      {
1441        sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1442 <                 from, to,
1442 >                 from, to,
1443                   (IsUpper(statchar)) ?
1444                   get_client_name(target_p, SHOW_IP) :
1445                   get_client_name(target_p, HIDE_IP),
# Line 1437 | Line 1448 | stats_L_list(struct Client *source_p,cha
1448                   target_p->localClient->send.bytes>>10,
1449                   target_p->localClient->recv.messages,
1450                   target_p->localClient->recv.bytes>>10,
1451 <                 (unsigned)(CurrentTime - target_p->firsttime),
1452 <                 (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1451 >                 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1452 >                 (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1453                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1454      }
1455      else
1456      {
1457        /* If its a hidden ip, an admin, or a server, mask the real IP */
1458 <      if(IsIPSpoof(target_p) || IsServer(target_p) || IsAdmin(target_p)
1458 >      if(IsIPSpoof(target_p) || IsServer(target_p) || HasUMode(target_p, UMODE_ADMIN)
1459           || IsHandshake(target_p) || IsConnecting(target_p))
1460          sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1461                     from, to,
1462 <                   get_client_name(target_p, MASK_IP),
1463 <                   dbuf_length(&target_p->localClient->buf_sendq),
1464 <                   target_p->localClient->send.messages,
1465 <                   target_p->localClient->send.bytes>>10,
1466 <                   target_p->localClient->recv.messages,
1467 <                   target_p->localClient->recv.bytes>>10,
1468 <                   (unsigned)(CurrentTime - target_p->firsttime),
1469 <                   (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1470 <                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1462 >                   get_client_name(target_p, MASK_IP),
1463 >                   dbuf_length(&target_p->localClient->buf_sendq),
1464 >                   target_p->localClient->send.messages,
1465 >                   target_p->localClient->send.bytes>>10,
1466 >                   target_p->localClient->recv.messages,
1467 >                   target_p->localClient->recv.bytes>>10,
1468 >                   (unsigned)(CurrentTime - target_p->localClient->firsttime),
1469 >                   (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1470 >                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1471        else /* show the real IP */
1472          sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1473                     from, to,
1474 <                   (IsUpper(statchar)) ?
1475 <                   get_client_name(target_p, SHOW_IP) :
1476 <                   get_client_name(target_p, HIDE_IP),
1477 <                   dbuf_length(&target_p->localClient->buf_sendq),
1478 <                   target_p->localClient->send.messages,
1479 <                   target_p->localClient->send.bytes>>10,
1480 <                   target_p->localClient->recv.messages,
1481 <                   target_p->localClient->recv.bytes>>10,
1482 <                   (unsigned)(CurrentTime - target_p->firsttime),
1483 <                   (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1484 <                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1474 >                   (IsUpper(statchar)) ?
1475 >                   get_client_name(target_p, SHOW_IP) :
1476 >                   get_client_name(target_p, HIDE_IP),
1477 >                   dbuf_length(&target_p->localClient->buf_sendq),
1478 >                   target_p->localClient->send.messages,
1479 >                   target_p->localClient->send.bytes>>10,
1480 >                   target_p->localClient->recv.messages,
1481 >                   target_p->localClient->recv.bytes>>10,
1482 >                   (unsigned)(CurrentTime - target_p->localClient->firsttime),
1483 >                   (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1484 >                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1485      }
1486    }
1487   }
1488  
1489 < /* parse_stats_args()
1489 > /*
1490 > * stats_L
1491   *
1492 < * inputs       - arg count
1493 < *              - args
1494 < *              - doall flag
1495 < *              - wild card or not
1496 < * output       - pointer to name to use
1497 < * side effects -
1498 < * common parse routine for m_stats args
1492 > * inputs       - pointer to client to report to
1493 > *              - doall flag
1494 > *              - wild card or not
1495 > * output       - NONE
1496 > * side effects -
1497 > */
1498 > static void
1499 > stats_L(struct Client *source_p,char *name,int doall,
1500 >        int wilds,char statchar)
1501 > {
1502 >  stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1503 >  stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1504 >  stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1505 > }
1506 >
1507 > static void
1508 > stats_ltrace(struct Client *source_p, int parc, char *parv[])
1509 > {
1510 >  int doall = 0;
1511 >  int wilds = 0;
1512 >  char *name = NULL;
1513 >  char statchar;
1514 >
1515 >  if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1516 >  {
1517 >    statchar = parv[1][0];
1518 >
1519 >    stats_L(source_p, name, doall, wilds, statchar);
1520 >  }
1521 >  else
1522 >    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1523 >               from, to, "STATS");
1524 > }
1525 >
1526 > static const struct StatsStruct
1527 > {
1528 >  const unsigned char letter;
1529 >  void (*handler)();
1530 >  const unsigned int need_oper;
1531 >  const unsigned int need_admin;
1532 > } stats_cmd_table[] = {
1533 >  /* letter     function            need_oper need_admin */
1534 >  { 'a',        stats_dns_servers,      1,      1       },
1535 >  { 'A',        stats_dns_servers,      1,      1       },
1536 >  { 'c',        stats_connect,          1,      0       },
1537 >  { 'C',        stats_connect,          1,      0       },
1538 >  { 'd',        stats_tdeny,            1,      0       },
1539 >  { 'D',        stats_deny,             1,      0       },
1540 >  { 'e',        stats_exempt,           1,      0       },
1541 >  { 'E',        stats_events,           1,      1       },
1542 >  { 'f',        fd_dump,                1,      1       },
1543 >  { 'F',        fd_dump,                1,      1       },
1544 >  { 'g',        stats_pending_glines,   1,      0       },
1545 >  { 'G',        stats_glines,           1,      0       },
1546 >  { 'h',        stats_hooks,            1,      1       },
1547 >  { 'H',        stats_hubleaf,          1,      0       },
1548 >  { 'i',        stats_auth,             0,      0       },
1549 >  { 'I',        stats_auth,             0,      0       },
1550 >  { 'k',        stats_tklines,          0,      0       },
1551 >  { 'K',        stats_klines,           0,      0       },
1552 >  { 'l',        stats_ltrace,           1,      0       },
1553 >  { 'L',        stats_ltrace,           1,      0       },
1554 >  { 'm',        stats_messages,         0,      0       },
1555 >  { 'M',        stats_messages,         0,      0       },
1556 >  { 'o',        stats_oper,             0,      0       },
1557 >  { 'O',        stats_oper,             0,      0       },
1558 >  { 'p',        stats_operedup,         0,      0       },
1559 >  { 'P',        stats_ports,            0,      0       },
1560 >  { 'q',        stats_resv,             1,      0       },
1561 >  { 'Q',        stats_resv,             1,      0       },
1562 >  { 'r',        stats_usage,            1,      0       },
1563 >  { 'R',        stats_usage,            1,      0       },
1564 >  { 's',        stats_service,          1,      0       },
1565 >  { 'S',        stats_service,          1,      0       },
1566 >  { 't',        stats_tstats,           1,      0       },
1567 >  { 'T',        motd_report,            1,      0       },
1568 >  { 'u',        stats_uptime,           0,      0       },
1569 >  { 'U',        stats_shared,           1,      0       },
1570 >  { 'v',        stats_servers,          1,      0       },
1571 >  { 'x',        stats_gecos,            1,      0       },
1572 >  { 'X',        stats_gecos,            1,      0       },
1573 >  { 'y',        stats_class,            1,      0       },
1574 >  { 'Y',        stats_class,            1,      0       },
1575 >  { 'z',        stats_memory,           1,      0       },
1576 >  { '?',        stats_servlinks,        0,      0       },
1577 >  { '\0',       NULL,                   0,      0       }
1578 > };
1579 >
1580 > static void
1581 > do_stats(struct Client *source_p, int parc, char *parv[])
1582 > {
1583 >  const struct StatsStruct *tab = stats_cmd_table;
1584 >  const char statchar = *parv[1];
1585 >
1586 >  if (statchar == '\0')
1587 >  {
1588 >    sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1589 >               from, to, '*');
1590 >    return;
1591 >  }
1592 >
1593 >  for (; tab->handler; ++tab)
1594 >  {
1595 >    if (tab->letter == statchar)
1596 >    {
1597 >      /* The stats table says what privs are needed, so check --fl_ */
1598 >      if ((tab->need_admin && !HasUMode(source_p, UMODE_ADMIN)) ||
1599 >          (tab->need_oper && !HasUMode(source_p, UMODE_OPER)))
1600 >      {
1601 >        sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1602 >                   from, to);
1603 >        break;
1604 >      }
1605 >
1606 >      sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE,
1607 >                           "STATS %c requested by %s (%s@%s) [%s]",
1608 >                           statchar, source_p->name, source_p->username,
1609 >                           source_p->host, source_p->servptr->name);
1610 >      tab->handler(source_p, parc, parv);
1611 >      break;
1612 >    }
1613 >  }
1614 >
1615 >  sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1616 >             from, to, statchar);
1617 > }
1618 >
1619 > /*
1620 > * m_stats()
1621 > *      parv[0] = sender prefix
1622 > *      parv[1] = stat letter/command
1623 > *      parv[2] = (if present) server/mask in stats L
1624   *
1625 + * This will search the tables for the appropriate stats letter/command,
1626 + * if found execute it.  
1627   */
1628 < static char *
1629 < parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1628 > static void
1629 > m_stats(struct Client *client_p, struct Client *source_p,
1630 >        int parc, char *parv[])
1631   {
1632 <  char *name;
1632 >  static time_t last_used = 0;
1633  
1634 <  if (parc > 2)
1634 >  /* Is the stats meant for us? */
1635 >  if (!ConfigFileEntry.disable_remote)
1636 >    if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1637 >                    parc, parv) != HUNTED_ISME)
1638 >      return;
1639 >
1640 >  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1641    {
1642 <    name = parv[2];
1642 >    from = me.id;
1643 >    to = source_p->id;
1644 >  }
1645 >  else
1646 >  {
1647 >    from = me.name;
1648 >    to = source_p->name;
1649 >  }
1650  
1651 <    if (!irccmp(name, from))
1652 <      *doall = 2;
1653 <    else if (match(name, from))
1654 <      *doall = 1;
1651 >  /* Check the user is actually allowed to do /stats, and isnt flooding */
1652 >  if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
1653 >  {
1654 >    sendto_one(source_p,form_str(RPL_LOAD2HI),
1655 >               from, to);
1656 >    return;
1657 >  }
1658  
1659 <    if (strchr(name, '*') ||
1660 <        strchr(name, '?'))
1661 <      *wilds = 1;
1659 >  last_used = CurrentTime;
1660 >
1661 >  do_stats(source_p, parc, parv);
1662 > }
1663  
1664 <    return(name);
1664 > /*
1665 > * mo_stats()
1666 > *      parv[0] = sender prefix
1667 > *      parv[1] = stat letter/command
1668 > *      parv[2] = (if present) server/mask in stats L, or target
1669 > *
1670 > * This will search the tables for the appropriate stats letter,
1671 > * if found execute it.  
1672 > */
1673 > static void
1674 > mo_stats(struct Client *client_p, struct Client *source_p,
1675 >         int parc, char *parv[])
1676 > {
1677 >  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1678 >                  parc, parv) != HUNTED_ISME)
1679 >     return;
1680 >
1681 >  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1682 >  {
1683 >    from = me.id;
1684 >    to = source_p->id;
1685    }
1686    else
1687 <    return(NULL);
1687 >  {
1688 >    from = me.name;
1689 >    to = source_p->name;
1690 >  }
1691 >
1692 >  do_stats(source_p, parc, parv);
1693   }
1694 +
1695 + /*
1696 + * ms_stats - STATS message handler
1697 + *      parv[0] = sender prefix
1698 + *      parv[1] = statistics selector (defaults to Message frequency)
1699 + *      parv[2] = server name (current server defaulted, if omitted)
1700 + */
1701 + static void
1702 + ms_stats(struct Client *client_p, struct Client *source_p,
1703 +         int parc, char *parv[])
1704 + {
1705 +  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1706 +                  parc, parv) != HUNTED_ISME)
1707 +    return;
1708 +
1709 +  if (IsClient(source_p))
1710 +    mo_stats(client_p, source_p, parc, parv);
1711 + }
1712 +
1713 + static struct Message stats_msgtab = {
1714 +  "STATS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
1715 +  { m_unregistered, m_stats, ms_stats, m_ignore, mo_stats, m_ignore }
1716 + };
1717 +
1718 + static void
1719 + module_init(void)
1720 + {
1721 +  mod_add_cmd(&stats_msgtab);
1722 + }
1723 +
1724 + static void
1725 + module_exit(void)
1726 + {
1727 +  mod_del_cmd(&stats_msgtab);
1728 + }
1729 +
1730 + struct module module_entry = {
1731 +  .node    = { NULL, NULL, NULL },
1732 +  .name    = NULL,
1733 +  .version = "$Revision$",
1734 +  .handle  = NULL,
1735 +  .modinit = module_init,
1736 +  .modexit = module_exit,
1737 +  .flags   = 0
1738 + };

Diff Legend

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