unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

stats.c (34355B)

      1 /*
      2  *   IRC - Internet Relay Chat, src/modules/stats.c
      3  *   (C) 2004-present The UnrealIRCd Team
      4  *
      5  *   See file AUTHORS in IRC package for additional names of
      6  *   the programmers.
      7  *
      8  *   This program is free software; you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 1, or (at your option)
     11  *   any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *   GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program; if not, write to the Free Software
     20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     21  */
     22 
     23 #include "unrealircd.h"
     24 
     25 CMD_FUNC(cmd_stats);
     26 
     27 #define MSG_STATS 	"STATS"
     28 
     29 ModuleHeader MOD_HEADER
     30   = {
     31 	"stats",
     32 	"5.0",
     33 	"command /stats",
     34 	"UnrealIRCd Team",
     35 	"unrealircd-6",
     36     };
     37 
     38 MOD_INIT()
     39 {
     40 	CommandAdd(modinfo->handle, MSG_STATS, cmd_stats, 3, CMD_USER);
     41 	MARK_AS_OFFICIAL_MODULE(modinfo);
     42 	return MOD_SUCCESS;
     43 }
     44 
     45 MOD_LOAD()
     46 {
     47 	return MOD_SUCCESS;
     48 }
     49 
     50 MOD_UNLOAD()
     51 {
     52 	return MOD_SUCCESS;
     53 }
     54 
     55 extern MODVAR int  max_connection_count;
     56 
     57 int stats_banversion(Client *, const char *);
     58 int stats_links(Client *, const char *);
     59 int stats_gline(Client *, const char *);
     60 int stats_except(Client *, const char *);
     61 int stats_allow(Client *, const char *);
     62 int stats_command(Client *, const char *);
     63 int stats_oper(Client *, const char *);
     64 int stats_port(Client *, const char *);
     65 int stats_bannick(Client *, const char *);
     66 int stats_traffic(Client *, const char *);
     67 int stats_uline(Client *, const char *);
     68 int stats_vhost(Client *, const char *);
     69 int stats_kline(Client *, const char *);
     70 int stats_banrealname(Client *, const char *);
     71 int stats_sqline(Client *, const char *);
     72 int stats_linkinfoint(Client *, const char *, int);
     73 int stats_linkinfo(Client *, const char *);
     74 int stats_linkinfoall(Client *, const char *);
     75 int stats_chanrestrict(Client *, const char *);
     76 int stats_shun(Client *, const char *);
     77 int stats_set(Client *, const char *);
     78 int stats_tld(Client *, const char *);
     79 int stats_uptime(Client *, const char *);
     80 int stats_denyver(Client *, const char *);
     81 int stats_notlink(Client *, const char *);
     82 int stats_class(Client *, const char *);
     83 int stats_officialchannels(Client *, const char *);
     84 int stats_spamfilter(Client *, const char *);
     85 int stats_fdtable(Client *, const char *);
     86 
     87 #define SERVER_AS_PARA 0x1
     88 #define FLAGS_AS_PARA 0x2
     89 
     90 struct statstab {
     91 	char flag;
     92 	char *longflag;
     93 	int (*func)(Client *client, const char *para);
     94 	int options;
     95 };
     96 
     97 /* Must be listed lexicographically */
     98 /* Long flags must be lowercase */
     99 struct statstab StatsTable[] = {
    100 	{ 'B', "banversion",	stats_banversion,	0		},
    101 	{ 'C', "link", 		stats_links,		0 		},
    102 	{ 'G', "gline",		stats_gline,		FLAGS_AS_PARA	},
    103 	{ 'H', "link",	 	stats_links,		0 		},
    104 	{ 'I', "allow",		stats_allow,		0 		},
    105 	{ 'K', "kline",		stats_kline,		0 		},
    106 	{ 'L', "linkinfoall",	stats_linkinfoall,	SERVER_AS_PARA	},
    107 	{ 'M', "command",	stats_command,		0 		},
    108 	{ 'O', "oper",		stats_oper,		0 		},
    109 	{ 'P', "port",		stats_port,		0 		},
    110 	{ 'Q', "sqline",	stats_sqline,		FLAGS_AS_PARA 	},
    111 	{ 'S', "set",		stats_set,		0		},
    112 	{ 'T', "traffic",	stats_traffic,		0 		},
    113 	{ 'U', "uline",		stats_uline,		0 		},
    114 	{ 'V', "vhost", 	stats_vhost,		0 		},
    115 	{ 'W', "fdtable",       stats_fdtable,          0               },
    116 	{ 'X', "notlink",	stats_notlink,		0 		},
    117 	{ 'Y', "class",		stats_class,		0 		},
    118 	{ 'c', "link", 		stats_links,		0 		},
    119 	{ 'e', "except",	stats_except,		0 		},
    120 	{ 'f', "spamfilter",	stats_spamfilter,	FLAGS_AS_PARA	},
    121 	{ 'g', "gline",		stats_gline,		FLAGS_AS_PARA	},
    122 	{ 'h', "link", 		stats_links,		0 		},
    123 	{ 'j', "officialchans", stats_officialchannels, 0 		},
    124 	{ 'k', "kline",		stats_kline,		0 		},
    125 	{ 'l', "linkinfo",	stats_linkinfo,		SERVER_AS_PARA 	},
    126 	{ 'm', "command",	stats_command,		0 		},
    127 	{ 'n', "banrealname",	stats_banrealname,	0 		},
    128 	{ 'o', "oper",		stats_oper,		0 		},
    129 	{ 'q', "bannick",	stats_bannick,		FLAGS_AS_PARA	},
    130 	{ 'r', "chanrestrict",	stats_chanrestrict,	0 		},
    131 	{ 's', "shun",		stats_shun,		FLAGS_AS_PARA	},
    132 	{ 't', "tld",		stats_tld,		0 		},
    133 	{ 'u', "uptime",	stats_uptime,		0 		},
    134 	{ 'v', "denyver",	stats_denyver,		0 		},
    135 	{ 'x', "notlink",	stats_notlink,		0 		},
    136 	{ 'y', "class",		stats_class,		0 		},
    137 	{ 0, 	NULL, 		NULL, 			0		}
    138 };
    139 
    140 int stats_compare(const char *s1, const char *s2)
    141 {
    142 	/* The long stats flags are always lowercase */
    143 	while (*s1 == tolower(*s2))
    144 	{
    145 		if (*s1 == 0)
    146 			return 0;
    147 		s1++;
    148 		s2++;
    149 	}
    150 	return 1;
    151 }
    152 
    153 static inline struct statstab *stats_binary_search(char c) {
    154 	int start = 0;
    155 	int stop = sizeof(StatsTable)/sizeof(StatsTable[0])-1;
    156 	int mid;
    157 	while (start <= stop) {
    158 		mid = (start+stop)/2;
    159 		if (c < StatsTable[mid].flag)
    160 			stop = mid-1;
    161 		else if (StatsTable[mid].flag == c)
    162 			return &StatsTable[mid];
    163 		else
    164 			start = mid+1;
    165 	}
    166 	return NULL;
    167 }
    168 
    169 static inline struct statstab *stats_search(const char *s) {
    170 	int i;
    171 	for (i = 0; StatsTable[i].flag; i++)
    172 		if (!stats_compare(StatsTable[i].longflag,s))
    173 			return &StatsTable[i];
    174 	return NULL;
    175 }
    176 
    177 static inline char *stats_combine_parv(const char *p1, const char *p2)
    178 {
    179 	static char buf[BUFSIZE+1];
    180         ircsnprintf(buf, sizeof(buf), "%s %s", p1, p2);
    181 	return buf;
    182 }
    183 
    184 static inline void stats_help(Client *client)
    185 {
    186 	sendnumeric(client, RPL_STATSHELP, "/Stats flags:");
    187 	sendnumeric(client, RPL_STATSHELP, "B - banversion - Send the ban version list");
    188 	sendnumeric(client, RPL_STATSHELP, "b - badword - Send the badwords list");
    189 	sendnumeric(client, RPL_STATSHELP, "C - link - Send the link block list");
    190 	sendnumeric(client, RPL_STATSHELP, "d - denylinkauto - Send the deny link (auto) block list");
    191 	sendnumeric(client, RPL_STATSHELP, "D - denylinkall - Send the deny link (all) block list");
    192 	sendnumeric(client, RPL_STATSHELP, "e - except - Send the ban exception list (ELINEs and in config))");
    193 	sendnumeric(client, RPL_STATSHELP, "f - spamfilter - Send the spamfilter list");
    194 	sendnumeric(client, RPL_STATSHELP, "F - denydcc - Send the deny dcc and allow dcc block lists");
    195 	sendnumeric(client, RPL_STATSHELP, "G - gline - Send the gline and gzline list");
    196 	sendnumeric(client, RPL_STATSHELP, "  Extended flags: [+/-mrs] [mask] [reason] [setby]");
    197 	sendnumeric(client, RPL_STATSHELP, "   m Return glines matching/not matching the specified mask");
    198 	sendnumeric(client, RPL_STATSHELP, "   r Return glines with a reason matching/not matching the specified reason");
    199 	sendnumeric(client, RPL_STATSHELP, "   s Return glines set by/not set by clients matching the specified name");
    200 	sendnumeric(client, RPL_STATSHELP, "I - allow - Send the allow block list");
    201 	sendnumeric(client, RPL_STATSHELP, "j - officialchans - Send the offical channels list");
    202 	sendnumeric(client, RPL_STATSHELP, "K - kline - Send the ban user/ban ip/except ban block list");
    203 	sendnumeric(client, RPL_STATSHELP, "l - linkinfo - Send link information");
    204 	sendnumeric(client, RPL_STATSHELP, "L - linkinfoall - Send all link information");
    205 	sendnumeric(client, RPL_STATSHELP, "M - command - Send list of how many times each command was used");
    206 	sendnumeric(client, RPL_STATSHELP, "n - banrealname - Send the ban realname block list");
    207 	sendnumeric(client, RPL_STATSHELP, "O - oper - Send the oper block list");
    208 	sendnumeric(client, RPL_STATSHELP, "P - port - Send information about ports");
    209 	sendnumeric(client, RPL_STATSHELP, "q - bannick - Send the ban nick block list");
    210 	sendnumeric(client, RPL_STATSHELP, "Q - sqline - Send the global qline list");
    211 	sendnumeric(client, RPL_STATSHELP, "r - chanrestrict - Send the channel deny/allow block list");
    212 	sendnumeric(client, RPL_STATSHELP, "S - set - Send the set block list");
    213 	sendnumeric(client, RPL_STATSHELP, "s - shun - Send the shun list");
    214 	sendnumeric(client, RPL_STATSHELP, "  Extended flags: [+/-mrs] [mask] [reason] [setby]");
    215 	sendnumeric(client, RPL_STATSHELP, "   m Return shuns matching/not matching the specified mask");
    216 	sendnumeric(client, RPL_STATSHELP, "   r Return shuns with a reason matching/not matching the specified reason");
    217 	sendnumeric(client, RPL_STATSHELP, "   s Return shuns set by/not set by clients matching the specified name");
    218 	sendnumeric(client, RPL_STATSHELP, "t - tld - Send the tld block list");
    219 	sendnumeric(client, RPL_STATSHELP, "T - traffic - Send traffic information");
    220 	sendnumeric(client, RPL_STATSHELP, "u - uptime - Send the server uptime and connection count");
    221 	sendnumeric(client, RPL_STATSHELP, "U - uline - Send the ulines block list");
    222 	sendnumeric(client, RPL_STATSHELP, "v - denyver - Send the deny version block list");
    223 	sendnumeric(client, RPL_STATSHELP, "V - vhost - Send the vhost block list");
    224 	sendnumeric(client, RPL_STATSHELP, "W - fdtable - Send the FD table listing");
    225 	sendnumeric(client, RPL_STATSHELP, "X - notlink - Send the list of servers that are not current linked");
    226 	sendnumeric(client, RPL_STATSHELP, "Y - class - Send the class block list");
    227 }
    228 
    229 static inline int allow_user_stats_short(char c)
    230 {
    231 	char l;
    232 	if (!ALLOW_USER_STATS)
    233 		return 0;
    234 	if (strchr(ALLOW_USER_STATS, c))
    235 		return 1;
    236 	l = tolower(c);
    237 	/* Hack for the flags that are case insensitive */
    238 	if (l == 'o' || l == 'y' || l == 'k' || l == 'g' || l == 'x' || l == 'c' ||
    239 		l =='f' || l == 'i' || l == 'h' || l == 'm')
    240 	{
    241 		if (islower(c) && strchr(ALLOW_USER_STATS, toupper(c)))
    242 			return 1;
    243 		else if (isupper(c) && strchr(ALLOW_USER_STATS, tolower(c)))
    244 			return 1;
    245 	}
    246 	/* Hack for c/C/H/h */
    247 	if (l == 'c')
    248 	{
    249 		if (strpbrk(ALLOW_USER_STATS, "hH"))
    250 			return 1;
    251 	} else if (l == 'h')
    252 		if (strpbrk(ALLOW_USER_STATS, "cC"))
    253 			return 1;
    254 	return 0;
    255 }
    256 
    257 static inline int allow_user_stats_long(const char *s)
    258 {
    259 	OperStat *os;
    260 	for (os = iConf.allow_user_stats_ext; os; os = os->next)
    261 	{
    262 		if (!strcasecmp(os->flag, s))
    263 			return 1;
    264 	}
    265 	return 0;
    266 }
    267 
    268 /* This is pretty slow, but it isn't used often so it isn't a big deal */
    269 static inline char *allow_user_stats_long_to_short()
    270 {
    271 	static char buffer[BUFSIZE+1];
    272 	int i = 0;
    273 	OperStat *os;
    274 	for (os = iConf.allow_user_stats_ext; os; os = os->next)
    275 	{
    276 		struct statstab *stat = stats_search(os->flag);
    277 		if (!stat)
    278 			continue;
    279 		if (!strchr(ALLOW_USER_STATS, stat->flag))
    280 			buffer[i++] = stat->flag;
    281 	}
    282 	buffer[i] = 0;
    283 	return buffer;
    284 }
    285 
    286 CMD_FUNC(cmd_stats)
    287 {
    288 	struct statstab *stat;
    289 	char flags[2];
    290 
    291 	if (parc == 3 && parv[2][0] != '+' && parv[2][0] != '-')
    292 	{
    293 		if (hunt_server(client, recv_mtags, "STATS", 2, parc, parv) != HUNTED_ISME)
    294 			return;
    295 	}
    296 	else if (parc == 4 && parv[2][0] != '+' && parv[2][0] != '-')
    297 	{
    298 		if (hunt_server(client, recv_mtags, "STATS", 2, parc, parv) != HUNTED_ISME)
    299 			return;
    300 	}
    301 	if (parc < 2 || !*parv[1])
    302 	{
    303 		stats_help(client);
    304 		sendnumeric(client, RPL_ENDOFSTATS, '*');
    305 		return;
    306 	}
    307 
    308 	/* Decide if we are looking for 1 char or a string */
    309 	if (parv[1][0] && !parv[1][1])
    310 	{
    311 		if (!ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL) && !allow_user_stats_short(parv[1][0]))
    312 		{
    313 			sendnumeric(client, ERR_NOPRIVILEGES);
    314 			return;
    315 		}
    316 		/* Old style, we can use a binary search here */
    317 		stat = stats_binary_search(parv[1][0]);
    318 	}
    319 	else
    320 	{
    321 		if (!ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL) && !allow_user_stats_long(parv[1]))
    322 		{
    323 			sendnumeric(client, ERR_NOPRIVILEGES);
    324 			return;
    325 		}
    326 		/* New style, search the hard way */
    327 		stat = stats_search(parv[1]);
    328 	}
    329 
    330 	if (!stat)
    331 	{
    332 		/* Not found. Perhaps a module provides it? */
    333 		Hook *h;
    334 		int found = 0, n;
    335 		for (h = Hooks[HOOKTYPE_STATS]; h; h = h->next)
    336 		{
    337 			n = (*(h->func.intfunc))(client, parv[1]);
    338 			if (n == 1)
    339 				found = 1;
    340 		}
    341 		if (!found)
    342 			stats_help(client);
    343 		sendnumeric(client, RPL_ENDOFSTATS, '*');
    344 		return;
    345 	}
    346 
    347 	flags[0] = stat->flag;
    348 	flags[1] = '\0';
    349 
    350 	if (stat->options & FLAGS_AS_PARA)
    351 	{
    352 		if (parc > 2 && (parv[2][0] == '+' || parv[2][0] == '-'))
    353 		{
    354 			if (parc > 3)
    355 				stat->func(client, stats_combine_parv(parv[2],parv[3]));
    356 			else
    357 				stat->func(client, parv[2]);
    358 		}
    359 		else if (parc > 3)
    360 			stat->func(client, parv[3]);
    361 		else
    362 			stat->func(client, NULL);
    363 	}
    364 	else if (stat->options & SERVER_AS_PARA)
    365 	{
    366 		if (parc > 2)
    367 			stat->func(client, parv[2]);
    368 		else
    369 			stat->func(client, NULL);
    370 	}
    371 	else
    372 		stat->func(client, NULL);
    373 
    374 	/* Modules can append data:
    375 	 * ('STATS S' already has special code for this that
    376 	 *  maintains certain ordering, so not included here)
    377 	 */
    378 	if (stat->flag != 'S')
    379 	{
    380 		RunHook(HOOKTYPE_STATS, client, flags);
    381 	}
    382 
    383 	sendnumeric(client, RPL_ENDOFSTATS, stat->flag);
    384 }
    385 
    386 int stats_banversion(Client *client, const char *para)
    387 {
    388 	ConfigItem_ban *bans;
    389 	for (bans = conf_ban; bans; bans = bans->next)
    390 	{
    391 		if (bans->flag.type != CONF_BAN_VERSION)
    392 			continue;
    393 		sendnumeric(client, RPL_STATSBANVER,
    394 			bans->mask, bans->reason ? bans->reason : "No Reason");
    395 	}
    396 	return 0;
    397 }
    398 
    399 int stats_links(Client *client, const char *para)
    400 {
    401 	ConfigItem_link *link_p;
    402 #ifdef DEBUGMODE
    403 	Client *acptr;
    404 #endif
    405 	for (link_p = conf_link; link_p; link_p = link_p->next)
    406 	{
    407 		sendnumericfmt(client, RPL_STATSCLINE, "C - * %s %i %s %s%s%s",
    408 			link_p->servername,
    409 			link_p->outgoing.port,
    410 			link_p->class->name,
    411 			(link_p->outgoing.options & CONNECT_AUTO) ? "a" : "",
    412 			(link_p->outgoing.options & CONNECT_TLS) ? "S" : "",
    413 			(link_p->flag.temporary == 1) ? "T" : "");
    414 #ifdef DEBUGMODE
    415 		sendnotice(client, "%s (%p) has refcount %d",
    416 			link_p->servername, link_p, link_p->refcount);
    417 #endif
    418 		if (link_p->hub)
    419 			sendnumericfmt(client, RPL_STATSHLINE, "H %s * %s",
    420 				link_p->hub, link_p->servername);
    421 		else if (link_p->leaf)
    422 			sendnumericfmt(client, RPL_STATSLLINE, "L %s * %s %d",
    423 				link_p->leaf, link_p->servername, link_p->leaf_depth);
    424 	}
    425 #ifdef DEBUGMODE
    426 	list_for_each_entry(acptr, &client_list, client_node)
    427 		if (MyConnect(acptr) && acptr->server && !IsMe(acptr))
    428 		{
    429 			if (!acptr->server->conf)
    430 				sendnotice(client, "client '%s' (%p) has NO CONF attached (? :P)",
    431 					acptr->name, acptr);
    432 			else
    433 				sendnotice(client, "client '%s' (%p) has conf %p attached, refcount: %d, temporary: %s",
    434 					acptr->name, acptr,
    435 					acptr->server->conf,
    436 					acptr->server->conf->refcount,
    437 					acptr->server->conf->flag.temporary ? "YES" : "NO");
    438 		}
    439 #endif
    440 	return 0;
    441 }
    442 
    443 int stats_gline(Client *client, const char *para)
    444 {
    445 	int cnt = 0;
    446 	tkl_stats(client, TKL_GLOBAL|TKL_KILL, para, &cnt);
    447 	tkl_stats(client, TKL_GLOBAL|TKL_ZAP, para, &cnt);
    448 	return 0;
    449 }
    450 
    451 int stats_spamfilter(Client *client, const char *para)
    452 {
    453 	int cnt = 0;
    454 	tkl_stats(client, TKL_SPAMF, para, &cnt);
    455 	tkl_stats(client, TKL_GLOBAL|TKL_SPAMF, para, &cnt);
    456 	return 0;
    457 }
    458 
    459 int stats_except(Client *client, const char *para)
    460 {
    461 	int cnt = 0;
    462 	tkl_stats(client, TKL_EXCEPTION, para, &cnt);
    463 	tkl_stats(client, TKL_EXCEPTION|TKL_GLOBAL, para, &cnt);
    464 	return 0;
    465 }
    466 
    467 int stats_allow(Client *client, const char *para)
    468 {
    469 	ConfigItem_allow *allows;
    470 	NameValuePrioList *m;
    471 
    472 	for (allows = conf_allow; allows; allows = allows->next)
    473 	{
    474 		for (m = allows->match->printable_list; m; m = m->next)
    475 		{
    476 			sendnumeric(client, RPL_STATSILINE,
    477 				    namevalue_nospaces(m), "-",
    478 				    allows->maxperip,
    479 				    allows->global_maxperip,
    480 				    allows->class->name,
    481 				    allows->server ? allows->server : DEFAULT_SERVER,
    482 				    allows->port ? allows->port : 6667);
    483 		}
    484 	}
    485 	return 0;
    486 }
    487 
    488 int stats_command(Client *client, const char *para)
    489 {
    490 	int i;
    491 	RealCommand *mptr;
    492 	for (i = 0; i < 256; i++)
    493 		for (mptr = CommandHash[i]; mptr; mptr = mptr->next)
    494 			if (mptr->count)
    495 			sendnumeric(client, RPL_STATSCOMMANDS, mptr->cmd,
    496 				mptr->count, mptr->bytes);
    497 
    498 	return 0;
    499 }
    500 
    501 int stats_oper(Client *client, const char *para)
    502 {
    503 	ConfigItem_oper *o;
    504 	NameValuePrioList *m;
    505 
    506 	for (o = conf_oper; o; o = o->next)
    507 	{
    508 		for (m = o->match->printable_list; m; m = m->next)
    509 		{
    510 			sendnumeric(client, RPL_STATSOLINE,
    511 			            'O', namevalue_nospaces(m), o->name,
    512 			            o->operclass ? o->operclass: "",
    513 			            o->class->name ? o->class->name : "");
    514 		}
    515 	}
    516 	return 0;
    517 }
    518 
    519 static char *stats_port_helper(ConfigItem_listen *listener)
    520 {
    521 	static char buf[256];
    522 
    523 	ircsnprintf(buf, sizeof(buf), "%s%s%s",
    524 	    (listener->options & LISTENER_CLIENTSONLY)? "clientsonly ": "",
    525 	    (listener->options & LISTENER_SERVERSONLY)? "serversonly ": "",
    526 	    (listener->options & LISTENER_DEFER_ACCEPT)? "defer-accept ": "");
    527 
    528 	/* And one of these.. */
    529 	if (listener->options & LISTENER_CONTROL)
    530 		strlcat(buf, "control ", sizeof(buf));
    531 	else if (listener->socket_type == SOCKET_TYPE_UNIX)
    532 		;
    533 	else if (listener->options & LISTENER_TLS)
    534 		strlcat(buf, "tls ", sizeof(buf));
    535 	else
    536 		strlcat(buf, "plaintext ", sizeof(buf));
    537 	return buf;
    538 }
    539 
    540 int stats_port(Client *client, const char *para)
    541 {
    542 	ConfigItem_listen *listener;
    543 
    544 	for (listener = conf_listen; listener != NULL; listener = listener->next)
    545 	{
    546 		if (!(listener->options & LISTENER_BOUND))
    547 			continue;
    548 		if ((listener->options & LISTENER_SERVERSONLY) && !ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL))
    549 			continue;
    550 		if (listener->socket_type == SOCKET_TYPE_UNIX)
    551 		{
    552 			sendnotice(client, "*** Listener on %s (UNIX): has %i client(s), options: %s %s",
    553 				   listener->file,
    554 				   listener->clients,
    555 				   stats_port_helper(listener),
    556 				   listener->flag.temporary ? "[TEMPORARY]" : "");
    557 		} else {
    558 			sendnotice(client, "*** Listener on %s:%i (%s): has %i client(s), options: %s %s",
    559 				   listener->ip,
    560 				   listener->port,
    561 				   listener->socket_type == SOCKET_TYPE_IPV6 ? "IPv6" : "IPv4",
    562 				   listener->clients,
    563 				   stats_port_helper(listener),
    564 				   listener->flag.temporary ? "[TEMPORARY]" : "");
    565 		}
    566 	}
    567 	return 0;
    568 }
    569 
    570 int stats_bannick(Client *client, const char *para)
    571 {
    572 	int cnt = 0;
    573 	tkl_stats(client, TKL_NAME, para, &cnt);
    574 	tkl_stats(client, TKL_GLOBAL|TKL_NAME, para, &cnt);
    575 	return 0;
    576 }
    577 
    578 int stats_traffic(Client *client, const char *para)
    579 {
    580 	Client *acptr;
    581 	IRCStatistics *sp;
    582 	IRCStatistics tmp;
    583 	time_t now = TStime();
    584 
    585 	sp = &tmp;
    586 	memcpy(sp, &ircstats, sizeof(IRCStatistics));
    587 
    588 	list_for_each_entry(acptr, &lclient_list, lclient_node)
    589 	{
    590 		if (IsServer(acptr))
    591 		{
    592 			sp->is_sti += now - acptr->local->creationtime;
    593 			sp->is_sv++;
    594 		}
    595 		else if (IsUser(acptr))
    596 		{
    597 			sp->is_cti += now - acptr->local->creationtime;
    598 			sp->is_cl++;
    599 		}
    600 		else if (IsUnknown(acptr))
    601 			sp->is_ni++;
    602 	}
    603 
    604 	sendnumericfmt(client, RPL_STATSDEBUG, "accepts %u refused %u", sp->is_ac, sp->is_ref);
    605 	sendnumericfmt(client, RPL_STATSDEBUG, "unknown commands %u prefixes %u", sp->is_unco, sp->is_unpf);
    606 	sendnumericfmt(client, RPL_STATSDEBUG, "nick collisions %u unknown closes %u", sp->is_kill, sp->is_ni);
    607 	sendnumericfmt(client, RPL_STATSDEBUG, "wrong direction %u empty %u", sp->is_wrdi, sp->is_empt);
    608 	sendnumericfmt(client, RPL_STATSDEBUG, "numerics seen %u mode fakes %u", sp->is_num, sp->is_fake);
    609 	sendnumericfmt(client, RPL_STATSDEBUG, "auth successes %u fails %u", sp->is_asuc, sp->is_abad);
    610 	sendnumericfmt(client, RPL_STATSDEBUG, "local connections %u udp packets %u", sp->is_loc, sp->is_udp);
    611 	sendnumericfmt(client, RPL_STATSDEBUG, "Client Server");
    612 	sendnumericfmt(client, RPL_STATSDEBUG, "connected %u %u", sp->is_cl, sp->is_sv);
    613 	sendnumericfmt(client, RPL_STATSDEBUG, "messages sent %lld", me.local->traffic.messages_sent);
    614 	sendnumericfmt(client, RPL_STATSDEBUG, "messages received %lld", me.local->traffic.messages_received);
    615 	sendnumericfmt(client, RPL_STATSDEBUG, "bytes sent %lld", me.local->traffic.bytes_sent);
    616 	sendnumericfmt(client, RPL_STATSDEBUG, "bytes received %lld", me.local->traffic.bytes_received);
    617 	sendnumericfmt(client, RPL_STATSDEBUG, "time connected %lld %lld",
    618 	    (long long)sp->is_cti, (long long)sp->is_sti);
    619 
    620 	return 0;
    621 }
    622 
    623 int stats_fdtable(Client *client, const char *para)
    624 {
    625 	int i;
    626 
    627 	for (i = 0; i < MAXCONNECTIONS; i++)
    628 	{
    629 		FDEntry *fde = &fd_table[i];
    630 
    631 		if (!fde->is_open)
    632 			continue;
    633 
    634 		sendnumericfmt(client, RPL_STATSDEBUG,
    635 			"fd %3d, desc '%s', read-hdl %p, write-hdl %p, cbdata %p",
    636 			fde->fd, fde->desc, fde->read_callback, fde->write_callback, fde->data);
    637 	}
    638 
    639 	return 0;
    640 }
    641 
    642 int stats_uline(Client *client, const char *para)
    643 {
    644 	ConfigItem_ulines *ulines;
    645 	for (ulines = conf_ulines; ulines; ulines = ulines->next)
    646 		sendnumeric(client, RPL_STATSULINE, ulines->servername);
    647 	return 0;
    648 }
    649 int stats_vhost(Client *client, const char *para)
    650 {
    651 	ConfigItem_vhost *vhosts;
    652 	NameValuePrioList *m;
    653 
    654 	for (vhosts = conf_vhost; vhosts; vhosts = vhosts->next)
    655 	{
    656 		for (m = vhosts->match->printable_list; m; m = m->next)
    657 		{
    658 			sendtxtnumeric(client, "vhost %s%s%s %s %s",
    659 			               vhosts->virtuser ? vhosts->virtuser : "",
    660 			               vhosts->virtuser ? "@" : "",
    661 			               vhosts->virthost,
    662 			               vhosts->login,
    663 			               namevalue_nospaces(m));
    664 		}
    665 	}
    666 	return 0;
    667 }
    668 
    669 int stats_kline(Client *client, const char *para)
    670 {
    671 	int cnt = 0;
    672 	tkl_stats(client, TKL_KILL, NULL, &cnt);
    673 	tkl_stats(client, TKL_ZAP, NULL, &cnt);
    674 	return 0;
    675 }
    676 
    677 int stats_banrealname(Client *client, const char *para)
    678 {
    679 	ConfigItem_ban *bans;
    680 	for (bans = conf_ban; bans; bans = bans->next)
    681 	{
    682 		if (bans->flag.type == CONF_BAN_REALNAME)
    683 		{
    684 			sendnumeric(client, RPL_STATSNLINE, bans->mask, bans->reason
    685 				? bans->reason : "<no reason>");
    686 		}
    687 	}
    688 	return 0;
    689 }
    690 
    691 int stats_sqline(Client *client, const char *para)
    692 {
    693 	int cnt = 0;
    694 	tkl_stats(client, TKL_NAME|TKL_GLOBAL, para, &cnt);
    695 	return 0;
    696 }
    697 
    698 int stats_chanrestrict(Client *client, const char *para)
    699 {
    700 	ConfigItem_deny_channel *dchans;
    701 	ConfigItem_allow_channel *achans;
    702 	for (dchans = conf_deny_channel; dchans; dchans = dchans->next)
    703 	{
    704 		sendtxtnumeric(client, "deny %s %c %s", dchans->channel, dchans->warn ? 'w' : '-', dchans->reason);
    705 	}
    706   	for (achans = conf_allow_channel; achans; achans = achans->next)
    707   	{
    708 		sendtxtnumeric(client, "allow %s", achans->channel);
    709 	}
    710 	return 0;
    711 }
    712 
    713 int stats_shun(Client *client, const char *para)
    714 {
    715 	int cnt = 0;
    716 	tkl_stats(client, TKL_GLOBAL|TKL_SHUN, para, &cnt);
    717 	return 0;
    718 }
    719 
    720 /* should this be moved to a seperate stats flag? */
    721 int stats_officialchannels(Client *client, const char *para)
    722 {
    723 	ConfigItem_offchans *x;
    724 
    725 	for (x = conf_offchans; x; x = x->next)
    726 	{
    727 		sendtxtnumeric(client, "%s %s", x->name, x->topic ? x->topic : "");
    728 	}
    729 	return 0;
    730 }
    731 
    732 #define SafePrint(x)   ((x) ? (x) : "")
    733 
    734 /** Helper for stats_set() */
    735 static void stats_set_anti_flood(Client *client, FloodSettings *f)
    736 {
    737 	int i;
    738 
    739 	for (i=0; floodoption_names[i]; i++)
    740 	{
    741 		if (i == FLD_CONVERSATIONS)
    742 		{
    743 			sendtxtnumeric(client, "anti-flood::%s::%s: %d users, new user every %s",
    744 				f->name, floodoption_names[i],
    745 				(int)f->limit[i], pretty_time_val(f->period[i]));
    746 		}
    747 		if (i == FLD_LAG_PENALTY)
    748 		{
    749 			sendtxtnumeric(client, "anti-flood::%s::lag-penalty: %d msec",
    750 				f->name, (int)f->period[i]);
    751 			sendtxtnumeric(client, "anti-flood::%s::lag-penalty-bytes: %d",
    752 				f->name,
    753 				f->limit[i] == INT_MAX ? 0 : (int)f->limit[i]);
    754 		}
    755 		else
    756 		{
    757 			sendtxtnumeric(client, "anti-flood::%s::%s: %d per %s",
    758 				f->name, floodoption_names[i],
    759 				(int)f->limit[i], pretty_time_val(f->period[i]));
    760 		}
    761 	}
    762 }
    763 
    764 int stats_set(Client *client, const char *para)
    765 {
    766 	char *uhallow;
    767 	SecurityGroup *s;
    768 	FloodSettings *f;
    769 	char modebuf[BUFSIZE], parabuf[BUFSIZE];
    770 
    771 	if (!ValidatePermissionsForPath("server:info:stats",client,NULL,NULL,NULL))
    772 	{
    773 		sendnumeric(client, ERR_NOPRIVILEGES);
    774 		return 0;
    775 	}
    776 
    777 	sendtxtnumeric(client, "*** Configuration Report ***");
    778 	sendtxtnumeric(client, "network-name: %s", NETWORK_NAME);
    779 	sendtxtnumeric(client, "default-server: %s", DEFAULT_SERVER);
    780 	if (SERVICES_NAME)
    781 	{
    782 		sendtxtnumeric(client, "services-server: %s", SERVICES_NAME);
    783 	}
    784 	if (STATS_SERVER)
    785 	{
    786 		sendtxtnumeric(client, "stats-server: %s", STATS_SERVER);
    787 	}
    788 	if (SASL_SERVER)
    789 	{
    790 		sendtxtnumeric(client, "sasl-server: %s", SASL_SERVER);
    791 	}
    792 	sendtxtnumeric(client, "cloak-prefix: %s", CLOAK_PREFIX);
    793 	sendtxtnumeric(client, "help-channel: %s", HELP_CHANNEL);
    794 	sendtxtnumeric(client, "cloak-keys: %s", CLOAK_KEY_CHECKSUM);
    795 	sendtxtnumeric(client, "kline-address: %s", KLINE_ADDRESS);
    796 	if (GLINE_ADDRESS)
    797 		sendtxtnumeric(client, "gline-address: %s", GLINE_ADDRESS);
    798 	sendtxtnumeric(client, "modes-on-connect: %s", get_usermode_string_raw(CONN_MODES));
    799 	sendtxtnumeric(client, "modes-on-oper: %s", get_usermode_string_raw(OPER_MODES));
    800 	*modebuf = *parabuf = 0;
    801 	chmode_str(&iConf.modes_on_join, modebuf, parabuf, sizeof(modebuf), sizeof(parabuf));
    802 	sendtxtnumeric(client, "modes-on-join: %s %s", modebuf, parabuf);
    803 	if (iConf.min_nick_length)
    804 		sendtxtnumeric(client, "min-nick-length: %i", iConf.min_nick_length);
    805 	sendtxtnumeric(client, "nick-length: %i", iConf.nick_length);
    806 	sendtxtnumeric(client, "snomask-on-oper: %s", OPER_SNOMASK);
    807 	if (ALLOW_USER_STATS)
    808 	{
    809 		char *longflags = allow_user_stats_long_to_short();
    810 		sendtxtnumeric(client, "allow-user-stats: %s%s", ALLOW_USER_STATS, longflags ? longflags : "");
    811 	}
    812 	if (RESTRICT_USERMODES)
    813 		sendtxtnumeric(client, "restrict-usermodes: %s", RESTRICT_USERMODES);
    814 	if (RESTRICT_CHANNELMODES)
    815 		sendtxtnumeric(client, "restrict-channelmodes: %s", RESTRICT_CHANNELMODES);
    816 	if (RESTRICT_EXTENDEDBANS)
    817 		sendtxtnumeric(client, "restrict-extendedbans: %s", RESTRICT_EXTENDEDBANS);
    818 	switch (UHOST_ALLOWED)
    819 	{
    820 		case UHALLOW_NEVER:
    821 			uhallow = "never";
    822 			break;
    823 		case UHALLOW_NOCHANS:
    824 			uhallow = "not-on-channels";
    825 			break;
    826 		case UHALLOW_REJOIN:
    827 			uhallow = "force-rejoin";
    828 			break;
    829 		case UHALLOW_ALWAYS:
    830 		default:
    831 			uhallow = "always";
    832 			break;
    833 	}
    834 	if (uhallow)
    835 		sendtxtnumeric(client, "allow-userhost-change: %s", uhallow);
    836 	sendtxtnumeric(client, "hide-ban-reason: %d", HIDE_BAN_REASON);
    837 	sendtxtnumeric(client, "anti-spam-quit-message-time: %s", pretty_time_val(ANTI_SPAM_QUIT_MSG_TIME));
    838 	sendtxtnumeric(client, "channel-command-prefix: %s", CHANCMDPFX ? CHANCMDPFX : "`");
    839 	sendtxtnumeric(client, "tls::certificate: %s", SafePrint(iConf.tls_options->certificate_file));
    840 	sendtxtnumeric(client, "tls::key: %s", SafePrint(iConf.tls_options->key_file));
    841 	sendtxtnumeric(client, "tls::trusted-ca-file: %s", SafePrint(iConf.tls_options->trusted_ca_file));
    842 	sendtxtnumeric(client, "tls::options: %s", iConf.tls_options->options & TLSFLAG_FAILIFNOCERT ? "FAILIFNOCERT" : "");
    843 	sendtxtnumeric(client, "options::show-opermotd: %d", SHOWOPERMOTD);
    844 	sendtxtnumeric(client, "options::hide-ulines: %d", HIDE_ULINES);
    845 	sendtxtnumeric(client, "options::identd-check: %d", IDENT_CHECK);
    846 	sendtxtnumeric(client, "options::fail-oper-warn: %d", FAILOPER_WARN);
    847 	sendtxtnumeric(client, "options::show-connect-info: %d", SHOWCONNECTINFO);
    848 	sendtxtnumeric(client, "options::no-connect-tls-info: %d", NOCONNECTTLSLINFO);
    849 	sendtxtnumeric(client, "options::dont-resolve: %d", DONT_RESOLVE);
    850 	sendtxtnumeric(client, "options::mkpasswd-for-everyone: %d", MKPASSWD_FOR_EVERYONE);
    851 	sendtxtnumeric(client, "options::allow-insane-bans: %d", ALLOW_INSANE_BANS);
    852 	sendtxtnumeric(client, "options::allow-part-if-shunned: %d", ALLOW_PART_IF_SHUNNED);
    853 	sendtxtnumeric(client, "maxchannelsperuser: %i", MAXCHANNELSPERUSER);
    854 	sendtxtnumeric(client, "ping-warning: %i seconds", PINGWARNING);
    855 	sendtxtnumeric(client, "auto-join: %s", AUTO_JOIN_CHANS ? AUTO_JOIN_CHANS : "0");
    856 	sendtxtnumeric(client, "oper-auto-join: %s", OPER_AUTO_JOIN_CHANS ? OPER_AUTO_JOIN_CHANS : "0");
    857 	sendtxtnumeric(client, "static-quit: %s", STATIC_QUIT ? STATIC_QUIT : "<none>");
    858 	sendtxtnumeric(client, "static-part: %s", STATIC_PART ? STATIC_PART : "<none>");
    859 	sendtxtnumeric(client, "who-limit: %d", WHOLIMIT);
    860 	sendtxtnumeric(client, "silence-limit: %d", SILENCE_LIMIT);
    861 	sendtxtnumeric(client, "ban-version-tkl-time: %s", pretty_time_val(BAN_VERSION_TKL_TIME));
    862 	if (LINK_BINDIP)
    863 		sendtxtnumeric(client, "link::bind-ip: %s", LINK_BINDIP);
    864 	sendtxtnumeric(client, "anti-flood::connect-flood: %d per %s", THROTTLING_COUNT, pretty_time_val(THROTTLING_PERIOD));
    865 	sendtxtnumeric(client, "anti-flood::handshake-data-flood::amount: %ld bytes", iConf.handshake_data_flood_amount);
    866 	sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-action: %s", banact_valtostring(iConf.handshake_data_flood_ban_action));
    867 	sendtxtnumeric(client, "anti-flood::handshake-data-flood::ban-time: %s", pretty_time_val(iConf.handshake_data_flood_ban_time));
    868 
    869 	/* set::anti-flood */
    870 	for (s = securitygroups; s; s = s->next)
    871 		if ((f = find_floodsettings_block(s->name)))
    872 			stats_set_anti_flood(client, f);
    873 	f = find_floodsettings_block("unknown-users");
    874 	stats_set_anti_flood(client, f);
    875 
    876 	//if (AWAY_PERIOD)
    877 	//	sendtxtnumeric(client, "anti-flood::away-flood: %d per %s", AWAY_COUNT, pretty_time_val(AWAY_PERIOD));
    878 	//sendtxtnumeric(client, "anti-flood::nick-flood: %d per %s", NICK_COUNT, pretty_time_val(NICK_PERIOD));
    879 	sendtxtnumeric(client, "handshake-timeout: %s", pretty_time_val(iConf.handshake_timeout));
    880 	sendtxtnumeric(client, "sasl-timeout: %s", pretty_time_val(iConf.sasl_timeout));
    881 	sendtxtnumeric(client, "ident::connect-timeout: %s", pretty_time_val(IDENT_CONNECT_TIMEOUT));
    882 	sendtxtnumeric(client, "ident::read-timeout: %s", pretty_time_val(IDENT_READ_TIMEOUT));
    883 	sendtxtnumeric(client, "spamfilter::ban-time: %s", pretty_time_val(SPAMFILTER_BAN_TIME));
    884 	sendtxtnumeric(client, "spamfilter::ban-reason: %s", SPAMFILTER_BAN_REASON);
    885 	sendtxtnumeric(client, "spamfilter::virus-help-channel: %s", SPAMFILTER_VIRUSCHAN);
    886 	if (SPAMFILTER_EXCEPT)
    887 		sendtxtnumeric(client, "spamfilter::except: %s", SPAMFILTER_EXCEPT);
    888 	sendtxtnumeric(client, "check-target-nick-bans: %s", CHECK_TARGET_NICK_BANS ? "yes" : "no");
    889 	sendtxtnumeric(client, "plaintext-policy::user: %s", policy_valtostr(iConf.plaintext_policy_user));
    890 	sendtxtnumeric(client, "plaintext-policy::oper: %s", policy_valtostr(iConf.plaintext_policy_oper));
    891 	sendtxtnumeric(client, "plaintext-policy::server: %s", policy_valtostr(iConf.plaintext_policy_server));
    892 	sendtxtnumeric(client, "outdated-tls-policy::user: %s", policy_valtostr(iConf.outdated_tls_policy_user));
    893 	sendtxtnumeric(client, "outdated-tls-policy::oper: %s", policy_valtostr(iConf.outdated_tls_policy_oper));
    894 	sendtxtnumeric(client, "outdated-tls-policy::server: %s", policy_valtostr(iConf.outdated_tls_policy_server));
    895 	RunHook(HOOKTYPE_STATS, client, "S");
    896 #ifndef _WIN32
    897 	sendtxtnumeric(client, "This server can handle %d concurrent sockets (%d clients + %d reserve)",
    898 		maxclients+CLIENTS_RESERVE, maxclients, CLIENTS_RESERVE);
    899 #endif
    900 	return 1;
    901 }
    902 
    903 int stats_tld(Client *client, const char *para)
    904 {
    905 	ConfigItem_tld *tld;
    906 	NameValuePrioList *m;
    907 
    908 	for (tld = conf_tld; tld; tld = tld->next)
    909 	{
    910 		for (m = tld->match->printable_list; m; m = m->next)
    911 		{
    912 			sendnumeric(client, RPL_STATSTLINE, namevalue_nospaces(m),
    913 			            tld->motd_file,
    914 			            tld->rules_file ? tld->rules_file : "none");
    915 		}
    916 	}
    917 
    918 	return 0;
    919 }
    920 
    921 int stats_uptime(Client *client, const char *para)
    922 {
    923 	long long uptime;
    924 
    925 	uptime = TStime() - me.local->fake_lag;
    926 	sendnumeric(client, RPL_STATSUPTIME,
    927 	    uptime / 86400, (uptime / 3600) % 24, (uptime / 60) % 60,
    928 	    uptime % 60);
    929 	sendnumeric(client, RPL_STATSCONN,
    930 	    max_connection_count, irccounts.me_max);
    931 	return 0;
    932 }
    933 
    934 int stats_denyver(Client *client, const char *para)
    935 {
    936 	ConfigItem_deny_version *versions;
    937 	for (versions = conf_deny_version; versions; versions = versions->next)
    938 	{
    939 		sendnumeric(client, RPL_STATSVLINE,
    940 			versions->version, versions->flags, versions->mask);
    941 	}
    942 	return 0;
    943 }
    944 
    945 int stats_notlink(Client *client, const char *para)
    946 {
    947 	ConfigItem_link *link_p;
    948 
    949 	for (link_p = conf_link; link_p; link_p = link_p->next)
    950 	{
    951 		if (!find_server_quick(link_p->servername))
    952 		{
    953 			sendnumeric(client, RPL_STATSXLINE, link_p->servername,
    954 				link_p->outgoing.port);
    955 		}
    956 	}
    957 	return 0;
    958 }
    959 
    960 int stats_class(Client *client, const char *para)
    961 {
    962 	ConfigItem_class *classes;
    963 
    964 	for (classes = conf_class; classes; classes = classes->next)
    965 	{
    966 		sendnumeric(client, RPL_STATSYLINE, classes->name, classes->pingfreq, classes->connfreq,
    967 			classes->maxclients, classes->sendq, classes->recvq ? classes->recvq : DEFAULT_RECVQ);
    968 #ifdef DEBUGMODE
    969 		sendnotice(client, "class '%s' has clients=%d, xrefcount=%d",
    970 			classes->name, classes->clients, classes->xrefcount);
    971 #endif
    972 	}
    973 	return 0;
    974 }
    975 
    976 int stats_linkinfo(Client *client, const char *para)
    977 {
    978 	return stats_linkinfoint(client, para, 0);
    979 }
    980 
    981 int stats_linkinfoall(Client *client, const char *para)
    982 {
    983 	return stats_linkinfoint(client, para, 1);
    984 }
    985 
    986 int stats_linkinfoint(Client *client, const char *para, int all)
    987 {
    988 	int remote = 0;
    989 	int wilds = 0;
    990 	int doall = 0;
    991 	Client *acptr;
    992 
    993 	/*
    994 	 * send info about connections which match, or all if the
    995 	 * mask matches me.name.  Only restrictions are on those who
    996 	 * are invisible not being visible to 'foreigners' who use
    997 	 * a wild card based search to list it.
    998 	 */
    999 	if (para)
   1000 	{
   1001 		if (!mycmp(para, me.name))
   1002 			doall = 2;
   1003 		else if (match_simple(para, me.name))
   1004 			doall = 1;
   1005 		if (strchr(para, '*') || strchr(para, '?'))
   1006 			wilds = 1;
   1007 	}
   1008 	else
   1009 		para = me.name;
   1010 
   1011 	sendnumericfmt(client, RPL_STATSLINKINFO, "Name SendQ SendM SendBytes RcveM RcveBytes Open_since :Idle");
   1012 
   1013 	if (!MyUser(client))
   1014 	{
   1015 		remote = 1;
   1016 		wilds = 0;
   1017 	}
   1018 
   1019 	list_for_each_entry(acptr, &lclient_list, lclient_node)
   1020 	{
   1021 		if (IsInvisible(acptr) && (doall || wilds) &&
   1022 			!IsOper(acptr) && (acptr != client))
   1023 			continue;
   1024 		if (remote && doall && !IsServer(acptr) && !IsMe(acptr))
   1025 			continue;
   1026 		if (remote && !doall && IsServer(acptr))
   1027 			continue;
   1028 		if (!doall && wilds && !match_simple(para, acptr->name))
   1029 			continue;
   1030 		if (!(para && (IsServer(acptr) || IsListening(acptr))) &&
   1031 		    !(doall || wilds) &&
   1032 		    mycmp(para, acptr->name))
   1033 		{
   1034 			continue;
   1035 		}
   1036 
   1037 		sendnumericfmt(client, RPL_STATSLINKINFO,
   1038 		        "%s%s %lld %lld %lld %lld %lld %lld :%lld",
   1039 			acptr->name, get_client_status(acptr),
   1040 			(long long)DBufLength(&acptr->local->sendQ),
   1041 			(long long)acptr->local->traffic.messages_sent,
   1042 			(long long)acptr->local->traffic.bytes_sent,
   1043 			(long long)acptr->local->traffic.messages_received,
   1044 			(long long)acptr->local->traffic.bytes_received,
   1045 			(long long)(TStime() - acptr->local->creationtime),
   1046 			(long long)(TStime() - acptr->local->last_msg_received));
   1047 	}
   1048 #ifdef DEBUGMODE
   1049 	list_for_each_entry(acptr, &client_list, client_node)
   1050 	{
   1051 		if (IsServer(acptr))
   1052 			sendnotice(client, "Server %s is %s",
   1053 				acptr->name, acptr->server->flags.synced ? "SYNCED" : "NOT SYNCED!!");
   1054 	}
   1055 #endif
   1056 	return 0;
   1057 }