ircd-ratbox/ircd-ratbox-3.0.10/modules/m_list.c
2023-08-20 13:26:10 -04:00

294 lines
7.3 KiB
C

/*
* ircd-ratbox: A slightly useful ircd.
* m_list.c: Shows what servers are currently connected.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2012 ircd-ratbox development team
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*
* $Id: m_list.c 27371 2012-03-16 05:33:15Z dubkat $
*/
#include "stdinc.h"
#include "struct.h"
#include "channel.h"
#include "hash.h"
#include "match.h"
#include "ircd.h"
#include "numeric.h"
#include "s_conf.h"
#include "send.h"
#include "parse.h"
#include "modules.h"
#include "class.h"
#include "client.h"
static int m_list(struct Client *, struct Client *, int, const char **);
static int mo_list(struct Client *, struct Client *, int, const char **);
struct Message list_msgtab = {
"LIST", 0, 0, 0, MFLG_SLOW,
{mg_unreg, {m_list, 0}, mg_ignore, mg_ignore, mg_ignore, {mo_list, 0}}
};
mapi_clist_av1 list_clist[] = { &list_msgtab, NULL };
DECLARE_MODULE_AV1(list, NULL, NULL, list_clist, NULL, NULL, "$Revision: 27371 $");
static void list_all_channels(struct Client *source_p);
static void list_limit_channels(struct Client *source_p, const char *param);
static void list_named_channel(struct Client *source_p, const char *name);
/* m_list()
* parv[0] = sender prefix
* parv[1] = channel
*/
static int
m_list(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
static time_t last_used = 0L;
if(parc < 2 || !IsChannelName(parv[1]))
{
/* pace this due to the sheer traffic involved */
if(((last_used + ConfigFileEntry.pace_wait) > rb_current_time()))
{
sendto_one(source_p, form_str(RPL_LOAD2HI),
me.name, source_p->name, "LIST");
sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
return 0;
}
else
last_used = rb_current_time();
}
/* If no arg, do all channels *whee*, else just one channel */
if(parc < 2 || EmptyString(parv[1]))
list_all_channels(source_p);
else if(IsChannelName(parv[1]))
list_named_channel(source_p, parv[1]);
else
list_limit_channels(source_p, parv[1]);
return 0;
}
/* mo_list()
* parv[0] = sender prefix
* parv[1] = channel
*/
static int
mo_list(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
/* If no arg, do all channels *whee*, else just one channel */
if(parc < 2 || EmptyString(parv[1]))
list_all_channels(source_p);
else if(IsChannelName(parv[1]))
list_named_channel(source_p, parv[1]);
else
list_limit_channels(source_p, parv[1]);
return 0;
}
/* list_all_channels()
*
* inputs - pointer to client requesting list
* output -
* side effects - list all channels to source_p
*/
static void
list_all_channels(struct Client *source_p)
{
struct Channel *chptr;
rb_dlink_node *ptr;
int sendq_limit;
int count = 0;
/* give them an output limit of 90% of their sendq. --fl */
sendq_limit = (int)get_sendq(source_p);
sendq_limit /= 10;
sendq_limit *= 9;
sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
SetCork(source_p);
RB_DLINK_FOREACH(ptr, global_channel_list.head)
{
chptr = ptr->data;
/* if theyre overflowing their sendq, stop. --fl */
if(rb_linebuf_len(&source_p->localClient->buf_sendq) > sendq_limit)
{
sendto_one(source_p, form_str(ERR_TOOMANYMATCHES),
me.name, source_p->name, "LIST");
break;
}
if(SecretChannel(chptr) && !IsMember(source_p, chptr))
continue;
sendto_one(source_p, form_str(RPL_LIST),
me.name, source_p->name, chptr->chname,
rb_dlink_list_length(&chptr->members),
chptr->topic == NULL ? "" : chptr->topic->topic);
if(count++ >= 10)
{
ClearCork(source_p);
send_pop_queue(source_p);
SetCork(source_p);
count = 0;
}
}
ClearCork(source_p);
sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
return;
}
static void
list_limit_channels(struct Client *source_p, const char *param)
{
struct Channel *chptr;
char *args;
char *p;
rb_dlink_node *ptr;
int sendq_limit;
int max = INT_MAX;
int min = 0;
int i;
int count = 0;
args = LOCAL_COPY(param);
for(i = 0; i < 2; i++)
{
if((p = strchr(args, ',')) != NULL)
*p++ = '\0';
if(*args == '<')
{
args++;
if((max = atoi(args)) <= 0)
max = INT_MAX;
}
else if(*args == '>')
{
args++;
if((min = atoi(args)) < 0)
min = 0;
}
if(EmptyString(p))
break;
else
args = p;
}
/* give them an output limit of 90% of their sendq. --fl */
sendq_limit = (unsigned int)get_sendq(source_p);
sendq_limit /= 10;
sendq_limit *= 9;
sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
SetCork(source_p);
RB_DLINK_FOREACH(ptr, global_channel_list.head)
{
chptr = ptr->data;
/* if theyre overflowing their sendq, stop. --fl */
if(rb_linebuf_len(&source_p->localClient->buf_sendq) > sendq_limit)
{
sendto_one(source_p, form_str(ERR_TOOMANYMATCHES),
me.name, source_p->name, "LIST");
break;
}
if((int)rb_dlink_list_length(&chptr->members) >= max ||
(int)rb_dlink_list_length(&chptr->members) <= min)
continue;
if(SecretChannel(chptr) && !IsMember(source_p, chptr))
continue;
sendto_one(source_p, form_str(RPL_LIST),
me.name, source_p->name, chptr->chname,
rb_dlink_list_length(&chptr->members),
chptr->topic == NULL ? "" : chptr->topic->topic);
if(count++ >= 10)
{
ClearCork(source_p);
send_pop_queue(source_p);
SetCork(source_p);
count = 0;
}
}
ClearCork(source_p);
sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
return;
}
/* list_named_channel()
*
* inputs - pointer to client requesting list
* output -
* side effects - list single channel to source
*/
static void
list_named_channel(struct Client *source_p, const char *name)
{
struct Channel *chptr;
char *p;
char *n = LOCAL_COPY(name);
SetCork(source_p);
sendto_one(source_p, form_str(RPL_LISTSTART), me.name, source_p->name);
if((p = strchr(n, ',')))
*p = '\0';
if(*n == '\0')
{
sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), name);
ClearCork(source_p);
sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
return;
}
chptr = find_channel(n);
if(chptr == NULL)
{
sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), n);
ClearCork(source_p);
sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
return;
}
if(ShowChannel(source_p, chptr))
sendto_one(source_p, form_str(RPL_LIST),
me.name, source_p->name, chptr->chname,
rb_dlink_list_length(&chptr->members),
chptr->topic == NULL ? "" : chptr->topic->topic);
ClearCork(source_p);
sendto_one(source_p, form_str(RPL_LISTEND), me.name, source_p->name);
return;
}