* note: it is guaranteed that parv[0]..parv[parc-1] are all
* non-NULL pointers.
*/
-#if 0
-/*
- * No need to include handlers.h here the signatures must match
- * and we don't need to force a rebuild of all the handlers everytime
- * we add a new one to the list. --Bleep
- */
-#include "handlers.h"
-#endif /* 0 */
+#include "config.h"
+
#include "channel.h"
#include "client.h"
#include "hash.h"
#include "ircd.h"
+#include "ircd_features.h"
+#include "ircd_log.h"
#include "ircd_reply.h"
#include "ircd_string.h"
#include "match.h"
#include "send.h"
#include "whocmds.h"
-#include <assert.h>
+/* #include <assert.h> -- Now using assert in ircd_log.h */
#include <string.h>
/*
- * m_whois - generic message handler
- *
- * parv[0] = sender prefix
- * parv[1] = nickname masklist
- *
- * or
- *
- * parv[1] = target server
- * parv[2] = nickname masklist
+ * 2000-07-01: Isomer
+ * * Rewritten to make this understandable
+ * * You can no longer /whois unregistered clients.
+ *
+ *
+ * General rules:
+ * /whois nick always shows the nick.
+ * /whois wild* shows the nick if:
+ * * they aren't +i and aren't on any channels.
+ * * they are on a common channel.
+ * * they aren't +i and are on a public channel. (not +p and not +s)
+ * * they aren't +i and are on a private channel. (+p but not +s)
+ * Or to look at it another way (I think):
+ * * +i users are only shown if your on a common channel.
+ * * users on +s channels only aren't shown.
+ *
+ * whois doesn't show what channels a +k client is on, for the reason that
+ * /whois X or /whois W floods a user off the server. :)
+ *
+ * nb: if the code and this comment disagree, the codes right and I screwed
+ * up.
*/
-int m_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
-{
- struct User* user;
- struct Client* acptr;
- struct Client* a2cptr;
- struct Channel* chptr;
- char* nick;
- char* tmp;
- const char* name;
- char* p = 0;
- int found;
- int len;
- int mlen;
- int total;
- static char buf[512];
- if (parc < 2)
- {
- send_reply(sptr, ERR_NONICKNAMEGIVEN);
- return 0;
- }
-
- if (parc > 2)
- {
- struct Client *acptr;
- /* For convenience: Accept a nickname as first parameter, by replacing
- it with the correct servername - as is needed by hunt_server() */
- if (MyUser(sptr) && (acptr = FindUser(parv[1])))
- parv[1] = acptr->user->server->name;
- if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) !=
- HUNTED_ISME)
- return 0;
- parv[1] = parv[2];
- }
-
- total = 0;
- for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
+/*
+ * Send whois information for acptr to sptr
+ */
+static void do_whois(struct Client* sptr, struct Client *acptr, int parc)
+{
+ struct Client *a2cptr=0;
+ struct Channel *chptr=0;
+ int mlen;
+ int len;
+ static char buf[512];
+
+ const struct User* user = cli_user(acptr);
+ const char* name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr);
+ a2cptr = feature_bool(FEAT_HIS_WHOIS_SERVERNAME) && !IsAnOper(sptr)
+ && sptr != acptr ? &his : user->server;
+ assert(user);
+ send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
+ cli_info(acptr));
+
+ /* Display the channels this user is on. */
+ if (!IsChannelService(acptr))
{
- int invis, showperson, member, wilds;
-
- found = 0;
- collapse(nick);
- wilds = (strchr(nick, '?') || strchr(nick, '*'));
- /* Do a hash lookup if the nick does not contain wilds */
- if (wilds)
+ struct Membership* chan;
+ mlen = strlen(cli_name(&me)) + strlen(cli_name(sptr)) + 12 + strlen(name);
+ len = 0;
+ *buf = '\0';
+ for (chan = user->channel; chan; chan = chan->next_channel)
{
- /*
- * We're no longer allowing remote users to generate requests with wildcards.
- */
- if (!MyConnect(sptr))
- continue;
- for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
- acptr = acptr->next)
- {
- if (!IsRegistered(acptr) || IsServer(acptr))
- continue;
- /*
- * I'm always last :-) and acptr->next == 0!!
- */
- if (IsMe(acptr))
- break;
- /*
- * 'Rules' established for sending a WHOIS reply:
- *
- * - if wildcards are being used dont send a reply if
- * the querier isnt any common channels and the
- * client in question is invisible and wildcards are
- * in use (allow exact matches only);
- *
- * - only send replies about common or public channels
- * the target user(s) are on;
- */
- user = acptr->user;
- name = (!*acptr->name) ? "?" : acptr->name;
-
- invis = acptr != sptr && IsInvisible(acptr);
- member = (user && user->channel) ? 1 : 0;
- showperson = (wilds && !invis && !member) || !wilds;
- if (user) {
- struct Membership* chan;
- for (chan = user->channel; chan; chan = chan->next_channel)
- {
- chptr = chan->channel;
- member = find_channel_member(sptr, chptr) ? 1 : 0;
- if (invis && !member)
- continue;
- if (IsZombie(chan))
- continue;
- if (member || (!invis && PubChannel(chptr)))
- {
- showperson = 1;
- break;
- }
- if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
- showperson = 1;
- }
- }
- if (!showperson)
+ chptr = chan->channel;
+
+ if (!ShowChannel(sptr, chptr)
+ && !(IsOper(sptr) && IsLocalChannel(chptr->chname)))
continue;
- if (user)
- {
- a2cptr = user->server;
- send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
- acptr->info);
- }
- else
- {
- a2cptr = &me;
- send_reply(sptr, RPL_WHOISUSER, name, "<unknown>", "<unknown>",
- "<unknown>");
- }
+ if (acptr != sptr && IsZombie(chan))
+ continue;
- found = 1;
+ /* Don't show local channels when HIS is defined, unless it's a
+ * remote WHOIS --ULtimaTe_
+ */
+ if (IsLocalChannel(chptr->chname) && (acptr != sptr) && (parc == 2)
+ && feature_bool(FEAT_HIS_WHOIS_LOCALCHAN) && !IsAnOper(sptr))
+ continue;
-exact_match:
- if (user && !IsChannelService(acptr))
- {
- struct Membership* chan;
- mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
- len = 0;
+ if (len+strlen(chptr->chname) + mlen > BUFSIZE - 5)
+ {
+ send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS, "%s :%s", name, buf);
*buf = '\0';
- for (chan = user->channel; chan; chan = chan->next_channel)
- {
- chptr = chan->channel;
- if (ShowChannel(sptr, chptr) &&
- (acptr == sptr || !IsZombie(chan)))
- {
- if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
- {
- send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS,
- "%s :%s", name, buf);
- *buf = '\0';
- len = 0;
- }
- if (IsDeaf(acptr))
- *(buf + len++) = '-';
- if (is_chan_op(acptr, chptr))
- *(buf + len++) = '@';
- else if (has_voice(acptr, chptr))
- *(buf + len++) = '+';
- else if (IsZombie(chan))
- *(buf + len++) = '!';
- if (len)
- *(buf + len) = '\0';
- strcpy(buf + len, chptr->chname);
- len += strlen(chptr->chname);
- strcat(buf + len, " ");
- len++;
- }
- }
- if (buf[0] != '\0')
- send_reply(sptr, RPL_WHOISCHANNELS, name, buf);
- }
+ len = 0;
+ }
+ if (IsDeaf(acptr))
+ *(buf + len++) = '-';
+ if (!ShowChannel(sptr, chptr))
+ *(buf + len++) = '*';
+ if (IsDelayedJoin(chan) && (sptr != acptr))
+ *(buf + len++) = '<';
+ else if (IsChanOp(chan))
+ *(buf + len++) = '@';
+ else if (HasVoice(chan))
+ *(buf + len++) = '+';
+ else if (IsZombie(chan))
+ *(buf + len++) = '!';
+ if (len)
+ *(buf + len) = '\0';
+ strcpy(buf + len, chptr->chname);
+ len += strlen(chptr->chname);
+ strcat(buf + len, " ");
+ len++;
+ }
+ if (buf[0] != '\0')
+ send_reply(sptr, RPL_WHOISCHANNELS, name, buf);
+ }
- send_reply(sptr, RPL_WHOISSERVER, name, a2cptr->name, a2cptr->info);
+ send_reply(sptr, RPL_WHOISSERVER, name, cli_name(a2cptr),
+ cli_info(a2cptr));
- if (user)
- {
- if (user->away)
- send_reply(sptr, RPL_AWAY, name, user->away);
+ if (user)
+ {
+ if (user->away)
+ send_reply(sptr, RPL_AWAY, name, user->away);
- if (IsAnOper(acptr))
- send_reply(sptr, RPL_WHOISOPERATOR, name);
+ if (SeeOper(sptr,acptr))
+ send_reply(sptr, RPL_WHOISOPERATOR, name);
- if (MyConnect(acptr))
- send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last,
- acptr->firsttime);
- }
- if (found == 2 || total++ >= MAX_WHOIS_LINES)
- break;
- }
- }
- else
- {
- /* No wildcards */
- if ((acptr = FindUser(nick)))
- {
- found = 2; /* Make sure we exit the loop after passing it once */
- user = acptr->user;
- name = (!*acptr->name) ? "?" : acptr->name;
- a2cptr = user->server;
- send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
- acptr->info);
- goto exact_match;
- }
- }
- if (!found)
- send_reply(sptr, ERR_NOSUCHNICK, nick);
- if (p)
- p[-1] = ',';
- if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
- break;
- }
- send_reply(sptr, RPL_ENDOFWHOIS, parv[1]);
+ if (IsAccount(acptr))
+ send_reply(sptr, RPL_WHOISACCOUNT, name, user->account);
- return 0;
+ if (HasHiddenHost(acptr) && (IsAnOper(sptr) || acptr == sptr))
+ send_reply(sptr, RPL_WHOISACTUALLY, name, user->username,
+ user->realhost, ircd_ntoa(&cli_ip(acptr)));
+
+ /* Hint: if your looking to add more flags to a user, eg +h, here's
+ * probably a good place to add them :)
+ */
+
+ if (MyConnect(acptr) && (!feature_bool(FEAT_HIS_WHOIS_IDLETIME) ||
+ (sptr == acptr || IsAnOper(sptr) || parc >= 3)))
+ send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last,
+ cli_firsttime(acptr));
+ }
}
/*
- * ms_whois - server message handler
- *
- * parv[0] = sender prefix
- * parv[1] = nickname masklist
- *
- * or
- *
- * parv[1] = target server
- * parv[2] = nickname masklist
+ * Search and return as many people as matched by the wild 'nick'.
+ * returns the number of people found (or, obviously, 0, if none where
+ * found).
*/
-int ms_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+static int do_wilds(struct Client* sptr, char *nick, int count, int parc)
{
- struct User* user;
- struct Client* acptr;
- struct Client* a2cptr;
- struct Channel* chptr;
- char* nick;
- char* tmp;
- const char* name;
- char* p = 0;
- int found;
- int len;
- int mlen;
- int total;
- static char buf[512];
-
- if (parc < 2)
- {
- send_reply(sptr, ERR_NONICKNAMEGIVEN);
- return 0;
- }
-
- if (parc > 2)
- {
- struct Client *acptr;
- /* For convenience: Accept a nickname as first parameter, by replacing
- it with the correct servername - as is needed by hunt_server() */
- if (MyUser(sptr) && (acptr = FindUser(parv[1])))
- parv[1] = acptr->user->server->name;
- if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) !=
- HUNTED_ISME)
- return 0;
- parv[1] = parv[2];
- }
-
- total = 0;
- for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
+ struct Client *acptr; /* Current client we're considering */
+ struct User *user; /* the user portion of the client */
+ const char *name; /* the name of this client */
+ struct Membership* chan;
+ int invis; /* does +i apply? */
+ int member; /* Is this user on any channels? */
+ int showperson; /* Should we show this person? */
+ int found = 0 ; /* How many were found? */
+
+ /* Ech! This is hideous! */
+ for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
+ acptr = cli_next(acptr))
{
- int invis, showperson, member, wilds;
-
- found = 0;
- collapse(nick);
- wilds = (strchr(nick, '?') || strchr(nick, '*'));
- /* Do a hash lookup if the nick does not contain wilds */
- if (wilds)
+ if (!IsRegistered(acptr))
+ continue;
+
+ if (IsServer(acptr))
+ continue;
+ /*
+ * I'm always last :-) and acptr->next == 0!!
+ *
+ * Isomer: Does this strike anyone else as being a horrible hideous
+ * hack?
+ */
+ if (IsMe(acptr)) {
+ assert(!cli_next(acptr));
+ break;
+ }
+
+ /*
+ * 'Rules' established for sending a WHOIS reply:
+ *
+ * - if wildcards are being used don't send a reply if
+ * the querier isn't any common channels and the
+ * client in question is invisible.
+ *
+ * - only send replies about common or public channels
+ * the target user(s) are on;
+ */
+ user = cli_user(acptr);
+ name = (!*(cli_name(acptr))) ? "?" : cli_name(acptr);
+ assert(user);
+
+ invis = (acptr != sptr) && IsInvisible(acptr);
+ member = (user && user->channel) ? 1 : 0;
+ showperson = !invis && !member;
+
+ /* Should we show this person now? */
+ if (showperson) {
+ found++;
+ do_whois(sptr, acptr, parc);
+ if (count+found>MAX_WHOIS_LINES)
+ return found;
+ continue;
+ }
+
+ /* Step through the channels this user is on */
+ for (chan = user->channel; chan; chan = chan->next_channel)
{
- /*
- * We're no longer allowing remote users to generate requests with wildcards.
- */
- if (!MyConnect(sptr))
- continue;
- for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
- acptr = acptr->next)
- {
- if (!IsRegistered(acptr) || IsServer(acptr))
- continue;
- /*
- * I'm always last :-) and acptr->next == 0!!
- */
- if (IsMe(acptr))
- break;
- /*
- * 'Rules' established for sending a WHOIS reply:
- *
- * - if wildcards are being used dont send a reply if
- * the querier isnt any common channels and the
- * client in question is invisible and wildcards are
- * in use (allow exact matches only);
- *
- * - only send replies about common or public channels
- * the target user(s) are on;
- */
- user = acptr->user;
- name = (!*acptr->name) ? "?" : acptr->name;
-
- invis = acptr != sptr && IsInvisible(acptr);
- member = (user && user->channel) ? 1 : 0;
- showperson = (wilds && !invis && !member) || !wilds;
- if (user) {
- struct Membership* chan;
- for (chan = user->channel; chan; chan = chan->next_channel)
- {
- chptr = chan->channel;
- member = find_channel_member(sptr, chptr) ? 1 : 0;
- if (invis && !member)
- continue;
- if (IsZombie(chan))
- continue;
- if (member || (!invis && PubChannel(chptr)))
- {
- showperson = 1;
- break;
- }
- if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
- showperson = 1;
- }
- }
- if (!showperson)
- continue;
+ struct Channel *chptr = chan->channel;
- if (user)
- {
- a2cptr = user->server;
- send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
- acptr->info);
- }
- else
- {
- a2cptr = &me;
- send_reply(sptr, RPL_WHOISUSER, name, "<unknown>", "<unknown>",
- "<unknown>");
- }
-
- found = 1;
-
-exact_match:
- if (user && !IsChannelService(acptr))
- {
- struct Membership* chan;
- mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
- len = 0;
- *buf = '\0';
- for (chan = user->channel; chan; chan = chan->next_channel)
- {
- chptr = chan->channel;
- if (ShowChannel(sptr, chptr) &&
- (acptr == sptr || !IsZombie(chan)))
- {
- if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
- {
- send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS,
- "%s :%s", name, buf);
- *buf = '\0';
- len = 0;
- }
- if (IsDeaf(acptr))
- *(buf + len++) = '-';
- if (is_chan_op(acptr, chptr))
- *(buf + len++) = '@';
- else if (has_voice(acptr, chptr))
- *(buf + len++) = '+';
- else if (IsZombie(chan))
- *(buf + len++) = '!';
- if (len)
- *(buf + len) = '\0';
- strcpy(buf + len, chptr->chname);
- len += strlen(chptr->chname);
- strcat(buf + len, " ");
- len++;
- }
- }
- if (buf[0] != '\0')
- send_reply(sptr, RPL_WHOISCHANNELS, name, buf);
- }
-
- send_reply(sptr, RPL_WHOISSERVER, name, a2cptr->name, a2cptr->info);
-
- if (user)
- {
- if (user->away)
- send_reply(sptr, RPL_AWAY, name, user->away);
-
- if (IsAnOper(acptr))
- send_reply(sptr, RPL_WHOISOPERATOR, name);
-
- if (MyConnect(acptr))
- send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last,
- acptr->firsttime);
- }
- if (found == 2 || total++ >= MAX_WHOIS_LINES)
- break;
+ /* If this is a public channel, show the person */
+ if (!invis && PubChannel(chptr)) {
+ showperson = 1;
+ break;
}
- }
- else
- {
- /* No wildcards */
- if ((acptr = FindUser(nick)))
- {
- found = 2; /* Make sure we exit the loop after passing it once */
- user = acptr->user;
- name = (!*acptr->name) ? "?" : acptr->name;
- a2cptr = user->server;
- send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
- acptr->info);
- goto exact_match;
+
+ /* if this channel is +p and not +s, show them */
+ if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr)) {
+ showperson = 1;
+ break;
}
- }
- if (!found)
- send_reply(sptr, ERR_NOSUCHNICK, nick);
- if (p)
- p[-1] = ',';
- if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
- break;
- }
- send_reply(sptr, RPL_ENDOFWHOIS, parv[1]);
+
+ member = find_channel_member(sptr, chptr) ? 1 : 0;
+ if (invis && !member)
+ continue;
- return 0;
+ /* If sptr isn't really on this channel, skip it */
+ if (IsZombie(chan))
+ continue;
+
+ /* Is this a common channel? */
+ if (member) {
+ showperson = 1;
+ break;
+ }
+ } /* of for (chan in channels) */
+
+ /* Don't show this person */
+ if (!showperson)
+ continue;
+
+ do_whois(sptr, acptr, parc);
+ found++;
+ if (count+found>MAX_WHOIS_LINES)
+ return found;
+ } /* of global client list */
+
+ return found;
}
/*
- * mo_whois - oper message handler
+ * m_whois - generic message handler
*
* parv[0] = sender prefix
* parv[1] = nickname masklist
*
* or
*
- * parv[1] = target server
+ * parv[1] = target server, or a nickname representing a server to target.
* parv[2] = nickname masklist
*/
-int mo_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+int m_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
- struct User* user;
- struct Client* acptr;
- struct Client* a2cptr;
- struct Channel* chptr;
char* nick;
char* tmp;
- const char* name;
char* p = 0;
- int found;
- int len;
- int mlen;
- int total;
- static char buf[512];
+ int found = 0;
+ int total = 0;
+ int wildscount = 0;
if (parc < 2)
{
if (parc > 2)
{
- struct Client *acptr;
/* For convenience: Accept a nickname as first parameter, by replacing
- it with the correct servername - as is needed by hunt_server() */
- if (MyUser(sptr) && (acptr = FindUser(parv[1])))
- parv[1] = acptr->user->server->name;
+ * it with the correct servername - as is needed by hunt_server().
+ * This is the secret behind the /whois nick nick trick.
+ */
+ if (feature_int(FEAT_HIS_REMOTE))
+ {
+ /* If remote queries are disabled, then use the *second* parameter of
+ * of whois, so /whois nick nick still works.
+ */
+ if (!IsAnOper(sptr))
+ {
+ if (!FindUser(parv[2]))
+ {
+ send_reply(sptr, ERR_NOSUCHNICK, parv[2]);
+ send_reply(sptr, RPL_ENDOFWHOIS, parv[2]);
+ return 0;
+ }
+ parv[1] = parv[2];
+ }
+ }
+
if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) !=
- HUNTED_ISME)
- return 0;
+ HUNTED_ISME)
+ return 0;
+
parv[1] = parv[2];
}
- total = 0;
for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
{
- int invis, showperson, member, wilds;
+ int wilds;
found = 0;
+
collapse(nick);
+
wilds = (strchr(nick, '?') || strchr(nick, '*'));
- /* Do a hash lookup if the nick does not contain wilds */
- if (wilds)
- {
- /*
- * We're no longer allowing remote users to generate requests with wildcards.
- */
- if (!MyConnect(sptr))
- continue;
- for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
- acptr = acptr->next)
- {
- if (!IsRegistered(acptr) || IsServer(acptr))
- continue;
- /*
- * I'm always last :-) and acptr->next == 0!!
- */
- if (IsMe(acptr))
- break;
- /*
- * 'Rules' established for sending a WHOIS reply:
- *
- * - if wildcards are being used dont send a reply if
- * the querier isnt any common channels and the
- * client in question is invisible and wildcards are
- * in use (allow exact matches only);
- *
- * - only send replies about common or public channels
- * the target user(s) are on;
- */
- user = acptr->user;
- name = (!*acptr->name) ? "?" : acptr->name;
-
- invis = acptr != sptr && IsInvisible(acptr);
- member = (user && user->channel) ? 1 : 0;
- showperson = (wilds && !invis && !member) || !wilds;
- if (user) {
- struct Membership* chan;
- for (chan = user->channel; chan; chan = chan->next_channel)
- {
- chptr = chan->channel;
- member = find_channel_member(sptr, chptr) ? 1 : 0;
- if (invis && !member)
- continue;
- if (IsZombie(chan))
- continue;
- if (member || (!invis && PubChannel(chptr)))
- {
- showperson = 1;
- break;
- }
- if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
- showperson = 1;
- }
- }
- if (!showperson)
- continue;
-
- if (user)
- {
- a2cptr = user->server;
- send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
- acptr->info);
- }
- else
- {
- a2cptr = &me;
- send_reply(sptr, RPL_WHOISUSER, name, "<unknown>", "<unknown>",
- "<unknown>");
- }
-
+ if (!wilds) {
+ struct Client *acptr = 0;
+ /* No wildcards */
+ acptr = FindUser(nick);
+ if (acptr && !IsServer(acptr)) {
+ do_whois(sptr, acptr, parc);
found = 1;
-
-exact_match:
- if (user && !IsChannelService(acptr))
- {
- struct Membership* chan;
- mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
- len = 0;
- *buf = '\0';
- for (chan = user->channel; chan; chan = chan->next_channel)
- {
- chptr = chan->channel;
- if (ShowChannel(sptr, chptr) &&
- (acptr == sptr || !IsZombie(chan)))
- {
- if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
- {
- send_reply(sptr, SND_EXPLICIT | RPL_WHOISCHANNELS,
- "%s :%s", name, buf);
- *buf = '\0';
- len = 0;
- }
- if (IsDeaf(acptr))
- *(buf + len++) = '-';
- if (is_chan_op(acptr, chptr))
- *(buf + len++) = '@';
- else if (has_voice(acptr, chptr))
- *(buf + len++) = '+';
- else if (IsZombie(chan))
- *(buf + len++) = '!';
- if (len)
- *(buf + len) = '\0';
- strcpy(buf + len, chptr->chname);
- len += strlen(chptr->chname);
- strcat(buf + len, " ");
- len++;
- }
- }
- if (buf[0] != '\0')
- send_reply(sptr, RPL_WHOISCHANNELS, name, buf);
- }
-
- send_reply(sptr, RPL_WHOISSERVER, name, a2cptr->name, a2cptr->info);
-
- if (user)
- {
- if (user->away)
- send_reply(sptr, RPL_AWAY, name, user->away);
-
- if (IsAnOper(acptr))
- send_reply(sptr, RPL_WHOISOPERATOR, name);
-
- if (MyConnect(acptr))
- send_reply(sptr, RPL_WHOISIDLE, name, CurrentTime - user->last,
- acptr->firsttime);
- }
- if (found == 2 || total++ >= MAX_WHOIS_LINES)
- break;
}
}
- else
+ else /* wilds */
{
- /* No wildcards */
- if ((acptr = FindUser(nick)))
- {
- found = 2; /* Make sure we exit the loop after passing it once */
- user = acptr->user;
- name = (!*acptr->name) ? "?" : acptr->name;
- a2cptr = user->server;
- send_reply(sptr, RPL_WHOISUSER, name, user->username, user->host,
- acptr->info);
- goto exact_match;
+ if (++wildscount > 3) {
+ send_reply(sptr, ERR_QUERYTOOLONG, parv[1]);
+ break;
}
+ found=do_wilds(sptr, nick, total, parc);
}
+
if (!found)
send_reply(sptr, ERR_NOSUCHNICK, nick);
+ total+=found;
+ if (total >= MAX_WHOIS_LINES) {
+ send_reply(sptr, ERR_QUERYTOOLONG, parv[1]);
+ break;
+ }
if (p)
p[-1] = ',';
- if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
- break;
- }
+ } /* of tokenised parm[1] */
send_reply(sptr, RPL_ENDOFWHOIS, parv[1]);
return 0;
}
-
-
-#if 0
/*
- * m_whois
+ * ms_whois - server message handler
*
* parv[0] = sender prefix
* parv[1] = nickname masklist
*
* or
*
- * parv[1] = target server
+ * parv[1] = target server, or a nickname representing a server to target.
* parv[2] = nickname masklist
*/
-int m_whois(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+int ms_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
{
- struct User* user;
- struct Client* acptr;
- struct Client* a2cptr;
- struct Channel* chptr;
char* nick;
char* tmp;
- char* name;
char* p = 0;
- int found;
- int len;
- int mlen;
- int total;
- static char buf[512];
+ int found = 0;
+ int total = 0;
if (parc < 2)
{
- sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); /* XXX DEAD */
+ send_reply(sptr, ERR_NONICKNAMEGIVEN);
return 0;
}
if (parc > 2)
{
- struct Client *acptr;
- /* For convenience: Accept a nickname as first parameter, by replacing
- it with the correct servername - as is needed by hunt_server() */
- if (MyUser(sptr) && (acptr = FindUser(parv[1])))
- parv[1] = acptr->user->server->name;
- if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) != /* XXX DEAD */
+ if (hunt_server_cmd(sptr, CMD_WHOIS, cptr, 0, "%C :%s", 1, parc, parv) !=
HUNTED_ISME)
return 0;
parv[1] = parv[2];
}
total = 0;
+
for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
{
- int invis, showperson, member, wilds;
+ struct Client *acptr = 0;
found = 0;
+
collapse(nick);
- wilds = (strchr(nick, '?') || strchr(nick, '*'));
- /* Do a hash lookup if the nick does not contain wilds */
- if (wilds)
- {
- /*
- * We're no longer allowing remote users to generate requests with wildcards.
- */
- if (!MyConnect(sptr))
- continue;
- for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
- acptr = acptr->next)
- {
- if (!IsRegistered(acptr) || IsServer(acptr))
- continue;
- /*
- * I'm always last :-) and acptr->next == NULL!!
- */
- if (IsMe(acptr))
- break;
- /*
- * 'Rules' established for sending a WHOIS reply:
- *
- * - if wildcards are being used dont send a reply if
- * the querier isnt any common channels and the
- * client in question is invisible and wildcards are
- * in use (allow exact matches only);
- *
- * - only send replies about common or public channels
- * the target user(s) are on;
- */
- user = acptr->user;
- name = (!*acptr->name) ? "?" : acptr->name;
-
- invis = acptr != sptr && IsInvisible(acptr);
- member = (user && user->channel) ? 1 : 0;
- showperson = (wilds && !invis && !member) || !wilds;
- if (user) {
- struct Membership* chan;
- for (chan = user->channel; chan; chan = chan->next_channel)
- {
- chptr = chan->channel;
- member = find_channel_member(sptr, chptr) ? 1 : 0;
- if (invis && !member)
- continue;
- if (IsZombie(chan))
- continue;
- if (member || (!invis && PubChannel(chptr)))
- {
- showperson = 1;
- break;
- }
- if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
- showperson = 1;
- }
- }
- if (!showperson)
- continue;
-
- if (user)
- {
- a2cptr = user->server;
- sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name, /* XXX DEAD */
- parv[0], name, user->username, user->host, acptr->info);
- }
- else
- {
- a2cptr = &me;
- sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name, /* XXX DEAD */
- parv[0], name, "<unknown>", "<unknown>", "<unknown>");
- }
-
- found = 1;
-
-exact_match:
- if (user && !IsChannelService(acptr))
- {
- struct Membership* chan;
- mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
- len = 0;
- *buf = '\0';
- for (chan = user->channel; chan; chan = chan->next_channel)
- {
- chptr = chan->channel;
- if (ShowChannel(sptr, chptr) &&
- (acptr == sptr || !IsZombie(chan)))
- {
- if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
- {
- sendto_one(sptr, ":%s %d %s %s :%s", /* XXX DEAD */
- me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
- *buf = '\0';
- len = 0;
- }
- if (IsDeaf(acptr))
- *(buf + len++) = '-';
- if (is_chan_op(acptr, chptr))
- *(buf + len++) = '@';
- else if (has_voice(acptr, chptr))
- *(buf + len++) = '+';
- else if (IsZombie(chan))
- *(buf + len++) = '!';
- if (len)
- *(buf + len) = '\0';
- strcpy(buf + len, chptr->chname);
- len += strlen(chptr->chname);
- strcat(buf + len, " ");
- len++;
- }
- }
- if (buf[0] != '\0')
- sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS), /* XXX DEAD */
- me.name, parv[0], name, buf);
- }
-
- sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, /* XXX DEAD */
- parv[0], name, a2cptr->name, a2cptr->info);
-
- if (user)
- {
- if (user->away)
- sendto_one(sptr, rpl_str(RPL_AWAY), me.name, /* XXX DEAD */
- parv[0], name, user->away);
+
- if (IsAnOper(acptr))
- sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR), /* XXX DEAD */
- me.name, parv[0], name);
-
- if (MyConnect(acptr))
- sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name, /* XXX DEAD */
- parv[0], name, CurrentTime - user->last, acptr->firsttime);
- }
- if (found == 2 || total++ >= MAX_WHOIS_LINES)
- break;
- }
- }
- else
- {
- /* No wildcards */
- if ((acptr = FindUser(nick)))
- {
- found = 2; /* Make sure we exit the loop after passing it once */
- user = acptr->user;
- name = (!*acptr->name) ? "?" : acptr->name;
- a2cptr = user->server;
- sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name, /* XXX DEAD */
- parv[0], name, user->username, user->host, acptr->info);
- goto exact_match;
- }
+ acptr = FindUser(nick);
+ if (acptr && !IsServer(acptr)) {
+ found++;
+ do_whois(sptr, acptr, parc);
}
+
if (!found)
- sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick); /* XXX DEAD */
+ send_reply(sptr, ERR_NOSUCHNICK, nick);
+
+ total+=found;
+
+ if (total >= MAX_WHOIS_LINES) {
+ send_reply(sptr, ERR_QUERYTOOLONG, parv[1]);
+ break;
+ }
+
if (p)
p[-1] = ',';
- if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
- break;
- }
- sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]); /* XXX DEAD */
+ } /* of tokenised parm[1] */
+ send_reply(sptr, RPL_ENDOFWHOIS, parv[1]);
return 0;
}
-#endif /* 0 */