This repository has been archived on 2025-02-12. You can view files and clone it, but cannot push or open issues or pull requests.
NeoStats-NeoIRCd/modules/m_who.c

540 lines
14 KiB
C
Raw Permalink Normal View History

2002-08-13 14:34:25 +00:00
/*
* NeoIRCd: NeoStats Group. Based on Hybird7
2002-08-13 14:34:25 +00:00
* m_who.c: Shows who is on a channel.
*
* Copyright (C) 2002 by the past and present ircd coders, and others.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* $Id: m_who.c,v 1.13 2002/10/31 13:01:56 fishwaldo Exp $
2002-08-13 14:34:25 +00:00
*/
#include "stdinc.h"
#include "tools.h"
#include "common.h"
#include "handlers.h"
#include "client.h"
#include "channel.h"
#include "channel_mode.h"
#include "hash.h"
#include "ircd.h"
#include "numeric.h"
#include "s_serv.h"
#include "send.h"
#include "list.h"
#include "irc_string.h"
#include "s_conf.h"
#include "msg.h"
#include "parse.h"
#include "modules.h"
static void m_who(struct Client*, struct Client*, int, char**);
static void ms_who(struct Client*, struct Client*, int, char**);
struct Message who_msgtab = {
"WHO", 0, 0, 2, 0, MFLG_SLOW, 0,
{m_unregistered, m_who, ms_who, m_who}
};
#ifndef STATIC_MODULES
void
_modinit(void)
{
mod_add_cmd(&who_msgtab);
}
void
_moddeinit(void)
{
mod_del_cmd(&who_msgtab);
}
const char *_version = "$Revision: 1.13 $";
2002-08-13 14:34:25 +00:00
#endif
static void do_who_on_channel(struct Client *source_p,
struct Channel *chptr, char *real_name,
int server_oper, int member);
static void do_who_list(struct Client *source_p, struct Channel *chptr,
dlink_list *peons_list, dlink_list *chanops_list,
dlink_list *halfops_list,
dlink_list *chanadmins_list,
2002-08-13 14:34:25 +00:00
dlink_list *voiced_list,
char *chanop_flag,
char *halfop_flag,
char *voiced_flag,
char *chanadmin_flag,
2002-08-13 14:34:25 +00:00
char *chname, int member);
static void who_global(struct Client *source_p, char *mask, int server_oper);
static void do_who(struct Client *source_p,
struct Client *target_p,
char *chname,
char *op_flags);
/*
** m_who
** parv[0] = sender prefix
** parv[1] = nickname mask list
** parv[2] = additional selection flag, only 'o' for now.
*/
static void m_who(struct Client *client_p,
struct Client *source_p,
int parc,
char *parv[])
{
struct Client *target_p;
char *mask = parc > 1 ? parv[1] : NULL;
dlink_node *lp;
struct Channel *chptr=NULL;
struct Channel *mychannel = NULL;
char flags[NUMLISTS][2];
int server_oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */
int member;
/* See if mask is there, collapse it or return if not there */
if (mask != NULL)
{
(void)collapse(mask);
if (*mask == '\0')
{
sendto_one(source_p, form_str(RPL_ENDOFWHO), me.name, parv[0], "*");
return;
}
}
else
{
who_global(source_p, mask, server_oper);
sendto_one(source_p, form_str(RPL_ENDOFWHO), me.name, parv[0], "*" );
return;
}
/* mask isn't NULL at this point. repeat after me... -db */
/* '/who *' */
if ((*(mask+1) == (char) 0) && (*mask == '*'))
{
if (source_p->user)
if ((lp = source_p->user->channel.head))
mychannel = lp->data;
if (!mychannel)
{
sendto_one(source_p, form_str(RPL_ENDOFWHO), me.name, parv[0], "*");
return;
}
do_who_on_channel(source_p, mychannel, "*", NO, YES);
sendto_one(source_p, form_str(RPL_ENDOFWHO), me.name, parv[0], "*");
return;
}
/* '/who #some_channel' */
if (IsChannelName(mask))
{
/*
* List all users on a given channel
*/
chptr = hash_find_channel(mask);
if (chptr != NULL)
{
{
if ( IsMember(source_p, chptr) )
do_who_on_channel(source_p, chptr, chptr->chname, NO, YES);
else if(!SecretChannel(chptr))
do_who_on_channel(source_p, chptr, chptr->chname, NO, NO);
}
}
sendto_one(source_p, form_str(RPL_ENDOFWHO), me.name, parv[0], mask);
return;
}
/* '/who nick' */
if (((target_p = find_client(mask)) != NULL) &&
IsPerson(target_p) && (!server_oper || IsOper(target_p)))
{
char *chname=NULL;
int isinvis = 0;
if(IsServer(client_p))
client_burst_if_needed(client_p,target_p);
isinvis = IsInvisible(target_p);
for (lp = target_p->user->channel.head; lp; lp = lp->next)
{
chptr = lp->data;
chname = chptr->chname;
member = IsMember(source_p, chptr);
if (isinvis && !member)
{
chptr = NULL;
2002-08-13 14:34:25 +00:00
continue;
}
2002-08-13 14:34:25 +00:00
if (member || (!isinvis && PubChannel(chptr)))
{
break;
}
chptr = NULL;
2002-08-13 14:34:25 +00:00
}
if (chptr != NULL)
{
/* XXX globalize this inside m_who.c ? */
/* jdc -- Check is_any_op() for +o > +h > +v priorities */
set_channel_mode_flags( flags, chptr, source_p );
if (is_chan_op(chptr,target_p))
do_who(source_p, target_p, chname, flags[0]);
else if(is_half_op(chptr,target_p))
do_who(source_p, target_p, chname, flags[1]);
else if(is_voiced(chptr,target_p))
do_who(source_p, target_p, chname, flags[2]);
else if(is_chan_admin(chptr, target_p))
do_who(source_p, target_p, chname, flags[3]);
2002-08-13 14:34:25 +00:00
else
do_who(source_p, target_p, chname, "");
}
else
{
do_who(source_p, target_p, NULL, "");
}
sendto_one(source_p, form_str(RPL_ENDOFWHO), me.name, parv[0], mask);
return;
}
/* '/who 0' */
if ((*(mask + 1) == '\0') && (*mask == '0'))
who_global(source_p, NULL, server_oper);
else
who_global(source_p, mask, server_oper);
/* Wasn't a nick, wasn't a channel, wasn't a '*' so ... */
sendto_one(source_p, form_str(RPL_ENDOFWHO), me.name, parv[0], mask);
}
/* who_common_channel
* inputs - pointer to client requesting who
* - pointer to channel member chain.
* - char * mask to match
* - int if oper on a server or not
* - pointer to int maxmatches
* output - NONE
* side effects - lists matching clients on specified channel,
* marks matched clients.
*
*/
static void
who_common_channel(struct Client *source_p,dlink_list chain,
char *mask,int server_oper, int *maxmatches)
2002-08-13 14:34:25 +00:00
{
dlink_node *clp;
struct Client *target_p;
2002-08-13 14:34:25 +00:00
DLINK_FOREACH(clp, chain.head)
{
target_p = clp->data;
2002-08-13 14:34:25 +00:00
if (!IsInvisible(target_p) || IsMarked(target_p))
continue;
2002-08-13 14:34:25 +00:00
if (server_oper && !IsOper(target_p))
continue;
2002-08-13 14:34:25 +00:00
SetMark(target_p);
2002-08-13 14:34:25 +00:00
if ((mask == NULL) ||
match(mask, target_p->name) || match(mask, target_p->username) ||
2002-09-20 14:49:36 +00:00
match(mask, target_p->host) || match(mask, target_p->vhost) ||
(match(mask, target_p->user->server) &&
(IsOper(source_p) || !ConfigServerHide.hide_servers)) ||
match(mask, target_p->info))
{
2002-08-13 14:34:25 +00:00
do_who(source_p, target_p, NULL, "");
2002-08-13 14:34:25 +00:00
if (*maxmatches > 0)
{
--(*maxmatches);
if(*maxmatches == 0)
return;
}
}
}
2002-08-13 14:34:25 +00:00
}
/*
* who_global
*
* inputs - pointer to client requesting who
* - char * mask to match
* - int if oper on a server or not
* output - NONE
* side effects - do a global scan of all clients looking for match
* this is slightly expensive on EFnet ...
*/
static void
who_global(struct Client *source_p,char *mask, int server_oper)
2002-08-13 14:34:25 +00:00
{
struct Channel *chptr=NULL;
struct Client *target_p;
dlink_node *lp;
int maxmatches = 500;
/* first, list all matching INvisible clients on common channels */
DLINK_FOREACH(lp, source_p->user->channel.head)
2002-08-13 14:34:25 +00:00
{
chptr = lp->data;
who_common_channel(source_p,chptr->chanadmins,mask,server_oper,&maxmatches);
2002-08-13 14:34:25 +00:00
who_common_channel(source_p,chptr->chanops,mask,server_oper,&maxmatches);
who_common_channel(source_p,chptr->halfops,mask,server_oper,&maxmatches);
who_common_channel(source_p,chptr->voiced,mask,server_oper,&maxmatches);
who_common_channel(source_p,chptr->peons,mask,server_oper,&maxmatches);
}
/* second, list all matching visible clients */
for (target_p = GlobalClientList; target_p; target_p = target_p->next)
{
if (!IsPerson(target_p))
continue;
if (IsInvisible(target_p))
{
ClearMark(target_p);
continue;
}
if (server_oper && !IsOper(target_p))
continue;
if (!mask ||
match(mask, target_p->name) || match(mask, target_p->username) ||
match(mask, target_p->host) || match(mask, target_p->user->server) ||
2002-08-13 14:45:13 +00:00
match(mask, target_p->info) || match(mask, target_p->vhost))
2002-08-13 14:34:25 +00:00
{
do_who(source_p, target_p, NULL, "");
if (maxmatches > 0)
{
--maxmatches;
if( maxmatches == 0 )
return;
}
}
}
}
/*
* do_who_on_channel
*
* inputs - pointer to client requesting who
* - pointer to channel to do who on
* - The "real name" of this channel
* - int if source_p is a server oper or not
* - int if client is member or not
* output - NONE
* side effects - do a who on given channel
*/
static void
do_who_on_channel(struct Client *source_p, struct Channel *chptr,
char *chname, int server_oper, int member)
2002-08-13 14:34:25 +00:00
{
char flags[NUMLISTS][2];
/* jdc -- Check is_any_op() for +o > +h > +v priorities */
set_channel_mode_flags( flags, chptr, source_p );
do_who_list(source_p, chptr,
&chptr->peons,
&chptr->chanops,
&chptr->halfops,
&chptr->chanadmins,
2002-08-13 14:34:25 +00:00
&chptr->voiced,
flags[0],
flags[1],
flags[2],
flags[3],
2002-08-13 14:34:25 +00:00
chname, member);
}
static void do_who_list(struct Client *source_p, struct Channel *chptr,
dlink_list *peons_list,
dlink_list *chanops_list,
dlink_list *halfops_list,
dlink_list *chanadmins_list,
2002-08-13 14:34:25 +00:00
dlink_list *voiced_list,
char *chanop_flag,
char *halfop_flag,
char *voiced_flag,
char *admins_flag,
2002-08-13 14:34:25 +00:00
char *chname, int member)
{
struct Client *target_p;
dlink_node *chanops_ptr;
dlink_node *peons_ptr;
dlink_node *voiced_ptr;
dlink_node *halfops_ptr;
dlink_node *chanadmins_ptr;
2002-08-13 14:34:25 +00:00
int done=0;
peons_ptr = peons_list->head;
chanops_ptr = chanops_list->head;
voiced_ptr = voiced_list->head;
halfops_ptr = halfops_list->head;
chanadmins_ptr = chanadmins_list->head;
2002-08-13 14:34:25 +00:00
2002-09-05 13:14:36 +00:00
while (done < NUMLISTS)
2002-08-13 14:34:25 +00:00
{
done = 0;
if(peons_ptr != NULL)
{
target_p = peons_ptr->data;
if(member || !IsInvisible(target_p))
do_who(source_p, target_p, chname, "");
peons_ptr = peons_ptr->next;
}
else
done++;
if(chanops_ptr != NULL)
{
target_p = chanops_ptr->data;
if(member || !IsInvisible(target_p))
do_who(source_p, target_p, chname, chanop_flag);
chanops_ptr = chanops_ptr->next;
}
else
done++;
if(chanadmins_ptr != NULL)
{
target_p = chanadmins_ptr->data;
if(member || !IsInvisible(target_p))
2002-09-14 17:03:00 +00:00
do_who(source_p, target_p, chname, admins_flag);
chanadmins_ptr = chanadmins_ptr->next;
}
else
done++;
2002-08-13 14:34:25 +00:00
if(halfops_ptr != NULL)
{
target_p = halfops_ptr->data;
if(member || !IsInvisible(target_p))
do_who(source_p, target_p, chname, halfop_flag);
halfops_ptr = halfops_ptr->next;
}
else
done++;
if(voiced_ptr != NULL)
{
target_p = voiced_ptr->data;
if(member || !IsInvisible(target_p))
{
if(target_p == source_p && is_voiced(chptr, source_p) &&
chptr->mode.mode & MODE_HIDEOPS)
do_who(source_p, target_p, chname, "+");
else
do_who(source_p, target_p, chname, voiced_flag);
}
voiced_ptr = voiced_ptr->next;
}
else
done++;
}
}
/*
* do_who
*
* inputs - pointer to client requesting who
* - pointer to client to do who on
* - The reported name
* - channel flags
* output - NONE
* side effects - do a who on given person
*/
static void
do_who(struct Client *source_p, struct Client *target_p,
char *chname, char *op_flags)
2002-08-13 14:34:25 +00:00
{
char status[5];
ircsprintf(status,"%c%s%s", target_p->user->away ? 'G' : 'H',
2002-08-13 14:34:25 +00:00
IsOper(target_p) ? "*" : "", op_flags );
if(ConfigServerHide.hide_servers)
{
2002-08-13 14:45:13 +00:00
sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
(chname) ? (chname) : "*",
target_p->username,
2002-09-20 14:49:36 +00:00
target_p->vhost, IsOper(source_p) ? target_p->user->server : "*",
2002-08-13 14:45:13 +00:00
target_p->name,
status, 0, target_p->info);
2002-08-13 14:34:25 +00:00
}
else
{
sendto_one(source_p, form_str(RPL_WHOREPLY), me.name, source_p->name,
(chname) ? (chname) : "*",
target_p->username,
2002-09-20 14:49:36 +00:00
target_p->vhost, target_p->user->server, target_p->name,
2002-08-13 14:34:25 +00:00
status, target_p->hopcount, target_p->info);
}
}
/*
** ms_who
** parv[0] = sender prefix
** parv[1] = nickname mask list
** parv[2] = additional selection flag, only 'o' for now.
*/
static void
ms_who(struct Client *client_p, struct Client *source_p,
int parc, char *parv[])
2002-08-13 14:34:25 +00:00
{
/* If its running as a hub, and linked with lazy links
* then allow leaf to use normal client m_who()
* other wise, ignore it.
*/
if( ServerInfo.hub )
{
if(!IsCapable(client_p->from,CAP_LL))
return;
}
2002-08-13 14:34:25 +00:00
m_who(client_p,source_p,parc,parv);
}