X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fm_whois.c;h=01c9db55db3d1d8311a6b89f76bc40ffa79a9930;hb=refs%2Fheads%2Fupstream;hp=0f2bf933b53fd10f9efb9d70f7ea0a23bb71dfad;hpb=8049d81b2a13d802a41016396781b02fad16f443;p=ircu2.10.12-pk.git diff --git a/ircd/m_whois.c b/ircd/m_whois.c index 0f2bf93..01c9db5 100644 --- a/ircd/m_whois.c +++ b/ircd/m_whois.c @@ -79,18 +79,14 @@ * 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" @@ -101,455 +97,260 @@ #include "send.h" #include "whocmds.h" -#include +/* #include -- Now using assert in ircd_log.h */ #include /* - * 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, "", "", - ""); - } + 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 */ + 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); + 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, "", "", - ""); - } - - 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) { @@ -559,396 +360,141 @@ int mo_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) 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, "", "", - ""); - } - + 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, "", "", ""); - } - - 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 */