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.
Revision 1483 by michael, Wed Jul 25 19:15:48 2012 UTC

# Line 25 | Line 25
25   #include "stdinc.h"
26   #include "list.h"        /* dlink_node/dlink_list */
27   #include "balloc.h"
28 #include "handlers.h"    /* m_pass prototype */
28   #include "client.h"      /* Client */
30 #include "common.h"      /* TRUE/FALSE */
29   #include "irc_string.h"  
30   #include "ircd.h"        /* me */
31   #include "listener.h"    /* show_ports */
32   #include "s_gline.h"
35 #include "ircd_handler.h"
36 #include "msg.h"         /* Message */
33   #include "hostmask.h"
34   #include "numeric.h"     /* ERR_xxx */
35   #include "send.h"        /* sendto_one */
36   #include "fdlist.h"      /* PF and friends */
37   #include "s_bsd.h"       /* highest_fd */
38 < #include "s_conf.h"      /* AccessItem, report_configured_links */
38 > #include "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 *[]);
59
60 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 }
78
79 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
118 {
119  const unsigned char letter;
120  void (*handler)();
121  const unsigned int need_oper;
122  const unsigned int need_admin;
123 } stats_cmd_table[] = {
124  /* letter     function            need_oper need_admin */
125  { 'a',        stats_dns_servers,      1,      1       },
126  { 'A',        stats_dns_servers,      1,      1       },
127  { 'c',        stats_connect,          1,      0       },
128  { 'C',        stats_connect,          1,      0       },
129  { 'd',        stats_tdeny,            1,      0       },
130  { '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       }
170 };
52  
53   const char *from, *to;
54  
174 static void
175 do_stats(struct Client *source_p, int parc, char *parv[])
176 {
177  const struct StatsStruct *tab = stats_cmd_table;
178  char statchar = *parv[1];
179
180  if (statchar == '\0')
181  {
182    sendto_one(source_p, form_str(RPL_ENDOFSTATS),
183               from, to, '*');
184    return;
185  }
186
187  for (; tab->handler; ++tab)
188  {
189    if (tab->letter == statchar)
190    {
191      /* 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      }
199
200      /* Blah, stats L needs the parameters, none of the others do.. */
201      if (statchar == 'L' || statchar == 'l')
202      {
203        sendto_realops_flags(UMODE_SPY, L_ALL,
204                             "STATS %c requested by %s (%s@%s) [%s] on %s",
205                             statchar, source_p->name, source_p->username,
206                             source_p->host, source_p->servptr->name,
207                             parc > 2 ? parv[2] : "<no recipient>");
208        tab->handler(source_p, parc, parv);
209      }
210      else
211      {
212        sendto_realops_flags(UMODE_SPY, L_ALL,
213                             "STATS %c requested by %s (%s@%s) [%s]",
214                             statchar, source_p->name, source_p->username,
215                             source_p->host, source_p->servptr->name);
216        tab->handler(source_p);
217      }
218
219      break;
220    }
221  }
222
223  sendto_one(source_p, form_str(RPL_ENDOFSTATS),
224             from, to, statchar);
225 }
226
227 /*
228 * m_stats()
229 *      parv[0] = sender prefix
230 *      parv[1] = stat letter/command
231 *      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;
241
242  /* 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;
247
248  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
249  {
250    from = me.id;
251    to = source_p->id;
252  }
253  else
254  {
255    from = me.name;
256    to = source_p->name;
257  }
258
259  /* 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  }
266
267  last_used = CurrentTime;
268
269  do_stats(source_p, parc, parv);
270 }
271
272 /*
273 * mo_stats()
274 *      parv[0] = sender prefix
275 *      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;
288
289  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
290  {
291    from = me.id;
292    to = source_p->id;
293  }
294  else
295  {
296    from = me.name;
297    to = source_p->name;
298  }
299
300  do_stats(source_p, parc, parv);
301 }
302
303 /*
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;
316
317  if (IsClient(source_p))
318    mo_stats(client_p, source_p, parc, parv);
319 }
320
55   /*
56   * This is part of the STATS replies. There is no offical numeric for this
57   * since this isnt an official command, in much the same way as HASH isnt.
# Line 326 | Line 60 | ms_stats(struct Client *client_p, struct
60   * -avalon
61   */
62   static void
63 < send_usage(struct Client *source_p)
63 > stats_usage(struct Client *source_p, int parc, char *parv[])
64   {
65    struct rusage rus;
66    time_t secs;
# Line 353 | Line 87 | send_usage(struct Client *source_p)
87    if (secs == 0)
88      secs = 1;
89  
90 <  rup = (CurrentTime - me.since) * hzz;
90 >  rup = (CurrentTime - me.localClient->since) * hzz;
91  
92    if (rup == 0)
93      rup = 1;
# Line 382 | Line 116 | send_usage(struct Client *source_p)
116   }
117  
118   static void
119 < count_memory(struct Client *source_p)
119 > stats_memory(struct Client *source_p, int parc, char *parv[])
120   {
121    const dlink_node *gptr = NULL;
122    const dlink_node *dlink = NULL;
# Line 409 | Line 143 | count_memory(struct Client *source_p)
143    unsigned int safelist_count = 0;
144    uint64_t safelist_memory = 0;
145  
412  uint64_t away_memory = 0;       /* memory used by aways           */
146    uint64_t wwm = 0;               /* whowas array memory used       */
147    uint64_t conf_memory = 0;       /* memory used by conf lines      */
148    uint64_t mem_ips_stored;        /* memory used by ip address hash */
# Line 448 | Line 181 | count_memory(struct Client *source_p)
181      {
182        ++users_counted;
183  
184 <      if (target_p->away != NULL)
452 <      {
184 >      if (target_p->away[0])
185          ++aways_counted;
454        away_memory += strlen(target_p->away) + 1;
455      }
186      }
187    }
188  
# Line 467 | Line 197 | count_memory(struct Client *source_p)
197      channel_members += dlink_list_length(&chptr->members);
198      channel_invites += dlink_list_length(&chptr->invites);
199  
200 <    if (chptr->topic != NULL)
200 >    if (chptr->topic[0])
201        ++topic_count;
202  
203      channel_bans += dlink_list_length(&chptr->banlist);
# Line 549 | Line 279 | count_memory(struct Client *source_p)
279               me.name, RPL_STATSDEBUG, source_p->name, users_counted,
280               (users_counted * sizeof(struct Client)));
281  
282 <  sendto_one(source_p, ":%s %d %s z :User aways %u(%llu)",
282 >  sendto_one(source_p, ":%s %d %s z :User aways %u",
283               me.name, RPL_STATSDEBUG, source_p->name,
284 <             aways_counted, away_memory);
284 >             aways_counted);
285  
286    sendto_one(source_p, ":%s %d %s z :Attached confs %u(%llu)",
287               me.name, RPL_STATSDEBUG, source_p->name,
# Line 649 | Line 379 | stats_dns_servers(struct Client *source_
379   }
380  
381   static void
382 < stats_connect(struct Client *source_p)
382 > stats_connect(struct Client *source_p, int parc, char *parv[])
383   {
384 <  report_confitem_types(source_p, SERVER_TYPE, 0);
384 >  report_confitem_types(source_p, SERVER_TYPE);
385   }
386  
387   /* stats_deny()
# Line 661 | Line 391 | stats_connect(struct Client *source_p)
391   * side effects - client is given dline list.
392   */
393   static void
394 < stats_deny(struct Client *source_p)
394 > stats_deny(struct Client *source_p, int parc, char *parv[])
395   {
666  struct AddressRec *arec;
396    struct ConfItem *conf;
397    struct AccessItem *aconf;
398 <  int i;
398 >  dlink_node *ptr = NULL;
399 >  unsigned int i = 0;
400  
401 <  for (i = 0; i < ATABLE_SIZE; i++)
401 >
402 >  for (i = 0; i < ATABLE_SIZE; ++i)
403    {
404 <    for (arec = atable[i]; arec; arec=arec->next)
404 >    DLINK_FOREACH(ptr, atable[i].head)
405      {
406 +      struct AddressRec *arec = ptr->data;
407 +
408        if (arec->type == CONF_DLINE)
409        {
410          aconf = arec->aconf;
# Line 697 | Line 430 | stats_deny(struct Client *source_p)
430   * side effects - client is given dline list.
431   */
432   static void
433 < stats_tdeny(struct Client *source_p)
433 > stats_tdeny(struct Client *source_p, int parc, char *parv[])
434   {
702  struct AddressRec *arec;
435    struct ConfItem *conf;
436    struct AccessItem *aconf;
437 <  int i;
437 >  dlink_node *ptr = NULL;
438 >  unsigned int i = 0;
439  
440 <  for (i = 0; i < ATABLE_SIZE; i++)
440 >
441 >  for (i = 0; i < ATABLE_SIZE; ++i)
442    {
443 <    for (arec = atable[i]; arec; arec=arec->next)
443 >    DLINK_FOREACH(ptr, atable[i].head)
444      {
445 +      struct AddressRec *arec = ptr->data;
446 +
447        if (arec->type == CONF_DLINE)
448        {
449          aconf = arec->aconf;
# Line 733 | Line 469 | stats_tdeny(struct Client *source_p)
469   * side effects - client is given list of exempt blocks
470   */
471   static void
472 < stats_exempt(struct Client *source_p)
472 > stats_exempt(struct Client *source_p, int parc, char *parv[])
473   {
738  struct AddressRec *arec;
474    struct ConfItem *conf;
475    struct AccessItem *aconf;
476 <  int i;
476 >  dlink_node *ptr = NULL;
477 >  unsigned int i = 0;
478  
479    if (ConfigFileEntry.stats_e_disabled)
480    {
# Line 747 | Line 483 | stats_exempt(struct Client *source_p)
483      return;
484    }
485  
486 <  for (i = 0; i < ATABLE_SIZE; i++)
486 >
487 >  for (i = 0; i < ATABLE_SIZE; ++i)
488    {
489 <    for (arec = atable[i]; arec; arec=arec->next)
489 >    DLINK_FOREACH(ptr, atable[i].head)
490      {
491 +      struct AddressRec *arec = ptr->data;
492 +
493        if (arec->type == CONF_EXEMPTDLINE)
494        {
495          aconf = arec->aconf;
# Line 766 | Line 505 | stats_exempt(struct Client *source_p)
505   }
506  
507   static void
508 < stats_events(struct Client *source_p)
508 > stats_events(struct Client *source_p, int parc, char *parv[])
509   {
510    show_events(source_p);
511   }
# Line 778 | Line 517 | stats_events(struct Client *source_p)
517   * side effects - client is shown list of pending glines
518   */
519   static void
520 < stats_pending_glines(struct Client *source_p)
520 > stats_pending_glines(struct Client *source_p, int parc, char *parv[])
521   {
522    const dlink_node *dn_ptr = NULL;
523    const struct gline_pending *glp_ptr = NULL;
# Line 867 | Line 606 | stats_pending_glines(struct Client *sour
606   * side effects - client is shown list of glines
607   */
608   static void
609 < stats_glines(struct Client *source_p)
609 > stats_glines(struct Client *source_p, int parc, char *parv[])
610   {
611 <  struct AddressRec *arec = NULL;
612 <  int i = 0;
611 >  dlink_node *ptr = NULL;
612 >  unsigned int i = 0;
613  
614    if (!ConfigFileEntry.glines)
615    {
# Line 879 | Line 618 | stats_glines(struct Client *source_p)
618      return;
619    }
620  
621 <  for (; i < ATABLE_SIZE; ++i)
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 +      const struct AddressRec *arec = ptr->data;
626 +
627        if (arec->type == CONF_GLINE)
628        {
629          const struct AccessItem *aconf = arec->aconf;
# Line 897 | Line 638 | stats_glines(struct Client *source_p)
638    }
639   }
640  
641 < /* stats_gdeny()
641 > static void
642 > stats_hubleaf(struct Client *source_p, int parc, char *parv[])
643 > {
644 >  report_confitem_types(source_p, HUB_TYPE);
645 >  report_confitem_types(source_p, LEAF_TYPE);
646 > }
647 >
648 > /*
649 > * show_iline_prefix()
650   *
651 < * input        - client pointer
652 < * outputs      - none
653 < * side effects - client is shown gline ACL
651 > * inputs       - pointer to struct Client requesting output
652 > *              - pointer to struct AccessItem
653 > *              - name to which iline prefix will be prefixed to
654 > * output       - pointer to static string with prefixes listed in ascii form
655 > * side effects - NONE
656   */
657 < static void
658 < stats_gdeny(struct Client *source_p)
657 > static const char *
658 > show_iline_prefix(struct Client *sptr, struct AccessItem *aconf, const char *name)
659   {
660 <  if (!ConfigFileEntry.glines)
661 <  {
662 <    sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
663 <               from, to);
664 <    return;
665 <  }
660 >  static char prefix_of_host[USERLEN + 14];
661 >  char *prefix_ptr = prefix_of_host;
662 >
663 >  if (IsNoTilde(aconf))
664 >    *prefix_ptr++ = '-';
665 >  if (IsLimitIp(aconf))
666 >    *prefix_ptr++ = '!';
667 >  if (IsNeedIdentd(aconf))
668 >    *prefix_ptr++ = '+';
669 >  if (!IsNeedPassword(aconf))
670 >    *prefix_ptr++ = '&';
671 >  if (IsConfExemptResv(aconf))
672 >    *prefix_ptr++ = '$';
673 >  if (IsNoMatchIp(aconf))
674 >    *prefix_ptr++ = '%';
675 >  if (IsConfDoSpoofIp(aconf))
676 >    *prefix_ptr++ = '=';
677 >  if (MyOper(sptr) && IsConfExemptKline(aconf))
678 >    *prefix_ptr++ = '^';
679 >  if (MyOper(sptr) && IsConfExemptGline(aconf))
680 >    *prefix_ptr++ = '_';
681 >  if (MyOper(sptr) && IsConfExemptLimits(aconf))
682 >    *prefix_ptr++ = '>';
683 >  if (IsConfCanFlood(aconf))
684 >    *prefix_ptr++ = '|';
685 >
686 >  strlcpy(prefix_ptr, name, USERLEN+1);
687  
688 <  report_confitem_types(source_p, GDENY_TYPE, 0);
688 >  return prefix_of_host;
689   }
690  
691   static void
692 < stats_hubleaf(struct Client *source_p)
692 > report_auth(struct Client *client_p, int parc, char *parv[])
693   {
694 <  report_confitem_types(source_p, HUB_TYPE, 0);
695 <  report_confitem_types(source_p, LEAF_TYPE, 0);
694 >  struct ConfItem *conf;
695 >  struct AccessItem *aconf;
696 >  dlink_node *ptr = NULL;
697 >  unsigned int i;
698 >
699 >
700 >  for (i = 0; i < ATABLE_SIZE; ++i)
701 >  {
702 >    DLINK_FOREACH(ptr, atable[i].head)
703 >    {
704 >      struct AddressRec *arec = ptr->data;
705 >
706 >      if (arec->type == CONF_CLIENT)
707 >      {
708 >        aconf = arec->aconf;
709 >
710 >        if (!MyOper(client_p) && IsConfDoSpoofIp(aconf))
711 >          continue;
712 >
713 >        conf = unmap_conf_item(aconf);
714 >
715 >        /* We are doing a partial list, based on what matches the u@h of the
716 >         * sender, so prepare the strings for comparing --fl_
717 >         */
718 >        if (ConfigFileEntry.hide_spoof_ips)
719 >          sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
720 >                     client_p->name, 'I',
721 >                     conf->name == NULL ? "*" : conf->name,
722 >                     show_iline_prefix(client_p, aconf, aconf->user),
723 >                     IsConfDoSpoofIp(aconf) ? "255.255.255.255" :
724 >                     aconf->host, aconf->port,
725 >                     aconf->class_ptr ? aconf->class_ptr->name : "<default>");
726 >
727 >        else
728 >          sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
729 >                     client_p->name, 'I',
730 >                     conf->name == NULL ? "*" : conf->name,
731 >                     show_iline_prefix(client_p, aconf, aconf->user),
732 >                     aconf->host, aconf->port,
733 >                     aconf->class_ptr ? aconf->class_ptr->name : "<default>");
734 >      }
735 >    }
736 >  }
737   }
738  
739   static void
740 < stats_auth(struct Client *source_p)
740 > stats_auth(struct Client *source_p, int parc, char *parv[])
741   {
742    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
743 <  if ((ConfigFileEntry.stats_i_oper_only == 2) && !IsOper(source_p))
743 >  if ((ConfigFileEntry.stats_i_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
744      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
745                 from, to);
746  
747    /* If unopered, Only return matching auth blocks */
748 <  else if ((ConfigFileEntry.stats_i_oper_only == 1) && !IsOper(source_p))
748 >  else if ((ConfigFileEntry.stats_i_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
749    {
750      struct ConfItem *conf;
751      struct AccessItem *aconf;
# Line 943 | Line 756 | stats_auth(struct Client *source_p)
756                                     CONF_CLIENT,
757                                     source_p->localClient->aftype,
758                                     source_p->username,
759 <                                   source_p->localClient->passwd);
759 >                                   source_p->localClient->passwd, 1);
760      else
761        aconf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
762 <                                   0, source_p->username, NULL);
762 >                                   0, source_p->username, NULL, 1);
763  
764      if (aconf == NULL)
765        return;
# Line 961 | Line 774 | stats_auth(struct Client *source_p)
774    }
775    /* They are opered, or allowed to see all auth blocks */
776    else
777 <    report_auth(source_p);
777 >    report_auth(source_p, 0, NULL);
778   }
779  
780 + /* report_Klines()
781 + * Inputs: Client to report to,
782 + *         type(==0 for perm, !=0 for temporary)
783 + *         mask
784 + * Output: None
785 + * Side effects: Reports configured K(or k)-lines to client_p.
786 + */
787   static void
788 < stats_tklines(struct Client *source_p)
788 > report_Klines(struct Client *client_p, int tkline)
789 > {
790 >  struct AccessItem *aconf = NULL;
791 >  unsigned int i = 0;
792 >  const char *p = NULL;
793 >  dlink_node *ptr = NULL;
794 >
795 >  if (tkline)
796 >    p = "k";
797 >  else
798 >    p = "K";
799 >
800 >  for (i = 0; i < ATABLE_SIZE; ++i)
801 >  {
802 >    DLINK_FOREACH(ptr, atable[i].head)
803 >    {
804 >      struct AddressRec *arec = ptr->data;
805 >
806 >      if (arec->type == CONF_KLINE)
807 >      {
808 >        if ((tkline && !((aconf = arec->aconf)->flags & CONF_FLAGS_TEMPORARY)) ||
809 >            (!tkline && ((aconf = arec->aconf)->flags & CONF_FLAGS_TEMPORARY)))
810 >          continue;
811 >
812 >        if (HasUMode(client_p, UMODE_OPER))
813 >          sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
814 >                     client_p->name, p, aconf->host, aconf->user,
815 >                     aconf->reason, aconf->oper_reason ? aconf->oper_reason : "");
816 >        else
817 >          sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
818 >                     client_p->name, p, aconf->host, aconf->user,
819 >                     aconf->reason, "");
820 >      }
821 >    }
822 >  }
823 > }
824 >
825 > static void
826 > stats_tklines(struct Client *source_p, int parc, char *parv[])
827   {
828    struct ConfItem *conf;
829    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
830 <  if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
830 >  if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
831      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
832                 from, to);
833  
834    /* If unopered, Only return matching klines */
835 <  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
835 >  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
836    {
837      struct AccessItem *aconf;
838  
839      if (MyConnect(source_p))
840        aconf = find_conf_by_address(source_p->host,
841                                     &source_p->localClient->ip,
842 <                                   CONF_KILL,
842 >                                   CONF_KLINE,
843                                     source_p->localClient->aftype,
844 <                                   source_p->username, NULL);
844 >                                   source_p->username, NULL, 1);
845      else
846 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
847 <                                   0, source_p->username, NULL);
846 >      aconf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
847 >                                   0, source_p->username, NULL, 1);
848  
849      if (aconf == NULL)
850        return;
# Line 1003 | Line 861 | stats_tklines(struct Client *source_p)
861    /* Theyre opered, or allowed to see all klines */
862    else {
863      report_Klines(source_p, 1);
1006    report_confitem_types(source_p, RKLINE_TYPE, 1);
864    }
865   }
866  
867   static void
868 < stats_klines(struct Client *source_p)
868 > stats_klines(struct Client *source_p, int parc, char *parv[])
869   {
870    /* Oper only, if unopered, return ERR_NOPRIVILEGES */
871 <  if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
871 >  if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
872      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
873                 from, to);
874  
875    /* If unopered, Only return matching klines */
876 <  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
876 >  else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
877    {
878      struct AccessItem *aconf;
879  
# Line 1024 | Line 881 | stats_klines(struct Client *source_p)
881      if (MyConnect(source_p))
882        aconf = find_conf_by_address(source_p->host,
883                                     &source_p->localClient->ip,
884 <                                   CONF_KILL,
884 >                                   CONF_KLINE,
885                                     source_p->localClient->aftype,
886 <                                   source_p->username, NULL);
886 >                                   source_p->username, NULL, 0);
887      else
888 <      aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
889 <                                   0, source_p->username, NULL);
888 >      aconf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
889 >                                   0, source_p->username, NULL, 0);
890  
891      if (aconf == NULL)
892        return;
# Line 1045 | Line 902 | stats_klines(struct Client *source_p)
902    /* Theyre opered, or allowed to see all klines */
903    else {
904      report_Klines(source_p, 0);
905 <    report_confitem_types(source_p, RKLINE_TYPE, 0);
905 >    report_confitem_types(source_p, RKLINE_TYPE);
906    }
907   }
908  
909   static void
910 < stats_messages(struct Client *source_p)
910 > stats_messages(struct Client *source_p, int parc, char *parv[])
911   {
912    report_messages(source_p);
913   }
914  
915   static void
916 < stats_oper(struct Client *source_p)
916 > stats_oper(struct Client *source_p, int parc, char *parv[])
917   {
918 <  if (!IsOper(source_p) && ConfigFileEntry.stats_o_oper_only)
918 >  if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_o_oper_only)
919      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
920                 from, to);
921    else
922 <    report_confitem_types(source_p, OPER_TYPE, 0);
922 >    report_confitem_types(source_p, OPER_TYPE);
923   }
924  
925   /* stats_operedup()
# Line 1072 | Line 929 | stats_oper(struct Client *source_p)
929   * side effects - client is shown a list of active opers
930   */
931   static void
932 < stats_operedup(struct Client *source_p)
932 > stats_operedup(struct Client *source_p, int parc, char *parv[])
933   {
934    dlink_node *ptr;
935  
# Line 1080 | Line 937 | stats_operedup(struct Client *source_p)
937    {
938      const struct Client *target_p = ptr->data;
939  
940 <    if (IsOperHidden(target_p) && !IsOper(source_p))
940 >    if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
941        continue;
942  
943 <    if (MyClient(source_p) && IsOper(source_p))
943 >    if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
944        sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %d",
945                   from, RPL_STATSDEBUG, to,
946 <                 IsAdmin(target_p) ?
1090 <                 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
946 >                 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
947                   oper_privs_as_string(target_p->localClient->operflags),
948                   target_p->name, target_p->username, target_p->host,
949                   (int)(CurrentTime - target_p->localClient->last_privmsg));
950      else
951        sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
952                   from, RPL_STATSDEBUG, to,
953 <                 IsAdmin(target_p) ?
1098 <                 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
953 >                 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
954                   target_p->name, target_p->username, target_p->host,
955                   (int)(CurrentTime - target_p->localClient->last_privmsg));
956    }
# Line 1105 | Line 960 | stats_operedup(struct Client *source_p)
960   }
961  
962   static void
963 < stats_ports(struct Client *source_p)
963 > stats_ports(struct Client *source_p, int parc, char *parv[])
964   {
965 <  if (!IsOper(source_p) && ConfigFileEntry.stats_P_oper_only)
965 >  if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_P_oper_only)
966      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
967                 from, to);
968    else
# Line 1115 | Line 970 | stats_ports(struct Client *source_p)
970   }
971  
972   static void
973 < stats_resv(struct Client *source_p)
973 > stats_resv(struct Client *source_p, int parc, char *parv[])
974   {
975    report_resv(source_p);
976   }
977  
978   static void
979 < stats_usage(struct Client *source_p)
979 > stats_service(struct Client *source_p, int parc, char *parv[])
980   {
981 <  send_usage(source_p);
981 >  report_confitem_types(source_p, SERVICE_TYPE);
982   }
983  
984   static void
985 < stats_service(struct Client *source_p)
1131 < {
1132 <  report_confitem_types(source_p, SERVICE_TYPE, 0);
1133 < }
1134 <
1135 < static void
1136 < stats_tstats(struct Client *source_p)
985 > stats_tstats(struct Client *source_p, int parc, char *parv[])
986   {
987    const struct Client *target_p = NULL;
988    const dlink_node *ptr = NULL;
# Line 1156 | Line 1005 | stats_tstats(struct Client *source_p)
1005  
1006      sp->is_sbs += target_p->localClient->send.bytes;
1007      sp->is_sbr += target_p->localClient->recv.bytes;
1008 <    sp->is_sti += CurrentTime - target_p->firsttime;
1008 >    sp->is_sti += CurrentTime - target_p->localClient->firsttime;
1009    }
1010  
1011    sp->is_cl += dlink_list_length(&local_client_list);
# Line 1167 | Line 1016 | stats_tstats(struct Client *source_p)
1016  
1017      sp->is_cbs += target_p->localClient->send.bytes;
1018      sp->is_cbr += target_p->localClient->recv.bytes;
1019 <    sp->is_cti += CurrentTime - target_p->firsttime;
1019 >    sp->is_cti += CurrentTime - target_p->localClient->firsttime;
1020    }
1021  
1022    sp->is_ni += dlink_list_length(&unknown_list);
# Line 1204 | Line 1053 | stats_tstats(struct Client *source_p)
1053   }
1054  
1055   static void
1056 < stats_uptime(struct Client *source_p)
1056 > stats_uptime(struct Client *source_p, int parc, char *parv[])
1057   {
1058 <  time_t now = CurrentTime - me.since;
1058 >  time_t now = CurrentTime - me.localClient->since;
1059  
1060    sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
1061               now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
1062  
1063 <  if (!ConfigFileEntry.disable_remote || IsOper(source_p))
1063 >  if (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER))
1064       sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
1065                  Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount);
1066   }
1067  
1068   static void
1069 < stats_shared(struct Client *source_p)
1069 > stats_shared(struct Client *source_p, int parc, char *parv[])
1070   {
1071 <  report_confitem_types(source_p, ULINE_TYPE, 0);
1071 >  report_confitem_types(source_p, ULINE_TYPE);
1072   }
1073  
1074   /* stats_servers()
# Line 1229 | Line 1078 | stats_shared(struct Client *source_p)
1078   * side effects - client is shown lists of who connected servers
1079   */
1080   static void
1081 < stats_servers(struct Client *source_p)
1081 > stats_servers(struct Client *source_p, int parc, char *parv[])
1082   {
1083    dlink_node *ptr = NULL;
1084  
# Line 1240 | Line 1089 | stats_servers(struct Client *source_p)
1089      sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
1090                 from, RPL_STATSDEBUG, to, target_p->name,
1091                 (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1092 <               "*", "*", (int)(CurrentTime - target_p->lasttime));
1092 >               "*", "*", (int)(CurrentTime - target_p->localClient->lasttime));
1093    }
1094  
1095    sendto_one(source_p, ":%s %d %s v :%u Server(s)",
# Line 1248 | Line 1097 | stats_servers(struct Client *source_p)
1097   }
1098  
1099   static void
1100 < stats_gecos(struct Client *source_p)
1252 < {
1253 <  report_confitem_types(source_p, XLINE_TYPE, 0);
1254 <  report_confitem_types(source_p, RXLINE_TYPE, 0);
1255 < }
1256 <
1257 < static void
1258 < stats_class(struct Client *source_p)
1100 > stats_gecos(struct Client *source_p, int parc, char *parv[])
1101   {
1102 <  report_confitem_types(source_p, CLASS_TYPE, 0);
1102 >  report_confitem_types(source_p, XLINE_TYPE);
1103 >  report_confitem_types(source_p, RXLINE_TYPE);
1104   }
1105  
1106   static void
1107 < stats_memory(struct Client *source_p)
1107 > stats_class(struct Client *source_p, int parc, char *parv[])
1108   {
1109 <  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);
1109 >  report_confitem_types(source_p, CLASS_TYPE);
1110   }
1111  
1112   static void
1113 < stats_servlinks(struct Client *source_p)
1113 > stats_servlinks(struct Client *source_p, int parc, char *parv[])
1114   {
1115    uint64_t sendB = 0, recvB = 0;
1116    time_t uptime = 0;
1117    dlink_node *ptr = NULL;
1118  
1119 <  if (ConfigServerHide.flatten_links && !IsOper(source_p))
1119 >  if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
1120    {
1121      sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1122                 from, to);
# Line 1324 | Line 1133 | stats_servlinks(struct Client *source_p)
1133      /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
1134      sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1135                 from, to,
1136 <               get_client_name(target_p, IsAdmin(source_p) ? SHOW_IP : MASK_IP),
1136 >               get_client_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
1137                 dbuf_length(&target_p->localClient->buf_sendq),
1138                 target_p->localClient->send.messages,
1139                 target_p->localClient->send.bytes >> 10,
1140                 target_p->localClient->recv.messages,
1141                 target_p->localClient->recv.bytes >> 10,
1142 <               (unsigned)(CurrentTime - target_p->firsttime),
1143 <               (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since): 0,
1144 <               IsOper(source_p) ? show_capabilities(target_p) : "TS");
1142 >               (unsigned)(CurrentTime - target_p->localClient->firsttime),
1143 >               (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since): 0,
1144 >               HasUMode(source_p, UMODE_OPER) ? show_capabilities(target_p) : "TS");
1145    }
1146  
1147    sendB >>= 10;
# Line 1347 | Line 1156 | stats_servlinks(struct Client *source_p)
1156               from, RPL_STATSDEBUG, to,
1157               _GMKv(recvB), _GMKs(recvB));
1158  
1159 <  uptime = (CurrentTime - me.since);
1159 >  uptime = (CurrentTime - me.localClient->since);
1160  
1161    sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
1162               from, RPL_STATSDEBUG, to,
# Line 1363 | Line 1172 | stats_servlinks(struct Client *source_p)
1172               (float)uptime));
1173   }
1174  
1175 < static void
1176 < stats_ltrace(struct Client *source_p, int parc, char *parv[])
1175 > /* parse_stats_args()
1176 > *
1177 > * inputs       - arg count
1178 > *              - args
1179 > *              - doall flag
1180 > *              - wild card or not
1181 > * output       - pointer to name to use
1182 > * side effects -
1183 > * common parse routine for m_stats args
1184 > *
1185 > */
1186 > static char *
1187 > parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1188   {
1189 <  int doall = 0;
1370 <  int wilds = 0;
1371 <  char *name = NULL;
1372 <  char statchar;
1189 >  char *name;
1190  
1191 <  if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1191 >  if (parc > 2)
1192    {
1193 <    statchar = parv[1][0];
1193 >    name = parv[2];
1194  
1195 <    stats_L(source_p, name, doall, wilds, statchar);
1195 >    if (!irccmp(name, from))
1196 >      *doall = 2;
1197 >    else if (match(name, from))
1198 >      *doall = 1;
1199 >
1200 >    *wilds = has_wildcards(name);
1201 >
1202 >    return name;
1203    }
1380  else
1381    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1382               from, to, "STATS");
1383 }
1204  
1205 < /*
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);
1205 >  return NULL;
1206   }
1207  
1208   static void
# Line 1417 | Line 1222 | stats_L_list(struct Client *source_p,cha
1222    {
1223      target_p = ptr->data;
1224  
1225 <    if (IsInvisible(target_p) && (doall || wilds) &&
1226 <        !(MyConnect(source_p) && IsOper(source_p)) &&
1227 <        !IsOper(target_p) && (target_p != source_p))
1225 >    if (HasUMode(target_p, UMODE_INVISIBLE) && (doall || wilds) &&
1226 >        !(MyConnect(source_p) && HasUMode(source_p, UMODE_OPER)) &&
1227 >        !HasUMode(target_p, UMODE_OPER) && (target_p != source_p))
1228        continue;
1229      if (!doall && wilds && !match(name, target_p->name))
1230        continue;
# Line 1428 | Line 1233 | stats_L_list(struct Client *source_p,cha
1233  
1234      /* This basically shows ips for our opers if its not a server/admin, or
1235       * its one of our admins.  */
1236 <    if(MyClient(source_p) && IsOper(source_p) &&
1237 <       (IsAdmin(source_p) ||
1238 <       (!IsServer(target_p) && !IsAdmin(target_p) &&
1236 >    if(MyClient(source_p) && HasUMode(source_p, UMODE_OPER) &&
1237 >       (HasUMode(source_p, UMODE_ADMIN) ||
1238 >       (!IsServer(target_p) && !HasUMode(target_p, UMODE_ADMIN) &&
1239         !IsHandshake(target_p) && !IsConnecting(target_p))))
1240      {
1241        sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1242 <                 from, to,
1242 >                 from, to,
1243                   (IsUpper(statchar)) ?
1244                   get_client_name(target_p, SHOW_IP) :
1245                   get_client_name(target_p, HIDE_IP),
# Line 1443 | Line 1248 | stats_L_list(struct Client *source_p,cha
1248                   target_p->localClient->send.bytes>>10,
1249                   target_p->localClient->recv.messages,
1250                   target_p->localClient->recv.bytes>>10,
1251 <                 (unsigned)(CurrentTime - target_p->firsttime),
1252 <                 (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1251 >                 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1252 >                 (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1253                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1254      }
1255      else
1256      {
1257        /* If its a hidden ip, an admin, or a server, mask the real IP */
1258 <      if(IsIPSpoof(target_p) || IsServer(target_p) || IsAdmin(target_p)
1258 >      if(IsIPSpoof(target_p) || IsServer(target_p) || HasUMode(target_p, UMODE_ADMIN)
1259           || IsHandshake(target_p) || IsConnecting(target_p))
1260          sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1261                     from, to,
1262 <                   get_client_name(target_p, MASK_IP),
1263 <                   dbuf_length(&target_p->localClient->buf_sendq),
1264 <                   target_p->localClient->send.messages,
1265 <                   target_p->localClient->send.bytes>>10,
1266 <                   target_p->localClient->recv.messages,
1267 <                   target_p->localClient->recv.bytes>>10,
1268 <                   (unsigned)(CurrentTime - target_p->firsttime),
1269 <                   (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1270 <                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1262 >                   get_client_name(target_p, MASK_IP),
1263 >                   dbuf_length(&target_p->localClient->buf_sendq),
1264 >                   target_p->localClient->send.messages,
1265 >                   target_p->localClient->send.bytes>>10,
1266 >                   target_p->localClient->recv.messages,
1267 >                   target_p->localClient->recv.bytes>>10,
1268 >                   (unsigned)(CurrentTime - target_p->localClient->firsttime),
1269 >                   (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1270 >                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1271        else /* show the real IP */
1272          sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1273                     from, to,
1274 <                   (IsUpper(statchar)) ?
1275 <                   get_client_name(target_p, SHOW_IP) :
1276 <                   get_client_name(target_p, HIDE_IP),
1277 <                   dbuf_length(&target_p->localClient->buf_sendq),
1278 <                   target_p->localClient->send.messages,
1279 <                   target_p->localClient->send.bytes>>10,
1280 <                   target_p->localClient->recv.messages,
1281 <                   target_p->localClient->recv.bytes>>10,
1282 <                   (unsigned)(CurrentTime - target_p->firsttime),
1283 <                   (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1284 <                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1274 >                   (IsUpper(statchar)) ?
1275 >                   get_client_name(target_p, SHOW_IP) :
1276 >                   get_client_name(target_p, HIDE_IP),
1277 >                   dbuf_length(&target_p->localClient->buf_sendq),
1278 >                   target_p->localClient->send.messages,
1279 >                   target_p->localClient->send.bytes>>10,
1280 >                   target_p->localClient->recv.messages,
1281 >                   target_p->localClient->recv.bytes>>10,
1282 >                   (unsigned)(CurrentTime - target_p->localClient->firsttime),
1283 >                   (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1284 >                   IsServer(target_p) ? show_capabilities(target_p) : "-");
1285      }
1286    }
1287   }
1288  
1289 < /* parse_stats_args()
1289 > /*
1290 > * stats_L
1291   *
1292 < * inputs       - arg count
1293 < *              - args
1294 < *              - doall flag
1295 < *              - wild card or not
1296 < * output       - pointer to name to use
1297 < * side effects -
1298 < * common parse routine for m_stats args
1292 > * inputs       - pointer to client to report to
1293 > *              - doall flag
1294 > *              - wild card or not
1295 > * output       - NONE
1296 > * side effects -
1297 > */
1298 > static void
1299 > stats_L(struct Client *source_p,char *name,int doall,
1300 >        int wilds,char statchar)
1301 > {
1302 >  stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1303 >  stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1304 >  stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1305 > }
1306 >
1307 > static void
1308 > stats_ltrace(struct Client *source_p, int parc, char *parv[])
1309 > {
1310 >  int doall = 0;
1311 >  int wilds = 0;
1312 >  char *name = NULL;
1313 >  char statchar;
1314 >
1315 >  if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1316 >  {
1317 >    statchar = parv[1][0];
1318 >
1319 >    stats_L(source_p, name, doall, wilds, statchar);
1320 >  }
1321 >  else
1322 >    sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1323 >               from, to, "STATS");
1324 > }
1325 >
1326 > static const struct StatsStruct
1327 > {
1328 >  const unsigned char letter;
1329 >  void (*handler)();
1330 >  const unsigned int need_oper;
1331 >  const unsigned int need_admin;
1332 > } stats_cmd_table[] = {
1333 >  /* letter     function            need_oper need_admin */
1334 >  { 'a',        stats_dns_servers,      1,      1       },
1335 >  { 'A',        stats_dns_servers,      1,      1       },
1336 >  { 'c',        stats_connect,          1,      0       },
1337 >  { 'C',        stats_connect,          1,      0       },
1338 >  { 'd',        stats_tdeny,            1,      0       },
1339 >  { 'D',        stats_deny,             1,      0       },
1340 >  { 'e',        stats_exempt,           1,      0       },
1341 >  { 'E',        stats_events,           1,      1       },
1342 >  { 'f',        fd_dump,                1,      1       },
1343 >  { 'F',        fd_dump,                1,      1       },
1344 >  { 'g',        stats_pending_glines,   1,      0       },
1345 >  { 'G',        stats_glines,           1,      0       },
1346 >  { 'h',        stats_hooks,            1,      1       },
1347 >  { 'H',        stats_hubleaf,          1,      0       },
1348 >  { 'i',        stats_auth,             0,      0       },
1349 >  { 'I',        stats_auth,             0,      0       },
1350 >  { 'k',        stats_tklines,          0,      0       },
1351 >  { 'K',        stats_klines,           0,      0       },
1352 >  { 'l',        stats_ltrace,           1,      0       },
1353 >  { 'L',        stats_ltrace,           1,      0       },
1354 >  { 'm',        stats_messages,         0,      0       },
1355 >  { 'M',        stats_messages,         0,      0       },
1356 >  { 'o',        stats_oper,             0,      0       },
1357 >  { 'O',        stats_oper,             0,      0       },
1358 >  { 'p',        stats_operedup,         0,      0       },
1359 >  { 'P',        stats_ports,            0,      0       },
1360 >  { 'q',        stats_resv,             1,      0       },
1361 >  { 'Q',        stats_resv,             1,      0       },
1362 >  { 'r',        stats_usage,            1,      0       },
1363 >  { 'R',        stats_usage,            1,      0       },
1364 >  { 'S',        stats_service,          1,      0       },
1365 >  { 't',        stats_tstats,           1,      0       },
1366 >  { 'T',        stats_tstats,           1,      0       },
1367 >  { 'u',        stats_uptime,           0,      0       },
1368 >  { 'U',        stats_shared,           1,      0       },
1369 >  { 'v',        stats_servers,          1,      0       },
1370 >  { 'x',        stats_gecos,            1,      0       },
1371 >  { 'X',        stats_gecos,            1,      0       },
1372 >  { 'y',        stats_class,            1,      0       },
1373 >  { 'Y',        stats_class,            1,      0       },
1374 >  { 'z',        stats_memory,           1,      0       },
1375 >  { '?',        stats_servlinks,        0,      0       },
1376 >  { '\0',       NULL,                   0,      0       }
1377 > };
1378 >
1379 > static void
1380 > do_stats(struct Client *source_p, int parc, char *parv[])
1381 > {
1382 >  const struct StatsStruct *tab = stats_cmd_table;
1383 >  const char statchar = *parv[1];
1384 >
1385 >  if (statchar == '\0')
1386 >  {
1387 >    sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1388 >               from, to, '*');
1389 >    return;
1390 >  }
1391 >
1392 >  for (; tab->handler; ++tab)
1393 >  {
1394 >    if (tab->letter == statchar)
1395 >    {
1396 >      /* The stats table says what privs are needed, so check --fl_ */
1397 >      if ((tab->need_admin && !HasUMode(source_p, UMODE_ADMIN)) ||
1398 >          (tab->need_oper && !HasUMode(source_p, UMODE_OPER)))
1399 >      {
1400 >        sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1401 >                   from, to);
1402 >        break;
1403 >      }
1404 >
1405 >      sendto_realops_flags(UMODE_SPY, L_ALL,
1406 >                           "STATS %c requested by %s (%s@%s) [%s] on %s",
1407 >                           statchar, source_p->name, source_p->username,
1408 >                           source_p->host, source_p->servptr->name);
1409 >      tab->handler(source_p, parc, parv);
1410 >      break;
1411 >    }
1412 >  }
1413 >
1414 >  sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1415 >             from, to, statchar);
1416 > }
1417 >
1418 > /*
1419 > * m_stats()
1420 > *      parv[0] = sender prefix
1421 > *      parv[1] = stat letter/command
1422 > *      parv[2] = (if present) server/mask in stats L
1423   *
1424 + * This will search the tables for the appropriate stats letter/command,
1425 + * if found execute it.  
1426   */
1427 < static char *
1428 < parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1427 > static void
1428 > m_stats(struct Client *client_p, struct Client *source_p,
1429 >        int parc, char *parv[])
1430   {
1431 <  char *name;
1431 >  static time_t last_used = 0;
1432  
1433 <  if (parc > 2)
1433 >  /* Is the stats meant for us? */
1434 >  if (!ConfigFileEntry.disable_remote)
1435 >    if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1436 >                    parc, parv) != HUNTED_ISME)
1437 >      return;
1438 >
1439 >  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1440    {
1441 <    name = parv[2];
1441 >    from = me.id;
1442 >    to = source_p->id;
1443 >  }
1444 >  else
1445 >  {
1446 >    from = me.name;
1447 >    to = source_p->name;
1448 >  }
1449  
1450 <    if (!irccmp(name, from))
1451 <      *doall = 2;
1452 <    else if (match(name, from))
1453 <      *doall = 1;
1450 >  /* Check the user is actually allowed to do /stats, and isnt flooding */
1451 >  if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
1452 >  {
1453 >    sendto_one(source_p,form_str(RPL_LOAD2HI),
1454 >               from, to);
1455 >    return;
1456 >  }
1457  
1458 <    if (strchr(name, '*') ||
1459 <        strchr(name, '?'))
1460 <      *wilds = 1;
1458 >  last_used = CurrentTime;
1459 >
1460 >  do_stats(source_p, parc, parv);
1461 > }
1462  
1463 <    return(name);
1463 > /*
1464 > * mo_stats()
1465 > *      parv[0] = sender prefix
1466 > *      parv[1] = stat letter/command
1467 > *      parv[2] = (if present) server/mask in stats L, or target
1468 > *
1469 > * This will search the tables for the appropriate stats letter,
1470 > * if found execute it.  
1471 > */
1472 > static void
1473 > mo_stats(struct Client *client_p, struct Client *source_p,
1474 >         int parc, char *parv[])
1475 > {
1476 >  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1477 >                  parc, parv) != HUNTED_ISME)
1478 >     return;
1479 >
1480 >  if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1481 >  {
1482 >    from = me.id;
1483 >    to = source_p->id;
1484    }
1485    else
1486 <    return(NULL);
1486 >  {
1487 >    from = me.name;
1488 >    to = source_p->name;
1489 >  }
1490 >
1491 >  do_stats(source_p, parc, parv);
1492   }
1493 +
1494 + /*
1495 + * ms_stats - STATS message handler
1496 + *      parv[0] = sender prefix
1497 + *      parv[1] = statistics selector (defaults to Message frequency)
1498 + *      parv[2] = server name (current server defaulted, if omitted)
1499 + */
1500 + static void
1501 + ms_stats(struct Client *client_p, struct Client *source_p,
1502 +         int parc, char *parv[])
1503 + {
1504 +  if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1505 +                  parc, parv) != HUNTED_ISME)
1506 +    return;
1507 +
1508 +  if (IsClient(source_p))
1509 +    mo_stats(client_p, source_p, parc, parv);
1510 + }
1511 +
1512 + static struct Message stats_msgtab = {
1513 +  "STATS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
1514 +  { m_unregistered, m_stats, ms_stats, m_ignore, mo_stats, m_ignore }
1515 + };
1516 +
1517 + static void
1518 + module_init(void)
1519 + {
1520 +  mod_add_cmd(&stats_msgtab);
1521 + }
1522 +
1523 + static void
1524 + module_exit(void)
1525 + {
1526 +  mod_del_cmd(&stats_msgtab);
1527 + }
1528 +
1529 + struct module module_entry = {
1530 +  .node    = { NULL, NULL, NULL },
1531 +  .name    = NULL,
1532 +  .version = "$Revision$",
1533 +  .handle  = NULL,
1534 +  .modinit = module_init,
1535 +  .modexit = module_exit,
1536 +  .flags   = 0
1537 + };

Diff Legend

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