]>
Commit | Line | Data |
---|---|---|
212380e3 | 1 | /* |
2 | * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd). | |
3 | * m_stats.c: Sends the user statistics or config information. | |
4 | * | |
5 | * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center | |
6 | * Copyright (C) 1996-2002 Hybrid Development Team | |
7 | * Copyright (C) 2002-2005 ircd-ratbox development team | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
22 | * USA | |
23 | * | |
212380e3 | 24 | */ |
25 | ||
26 | #include "stdinc.h" | |
212380e3 | 27 | #include "class.h" /* report_classes */ |
28 | #include "client.h" /* Client */ | |
29 | #include "common.h" /* TRUE/FALSE */ | |
13ae2f4b | 30 | #include "match.h" |
212380e3 | 31 | #include "ircd.h" /* me */ |
32 | #include "listener.h" /* show_ports */ | |
212380e3 | 33 | #include "msg.h" /* Message */ |
34 | #include "hostmask.h" /* report_mtrie_conf_links */ | |
35 | #include "numeric.h" /* ERR_xxx */ | |
36 | #include "scache.h" /* list_scache */ | |
37 | #include "send.h" /* sendto_one */ | |
212380e3 | 38 | #include "s_conf.h" /* ConfItem */ |
39 | #include "s_serv.h" /* hunt_server */ | |
83251205 | 40 | #include "s_stats.h" |
212380e3 | 41 | #include "s_user.h" /* show_opers */ |
212380e3 | 42 | #include "blacklist.h" /* dnsbl stuff */ |
212380e3 | 43 | #include "parse.h" |
44 | #include "modules.h" | |
45 | #include "hook.h" | |
46 | #include "s_newconf.h" | |
47 | #include "hash.h" | |
83251205 VY |
48 | #include "reject.h" |
49 | #include "whowas.h" | |
212380e3 | 50 | |
51 | static int m_stats (struct Client *, struct Client *, int, const char **); | |
52 | ||
53 | struct Message stats_msgtab = { | |
54 | "STATS", 0, 0, 0, MFLG_SLOW, | |
55 | {mg_unreg, {m_stats, 2}, {m_stats, 3}, mg_ignore, mg_ignore, {m_stats, 2}} | |
56 | }; | |
57 | ||
58 | int doing_stats_hook; | |
59 | int doing_stats_p_hook; | |
60 | ||
61 | mapi_clist_av1 stats_clist[] = { &stats_msgtab, NULL }; | |
62 | mapi_hlist_av1 stats_hlist[] = { | |
63 | { "doing_stats", &doing_stats_hook }, | |
64 | { "doing_stats_p", &doing_stats_p_hook }, | |
65 | { NULL, NULL } | |
66 | }; | |
67 | ||
68 | DECLARE_MODULE_AV1(stats, NULL, NULL, stats_clist, stats_hlist, NULL, "$Revision: 1608 $"); | |
69 | ||
70 | const char *Lformat = "%s %u %u %u %u %u :%u %u %s"; | |
71 | ||
08d11e34 | 72 | static void stats_l_list(struct Client *s, const char *, int, int, rb_dlink_list *, char); |
212380e3 | 73 | static void stats_l_client(struct Client *source_p, struct Client *target_p, |
74 | char statchar); | |
75 | ||
76 | static void stats_spy(struct Client *, char, const char *); | |
77 | static void stats_p_spy(struct Client *); | |
78 | ||
79 | /* Heres our struct for the stats table */ | |
80 | struct StatsStruct | |
81 | { | |
82 | char letter; | |
4a4ea261 | 83 | void (*handler) (struct Client *source_p); |
212380e3 | 84 | int need_oper; |
85 | int need_admin; | |
86 | }; | |
87 | ||
4a4ea261 | 88 | static void stats_dns_servers(struct Client *); |
212380e3 | 89 | static void stats_delay(struct Client *); |
90 | static void stats_hash(struct Client *); | |
91 | static void stats_connect(struct Client *); | |
92 | static void stats_tdeny(struct Client *); | |
93 | static void stats_deny(struct Client *); | |
94 | static void stats_exempt(struct Client *); | |
95 | static void stats_events(struct Client *); | |
20eef930 | 96 | static void stats_prop_klines(struct Client *); |
212380e3 | 97 | static void stats_hubleaf(struct Client *); |
98 | static void stats_auth(struct Client *); | |
99 | static void stats_tklines(struct Client *); | |
100 | static void stats_klines(struct Client *); | |
101 | static void stats_messages(struct Client *); | |
102 | static void stats_dnsbl(struct Client *); | |
103 | static void stats_oper(struct Client *); | |
3619e299 | 104 | static void stats_privset(struct Client *); |
212380e3 | 105 | static void stats_operedup(struct Client *); |
106 | static void stats_ports(struct Client *); | |
107 | static void stats_tresv(struct Client *); | |
108 | static void stats_resv(struct Client *); | |
109 | static void stats_usage(struct Client *); | |
110 | static void stats_tstats(struct Client *); | |
111 | static void stats_uptime(struct Client *); | |
112 | static void stats_shared(struct Client *); | |
113 | static void stats_servers(struct Client *); | |
114 | static void stats_tgecos(struct Client *); | |
115 | static void stats_gecos(struct Client *); | |
116 | static void stats_class(struct Client *); | |
117 | static void stats_memory(struct Client *); | |
118 | static void stats_servlinks(struct Client *); | |
119 | static void stats_ltrace(struct Client *, int, const char **); | |
120 | static void stats_ziplinks(struct Client *); | |
b8127271 | 121 | static void stats_comm(struct Client *); |
212380e3 | 122 | /* This table contains the possible stats items, in order: |
123 | * stats letter, function to call, operonly? adminonly? | |
124 | * case only matters in the stats letter column.. -- fl_ | |
125 | */ | |
126 | static struct StatsStruct stats_cmd_table[] = { | |
127 | /* letter function need_oper need_admin */ | |
128 | {'a', stats_dns_servers, 1, 1, }, | |
129 | {'A', stats_dns_servers, 1, 1, }, | |
130 | {'b', stats_delay, 1, 1, }, | |
131 | {'B', stats_hash, 1, 1, }, | |
132 | {'c', stats_connect, 0, 0, }, | |
133 | {'C', stats_connect, 0, 0, }, | |
134 | {'d', stats_tdeny, 1, 0, }, | |
135 | {'D', stats_deny, 1, 0, }, | |
136 | {'e', stats_exempt, 1, 0, }, | |
137 | {'E', stats_events, 1, 1, }, | |
b8127271 VY |
138 | {'f', stats_comm, 1, 1, }, |
139 | {'F', stats_comm, 1, 1, }, | |
20eef930 | 140 | {'g', stats_prop_klines, 1, 0, }, |
212380e3 | 141 | {'h', stats_hubleaf, 0, 0, }, |
142 | {'H', stats_hubleaf, 0, 0, }, | |
143 | {'i', stats_auth, 0, 0, }, | |
144 | {'I', stats_auth, 0, 0, }, | |
145 | {'k', stats_tklines, 0, 0, }, | |
146 | {'K', stats_klines, 0, 0, }, | |
4a4ea261 JT |
147 | {'l', NULL /* special */, 0, 0, }, |
148 | {'L', NULL /* special */, 0, 0, }, | |
212380e3 | 149 | {'m', stats_messages, 0, 0, }, |
150 | {'M', stats_messages, 0, 0, }, | |
151 | {'n', stats_dnsbl, 0, 0, }, | |
152 | {'o', stats_oper, 0, 0, }, | |
3619e299 | 153 | {'O', stats_privset, 1, 0, }, |
212380e3 | 154 | {'p', stats_operedup, 0, 0, }, |
155 | {'P', stats_ports, 0, 0, }, | |
156 | {'q', stats_tresv, 1, 0, }, | |
157 | {'Q', stats_resv, 1, 0, }, | |
158 | {'r', stats_usage, 1, 0, }, | |
159 | {'R', stats_usage, 1, 0, }, | |
160 | {'t', stats_tstats, 1, 0, }, | |
161 | {'T', stats_tstats, 1, 0, }, | |
162 | {'u', stats_uptime, 0, 0, }, | |
163 | {'U', stats_shared, 1, 0, }, | |
164 | {'v', stats_servers, 0, 0, }, | |
165 | {'V', stats_servers, 0, 0, }, | |
166 | {'x', stats_tgecos, 1, 0, }, | |
167 | {'X', stats_gecos, 1, 0, }, | |
168 | {'y', stats_class, 0, 0, }, | |
169 | {'Y', stats_class, 0, 0, }, | |
170 | {'z', stats_memory, 1, 0, }, | |
171 | {'Z', stats_ziplinks, 1, 0, }, | |
172 | {'?', stats_servlinks, 0, 0, }, | |
173 | {(char) 0, (void (*)()) 0, 0, 0, } | |
174 | }; | |
175 | ||
176 | /* | |
177 | * m_stats by fl_ | |
212380e3 | 178 | * parv[1] = stat letter/command |
179 | * parv[2] = (if present) server/mask in stats L, or target | |
180 | * | |
181 | * This will search the tables for the appropriate stats letter, | |
182 | * if found execute it. | |
183 | */ | |
184 | static int | |
185 | m_stats(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) | |
186 | { | |
187 | static time_t last_used = 0; | |
188 | int i; | |
189 | char statchar; | |
190 | ||
191 | statchar = parv[1][0]; | |
192 | ||
193 | if(MyClient(source_p) && !IsOper(source_p)) | |
194 | { | |
195 | /* Check the user is actually allowed to do /stats, and isnt flooding */ | |
9f6bbe3c | 196 | if((last_used + ConfigFileEntry.pace_wait) > rb_current_time()) |
212380e3 | 197 | { |
198 | /* safe enough to give this on a local connect only */ | |
199 | sendto_one(source_p, form_str(RPL_LOAD2HI), | |
200 | me.name, source_p->name, "STATS"); | |
201 | sendto_one_numeric(source_p, RPL_ENDOFSTATS, | |
202 | form_str(RPL_ENDOFSTATS), statchar); | |
203 | return 0; | |
204 | } | |
205 | else | |
9f6bbe3c | 206 | last_used = rb_current_time(); |
212380e3 | 207 | } |
208 | ||
209 | if(hunt_server (client_p, source_p, ":%s STATS %s :%s", 2, parc, parv) != HUNTED_ISME) | |
210 | return 0; | |
211 | ||
212 | if((statchar != 'L') && (statchar != 'l')) | |
213 | stats_spy(source_p, statchar, NULL); | |
214 | ||
4a4ea261 | 215 | for (i = 0; stats_cmd_table[i].letter; i++) |
212380e3 | 216 | { |
217 | if(stats_cmd_table[i].letter == statchar) | |
218 | { | |
219 | /* The stats table says what privs are needed, so check --fl_ */ | |
220 | /* Called for remote clients and for local opers, so check need_admin | |
221 | * and need_oper | |
222 | */ | |
ff74c93a | 223 | if(stats_cmd_table[i].need_oper && !IsOper(source_p)) |
212380e3 | 224 | { |
225 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
226 | form_str (ERR_NOPRIVILEGES)); | |
227 | break; | |
228 | } | |
ff74c93a JT |
229 | if(stats_cmd_table[i].need_admin && !IsOperAdmin(source_p)) |
230 | { | |
231 | sendto_one(source_p, form_str(ERR_NOPRIVS), | |
232 | me.name, source_p->name, "admin"); | |
233 | break; | |
234 | } | |
212380e3 | 235 | |
236 | /* Blah, stats L needs the parameters, none of the others do.. */ | |
237 | if(statchar == 'L' || statchar == 'l') | |
4a4ea261 | 238 | stats_ltrace (source_p, parc, parv); |
212380e3 | 239 | else |
240 | stats_cmd_table[i].handler (source_p); | |
241 | } | |
242 | } | |
243 | ||
244 | /* Send the end of stats notice, and the stats_spy */ | |
245 | sendto_one_numeric(source_p, RPL_ENDOFSTATS, | |
246 | form_str(RPL_ENDOFSTATS), statchar); | |
247 | ||
248 | return 0; | |
249 | } | |
250 | ||
251 | static void | |
252 | stats_dns_servers (struct Client *source_p) | |
253 | { | |
254 | report_dns_servers (source_p); | |
255 | } | |
256 | ||
257 | static void | |
258 | stats_delay(struct Client *source_p) | |
259 | { | |
260 | struct nd_entry *nd; | |
b37021a4 | 261 | struct DictionaryIter iter; |
212380e3 | 262 | |
b37021a4 | 263 | DICTIONARY_FOREACH(nd, &iter, nd_dict) |
212380e3 | 264 | { |
d1264ac8 | 265 | sendto_one_notice(source_p, ":Delaying: %s for %ld", |
212380e3 | 266 | nd->name, (long) nd->expire); |
267 | } | |
212380e3 | 268 | } |
269 | ||
270 | static void | |
271 | stats_hash(struct Client *source_p) | |
272 | { | |
273 | hash_stats(source_p); | |
274 | } | |
275 | ||
276 | static void | |
277 | stats_connect(struct Client *source_p) | |
278 | { | |
279 | static char buf[5]; | |
280 | struct server_conf *server_p; | |
281 | char *s; | |
08d11e34 | 282 | rb_dlink_node *ptr; |
212380e3 | 283 | |
284 | if((ConfigFileEntry.stats_c_oper_only || | |
285 | (ConfigServerHide.flatten_links && !IsExemptShide(source_p))) && | |
286 | !IsOper(source_p)) | |
287 | { | |
288 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
289 | form_str(ERR_NOPRIVILEGES)); | |
290 | return; | |
291 | } | |
292 | ||
08d11e34 | 293 | RB_DLINK_FOREACH(ptr, server_conf_list.head) |
212380e3 | 294 | { |
295 | server_p = ptr->data; | |
296 | ||
297 | if(ServerConfIllegal(server_p)) | |
298 | continue; | |
299 | ||
300 | buf[0] = '\0'; | |
301 | s = buf; | |
302 | ||
303 | if(IsOper(source_p)) | |
304 | { | |
305 | if(ServerConfAutoconn(server_p)) | |
306 | *s++ = 'A'; | |
b717a466 | 307 | if(ServerConfSSL(server_p)) |
92b89763 | 308 | *s++ = 'S'; |
212380e3 | 309 | if(ServerConfTb(server_p)) |
310 | *s++ = 'T'; | |
311 | if(ServerConfCompressed(server_p)) | |
312 | *s++ = 'Z'; | |
313 | } | |
314 | ||
315 | if(!buf[0]) | |
316 | *s++ = '*'; | |
317 | ||
318 | *s = '\0'; | |
319 | ||
320 | sendto_one_numeric(source_p, RPL_STATSCLINE, | |
321 | form_str(RPL_STATSCLINE), | |
212380e3 | 322 | "*@127.0.0.1", |
212380e3 | 323 | buf, server_p->name, |
324 | server_p->port, server_p->class_name); | |
325 | } | |
326 | } | |
327 | ||
328 | /* stats_tdeny() | |
329 | * | |
330 | * input - client to report to | |
331 | * output - none | |
332 | * side effects - client is given temp dline list. | |
333 | */ | |
334 | static void | |
335 | stats_tdeny (struct Client *source_p) | |
336 | { | |
337 | char *host, *pass, *user, *oper_reason; | |
338 | struct AddressRec *arec; | |
339 | struct ConfItem *aconf; | |
340 | int i; | |
341 | ||
342 | for (i = 0; i < ATABLE_SIZE; i++) | |
343 | { | |
344 | for (arec = atable[i]; arec; arec = arec->next) | |
345 | { | |
346 | if(arec->type == CONF_DLINE) | |
347 | { | |
348 | aconf = arec->aconf; | |
349 | ||
350 | if(!(aconf->flags & CONF_FLAGS_TEMPORARY)) | |
351 | continue; | |
352 | ||
353 | get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason); | |
354 | ||
355 | sendto_one_numeric(source_p, RPL_STATSDLINE, | |
356 | form_str (RPL_STATSDLINE), | |
357 | 'd', host, pass, | |
358 | oper_reason ? "|" : "", | |
359 | oper_reason ? oper_reason : ""); | |
360 | } | |
361 | } | |
362 | } | |
363 | } | |
364 | ||
365 | /* stats_deny() | |
366 | * | |
367 | * input - client to report to | |
368 | * output - none | |
369 | * side effects - client is given dline list. | |
370 | */ | |
371 | static void | |
372 | stats_deny (struct Client *source_p) | |
373 | { | |
374 | char *host, *pass, *user, *oper_reason; | |
375 | struct AddressRec *arec; | |
376 | struct ConfItem *aconf; | |
377 | int i; | |
378 | ||
379 | for (i = 0; i < ATABLE_SIZE; i++) | |
380 | { | |
381 | for (arec = atable[i]; arec; arec = arec->next) | |
382 | { | |
383 | if(arec->type == CONF_DLINE) | |
384 | { | |
385 | aconf = arec->aconf; | |
386 | ||
387 | if(aconf->flags & CONF_FLAGS_TEMPORARY) | |
388 | continue; | |
389 | ||
390 | get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason); | |
391 | ||
392 | sendto_one_numeric(source_p, RPL_STATSDLINE, | |
393 | form_str (RPL_STATSDLINE), | |
394 | 'D', host, pass, | |
395 | oper_reason ? "|" : "", | |
396 | oper_reason ? oper_reason : ""); | |
397 | } | |
398 | } | |
399 | } | |
400 | } | |
401 | ||
402 | ||
403 | /* stats_exempt() | |
404 | * | |
405 | * input - client to report to | |
406 | * output - none | |
407 | * side effects - client is given list of exempt blocks | |
408 | */ | |
409 | static void | |
410 | stats_exempt(struct Client *source_p) | |
411 | { | |
412 | char *name, *host, *pass, *user, *classname; | |
413 | struct AddressRec *arec; | |
414 | struct ConfItem *aconf; | |
415 | int i, port; | |
416 | ||
417 | if(ConfigFileEntry.stats_e_disabled) | |
418 | { | |
889b0321 JT |
419 | sendto_one_numeric(source_p, ERR_DISABLED, |
420 | form_str(ERR_DISABLED), "STATS e"); | |
212380e3 | 421 | return; |
422 | } | |
423 | ||
424 | for (i = 0; i < ATABLE_SIZE; i++) | |
425 | { | |
426 | for (arec = atable[i]; arec; arec = arec->next) | |
427 | { | |
428 | if(arec->type == CONF_EXEMPTDLINE) | |
429 | { | |
430 | aconf = arec->aconf; | |
431 | get_printable_conf (aconf, &name, &host, &pass, | |
432 | &user, &port, &classname); | |
433 | ||
434 | sendto_one_numeric(source_p, RPL_STATSDLINE, | |
435 | form_str(RPL_STATSDLINE), | |
436 | 'e', host, pass, "", ""); | |
437 | } | |
438 | } | |
439 | }} | |
440 | ||
441 | ||
9df69d5b JT |
442 | static void |
443 | stats_events_cb(char *str, void *ptr) | |
444 | { | |
445 | sendto_one_numeric(ptr, RPL_STATSDEBUG, "E :%s", str); | |
446 | } | |
447 | ||
448 | static void | |
449 | stats_events (struct Client *source_p) | |
450 | { | |
451 | rb_dump_events(stats_events_cb, source_p); | |
212380e3 | 452 | } |
453 | ||
20eef930 JT |
454 | static void |
455 | stats_prop_klines(struct Client *source_p) | |
456 | { | |
457 | struct ConfItem *aconf; | |
458 | rb_dlink_node *ptr; | |
459 | char *user, *host, *pass, *oper_reason; | |
460 | ||
461 | RB_DLINK_FOREACH(ptr, prop_bans.head) | |
462 | { | |
463 | aconf = ptr->data; | |
464 | ||
465 | /* Skip non-klines and deactivated klines. */ | |
466 | if(aconf->status != CONF_KILL) | |
467 | continue; | |
468 | ||
469 | get_printable_kline(source_p, aconf, &host, &pass, | |
470 | &user, &oper_reason); | |
471 | ||
472 | sendto_one_numeric(source_p, RPL_STATSKLINE, | |
473 | form_str(RPL_STATSKLINE), | |
474 | 'g', host, user, pass, | |
475 | oper_reason ? "|" : "", | |
476 | oper_reason ? oper_reason : ""); | |
477 | } | |
478 | } | |
479 | ||
212380e3 | 480 | static void |
481 | stats_hubleaf(struct Client *source_p) | |
482 | { | |
483 | struct remote_conf *hub_p; | |
08d11e34 | 484 | rb_dlink_node *ptr; |
212380e3 | 485 | |
486 | if((ConfigFileEntry.stats_h_oper_only || | |
487 | (ConfigServerHide.flatten_links && !IsExemptShide(source_p))) && | |
488 | !IsOper(source_p)) | |
489 | { | |
490 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
491 | form_str (ERR_NOPRIVILEGES)); | |
492 | return; | |
493 | } | |
494 | ||
08d11e34 | 495 | RB_DLINK_FOREACH(ptr, hubleaf_conf_list.head) |
212380e3 | 496 | { |
497 | hub_p = ptr->data; | |
498 | ||
499 | if(hub_p->flags & CONF_HUB) | |
500 | sendto_one_numeric(source_p, RPL_STATSHLINE, | |
501 | form_str(RPL_STATSHLINE), | |
502 | hub_p->host, hub_p->server); | |
503 | else | |
504 | sendto_one_numeric(source_p, RPL_STATSLLINE, | |
505 | form_str(RPL_STATSLLINE), | |
506 | hub_p->host, hub_p->server); | |
507 | } | |
508 | } | |
509 | ||
510 | ||
511 | static void | |
512 | stats_auth (struct Client *source_p) | |
513 | { | |
514 | /* Oper only, if unopered, return ERR_NOPRIVS */ | |
515 | if((ConfigFileEntry.stats_i_oper_only == 2) && !IsOper (source_p)) | |
516 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
517 | form_str (ERR_NOPRIVILEGES)); | |
518 | ||
519 | /* If unopered, Only return matching auth blocks */ | |
520 | else if((ConfigFileEntry.stats_i_oper_only == 1) && !IsOper (source_p)) | |
521 | { | |
522 | struct ConfItem *aconf; | |
969a1ae6 | 523 | char *name, *host, *pass = "*", *user, *classname; |
212380e3 | 524 | int port; |
525 | ||
526 | if(MyConnect (source_p)) | |
527 | aconf = find_conf_by_address (source_p->host, source_p->sockhost, NULL, | |
528 | (struct sockaddr *)&source_p->localClient->ip, | |
529 | CONF_CLIENT, | |
530 | source_p->localClient->ip.ss_family, | |
969a1ae6 | 531 | source_p->username, NULL); |
212380e3 | 532 | else |
533 | aconf = find_conf_by_address (source_p->host, NULL, NULL, NULL, CONF_CLIENT, | |
969a1ae6 | 534 | 0, source_p->username, NULL); |
212380e3 | 535 | |
536 | if(aconf == NULL) | |
537 | return; | |
538 | ||
539 | get_printable_conf (aconf, &name, &host, &pass, &user, &port, &classname); | |
969a1ae6 VY |
540 | if(!EmptyString(aconf->spasswd)) |
541 | pass = aconf->spasswd; | |
212380e3 | 542 | |
543 | sendto_one_numeric(source_p, RPL_STATSILINE, form_str(RPL_STATSILINE), | |
969a1ae6 | 544 | name, pass, show_iline_prefix(source_p, aconf, user), |
212380e3 | 545 | host, port, classname); |
546 | } | |
547 | ||
548 | /* Theyre opered, or allowed to see all auth blocks */ | |
549 | else | |
550 | report_auth (source_p); | |
551 | } | |
552 | ||
553 | ||
554 | static void | |
555 | stats_tklines(struct Client *source_p) | |
556 | { | |
557 | /* Oper only, if unopered, return ERR_NOPRIVS */ | |
558 | if((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper (source_p)) | |
559 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
560 | form_str (ERR_NOPRIVILEGES)); | |
561 | ||
562 | /* If unopered, Only return matching klines */ | |
563 | else if((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper (source_p)) | |
564 | { | |
565 | struct ConfItem *aconf; | |
566 | char *host, *pass, *user, *oper_reason; | |
567 | ||
568 | if(MyConnect (source_p)) | |
569 | aconf = find_conf_by_address (source_p->host, source_p->sockhost, NULL, | |
570 | (struct sockaddr *)&source_p->localClient->ip, | |
571 | CONF_KILL, | |
572 | source_p->localClient->ip.ss_family, | |
969a1ae6 | 573 | source_p->username, NULL); |
212380e3 | 574 | else |
575 | aconf = find_conf_by_address (source_p->host, NULL, NULL, NULL, CONF_KILL, | |
969a1ae6 | 576 | 0, source_p->username, NULL); |
212380e3 | 577 | |
578 | if(aconf == NULL) | |
579 | return; | |
580 | ||
581 | /* dont report a permanent kline as a tkline */ | |
582 | if((aconf->flags & CONF_FLAGS_TEMPORARY) == 0) | |
583 | return; | |
584 | ||
585 | get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason); | |
586 | ||
587 | sendto_one_numeric(source_p, RPL_STATSKLINE, | |
8eee9ee1 JT |
588 | form_str(RPL_STATSKLINE), aconf->flags & CONF_FLAGS_TEMPORARY ? 'k' : 'K', |
589 | host, user, pass, oper_reason ? "|" : "", | |
212380e3 | 590 | oper_reason ? oper_reason : ""); |
591 | } | |
592 | /* Theyre opered, or allowed to see all klines */ | |
593 | else | |
594 | { | |
595 | struct ConfItem *aconf; | |
08d11e34 | 596 | rb_dlink_node *ptr; |
212380e3 | 597 | int i; |
598 | char *user, *host, *pass, *oper_reason; | |
599 | ||
600 | for(i = 0; i < LAST_TEMP_TYPE; i++) | |
601 | { | |
08d11e34 | 602 | RB_DLINK_FOREACH(ptr, temp_klines[i].head) |
212380e3 | 603 | { |
604 | aconf = ptr->data; | |
605 | ||
606 | get_printable_kline(source_p, aconf, &host, &pass, | |
607 | &user, &oper_reason); | |
608 | ||
609 | sendto_one_numeric(source_p, RPL_STATSKLINE, | |
610 | form_str(RPL_STATSKLINE), | |
611 | 'k', host, user, pass, | |
612 | oper_reason ? "|" : "", | |
613 | oper_reason ? oper_reason : ""); | |
614 | } | |
615 | } | |
616 | } | |
617 | } | |
618 | ||
619 | static void | |
620 | stats_klines(struct Client *source_p) | |
621 | { | |
622 | /* Oper only, if unopered, return ERR_NOPRIVS */ | |
623 | if((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper (source_p)) | |
624 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
625 | form_str (ERR_NOPRIVILEGES)); | |
626 | ||
627 | /* If unopered, Only return matching klines */ | |
628 | else if((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper (source_p)) | |
629 | { | |
630 | struct ConfItem *aconf; | |
631 | char *host, *pass, *user, *oper_reason; | |
632 | ||
633 | /* search for a kline */ | |
634 | if(MyConnect (source_p)) | |
635 | aconf = find_conf_by_address (source_p->host, source_p->sockhost, NULL, | |
636 | (struct sockaddr *)&source_p->localClient->ip, | |
637 | CONF_KILL, | |
638 | source_p->localClient->ip.ss_family, | |
969a1ae6 | 639 | source_p->username, NULL); |
212380e3 | 640 | else |
641 | aconf = find_conf_by_address (source_p->host, NULL, NULL, NULL, CONF_KILL, | |
969a1ae6 | 642 | 0, source_p->username, NULL); |
212380e3 | 643 | |
644 | if(aconf == NULL) | |
645 | return; | |
646 | ||
212380e3 | 647 | get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason); |
648 | ||
649 | sendto_one_numeric(source_p, RPL_STATSKLINE, form_str(RPL_STATSKLINE), | |
8eee9ee1 JT |
650 | aconf->flags & CONF_FLAGS_TEMPORARY ? 'k' : 'K', |
651 | host, user, pass, oper_reason ? "|" : "", | |
212380e3 | 652 | oper_reason ? oper_reason : ""); |
653 | } | |
654 | /* Theyre opered, or allowed to see all klines */ | |
655 | else | |
656 | report_Klines (source_p); | |
657 | } | |
658 | ||
659 | static void | |
660 | stats_messages(struct Client *source_p) | |
661 | { | |
662 | report_messages(source_p); | |
663 | } | |
664 | ||
665 | static void | |
666 | stats_dnsbl(struct Client *source_p) | |
667 | { | |
08d11e34 | 668 | rb_dlink_node *ptr; |
212380e3 | 669 | struct Blacklist *blptr; |
670 | ||
08d11e34 | 671 | RB_DLINK_FOREACH(ptr, blacklist_list.head) |
212380e3 | 672 | { |
673 | blptr = ptr->data; | |
674 | ||
675 | /* use RPL_STATSDEBUG for now -- jilles */ | |
676 | sendto_one_numeric(source_p, RPL_STATSDEBUG, "n :%d %s %s (%d)", | |
677 | blptr->hits, | |
678 | blptr->host, | |
679 | blptr->status & CONF_ILLEGAL ? "disabled" : "active", | |
680 | blptr->refcount); | |
681 | } | |
682 | } | |
683 | ||
684 | static void | |
685 | stats_oper(struct Client *source_p) | |
686 | { | |
687 | struct oper_conf *oper_p; | |
08d11e34 | 688 | rb_dlink_node *ptr; |
212380e3 | 689 | |
690 | if(!IsOper(source_p) && ConfigFileEntry.stats_o_oper_only) | |
691 | { | |
692 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
693 | form_str (ERR_NOPRIVILEGES)); | |
694 | return; | |
695 | } | |
696 | ||
08d11e34 | 697 | RB_DLINK_FOREACH(ptr, oper_conf_list.head) |
212380e3 | 698 | { |
699 | oper_p = ptr->data; | |
700 | ||
701 | sendto_one_numeric(source_p, RPL_STATSOLINE, | |
702 | form_str(RPL_STATSOLINE), | |
703 | oper_p->username, oper_p->host, oper_p->name, | |
e2d7f731 | 704 | IsOper(source_p) ? oper_p->privset->name : "0", "-1"); |
212380e3 | 705 | } |
706 | } | |
707 | ||
3619e299 JT |
708 | static void |
709 | stats_privset(struct Client *source_p) | |
710 | { | |
711 | privilegeset_report(source_p); | |
712 | } | |
212380e3 | 713 | |
714 | /* stats_operedup() | |
715 | * | |
716 | * input - client pointer | |
717 | * output - none | |
718 | * side effects - client is shown a list of active opers | |
719 | */ | |
720 | static void | |
721 | stats_operedup (struct Client *source_p) | |
722 | { | |
723 | struct Client *target_p; | |
08d11e34 | 724 | rb_dlink_node *oper_ptr; |
212380e3 | 725 | unsigned int count = 0; |
726 | ||
08d11e34 | 727 | RB_DLINK_FOREACH (oper_ptr, oper_list.head) |
212380e3 | 728 | { |
729 | target_p = oper_ptr->data; | |
730 | ||
731 | if(IsOperInvis(target_p) && !IsOper(source_p)) | |
732 | continue; | |
733 | ||
c387fc41 | 734 | if(target_p->user->away) |
212380e3 | 735 | continue; |
736 | ||
737 | count++; | |
738 | ||
739 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
740 | "p :%s (%s@%s)", | |
741 | target_p->name, target_p->username, | |
742 | target_p->host); | |
743 | } | |
744 | ||
745 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
746 | "p :%u staff members", count); | |
747 | ||
748 | stats_p_spy (source_p); | |
749 | } | |
750 | ||
751 | static void | |
752 | stats_ports (struct Client *source_p) | |
753 | { | |
754 | if(!IsOper (source_p) && ConfigFileEntry.stats_P_oper_only) | |
755 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
756 | form_str (ERR_NOPRIVILEGES)); | |
757 | else | |
758 | show_ports (source_p); | |
759 | } | |
760 | ||
761 | static void | |
762 | stats_tresv(struct Client *source_p) | |
763 | { | |
764 | struct ConfItem *aconf; | |
08d11e34 | 765 | rb_dlink_node *ptr; |
212380e3 | 766 | int i; |
767 | ||
08d11e34 | 768 | RB_DLINK_FOREACH(ptr, resv_conf_list.head) |
212380e3 | 769 | { |
770 | aconf = ptr->data; | |
771 | if(aconf->hold) | |
772 | sendto_one_numeric(source_p, RPL_STATSQLINE, | |
773 | form_str(RPL_STATSQLINE), | |
70c6c150 | 774 | 'q', aconf->port, aconf->host, aconf->passwd); |
212380e3 | 775 | } |
776 | ||
777 | HASH_WALK(i, R_MAX, ptr, resvTable) | |
778 | { | |
779 | aconf = ptr->data; | |
780 | if(aconf->hold) | |
781 | sendto_one_numeric(source_p, RPL_STATSQLINE, | |
782 | form_str(RPL_STATSQLINE), | |
70c6c150 | 783 | 'q', aconf->port, aconf->host, aconf->passwd); |
212380e3 | 784 | } |
785 | HASH_WALK_END | |
786 | } | |
787 | ||
788 | ||
789 | static void | |
790 | stats_resv(struct Client *source_p) | |
791 | { | |
792 | struct ConfItem *aconf; | |
08d11e34 | 793 | rb_dlink_node *ptr; |
212380e3 | 794 | int i; |
795 | ||
08d11e34 | 796 | RB_DLINK_FOREACH(ptr, resv_conf_list.head) |
212380e3 | 797 | { |
798 | aconf = ptr->data; | |
799 | if(!aconf->hold) | |
800 | sendto_one_numeric(source_p, RPL_STATSQLINE, | |
801 | form_str(RPL_STATSQLINE), | |
ff0482a9 | 802 | 'Q', aconf->port, aconf->host, aconf->passwd); |
212380e3 | 803 | } |
804 | ||
805 | HASH_WALK(i, R_MAX, ptr, resvTable) | |
806 | { | |
807 | aconf = ptr->data; | |
808 | if(!aconf->hold) | |
809 | sendto_one_numeric(source_p, RPL_STATSQLINE, | |
810 | form_str(RPL_STATSQLINE), | |
ff0482a9 | 811 | 'Q', aconf->port, aconf->host, aconf->passwd); |
212380e3 | 812 | } |
813 | HASH_WALK_END | |
814 | } | |
815 | ||
816 | static void | |
817 | stats_usage (struct Client *source_p) | |
818 | { | |
819 | struct rusage rus; | |
820 | time_t secs; | |
821 | time_t rup; | |
822 | #ifdef hz | |
823 | # define hzz hz | |
824 | #else | |
825 | # ifdef HZ | |
826 | # define hzz HZ | |
827 | # else | |
828 | int hzz = 1; | |
829 | # endif | |
830 | #endif | |
831 | ||
832 | if(getrusage(RUSAGE_SELF, &rus) == -1) | |
833 | { | |
834 | sendto_one_notice(source_p, ":Getruseage error: %s.", | |
835 | strerror(errno)); | |
836 | return; | |
837 | } | |
838 | secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec; | |
839 | if(0 == secs) | |
840 | secs = 1; | |
841 | ||
9f6bbe3c | 842 | rup = (rb_current_time() - startup_time) * hzz; |
212380e3 | 843 | if(0 == rup) |
844 | rup = 1; | |
845 | ||
846 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
847 | "R :CPU Secs %d:%d User %d:%d System %d:%d", | |
848 | (int) (secs / 60), (int) (secs % 60), | |
849 | (int) (rus.ru_utime.tv_sec / 60), | |
850 | (int) (rus.ru_utime.tv_sec % 60), | |
851 | (int) (rus.ru_stime.tv_sec / 60), | |
852 | (int) (rus.ru_stime.tv_sec % 60)); | |
853 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
854 | "R :RSS %ld ShMem %ld Data %ld Stack %ld", | |
855 | rus.ru_maxrss, (rus.ru_ixrss / rup), | |
856 | (rus.ru_idrss / rup), (rus.ru_isrss / rup)); | |
857 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
858 | "R :Swaps %d Reclaims %d Faults %d", | |
859 | (int) rus.ru_nswap, (int) rus.ru_minflt, (int) rus.ru_majflt); | |
860 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
861 | "R :Block in %d out %d", | |
862 | (int) rus.ru_inblock, (int) rus.ru_oublock); | |
863 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
864 | "R :Msg Rcv %d Send %d", | |
865 | (int) rus.ru_msgrcv, (int) rus.ru_msgsnd); | |
866 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
867 | "R :Signals %d Context Vol. %d Invol %d", | |
868 | (int) rus.ru_nsignals, (int) rus.ru_nvcsw, | |
869 | (int) rus.ru_nivcsw); | |
870 | } | |
871 | ||
21c9d815 VY |
872 | static void |
873 | stats_tstats (struct Client *source_p) | |
874 | { | |
83251205 VY |
875 | struct Client *target_p; |
876 | struct ServerStatistics sp; | |
877 | rb_dlink_node *ptr; | |
878 | ||
879 | memcpy(&sp, &ServerStats, sizeof(struct ServerStatistics)); | |
880 | ||
b717a466 JT |
881 | RB_DLINK_FOREACH(ptr, serv_list.head) |
882 | { | |
883 | target_p = ptr->data; | |
884 | ||
885 | sp.is_sbs += target_p->localClient->sendB; | |
886 | sp.is_sbr += target_p->localClient->receiveB; | |
17d00839 | 887 | sp.is_sti += (unsigned long long)(rb_current_time() - target_p->localClient->firsttime); |
b717a466 JT |
888 | sp.is_sv++; |
889 | } | |
890 | ||
891 | RB_DLINK_FOREACH(ptr, lclient_list.head) | |
892 | { | |
893 | target_p = ptr->data; | |
894 | ||
895 | sp.is_cbs += target_p->localClient->sendB; | |
896 | sp.is_cbr += target_p->localClient->receiveB; | |
17d00839 | 897 | sp.is_cti += (unsigned long long)(rb_current_time() - target_p->localClient->firsttime); |
b717a466 | 898 | sp.is_cl++; |
83251205 VY |
899 | } |
900 | ||
901 | RB_DLINK_FOREACH(ptr, unknown_list.head) | |
902 | { | |
903 | sp.is_ni++; | |
904 | } | |
905 | ||
906 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
907 | "T :accepts %u refused %u", sp.is_ac, sp.is_ref); | |
908 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
909 | "T :rejected %u delaying %lu", | |
d1275a8f | 910 | sp.is_rej, delay_exit_length()); |
76d49681 JT |
911 | sendto_one_numeric(source_p, RPL_STATSDEBUG, |
912 | "T :throttled refused %u throttle list size %lu", sp.is_thr, throttle_size()); | |
83251205 VY |
913 | sendto_one_numeric(source_p, RPL_STATSDEBUG, |
914 | "T :nicks being delayed %lu", | |
915 | get_nd_count()); | |
916 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
917 | "T :unknown commands %u prefixes %u", | |
918 | sp.is_unco, sp.is_unpf); | |
919 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
920 | "T :nick collisions %u saves %u unknown closes %u", | |
921 | sp.is_kill, sp.is_save, sp.is_ni); | |
922 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
923 | "T :wrong direction %u empty %u", | |
924 | sp.is_wrdi, sp.is_empt); | |
925 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
926 | "T :numerics seen %u", sp.is_num); | |
927 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
928 | "T :tgchange blocked msgs %u restricted addrs %lu", | |
929 | sp.is_tgch, rb_dlink_list_length(&tgchange_list)); | |
930 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
931 | "T :auth successes %u fails %u", | |
932 | sp.is_asuc, sp.is_abad); | |
933 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
934 | "T :sasl successes %u fails %u", | |
935 | sp.is_ssuc, sp.is_sbad); | |
936 | sendto_one_numeric(source_p, RPL_STATSDEBUG, "T :Client Server"); | |
937 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
938 | "T :connected %u %u", sp.is_cl, sp.is_sv); | |
b717a466 JT |
939 | sendto_one_numeric(source_p, RPL_STATSDEBUG, |
940 | "T :bytes sent %lluK %lluK", | |
941 | sp.is_cbs / 1024, | |
942 | sp.is_sbs / 1024); | |
943 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
944 | "T :bytes recv %lluK %lluK", | |
945 | sp.is_cbr / 1024, | |
477035a4 | 946 | sp.is_sbr / 1024); |
b717a466 | 947 | sendto_one_numeric(source_p, RPL_STATSDEBUG, |
17d00839 AS |
948 | "T :time connected %llu %llu", |
949 | sp.is_cti, sp.is_sti); | |
212380e3 | 950 | } |
951 | ||
952 | static void | |
953 | stats_uptime (struct Client *source_p) | |
954 | { | |
955 | time_t now; | |
956 | ||
9f6bbe3c | 957 | now = rb_current_time() - startup_time; |
212380e3 | 958 | sendto_one_numeric(source_p, RPL_STATSUPTIME, |
959 | form_str (RPL_STATSUPTIME), | |
960 | now / 86400, (now / 3600) % 24, | |
961 | (now / 60) % 60, now % 60); | |
962 | sendto_one_numeric(source_p, RPL_STATSCONN, | |
963 | form_str (RPL_STATSCONN), | |
964 | MaxConnectionCount, MaxClientCount, | |
965 | Count.totalrestartcount); | |
966 | } | |
967 | ||
968 | struct shared_flags | |
969 | { | |
970 | int flag; | |
971 | char letter; | |
972 | }; | |
973 | static struct shared_flags shared_flagtable[] = | |
974 | { | |
975 | { SHARED_PKLINE, 'K' }, | |
976 | { SHARED_TKLINE, 'k' }, | |
977 | { SHARED_UNKLINE, 'U' }, | |
978 | { SHARED_PXLINE, 'X' }, | |
979 | { SHARED_TXLINE, 'x' }, | |
980 | { SHARED_UNXLINE, 'Y' }, | |
981 | { SHARED_PRESV, 'Q' }, | |
982 | { SHARED_TRESV, 'q' }, | |
983 | { SHARED_UNRESV, 'R' }, | |
984 | { SHARED_LOCOPS, 'L' }, | |
985 | { SHARED_REHASH, 'H' }, | |
90b9ef6c JT |
986 | { SHARED_TDLINE, 'd' }, |
987 | { SHARED_PDLINE, 'D' }, | |
988 | { SHARED_UNDLINE, 'E' }, | |
74e3e4f1 | 989 | { SHARED_DIE, 'I' }, |
069f104a | 990 | { SHARED_MODULE, 'M' }, |
212380e3 | 991 | { 0, '\0'} |
992 | }; | |
993 | ||
994 | ||
995 | static void | |
996 | stats_shared (struct Client *source_p) | |
997 | { | |
998 | struct remote_conf *shared_p; | |
08d11e34 | 999 | rb_dlink_node *ptr; |
3c80e9d6 | 1000 | char buf[sizeof(shared_flagtable)/sizeof(shared_flagtable[0])]; |
212380e3 | 1001 | char *p; |
1002 | int i; | |
1003 | ||
08d11e34 | 1004 | RB_DLINK_FOREACH(ptr, shared_conf_list.head) |
212380e3 | 1005 | { |
1006 | shared_p = ptr->data; | |
1007 | ||
1008 | p = buf; | |
1009 | ||
1010 | *p++ = 'c'; | |
1011 | ||
1012 | for(i = 0; shared_flagtable[i].flag != 0; i++) | |
1013 | { | |
1014 | if(shared_p->flags & shared_flagtable[i].flag) | |
1015 | *p++ = shared_flagtable[i].letter; | |
1016 | } | |
1017 | ||
1018 | *p = '\0'; | |
1019 | ||
1020 | sendto_one_numeric(source_p, RPL_STATSULINE, | |
1021 | form_str(RPL_STATSULINE), | |
1022 | shared_p->server, shared_p->username, | |
1023 | shared_p->host, buf); | |
1024 | } | |
1025 | ||
08d11e34 | 1026 | RB_DLINK_FOREACH(ptr, cluster_conf_list.head) |
212380e3 | 1027 | { |
1028 | shared_p = ptr->data; | |
1029 | ||
1030 | p = buf; | |
1031 | ||
1032 | *p++ = 'C'; | |
1033 | ||
1034 | for(i = 0; shared_flagtable[i].flag != 0; i++) | |
1035 | { | |
1036 | if(shared_p->flags & shared_flagtable[i].flag) | |
1037 | *p++ = shared_flagtable[i].letter; | |
1038 | } | |
1039 | ||
1040 | *p = '\0'; | |
1041 | ||
1042 | sendto_one_numeric(source_p, RPL_STATSULINE, | |
1043 | form_str(RPL_STATSULINE), | |
1044 | shared_p->server, "*", "*", buf); | |
1045 | } | |
1046 | } | |
1047 | ||
1048 | /* stats_servers() | |
1049 | * | |
1050 | * input - client pointer | |
1051 | * output - none | |
1052 | * side effects - client is shown lists of who connected servers | |
1053 | */ | |
1054 | static void | |
1055 | stats_servers (struct Client *source_p) | |
1056 | { | |
1057 | struct Client *target_p; | |
08d11e34 | 1058 | rb_dlink_node *ptr; |
212380e3 | 1059 | time_t seconds; |
1060 | int days, hours, minutes; | |
1061 | int j = 0; | |
1062 | ||
1063 | if(ConfigServerHide.flatten_links && !IsOper(source_p) && | |
1064 | !IsExemptShide(source_p)) | |
1065 | { | |
1066 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
1067 | form_str (ERR_NOPRIVILEGES)); | |
1068 | return; | |
1069 | } | |
1070 | ||
08d11e34 | 1071 | RB_DLINK_FOREACH (ptr, serv_list.head) |
212380e3 | 1072 | { |
1073 | target_p = ptr->data; | |
1074 | ||
1075 | j++; | |
9f6bbe3c | 1076 | seconds = rb_current_time() - target_p->localClient->firsttime; |
212380e3 | 1077 | |
1078 | days = (int) (seconds / 86400); | |
1079 | seconds %= 86400; | |
1080 | hours = (int) (seconds / 3600); | |
1081 | seconds %= 3600; | |
1082 | minutes = (int) (seconds / 60); | |
1083 | seconds %= 60; | |
1084 | ||
1085 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1086 | "V :%s (%s!*@*) Idle: %d SendQ: %d " | |
1087 | "Connected: %d day%s, %d:%02d:%02d", | |
1088 | target_p->name, | |
1089 | (target_p->serv->by[0] ? target_p->serv->by : "Remote."), | |
9f6bbe3c | 1090 | (int) (rb_current_time() - target_p->localClient->lasttime), |
e6871258 | 1091 | (int) rb_linebuf_len (&target_p->localClient->buf_sendq), |
212380e3 | 1092 | days, (days == 1) ? "" : "s", hours, minutes, |
1093 | (int) seconds); | |
1094 | } | |
1095 | ||
1096 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1097 | "V :%d Server(s)", j); | |
1098 | } | |
1099 | ||
1100 | static void | |
1101 | stats_tgecos(struct Client *source_p) | |
1102 | { | |
1103 | struct ConfItem *aconf; | |
08d11e34 | 1104 | rb_dlink_node *ptr; |
212380e3 | 1105 | |
08d11e34 | 1106 | RB_DLINK_FOREACH(ptr, xline_conf_list.head) |
212380e3 | 1107 | { |
1108 | aconf = ptr->data; | |
1109 | ||
1110 | if(aconf->hold) | |
1111 | sendto_one_numeric(source_p, RPL_STATSXLINE, | |
1112 | form_str(RPL_STATSXLINE), | |
ff0482a9 | 1113 | 'x', aconf->port, aconf->host, |
212380e3 | 1114 | aconf->passwd); |
1115 | } | |
1116 | } | |
1117 | ||
1118 | static void | |
1119 | stats_gecos(struct Client *source_p) | |
1120 | { | |
1121 | struct ConfItem *aconf; | |
08d11e34 | 1122 | rb_dlink_node *ptr; |
212380e3 | 1123 | |
08d11e34 | 1124 | RB_DLINK_FOREACH(ptr, xline_conf_list.head) |
212380e3 | 1125 | { |
1126 | aconf = ptr->data; | |
1127 | ||
1128 | if(!aconf->hold) | |
1129 | sendto_one_numeric(source_p, RPL_STATSXLINE, | |
1130 | form_str(RPL_STATSXLINE), | |
ff0482a9 | 1131 | 'X', aconf->port, aconf->host, |
212380e3 | 1132 | aconf->passwd); |
1133 | } | |
1134 | } | |
1135 | ||
1136 | static void | |
1137 | stats_class(struct Client *source_p) | |
1138 | { | |
1139 | if(ConfigFileEntry.stats_y_oper_only && !IsOper(source_p)) | |
1140 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
1141 | form_str (ERR_NOPRIVILEGES)); | |
1142 | else | |
1143 | report_classes(source_p); | |
1144 | } | |
1145 | ||
1146 | static void | |
1147 | stats_memory (struct Client *source_p) | |
1148 | { | |
83251205 VY |
1149 | struct Client *target_p; |
1150 | struct Channel *chptr; | |
1151 | struct Ban *actualBan; | |
1152 | rb_dlink_node *rb_dlink; | |
1153 | rb_dlink_node *ptr; | |
1154 | int channel_count = 0; | |
1155 | int local_client_conf_count = 0; /* local client conf links */ | |
1156 | int users_counted = 0; /* user structs */ | |
1157 | ||
1158 | int channel_users = 0; | |
1159 | int channel_invites = 0; | |
1160 | int channel_bans = 0; | |
1161 | int channel_except = 0; | |
1162 | int channel_invex = 0; | |
1163 | int channel_quiets = 0; | |
1164 | ||
1165 | int class_count = 0; /* classes */ | |
1166 | int conf_count = 0; /* conf lines */ | |
1167 | int users_invited_count = 0; /* users invited */ | |
1168 | int user_channels = 0; /* users in channels */ | |
c387fc41 | 1169 | int aways_counted = 0; |
83251205 VY |
1170 | size_t number_servers_cached; /* number of servers cached by scache */ |
1171 | ||
1172 | size_t channel_memory = 0; | |
1173 | size_t channel_ban_memory = 0; | |
1174 | size_t channel_except_memory = 0; | |
1175 | size_t channel_invex_memory = 0; | |
1176 | size_t channel_quiet_memory = 0; | |
1177 | ||
c387fc41 | 1178 | size_t away_memory = 0; /* memory used by aways */ |
83251205 VY |
1179 | size_t ww = 0; /* whowas array count */ |
1180 | size_t wwm = 0; /* whowas array memory used */ | |
1181 | size_t conf_memory = 0; /* memory used by conf lines */ | |
1182 | size_t mem_servers_cached; /* memory used by scache */ | |
1183 | ||
1184 | size_t linebuf_count = 0; | |
1185 | size_t linebuf_memory_used = 0; | |
1186 | ||
1187 | size_t total_channel_memory = 0; | |
1188 | size_t totww = 0; | |
1189 | ||
1190 | size_t local_client_count = 0; | |
1191 | size_t local_client_memory_used = 0; | |
1192 | ||
1193 | size_t remote_client_count = 0; | |
1194 | size_t remote_client_memory_used = 0; | |
1195 | ||
1196 | size_t total_memory = 0; | |
1197 | ||
1198 | count_whowas_memory(&ww, &wwm); | |
1199 | ||
1200 | RB_DLINK_FOREACH(ptr, global_client_list.head) | |
1201 | { | |
1202 | target_p = ptr->data; | |
1203 | if(MyConnect(target_p)) | |
1204 | { | |
1205 | local_client_conf_count++; | |
1206 | } | |
1207 | ||
1208 | if(target_p->user) | |
1209 | { | |
1210 | users_counted++; | |
1211 | users_invited_count += rb_dlink_list_length(&target_p->user->invited); | |
1212 | user_channels += rb_dlink_list_length(&target_p->user->channel); | |
c387fc41 SB |
1213 | if(target_p->user->away) |
1214 | { | |
1215 | aways_counted++; | |
1216 | away_memory += (strlen(target_p->user->away) + 1); | |
1217 | } | |
83251205 VY |
1218 | } |
1219 | } | |
1220 | ||
1221 | /* Count up all channels, ban lists, except lists, Invex lists */ | |
1222 | RB_DLINK_FOREACH(ptr, global_channel_list.head) | |
1223 | { | |
1224 | chptr = ptr->data; | |
1225 | channel_count++; | |
1226 | channel_memory += (strlen(chptr->chname) + sizeof(struct Channel)); | |
1227 | ||
1228 | channel_users += rb_dlink_list_length(&chptr->members); | |
1229 | channel_invites += rb_dlink_list_length(&chptr->invites); | |
1230 | ||
1231 | RB_DLINK_FOREACH(rb_dlink, chptr->banlist.head) | |
1232 | { | |
1233 | actualBan = rb_dlink->data; | |
1234 | channel_bans++; | |
1235 | ||
1236 | channel_ban_memory += sizeof(rb_dlink_node) + sizeof(struct Ban); | |
1237 | } | |
1238 | ||
1239 | RB_DLINK_FOREACH(rb_dlink, chptr->exceptlist.head) | |
1240 | { | |
1241 | actualBan = rb_dlink->data; | |
1242 | channel_except++; | |
1243 | ||
1244 | channel_except_memory += (sizeof(rb_dlink_node) + sizeof(struct Ban)); | |
1245 | } | |
1246 | ||
1247 | RB_DLINK_FOREACH(rb_dlink, chptr->invexlist.head) | |
1248 | { | |
1249 | actualBan = rb_dlink->data; | |
1250 | channel_invex++; | |
1251 | ||
1252 | channel_invex_memory += (sizeof(rb_dlink_node) + sizeof(struct Ban)); | |
1253 | } | |
1254 | ||
1255 | RB_DLINK_FOREACH(rb_dlink, chptr->quietlist.head) | |
1256 | { | |
1257 | actualBan = rb_dlink->data; | |
1258 | channel_quiets++; | |
1259 | ||
1260 | channel_quiet_memory += (sizeof(rb_dlink_node) + sizeof(struct Ban)); | |
1261 | } | |
1262 | } | |
1263 | ||
1264 | /* count up all classes */ | |
1265 | ||
1266 | class_count = rb_dlink_list_length(&class_list) + 1; | |
1267 | ||
1268 | rb_count_rb_linebuf_memory(&linebuf_count, &linebuf_memory_used); | |
1269 | ||
1270 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1271 | "z :Users %u(%lu) Invites %u(%lu)", | |
1272 | users_counted, | |
1273 | (unsigned long) users_counted * sizeof(struct User), | |
1274 | users_invited_count, | |
1275 | (unsigned long) users_invited_count * sizeof(rb_dlink_node)); | |
1276 | ||
1277 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
c387fc41 | 1278 | "z :User channels %u(%lu) Aways %u(%d)", |
83251205 | 1279 | user_channels, |
c387fc41 SB |
1280 | (unsigned long) user_channels * sizeof(rb_dlink_node), |
1281 | aways_counted, (int) away_memory); | |
83251205 VY |
1282 | |
1283 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1284 | "z :Attached confs %u(%lu)", | |
1285 | local_client_conf_count, | |
1286 | (unsigned long) local_client_conf_count * sizeof(rb_dlink_node)); | |
1287 | ||
1288 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1289 | "z :Conflines %u(%d)", conf_count, (int) conf_memory); | |
1290 | ||
1291 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1292 | "z :Classes %u(%lu)", | |
1293 | class_count, | |
1294 | (unsigned long) class_count * sizeof(struct Class)); | |
1295 | ||
1296 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1297 | "z :Channels %u(%d)", | |
1298 | channel_count, (int) channel_memory); | |
1299 | ||
1300 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1301 | "z :Bans %u(%d) Exceptions %u(%d) Invex %u(%d) Quiets %u(%d)", | |
1302 | channel_bans, (int) channel_ban_memory, | |
1303 | channel_except, (int) channel_except_memory, | |
1304 | channel_invex, (int) channel_invex_memory, | |
1305 | channel_quiets, (int) channel_quiet_memory); | |
1306 | ||
1307 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1308 | "z :Channel members %u(%lu) invite %u(%lu)", | |
1309 | channel_users, | |
1310 | (unsigned long) channel_users * sizeof(rb_dlink_node), | |
1311 | channel_invites, | |
1312 | (unsigned long) channel_invites * sizeof(rb_dlink_node)); | |
1313 | ||
1314 | total_channel_memory = channel_memory + | |
1315 | channel_ban_memory + | |
1316 | channel_users * sizeof(rb_dlink_node) + channel_invites * sizeof(rb_dlink_node); | |
1317 | ||
1318 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1319 | "z :Whowas array %ld(%ld)", | |
1320 | (long)ww, (long)wwm); | |
1321 | ||
1322 | totww = wwm; | |
1323 | ||
1324 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1325 | "z :Hash: client %u(%ld) chan %u(%ld)", | |
1326 | U_MAX, (long)(U_MAX * sizeof(rb_dlink_list)), | |
1327 | CH_MAX, (long)(CH_MAX * sizeof(rb_dlink_list))); | |
1328 | ||
1329 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1330 | "z :linebuf %ld(%ld)", | |
1331 | (long)linebuf_count, (long)linebuf_memory_used); | |
1332 | ||
1333 | count_scache(&number_servers_cached, &mem_servers_cached); | |
1334 | ||
1335 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1336 | "z :scache %ld(%ld)", | |
1337 | (long)number_servers_cached, (long)mem_servers_cached); | |
1338 | ||
1339 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1340 | "z :hostname hash %d(%ld)", | |
1341 | HOST_MAX, (long)HOST_MAX * sizeof(rb_dlink_list)); | |
1342 | ||
1343 | total_memory = totww + total_channel_memory + conf_memory + | |
1344 | class_count * sizeof(struct Class); | |
1345 | ||
1346 | total_memory += mem_servers_cached; | |
1347 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1348 | "z :Total: whowas %d channel %d conf %d", | |
1349 | (int) totww, (int) total_channel_memory, | |
1350 | (int) conf_memory); | |
1351 | ||
1352 | count_local_client_memory(&local_client_count, &local_client_memory_used); | |
1353 | total_memory += local_client_memory_used; | |
1354 | ||
1355 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1356 | "z :Local client Memory in use: %ld(%ld)", | |
1357 | (long)local_client_count, (long)local_client_memory_used); | |
1358 | ||
1359 | ||
1360 | count_remote_client_memory(&remote_client_count, &remote_client_memory_used); | |
1361 | total_memory += remote_client_memory_used; | |
1362 | ||
1363 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1364 | "z :Remote client Memory in use: %ld(%ld)", | |
1365 | (long)remote_client_count, | |
1366 | (long)remote_client_memory_used); | |
212380e3 | 1367 | } |
1368 | ||
1369 | static void | |
1370 | stats_ziplinks (struct Client *source_p) | |
1371 | { | |
08d11e34 | 1372 | rb_dlink_node *ptr; |
212380e3 | 1373 | struct Client *target_p; |
6b7c7401 | 1374 | struct ZipStats *zipstats; |
212380e3 | 1375 | int sent_data = 0; |
eeb13d32 | 1376 | char buf[128], buf1[128]; |
08d11e34 | 1377 | RB_DLINK_FOREACH (ptr, serv_list.head) |
212380e3 | 1378 | { |
1379 | target_p = ptr->data; | |
1380 | if(IsCapable (target_p, CAP_ZIP)) | |
1381 | { | |
6b7c7401 VY |
1382 | zipstats = target_p->localClient->zipstats; |
1383 | sprintf(buf, "%.2f%%", zipstats->out_ratio); | |
1384 | sprintf(buf1, "%.2f%%", zipstats->in_ratio); | |
212380e3 | 1385 | sendto_one_numeric(source_p, RPL_STATSDEBUG, |
eeb13d32 | 1386 | "Z :ZipLinks stats for %s send[%s compression " |
6b7c7401 VY |
1387 | "(%llu kB data/%llu kB wire)] recv[%s compression " |
1388 | "(%llu kB data/%llu kB wire)]", | |
212380e3 | 1389 | target_p->name, |
6b7c7401 VY |
1390 | buf, zipstats->out >> 10, |
1391 | zipstats->out_wire >> 10, buf1, | |
1392 | zipstats->in >> 10, zipstats->in_wire >> 10); | |
212380e3 | 1393 | sent_data++; |
1394 | } | |
1395 | } | |
1396 | ||
1397 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1398 | "Z :%u ziplink(s)", sent_data); | |
1399 | } | |
1400 | ||
1401 | static void | |
1402 | stats_servlinks (struct Client *source_p) | |
1403 | { | |
1404 | static char Sformat[] = ":%s %d %s %s %u %u %u %u %u :%u %u %s"; | |
1405 | long uptime, sendK, receiveK; | |
1406 | struct Client *target_p; | |
08d11e34 | 1407 | rb_dlink_node *ptr; |
212380e3 | 1408 | int j = 0; |
eeb13d32 | 1409 | char buf[128]; |
212380e3 | 1410 | |
1411 | if(ConfigServerHide.flatten_links && !IsOper (source_p) && | |
1412 | !IsExemptShide(source_p)) | |
1413 | { | |
1414 | sendto_one_numeric(source_p, ERR_NOPRIVILEGES, | |
1415 | form_str (ERR_NOPRIVILEGES)); | |
1416 | return; | |
1417 | } | |
1418 | ||
1419 | sendK = receiveK = 0; | |
1420 | ||
08d11e34 | 1421 | RB_DLINK_FOREACH (ptr, serv_list.head) |
212380e3 | 1422 | { |
1423 | target_p = ptr->data; | |
1424 | ||
1425 | j++; | |
1426 | sendK += target_p->localClient->sendK; | |
1427 | receiveK += target_p->localClient->receiveK; | |
1428 | ||
1429 | sendto_one(source_p, Sformat, | |
1430 | get_id(&me, source_p), RPL_STATSLINKINFO, get_id(source_p, source_p), | |
715b28fe | 1431 | target_p->name, |
f781a345 | 1432 | (int) rb_linebuf_len (&target_p->localClient->buf_sendq), |
212380e3 | 1433 | (int) target_p->localClient->sendM, |
1434 | (int) target_p->localClient->sendK, | |
1435 | (int) target_p->localClient->receiveM, | |
1436 | (int) target_p->localClient->receiveK, | |
9f6bbe3c VY |
1437 | rb_current_time() - target_p->localClient->firsttime, |
1438 | (rb_current_time() > target_p->localClient->lasttime) ? | |
1439 | (rb_current_time() - target_p->localClient->lasttime) : 0, | |
212380e3 | 1440 | IsOper (source_p) ? show_capabilities (target_p) : "TS"); |
1441 | } | |
1442 | ||
1443 | sendto_one_numeric(source_p, RPL_STATSDEBUG, | |
1444 | "? :%u total server(s)", j); | |
1445 | ||
eeb13d32 | 1446 | snprintf(buf, sizeof buf, "%7.2f", _GMKv ((sendK))); |
212380e3 | 1447 | sendto_one_numeric(source_p, RPL_STATSDEBUG, |
eeb13d32 JT |
1448 | "? :Sent total : %s %s", |
1449 | buf, _GMKs (sendK)); | |
1450 | snprintf(buf, sizeof buf, "%7.2f", _GMKv ((receiveK))); | |
212380e3 | 1451 | sendto_one_numeric(source_p, RPL_STATSDEBUG, |
eeb13d32 JT |
1452 | "? :Recv total : %s %s", |
1453 | buf, _GMKs (receiveK)); | |
212380e3 | 1454 | |
9f6bbe3c | 1455 | uptime = (rb_current_time() - startup_time); |
eeb13d32 | 1456 | snprintf(buf, sizeof buf, "%7.2f %s (%4.1f K/s)", |
212380e3 | 1457 | _GMKv (me.localClient->sendK), |
1458 | _GMKs (me.localClient->sendK), | |
1459 | (float) ((float) me.localClient->sendK / (float) uptime)); | |
eeb13d32 JT |
1460 | sendto_one_numeric(source_p, RPL_STATSDEBUG, "? :Server send: %s", buf); |
1461 | snprintf(buf, sizeof buf, "%7.2f %s (%4.1f K/s)", | |
212380e3 | 1462 | _GMKv (me.localClient->receiveK), |
1463 | _GMKs (me.localClient->receiveK), | |
1464 | (float) ((float) me.localClient->receiveK / (float) uptime)); | |
eeb13d32 | 1465 | sendto_one_numeric(source_p, RPL_STATSDEBUG, "? :Server recv: %s", buf); |
212380e3 | 1466 | } |
1467 | ||
1468 | static void | |
1469 | stats_ltrace(struct Client *source_p, int parc, const char *parv[]) | |
1470 | { | |
1471 | int doall = 0; | |
1472 | int wilds = 0; | |
1473 | const char *name; | |
1474 | char statchar = parv[1][0]; | |
1475 | ||
1476 | /* this is def targeted at us somehow.. */ | |
1477 | if(parc > 2 && !EmptyString(parv[2])) | |
1478 | { | |
1479 | /* directed at us generically? */ | |
1480 | if(match(parv[2], me.name) || | |
1481 | (!MyClient(source_p) && !irccmp(parv[2], me.id))) | |
1482 | { | |
1483 | name = me.name; | |
1484 | doall = 1; | |
1485 | } | |
1486 | else | |
1487 | { | |
1488 | name = parv[2]; | |
1489 | wilds = strchr(name, '*') || strchr(name, '?'); | |
1490 | } | |
1491 | ||
1492 | /* must be directed at a specific person thats not us */ | |
1493 | if(!doall && !wilds) | |
1494 | { | |
1495 | struct Client *target_p; | |
1496 | ||
1497 | if(MyClient(source_p)) | |
1498 | target_p = find_named_person(name); | |
1499 | else | |
1500 | target_p = find_person(name); | |
1501 | ||
1502 | if(target_p != NULL) | |
1503 | { | |
1504 | stats_spy(source_p, statchar, target_p->name); | |
1505 | stats_l_client(source_p, target_p, statchar); | |
1506 | } | |
1507 | else | |
1508 | sendto_one_numeric(source_p, ERR_NOSUCHSERVER, | |
1509 | form_str(ERR_NOSUCHSERVER), | |
1510 | name); | |
1511 | ||
1512 | return; | |
1513 | } | |
1514 | } | |
1515 | else | |
1516 | { | |
1517 | name = me.name; | |
1518 | doall = 1; | |
1519 | } | |
1520 | ||
1521 | stats_spy(source_p, statchar, name); | |
1522 | ||
1523 | if(doall) | |
1524 | { | |
1525 | /* local opers get everyone */ | |
1526 | if(MyOper(source_p)) | |
1527 | { | |
1528 | stats_l_list(source_p, name, doall, wilds, &unknown_list, statchar); | |
1529 | stats_l_list(source_p, name, doall, wilds, &lclient_list, statchar); | |
1530 | } | |
1531 | else | |
1532 | { | |
1533 | /* they still need themselves if theyre local.. */ | |
1534 | if(MyClient(source_p)) | |
1535 | stats_l_client(source_p, source_p, statchar); | |
1536 | ||
1537 | stats_l_list(source_p, name, doall, wilds, &local_oper_list, statchar); | |
1538 | } | |
1539 | ||
1540 | if (!ConfigServerHide.flatten_links || IsOper(source_p) || | |
1541 | IsExemptShide(source_p)) | |
1542 | stats_l_list(source_p, name, doall, wilds, &serv_list, statchar); | |
1543 | ||
1544 | return; | |
1545 | } | |
1546 | ||
1547 | /* ok, at this point theyre looking for a specific client whos on | |
1548 | * our server.. but it contains a wildcard. --fl | |
1549 | */ | |
1550 | stats_l_list(source_p, name, doall, wilds, &lclient_list, statchar); | |
1551 | ||
1552 | return; | |
1553 | } | |
1554 | ||
1555 | ||
1556 | static void | |
1557 | stats_l_list(struct Client *source_p, const char *name, int doall, int wilds, | |
08d11e34 | 1558 | rb_dlink_list * list, char statchar) |
212380e3 | 1559 | { |
08d11e34 | 1560 | rb_dlink_node *ptr; |
212380e3 | 1561 | struct Client *target_p; |
1562 | ||
1563 | /* send information about connections which match. note, we | |
1564 | * dont need tests for IsInvisible(), because non-opers will | |
1565 | * never get here for normal clients --fl | |
1566 | */ | |
08d11e34 | 1567 | RB_DLINK_FOREACH(ptr, list->head) |
212380e3 | 1568 | { |
1569 | target_p = ptr->data; | |
1570 | ||
1571 | if(!doall && wilds && !match(name, target_p->name)) | |
1572 | continue; | |
1573 | ||
1574 | stats_l_client(source_p, target_p, statchar); | |
1575 | } | |
1576 | } | |
1577 | ||
1578 | void | |
1579 | stats_l_client(struct Client *source_p, struct Client *target_p, | |
1580 | char statchar) | |
1581 | { | |
1582 | if(IsAnyServer(target_p)) | |
1583 | { | |
1584 | sendto_one_numeric(source_p, RPL_STATSLINKINFO, Lformat, | |
715b28fe | 1585 | target_p->name, |
f781a345 | 1586 | (int) rb_linebuf_len(&target_p->localClient->buf_sendq), |
212380e3 | 1587 | (int) target_p->localClient->sendM, |
1588 | (int) target_p->localClient->sendK, | |
1589 | (int) target_p->localClient->receiveM, | |
1590 | (int) target_p->localClient->receiveK, | |
9f6bbe3c VY |
1591 | rb_current_time() - target_p->localClient->firsttime, |
1592 | (rb_current_time() > target_p->localClient->lasttime) ? | |
1593 | (rb_current_time() - target_p->localClient->lasttime) : 0, | |
212380e3 | 1594 | IsOper(source_p) ? show_capabilities(target_p) : "-"); |
1595 | } | |
1596 | ||
1597 | else | |
1598 | { | |
1599 | sendto_one_numeric(source_p, RPL_STATSLINKINFO, Lformat, | |
1600 | show_ip(source_p, target_p) ? | |
1601 | (IsUpper(statchar) ? | |
1602 | get_client_name(target_p, SHOW_IP) : | |
1603 | get_client_name(target_p, HIDE_IP)) : | |
1604 | get_client_name(target_p, MASK_IP), | |
f781a345 | 1605 | (int) rb_linebuf_len(&target_p->localClient->buf_sendq), |
212380e3 | 1606 | (int) target_p->localClient->sendM, |
1607 | (int) target_p->localClient->sendK, | |
1608 | (int) target_p->localClient->receiveM, | |
1609 | (int) target_p->localClient->receiveK, | |
9f6bbe3c VY |
1610 | rb_current_time() - target_p->localClient->firsttime, |
1611 | (rb_current_time() > target_p->localClient->lasttime) ? | |
1612 | (rb_current_time() - target_p->localClient->lasttime) : 0, | |
212380e3 | 1613 | "-"); |
1614 | } | |
1615 | } | |
1616 | ||
9df69d5b JT |
1617 | static void |
1618 | rb_dump_fd_callback(int fd, const char *desc, void *data) | |
1619 | { | |
1620 | struct Client *source_p = data; | |
1621 | sendto_one_numeric(source_p, RPL_STATSDEBUG, "F :fd %-3d desc '%s'", fd, desc); | |
1622 | } | |
1623 | ||
1624 | static void | |
1625 | stats_comm(struct Client *source_p) | |
1626 | { | |
1627 | rb_dump_fd(rb_dump_fd_callback, source_p); | |
b8127271 VY |
1628 | } |
1629 | ||
212380e3 | 1630 | /* |
1631 | * stats_spy | |
1632 | * | |
1633 | * inputs - pointer to client doing the /stats | |
1634 | * - char letter they are doing /stats on | |
1635 | * output - none | |
1636 | * side effects - | |
1637 | * This little helper function reports to opers if configured. | |
1638 | * personally, I don't see why opers need to see stats requests | |
1639 | * at all. They are just "noise" to an oper, and users can't do | |
1640 | * any damage with stats requests now anyway. So, why show them? | |
1641 | * -Dianora | |
1642 | */ | |
1643 | static void | |
1644 | stats_spy(struct Client *source_p, char statchar, const char *name) | |
1645 | { | |
1646 | hook_data_int data; | |
1647 | ||
1648 | data.client = source_p; | |
1649 | data.arg1 = name; | |
1650 | data.arg2 = (int) statchar; | |
1651 | ||
1652 | call_hook(doing_stats_hook, &data); | |
1653 | } | |
1654 | ||
1655 | /* stats_p_spy() | |
1656 | * | |
1657 | * input - pointer to client doing stats | |
1658 | * ouput - | |
1659 | * side effects - call hook doing_stats_p | |
1660 | */ | |
1661 | static void | |
1662 | stats_p_spy (struct Client *source_p) | |
1663 | { | |
1664 | hook_data data; | |
1665 | ||
1666 | data.client = source_p; | |
1667 | data.arg1 = data.arg2 = NULL; | |
1668 | ||
1669 | call_hook(doing_stats_p_hook, &data); | |
1670 | } | |
1671 |