* 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_chattr.h"
+#include "ircd_features.h"
#include "ircd_log.h"
#include "ircd_reply.h"
#include "ircd_string.h"
#include "numeric.h"
#include "numnicks.h"
#include "send.h"
-#include "support.h"
#include "whocmds.h"
-
-#include <assert.h>
+/* #include <assert.h> -- Now using assert in ircd_log.h */
#include <string.h>
/*
- * A little spin-marking utility to tell us wich clients we have already
- * processed and wich not
+ * A little spin-marking utility to tell us which clients we have already
+ * processed and which not
*/
static int who_marker = 0;
static void move_marker(void)
struct Client *acptr; /* Client to show */
int bitsel; /* Mask of selectors to apply */
- int matchsel; /* Wich fields the match should apply on */
+ int matchsel; /* Which fields the match should apply on */
int counter; /* Query size counter,
initially used to count fields */
int commas; /* Does our mask contain any comma ?
while (((ch = *(p++))) && (ch != '%') && (ch != ','))
switch (ch)
{
+ case 'd':
+ case 'D':
+ bitsel |= WHOSELECT_DELAY;
+ continue;
case 'o':
case 'O':
bitsel |= WHOSELECT_OPER;
continue;
case 's':
case 'S':
-#ifdef HEAD_IN_SAND_WHO_SERVERNAME
- if (IsAnOper(sptr))
-#endif
- matchsel |= WHO_FIELD_SER;
+ matchsel |= WHO_FIELD_SER;
continue;
case 'r':
case 'R':
matchsel |= WHO_FIELD_REN;
continue;
+ case 'a':
+ case 'A':
+ matchsel |= WHO_FIELD_ACC;
+ continue;
}
if (ch == '%')
while ((ch = *p++) && (ch != ','))
break;
case 's':
case 'S':
-#ifdef HEAD_IN_SAND_WHO_SERVERNAME
- if (IsAnOper(sptr))
-#endif
- fields |= WHO_FIELD_SER;
+ fields |= WHO_FIELD_SER;
break;
case 't':
case 'T':
case 'U':
fields |= WHO_FIELD_UID;
break;
+ case 'a':
+ case 'A':
+ fields |= WHO_FIELD_ACC;
+ break;
+ case 'o':
+ case 'O':
+ fields |= WHO_FIELD_OPL;
+ break;
default:
break;
}
if (!fields)
counter = 7;
+ if (feature_bool(FEAT_HIS_WHO_SERVERNAME) && !IsAnOper(sptr))
+ matchsel &= ~WHO_FIELD_SER;
+
if (qrt && (fields & WHO_FIELD_QTY))
{
p = qrt;
for (member = chptr->members; member; member = member->next_member)
{
acptr = member->user;
- if ((bitsel & WHOSELECT_OPER) &&
- !(IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) ||
- HasPriv(sptr, PRIV_SEE_OPERS))))
+ if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr))
continue;
- if ((acptr != sptr) && (member->status & CHFL_ZOMBIE))
+ if ((acptr != sptr)
+ && ((member->status & CHFL_ZOMBIE)
+ || ((member->status & CHFL_DELAYED)
+ && !(bitsel & WHOSELECT_DELAY))))
continue;
if (!(isthere || (SEE_USER(sptr, acptr, bitsel))))
continue;
else
{
if ((acptr = FindUser(nick)) &&
- ((!(bitsel & WHOSELECT_OPER)) ||
- (IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) ||
- HasPriv(sptr, PRIV_SEE_OPERS)))) &&
+ ((!(bitsel & WHOSELECT_OPER)) || SeeOper(sptr,acptr)) &&
Process(acptr) && SHOW_MORE(sptr, counter))
{
do_who(sptr, acptr, 0, fields, qrt);
real mask and try to match all relevant fields */
if (!(commas || (counter < 1)))
{
+ struct irc_in_addr imask;
int minlen, cset;
- static struct in_mask imask;
+ unsigned char ibits;
+
if (mask)
{
matchcomp(mymask, &minlen, &cset, mask);
- if (matchcompIP(&imask, mask))
+ if (!ipmask_parse(mask, &imask, &ibits))
matchsel &= ~WHO_FIELD_NIP;
if ((minlen > NICKLEN) || !(cset & NTL_IRCNK))
matchsel &= ~WHO_FIELD_NIC;
matchsel &= ~WHO_FIELD_UID;
if ((minlen > HOSTLEN) || !(cset & NTL_IRCHN))
matchsel &= ~WHO_FIELD_HOS;
+ if ((minlen > ACCOUNTLEN))
+ matchsel &= ~WHO_FIELD_ACC;
}
/* First of all loop through the clients in common channels */
if (!(IsUser(acptr) && Process(acptr)))
continue; /* Now Process() is at the beginning, if we fail
we'll never have to show this acptr in this query */
- if ((bitsel & WHOSELECT_OPER) &&
- !(IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) ||
- HasPriv(sptr, PRIV_SEE_OPERS))))
+ if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr))
continue;
if ((mask) &&
((!(matchsel & WHO_FIELD_NIC))
&& ((!(matchsel & WHO_FIELD_UID))
|| matchexec(cli_user(acptr)->username, mymask, minlen))
&& ((!(matchsel & WHO_FIELD_SER))
- || (!(cli_flags(cli_user(acptr)->server) & FLAGS_MAP)))
+ || (!(HasFlag(cli_user(acptr)->server, FLAG_MAP))))
&& ((!(matchsel & WHO_FIELD_HOS))
|| matchexec(cli_user(acptr)->host, mymask, minlen))
+ && ((!(matchsel & WHO_FIELD_HOS))
+ || !HasHiddenHost(acptr)
+ || !IsAnOper(sptr)
+ || matchexec(cli_user(acptr)->realhost, mymask, minlen))
&& ((!(matchsel & WHO_FIELD_REN))
|| matchexec(cli_info(acptr), mymask, minlen))
&& ((!(matchsel & WHO_FIELD_NIP))
- || ((((cli_ip(acptr).s_addr & imask.mask.s_addr) !=
- imask.bits.s_addr)) || (imask.fall
- && matchexec(ircd_ntoa((const char*) &(cli_ip(acptr))), mymask, minlen)))))
+ || (HasHiddenHost(acptr) && !IsAnOper(sptr))
+ || !ipmask_check(&cli_ip(acptr), &imask, ibits))
+ && ((!(matchsel & WHO_FIELD_ACC))
+ || matchexec(cli_user(acptr)->account, mymask, minlen)))
continue;
if (!SHOW_MORE(sptr, counter))
break;
{
if (!(IsUser(acptr) && Process(acptr)))
continue;
- if ((bitsel & WHOSELECT_OPER) &&
- !(IsAnOper(acptr) && (HasPriv(acptr, PRIV_DISPLAY) ||
- HasPriv(sptr, PRIV_SEE_OPERS))))
+ if ((bitsel & WHOSELECT_OPER) && !SeeOper(sptr,acptr))
continue;
if (!(SEE_USER(sptr, acptr, bitsel)))
continue;
&& ((!(matchsel & WHO_FIELD_UID))
|| matchexec(cli_user(acptr)->username, mymask, minlen))
&& ((!(matchsel & WHO_FIELD_SER))
- || (!(cli_flags(cli_user(acptr)->server) & FLAGS_MAP)))
+ || (!(HasFlag(cli_user(acptr)->server, FLAG_MAP))))
&& ((!(matchsel & WHO_FIELD_HOS))
|| matchexec(cli_user(acptr)->host, mymask, minlen))
- && ((!(matchsel & WHO_FIELD_REN))
- || matchexec(cli_info(acptr), mymask, minlen))
- && ((!(matchsel & WHO_FIELD_NIP))
- || ((((cli_ip(acptr).s_addr & imask.mask.s_addr) != imask.bits.s_addr))
- || (imask.fall
- && matchexec(ircd_ntoa((const char*) &(cli_ip(acptr))), mymask, minlen)))))
- continue;
- if (!SHOW_MORE(sptr, counter))
- break;
- do_who(sptr, acptr, 0, fields, qrt);
- }
- }
-
- /* Make a clean mask suitable to be sent in the "end of" */
- if (mask && (p = strchr(mask, ' ')))
- *p = '\0';
- send_reply(sptr, RPL_ENDOFWHO, BadPtr(mask) ? "*" : mask);
-
- /* Notify the user if we decided that his query was too long */
- if (counter < 0)
- send_reply(sptr, ERR_QUERYTOOLONG, "WHO");
-
- return 0;
-}
-
-
-#if 0
-/*
- * m_who
- *
- * parv[0] = sender prefix
- * parv[1] = nickname mask list
- * parv[2] = additional selection flag, only 'o' for now.
- * and %flags to specify what fields to output
- * plus a ,querytype if the t flag is specified
- * so the final thing will be like o%tnchu,777
- * parv[3] = _optional_ parameter that overrides parv[1]
- * This can be used as "/quote who foo % :The Black Hacker
- * to find me, parv[3] _can_ contain spaces !.
- */
-
-int m_who(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
-{
- char *mask; /* The mask we are looking for */
- char ch; /* Scratch char register */
- struct Channel *chptr; /* Channel to show */
- struct Client *acptr; /* Client to show */
-
- int bitsel; /* Mask of selectors to apply */
- int matchsel; /* Wich fields the match should apply on */
- int counter; /* Query size counter,
- initially used to count fields */
- int commas; /* Does our mask contain any comma ?
- If so is a list.. */
- int fields; /* Mask of fields to show */
- int isthere = 0; /* When this set the user is member of chptr */
- char *nick; /* Single element extracted from
- the mask list */
- char *p; /* Scratch char pointer */
- char *qrt; /* Pointer to the query type */
- static char mymask[512]; /* To save the mask before corrupting it */
-
- /* Let's find where is our mask, and if actually contains something */
- mask = ((parc > 1) ? parv[1] : 0);
- if (parc > 3 && parv[3])
- mask = parv[3];
- if (mask && ((mask[0] == '\0') ||
- (mask[1] == '\0' && ((mask[0] == '0') || (mask[0] == '*')))))
- mask = 0;
-
- /* Evaluate the flags now, we consider the second parameter
- as "matchFlags%fieldsToInclude,querytype" */
- bitsel = fields = counter = matchsel = 0;
- qrt = 0;
- if (parc > 2 && parv[2] && *parv[2])
- {
- p = parv[2];
- while (((ch = *(p++))) && (ch != '%') && (ch != ','))
- switch (ch)
- {
- case 'o':
- case 'O':
- bitsel |= WHOSELECT_OPER;
- continue;
- case 'x':
- case 'X':
- bitsel |= WHOSELECT_EXTRA;
-#ifdef WPATH
- if (IsAnOper(sptr))
- write_log(WPATH, "# " TIME_T_FMT " %s!%s@%s WHO %s %s\n", /* XXX DEAD */
- CurrentTime, sptr->name, sptr->user->username, sptr->user->host,
- (BadPtr(parv[3]) ? parv[1] : parv[3]), parv[2]);
-#endif /* WPATH */
- continue;
- case 'n':
- case 'N':
- matchsel |= WHO_FIELD_NIC;
- continue;
- case 'u':
- case 'U':
- matchsel |= WHO_FIELD_UID;
- continue;
- case 'h':
- case 'H':
- matchsel |= WHO_FIELD_HOS;
- continue;
- case 'i':
- case 'I':
- matchsel |= WHO_FIELD_NIP;
- continue;
- case 's':
- case 'S':
- matchsel |= WHO_FIELD_SER;
- continue;
- case 'r':
- case 'R':
- matchsel |= WHO_FIELD_REN;
- continue;
- }
- if (ch == '%')
- while ((ch = *p++) && (ch != ','))
- {
- counter++;
- switch (ch)
- {
- case 'c':
- case 'C':
- fields |= WHO_FIELD_CHA;
- break;
- case 'd':
- case 'D':
- fields |= WHO_FIELD_DIS;
- break;
- case 'f':
- case 'F':
- fields |= WHO_FIELD_FLA;
- break;
- case 'h':
- case 'H':
- fields |= WHO_FIELD_HOS;
- break;
- case 'i':
- case 'I':
- fields |= WHO_FIELD_NIP;
- break;
- case 'n':
- case 'N':
- fields |= WHO_FIELD_NIC;
- break;
- case 'r':
- case 'R':
- fields |= WHO_FIELD_REN;
- break;
- case 's':
- case 'S':
- fields |= WHO_FIELD_SER;
- break;
- case 't':
- case 'T':
- fields |= WHO_FIELD_QTY;
- break;
- case 'u':
- case 'U':
- fields |= WHO_FIELD_UID;
- break;
- default:
- break;
- }
- };
- if (ch)
- qrt = p;
- }
-
- if (!matchsel)
- matchsel = WHO_FIELD_DEF;
- if (!fields)
- counter = 7;
-
- if (qrt && (fields & WHO_FIELD_QTY))
- {
- p = qrt;
- if (!((*p > '9') || (*p < '0')))
- p++;
- if (!((*p > '9') || (*p < '0')))
- p++;
- if (!((*p > '9') || (*p < '0')))
- p++;
- *p = '\0';
- }
- else
- qrt = 0;
-
- /* I'd love to add also a check on the number of matches fields per time */
- counter = (2048 / (counter + 4));
- if (mask && (strlen(mask) > 510))
- mask[510] = '\0';
- move_marker();
- commas = (mask && strchr(mask, ','));
-
- /* First treat mask as a list of plain nicks/channels */
- if (mask)
- {
- strcpy(mymask, mask);
- for (p = 0, nick = ircd_strtok(&p, mymask, ","); nick;
- nick = ircd_strtok(&p, 0, ","))
- {
- if (IsChannelName(nick) && (chptr = FindChannel(nick)))
- {
- isthere = (find_channel_member(sptr, chptr) != 0);
- if (isthere || SEE_CHANNEL(sptr, chptr, bitsel))
- {
- struct Membership* member;
- for (member = chptr->members; member; member = member->next_member)
- {
- acptr = member->user;
- if ((bitsel & WHOSELECT_OPER) && !(IsAnOper(acptr)))
- continue;
- if ((acptr != sptr) && (member->status & CHFL_ZOMBIE))
- continue;
- if (!(isthere || (SEE_USER(sptr, acptr, bitsel))))
- continue;
- if (!Process(acptr)) /* This can't be moved before other checks */
- continue;
- if (!(isthere || (SHOW_MORE(sptr, counter))))
- break;
- do_who(sptr, acptr, chptr, fields, qrt);
- }
- }
- }
- else
- {
- if ((acptr = FindUser(nick)) &&
- ((!(bitsel & WHOSELECT_OPER)) || IsAnOper(acptr)) &&
- Process(acptr) && SHOW_MORE(sptr, counter))
- {
- do_who(sptr, acptr, 0, fields, qrt);
- }
- }
- }
- }
-
- /* If we didn't have any comma in the mask treat it as a
- real mask and try to match all relevant fields */
- if (!(commas || (counter < 1)))
- {
- int minlen, cset;
- static struct in_mask imask;
- if (mask)
- {
- matchcomp(mymask, &minlen, &cset, mask);
- if (matchcompIP(&imask, mask))
- matchsel &= ~WHO_FIELD_NIP;
- if ((minlen > NICKLEN) || !(cset & NTL_IRCNK))
- matchsel &= ~WHO_FIELD_NIC;
- if ((matchsel & WHO_FIELD_SER) &&
- ((minlen > HOSTLEN) || (!(cset & NTL_IRCHN))
- || (!markMatchexServer(mymask, minlen))))
- matchsel &= ~WHO_FIELD_SER;
- if ((minlen > USERLEN) || !(cset & NTL_IRCUI))
- matchsel &= ~WHO_FIELD_UID;
- if ((minlen > HOSTLEN) || !(cset & NTL_IRCHN))
- matchsel &= ~WHO_FIELD_HOS;
- }
-
- /* First of all loop through the clients in common channels */
- if ((!(counter < 1)) && matchsel) {
- struct Membership* member;
- struct Membership* chan;
- for (chan = sptr->user->channel; chan; chan = chan->next_channel) {
- chptr = chan->channel;
- for (member = chptr->members; member; member = member->next_member)
- {
- acptr = member->user;
- if (!(IsUser(acptr) && Process(acptr)))
- continue; /* Now Process() is at the beginning, if we fail
- we'll never have to show this acptr in this query */
- if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
- continue;
- if ((mask) &&
- ((!(matchsel & WHO_FIELD_NIC))
- || matchexec(acptr->name, mymask, minlen))
- && ((!(matchsel & WHO_FIELD_UID))
- || matchexec(acptr->user->username, mymask, minlen))
- && ((!(matchsel & WHO_FIELD_SER))
- || (!(acptr->user->server->flags & FLAGS_MAP)))
- && ((!(matchsel & WHO_FIELD_HOS))
- || matchexec(acptr->user->host, mymask, minlen))
- && ((!(matchsel & WHO_FIELD_REN))
- || matchexec(acptr->info, mymask, minlen))
- && ((!(matchsel & WHO_FIELD_NIP))
- || ((((acptr->ip.s_addr & imask.mask.s_addr) !=
- imask.bits.s_addr)) || (imask.fall
- && matchexec(inet_ntoa(acptr->ip), mymask, minlen)))))
- continue;
- if (!SHOW_MORE(sptr, counter))
- break;
- do_who(sptr, acptr, chptr, fields, qrt);
- }
- }
- }
- /* Loop through all clients :-\, if we still have something to match to
- and we can show more clients */
- if ((!(counter < 1)) && matchsel)
- for (acptr = me.prev; acptr; acptr = acptr->prev)
- {
- if (!(IsUser(acptr) && Process(acptr)))
- continue;
- if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
- continue;
- if (!(SEE_USER(sptr, acptr, bitsel)))
- continue;
- if ((mask) &&
- ((!(matchsel & WHO_FIELD_NIC))
- || matchexec(acptr->name, mymask, minlen))
- && ((!(matchsel & WHO_FIELD_UID))
- || matchexec(acptr->user->username, mymask, minlen))
- && ((!(matchsel & WHO_FIELD_SER))
- || (!(acptr->user->server->flags & FLAGS_MAP)))
&& ((!(matchsel & WHO_FIELD_HOS))
- || matchexec(acptr->user->host, mymask, minlen))
+ || !HasHiddenHost(acptr)
+ || !IsAnOper(sptr)
+ || matchexec(cli_user(acptr)->realhost, mymask, minlen))
&& ((!(matchsel & WHO_FIELD_REN))
- || matchexec(acptr->info, mymask, minlen))
+ || matchexec(cli_info(acptr), mymask, minlen))
&& ((!(matchsel & WHO_FIELD_NIP))
- || ((((acptr->ip.s_addr & imask.mask.s_addr) != imask.bits.s_addr))
- || (imask.fall
- && matchexec(inet_ntoa(acptr->ip), mymask, minlen)))))
+ || (HasHiddenHost(acptr) && !IsAnOper(sptr))
+ || !ipmask_check(&cli_ip(acptr), &imask, ibits))
+ && ((!(matchsel & WHO_FIELD_ACC))
+ || matchexec(cli_user(acptr)->account, mymask, minlen)))
continue;
if (!SHOW_MORE(sptr, counter))
break;
/* Make a clean mask suitable to be sent in the "end of" */
if (mask && (p = strchr(mask, ' ')))
*p = '\0';
- sendto_one(sptr, rpl_str(RPL_ENDOFWHO), /* XXX DEAD */
- me.name, parv[0], BadPtr(mask) ? "*" : mask);
-
/* Notify the user if we decided that his query was too long */
if (counter < 0)
- sendto_one(sptr, err_str(ERR_QUERYTOOLONG), me.name, parv[0], "WHO"); /* XXX DEAD */
+ send_reply(sptr, ERR_QUERYTOOLONG, BadPtr(mask) ? "*" : mask);
+ send_reply(sptr, RPL_ENDOFWHO, BadPtr(mask) ? "*" : mask);
return 0;
}
-#endif /* 0 */
-