]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/m_check.c
2 * IRC - Internet Relay Chat, ircd/m_check.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
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 1, or (at your option)
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include "ircd_alloc.h"
30 #include "ircd_defs.h"
31 #include "ircd_features.h"
32 #include "ircd_reply.h"
33 #include "ircd_string.h"
34 #include "ircd_snprintf.h"
40 #include "querycmds.h"
47 #define CHECK_CHECKCHAN 0x01 /* -c */
48 #define CHECK_SHOWUSERS 0x02 /* ! -u */
49 #define CHECK_OPSONLY 0x04 /* -o */
50 #define CHECK_SHOWIPS 0x08 /* -i */
51 #define CHECK_CIDRMASK 0x10 /* automatically detected when performing a hostmask /CHECK */
54 * - ASUKA ---------------------------------------------------------------------
55 * This is the implimentation of the CHECK function for Asuka.
56 * Some of this code is from previous QuakeNet ircds, but most of it is mine..
57 * The old code was written by Durzel (durzel@quakenet.org).
59 * qoreQ (qoreQ@quakenet.org) - 08/14/2002
60 * -----------------------------------------------------------------------------
64 * Syntax: CHECK <channel|nick|server|hostmask> [-flags]
66 * Where valid flags are:
67 * -c: Show channels when checking a hostmask.
68 * -i: Show IPs instead of hostnames when displaying results.
69 * -o: Only show channel operators when checking a channel.
70 * -u: Hide users when checking a channel.
72 * <hostmask> can be of the form host, user@host, nick!user@host,
73 * with host being host.domain.cc, 127.0.0.1 or 127.0.0.0/24.
74 * Wildcards are supported.
77 int m_check(struct Client
*cptr
, struct Client
*sptr
, int parc
, char *parv
[]) {
78 struct Channel
*chptr
;
81 int flags
= CHECK_SHOWUSERS
, i
;
84 send_reply(sptr
, ERR_NEEDMOREPARAMS
, "CHECK");
88 /* This checks to see if any flags have been supplied */
89 if ((parc
>= 3) && (parv
[2][0] == '-')) {
90 for (i
= 0; parv
[2][i
]; i
++) {
93 flags
|= CHECK_CHECKCHAN
;
97 flags
|= CHECK_OPSONLY
; /* fall through */
99 flags
&= ~(CHECK_SHOWUSERS
);
103 flags
|= CHECK_SHOWIPS
;
107 /* might want to raise some sort of error here? */
113 if (IsChannelName(parv
[1])) { /* channel */
114 if ((chptr
= FindChannel(parv
[1]))) {
115 checkChannel(sptr
, chptr
);
116 checkUsers(sptr
, chptr
, flags
);
119 send_reply(sptr
, ERR_SEARCHNOMATCH
, "CHECK", parv
[1]);
121 else if ((acptr
= FindClient(parv
[1])) && !(FindServer(parv
[1]))) { /* client and not a server */
122 if (!IsRegistered(acptr
)) {
123 send_reply(sptr
, ERR_SEARCHNOMATCH
, "CHECK", parv
[1]);
127 checkClient(sptr
, acptr
);
129 else if ((acptr
= FindServer(parv
[1]))) { /* server */
130 checkServer(sptr
, acptr
);
132 else if (checkHostmask(sptr
, parv
[1], flags
) > 0) /* hostmask */
135 send_reply(sptr
, ERR_SEARCHNOMATCH
, "CHECK", parv
[1]);
140 static int checkClones(struct Channel
*chptr
, char *nick
, char *host
) {
142 struct Membership
*lp
;
143 struct Client
*acptr
;
145 for (lp
= chptr
->members
; lp
; lp
= lp
->next_member
) {
147 if (!strcmp(acptr
->cli_user
->realhost
, host
) && strcmp(acptr
->cli_name
, nick
)) {
148 /* this is a clone */
153 return ((clones
) ? clones
+ 1 : 0);
156 void checkUsers(struct Client
*sptr
, struct Channel
*chptr
, int flags
) {
157 struct Membership
*lp
;
159 struct Client
*acptr
;
161 char outbuf
[BUFSIZE
], ustat
[64];
162 int cntr
= 0, opcntr
= 0, vcntr
= 0, clones
= 0, bans
= 0, c
= 0, authed
= 0;
164 if (flags
& CHECK_SHOWUSERS
) send_reply(sptr
, RPL_DATASTR
, "Users (@ = op, + = voice)");
166 for (lp
= chptr
->members
; lp
; lp
= lp
->next_member
) {
171 if ((c
= checkClones(chptr
, acptr
->cli_name
, acptr
->cli_user
->realhost
)) != 0) {
172 ircd_snprintf(0, ustat
, sizeof(ustat
), "%2d ", c
);
178 if (chptr
&& is_chan_op(acptr
, chptr
)) {
183 else if (chptr
&& has_voice(acptr
, chptr
)) {
190 if ((c
= IsAccount(acptr
)) != 0) ++authed
;
192 if ((flags
& CHECK_SHOWUSERS
) || ((flags
& CHECK_OPSONLY
) && opped
)) {
193 ircd_snprintf(0, outbuf
, sizeof(outbuf
), "%s%c", acptr
->cli_info
, COLOR_OFF
);
194 send_reply(sptr
, RPL_CHANUSER
, ustat
, acptr
->cli_name
, acptr
->cli_user
->realusername
,
195 (flags
& CHECK_SHOWIPS
) ? ircd_ntoa(&(cli_ip(acptr
))) : acptr
->cli_user
->realhost
, outbuf
,
196 (c
? acptr
->cli_user
->account
: ""));
202 send_reply(sptr
, RPL_DATASTR
, " ");
204 ircd_snprintf(0, outbuf
, sizeof(outbuf
),
205 "Total users:: %d (%d ops, %d voiced, %d clones, %d authed)",
206 cntr
, opcntr
, vcntr
, clones
, authed
);
208 send_reply(sptr
, RPL_DATASTR
, outbuf
);
210 send_reply(sptr
, RPL_DATASTR
, " ");
212 /* Do not display bans if ! flags & CHECK_SHOWUSERS */
213 if (!(flags
& CHECK_SHOWUSERS
)) {
214 send_reply(sptr
, RPL_ENDOFCHECK
, " ");
219 send_reply(sptr
, RPL_DATASTR
, "Bans on channel::");
221 for (ban
= chptr
->banlist
; ban
; ban
= ban
->next
) {
222 ircd_snprintf(0, outbuf
, sizeof(outbuf
), "[%d] - %s - Set by %s, on %s",
223 ++bans
, ban
->banstr
, ban
->who
, myctime(ban
->when
));
224 send_reply(sptr
, RPL_DATASTR
, outbuf
);
228 send_reply(sptr
, RPL_DATASTR
, "<none>");
230 send_reply(sptr
, RPL_ENDOFCHECK
, " ");
233 void checkChannel(struct Client
*sptr
, struct Channel
*chptr
) {
234 char outbuf
[TOPICLEN
+ MODEBUFLEN
+ 64], modebuf
[MODEBUFLEN
], parabuf
[MODEBUFLEN
];
237 send_reply(sptr
, RPL_DATASTR
, " ");
238 send_reply(sptr
, RPL_CHKHEAD
, "channel", chptr
->chname
);
239 send_reply(sptr
, RPL_DATASTR
, " ");
242 ircd_snprintf(sptr
, outbuf
, sizeof(outbuf
), " Creation time:: %s", myctime(chptr
->creationtime
));
243 send_reply(sptr
, RPL_DATASTR
, outbuf
);
246 if (strlen(chptr
->topic
) <= 0)
247 send_reply(sptr
, RPL_DATASTR
, " Topic:: <none>");
249 ircd_snprintf(sptr
, outbuf
, sizeof(outbuf
), " Topic:: %s", chptr
->topic
);
250 send_reply(sptr
, RPL_DATASTR
, outbuf
);
253 ircd_snprintf(sptr
, outbuf
, sizeof(outbuf
), " Set by:: %s", chptr
->topic_nick
);
254 send_reply(sptr
, RPL_DATASTR
, outbuf
);
259 strcpy(outbuf
, "Channel mode(s):: ");
264 channel_modes(sptr
, modebuf
, parabuf
, sizeof(modebuf
), chptr
, NULL
);
266 if(modebuf
[1] == '\0')
267 strcat(outbuf
, "<none>");
269 strcat(outbuf
, modebuf
);
271 strcat(outbuf
, parabuf
);
274 strcat(outbuf
, modebuf
);
276 send_reply(sptr
, RPL_DATASTR
, outbuf
);
278 /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */
281 void checkClient(struct Client
*sptr
, struct Client
*acptr
) {
282 struct Channel
*chptr
;
283 struct Membership
*lp
;
284 struct irc_sockaddr sin
;
285 char outbuf
[BUFSIZE
];
289 send_reply(sptr
, RPL_DATASTR
, " ");
290 send_reply(sptr
, RPL_CHKHEAD
, "user", acptr
->cli_name
);
291 send_reply(sptr
, RPL_DATASTR
, " ");
293 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Nick:: %s (%s%s)", acptr
->cli_name
, NumNick(acptr
));
294 send_reply(sptr
, RPL_DATASTR
, outbuf
);
297 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Signed on:: %s", myctime(acptr
->cli_firsttime
));
298 send_reply(sptr
, RPL_DATASTR
, outbuf
);
301 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Timestamp:: %s (%d)", myctime(acptr
->cli_lastnick
), acptr
->cli_lastnick
);
302 send_reply(sptr
, RPL_DATASTR
, outbuf
);
304 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " User/Hostmask:: %s@%s (%s)", acptr
->cli_user
->username
, acptr
->cli_user
->host
,
305 ircd_ntoa(&(cli_ip(acptr
))));
306 send_reply(sptr
, RPL_DATASTR
, outbuf
);
308 if (IsSetHost(acptr
) || IsAccount(acptr
)) {
309 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Real User/Host:: %s@%s", acptr
->cli_user
->realusername
, acptr
->cli_user
->realhost
);
310 send_reply(sptr
, RPL_DATASTR
, outbuf
);
313 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Real Name:: %s%c", cli_info(acptr
), COLOR_OFF
);
314 send_reply(sptr
, RPL_DATASTR
, outbuf
);
316 if (IsService(acptr
) == -1)
317 send_reply(sptr
, RPL_DATASTR
, " Status:: Network Service");
318 else if (IsAnOper(acptr
))
319 send_reply(sptr
, RPL_DATASTR
, " Status:: IRC Operator");
321 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Connected to:: %s", cli_name(acptr
->cli_user
->server
));
322 send_reply(sptr
, RPL_DATASTR
, outbuf
);
324 /* +s (SERV_NOTICE) is not relayed to us from remote servers,
325 * so we cannot tell if a remote client has that mode set.
326 * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG
327 * (and breaks if the user is +r) so we won't do that either.
330 if (strlen(umode_str(acptr
)) < 1)
331 strcpy(outbuf
, " Umode(s):: <none>");
333 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Umode(s):: +%s", umode_str(acptr
));
334 send_reply(sptr
, RPL_DATASTR
, outbuf
);
336 if (acptr
->cli_user
->joined
== 0)
337 send_reply(sptr
, RPL_DATASTR
, " Channel(s):: <none>");
338 else if (acptr
->cli_user
->joined
> 50) {
340 /* NB. As a sanity check, we DO NOT show the individual channels the
341 * client is on if it is on > 50 channels. This is to prevent the ircd
342 * barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine
343 * an Oper would want to see every single channel 'x' client is on anyway if
344 * they are on *that* many).
347 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Channel(s):: - (total: %u)", acptr
->cli_user
->joined
);
348 send_reply(sptr
, RPL_DATASTR
, outbuf
);
351 char chntext
[BUFSIZE
];
352 int len
= strlen(" Channel(s):: ");
353 int mlen
= strlen(me
.cli_name
) + len
+ strlen(sptr
->cli_name
);
356 strcpy(chntext
, " Channel(s):: ");
357 for (lp
= acptr
->cli_user
->channel
; lp
; lp
= lp
->next_channel
) {
359 if (len
+ strlen(chptr
->chname
) + mlen
> BUFSIZE
- 5) {
360 send_reply(sptr
, RPL_DATASTR
, chntext
);
362 strcpy(chntext
, " Channel(s):: ");
363 len
= strlen(chntext
);
366 *(chntext
+ len
++) = '-';
367 if (is_chan_op(acptr
, chptr
))
368 *(chntext
+ len
++) = '@';
369 else if (has_voice(acptr
, chptr
))
370 *(chntext
+ len
++) = '+';
371 else if (IsZombie(lp
))
372 *(chntext
+ len
++) = '!';
374 *(chntext
+ len
) = '\0';
376 strcpy(chntext
+ len
, chptr
->chname
);
377 len
+= strlen(chptr
->chname
);
378 strcat(chntext
+ len
, " ");
382 if (chntext
[0] != '\0')
383 send_reply(sptr
, RPL_DATASTR
, chntext
);
386 /* If client processing command ISN'T target (or a registered
387 * Network Service), show idle time since the last time we
390 if (MyUser(acptr
) && !(IsService(acptr
) == -1) && !(strCasediff(acptr
->cli_name
, sptr
->cli_name
) == 0)) {
391 nowr
= CurrentTime
- acptr
->cli_user
->last
;
392 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Idle for:: %d days, %02ld:%02ld:%02ld",
393 nowr
/ 86400, (nowr
/ 3600) % 24, (nowr
/ 60) % 60, nowr
% 60);
394 send_reply(sptr
, RPL_DATASTR
, outbuf
);
397 /* Away message (if applicable) */
398 if (acptr
->cli_user
->away
) {
399 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Away message:: %s", acptr
->cli_user
->away
);
400 send_reply(sptr
, RPL_DATASTR
, outbuf
);
403 /* If local user.. */
405 os_get_peername(con_fd(cli_connect(sptr
)), &sin
);
407 send_reply(sptr
, RPL_DATASTR
, " ");
408 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Ports:: %d -> %d (client -> server)",
409 sin
.port
, cli_listener(acptr
)->addr
.port
);
410 send_reply(sptr
, RPL_DATASTR
, outbuf
);
411 if (feature_bool(FEAT_EXTENDED_CHECKCMD
)) {
412 /* Note: sendq = receiveq for a client (it makes sense really) */
413 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Data sent:: %lu.%0.3u Kb (%u protocol messages)",
414 (unsigned long)cli_receiveB(acptr
) / 1024, (unsigned long)cli_receiveB(acptr
) % 1024, cli_receiveM(acptr
));
415 send_reply(sptr
, RPL_DATASTR
, outbuf
);
416 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Data received:: %lu.%0.3lu Kb (%u protocol messages)",
417 (unsigned long)cli_sendB(acptr
) / 1024, (unsigned long)cli_sendB(acptr
) % 1024, cli_sendM(acptr
));
418 send_reply(sptr
, RPL_DATASTR
, outbuf
);
419 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " receiveQ size:: %d bytes (max. %d bytes)",
420 DBufLength(&(cli_recvQ(acptr
))), feature_int(FEAT_CLIENT_FLOOD
));
421 send_reply(sptr
, RPL_DATASTR
, outbuf
);
422 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " sendQ size:: %d bytes (max. %d bytes)",
423 DBufLength(&(cli_sendQ(acptr
))), get_sendq(acptr
));
424 send_reply(sptr
, RPL_DATASTR
, outbuf
);
428 /* Send 'END OF CHECK' message */
429 send_reply(sptr
, RPL_ENDOFCHECK
, " ");
432 void checkServer(struct Client
*sptr
, struct Client
*acptr
) {
433 char outbuf
[BUFSIZE
];
436 send_reply(sptr
, RPL_DATASTR
, " ");
437 send_reply(sptr
, RPL_CHKHEAD
, "server", acptr
->cli_name
);
438 send_reply(sptr
, RPL_DATASTR
, " ");
440 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Connected at:: %s", myctime(acptr
->cli_serv
->timestamp
));
441 send_reply(sptr
, RPL_DATASTR
, outbuf
);
443 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Server name:: %s", acptr
->cli_name
);
444 send_reply(sptr
, RPL_DATASTR
, outbuf
);
446 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Numeric:: %s --> %d", NumServ(acptr
), base64toint(acptr
->cli_yxx
));
447 send_reply(sptr
, RPL_DATASTR
, outbuf
);
449 ircd_snprintf(0, outbuf
, sizeof(outbuf
), " Users:: %d / %d", cli_serv(acptr
)->clients
,
450 base64toint(cli_serv(acptr
)->nn_capacity
));
451 send_reply(sptr
, RPL_DATASTR
, outbuf
);
454 send_reply(sptr
, RPL_DATASTR
, " Status:: Bursting");
455 else if (IsBurstAck(acptr
))
456 send_reply(sptr
, RPL_DATASTR
, " Status:: Awaiting EOB Ack");
457 else if (IsService(acptr
))
458 send_reply(sptr
, RPL_DATASTR
, " Status:: Network Service");
459 else if (IsHub(acptr
))
460 send_reply(sptr
, RPL_DATASTR
, " Status:: Network Hub");
462 if (feature_bool(FEAT_EXTENDED_CHECKCMD
)) {
464 struct DLink
* slink
= NULL
;
466 send_reply(sptr
, RPL_DATASTR
, " ");
467 send_reply(sptr
, RPL_DATASTR
, "Downlinks::");
468 for (slink
= cli_serv(acptr
)->down
; slink
; slink
= slink
->next
) {
469 ircd_snprintf(0, outbuf
, sizeof(outbuf
), "[%d] - %s%s", ++dlinkc
,
470 IsBurst(slink
->value
.cptr
) ? "*" : IsBurstAck(slink
->value
.cptr
) ? "!" : IsService(slink
->value
.cptr
) ? "=" : IsHub(slink
->value
.cptr
) ? "+" : " ",
471 cli_name(slink
->value
.cptr
));
472 send_reply(sptr
, RPL_DATASTR
, outbuf
);
476 send_reply(sptr
, RPL_DATASTR
, "<none>");
479 /* Send 'END OF CHECK' message */
480 send_reply(sptr
, RPL_ENDOFCHECK
, " ");
483 signed int checkHostmask(struct Client
*sptr
, char *hoststr
, int flags
) {
484 struct Client
*acptr
;
485 struct Channel
*chptr
;
486 struct Membership
*lp
;
487 int count
= 0, found
= 0;
488 char outbuf
[BUFSIZE
];
489 char targhost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 3], curhost
[NICKLEN
+ USERLEN
+ HOSTLEN
+ 3];
490 char nickm
[NICKLEN
+ 1], userm
[USERLEN
+ 1], hostm
[HOSTLEN
+ 1];
492 struct irc_in_addr cidr_check
;
493 char cidr_check_bits
;
499 if (!strchr(hoststr
, '!') && !strchr(hoststr
, '@'))
500 ircd_strncpy(hostm
,hoststr
,HOSTLEN
);
502 if (p
= strchr(hoststr
, '@')) {
504 if (*p
) ircd_strncpy(hostm
,p
, HOSTLEN
);
507 /* Get the nick!user mask */
508 if (p
= strchr(hoststr
, '!')) {
510 if (*p
) ircd_strncpy(userm
,p
,USERLEN
);
511 if (*hoststr
) ircd_strncpy(nickm
,hoststr
,NICKLEN
);
514 /* Durz: We should only do the following *IF* the hoststr has not already been
515 * copied into hostm (ie. neither ! or @ specified).. otherwise, when we do
516 * /quote check *.barrysworld.com - we end up with targhost as: *!*.barryswo@*.barrysworld.com
518 ircd_strncpy(userm
,hoststr
,USERLEN
);
522 if (ipmask_parse(hostm
, &cidr_check
, &cidr_check_bits
) != 0) {
523 flags
|= CHECK_CIDRMASK
;
526 /*if ((p = strchr(hostm, '/')) || inet_aton(hostm, &cidr_check)) {
529 if (inet_aton(hostm, &cidr_check)) {
530 cidr_check_bits = p ? atoi(p + 1) : 32;
531 if ((cidr_check_bits >= 0) && (cidr_check_bits <= 32)) {
532 flags |= CHECK_CIDRMASK;
533 cidr_check.s_addr &= NETMASK(cidr_check_bits);
540 /* Copy formatted string into "targhost" buffer */
541 ircd_snprintf(0, targhost
, sizeof(targhost
), "%s!%s@%s", nickm
, userm
, hostm
);
543 targhost
[sizeof(targhost
) - 1] = '\0';
545 /* Note: we have to exclude the last client struct as it is not a real client
546 * structure, and therefore any attempt to access elements in it would cause
550 for (acptr
= GlobalClientList
; acptr
; acptr
= cli_next(acptr
)) {
551 /* Dont process if acptr is a unregistered client, a server or a ping */
552 if (!IsRegistered(acptr
) || IsServer(acptr
))
555 if (IsMe(acptr
)) /* Always the last acptr record */
558 if(count
> 500) { /* sanity stuff */
559 send_reply(sptr
, RPL_ENDOFCHECK
, " ");
563 /* Copy host info into buffer */
565 ircd_snprintf(0, curhost
, sizeof(curhost
), "%s!%s@%s", acptr
->cli_name
, acptr
->cli_user
->realusername
, acptr
->cli_user
->realhost
);
567 if (flags
& CHECK_CIDRMASK
) {
568 if (ipmask_check(&cli_ip(acptr
), &cidr_check
, cidr_check_bits
) && !match(nickm
, acptr
->cli_name
)
569 && (!match(userm
, acptr
->cli_user
->realusername
) || !match(userm
, acptr
->cli_user
->username
)))
573 if(match((const char*)targhost
,(const char*)curhost
) == 0)
577 ircd_snprintf(0, curhost
, sizeof(curhost
), "%s!%s@%s", acptr
->cli_name
, acptr
->cli_user
->username
, acptr
->cli_user
->host
);
579 if(match((const char*)targhost
,(const char*)curhost
) == 0)
585 found
= 0; /* reset that so it doesn't get crazy go nuts */
587 /* Show header if we've found at least 1 record */
590 send_reply(sptr
, RPL_DATASTR
, " ");
591 send_reply(sptr
, RPL_CHKHEAD
, "host", targhost
);
593 send_reply(sptr
, RPL_DATASTR
, " ");
594 ircd_snprintf(0, outbuf
, sizeof(outbuf
), "%s %-*s%-*s%s", "No.", (NICKLEN
+ 2 ), "Nick",
595 (USERLEN
+ 2), "User", "Host");
596 send_reply(sptr
, RPL_DATASTR
, outbuf
);
599 ircd_snprintf(0, outbuf
, sizeof(outbuf
), "%-4d %-*s%-*s%s", (count
+1), (NICKLEN
+ 2),
600 acptr
->cli_name
, (USERLEN
+ 2), acptr
->cli_user
->realusername
,
601 (flags
& CHECK_SHOWIPS
) ? ircd_ntoa(&(cli_ip(acptr
))) : acptr
->cli_user
->realhost
);
602 send_reply(sptr
, RPL_DATASTR
, outbuf
);
604 /* Show channel output (if applicable) - the 50 channel limit sanity check
605 * is specifically to prevent coredumping when someone lamely tries to /check
606 * Q or some other channel service...
608 if (flags
& CHECK_CHECKCHAN
) {
609 if (acptr
->cli_user
->joined
> 0 && acptr
->cli_user
->joined
<= 50) {
610 char chntext
[BUFSIZE
];
611 int len
= strlen(" on channels: ");
612 int mlen
= strlen(me
.cli_name
) + len
+ strlen(sptr
->cli_name
);
615 strcpy(chntext
, " on channels: ");
616 for (lp
= acptr
->cli_user
->channel
; lp
; lp
= lp
->next_channel
) {
618 if (len
+ strlen(chptr
->chname
) + mlen
> BUFSIZE
- 5) {
619 send_reply(sptr
, RPL_DATASTR
, chntext
);
621 strcpy(chntext
, " on channels: ");
622 len
= strlen(chntext
);
625 *(chntext
+ len
++) = '-';
626 if (is_chan_op(acptr
, chptr
))
627 *(chntext
+ len
++) = '@';
628 else if (has_voice(acptr
, chptr
))
629 *(chntext
+ len
++) = '+';
630 else if (IsZombie(lp
))
631 *(chntext
+ len
++) = '!';
633 *(chntext
+ len
) = '\0';
635 strcpy(chntext
+ len
, chptr
->chname
);
636 len
+= strlen(chptr
->chname
);
637 strcat(chntext
+ len
, " ");
640 if (chntext
[0] != '\0')
641 send_reply(sptr
, RPL_DATASTR
, chntext
);
643 send_reply(sptr
, RPL_DATASTR
, " ");
651 send_reply(sptr
, RPL_DATASTR
, " ");
653 ircd_snprintf(0, outbuf
, sizeof(outbuf
), "Matching records found:: %d", count
);
654 send_reply(sptr
, RPL_DATASTR
, outbuf
);
656 send_reply(sptr
, RPL_ENDOFCHECK
, " ");