]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/m_check.c
fixed autochanmodes code so it works for channel modes +CN
[irc/quakenet/snircd.git] / ircd / m_check.c
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"
35 #include "list.h"
36 #include "listener.h"
37 #include "match.h"
38 #include "numeric.h"
39 #include "numnicks.h"
40 #include "querycmds.h"
41 #include "send.h"
42 #include "s_user.h"
43 #include "s_debug.h"
44
45 #include <string.h>
46
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 */
52
53 /*
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).
58 *
59 * qoreQ (qoreQ@quakenet.org) - 08/14/2002
60 * -----------------------------------------------------------------------------
61 */
62
63 /*
64 * Syntax: CHECK <channel|nick|server|hostmask> [-flags]
65 *
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.
71 *
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.
75 */
76
77 int m_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
78 struct Channel *chptr;
79 struct Client *acptr;
80 char *param;
81 int flags = CHECK_SHOWUSERS, i;
82
83 if (parc < 2) {
84 send_reply(sptr, ERR_NEEDMOREPARAMS, "CHECK");
85 return 0;
86 }
87
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++) {
91 switch (parv[2][i]) {
92 case 'c':
93 flags |= CHECK_CHECKCHAN;
94 break;
95
96 case 'o':
97 flags |= CHECK_OPSONLY; /* fall through */
98 case 'u':
99 flags &= ~(CHECK_SHOWUSERS);
100 break;
101
102 case 'i':
103 flags |= CHECK_SHOWIPS;
104 break;
105
106 default:
107 /* might want to raise some sort of error here? */
108 break;
109 }
110 }
111 }
112
113 if (IsChannelName(parv[1])) { /* channel */
114 if ((chptr = FindChannel(parv[1]))) {
115 checkChannel(sptr, chptr);
116 checkUsers(sptr, chptr, flags);
117 }
118 else
119 send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
120 }
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]);
124 return 0;
125 }
126
127 checkClient(sptr, acptr);
128 }
129 else if ((acptr = FindServer(parv[1]))) { /* server */
130 checkServer(sptr, acptr);
131 }
132 else if (checkHostmask(sptr, parv[1], flags) > 0) /* hostmask */
133 return 1;
134 else /* no match */
135 send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
136
137 return 1;
138 }
139
140 static int checkClones(struct Channel *chptr, char *nick, char *host) {
141 int clones = 0;
142 struct Membership *lp;
143 struct Client *acptr;
144
145 for (lp = chptr->members; lp; lp = lp->next_member) {
146 acptr = lp->user;
147 if (!strcmp(acptr->cli_user->realhost, host) && strcmp(acptr->cli_name, nick)) {
148 /* this is a clone */
149 clones++;
150 }
151 }
152
153 return ((clones) ? clones + 1 : 0);
154 }
155
156 void checkUsers(struct Client *sptr, struct Channel *chptr, int flags) {
157 struct Membership *lp;
158 struct Ban *ban;
159 struct Client *acptr;
160
161 char outbuf[BUFSIZE], ustat[64];
162 int cntr = 0, opcntr = 0, vcntr = 0, clones = 0, bans = 0, c = 0, authed = 0;
163
164 if (flags & CHECK_SHOWUSERS) send_reply(sptr, RPL_DATASTR, "Users (@ = op, + = voice)");
165
166 for (lp = chptr->members; lp; lp = lp->next_member) {
167 int opped = 0;
168
169 acptr = lp->user;
170
171 if ((c = checkClones(chptr, acptr->cli_name, acptr->cli_user->realhost)) != 0) {
172 ircd_snprintf(0, ustat, sizeof(ustat), "%2d ", c);
173 clones++;
174 }
175 else
176 strcpy(ustat, " ");
177
178 if (chptr && is_chan_op(acptr, chptr)) {
179 strcat(ustat, "@");
180 opcntr++;
181 opped = 1;
182 }
183 else if (chptr && has_voice(acptr, chptr)) {
184 strcat(ustat, "+");
185 vcntr++;
186 }
187 else
188 strcat(ustat, " ");
189
190 if ((c = IsAccount(acptr)) != 0) ++authed;
191
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 : ""));
197 }
198
199 cntr++;
200 }
201
202 send_reply(sptr, RPL_DATASTR, " ");
203
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);
207
208 send_reply(sptr, RPL_DATASTR, outbuf);
209
210 send_reply(sptr, RPL_DATASTR, " ");
211
212 /* Do not display bans if ! flags & CHECK_SHOWUSERS */
213 if (!(flags & CHECK_SHOWUSERS)) {
214 send_reply(sptr, RPL_ENDOFCHECK, " ");
215 return;
216 }
217
218 /* Bans */
219 send_reply(sptr, RPL_DATASTR, "Bans on channel::");
220
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);
225 }
226
227 if (bans == 0)
228 send_reply(sptr, RPL_DATASTR, "<none>");
229
230 send_reply(sptr, RPL_ENDOFCHECK, " ");
231 }
232
233 void checkChannel(struct Client *sptr, struct Channel *chptr) {
234 char outbuf[TOPICLEN + MODEBUFLEN + 64], modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
235
236 /* Header */
237 send_reply(sptr, RPL_DATASTR, " ");
238 send_reply(sptr, RPL_CHKHEAD, "channel", chptr->chname);
239 send_reply(sptr, RPL_DATASTR, " ");
240
241 /* Creation Time */
242 ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Creation time:: %s", myctime(chptr->creationtime));
243 send_reply(sptr, RPL_DATASTR, outbuf);
244
245 /* Topic */
246 if (strlen(chptr->topic) <= 0)
247 send_reply(sptr, RPL_DATASTR, " Topic:: <none>");
248 else {
249 ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Topic:: %s", chptr->topic);
250 send_reply(sptr, RPL_DATASTR, outbuf);
251
252 /* ..set by */
253 ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Set by:: %s", chptr->topic_nick);
254 send_reply(sptr, RPL_DATASTR, outbuf);
255 }
256
257 /* Channel Modes */
258
259 strcpy(outbuf, "Channel mode(s):: ");
260
261 modebuf[0] = '\0';
262 parabuf[0] = '\0';
263
264 channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr, NULL);
265
266 if(modebuf[1] == '\0')
267 strcat(outbuf, "<none>");
268 else if(*parabuf) {
269 strcat(outbuf, modebuf);
270 strcat(outbuf, " ");
271 strcat(outbuf, parabuf);
272 }
273 else
274 strcat(outbuf, modebuf);
275
276 send_reply(sptr, RPL_DATASTR, outbuf);
277
278 /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */
279 }
280
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];
286 time_t nowr;
287
288 /* Header */
289 send_reply(sptr, RPL_DATASTR, " ");
290 send_reply(sptr, RPL_CHKHEAD, "user", acptr->cli_name);
291 send_reply(sptr, RPL_DATASTR, " ");
292
293 ircd_snprintf(0, outbuf, sizeof(outbuf), " Nick:: %s (%s%s)", acptr->cli_name, NumNick(acptr));
294 send_reply(sptr, RPL_DATASTR, outbuf);
295
296 if (MyUser(acptr)) {
297 ircd_snprintf(0, outbuf, sizeof(outbuf), " Signed on:: %s", myctime(acptr->cli_firsttime));
298 send_reply(sptr, RPL_DATASTR, outbuf);
299 }
300
301 ircd_snprintf(0, outbuf, sizeof(outbuf), " Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick);
302 send_reply(sptr, RPL_DATASTR, outbuf);
303
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);
307
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);
311 }
312
313 ircd_snprintf(0, outbuf, sizeof(outbuf), " Real Name:: %s%c", cli_info(acptr), COLOR_OFF);
314 send_reply(sptr, RPL_DATASTR, outbuf);
315
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");
320
321 ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected to:: %s", cli_name(acptr->cli_user->server));
322 send_reply(sptr, RPL_DATASTR, outbuf);
323
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.
328 */
329
330 if (strlen(umode_str(acptr)) < 1)
331 strcpy(outbuf, " Umode(s):: <none>");
332 else
333 ircd_snprintf(0, outbuf, sizeof(outbuf), " Umode(s):: +%s", umode_str(acptr));
334 send_reply(sptr, RPL_DATASTR, outbuf);
335
336 if (acptr->cli_user->joined == 0)
337 send_reply(sptr, RPL_DATASTR, " Channel(s):: <none>");
338 else if (acptr->cli_user->joined > 50) {
339
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).
345 */
346
347 ircd_snprintf(0, outbuf, sizeof(outbuf), " Channel(s):: - (total: %u)", acptr->cli_user->joined);
348 send_reply(sptr, RPL_DATASTR, outbuf);
349 }
350 else {
351 char chntext[BUFSIZE];
352 int len = strlen(" Channel(s):: ");
353 int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
354 *chntext = '\0';
355
356 strcpy(chntext, " Channel(s):: ");
357 for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
358 chptr = lp->channel;
359 if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
360 send_reply(sptr, RPL_DATASTR, chntext);
361 *chntext = '\0';
362 strcpy(chntext, " Channel(s):: ");
363 len = strlen(chntext);
364 }
365 if (IsDeaf(acptr))
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++) = '!';
373 if (len)
374 *(chntext + len) = '\0';
375
376 strcpy(chntext + len, chptr->chname);
377 len += strlen(chptr->chname);
378 strcat(chntext + len, " ");
379 len++;
380 }
381
382 if (chntext[0] != '\0')
383 send_reply(sptr, RPL_DATASTR, chntext);
384 }
385
386 /* If client processing command ISN'T target (or a registered
387 * Network Service), show idle time since the last time we
388 * parsed something.
389 */
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);
395 }
396
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);
401 }
402
403 /* If local user.. */
404 if (MyUser(acptr)) {
405 os_get_peername(con_fd(cli_connect(sptr)), &sin);
406
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);
425 }
426 }
427
428 /* Send 'END OF CHECK' message */
429 send_reply(sptr, RPL_ENDOFCHECK, " ");
430 }
431
432 void checkServer(struct Client *sptr, struct Client *acptr) {
433 char outbuf[BUFSIZE];
434
435 /* Header */
436 send_reply(sptr, RPL_DATASTR, " ");
437 send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name);
438 send_reply(sptr, RPL_DATASTR, " ");
439
440 ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected at:: %s", myctime(acptr->cli_serv->timestamp));
441 send_reply(sptr, RPL_DATASTR, outbuf);
442
443 ircd_snprintf(0, outbuf, sizeof(outbuf), " Server name:: %s", acptr->cli_name);
444 send_reply(sptr, RPL_DATASTR, outbuf);
445
446 ircd_snprintf(0, outbuf, sizeof(outbuf), " Numeric:: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx));
447 send_reply(sptr, RPL_DATASTR, outbuf);
448
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);
452
453 if (IsBurst(acptr))
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");
461
462 if (feature_bool(FEAT_EXTENDED_CHECKCMD)) {
463 int dlinkc = 0;
464 struct DLink* slink = NULL;
465
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);
473 }
474
475 if (!dlinkc)
476 send_reply(sptr, RPL_DATASTR, "<none>");
477 }
478
479 /* Send 'END OF CHECK' message */
480 send_reply(sptr, RPL_ENDOFCHECK, " ");
481 }
482
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];
491 char *p = NULL;
492 struct irc_in_addr cidr_check;
493 char cidr_check_bits;
494
495 strcpy(nickm,"*");
496 strcpy(userm,"*");
497 strcpy(hostm,"*");
498
499 if (!strchr(hoststr, '!') && !strchr(hoststr, '@'))
500 ircd_strncpy(hostm,hoststr,HOSTLEN);
501 else {
502 if (p = strchr(hoststr, '@')) {
503 *p++ = '\0';
504 if (*p) ircd_strncpy(hostm,p, HOSTLEN);
505 }
506
507 /* Get the nick!user mask */
508 if (p = strchr(hoststr, '!')) {
509 *p++ = '\0';
510 if (*p) ircd_strncpy(userm,p,USERLEN);
511 if (*hoststr) ircd_strncpy(nickm,hoststr,NICKLEN);
512 }
513 else if (*hoststr) {
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
517 */
518 ircd_strncpy(userm,hoststr,USERLEN);
519 }
520 }
521
522 if (ipmask_parse(hostm, &cidr_check, &cidr_check_bits) != 0) {
523 flags |= CHECK_CIDRMASK;
524 }
525
526 /*if ((p = strchr(hostm, '/')) || inet_aton(hostm, &cidr_check)) {
527 if (p)
528 *p = '\0';
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);
534 }
535 }
536 if (p)
537 *p = '/';
538 }*/
539
540 /* Copy formatted string into "targhost" buffer */
541 ircd_snprintf(0, targhost, sizeof(targhost), "%s!%s@%s", nickm, userm, hostm);
542
543 targhost[sizeof(targhost) - 1] = '\0';
544
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
547 * a segfault.
548 */
549
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))
553 continue;
554
555 if (IsMe(acptr)) /* Always the last acptr record */
556 break;
557
558 if(count > 500) { /* sanity stuff */
559 send_reply(sptr, RPL_ENDOFCHECK, " ");
560 break;
561 }
562
563 /* Copy host info into buffer */
564 curhost[0] = '\0';
565 ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->realusername, acptr->cli_user->realhost);
566
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)))
570 found = 1;
571 }
572 else {
573 if(match((const char*)targhost,(const char*)curhost) == 0)
574 found = 1;
575 else {
576 curhost[0] = '\0';
577 ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, acptr->cli_user->username, acptr->cli_user->host);
578
579 if(match((const char*)targhost,(const char*)curhost) == 0)
580 found = 1;
581 }
582 }
583
584 if (found == 1) {
585 found = 0; /* reset that so it doesn't get crazy go nuts */
586
587 /* Show header if we've found at least 1 record */
588 if (count == 0) {
589 /* Output header */
590 send_reply(sptr, RPL_DATASTR, " ");
591 send_reply(sptr, RPL_CHKHEAD, "host", targhost);
592
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);
597 }
598
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);
603
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...
607 */
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);
613 *chntext = '\0';
614
615 strcpy(chntext, " on channels: ");
616 for (lp = acptr->cli_user->channel; lp; lp = lp->next_channel) {
617 chptr = lp->channel;
618 if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
619 send_reply(sptr, RPL_DATASTR, chntext);
620 *chntext = '\0';
621 strcpy(chntext, " on channels: ");
622 len = strlen(chntext);
623 }
624 if (IsDeaf(acptr))
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++) = '!';
632 if (len)
633 *(chntext + len) = '\0';
634
635 strcpy(chntext + len, chptr->chname);
636 len += strlen(chptr->chname);
637 strcat(chntext + len, " ");
638 len++;
639 }
640 if (chntext[0] != '\0')
641 send_reply(sptr, RPL_DATASTR, chntext);
642
643 send_reply(sptr, RPL_DATASTR, " ");
644 }
645 }
646 count++;
647 }
648 }
649
650 if (count > 0) {
651 send_reply(sptr, RPL_DATASTR, " ");
652
653 ircd_snprintf(0, outbuf, sizeof(outbuf), "Matching records found:: %d", count);
654 send_reply(sptr, RPL_DATASTR, outbuf);
655
656 send_reply(sptr, RPL_ENDOFCHECK, " ");
657 }
658
659 return count;
660 }