diff --git a/src/modules/m_who.c b/src/modules/m_who.c index 3b47b8532..255e9a6f8 100644 --- a/src/modules/m_who.c +++ b/src/modules/m_who.c @@ -811,19 +811,57 @@ static char *first_visible_channel(aClient *sptr, aClient *acptr, int *flg) for (lp = acptr->user->channel; lp; lp = lp->next) { - aChannel *chptr = lp->chptr; - int cansee = ShowChannel(sptr, chptr); + aChannel *chptr = lp->chptr; + Hook *h; + int ret = EX_ALLOW; + int operoverride = 0; + int showchannel = 0; + + /* Note that the code below is almost identical to the one in /WHOIS */ - if (cansee && (acptr->umodes & UMODE_HIDEWHOIS) && !IsMember(sptr, chptr)) - cansee = 0; - if (!cansee) + if (ShowChannel(sptr, chptr)) + showchannel = 1; + + for (h = Hooks[HOOKTYPE_SEE_CHANNEL_IN_WHOIS]; h; h = h->next) { - if (OPCanSeeSecret(sptr)) - *flg |= FVC_HIDDEN; - else - continue; + int n = (*(h->func.intfunc))(sptr, acptr, chptr); + /* Hook return values: + * EX_ALLOW means 'yes is ok, as far as modules are concerned' + * EX_DENY means 'hide this channel, unless oper overriding' + * EX_ALWAYS_DENY means 'hide this channel, always' + * ... with the exception that we always show the channel if you /WHOIS yourself + */ + if (n == EX_DENY) + { + ret = EX_DENY; + } + else if (n == EX_ALWAYS_DENY) + { + ret = EX_ALWAYS_DENY; + break; + } } - return chptr->chname; + + if (ret == EX_DENY) + showchannel = 0; + + if (!showchannel && (OPCanSeeSecret(sptr) || OperClass_evaluateACLPath("override:whois",sptr,NULL,chptr,NULL))) + { + showchannel = 1; /* OperOverride */ + operoverride = 1; + } + + if ((ret == EX_ALWAYS_DENY) && (acptr != sptr)) + continue; /* a module asked us to really not expose this channel, so we don't (except target==ourselves). */ + + if (acptr == sptr) + showchannel = 1; + + if (operoverride) + *flg |= FVC_HIDDEN; + + if (showchannel) + return chptr->chname; } /* no channels that they can see */