]> jfr.im git - irc/quakenet/snircd.git/blame - ircd/m_check.c
add sbounce from asuka into snircd tree
[irc/quakenet/snircd.git] / ircd / m_check.c
CommitLineData
f4a888ca 1/*
2 * IRC - Internet Relay Chat, ircd/m_check.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
5 *
6 * See file AUTHORS in IRC package for additional names of
7 * the programmers.
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 1, or (at your option)
12 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include "channel.h"
25#include "check.h"
26#include "client.h"
27#include "hash.h"
28#include "ircd.h"
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"
caa12862 35#include "ircd_osdep.h"
f4a888ca 36#include "list.h"
37#include "listener.h"
38#include "match.h"
39#include "numeric.h"
40#include "numnicks.h"
41#include "querycmds.h"
42#include "send.h"
43#include "s_user.h"
44#include "s_debug.h"
45
46#include <string.h>
47
48#define CHECK_CHECKCHAN 0x01 /* -c */
49#define CHECK_SHOWUSERS 0x02 /* ! -u */
50#define CHECK_OPSONLY 0x04 /* -o */
51#define CHECK_SHOWIPS 0x08 /* -i */
52#define CHECK_CIDRMASK 0x10 /* automatically detected when performing a hostmask /CHECK */
53
54/*
55 * - ASUKA ---------------------------------------------------------------------
56 * This is the implimentation of the CHECK function for Asuka.
57 * Some of this code is from previous QuakeNet ircds, but most of it is mine..
58 * The old code was written by Durzel (durzel@quakenet.org).
59 *
60 * qoreQ (qoreQ@quakenet.org) - 08/14/2002
61 * -----------------------------------------------------------------------------
62 */
63
64/*
65 * Syntax: CHECK <channel|nick|server|hostmask> [-flags]
66 *
67 * Where valid flags are:
68 * -c: Show channels when checking a hostmask.
69 * -i: Show IPs instead of hostnames when displaying results.
70 * -o: Only show channel operators when checking a channel.
71 * -u: Hide users when checking a channel.
72 *
73 * <hostmask> can be of the form host, user@host, nick!user@host,
74 * with host being host.domain.cc, 127.0.0.1 or 127.0.0.0/24.
75 * Wildcards are supported.
76 */
77
78int m_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
79 struct Channel *chptr;
80 struct Client *acptr;
81 char *param;
82 int flags = CHECK_SHOWUSERS, i;
83
84 if (parc < 2) {
85 send_reply(sptr, ERR_NEEDMOREPARAMS, "CHECK");
86 return 0;
87 }
88
89 /* This checks to see if any flags have been supplied */
90 if ((parc >= 3) && (parv[2][0] == '-')) {
91 for (i = 0; parv[2][i]; i++) {
92 switch (parv[2][i]) {
93 case 'c':
94 flags |= CHECK_CHECKCHAN;
95 break;
96
97 case 'o':
98 flags |= CHECK_OPSONLY; /* fall through */
99 case 'u':
100 flags &= ~(CHECK_SHOWUSERS);
101 break;
102
103 case 'i':
104 flags |= CHECK_SHOWIPS;
105 break;
106
107 default:
108 /* might want to raise some sort of error here? */
109 break;
110 }
111 }
112 }
113
114 if (IsChannelName(parv[1])) { /* channel */
115 if ((chptr = FindChannel(parv[1]))) {
116 checkChannel(sptr, chptr);
117 checkUsers(sptr, chptr, flags);
118 }
119 else
120 send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
121 }
122 else if ((acptr = FindClient(parv[1])) && !(FindServer(parv[1]))) { /* client and not a server */
123 if (!IsRegistered(acptr)) {
124 send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
125 return 0;
126 }
127
128 checkClient(sptr, acptr);
129 }
130 else if ((acptr = FindServer(parv[1]))) { /* server */
131 checkServer(sptr, acptr);
132 }
133 else if (checkHostmask(sptr, parv[1], flags) > 0) /* hostmask */
134 return 1;
135 else /* no match */
136 send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
137
138 return 1;
139}
140
141static int checkClones(struct Channel *chptr, char *nick, char *host) {
142 int clones = 0;
143 struct Membership *lp;
144 struct Client *acptr;
145
146 for (lp = chptr->members; lp; lp = lp->next_member) {
147 acptr = lp->user;
148 if (!strcmp(acptr->cli_user->realhost, host) && strcmp(acptr->cli_name, nick)) {
149 /* this is a clone */
150 clones++;
151 }
152 }
153
154 return ((clones) ? clones + 1 : 0);
155}
156
157void checkUsers(struct Client *sptr, struct Channel *chptr, int flags) {
158 struct Membership *lp;
159 struct Ban *ban;
160 struct Client *acptr;
161
162 char outbuf[BUFSIZE], ustat[64];
163 int cntr = 0, opcntr = 0, vcntr = 0, clones = 0, bans = 0, c = 0, authed = 0;
164
165 if (flags & CHECK_SHOWUSERS) send_reply(sptr, RPL_DATASTR, "Users (@ = op, + = voice)");
166
167 for (lp = chptr->members; lp; lp = lp->next_member) {
168 int opped = 0;
169
170 acptr = lp->user;
171
172 if ((c = checkClones(chptr, acptr->cli_name, acptr->cli_user->realhost)) != 0) {
173 ircd_snprintf(0, ustat, sizeof(ustat), "%2d ", c);
174 clones++;
175 }
176 else
177 strcpy(ustat, " ");
178
179 if (chptr && is_chan_op(acptr, chptr)) {
180 strcat(ustat, "@");
181 opcntr++;
182 opped = 1;
183 }
184 else if (chptr && has_voice(acptr, chptr)) {
185 strcat(ustat, "+");
186 vcntr++;
187 }
188 else
189 strcat(ustat, " ");
190
191 if ((c = IsAccount(acptr)) != 0) ++authed;
192
193 if ((flags & CHECK_SHOWUSERS) || ((flags & CHECK_OPSONLY) && opped)) {
194 ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%c", acptr->cli_info, COLOR_OFF);
195 send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, acptr->cli_user->realusername,
196 (flags & CHECK_SHOWIPS) ? ircd_ntoa(&(cli_ip(acptr))) : acptr->cli_user->realhost, outbuf,
197 (c ? acptr->cli_user->account : ""));
198 }
199
200 cntr++;
201 }
202
203 send_reply(sptr, RPL_DATASTR, " ");
204
205 ircd_snprintf(0, outbuf, sizeof(outbuf),
206 "Total users:: %d (%d ops, %d voiced, %d clones, %d authed)",
207 cntr, opcntr, vcntr, clones, authed);
208
209 send_reply(sptr, RPL_DATASTR, outbuf);
210
211 send_reply(sptr, RPL_DATASTR, " ");
212
213 /* Do not display bans if ! flags & CHECK_SHOWUSERS */
214 if (!(flags & CHECK_SHOWUSERS)) {
215 send_reply(sptr, RPL_ENDOFCHECK, " ");
216 return;
217 }
218
219 /* Bans */
220 send_reply(sptr, RPL_DATASTR, "Bans on channel::");
221
222 for (ban = chptr->banlist; ban; ban = ban->next) {
223 ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s - Set by %s, on %s",
224 ++bans, ban->banstr, ban->who, myctime(ban->when));
225 send_reply(sptr, RPL_DATASTR, outbuf);
226 }
227
228 if (bans == 0)
229 send_reply(sptr, RPL_DATASTR, "<none>");
230
231 send_reply(sptr, RPL_ENDOFCHECK, " ");
232}
233
234void checkChannel(struct Client *sptr, struct Channel *chptr) {
235 char outbuf[TOPICLEN + MODEBUFLEN + 64], modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
236
237 /* Header */
238 send_reply(sptr, RPL_DATASTR, " ");
239 send_reply(sptr, RPL_CHKHEAD, "channel", chptr->chname);
240 send_reply(sptr, RPL_DATASTR, " ");
241
242 /* Creation Time */
243 ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Creation time:: %s", myctime(chptr->creationtime));
244 send_reply(sptr, RPL_DATASTR, outbuf);
245
246 /* Topic */
247 if (strlen(chptr->topic) <= 0)
248 send_reply(sptr, RPL_DATASTR, " Topic:: <none>");
249 else {
250 ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Topic:: %s", chptr->topic);
251 send_reply(sptr, RPL_DATASTR, outbuf);
252
253 /* ..set by */
254 ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Set by:: %s", chptr->topic_nick);
255 send_reply(sptr, RPL_DATASTR, outbuf);
256 }
257
258 /* Channel Modes */
259
260 strcpy(outbuf, "Channel mode(s):: ");
261
262 modebuf[0] = '\0';
263 parabuf[0] = '\0';
264
265 channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr, NULL);
266
267 if(modebuf[1] == '\0')
268 strcat(outbuf, "<none>");
269 else if(*parabuf) {
270 strcat(outbuf, modebuf);
271 strcat(outbuf, " ");
272 strcat(outbuf, parabuf);
273 }
274 else
275 strcat(outbuf, modebuf);
276
277 send_reply(sptr, RPL_DATASTR, outbuf);
278
279 /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */
280}
281
282void checkClient(struct Client *sptr, struct Client *acptr) {
283 struct Channel *chptr;
284 struct Membership *lp;
285 struct irc_sockaddr sin;
286 char outbuf[BUFSIZE];
287 time_t nowr;
288
289 /* Header */
290 send_reply(sptr, RPL_DATASTR, " ");
291 send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name);
292 send_reply(sptr, RPL_DATASTR, " ");
293
294 ircd_snprintf(0, outbuf, sizeof(outbuf), " Nick:: %s (%s%s)", acptr->cli_name, NumNick(acptr));
295 send_reply(sptr, RPL_DATASTR, outbuf);
296
297 if (MyUser(acptr)) {
298 ircd_snprintf(0, outbuf, sizeof(outbuf), " Signed on:: %s", myctime(acptr->cli_firsttime));
299 send_reply(sptr, RPL_DATASTR, outbuf);
300 }
301
302 ircd_snprintf(0, outbuf, sizeof(outbuf), " Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick);
303 send_reply(sptr, RPL_DATASTR, outbuf);
304
305 ircd_snprintf(0, outbuf, sizeof(outbuf), " User/Hostmask:: %s@%s (%s)", acptr->cli_user->username, acptr->cli_user->host,
306 ircd_ntoa(&(cli_ip(acptr))));
307 send_reply(sptr, RPL_DATASTR, outbuf);
308
309 if (IsSetHost(acptr) || IsAccount(acptr)) {
310 ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", acptr->cli_user->realusername, acptr->cli_user->realhost);
311 send_reply(sptr, RPL_DATASTR, outbuf);
312 }
313
314 ircd_snprintf(0, outbuf, sizeof(outbuf), " Real Name:: %s%c", cli_info(acptr), COLOR_OFF);
315 send_reply(sptr, RPL_DATASTR, outbuf);
316
317 if (IsService(acptr) == -1)
318 send_reply(sptr, RPL_DATASTR, " Status:: Network Service");
319 else if (IsAnOper(acptr))
320 send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator");
321
322 ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected to:: %s", cli_name(acptr->cli_user->server));
323 send_reply(sptr, RPL_DATASTR, outbuf);
324
325 /* +s (SERV_NOTICE) is not relayed to us from remote servers,
326 * so we cannot tell if a remote client has that mode set.
327 * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG
328 * (and breaks if the user is +r) so we won't do that either.
329 */
330
331 if (strlen(umode_str(acptr)) < 1)
332 strcpy(outbuf, " Umode(s):: <none>");
333 else
334 ircd_snprintf(0, outbuf, sizeof(outbuf), " Umode(s):: +%s", umode_str(acptr));
335 send_reply(sptr, RPL_DATASTR, outbuf);
336
337 if (acptr->cli_user->joined == 0)
338 send_reply(sptr, RPL_DATASTR, " Channel(s):: <none>");
339 else if (acptr->cli_user->joined > 50) {
340
341 /* NB. As a sanity check, we DO NOT show the individual channels the
342 * client is on if it is on > 50 channels. This is to prevent the ircd
343 * barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine
344 * an Oper would want to see every single channel 'x' client is on anyway if
345 * they are on *that* many).
346 */
347
348 ircd_snprintf(0, outbuf, sizeof(outbuf), " Channel(s):: - (total: %u)", acptr->cli_user->joined);
349 send_reply(sptr, RPL_DATASTR, outbuf);
350 }
351 else {
352 char chntext[BUFSIZE];
353 int len = strlen(" Channel(s):: ");
354 int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
355 *chntext = '\0';
356
357 strcpy(chntext, " Channel(s):: ");
358 for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
359 chptr = lp->channel;
360 if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
361 send_reply(sptr, RPL_DATASTR, chntext);
362 *chntext = '\0';
363 strcpy(chntext, " Channel(s):: ");
364 len = strlen(chntext);
365 }
366 if (IsDeaf(acptr))
367 *(chntext + len++) = '-';
368 if (is_chan_op(acptr, chptr))
369 *(chntext + len++) = '@';
370 else if (has_voice(acptr, chptr))
371 *(chntext + len++) = '+';
372 else if (IsZombie(lp))
373 *(chntext + len++) = '!';
374 if (len)
375 *(chntext + len) = '\0';
376
377 strcpy(chntext + len, chptr->chname);
378 len += strlen(chptr->chname);
379 strcat(chntext + len, " ");
380 len++;
381 }
382
383 if (chntext[0] != '\0')
384 send_reply(sptr, RPL_DATASTR, chntext);
385 }
386
387 /* If client processing command ISN'T target (or a registered
388 * Network Service), show idle time since the last time we
389 * parsed something.
390 */
391 if (MyUser(acptr) && !(IsService(acptr) == -1) && !(strCasediff(acptr->cli_name, sptr->cli_name) == 0)) {
392 nowr = CurrentTime - acptr->cli_user->last;
393 ircd_snprintf(0, outbuf, sizeof(outbuf), " Idle for:: %d days, %02ld:%02ld:%02ld",
394 nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
395 send_reply(sptr, RPL_DATASTR, outbuf);
396 }
397
398 /* Away message (if applicable) */
399 if (acptr->cli_user->away) {
400 ircd_snprintf(0, outbuf, sizeof(outbuf), " Away message:: %s", acptr->cli_user->away);
401 send_reply(sptr, RPL_DATASTR, outbuf);
402 }
403
404 /* If local user.. */
405 if (MyUser(acptr)) {
406 os_get_peername(con_fd(cli_connect(sptr)), &sin);
407
408 send_reply(sptr, RPL_DATASTR, " ");
409 ircd_snprintf(0, outbuf, sizeof(outbuf), " Ports:: %d -> %d (client -> server)",
410 sin.port, cli_listener(acptr)->addr.port);
411 send_reply(sptr, RPL_DATASTR, outbuf);
412 if (feature_bool(FEAT_EXTENDED_CHECKCMD)) {
413 /* Note: sendq = receiveq for a client (it makes sense really) */
414 ircd_snprintf(0, outbuf, sizeof(outbuf), " Data sent:: %lu.%0.3u Kb (%u protocol messages)",
415 (unsigned long)cli_receiveB(acptr) / 1024, (unsigned long)cli_receiveB(acptr) % 1024, cli_receiveM(acptr));
416 send_reply(sptr, RPL_DATASTR, outbuf);
417 ircd_snprintf(0, outbuf, sizeof(outbuf), " Data received:: %lu.%0.3lu Kb (%u protocol messages)",
418 (unsigned long)cli_sendB(acptr) / 1024, (unsigned long)cli_sendB(acptr) % 1024, cli_sendM(acptr));
419 send_reply(sptr, RPL_DATASTR, outbuf);
420 ircd_snprintf(0, outbuf, sizeof(outbuf), " receiveQ size:: %d bytes (max. %d bytes)",
421 DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD));
422 send_reply(sptr, RPL_DATASTR, outbuf);
423 ircd_snprintf(0, outbuf, sizeof(outbuf), " sendQ size:: %d bytes (max. %d bytes)",
424 DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr));
425 send_reply(sptr, RPL_DATASTR, outbuf);
426 }
427 }
428
429 /* Send 'END OF CHECK' message */
430 send_reply(sptr, RPL_ENDOFCHECK, " ");
431}
432
433void checkServer(struct Client *sptr, struct Client *acptr) {
434 char outbuf[BUFSIZE];
435
436 /* Header */
437 send_reply(sptr, RPL_DATASTR, " ");
438 send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name);
439 send_reply(sptr, RPL_DATASTR, " ");
440
441 ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected at:: %s", myctime(acptr->cli_serv->timestamp));
442 send_reply(sptr, RPL_DATASTR, outbuf);
443
444 ircd_snprintf(0, outbuf, sizeof(outbuf), " Server name:: %s", acptr->cli_name);
445 send_reply(sptr, RPL_DATASTR, outbuf);
446
447 ircd_snprintf(0, outbuf, sizeof(outbuf), " Numeric:: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx));
448 send_reply(sptr, RPL_DATASTR, outbuf);
449
9826eca0 450 ircd_snprintf(0, outbuf, sizeof(outbuf), " Users:: %d / %d", (acptr == &me) ? UserStats.local_clients : cli_serv(acptr)->clients,
f4a888ca 451 base64toint(cli_serv(acptr)->nn_capacity));
452 send_reply(sptr, RPL_DATASTR, outbuf);
453
454 if (IsBurst(acptr))
455 send_reply(sptr, RPL_DATASTR, " Status:: Bursting");
456 else if (IsBurstAck(acptr))
457 send_reply(sptr, RPL_DATASTR, " Status:: Awaiting EOB Ack");
458 else if (IsService(acptr))
459 send_reply(sptr, RPL_DATASTR, " Status:: Network Service");
460 else if (IsHub(acptr))
461 send_reply(sptr, RPL_DATASTR, " Status:: Network Hub");
462
463 if (feature_bool(FEAT_EXTENDED_CHECKCMD)) {
464 int dlinkc = 0;
465 struct DLink* slink = NULL;
466
467 send_reply(sptr, RPL_DATASTR, " ");
468 send_reply(sptr, RPL_DATASTR, "Downlinks::");
469 for (slink = cli_serv(acptr)->down; slink; slink = slink->next) {
470 ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc,
471 IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" : IsService(slink->value.cptr) ? "=" : IsHub(slink->value.cptr) ? "+" : " ",
472 cli_name(slink->value.cptr));
473 send_reply(sptr, RPL_DATASTR, outbuf);
474 }
475
476 if (!dlinkc)
477 send_reply(sptr, RPL_DATASTR, "<none>");
478 }
479
480 /* Send 'END OF CHECK' message */
481 send_reply(sptr, RPL_ENDOFCHECK, " ");
482}
483
484signed int checkHostmask(struct Client *sptr, char *hoststr, int flags) {
485 struct Client *acptr;
486 struct Channel *chptr;
487 struct Membership *lp;
488 int count = 0, found = 0;
489 char outbuf[BUFSIZE];
490 char targhost[NICKLEN + USERLEN + HOSTLEN + 3], curhost[NICKLEN + USERLEN + HOSTLEN + 3];
491 char nickm[NICKLEN + 1], userm[USERLEN + 1], hostm[HOSTLEN + 1];
492 char *p = NULL;
493 struct irc_in_addr cidr_check;
494 char cidr_check_bits;
495
496 strcpy(nickm,"*");
497 strcpy(userm,"*");
498 strcpy(hostm,"*");
499
500 if (!strchr(hoststr, '!') && !strchr(hoststr, '@'))
501 ircd_strncpy(hostm,hoststr,HOSTLEN);
502 else {
503 if (p = strchr(hoststr, '@')) {
504 *p++ = '\0';
505 if (*p) ircd_strncpy(hostm,p, HOSTLEN);
506 }
507
508 /* Get the nick!user mask */
509 if (p = strchr(hoststr, '!')) {
510 *p++ = '\0';
511 if (*p) ircd_strncpy(userm,p,USERLEN);
512 if (*hoststr) ircd_strncpy(nickm,hoststr,NICKLEN);
513 }
514 else if (*hoststr) {
515 /* Durz: We should only do the following *IF* the hoststr has not already been
516 * copied into hostm (ie. neither ! or @ specified).. otherwise, when we do
517 * /quote check *.barrysworld.com - we end up with targhost as: *!*.barryswo@*.barrysworld.com
518 */
519 ircd_strncpy(userm,hoststr,USERLEN);
520 }
521 }
522
523 if (ipmask_parse(hostm, &cidr_check, &cidr_check_bits) != 0) {
524 flags |= CHECK_CIDRMASK;
525 }
526
527 /*if ((p = strchr(hostm, '/')) || inet_aton(hostm, &cidr_check)) {
528 if (p)
529 *p = '\0';
530 if (inet_aton(hostm, &cidr_check)) {
531 cidr_check_bits = p ? atoi(p + 1) : 32;
532 if ((cidr_check_bits >= 0) && (cidr_check_bits <= 32)) {
533 flags |= CHECK_CIDRMASK;
534 cidr_check.s_addr &= NETMASK(cidr_check_bits);
535 }
536 }
537 if (p)
538 *p = '/';
539 }*/
540
541 /* Copy formatted string into "targhost" buffer */
542 ircd_snprintf(0, targhost, sizeof(targhost), "%s!%s@%s", nickm, userm, hostm);
543
544 targhost[sizeof(targhost) - 1] = '\0';
545
546 /* Note: we have to exclude the last client struct as it is not a real client
547 * structure, and therefore any attempt to access elements in it would cause
548 * a segfault.
549 */
550
551 for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
552 /* Dont process if acptr is a unregistered client, a server or a ping */
553 if (!IsRegistered(acptr) || IsServer(acptr))
554 continue;
555
556 if (IsMe(acptr)) /* Always the last acptr record */
557 break;
558
559 if(count > 500) { /* sanity stuff */
560 send_reply(sptr, RPL_ENDOFCHECK, " ");
561 break;
562 }
563
564 /* Copy host info into buffer */
565 curhost[0] = '\0';
566 ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->realusername, acptr->cli_user->realhost);
567
568 if (flags & CHECK_CIDRMASK) {
569 if (ipmask_check(&cli_ip(acptr), &cidr_check, cidr_check_bits) && !match(nickm, acptr->cli_name)
570 && (!match(userm, acptr->cli_user->realusername) || !match(userm, acptr->cli_user->username)))
571 found = 1;
572 }
573 else {
574 if(match((const char*)targhost,(const char*)curhost) == 0)
575 found = 1;
576 else {
577 curhost[0] = '\0';
578 ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->username, acptr->cli_user->host);
579
580 if(match((const char*)targhost,(const char*)curhost) == 0)
581 found = 1;
582 }
583 }
584
585 if (found == 1) {
586 found = 0; /* reset that so it doesn't get crazy go nuts */
587
588 /* Show header if we've found at least 1 record */
589 if (count == 0) {
590 /* Output header */
591 send_reply(sptr, RPL_DATASTR, " ");
592 send_reply(sptr, RPL_CHKHEAD, "host", targhost);
593
594 send_reply(sptr, RPL_DATASTR, " ");
595 ircd_snprintf(0, outbuf, sizeof(outbuf), "%s %-*s%-*s%s", "No.", (NICKLEN + 2 ), "Nick",
596 (USERLEN + 2), "User", "Host");
597 send_reply(sptr, RPL_DATASTR, outbuf);
598 }
599
600 ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d %-*s%-*s%s", (count+1), (NICKLEN + 2),
601 acptr->cli_name, (USERLEN + 2), acptr->cli_user->realusername,
602 (flags & CHECK_SHOWIPS) ? ircd_ntoa(&(cli_ip(acptr))) : acptr->cli_user->realhost);
603 send_reply(sptr, RPL_DATASTR, outbuf);
604
605 /* Show channel output (if applicable) - the 50 channel limit sanity check
606 * is specifically to prevent coredumping when someone lamely tries to /check
607 * Q or some other channel service...
608 */
609 if (flags & CHECK_CHECKCHAN) {
610 if (acptr->cli_user->joined > 0 && acptr->cli_user->joined <= 50) {
611 char chntext[BUFSIZE];
612 int len = strlen(" on channels: ");
613 int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
614 *chntext = '\0';
615
616 strcpy(chntext, " on channels: ");
617 for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
618 chptr = lp->channel;
619 if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
620 send_reply(sptr, RPL_DATASTR, chntext);
621 *chntext = '\0';
622 strcpy(chntext, " on channels: ");
623 len = strlen(chntext);
624 }
625 if (IsDeaf(acptr))
626 *(chntext + len++) = '-';
627 if (is_chan_op(acptr, chptr))
628 *(chntext + len++) = '@';
629 else if (has_voice(acptr, chptr))
630 *(chntext + len++) = '+';
631 else if (IsZombie(lp))
632 *(chntext + len++) = '!';
633 if (len)
634 *(chntext + len) = '\0';
635
636 strcpy(chntext + len, chptr->chname);
637 len += strlen(chptr->chname);
638 strcat(chntext + len, " ");
639 len++;
640 }
641 if (chntext[0] != '\0')
642 send_reply(sptr, RPL_DATASTR, chntext);
643
644 send_reply(sptr, RPL_DATASTR, " ");
645 }
646 }
647 count++;
648 }
649 }
650
651 if (count > 0) {
652 send_reply(sptr, RPL_DATASTR, " ");
653
654 ircd_snprintf(0, outbuf, sizeof(outbuf), "Matching records found:: %d", count);
655 send_reply(sptr, RPL_DATASTR, outbuf);
656
657 send_reply(sptr, RPL_ENDOFCHECK, " ");
658 }
659
660 return count;
661}