]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blob - check
nickgline: include nick! bit in gline loggin
[irc/quakenet/snircd-patchqueue.git] / check
1 # HG changeset patch
2 # Parent 3303f23758b0f0bc35a9d786a027aba155488e62
3
4 diff -r 3303f23758b0 include/check.h
5 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6 +++ b/include/check.h Wed Jul 17 21:38:16 2013 +0100
7 @@ -0,0 +1,49 @@
8 +/*
9 + * IRC - Internet Relay Chat, ircd/check.h
10 + * Copyright (C) 1990 University of Oulu, Computing Center
11 + *
12 + * This program is free software; you can redistribute it and/or modify
13 + * it under the terms of the GNU General Public License as published by
14 + * the Free Software Foundation; either version 1, or (at your option)
15 + * any later version.
16 + *
17 + * This program is distributed in the hope that it will be useful,
18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 + * GNU General Public License for more details.
21 + *
22 + * You should have received a copy of the GNU General Public License
23 + * along with this program; if not, write to the Free Software
24 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 + */
26 +
27 +/*
28 + * - ASUKA ---------------------------------------------------------------------
29 + * These are the declarations of the CHECK functions for Asuka.
30 + * Some of this code is from previous QuakeNet ircds, and some of it is my own.
31 + * The old code was written by Durzel (durzel@quakenet.org).
32 + *
33 + * qoreQ (qoreQ@quakenet.org) - 08/14/2002
34 + * -----------------------------------------------------------------------------
35 + */
36 +
37 +#ifndef INCLUDED_check_h
38 +#define INCLUDED_check_h
39 +
40 +#define HEADERLINE "--------------------------------------------------------------------"
41 +#define COLOR_OFF '\017'
42 +
43 +/* IP is IPv4, or IPv4 over IPv6 (2002::/16 range) */
44 +#define has_ipv4_addr(x) (irc_in_addr_is_ipv4(x) || (x)->in6_16[0] == htons(0x2002))
45 +/* Return IP in IPv4 notation, also when IP is IPv4 over IPv6 */
46 +#define get_ipv4_addr(x) (irc_in_addr_is_ipv4(x) ? \
47 + (ntohs((x)->in6_16[6]) << 16) | ntohs((x)->in6_16[7]) : \
48 + (ntohs((x)->in6_16[1]) << 16) | ntohs((x)->in6_16[2]))
49 +
50 +extern void checkChannel(struct Client *sptr, struct Channel *chptr);
51 +extern void checkUsers(struct Client *sptr, struct Channel *chptr, int flags);
52 +extern void checkClient(struct Client *sptr, struct Client *acptr);
53 +extern void checkServer(struct Client *sptr, struct Client *acptr);
54 +extern signed int checkHostmask(struct Client *sptr, char *hoststr, int flags);
55 +
56 +#endif /* INCLUDED_check_h */
57 diff -r 3303f23758b0 include/client.h
58 --- a/include/client.h Wed Jul 17 21:30:44 2013 +0100
59 +++ b/include/client.h Wed Jul 17 21:38:16 2013 +0100
60 @@ -774,6 +774,9 @@
61 #define HIDE_IP 0 /**< Do not show IP address in get_client_name() */
62 #define SHOW_IP 1 /**< Show ident and IP address in get_client_name() */
63
64 +/** Number of bits unique per user under IPv6, used for clone checks */
65 +#define IPV6USERBITS 64
66 +
67 extern const char* get_client_name(const struct Client* sptr, int showip);
68 extern const char* client_get_default_umode(const struct Client* sptr);
69 extern int client_get_ping(const struct Client* local_client);
70 diff -r 3303f23758b0 include/handlers.h
71 --- a/include/handlers.h Wed Jul 17 21:30:44 2013 +0100
72 +++ b/include/handlers.h Wed Jul 17 21:38:16 2013 +0100
73 @@ -88,6 +88,19 @@
74
75 extern int m_admin(struct Client*, struct Client*, int, char*[]);
76 extern int m_away(struct Client*, struct Client*, int, char*[]);
77 +
78 +/*
79 + * - ASUKA ---------------------------------------------------------------------
80 + * Add the command for CHECK.
81 + * This was adapted from Lain for use in Asuka.
82 + * Original code by Durzel (durzel@quakenet.org).
83 + *
84 + * qoreQ (qoreQ@quakenet.org) - 08/30/2002
85 + * -----------------------------------------------------------------------------
86 + */
87 +
88 +extern int m_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]);
89 +
90 extern int m_cap(struct Client*, struct Client*, int, char*[]);
91 extern int m_cnotice(struct Client*, struct Client*, int, char*[]);
92 extern int m_cprivmsg(struct Client*, struct Client*, int, char*[]);
93 diff -r 3303f23758b0 include/ircd_features.h
94 --- a/include/ircd_features.h Wed Jul 17 21:30:44 2013 +0100
95 +++ b/include/ircd_features.h Wed Jul 17 21:38:16 2013 +0100
96 @@ -102,6 +102,7 @@
97 FEAT_ANNOUNCE_INVITES,
98
99 /* features that affect all operators */
100 + FEAT_EXTENDED_CHECKCMD,
101 FEAT_CONFIG_OPERCMDS,
102 FEAT_SETHOST,
103 FEAT_SETHOST_USER,
104 diff -r 3303f23758b0 include/msg.h
105 --- a/include/msg.h Wed Jul 17 21:30:44 2013 +0100
106 +++ b/include/msg.h Wed Jul 17 21:38:16 2013 +0100
107 @@ -260,6 +260,10 @@
108 #define TOK_SERVSET "SERVSET"
109 #define CMD_SERVSET MSG_SERVSET, TOK_SERVSET
110
111 +#define MSG_CHECK "CHECK"
112 +#define TOK_CHECK "CC"
113 +#define CMD_CHECK MSG_CHECK, TOK_CHECK
114 +
115 #define MSG_REHASH "REHASH" /* REHA */
116 #define TOK_REHASH "REHASH"
117 #define CMD_REHASH MSG_REHASH, TOK_REHASH
118 diff -r 3303f23758b0 include/s_user.h
119 --- a/include/s_user.h Wed Jul 17 21:30:44 2013 +0100
120 +++ b/include/s_user.h Wed Jul 17 21:38:16 2013 +0100
121 @@ -54,6 +54,12 @@
122 #define ALLOWMODES_ANY 0 /**< Allow any user mode */
123 #define ALLOWMODES_DEFAULT 1 /**< Only allow the subset of modes that are legit defaults */
124
125 +/* return sets for umode_str() */
126 +#define UMODE_ALL_PARAMS 0 /**< return the user modes and all parameters */
127 +#define UMODE_ALL_PARAMS_BUT_OPERID 1 /**< return the user modes and all parameters except OperID */
128 +#define UMODE_AND_ACCOUNT 2 /**< return the user modes and account parameter */
129 +#define UMODE_AND_ACCOUNT_SHORT 3 /**< return the user modes and account (but no account timestamp, ID or flags) */
130 +
131 /** Formatter function for send_user_info().
132 * @param who Client being displayed.
133 * @param sptr Client requesting information.
134 diff -r 3303f23758b0 ircd/IPcheck.c
135 --- a/ircd/IPcheck.c Wed Jul 17 21:30:44 2013 +0100
136 +++ b/ircd/IPcheck.c Wed Jul 17 21:38:16 2013 +0100
137 @@ -120,7 +120,7 @@
138 ip_registry_canonicalize(&canon, ip);
139 entry = hashTable[ip_registry_hash(&canon)];
140 for ( ; entry; entry = entry->next) {
141 - int bits = (canon.in6_16[0] == htons(0x2002)) ? 48 : 64;
142 + int bits = (canon.in6_16[0] == htons(0x2002)) ? 48 : IPV6USERBITS;
143 if (ipmask_check(&canon, &entry->addr, bits))
144 break;
145 }
146 diff -r 3303f23758b0 ircd/Makefile.in
147 --- a/ircd/Makefile.in Wed Jul 17 21:30:44 2013 +0100
148 +++ b/ircd/Makefile.in Wed Jul 17 21:38:16 2013 +0100
149 @@ -119,6 +119,7 @@
150 m_away.c \
151 m_burst.c \
152 m_cap.c \
153 + m_check.c \
154 m_clearmode.c \
155 m_close.c \
156 m_connect.c \
157 diff -r 3303f23758b0 ircd/ircd_features.c
158 --- a/ircd/ircd_features.c Wed Jul 17 21:30:44 2013 +0100
159 +++ b/ircd/ircd_features.c Wed Jul 17 21:38:16 2013 +0100
160 @@ -367,6 +367,7 @@
161 F_B(ANNOUNCE_INVITES, 0, 0, 0),
162
163 /* features that affect all operators */
164 + F_B(EXTENDED_CHECKCMD, 0, 0, 0),
165 F_B(CONFIG_OPERCMDS, 0, 0, 0),
166 F_B(SETHOST, 0, 0, 0),
167 F_B(SETHOST_USER, 0, 0, 0),
168 diff -r 3303f23758b0 ircd/m_check.c
169 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
170 +++ b/ircd/m_check.c Wed Jul 17 21:38:16 2013 +0100
171 @@ -0,0 +1,809 @@
172 +/*
173 + * IRC - Internet Relay Chat, ircd/m_check.c
174 + * Copyright (C) 1990 Jarkko Oikarinen and
175 + * University of Oulu, Computing Center
176 + *
177 + * See file AUTHORS in IRC package for additional names of
178 + * the programmers.
179 + *
180 + * This program is free software; you can redistribute it and/or modify
181 + * it under the terms of the GNU General Public License as published by
182 + * the Free Software Foundation; either version 1, or (at your option)
183 + * any later version.
184 + *
185 + * This program is distributed in the hope that it will be useful,
186 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
187 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
188 + * GNU General Public License for more details.
189 + *
190 + * You should have received a copy of the GNU General Public License
191 + * along with this program; if not, write to the Free Software
192 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
193 + */
194 +
195 +#include "channel.h"
196 +#include "check.h"
197 +#include "class.h"
198 +#include "client.h"
199 +#include "hash.h"
200 +#include "IPcheck.h"
201 +#include "ircd.h"
202 +#include "ircd_alloc.h"
203 +#include "ircd_defs.h"
204 +#include "ircd_features.h"
205 +#include "ircd_reply.h"
206 +#include "ircd_string.h"
207 +#include "ircd_snprintf.h"
208 +#include "ircd_osdep.h"
209 +#include "list.h"
210 +#include "listener.h"
211 +#include "match.h"
212 +#include "msg.h"
213 +#include "numeric.h"
214 +#include "numnicks.h"
215 +#include "querycmds.h"
216 +#include "send.h"
217 +#include "s_user.h"
218 +#include "s_debug.h"
219 +#include "s_misc.h"
220 +
221 +#include <string.h>
222 +
223 +#define CHECK_CHECKCHAN 0x01 /* -c */
224 +#define CHECK_SHOWUSERS 0x02 /* ! -u */
225 +#define CHECK_OPSONLY 0x04 /* -o */
226 +#define CHECK_SHOWIPS 0x08 /* -i */
227 +#define CHECK_CIDRMASK 0x10 /* automatically detected when performing a hostmask /CHECK */
228 +#define CHECK_OPLEVELS 0x20 /* -l */
229 +#define CHECK_CLONES 0x40 /* -C */
230 +#define CHECK_SHOWSERVER 0x80 /* -s */
231 +#define CHECK_SHOWHOSTIP 0x100 /* -I */
232 +#define CHECK_SHOWMORE 0x200 /* -e */
233 +
234 +/*
235 + * - ASUKA ---------------------------------------------------------------------
236 + * This is the implimentation of the CHECK function for Asuka.
237 + * Some of this code is from previous QuakeNet ircds, but most of it is mine..
238 + * The old code was written by Durzel (durzel@quakenet.org).
239 + *
240 + * qoreQ (qoreQ@quakenet.org) - 08/14/2002
241 + * -----------------------------------------------------------------------------
242 + */
243 +
244 +/*
245 + * Syntax: CHECK <channel|nick|server|hostmask> [-flags]
246 + *
247 + * Where valid flags are:
248 + * -c: Show channels when checking a hostmask.
249 + * -e: show more inform when checking a mask.
250 + * -i: Show IPs instead of hostnames when displaying results.
251 + * -l: Show oplevels when checking a channel.
252 + * -o: Only show channel operators when checking a channel.
253 + * -s: show server user is on when checking a channel (or on a mask when combined with -e).
254 + * -u: Hide users when checking a channel.
255 + * -C: Perform clone count when checking a channel.
256 + * -I: show hostnames and IPs when checking a channel.
257 + *
258 + * <hostmask> can be of the form host, user@host, nick!user@host,
259 + * with host being host.domain.cc, 127.0.0.1 or 127.0.0.0/24.
260 + * Wildcards are supported.
261 + */
262 +
263 +int m_check(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) {
264 + struct Channel *chptr;
265 + struct Client *acptr;
266 + int flags = CHECK_SHOWUSERS, i;
267 +
268 + if (parc < 2) {
269 + send_reply(sptr, ERR_NEEDMOREPARAMS, "CHECK");
270 + return 0;
271 + }
272 +
273 + if ( parc>=4 ||
274 + (parc==3 && parv[2][0] != '-')) {
275 + /* remote query */
276 + if (hunt_server_cmd(sptr, CMD_CHECK, cptr, 0, parc==4 ? "%C %s %s" : "%C %s", 1, parc, parv) != HUNTED_ISME)
277 + return 0;
278 + parv++; parc--;
279 + }
280 +
281 + /* This checks to see if any flags have been supplied */
282 + if ((parc >= 3) && (parv[2][0] == '-')) {
283 + for (i = 0; parv[2][i]; i++) {
284 + switch (parv[2][i]) {
285 + case 'c':
286 + flags |= CHECK_CHECKCHAN;
287 + break;
288 +
289 + case 'o':
290 + flags |= CHECK_OPSONLY; /* fall through */
291 + case 'u':
292 + flags &= ~(CHECK_SHOWUSERS);
293 + break;
294 +
295 + case 'i':
296 + flags |= CHECK_SHOWIPS;
297 + break;
298 + case 'l':
299 + flags |= CHECK_OPLEVELS;
300 + break;
301 + case 'C':
302 + flags |= CHECK_CLONES;
303 + break;
304 + case 's':
305 + flags |= CHECK_SHOWSERVER;
306 + break;
307 + case 'I':
308 + flags |= CHECK_SHOWHOSTIP;
309 + break;
310 + case 'e':
311 + flags |= CHECK_SHOWMORE;
312 + break;
313 + default:
314 + /* might want to raise some sort of error here? */
315 + break;
316 + }
317 + }
318 + }
319 +
320 + if (IsChannelName(parv[1])) { /* channel */
321 + if ((chptr = FindChannel(parv[1]))) {
322 + checkChannel(sptr, chptr);
323 + checkUsers(sptr, chptr, flags);
324 + }
325 + else
326 + send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
327 + }
328 + else if ((acptr = FindClient(parv[1])) && !(FindServer(parv[1]))) { /* client and not a server */
329 + if (!IsRegistered(acptr)) {
330 + send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
331 + return 0;
332 + }
333 +
334 + checkClient(sptr, acptr);
335 + }
336 + else if ((acptr = FindServer(parv[1]))) { /* server */
337 + checkServer(sptr, acptr);
338 + }
339 + else if (checkHostmask(sptr, parv[1], flags) > 0) /* hostmask */
340 + return 1;
341 + else /* no match */
342 + send_reply(sptr, ERR_SEARCHNOMATCH, "CHECK", parv[1]);
343 +
344 + return 1;
345 +}
346 +
347 +
348 +
349 +/* return number of clients from same IP on the channel */
350 +static int checkClones(struct Channel *chptr, struct Client *cptr) {
351 + int clones = 0, count = 0;
352 + struct Membership *lp;
353 + struct Client *acptr;
354 +
355 + for (lp = chptr->members; lp; lp = lp->next_member) {
356 + acptr = lp->user;
357 + if (are_ips_clones(&cli_ip(cptr),&cli_ip(acptr))) {
358 + clones++;
359 + }
360 + }
361 +
362 + /* Optimise only if we will actually save CPU time */
363 + if (clones >= 2) {
364 + for (lp = chptr->members; lp; lp = lp->next_member) {
365 + acptr = lp->user;
366 + if (are_ips_clones(&cli_ip(cptr),&cli_ip(acptr))) {
367 + cli_marker(acptr) = clones;
368 + count++;
369 + if (clones == count) {
370 + break;
371 + }
372 + }
373 + }
374 + }
375 +
376 + return clones;
377 +}
378 +
379 +
380 +/* compare IPs from clients and return 1 when they are clones
381 + * same IPv4 IP
382 + * IPv4 and IPv6 IPs, but IPv4 over IPv6 etc cases
383 + * IPv6 IPs from the same /64 block
384 + */
385 +int are_ips_clones(const struct irc_in_addr *ip1, const struct irc_in_addr *ip2) {
386 + int ipv4ip1 = has_ipv4_addr(ip1);
387 +
388 + /* are both ip addresses ipv4 or ipv6? if not, no clones */
389 + if (ipv4ip1 != has_ipv4_addr(ip2)) return 0;
390 +
391 + if (ipv4ip1) /* check ipv4 */
392 + return (get_ipv4_addr(ip1) == get_ipv4_addr(ip2)) ? 1 : 0;
393 +
394 + /* check ipv6 */
395 + return ipmask_check(ip1, ip2, IPV6USERBITS) ? 1 : 0;
396 +}
397 +
398 +
399 +void checkUsers(struct Client *sptr, struct Channel *chptr, int flags) {
400 + struct Membership *lp;
401 + struct Ban *ban;
402 + struct Client *acptr;
403 +
404 + char outbuf[BUFSIZE], outbuf2[BUFSIZE], ustat[64];
405 + int cntr = 0, opcntr = 0, vcntr = 0, clones = 0, bans = 0, authed = 0, delayedjoin = 0;
406 + char *zombie, *showlevel;
407 +
408 + if (flags & CHECK_SHOWUSERS) {
409 + send_reply(sptr, RPL_DATASTR, "Users (@ = op, + = voice)");
410 + }
411 +
412 + if (flags & CHECK_CLONES) {
413 + for (lp = chptr->members; lp; lp = lp->next_member) {
414 + cli_marker(lp->user) = 0;
415 + }
416 + }
417 +
418 + for (lp = chptr->members; lp; lp = lp->next_member) {
419 + int opped = 0, c = 0;
420 +
421 + acptr = lp->user;
422 + zombie = IsZombie(lp) ? "!" : "";
423 + showlevel = (flags & CHECK_OPLEVELS) ? " " : "";
424 +
425 + if (flags & CHECK_CLONES) {
426 + if (!cli_marker(acptr)) {
427 + c = checkClones(chptr, acptr);
428 + } else {
429 + c = cli_marker(acptr);
430 + }
431 +
432 + if (c != 1) {
433 + clones++;
434 + }
435 + }
436 +
437 + if (IsChanOp(lp)) {
438 + if (flags & CHECK_OPLEVELS) {
439 + if (c) {
440 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s%3hu@", c, zombie, OpLevel(lp));
441 + } else {
442 + ircd_snprintf(0, ustat, sizeof(ustat), "%s%3hu@", zombie, OpLevel(lp));
443 + }
444 + } else {
445 + if (c) {
446 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s@", c, zombie);
447 + } else {
448 + ircd_snprintf(0, ustat, sizeof(ustat), "%s@", zombie);
449 + }
450 + }
451 + opcntr++;
452 + opped = 1;
453 + }
454 + else if (HasVoice(lp)) {
455 + if (c) {
456 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s%s+", c, showlevel, zombie);
457 + } else {
458 + ircd_snprintf(0, ustat, sizeof(ustat), "%s%s+", showlevel, zombie);
459 + }
460 + vcntr++;
461 + }
462 + else if (IsDelayedJoin(lp)) {
463 + if (c) {
464 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s%s<", c, showlevel, zombie);
465 + } else {
466 + ircd_snprintf(0, ustat, sizeof(ustat), "%s%s<", showlevel, zombie);
467 + }
468 + delayedjoin++;
469 + }
470 + else {
471 + if (c) {
472 + ircd_snprintf(0, ustat, sizeof(ustat), "%2d %s%s", c, showlevel, zombie);
473 + } else {
474 + ircd_snprintf(0, ustat, sizeof(ustat), " %s%s", showlevel, zombie);
475 + }
476 + }
477 +
478 + if ((c = IsAccount(acptr))) {
479 + authed++;
480 + }
481 +
482 + if ((flags & CHECK_SHOWUSERS) || ((flags & CHECK_OPSONLY) && opped)) {
483 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%c", acptr->cli_info, COLOR_OFF);
484 + if (flags & CHECK_SHOWHOSTIP) {
485 + ircd_snprintf(0, outbuf2, sizeof(outbuf2), " [%s]", ircd_ntoa(&(cli_ip(acptr))));
486 + }
487 + send_reply(sptr, RPL_CHANUSER, ustat, acptr->cli_name, cli_user(acptr)->realusername,
488 + ((flags & CHECK_SHOWIPS) ? ircd_ntoa(&(cli_ip(acptr))) : cli_user(acptr)->realhost), (flags & CHECK_SHOWHOSTIP) ? outbuf2 : "", (flags & CHECK_SHOWSERVER) ? cli_name(cli_user(acptr)->server) : outbuf,
489 + (c ? cli_user(acptr)->account : ""));
490 + }
491 +
492 + cntr++;
493 + }
494 +
495 + send_reply(sptr, RPL_DATASTR, " ");
496 +
497 + if (flags & CHECK_CLONES) {
498 + ircd_snprintf(0, outbuf, sizeof(outbuf),
499 + "Total users:: %d (%d ops, %d voiced, %d clones, %d authed, %d hidden)",
500 + cntr, opcntr, vcntr, clones, authed, delayedjoin);
501 +
502 + for (lp = chptr->members; lp; lp = lp->next_member) {
503 + cli_marker(lp->user) = 0;
504 + }
505 + } else {
506 + ircd_snprintf(0, outbuf, sizeof(outbuf),
507 + "Total users:: %d (%d ops, %d voiced, %d authed, %d hidden)",
508 + cntr, opcntr, vcntr, authed, delayedjoin);
509 + }
510 +
511 + send_reply(sptr, RPL_DATASTR, outbuf);
512 + send_reply(sptr, RPL_DATASTR, " ");
513 +
514 + /* Do not display bans if ! flags & CHECK_SHOWUSERS */
515 + if (flags & CHECK_SHOWUSERS) {
516 + send_reply(sptr, RPL_DATASTR, "Bans on channel::");
517 +
518 + for (ban = chptr->banlist; ban; ban = ban->next) {
519 + ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s - Set by %s, on %s (%Tu)",
520 + ++bans, ban->banstr, ban->who, myctime(ban->when), ban->when);
521 + send_reply(sptr, RPL_DATASTR, outbuf);
522 + }
523 +
524 + if (bans == 0)
525 + send_reply(sptr, RPL_DATASTR, "<none>");
526 + }
527 +
528 + send_reply(sptr, RPL_ENDOFCHECK, " ");
529 +}
530 +
531 +void checkChannel(struct Client *sptr, struct Channel *chptr) {
532 + char outbuf[TOPICLEN + MODEBUFLEN + 64], modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
533 +
534 + /* Header */
535 + send_reply(sptr, RPL_DATASTR, " ");
536 + send_reply(sptr, RPL_CHKHEAD, "channel", chptr->chname);
537 + send_reply(sptr, RPL_DATASTR, " ");
538 +
539 + /* Creation Time */
540 + ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Creation time:: %s (%Tu)", myctime(chptr->creationtime), chptr->creationtime);
541 + send_reply(sptr, RPL_DATASTR, outbuf);
542 +
543 + /* Topic */
544 + if (strlen(chptr->topic) <= 0)
545 + send_reply(sptr, RPL_DATASTR, " Topic:: <none>");
546 + else {
547 + ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Topic:: %s", chptr->topic);
548 + send_reply(sptr, RPL_DATASTR, outbuf);
549 +
550 + /* ..set by */
551 + ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Set by:: %s", chptr->topic_nick);
552 + send_reply(sptr, RPL_DATASTR, outbuf);
553 +
554 + ircd_snprintf(sptr, outbuf, sizeof(outbuf), " Set at:: %s (%Tu)", myctime(chptr->topic_time), chptr->topic_time);
555 + send_reply(sptr, RPL_DATASTR, outbuf);
556 + }
557 +
558 + /* Channel Modes */
559 +
560 + strcpy(outbuf, "Channel mode(s):: ");
561 +
562 + modebuf[0] = '\0';
563 + parabuf[0] = '\0';
564 +
565 + channel_modes(sptr, modebuf, parabuf, sizeof(modebuf), chptr, NULL);
566 +
567 + if(modebuf[1] == '\0')
568 + strcat(outbuf, "<none>");
569 + else if(*parabuf) {
570 + strcat(outbuf, modebuf);
571 + strcat(outbuf, " ");
572 + strcat(outbuf, parabuf);
573 + }
574 + else
575 + strcat(outbuf, modebuf);
576 +
577 + send_reply(sptr, RPL_DATASTR, outbuf);
578 +
579 + /* Don't send 'END OF CHECK' message, it's sent in checkUsers, which is called after this. */
580 +}
581 +
582 +void checkClient(struct Client *sptr, struct Client *acptr) {
583 + struct Channel *chptr;
584 + struct Membership *lp;
585 + struct irc_sockaddr sin;
586 + char outbuf[BUFSIZE];
587 + time_t nowr;
588 +
589 + /* Header */
590 + send_reply(sptr, RPL_DATASTR, " ");
591 + send_reply(sptr, RPL_CHKHEAD, "user", cli_name(acptr));
592 + send_reply(sptr, RPL_DATASTR, " ");
593 +
594 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Nick:: %s (%s%s)", cli_name(acptr), NumNick(acptr));
595 + send_reply(sptr, RPL_DATASTR, outbuf);
596 +
597 + if (MyUser(acptr)) {
598 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Signed on:: %s (%Tu)", myctime(acptr->cli_firsttime), acptr->cli_firsttime);
599 + send_reply(sptr, RPL_DATASTR, outbuf);
600 + }
601 +
602 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Timestamp:: %s (%d)", myctime(acptr->cli_lastnick), acptr->cli_lastnick);
603 + send_reply(sptr, RPL_DATASTR, outbuf);
604 +
605 + ircd_snprintf(0, outbuf, sizeof(outbuf), " User/Hostmask:: %s@%s [%s] (Clients: %hu)", cli_user(acptr)->username, cli_user(acptr)->host,
606 + ircd_ntoa(&(cli_ip(acptr))), IPcheck_nr(acptr));
607 + send_reply(sptr, RPL_DATASTR, outbuf);
608 +
609 + if (IsSetHost(acptr) || HasHiddenHost(acptr)) {
610 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Real User/Host:: %s@%s", cli_user(acptr)->realusername, cli_user(acptr)->realhost);
611 + send_reply(sptr, RPL_DATASTR, outbuf);
612 + }
613 +
614 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Real Name:: %s%c", cli_info(acptr), COLOR_OFF);
615 + send_reply(sptr, RPL_DATASTR, outbuf);
616 +
617 + if( IsService(cli_user(acptr)->server)) {
618 + if (IsChannelService(acptr))
619 + send_reply(sptr, RPL_DATASTR, " Status:: Network Service");
620 + else if (IsAnOper(acptr))
621 + send_reply(sptr, RPL_DATASTR, " Status:: IRC Operator (service) (ID: %s)", cli_user(acptr)->opername ? cli_user(acptr)->opername : "<unknown>");
622 + else
623 + send_reply(sptr, RPL_DATASTR, " Status:: Client (service)");
624 + } else if (IsAnOper(acptr)) {
625 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Status:: IRC Operator (ID: %s)", cli_user(acptr)->opername ? cli_user(acptr)->opername : "<unknown>");
626 + send_reply(sptr, RPL_DATASTR, outbuf);
627 + } else
628 + send_reply(sptr, RPL_DATASTR, " Status:: Client");
629 +
630 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected to:: %s (Hops: %d)", cli_name(cli_user(acptr)->server), cli_hopcount(acptr));
631 + send_reply(sptr, RPL_DATASTR, outbuf);
632 +
633 + /* +s (SERV_NOTICE) is not relayed to us from remote servers,
634 + * so we cannot tell if a remote client has that mode set.
635 + * And hacking it onto the end of the output of umode_str is EVIL BAD AND WRONG
636 + * (and breaks if the user is +r) so we won't do that either.
637 + */
638 +
639 + /* show the usermodes and account info (but not OperID and sethost) */
640 + umodes = umode_str(acptr, UMODE_AND_ACCOUNT);
641 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Usermode(s):: %s%s", *umodes ? "+" : "<none>", umodes);
642 + send_reply(sptr, RPL_DATASTR, outbuf);
643 +
644 + if (cli_user(acptr)->joined == 0)
645 + send_reply(sptr, RPL_DATASTR, " Channel(s):: <none>");
646 + else if (cli_user(acptr)->joined > 50) {
647 +
648 + /* NB. As a sanity check, we DO NOT show the individual channels the
649 + * client is on if it is on > 50 channels. This is to prevent the ircd
650 + * barfing ala Uworld when someone does /quote check Q :).. (I shouldn't imagine
651 + * an Oper would want to see every single channel 'x' client is on anyway if
652 + * they are on *that* many).
653 + */
654 +
655 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Channel(s):: - (total: %u)", cli_user(acptr)->joined);
656 + send_reply(sptr, RPL_DATASTR, outbuf);
657 + }
658 + else {
659 + char chntext[BUFSIZE];
660 + int len = strlen(" Channel(s):: ");
661 + int mlen = strlen(me.cli_name) + len + strlen(cli_name(sptr));
662 + *chntext = '\0';
663 +
664 + strcpy(chntext, " Channel(s):: ");
665 + for (lp = cli_user(acptr)->channel; lp; lp = lp->next_channel) {
666 + chptr = lp->channel;
667 + if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
668 + send_reply(sptr, RPL_DATASTR, chntext);
669 + *chntext = '\0';
670 + strcpy(chntext, " Channel(s):: ");
671 + len = strlen(chntext);
672 + }
673 + if (IsDeaf(acptr))
674 + *(chntext + len++) = '-';
675 + if (!PubChannel(chptr))
676 + *(chntext + len++) = '*';
677 + if (IsZombie(lp))
678 + *(chntext + len++) = '!';
679 + if (IsChanOp(lp))
680 + *(chntext + len++) = '@';
681 + else if (HasVoice(lp))
682 + *(chntext + len++) = '+';
683 + else if (IsDelayedJoin(lp))
684 + *(chntext + len++) = '<';
685 + if (len)
686 + *(chntext + len) = '\0';
687 +
688 + strcpy(chntext + len, chptr->chname);
689 + len += strlen(chptr->chname);
690 + strcat(chntext + len, " ");
691 + len++;
692 + }
693 +
694 + if (chntext[0] != '\0')
695 + send_reply(sptr, RPL_DATASTR, chntext);
696 + }
697 +
698 + if (MyUser(acptr)) {
699 + nowr = CurrentTime - cli_user(acptr)->last;
700 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Idle for:: %d days, %02ld:%02ld:%02ld",
701 + nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
702 + send_reply(sptr, RPL_DATASTR, outbuf);
703 + }
704 +
705 + /* Away message (if applicable) */
706 + if (cli_user(acptr)->away) {
707 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Away message:: %s", cli_user(acptr)->away);
708 + send_reply(sptr, RPL_DATASTR, outbuf);
709 + }
710 +
711 + /* If local user.. */
712 + if (MyUser(acptr)) {
713 + os_get_peername(con_fd(cli_connect(sptr)), &sin);
714 +
715 + send_reply(sptr, RPL_DATASTR, " ");
716 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Ports:: %d -> %d (client -> server)",
717 + sin.port, cli_listener(acptr)->addr.port);
718 + send_reply(sptr, RPL_DATASTR, outbuf);
719 + if (feature_bool(FEAT_EXTENDED_CHECKCMD)) {
720 + /* Note: sendq = receiveq for a client (it makes sense really) */
721 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Data sent:: %lu.%0.3u Kb (%u protocol messages)",
722 + (unsigned long)cli_receiveB(acptr) / 1024, (unsigned long)cli_receiveB(acptr) % 1024, cli_receiveM(acptr));
723 + send_reply(sptr, RPL_DATASTR, outbuf);
724 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Data received:: %lu.%0.3lu Kb (%u protocol messages)",
725 + (unsigned long)cli_sendB(acptr) / 1024, (unsigned long)cli_sendB(acptr) % 1024, cli_sendM(acptr));
726 + send_reply(sptr, RPL_DATASTR, outbuf);
727 + ircd_snprintf(0, outbuf, sizeof(outbuf), " receiveQ size:: %d bytes (max. %d bytes)",
728 + DBufLength(&(cli_recvQ(acptr))), feature_int(FEAT_CLIENT_FLOOD));
729 + send_reply(sptr, RPL_DATASTR, outbuf);
730 + ircd_snprintf(0, outbuf, sizeof(outbuf), " sendQ size:: %d bytes (max. %d bytes)",
731 + DBufLength(&(cli_sendQ(acptr))), get_sendq(acptr));
732 + send_reply(sptr, RPL_DATASTR, outbuf);
733 + }
734 + }
735 +
736 + /* Send 'END OF CHECK' message */
737 + send_reply(sptr, RPL_ENDOFCHECK, " ");
738 +}
739 +
740 +void checkServer(struct Client *sptr, struct Client *acptr) {
741 + char outbuf[BUFSIZE];
742 +
743 + /* Header */
744 + send_reply(sptr, RPL_DATASTR, " ");
745 + send_reply(sptr, RPL_CHKHEAD, "server", acptr->cli_name);
746 + send_reply(sptr, RPL_DATASTR, " ");
747 +
748 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Connected at:: %s (%Tu)", myctime(acptr->cli_serv->timestamp), acptr->cli_serv->timestamp);
749 + send_reply(sptr, RPL_DATASTR, outbuf);
750 +
751 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Server name:: %s", acptr->cli_name);
752 + send_reply(sptr, RPL_DATASTR, outbuf);
753 +
754 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Numeric:: %s --> %d", NumServ(acptr), base64toint(acptr->cli_yxx));
755 + send_reply(sptr, RPL_DATASTR, outbuf);
756 +
757 + ircd_snprintf(0, outbuf, sizeof(outbuf), " Users:: %d / %d", (acptr == &me) ? UserStats.local_clients : cli_serv(acptr)->clients,
758 + base64toint(cli_serv(acptr)->nn_capacity));
759 + send_reply(sptr, RPL_DATASTR, outbuf);
760 +
761 + if (IsBurst(acptr))
762 + send_reply(sptr, RPL_DATASTR, " Status:: Bursting");
763 + else if (IsBurstAck(acptr))
764 + send_reply(sptr, RPL_DATASTR, " Status:: Awaiting EOB Ack");
765 + else if (IsService(acptr))
766 + send_reply(sptr, RPL_DATASTR, " Status:: Network Service");
767 + else if (IsHub(acptr))
768 + send_reply(sptr, RPL_DATASTR, " Status:: Network Hub");
769 +
770 + if (feature_bool(FEAT_EXTENDED_CHECKCMD)) {
771 + int dlinkc = 0;
772 + struct DLink* slink = NULL;
773 +
774 + send_reply(sptr, RPL_DATASTR, " ");
775 + send_reply(sptr, RPL_DATASTR, "Downlinks::");
776 + for (slink = cli_serv(acptr)->down; slink; slink = slink->next) {
777 + ircd_snprintf(0, outbuf, sizeof(outbuf), "[%d] - %s%s", ++dlinkc,
778 + IsBurst(slink->value.cptr) ? "*" : IsBurstAck(slink->value.cptr) ? "!" : IsService(slink->value.cptr) ? "=" : IsHub(slink->value.cptr) ? "+" : " ",
779 + cli_name(slink->value.cptr));
780 + send_reply(sptr, RPL_DATASTR, outbuf);
781 + }
782 +
783 + if (!dlinkc)
784 + send_reply(sptr, RPL_DATASTR, "<none>");
785 + }
786 +
787 + /* Send 'END OF CHECK' message */
788 + send_reply(sptr, RPL_ENDOFCHECK, " ");
789 +}
790 +
791 +signed int checkHostmask(struct Client *sptr, char *orighoststr, int flags) {
792 + struct Client *acptr;
793 + struct Channel *chptr;
794 + struct Membership *lp;
795 + int count = 0, found = 0;
796 + char outbuf[BUFSIZE];
797 + char targhost[NICKLEN + USERLEN + HOSTLEN + 3], curhost[NICKLEN + USERLEN + HOSTLEN + 3];
798 + char hoststr[NICKLEN + USERLEN + HOSTLEN + 3];
799 + char nickm[NICKLEN + 1], userm[USERLEN + 1], hostm[HOSTLEN + 1];
800 + char *p = NULL;
801 + char *umodes;
802 + struct irc_in_addr cidr_check;
803 + unsigned char cidr_check_bits;
804 +
805 + ircd_strncpy(hoststr, orighoststr, NICKLEN + USERLEN + HOSTLEN + 3);
806 + strcpy(nickm,"*");
807 + strcpy(userm,"*");
808 + strcpy(hostm,"*");
809 +
810 + if (!strchr(hoststr, '!') && !strchr(hoststr, '@'))
811 + ircd_strncpy(hostm,hoststr,HOSTLEN);
812 + else {
813 + if ((p = strchr(hoststr, '@'))) {
814 + *p++ = '\0';
815 + if (*p) ircd_strncpy(hostm,p, HOSTLEN);
816 + }
817 +
818 + /* Get the nick!user mask */
819 + if ((p = strchr(hoststr, '!'))) {
820 + *p++ = '\0';
821 + if (*p) ircd_strncpy(userm,p,USERLEN);
822 + if (*hoststr) ircd_strncpy(nickm,hoststr,NICKLEN);
823 + }
824 + else if (*hoststr) {
825 + /* Durz: We should only do the following *IF* the hoststr has not already been
826 + * copied into hostm (ie. neither ! or @ specified).. otherwise, when we do
827 + * /quote check *.barrysworld.com - we end up with targhost as: *!*.barryswo@*.barrysworld.com
828 + */
829 + ircd_strncpy(userm,hoststr,USERLEN);
830 + }
831 + }
832 +
833 + if (ipmask_parse(hostm, &cidr_check, &cidr_check_bits) != 0) {
834 + flags |= CHECK_CIDRMASK;
835 + }
836 +
837 + /* Copy formatted string into "targhost" buffer */
838 + ircd_snprintf(0, targhost, sizeof(targhost), "%s!%s@%s", nickm, userm, hostm);
839 +
840 + targhost[sizeof(targhost) - 1] = '\0';
841 +
842 + /* Note: we have to exclude the last client struct as it is not a real client
843 + * structure, and therefore any attempt to access elements in it would cause
844 + * a segfault.
845 + */
846 +
847 + for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
848 + /* Dont process if acptr is a unregistered client, a server or a ping */
849 + if (!IsRegistered(acptr) || IsServer(acptr))
850 + continue;
851 +
852 + if (IsMe(acptr)) /* Always the last acptr record */
853 + break;
854 +
855 + if(count >= 500) { /* sanity stuff */
856 + ircd_snprintf(0, outbuf, sizeof(outbuf), "More than %d results, truncating...", count);
857 + send_reply(sptr, RPL_DATASTR, outbuf);
858 + break;
859 + }
860 +
861 + /* Copy host info into buffer */
862 + curhost[0] = '\0';
863 + ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", cli_name(acptr), cli_user(acptr)->realusername, cli_user(acptr)->realhost);
864 +
865 + if (flags & CHECK_CIDRMASK) {
866 + if (ipmask_check(&cli_ip(acptr), &cidr_check, cidr_check_bits) && !match(nickm, acptr->cli_name)
867 + && (!match(userm, cli_user(acptr)->realusername) || !match(userm, cli_user(acptr)->username)))
868 + found = 1;
869 + }
870 + else {
871 + if(match((const char*)targhost,(const char*)curhost) == 0)
872 + found = 1;
873 + else {
874 + curhost[0] = '\0';
875 + ircd_snprintf(0, curhost, sizeof(curhost), "%s!%s@%s", acptr->cli_name, cli_user(acptr)->username, cli_user(acptr)->host);
876 +
877 + if(match((const char*)targhost,(const char*)curhost) == 0)
878 + found = 1;
879 + }
880 + }
881 +
882 + if (found == 1) {
883 + found = 0; /* reset that so it doesn't get crazy go nuts */
884 +
885 + /* Show header if we've found at least 1 record */
886 + if (count == 0) {
887 + /* Output header */
888 + send_reply(sptr, RPL_DATASTR, " ");
889 + send_reply(sptr, RPL_CHKHEAD, "host", targhost);
890 +
891 + send_reply(sptr, RPL_DATASTR, " ");
892 + if (flags & CHECK_SHOWMORE)
893 + ircd_snprintf(0, outbuf, sizeof(outbuf), "No. %s nick user@host [IP] (usermodes) :realname", (flags & CHECK_CLONES) ? "[clients]" : "");
894 + else
895 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%s %-*s%-*s%s", "No.", (NICKLEN + 2), "Nick",
896 + (USERLEN + 2), "User", "Host");
897 + send_reply(sptr, RPL_DATASTR, outbuf);
898 + }
899 +
900 + if (flags & CHECK_SHOWMORE) {
901 + /* show more information */
902 + umodes = umode_str(acptr, UMODE_AND_ACCOUNT_SHORT);
903 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d ", (count+1));
904 + if (flags & CHECK_CLONES)
905 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%s[%+3hu] ", outbuf, IPcheck_nr(acptr));
906 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%s%s %s@%s [%s] (%s%s) :%s", outbuf,
907 + acptr->cli_name,
908 + cli_user(acptr)->realusername, cli_user(acptr)->realhost,
909 + ircd_ntoa(&(cli_ip(acptr))),
910 + *umodes ? "+" : "<none>", umodes,
911 + (flags & CHECK_SHOWSERVER) ? cli_name(cli_user(acptr)->server) : cli_info(acptr));
912 + } else {
913 + /* default output */
914 + ircd_snprintf(0, outbuf, sizeof(outbuf), "%-4d %-*s%-*s%s", (count+1), (NICKLEN + 2),
915 + acptr->cli_name, (USERLEN + 2), cli_user(acptr)->realusername,
916 + (flags & CHECK_SHOWIPS) ? ircd_ntoa(&(cli_ip(acptr))) : cli_user(acptr)->realhost);
917 + }
918 + send_reply(sptr, RPL_DATASTR, outbuf);
919 +
920 + /* Show channel output (if applicable) - the 50 channel limit sanity check
921 + * is specifically to prevent coredumping when someone lamely tries to /check
922 + * Q or some other channel service...
923 + */
924 + if (flags & CHECK_CHECKCHAN) {
925 + if (cli_user(acptr)->joined > 0 && cli_user(acptr)->joined <= 50) {
926 + char chntext[BUFSIZE];
927 + int len = strlen(" on channels: ");
928 + int mlen = strlen(me.cli_name) + len + strlen(sptr->cli_name);
929 + *chntext = '\0';
930 +
931 + strcpy(chntext, " on channels: ");
932 + for (lp = cli_user(acptr)->channel; lp; lp = lp->next_channel) {
933 + chptr = lp->channel;
934 + if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5) {
935 + send_reply(sptr, RPL_DATASTR, chntext);
936 + *chntext = '\0';
937 + strcpy(chntext, " on channels: ");
938 + len = strlen(chntext);
939 + }
940 + if (IsDeaf(acptr))
941 + *(chntext + len++) = '-';
942 + if (!PubChannel(chptr))
943 + *(chntext + len++) = '*';
944 + if (IsZombie(lp))
945 + *(chntext + len++) = '!';
946 + if (IsChanOp(lp))
947 + *(chntext + len++) = '@';
948 + else if (HasVoice(lp))
949 + *(chntext + len++) = '+';
950 + else if (IsDelayedJoin(lp))
951 + *(chntext + len++) = '<';
952 + if (len)
953 + *(chntext + len) = '\0';
954 +
955 + strcpy(chntext + len, chptr->chname);
956 + len += strlen(chptr->chname);
957 + strcat(chntext + len, " ");
958 + len++;
959 + }
960 + if (chntext[0] != '\0')
961 + send_reply(sptr, RPL_DATASTR, chntext);
962 +
963 + send_reply(sptr, RPL_DATASTR, " ");
964 + }
965 + }
966 + count++;
967 + }
968 + }
969 +
970 + if (count > 0) {
971 + send_reply(sptr, RPL_DATASTR, " ");
972 +
973 + ircd_snprintf(0, outbuf, sizeof(outbuf), "Matching records found:: %d", count);
974 + send_reply(sptr, RPL_DATASTR, outbuf);
975 +
976 + send_reply(sptr, RPL_ENDOFCHECK, " ");
977 + }
978 +
979 + return count;
980 +}
981 diff -r 3303f23758b0 ircd/parse.c
982 --- a/ircd/parse.c Wed Jul 17 21:30:44 2013 +0100
983 +++ b/ircd/parse.c Wed Jul 17 21:38:16 2013 +0100
984 @@ -647,6 +647,23 @@
985 { m_cap, m_cap, m_ignore, m_cap, m_ignore }
986 },
987 #endif
988 +
989 + /*
990 + * - ASUKA ---------------------------------------------------------------------
991 + * Add the command for CHECK.
992 + * This was adapted from Lain for use in Asuka.
993 + * Original code by Durzel (durzel@quakenet.org).
994 + *
995 + * qoreQ (qoreQ@quakenet.org) - 08/14/2002
996 + * -----------------------------------------------------------------------------
997 + */
998 + {
999 + MSG_CHECK,
1000 + TOK_CHECK,
1001 + 0, MAXPARA, MFLG_SLOW, 0, NULL,
1002 + { m_unregistered, m_not_oper, m_check, m_check, m_ignore }
1003 + },
1004 +
1005 /* This command is an alias for QUIT during the unregistered part of
1006 * of the server. This is because someone jumping via a broken web
1007 * proxy will send a 'POST' as their first command - which we will
1008 diff -r 3303f23758b0 ircd/s_err.c
1009 --- a/ircd/s_err.c Wed Jul 17 21:30:44 2013 +0100
1010 +++ b/ircd/s_err.c Wed Jul 17 21:38:16 2013 +0100
1011 @@ -602,19 +602,19 @@
1012 /* 284 */
1013 { RPL_FEATURE, 0, "284" },
1014 /* 285 */
1015 - { 0 },
1016 + { RPL_NEWHOSTIS, "%s: %s host %s - [%s@%s]" },
1017 /* 286 */
1018 - { 0 },
1019 + { RPL_CHKHEAD, ":Information for %s %s", "286" },
1020 /* 287 */
1021 - { 0 },
1022 + { RPL_CHANUSER, ": %s%s (%s@%s) %s (%s) %s", "287" },
1023 /* 288 */
1024 { 0 },
1025 /* 289 */
1026 { 0 },
1027 /* 290 */
1028 - { 0 },
1029 + { RPL_DATASTR, ":%s", "290" },
1030 /* 291 */
1031 - { 0 },
1032 + { RPL_ENDOFCHECK, ":%s", "291" },
1033 /* 292 */
1034 { 0 },
1035 /* 293 */
1036 @@ -848,7 +848,7 @@
1037 /* 407 */
1038 { ERR_TOOMANYTARGETS, "%s :Duplicate recipients. No message delivered", "407" },
1039 /* 408 */
1040 - { 0 },
1041 + { ERR_SEARCHNOMATCH, ":%s %s No matching record(s) found", "408" },
1042 /* 409 */
1043 { ERR_NOORIGIN, ":No origin specified", "409" },
1044 /* 410 */
1045 diff -r 3303f23758b0 ircd/s_user.c
1046 --- a/ircd/s_user.c Wed Jul 17 21:30:44 2013 +0100
1047 +++ b/ircd/s_user.c Wed Jul 17 21:38:16 2013 +0100
1048 @@ -1485,7 +1485,8 @@
1049 m--; /* Step back over the '\0' */
1050 }
1051
1052 - if (IsSetHost(cptr)) {
1053 + /* sethost parameter is wanted */
1054 + if (type != UMODE_AND_ACCOUNT && IsSetHost(cptr)) {
1055 *m++ = ' ';
1056 ircd_snprintf(0, m, USERLEN + HOSTLEN + 2, "%s@%s", cli_user(cptr)->username,
1057 cli_user(cptr)->host);