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-8/modules/m_stats.c (file contents), Revision 1176 by michael, Sun Aug 14 11:24:24 2011 UTC vs.
ircd-hybrid/trunk/modules/m_stats.c (file contents), Revision 1925 by michael, Tue Apr 30 15:22:51 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 */
# Line 51 | Line 47
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 < };
64 <
65 < const char *_version = "$Revision$";
66 <
67 < void
68 < _modinit(void)
69 < {
70 <  mod_add_cmd(&stats_msgtab);
71 < }
72 <
73 < void
74 < _moddeinit(void)
75 < {
76 <  mod_del_cmd(&stats_msgtab);
77 < }
53 > const char *from, *to;
54  
55 < static char *parse_stats_args(int, char **, int *, int *);
80 < static void stats_L(struct Client *, char *, int, int, char);
81 < static void stats_L_list(struct Client *, char *, int, int, dlink_list *, char);
82 <
83 < static void stats_dns_servers(struct Client *);
84 < static void stats_connect(struct Client *);
85 < static void stats_deny(struct Client *);
86 < static void stats_tdeny(struct Client *);
87 < static void stats_exempt(struct Client *);
88 < static void stats_events(struct Client *);
89 < static void stats_pending_glines(struct Client *);
90 < static void stats_glines(struct Client *);
91 < static void stats_gdeny(struct Client *);
92 < static void stats_hubleaf(struct Client *);
93 < static void stats_auth(struct Client *);
94 < static void stats_tklines(struct Client *);
95 < static void stats_klines(struct Client *);
96 < static void stats_messages(struct Client *);
97 < static void stats_oper(struct Client *);
98 < static void stats_operedup(struct Client *);
99 < static void stats_ports(struct Client *);
100 < static void stats_resv(struct Client *);
101 < static void stats_usage(struct Client *);
102 < static void stats_service(struct Client *);
103 < static void stats_tstats(struct Client *);
104 < static void stats_uptime(struct Client *);
105 < static void stats_shared(struct Client *);
106 < static void stats_servers(struct Client *);
107 < static void stats_gecos(struct Client *);
108 < static void stats_class(struct Client *);
109 < static void stats_memory(struct Client *);
110 < static void stats_servlinks(struct Client *);
111 < static void stats_ltrace(struct Client *, int, char **);
112 < static void stats_ziplinks(struct Client *);
113 <
114 < /* This table contains the possible stats items, in order:
115 < * /stats name,  function to call, operonly? adminonly? /stats letter
116 < * case only matters in the stats letter column.. -- fl_ */
117 < static const struct StatsStruct
55 > static const struct shared_flags
56   {
57 +  const unsigned int type;
58    const unsigned char letter;
59 <  void (*handler)();
60 <  const unsigned int need_oper;
61 <  const unsigned int need_admin;
62 < } stats_cmd_table[] = {
63 <  /* letter     function            need_oper need_admin */
64 <  { 'a',        stats_dns_servers,      1,      1       },
65 <  { 'A',        stats_dns_servers,      1,      1       },
66 <  { 'c',        stats_connect,          1,      0       },
67 <  { 'C',        stats_connect,          1,      0       },
68 <  { 'd',        stats_tdeny,            1,      0       },
69 <  { 'D',        stats_deny,             1,      0       },
131 <  { 'e',        stats_exempt,           1,      0       },
132 <  { 'E',        stats_events,           1,      1       },
133 <  { 'f',        fd_dump,                1,      1       },
134 <  { 'F',        fd_dump,                1,      1       },
135 <  { 'g',        stats_pending_glines,   1,      0       },
136 <  { 'G',        stats_glines,           1,      0       },
137 <  { 'h',        stats_hooks,            1,      1       },
138 <  { 'H',        stats_hubleaf,          1,      0       },
139 <  { 'i',        stats_auth,             0,      0       },
140 <  { 'I',        stats_auth,             0,      0       },
141 <  { 'k',        stats_tklines,          0,      0       },
142 <  { 'K',        stats_klines,           0,      0       },
143 <  { 'l',        stats_ltrace,           1,      0       },
144 <  { 'L',        stats_ltrace,           1,      0       },
145 <  { 'm',        stats_messages,         0,      0       },
146 <  { 'M',        stats_messages,         0,      0       },
147 <  { 'o',        stats_oper,             0,      0       },
148 <  { 'O',        stats_oper,             0,      0       },
149 <  { 'p',        stats_operedup,         0,      0       },
150 <  { 'P',        stats_ports,            0,      0       },
151 <  { 'q',        stats_resv,             1,      0       },
152 <  { 'Q',        stats_resv,             1,      0       },
153 <  { 'r',        stats_usage,            1,      0       },
154 <  { 'R',        stats_usage,            1,      0       },
155 <  { 'S',        stats_service,          1,      0       },
156 <  { 't',        stats_tstats,           1,      0       },
157 <  { 'T',        stats_tstats,           1,      0       },
158 <  { 'u',        stats_uptime,           0,      0       },
159 <  { 'U',        stats_shared,           1,      0       },
160 <  { 'v',        stats_servers,          1,      0       },
161 <  { 'V',        stats_gdeny,            1,      0       },
162 <  { 'x',        stats_gecos,            1,      0       },
163 <  { 'X',        stats_gecos,            1,      0       },
164 <  { 'y',        stats_class,            1,      0       },
165 <  { 'Y',        stats_class,            1,      0       },
166 <  { 'z',        stats_memory,           1,      0       },
167 <  { 'Z',        stats_ziplinks,         1,      0       },
168 <  { '?',        stats_servlinks,        0,      0       },
169 <  { '\0',       NULL,                   0,      0       }
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 < const char *from, *to;
73 <
72 > /*
73 > * inputs       - pointer to client requesting confitem report
74 > *              - ConfType to report
75 > * output       - none
76 > * side effects -
77 > */
78   static void
79 < do_stats(struct Client *source_p, int parc, char *parv[])
79 > report_confitem_types(struct Client *source_p, enum maskitem_type type)
80   {
81 <  const struct StatsStruct *tab = stats_cmd_table;
82 <  char statchar = *parv[1];
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 <  if (statchar == '\0')
88 >  switch (type)
89    {
90 <    sendto_one(source_p, form_str(RPL_ENDOFSTATS),
91 <               from, to, '*');
92 <    return;
93 <  }
90 >  case CONF_XLINE:
91 >    DLINK_FOREACH(ptr, xconf_items.head)
92 >    {
93 >      conf = ptr->data;
94  
95 <  for (; tab->handler; ++tab)
96 <  {
97 <    if (tab->letter == statchar)
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 >  case CONF_ULINE:
103 >    shared = flag_table;
104 >    DLINK_FOREACH(ptr, uconf_items.head)
105      {
106 <      /* The stats table says what privs are needed, so check --fl_ */
192 <      if ((tab->need_admin && !IsAdmin(source_p)) ||
193 <          (tab->need_oper && !IsOper(source_p)))
194 <      {
195 <        sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
196 <                   from, to);
197 <        break;
198 <      }
106 >      conf = ptr->data;
107  
108 <      /* Blah, stats L needs the parameters, none of the others do.. */
109 <      if (statchar == 'L' || statchar == 'l')
110 <      {
111 <        sendto_realops_flags(UMODE_SPY, L_ALL,
112 <                             "STATS %c requested by %s (%s@%s) [%s] on %s",
113 <                             statchar, source_p->name, source_p->username,
114 <                             source_p->host, source_p->servptr->name,
115 <                             parc > 2 ? parv[2] : "<no recipient>");
116 <        tab->handler(source_p, parc, parv);
117 <      }
108 >      p = buf;
109 >
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 >    shared = flag_table;
124 >    DLINK_FOREACH(ptr, cluster_items.head)
125 >    {
126 >      conf = ptr->data;
127 >
128 >      p = buf;
129 >
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 >      conf = ptr->data;
148 >
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 <      {
157 <        sendto_realops_flags(UMODE_SPY, L_ALL,
158 <                             "STATS %c requested by %s (%s@%s) [%s]",
159 <                             statchar, source_p->name, source_p->username,
160 <                             source_p->host, source_p->servptr->name);
161 <        tab->handler(source_p);
217 <      }
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
232 < *
233 < * This will search the tables for the appropriate stats letter/command,
234 < * if found execute it.  
235 < */
236 < static void
237 < m_stats(struct Client *client_p, struct Client *source_p,
238 <        int parc, char *parv[])
239 < {
240 <  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? */
243 <  if (!ConfigFileEntry.disable_remote)
244 <    if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
245 <                    parc, parv) != HUNTED_ISME)
246 <      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
254 <  {
255 <    from = me.name;
256 <    to = source_p->name;
257 <  }
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 */
260 <  if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
261 <  {
262 <    sendto_one(source_p,form_str(RPL_LOAD2HI),
263 <               from, to);
264 <    return;
265 <  }
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 <  do_stats(source_p, parc, parv);
223 < }
222 >  case CONF_HUB:
223 >    DLINK_FOREACH(ptr, server_items.head)
224 >    {
225 >      conf = ptr->data;
226  
227 < /*
228 < * mo_stats()
229 < *      parv[0] = sender prefix
230 < *      parv[1] = stat letter/command
276 < *      parv[2] = (if present) server/mask in stats L, or target
277 < *
278 < * This will search the tables for the appropriate stats letter,
279 < * if found execute it.  
280 < */
281 < static void
282 < mo_stats(struct Client *client_p, struct Client *source_p,
283 <         int parc, char *parv[])
284 < {
285 <  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
286 <                  parc, parv) != HUNTED_ISME)
287 <     return;
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 <  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
233 <  {
234 <    from = me.id;
292 <    to = source_p->id;
293 <  }
294 <  else
295 <  {
296 <    from = me.name;
297 <    to = source_p->name;
298 <  }
232 >    DLINK_FOREACH(ptr, server_items.head)
233 >    {
234 >      conf = ptr->data;
235  
236 <  do_stats(source_p, parc, parv);
237 < }
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 < /*
304 < * ms_stats - STATS message handler
305 < *      parv[0] = sender prefix
306 < *      parv[1] = statistics selector (defaults to Message frequency)
307 < *      parv[2] = server name (current server defaulted, if omitted)
308 < */
309 < static void
310 < ms_stats(struct Client *client_p, struct Client *source_p,
311 <         int parc, char *parv[])
312 < {
313 <  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
314 <                  parc, parv) != HUNTED_ISME)
315 <    return;
241 >    break;
242  
243 <  if (IsClient(source_p))
244 <    mo_stats(client_p, source_p, parc, parv);
243 >  default:
244 >    break;
245 >  }
246   }
247  
248   /*
# Line 326 | Line 253 | ms_stats(struct Client *client_p, struct
253   * -avalon
254   */
255   static void
256 < send_usage(struct Client *source_p)
256 > stats_usage(struct Client *source_p, int parc, char *parv[])
257   {
258    struct rusage rus;
259    time_t secs;
# Line 353 | Line 280 | send_usage(struct Client *source_p)
280    if (secs == 0)
281      secs = 1;
282  
283 <  rup = (CurrentTime - me.since) * hzz;
283 >  rup = (CurrentTime - me.localClient->since) * hzz;
284  
285    if (rup == 0)
286      rup = 1;
# Line 382 | Line 309 | send_usage(struct Client *source_p)
309   }
310  
311   static void
312 < count_memory(struct Client *source_p)
312 > stats_memory(struct Client *source_p, int parc, char *parv[])
313   {
314    const dlink_node *gptr = NULL;
315    const dlink_node *dlink = NULL;
# Line 409 | Line 336 | count_memory(struct Client *source_p)
336    unsigned int safelist_count = 0;
337    uint64_t safelist_memory = 0;
338  
412 –  uint64_t away_memory = 0;       /* memory used by aways           */
339    uint64_t wwm = 0;               /* whowas array memory used       */
340    uint64_t conf_memory = 0;       /* memory used by conf lines      */
341    uint64_t mem_ips_stored;        /* memory used by ip address hash */
# Line 448 | Line 374 | count_memory(struct Client *source_p)
374      {
375        ++users_counted;
376  
377 <      if (target_p->away != NULL)
452 <      {
377 >      if (target_p->away[0])
378          ++aways_counted;
454 –        away_memory += strlen(target_p->away) + 1;
455 –      }
379      }
380    }
381  
# Line 467 | Line 390 | count_memory(struct Client *source_p)
390      channel_members += dlink_list_length(&chptr->members);
391      channel_invites += dlink_list_length(&chptr->invites);
392  
393 <    if (chptr->topic != NULL)
393 >    if (chptr->topic[0])
394        ++topic_count;
395  
396      channel_bans += dlink_list_length(&chptr->banlist);
# Line 535 | Line 458 | count_memory(struct Client *source_p)
458    }
459   #endif
460    /* count up all classes */
461 <  class_count = dlink_list_length(&class_items);
461 >  class_count = dlink_list_length(class_get_list());
462  
463    count_whowas_memory(&wwu, &wwm);
464    watch_count_memory(&watch_list_headers, &watch_list_memory);
465  
466 <  sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%u) entries %d(%u)",
466 >  sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%llu) entries %d(%u)",
467               me.name, RPL_STATSDEBUG, source_p->name, watch_list_headers,
468               watch_list_memory, watch_list_entries,
469               watch_list_entries * sizeof(dlink_node) * 2);
# Line 549 | Line 472 | count_memory(struct Client *source_p)
472               me.name, RPL_STATSDEBUG, source_p->name, users_counted,
473               (users_counted * sizeof(struct Client)));
474  
475 <  sendto_one(source_p, ":%s %d %s z :User aways %u(%llu)",
475 >  sendto_one(source_p, ":%s %d %s z :User aways %u",
476               me.name, RPL_STATSDEBUG, source_p->name,
477 <             aways_counted, away_memory);
477 >             aways_counted);
478  
479    sendto_one(source_p, ":%s %d %s z :Attached confs %u(%llu)",
480               me.name, RPL_STATSDEBUG, source_p->name,
# Line 561 | Line 484 | count_memory(struct Client *source_p)
484    sendto_one(source_p, ":%s %d %s z :Resv channels %u(%lu) nicks %u(%lu)",
485               me.name, RPL_STATSDEBUG, source_p->name,
486               dlink_list_length(&resv_channel_list),
487 <             dlink_list_length(&resv_channel_list) * sizeof(struct ResvChannel),
487 >             dlink_list_length(&resv_channel_list) * sizeof(struct MaskItem),
488               dlink_list_length(&nresv_items),
489 <             dlink_list_length(&nresv_items) * sizeof(struct MatchItem));
489 >             dlink_list_length(&nresv_items) * sizeof(struct MaskItem));
490  
491    sendto_one(source_p, ":%s %d %s z :Classes %u(%llu)",
492               me.name, RPL_STATSDEBUG, source_p->name,
493               class_count, (unsigned long long)(class_count * sizeof(struct ClassItem)));
494  
495 <  sendto_one(source_p, ":%s %d %s z :Channels %uu(%llu) Topics %u(%u)",
495 >  sendto_one(source_p, ":%s %d %s z :Channels %u(%llu) Topics %u(%u)",
496               me.name, RPL_STATSDEBUG, source_p->name,
497               dlink_list_length(&global_channel_list),
498               channel_memory, topic_count, topic_count *
# Line 634 | Line 557 | count_memory(struct Client *source_p)
557               me.name, RPL_STATSDEBUG, source_p->name, remote_client_count,
558               remote_client_memory_used);
559  
637 –  block_heap_report_stats(source_p);
638 –
560    sendto_one(source_p,
561               ":%s %d %s z :TOTAL: %llu",
562               me.name, RPL_STATSDEBUG, source_p->name,
# Line 649 | Line 570 | stats_dns_servers(struct Client *source_
570   }
571  
572   static void
573 < stats_connect(struct Client *source_p)
573 > stats_connect(struct Client *source_p, int parc, char *parv[])
574   {
575 <  report_confitem_types(source_p, SERVER_TYPE, 0);
575 >  report_confitem_types(source_p, CONF_SERVER);
576   }
577  
578   /* stats_deny()
# Line 661 | Line 582 | stats_connect(struct Client *source_p)
582   * side effects - client is given dline list.
583   */
584   static void
585 < stats_deny(struct Client *source_p)
585 > stats_deny(struct Client *source_p, int parc, char *parv[])
586   {
587 <  struct AddressRec *arec;
588 <  struct ConfItem *conf;
589 <  struct AccessItem *aconf;
669 <  int i;
587 >  struct MaskItem *conf;
588 >  dlink_node *ptr = NULL;
589 >  unsigned int i = 0;
590  
591 <  for (i = 0; i < ATABLE_SIZE; i++)
591 >
592 >  for (i = 0; i < ATABLE_SIZE; ++i)
593    {
594 <    for (arec = atable[i]; arec; arec=arec->next)
594 >    DLINK_FOREACH(ptr, atable[i].head)
595      {
596 <      if (arec->type == CONF_DLINE)
676 <      {
677 <        aconf = arec->aconf;
596 >      struct AddressRec *arec = ptr->data;
597  
598 <        /* dont report a tdline as a dline */
599 <        if (aconf->flags & CONF_FLAGS_TEMPORARY)
681 <          continue;
598 >      if (arec->type != CONF_DLINE)
599 >        continue;
600  
601 <        conf = unmap_conf_item(aconf);
601 >      conf = arec->conf;
602  
603 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
604 <                   from, to, 'D', aconf->host, aconf->reason,
605 <                   aconf->oper_reason);
606 <      }
603 >      /* dont report a tdline as a dline */
604 >      if (conf->until)
605 >        continue;
606 >
607 >      sendto_one(source_p, form_str(RPL_STATSDLINE),
608 >                 from, to, 'D', conf->host, conf->reason);
609      }
610    }
611   }
# Line 697 | Line 617 | stats_deny(struct Client *source_p)
617   * side effects - client is given dline list.
618   */
619   static void
620 < stats_tdeny(struct Client *source_p)
620 > stats_tdeny(struct Client *source_p, int parc, char *parv[])
621   {
622 <  struct AddressRec *arec;
623 <  struct ConfItem *conf;
624 <  struct AccessItem *aconf;
705 <  int i;
622 >  struct MaskItem *conf = NULL;
623 >  dlink_node *ptr = NULL;
624 >  unsigned int i = 0;
625  
626 <  for (i = 0; i < ATABLE_SIZE; i++)
626 >
627 >  for (i = 0; i < ATABLE_SIZE; ++i)
628    {
629 <    for (arec = atable[i]; arec; arec=arec->next)
629 >    DLINK_FOREACH(ptr, atable[i].head)
630      {
631 <      if (arec->type == CONF_DLINE)
712 <      {
713 <        aconf = arec->aconf;
631 >      struct AddressRec *arec = ptr->data;
632  
633 <        /* dont report a permanent dline as a tdline */
634 <        if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
717 <          continue;
633 >      if (arec->type != CONF_DLINE)
634 >        continue;
635  
636 <        conf = unmap_conf_item(aconf);
636 >      conf = arec->conf;
637  
638 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
639 <                   from, to, 'd', aconf->host, aconf->reason,
640 <                   aconf->oper_reason);
641 <      }
638 >      /* dont report a permanent dline as a tdline */
639 >      if (!conf->until)
640 >        continue;
641 >
642 >      sendto_one(source_p, form_str(RPL_STATSDLINE),
643 >                 from, to, 'd', conf->host, conf->reason);
644      }
645    }
646   }
# Line 733 | Line 652 | stats_tdeny(struct Client *source_p)
652   * side effects - client is given list of exempt blocks
653   */
654   static void
655 < stats_exempt(struct Client *source_p)
655 > stats_exempt(struct Client *source_p, int parc, char *parv[])
656   {
657 <  struct AddressRec *arec;
658 <  struct ConfItem *conf;
659 <  struct AccessItem *aconf;
741 <  int i;
657 >  struct MaskItem *conf;
658 >  dlink_node *ptr = NULL;
659 >  unsigned int i = 0;
660  
661    if (ConfigFileEntry.stats_e_disabled)
662    {
# Line 747 | Line 665 | stats_exempt(struct Client *source_p)
665      return;
666    }
667  
668 <  for (i = 0; i < ATABLE_SIZE; i++)
668 >
669 >  for (i = 0; i < ATABLE_SIZE; ++i)
670    {
671 <    for (arec = atable[i]; arec; arec=arec->next)
671 >    DLINK_FOREACH(ptr, atable[i].head)
672      {
673 <      if (arec->type == CONF_EXEMPTDLINE)
755 <      {
756 <        aconf = arec->aconf;
673 >      struct AddressRec *arec = ptr->data;
674  
675 <        conf = unmap_conf_item(aconf);
675 >      if (arec->type != CONF_EXEMPT)
676 >        continue;
677  
678 <        sendto_one(source_p, form_str(RPL_STATSDLINE),
679 <                   from, to, 'e', aconf->host,
680 <                   aconf->reason, aconf->oper_reason);
681 <      }
678 >      conf = arec->conf;
679 >
680 >      sendto_one(source_p, form_str(RPL_STATSDLINE), from, to, 'e',
681 >                 conf->host, "");
682      }
683    }
684   }
685  
686   static void
687 < stats_events(struct Client *source_p)
687 > stats_events(struct Client *source_p, int parc, char *parv[])
688   {
689    show_events(source_p);
690   }
# Line 778 | Line 696 | stats_events(struct Client *source_p)
696   * side effects - client is shown list of pending glines
697   */
698   static void
699 < stats_pending_glines(struct Client *source_p)
699 > stats_pending_glines(struct Client *source_p, int parc, char *parv[])
700   {
701    const dlink_node *dn_ptr = NULL;
702    const struct gline_pending *glp_ptr = NULL;
# Line 867 | Line 785 | stats_pending_glines(struct Client *sour
785   * side effects - client is shown list of glines
786   */
787   static void
788 < stats_glines(struct Client *source_p)
788 > stats_glines(struct Client *source_p, int parc, char *parv[])
789   {
790 <  struct AddressRec *arec = NULL;
791 <  int i = 0;
790 >  dlink_node *ptr = NULL;
791 >  unsigned int i = 0;
792  
793    if (!ConfigFileEntry.glines)
794    {
# Line 879 | Line 797 | stats_glines(struct Client *source_p)
797      return;
798    }
799  
800 <  for (; i < ATABLE_SIZE; ++i)
800 >  for (i = 0; i < ATABLE_SIZE; ++i)
801    {
802 <    for (arec = atable[i]; arec; arec = arec->next)
802 >    DLINK_FOREACH(ptr, atable[i].head)
803      {
804 +      const struct AddressRec *arec = ptr->data;
805 +
806        if (arec->type == CONF_GLINE)
807        {
808 <        const struct AccessItem *aconf = arec->aconf;
808 >        const struct MaskItem *conf = arec->conf;
809  
810          sendto_one(source_p, form_str(RPL_STATSKLINE),
811 <                   from, to, "G",
812 <                   aconf->host ? aconf->host : "*",
813 <                   aconf->user ? aconf->user : "*",
814 <                   aconf->reason ? aconf->reason : "No reason", "" );
811 >                   from, to, 'G',
812 >                   conf->host ? conf->host : "*",
813 >                   conf->user ? conf->user : "*",
814 >                   conf->reason ? conf->reason : CONF_NOREASON);
815        }
816      }
817    }
818   }
819  
820 < /* stats_gdeny()
820 > static void
821 > stats_hubleaf(struct Client *source_p, int parc, char *parv[])
822 > {
823 >  report_confitem_types(source_p, CONF_HUB);
824 > }
825 >
826 > /*
827 > * show_iline_prefix()
828   *
829 < * input        - client pointer
830 < * outputs      - none
831 < * side effects - client is shown gline ACL
829 > * inputs       - pointer to struct Client requesting output
830 > *              - pointer to struct MaskItem
831 > *              - name to which iline prefix will be prefixed to
832 > * output       - pointer to static string with prefixes listed in ascii form
833 > * side effects - NONE
834   */
835 < static void
836 < stats_gdeny(struct Client *source_p)
835 > static const char *
836 > show_iline_prefix(const struct Client *sptr, const struct MaskItem *conf)
837   {
838 <  if (!ConfigFileEntry.glines)
839 <  {
840 <    sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
841 <               from, to);
842 <    return;
843 <  }
838 >  static char prefix_of_host[USERLEN + 15];
839 >  char *prefix_ptr = prefix_of_host;
840 >
841 >  if (IsConfWebIRC(conf))
842 >    *prefix_ptr++ = '<';
843 >  if (IsNoTilde(conf))
844 >    *prefix_ptr++ = '-';
845 >  if (IsLimitIp(conf))
846 >    *prefix_ptr++ = '!';
847 >  if (IsNeedIdentd(conf))
848 >    *prefix_ptr++ = '+';
849 >  if (!IsNeedPassword(conf))
850 >    *prefix_ptr++ = '&';
851 >  if (IsConfExemptResv(conf))
852 >    *prefix_ptr++ = '$';
853 >  if (IsNoMatchIp(conf))
854 >    *prefix_ptr++ = '%';
855 >  if (IsConfDoSpoofIp(conf))
856 >    *prefix_ptr++ = '=';
857 >  if (MyOper(sptr) && IsConfExemptKline(conf))
858 >    *prefix_ptr++ = '^';
859 >  if (MyOper(sptr) && IsConfExemptGline(conf))
860 >    *prefix_ptr++ = '_';
861 >  if (MyOper(sptr) && IsConfExemptLimits(conf))
862 >    *prefix_ptr++ = '>';
863 >  if (IsConfCanFlood(conf))
864 >    *prefix_ptr++ = '|';
865 >
866 >  strlcpy(prefix_ptr, conf->user, USERLEN+1);
867  
868 <  report_confitem_types(source_p, GDENY_TYPE, 0);
868 >  return prefix_of_host;
869   }
870  
871   static void
872 < stats_hubleaf(struct Client *source_p)
872 > report_auth(struct Client *client_p, int parc, char *parv[])
873   {
874 <  report_confitem_types(source_p, HUB_TYPE, 0);
875 <  report_confitem_types(source_p, LEAF_TYPE, 0);
874 >  struct MaskItem *conf = NULL;
875 >  dlink_node *ptr = NULL;
876 >  unsigned int i;
877 >
878 >
879 >  for (i = 0; i < ATABLE_SIZE; ++i)
880 >  {
881 >    DLINK_FOREACH(ptr, atable[i].head)
882 >    {
883 >      struct AddressRec *arec = ptr->data;
884 >
885 >      if (arec->type != CONF_CLIENT)
886 >        continue;
887 >
888 >      conf = arec->conf;
889 >
890 >      if (!MyOper(client_p) && IsConfDoSpoofIp(conf))
891 >        continue;
892 >
893 >      /* We are doing a partial list, based on what matches the u@h of the
894 >       * sender, so prepare the strings for comparing --fl_
895 >       */
896 >      if (ConfigFileEntry.hide_spoof_ips)
897 >        sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
898 >                   client_p->name, 'I',
899 >                   conf->name == NULL ? "*" : conf->name,
900 >                   show_iline_prefix(client_p, conf),
901 >                   IsConfDoSpoofIp(conf) ? "255.255.255.255" :
902 >                   conf->host, conf->port,
903 >                   conf->class ? conf->class->name : "<default>");
904 >
905 >      else
906 >        sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
907 >                   client_p->name, 'I',
908 >                   conf->name == NULL ? "*" : conf->name,
909 >                   show_iline_prefix(client_p, conf),
910 >                   conf->host, conf->port,
911 >                   conf->class ? conf->class->name : "<default>");
912 >    }
913 >  }
914   }
915  
916   static void
917 < stats_auth(struct Client *source_p)
917 > stats_auth(struct Client *source_p, int parc, char *parv[])
918   {
919    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
920 <  if ((ConfigFileEntry.stats_i_oper_only == 2) && !IsOper(source_p))
920 >  if ((ConfigFileEntry.stats_i_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
921      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
922                 from, to);
923  
924    /* If unopered, Only return matching auth blocks */
925 <  else if ((ConfigFileEntry.stats_i_oper_only == 1) && !IsOper(source_p))
925 >  else if ((ConfigFileEntry.stats_i_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
926    {
927 <    struct ConfItem *conf;
938 <    struct AccessItem *aconf;
927 >    struct MaskItem *conf;
928  
929      if (MyConnect(source_p))
930 <      aconf = find_conf_by_address(source_p->host,
930 >      conf = find_conf_by_address(source_p->host,
931                                     &source_p->localClient->ip,
932                                     CONF_CLIENT,
933                                     source_p->localClient->aftype,
934                                     source_p->username,
935 <                                   source_p->localClient->passwd);
935 >                                   source_p->localClient->passwd, 1);
936      else
937 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
938 <                                   0, source_p->username, NULL);
937 >      conf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
938 >                                   0, source_p->username, NULL, 1);
939  
940 <    if (aconf == NULL)
940 >    if (conf == NULL)
941        return;
942  
954 –    conf = unmap_conf_item(aconf);
955 –
943      sendto_one(source_p, form_str(RPL_STATSILINE), from,
944                 to, 'I',
945 <               "*", show_iline_prefix(source_p, aconf, aconf->user),
946 <               aconf->host, aconf->port,
947 <               aconf->class_ptr ? aconf->class_ptr->name : "<default>");
945 >               "*", show_iline_prefix(source_p, conf),
946 >               conf->host, conf->port,
947 >               conf->class ? conf->class->name : "<default>");
948    }
949    /* They are opered, or allowed to see all auth blocks */
950    else
951 <    report_auth(source_p);
951 >    report_auth(source_p, 0, NULL);
952   }
953  
954 + /* report_Klines()
955 + * Inputs: Client to report to,
956 + *         type(==0 for perm, !=0 for temporary)
957 + *         mask
958 + * Output: None
959 + * Side effects: Reports configured K(or k)-lines to client_p.
960 + */
961   static void
962 < stats_tklines(struct Client *source_p)
962 > report_Klines(struct Client *client_p, int tkline)
963 > {
964 >  struct MaskItem *conf = NULL;
965 >  unsigned int i = 0;
966 >  char c = '\0';
967 >  dlink_node *ptr = NULL;
968 >
969 >  if (tkline)
970 >    c = 'k';
971 >  else
972 >    c = 'K';
973 >
974 >  for (i = 0; i < ATABLE_SIZE; ++i)
975 >  {
976 >    DLINK_FOREACH(ptr, atable[i].head)
977 >    {
978 >      struct AddressRec *arec = ptr->data;
979 >
980 >      if (arec->type != CONF_KLINE)
981 >        continue;
982 >
983 >      conf = arec->conf;
984 >
985 >      if ((!tkline && conf->until) ||
986 >          (tkline && !conf->until))
987 >        continue;
988 >
989 >      if (HasUMode(client_p, UMODE_OPER))
990 >        sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
991 >                   client_p->name, c, conf->host, conf->user,
992 >                   conf->reason);
993 >      else
994 >        sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
995 >                   client_p->name, c, conf->host, conf->user,
996 >                   conf->reason);
997 >    }
998 >  }
999 > }
1000 >
1001 > static void
1002 > stats_tklines(struct Client *source_p, int parc, char *parv[])
1003   {
970 –  struct ConfItem *conf;
1004    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1005 <  if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
1005 >  if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1006      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1007                 from, to);
1008  
1009    /* If unopered, Only return matching klines */
1010 <  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
1010 >  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1011    {
1012 <    struct AccessItem *aconf;
1012 >    struct MaskItem *conf = NULL;
1013  
1014      if (MyConnect(source_p))
1015 <      aconf = find_conf_by_address(source_p->host,
1016 <                                   &source_p->localClient->ip,
1017 <                                   CONF_KILL,
1015 >      conf = find_conf_by_address(source_p->host,
1016 >                                  &source_p->localClient->ip,
1017 >                                   CONF_KLINE,
1018                                     source_p->localClient->aftype,
1019 <                                   source_p->username, NULL);
1019 >                                   source_p->username, NULL, 1);
1020      else
1021 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
1022 <                                   0, source_p->username, NULL);
1021 >      conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1022 >                                   0, source_p->username, NULL, 1);
1023  
1024 <    if (aconf == NULL)
1024 >    if (!conf)
1025        return;
1026  
1027      /* dont report a permanent kline as a tkline */
1028 <    if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
1028 >    if (!conf->until)
1029        return;
1030  
998 –    conf = unmap_conf_item(aconf);
999 –
1031      sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1032 <               to, "k", aconf->host, aconf->user, aconf->reason, "");
1032 >               to, 'k', conf->host, conf->user, conf->reason);
1033    }
1034    /* Theyre opered, or allowed to see all klines */
1035    else {
1036      report_Klines(source_p, 1);
1006 –    report_confitem_types(source_p, RKLINE_TYPE, 1);
1037    }
1038   }
1039  
1040   static void
1041 < stats_klines(struct Client *source_p)
1041 > stats_klines(struct Client *source_p, int parc, char *parv[])
1042   {
1043    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1044 <  if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
1044 >  if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1045      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1046                 from, to);
1047  
1048    /* If unopered, Only return matching klines */
1049 <  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
1049 >  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1050    {
1051 <    struct AccessItem *aconf;
1051 >    struct MaskItem *conf = NULL;
1052  
1053      /* search for a kline */
1054      if (MyConnect(source_p))
1055 <      aconf = find_conf_by_address(source_p->host,
1055 >      conf = find_conf_by_address(source_p->host,
1056                                     &source_p->localClient->ip,
1057 <                                   CONF_KILL,
1057 >                                   CONF_KLINE,
1058                                     source_p->localClient->aftype,
1059 <                                   source_p->username, NULL);
1059 >                                   source_p->username, NULL, 0);
1060      else
1061 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
1062 <                                   0, source_p->username, NULL);
1061 >      conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1062 >                                   0, source_p->username, NULL, 0);
1063  
1064 <    if (aconf == NULL)
1064 >    if (!conf)
1065        return;
1066  
1067      /* dont report a tkline as a kline */
1068 <    if (aconf->flags & CONF_FLAGS_TEMPORARY)
1068 >    if (conf->until)
1069        return;
1070        
1071      sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1072 <               to, "K", aconf->host, aconf->user, aconf->reason,
1043 <               aconf->oper_reason);
1072 >               to, 'K', conf->host, conf->user, conf->reason);
1073    }
1074    /* Theyre opered, or allowed to see all klines */
1075 <  else {
1075 >  else
1076      report_Klines(source_p, 0);
1048 –    report_confitem_types(source_p, RKLINE_TYPE, 0);
1049 –  }
1077   }
1078  
1079   static void
1080 < stats_messages(struct Client *source_p)
1080 > stats_messages(struct Client *source_p, int parc, char *parv[])
1081   {
1082    report_messages(source_p);
1083   }
1084  
1085   static void
1086 < stats_oper(struct Client *source_p)
1086 > stats_oper(struct Client *source_p, int parc, char *parv[])
1087   {
1088 <  if (!IsOper(source_p) && ConfigFileEntry.stats_o_oper_only)
1088 >  if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_o_oper_only)
1089      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1090                 from, to);
1091    else
1092 <    report_confitem_types(source_p, OPER_TYPE, 0);
1092 >    report_confitem_types(source_p, CONF_OPER);
1093   }
1094  
1095   /* stats_operedup()
# Line 1072 | Line 1099 | stats_oper(struct Client *source_p)
1099   * side effects - client is shown a list of active opers
1100   */
1101   static void
1102 < stats_operedup(struct Client *source_p)
1102 > stats_operedup(struct Client *source_p, int parc, char *parv[])
1103   {
1104    dlink_node *ptr;
1105  
# Line 1080 | Line 1107 | stats_operedup(struct Client *source_p)
1107    {
1108      const struct Client *target_p = ptr->data;
1109  
1110 <    if (IsOperHidden(target_p) && !IsOper(source_p))
1110 >    if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
1111        continue;
1112  
1113 <    if (MyClient(source_p) && IsOper(source_p))
1114 <      sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %d",
1113 >    if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
1114 >      sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %u",
1115                   from, RPL_STATSDEBUG, to,
1116 <                 IsAdmin(target_p) ?
1090 <                 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
1116 >                 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1117                   oper_privs_as_string(target_p->localClient->operflags),
1118                   target_p->name, target_p->username, target_p->host,
1119 <                 (int)(CurrentTime - target_p->localClient->last_privmsg));
1119 >                 idle_time_get(source_p, target_p));
1120      else
1121 <      sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
1121 >      sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %u",
1122                   from, RPL_STATSDEBUG, to,
1123 <                 IsAdmin(target_p) ?
1098 <                 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
1123 >                 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1124                   target_p->name, target_p->username, target_p->host,
1125 <                 (int)(CurrentTime - target_p->localClient->last_privmsg));
1125 >                 idle_time_get(source_p, target_p));
1126    }
1127  
1128 <  sendto_one(source_p, ":%s %d %s p :%lu OPER(s)",
1128 >  sendto_one(source_p, ":%s %d %s p :%u OPER(s)",
1129               from, RPL_STATSDEBUG, to, dlink_list_length(&oper_list));
1130   }
1131  
1132   static void
1133 < stats_ports(struct Client *source_p)
1133 > stats_ports(struct Client *source_p, int parc, char *parv[])
1134   {
1135 <  if (!IsOper(source_p) && ConfigFileEntry.stats_P_oper_only)
1135 >  if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_P_oper_only)
1136      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1137                 from, to);
1138    else
# Line 1115 | Line 1140 | stats_ports(struct Client *source_p)
1140   }
1141  
1142   static void
1143 < stats_resv(struct Client *source_p)
1143 > stats_resv(struct Client *source_p, int parc, char *parv[])
1144   {
1145    report_resv(source_p);
1146   }
1147  
1148   static void
1149 < stats_usage(struct Client *source_p)
1125 < {
1126 <  send_usage(source_p);
1127 < }
1128 <
1129 < static void
1130 < stats_service(struct Client *source_p)
1149 > stats_service(struct Client *source_p, int parc, char *parv[])
1150   {
1151 <  report_confitem_types(source_p, SERVICE_TYPE, 0);
1151 >  report_confitem_types(source_p, CONF_SERVICE);
1152   }
1153  
1154   static void
1155 < stats_tstats(struct Client *source_p)
1155 > stats_tstats(struct Client *source_p, int parc, char *parv[])
1156   {
1157    const struct Client *target_p = NULL;
1158    const dlink_node *ptr = NULL;
1140 –  struct ServerStatistics *sp;
1159    struct ServerStatistics tmp;
1160 +  struct ServerStatistics *sp = &tmp;
1161  
1143 –  sp = &tmp;
1162    memcpy(sp, &ServerStats, sizeof(struct ServerStatistics));
1163  
1164    /*
# Line 1156 | Line 1174 | stats_tstats(struct Client *source_p)
1174  
1175      sp->is_sbs += target_p->localClient->send.bytes;
1176      sp->is_sbr += target_p->localClient->recv.bytes;
1177 <    sp->is_sti += CurrentTime - target_p->firsttime;
1177 >    sp->is_sti += CurrentTime - target_p->localClient->firsttime;
1178    }
1179  
1180    sp->is_cl += dlink_list_length(&local_client_list);
# Line 1167 | Line 1185 | stats_tstats(struct Client *source_p)
1185  
1186      sp->is_cbs += target_p->localClient->send.bytes;
1187      sp->is_cbr += target_p->localClient->recv.bytes;
1188 <    sp->is_cti += CurrentTime - target_p->firsttime;
1188 >    sp->is_cti += CurrentTime - target_p->localClient->firsttime;
1189    }
1190  
1191    sp->is_ni += dlink_list_length(&unknown_list);
# Line 1204 | Line 1222 | stats_tstats(struct Client *source_p)
1222   }
1223  
1224   static void
1225 < stats_uptime(struct Client *source_p)
1225 > stats_uptime(struct Client *source_p, int parc, char *parv[])
1226   {
1227 <  time_t now = CurrentTime - me.since;
1227 >  time_t now = CurrentTime - me.localClient->since;
1228  
1229    sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
1230               now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
1231  
1232 <  if (!ConfigFileEntry.disable_remote || IsOper(source_p))
1232 >  if (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER))
1233       sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
1234                  Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount);
1235   }
1236  
1237   static void
1238 < stats_shared(struct Client *source_p)
1238 > stats_shared(struct Client *source_p, int parc, char *parv[])
1239   {
1240 <  report_confitem_types(source_p, ULINE_TYPE, 0);
1240 >  report_confitem_types(source_p, CONF_ULINE);
1241   }
1242  
1243   /* stats_servers()
# Line 1229 | Line 1247 | stats_shared(struct Client *source_p)
1247   * side effects - client is shown lists of who connected servers
1248   */
1249   static void
1250 < stats_servers(struct Client *source_p)
1250 > stats_servers(struct Client *source_p, int parc, char *parv[])
1251   {
1252    dlink_node *ptr = NULL;
1253  
# Line 1240 | Line 1258 | stats_servers(struct Client *source_p)
1258      sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
1259                 from, RPL_STATSDEBUG, to, target_p->name,
1260                 (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1261 <               "*", "*", (int)(CurrentTime - target_p->lasttime));
1261 >               "*", "*", (int)(CurrentTime - target_p->localClient->lasttime));
1262    }
1263  
1264    sendto_one(source_p, ":%s %d %s v :%u Server(s)",
# Line 1248 | Line 1266 | stats_servers(struct Client *source_p)
1266   }
1267  
1268   static void
1269 < stats_gecos(struct Client *source_p)
1269 > stats_gecos(struct Client *source_p, int parc, char *parv[])
1270   {
1271 <  report_confitem_types(source_p, XLINE_TYPE, 0);
1254 <  report_confitem_types(source_p, RXLINE_TYPE, 0);
1271 >  report_confitem_types(source_p, CONF_XLINE);
1272   }
1273  
1274   static void
1275 < stats_class(struct Client *source_p)
1275 > stats_class(struct Client *source_p, int parc, char *parv[])
1276   {
1277 <  report_confitem_types(source_p, CLASS_TYPE, 0);
1277 >  report_confitem_types(source_p, CONF_CLASS);
1278   }
1279  
1280   static void
1281 < stats_memory(struct Client *source_p)
1265 < {
1266 <  count_memory(source_p);
1267 < }
1268 <
1269 < static void
1270 < stats_ziplinks(struct Client *source_p)
1271 < {
1272 <  dlink_node *ptr = NULL;
1273 <  unsigned int sent_data = 0;
1274 <
1275 <  DLINK_FOREACH(ptr, serv_list.head)
1276 <  {
1277 <    const struct Client *target_p = ptr->data;
1278 <
1279 <    if (IsCapable(target_p, CAP_ZIP))
1280 <    {
1281 <      /* we use memcpy(3) and a local copy of the structure to
1282 <       * work around a register use bug on GCC on the SPARC.
1283 <       * -jmallett, 04/27/2002
1284 <       */
1285 <      struct ZipStats zipstats;
1286 <
1287 <      memcpy(&zipstats, &target_p->localClient->zipstats, sizeof(zipstats));
1288 <
1289 <      sendto_one(source_p, ":%s %d %s Z :ZipLinks stats for %s send[%.2f%% "
1290 <                 "compression (%llu bytes data/%llu bytes wire)] recv[%.2f%% "
1291 <                 "compression (%llu bytes data/%llu bytes wire)]",
1292 <                 from, RPL_STATSDEBUG, to, target_p->name,
1293 <                 zipstats.out_ratio, zipstats.out, zipstats.out_wire,
1294 <                 zipstats.in_ratio,  zipstats.in,  zipstats.in_wire);
1295 <      ++sent_data;
1296 <    }
1297 <  }
1298 <
1299 <  sendto_one(source_p, ":%s %d %s Z :%u ziplink(s)",
1300 <             from, RPL_STATSDEBUG, to, sent_data);
1301 < }
1302 <
1303 < static void
1304 < stats_servlinks(struct Client *source_p)
1281 > stats_servlinks(struct Client *source_p, int parc, char *parv[])
1282   {
1283    uint64_t sendB = 0, recvB = 0;
1284    time_t uptime = 0;
1285    dlink_node *ptr = NULL;
1286  
1287 <  if (ConfigServerHide.flatten_links && !IsOper(source_p))
1287 >  if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
1288    {
1289      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1290                 from, to);
# Line 1318 | Line 1295 | stats_servlinks(struct Client *source_p)
1295    {
1296      struct Client *target_p = ptr->data;
1297  
1298 +    if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
1299 +      if (!HasUMode(source_p, UMODE_OPER))
1300 +        continue;
1301 +
1302      sendB += target_p->localClient->send.bytes;
1303      recvB += target_p->localClient->recv.bytes;
1304  
1305      /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
1306      sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1307                 from, to,
1308 <               get_client_name(target_p, IsAdmin(source_p) ? SHOW_IP : MASK_IP),
1308 >               get_client_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
1309                 dbuf_length(&target_p->localClient->buf_sendq),
1310                 target_p->localClient->send.messages,
1311                 target_p->localClient->send.bytes >> 10,
1312                 target_p->localClient->recv.messages,
1313                 target_p->localClient->recv.bytes >> 10,
1314 <               (unsigned)(CurrentTime - target_p->firsttime),
1315 <               (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since): 0,
1316 <               IsOper(source_p) ? show_capabilities(target_p) : "TS");
1314 >               (unsigned)(CurrentTime - target_p->localClient->firsttime),
1315 >               (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since): 0,
1316 >               HasUMode(source_p, UMODE_OPER) ? show_capabilities(target_p) : "TS");
1317    }
1318  
1319    sendB >>= 10;
# Line 1347 | Line 1328 | stats_servlinks(struct Client *source_p)
1328               from, RPL_STATSDEBUG, to,
1329               _GMKv(recvB), _GMKs(recvB));
1330  
1331 <  uptime = (CurrentTime - me.since);
1331 >  uptime = (CurrentTime - me.localClient->since);
1332  
1333    sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
1334               from, RPL_STATSDEBUG, to,
# Line 1363 | Line 1344 | stats_servlinks(struct Client *source_p)
1344               (float)uptime));
1345   }
1346  
1347 < static void
1348 < stats_ltrace(struct Client *source_p, int parc, char *parv[])
1347 > /* parse_stats_args()
1348 > *
1349 > * inputs       - arg count
1350 > *              - args
1351 > *              - doall flag
1352 > *              - wild card or not
1353 > * output       - pointer to name to use
1354 > * side effects -
1355 > * common parse routine for m_stats args
1356 > *
1357 > */
1358 > static char *
1359 > parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1360   {
1361 <  int doall = 0;
1370 <  int wilds = 0;
1371 <  char *name = NULL;
1372 <  char statchar;
1361 >  char *name;
1362  
1363 <  if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1363 >  if (parc > 2)
1364    {
1365 <    statchar = parv[1][0];
1365 >    name = parv[2];
1366  
1367 <    stats_L(source_p, name, doall, wilds, statchar);
1367 >    if (!irccmp(name, from))
1368 >      *doall = 2;
1369 >    else if (!match(name, from))
1370 >      *doall = 1;
1371 >
1372 >    *wilds = has_wildcards(name);
1373 >
1374 >    return name;
1375    }
1380 –  else
1381 –    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1382 –               from, to, "STATS");
1383 – }
1376  
1377 < /*
1386 < * stats_L
1387 < *
1388 < * inputs       - pointer to client to report to
1389 < *              - doall flag
1390 < *              - wild card or not
1391 < * output       - NONE
1392 < * side effects -
1393 < */
1394 < static void
1395 < stats_L(struct Client *source_p,char *name,int doall,
1396 <        int wilds,char statchar)
1397 < {
1398 <  stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1399 <  stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1400 <  stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1377 >  return NULL;
1378   }
1379  
1380   static void
# Line 1417 | Line 1394 | stats_L_list(struct Client *source_p,cha
1394    {
1395      target_p = ptr->data;
1396  
1397 <    if (IsInvisible(target_p) && (doall || wilds) &&
1398 <        !(MyConnect(source_p) && IsOper(source_p)) &&
1399 <        !IsOper(target_p) && (target_p != source_p))
1397 >    if (HasUMode(target_p, UMODE_INVISIBLE) && (doall || wilds) &&
1398 >        !(MyConnect(source_p) && HasUMode(source_p, UMODE_OPER)) &&
1399 >        !HasUMode(target_p, UMODE_OPER) && (target_p != source_p))
1400        continue;
1401 <    if (!doall && wilds && !match(name, target_p->name))
1401 >    if (!doall && wilds && match(name, target_p->name))
1402        continue;
1403      if (!(doall || wilds) && irccmp(name, target_p->name))
1404        continue;
1405  
1406      /* This basically shows ips for our opers if its not a server/admin, or
1407       * its one of our admins.  */
1408 <    if(MyClient(source_p) && IsOper(source_p) &&
1409 <       (IsAdmin(source_p) ||
1410 <       (!IsServer(target_p) && !IsAdmin(target_p) &&
1408 >    if(MyClient(source_p) && HasUMode(source_p, UMODE_OPER) &&
1409 >       (HasUMode(source_p, UMODE_ADMIN) ||
1410 >       (!IsServer(target_p) && !HasUMode(target_p, UMODE_ADMIN) &&
1411         !IsHandshake(target_p) && !IsConnecting(target_p))))
1412      {
1413        sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1414 <                 from, to,
1414 >                 from, to,
1415                   (IsUpper(statchar)) ?
1416                   get_client_name(target_p, SHOW_IP) :
1417                   get_client_name(target_p, HIDE_IP),
# Line 1443 | Line 1420 | stats_L_list(struct Client *source_p,cha
1420                   target_p->localClient->send.bytes>>10,
1421                   target_p->localClient->recv.messages,
1422                   target_p->localClient->recv.bytes>>10,
1423 <                 (unsigned)(CurrentTime - target_p->firsttime),
1424 <                 (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1423 >                 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1424 >                 (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1425                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1426      }
1427      else
1428      {
1429        /* If its a hidden ip, an admin, or a server, mask the real IP */
1430 <      if(IsIPSpoof(target_p) || IsServer(target_p) || IsAdmin(target_p)
1430 >      if(IsIPSpoof(target_p) || IsServer(target_p) || HasUMode(target_p, UMODE_ADMIN)
1431           || IsHandshake(target_p) || IsConnecting(target_p))
1432          sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1433                     from, to,
1434 <                   get_client_name(target_p, MASK_IP),
1435 <                   dbuf_length(&target_p->localClient->buf_sendq),
1436 <                   target_p->localClient->send.messages,
1437 <                   target_p->localClient->send.bytes>>10,
1438 <                   target_p->localClient->recv.messages,
1439 <                   target_p->localClient->recv.bytes>>10,
1440 <                   (unsigned)(CurrentTime - target_p->firsttime),
1441 <                   (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1442 <                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1434 >                   get_client_name(target_p, MASK_IP),
1435 >                   dbuf_length(&target_p->localClient->buf_sendq),
1436 >                   target_p->localClient->send.messages,
1437 >                   target_p->localClient->send.bytes>>10,
1438 >                   target_p->localClient->recv.messages,
1439 >                   target_p->localClient->recv.bytes>>10,
1440 >                   (unsigned)(CurrentTime - target_p->localClient->firsttime),
1441 >                   (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1442 >                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1443        else /* show the real IP */
1444          sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1445                     from, to,
1446 <                   (IsUpper(statchar)) ?
1447 <                   get_client_name(target_p, SHOW_IP) :
1448 <                   get_client_name(target_p, HIDE_IP),
1449 <                   dbuf_length(&target_p->localClient->buf_sendq),
1450 <                   target_p->localClient->send.messages,
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,
1456 <                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1446 >                   (IsUpper(statchar)) ?
1447 >                   get_client_name(target_p, SHOW_IP) :
1448 >                   get_client_name(target_p, HIDE_IP),
1449 >                   dbuf_length(&target_p->localClient->buf_sendq),
1450 >                   target_p->localClient->send.messages,
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->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    }
1459   }
1460  
1461 < /* parse_stats_args()
1461 > /*
1462 > * stats_L
1463   *
1464 < * inputs       - arg count
1465 < *              - args
1466 < *              - doall flag
1467 < *              - wild card or not
1468 < * output       - pointer to name to use
1469 < * side effects -
1470 < * common parse routine for m_stats args
1464 > * inputs       - pointer to client to report to
1465 > *              - doall flag
1466 > *              - wild card or not
1467 > * output       - NONE
1468 > * side effects -
1469 > */
1470 > static void
1471 > stats_L(struct Client *source_p,char *name,int doall,
1472 >        int wilds,char statchar)
1473 > {
1474 >  stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1475 >  stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1476 >  stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1477 > }
1478 >
1479 > static void
1480 > stats_ltrace(struct Client *source_p, int parc, char *parv[])
1481 > {
1482 >  int doall = 0;
1483 >  int wilds = 0;
1484 >  char *name = NULL;
1485 >  char statchar;
1486 >
1487 >  if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1488 >  {
1489 >    statchar = parv[1][0];
1490 >
1491 >    stats_L(source_p, name, doall, wilds, statchar);
1492 >  }
1493 >  else
1494 >    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1495 >               from, to, "STATS");
1496 > }
1497 >
1498 > static const struct StatsStruct
1499 > {
1500 >  const unsigned char letter;
1501 >  void (*handler)();
1502 >  const unsigned int need_oper;
1503 >  const unsigned int need_admin;
1504 > } stats_cmd_table[] = {
1505 >  /* letter     function            need_oper need_admin */
1506 >  { 'a',        stats_dns_servers,      1,      1       },
1507 >  { 'A',        stats_dns_servers,      1,      1       },
1508 >  { 'c',        stats_connect,          1,      0       },
1509 >  { 'C',        stats_connect,          1,      0       },
1510 >  { 'd',        stats_tdeny,            1,      0       },
1511 >  { 'D',        stats_deny,             1,      0       },
1512 >  { 'e',        stats_exempt,           1,      0       },
1513 >  { 'E',        stats_events,           1,      1       },
1514 >  { 'f',        fd_dump,                1,      1       },
1515 >  { 'F',        fd_dump,                1,      1       },
1516 >  { 'g',        stats_pending_glines,   1,      0       },
1517 >  { 'G',        stats_glines,           1,      0       },
1518 >  { 'h',        stats_hooks,            1,      1       },
1519 >  { 'H',        stats_hubleaf,          1,      0       },
1520 >  { 'i',        stats_auth,             0,      0       },
1521 >  { 'I',        stats_auth,             0,      0       },
1522 >  { 'k',        stats_tklines,          0,      0       },
1523 >  { 'K',        stats_klines,           0,      0       },
1524 >  { 'l',        stats_ltrace,           1,      0       },
1525 >  { 'L',        stats_ltrace,           1,      0       },
1526 >  { 'm',        stats_messages,         0,      0       },
1527 >  { 'M',        stats_messages,         0,      0       },
1528 >  { 'o',        stats_oper,             0,      0       },
1529 >  { 'O',        stats_oper,             0,      0       },
1530 >  { 'p',        stats_operedup,         0,      0       },
1531 >  { 'P',        stats_ports,            0,      0       },
1532 >  { 'q',        stats_resv,             1,      0       },
1533 >  { 'Q',        stats_resv,             1,      0       },
1534 >  { 'r',        stats_usage,            1,      0       },
1535 >  { 'R',        stats_usage,            1,      0       },
1536 >  { 's',        stats_service,          1,      0       },
1537 >  { 'S',        stats_service,          1,      0       },
1538 >  { 't',        stats_tstats,           1,      0       },
1539 >  { 'T',        stats_tstats,           1,      0       },
1540 >  { 'u',        stats_uptime,           0,      0       },
1541 >  { 'U',        stats_shared,           1,      0       },
1542 >  { 'v',        stats_servers,          1,      0       },
1543 >  { 'x',        stats_gecos,            1,      0       },
1544 >  { 'X',        stats_gecos,            1,      0       },
1545 >  { 'y',        stats_class,            1,      0       },
1546 >  { 'Y',        stats_class,            1,      0       },
1547 >  { 'z',        stats_memory,           1,      0       },
1548 >  { '?',        stats_servlinks,        0,      0       },
1549 >  { '\0',       NULL,                   0,      0       }
1550 > };
1551 >
1552 > static void
1553 > do_stats(struct Client *source_p, int parc, char *parv[])
1554 > {
1555 >  const struct StatsStruct *tab = stats_cmd_table;
1556 >  const char statchar = *parv[1];
1557 >
1558 >  if (statchar == '\0')
1559 >  {
1560 >    sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1561 >               from, to, '*');
1562 >    return;
1563 >  }
1564 >
1565 >  for (; tab->handler; ++tab)
1566 >  {
1567 >    if (tab->letter == statchar)
1568 >    {
1569 >      /* The stats table says what privs are needed, so check --fl_ */
1570 >      if ((tab->need_admin && !HasUMode(source_p, UMODE_ADMIN)) ||
1571 >          (tab->need_oper && !HasUMode(source_p, UMODE_OPER)))
1572 >      {
1573 >        sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1574 >                   from, to);
1575 >        break;
1576 >      }
1577 >
1578 >      sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE,
1579 >                           "STATS %c requested by %s (%s@%s) [%s]",
1580 >                           statchar, source_p->name, source_p->username,
1581 >                           source_p->host, source_p->servptr->name);
1582 >      tab->handler(source_p, parc, parv);
1583 >      break;
1584 >    }
1585 >  }
1586 >
1587 >  sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1588 >             from, to, statchar);
1589 > }
1590 >
1591 > /*
1592 > * m_stats()
1593 > *      parv[0] = sender prefix
1594 > *      parv[1] = stat letter/command
1595 > *      parv[2] = (if present) server/mask in stats L
1596   *
1597 + * This will search the tables for the appropriate stats letter/command,
1598 + * if found execute it.  
1599   */
1600 < static char *
1601 < parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1600 > static void
1601 > m_stats(struct Client *client_p, struct Client *source_p,
1602 >        int parc, char *parv[])
1603   {
1604 <  char *name;
1604 >  static time_t last_used = 0;
1605  
1606 <  if (parc > 2)
1606 >  /* Is the stats meant for us? */
1607 >  if (!ConfigFileEntry.disable_remote)
1608 >    if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1609 >                    parc, parv) != HUNTED_ISME)
1610 >      return;
1611 >
1612 >  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1613    {
1614 <    name = parv[2];
1614 >    from = me.id;
1615 >    to = source_p->id;
1616 >  }
1617 >  else
1618 >  {
1619 >    from = me.name;
1620 >    to = source_p->name;
1621 >  }
1622  
1623 <    if (!irccmp(name, from))
1624 <      *doall = 2;
1625 <    else if (match(name, from))
1626 <      *doall = 1;
1623 >  /* Check the user is actually allowed to do /stats, and isnt flooding */
1624 >  if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
1625 >  {
1626 >    sendto_one(source_p,form_str(RPL_LOAD2HI),
1627 >               from, to);
1628 >    return;
1629 >  }
1630  
1631 <    if (strchr(name, '*') ||
1510 <        strchr(name, '?'))
1511 <      *wilds = 1;
1631 >  last_used = CurrentTime;
1632  
1633 <    return(name);
1633 >  do_stats(source_p, parc, parv);
1634 > }
1635 >
1636 > /*
1637 > * mo_stats()
1638 > *      parv[0] = sender prefix
1639 > *      parv[1] = stat letter/command
1640 > *      parv[2] = (if present) server/mask in stats L, or target
1641 > *
1642 > * This will search the tables for the appropriate stats letter,
1643 > * if found execute it.  
1644 > */
1645 > static void
1646 > mo_stats(struct Client *client_p, struct Client *source_p,
1647 >         int parc, char *parv[])
1648 > {
1649 >  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1650 >                  parc, parv) != HUNTED_ISME)
1651 >     return;
1652 >
1653 >  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1654 >  {
1655 >    from = me.id;
1656 >    to = source_p->id;
1657    }
1658    else
1659 <    return(NULL);
1659 >  {
1660 >    from = me.name;
1661 >    to = source_p->name;
1662 >  }
1663 >
1664 >  do_stats(source_p, parc, parv);
1665   }
1666 +
1667 + /*
1668 + * ms_stats - STATS message handler
1669 + *      parv[0] = sender prefix
1670 + *      parv[1] = statistics selector (defaults to Message frequency)
1671 + *      parv[2] = server name (current server defaulted, if omitted)
1672 + */
1673 + static void
1674 + ms_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 (IsClient(source_p))
1682 +    mo_stats(client_p, source_p, parc, parv);
1683 + }
1684 +
1685 + static struct Message stats_msgtab = {
1686 +  "STATS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
1687 +  { m_unregistered, m_stats, ms_stats, m_ignore, mo_stats, m_ignore }
1688 + };
1689 +
1690 + static void
1691 + module_init(void)
1692 + {
1693 +  mod_add_cmd(&stats_msgtab);
1694 + }
1695 +
1696 + static void
1697 + module_exit(void)
1698 + {
1699 +  mod_del_cmd(&stats_msgtab);
1700 + }
1701 +
1702 + struct module module_entry = {
1703 +  .node    = { NULL, NULL, NULL },
1704 +  .name    = NULL,
1705 +  .version = "$Revision$",
1706 +  .handle  = NULL,
1707 +  .modinit = module_init,
1708 +  .modexit = module_exit,
1709 +  .flags   = 0
1710 + };

Diff Legend

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