Add target change for channels.

This has a separate enabling option channel::channel_target_change.

It applies to PRIVMSG, NOTICE and TOPIC by unvoiced unopped non-opers.

The same slots are used for channels and users.
This commit is contained in:
Jilles Tjoelker 2010-08-28 20:02:42 -04:00
parent 7f3998618e
commit 9e94d9ea13
10 changed files with 73 additions and 15 deletions

View File

@ -400,6 +400,7 @@ channel {
cycle_host_change = yes; cycle_host_change = yes;
host_in_topic = yes; host_in_topic = yes;
resv_forcepart = yes; resv_forcepart = yes;
channel_target_change = yes;
}; };
serverhide { serverhide {

View File

@ -914,6 +914,12 @@ channel {
* when a RESV is issued. * when a RESV is issued.
*/ */
resv_forcepart = yes; resv_forcepart = yes;
/* channel target change: restrict how many channels users can
* message per unit of time. IRC operators, channel operators and
* voiced users are exempt.
*/
channel_target_change = yes;
}; };

View File

@ -3,15 +3,17 @@ Lee H <lee -at- leeh.co.uk>
--------------------------- ---------------------------
Reworked by Jilles Tjoelker, February 2010. Reworked by Jilles Tjoelker, February 2010.
Channel target change added by Jilles Tjoelker, August 2010.
If the server you are using uses the target change mechanism, then If the server you are using uses the target change mechanism, then
restrictions are placed on how many different users you can message in a set restrictions are placed on how many different users and/or channels you can
timeframe. This also applies to invites. message in a set timeframe. This also applies to invites (for the target
user) and topic changes.
Target change does not apply to channels, ctcp replies, messages to Target change does not apply to ctcp replies, messages to yourself, messages
yourself or messages to services. to services and joins.
You will have a set number of 'slots', each different client you message You will have a set number of 'slots', each different target you message
will take up one slot. A client doing a nick change will not use a new slot, will take up one slot. A client doing a nick change will not use a new slot,
however a client disconnecting from the server it is on and reconnecting however a client disconnecting from the server it is on and reconnecting
will. You will receive 1 new slot roughly every minute. will. You will receive 1 new slot roughly every minute.
@ -20,14 +22,14 @@ Additionally, clients that message or invite you are placed in one of a
small number of special slots, in many cases allowing replies without using small number of special slots, in many cases allowing replies without using
a slot. a slot.
When all slots are filled, messages to new clients will not be accepted. When all slots are filled, messages to new targets will not be accepted.
Messages to clients already filling a slot will be accepted. If all slots Messages to targets already filling a slot will be accepted. If all slots
are full, you will receive the ERR_TARGCHANGE numeric, number 707 in the are full, you will receive the ERR_TARGCHANGE numeric, number 707 in the
form: form:
:<server> 707 <yournick> <targetnick> :Targets changing too fast, message dropped :<server> 707 <yournick> <target> :Targets changing too fast, message dropped
The slots are operated in an LRU (least recently used), so the person you The slots are operated in an LRU (least recently used), so the person or
have talked to least recently will be replaced. channel you have talked to least recently will be replaced.
The number of slots in use will be kept through a reconnection, though the The number of slots in use will be kept through a reconnection, though the
information in those slots will be dropped. However, you will always information in those slots will be dropped. However, you will always
@ -35,8 +37,9 @@ receive one free slot on a reconnection. Other servers using this mechanism
will also be made aware of details about slots. will also be made aware of details about slots.
Target change does not apply if you are opped or voiced in a channel, and Target change does not apply if you are opped or voiced in a channel, and
you are messaging a client within that channel. This can be done explicitly you are messaging that channel or a client within that channel. The latter
using the CNOTICE and CPRIVMSG commands, see /quote help cnotice and /quote can be done explicitly using the CNOTICE and CPRIVMSG commands, see
help cprivmsg, but is also implicit in a normal /msg, /notice or /invite. /quote help cnotice and /quote help cprivmsg, but is also implicit in a
normal /msg, /notice or /invite.
-- --

View File

@ -261,6 +261,7 @@ struct config_channel_entry
int cycle_host_change; int cycle_host_change;
int host_in_topic; int host_in_topic;
int resv_forcepart; int resv_forcepart;
int channel_target_change;
int exempt_cmode_c; int exempt_cmode_c;
int exempt_cmode_C; int exempt_cmode_C;

View File

@ -30,6 +30,8 @@
struct Channel *find_allowing_channel(struct Client *source_p, struct Client *target_p); struct Channel *find_allowing_channel(struct Client *source_p, struct Client *target_p);
/* checks if source_p is allowed to send to target_p */ /* checks if source_p is allowed to send to target_p */
int add_target(struct Client *source_p, struct Client *target_p); int add_target(struct Client *source_p, struct Client *target_p);
/* checks if source_p is allowed to send to chptr */
int add_channel_target(struct Client *source_p, struct Channel *chptr);
/* allows source_p to send to target_p */ /* allows source_p to send to target_p */
void add_reply_target(struct Client *source_p, struct Client *target_p); void add_reply_target(struct Client *source_p, struct Client *target_p);

View File

@ -536,6 +536,14 @@ msg_channel(int p_or_n, const char *command,
/* chanops and voiced can flood their own channel with impunity */ /* chanops and voiced can flood their own channel with impunity */
if((result = can_send(chptr, source_p, NULL))) if((result = can_send(chptr, source_p, NULL)))
{ {
if(result != CAN_SEND_OPV && MyClient(source_p) &&
!IsOper(source_p) &&
!add_channel_target(source_p, chptr))
{
sendto_one(source_p, form_str(ERR_TARGCHANGE),
me.name, source_p->name, chptr->chname);
return;
}
if(result == CAN_SEND_OPV || if(result == CAN_SEND_OPV ||
!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname)) !flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
{ {
@ -586,6 +594,13 @@ msg_channel(int p_or_n, const char *command,
(!(chptr->mode.mode & MODE_NOPRIVMSGS) || (!(chptr->mode.mode & MODE_NOPRIVMSGS) ||
IsMember(source_p, chptr))) IsMember(source_p, chptr)))
{ {
if(MyClient(source_p) && !IsOper(source_p) &&
!add_channel_target(source_p, chptr))
{
sendto_one(source_p, form_str(ERR_TARGCHANGE),
me.name, source_p->name, chptr->chname);
return;
}
if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname)) if(!flood_attack_channel(p_or_n, source_p, chptr, chptr->chname))
{ {
sendto_channel_opmod(client_p, source_p, chptr, sendto_channel_opmod(client_p, source_p, chptr,

View File

@ -38,6 +38,7 @@
#include "parse.h" #include "parse.h"
#include "modules.h" #include "modules.h"
#include "packet.h" #include "packet.h"
#include "tgchange.h"
static int m_topic(struct Client *, struct Client *, int, const char **); static int m_topic(struct Client *, struct Client *, int, const char **);
static int ms_topic(struct Client *, struct Client *, int, const char **); static int ms_topic(struct Client *, struct Client *, int, const char **);
@ -115,6 +116,15 @@ m_topic(struct Client *client_p, struct Client *source_p, int parc, const char *
return 0; return 0;
} }
if(MyClient(source_p) && !is_chanop_voiced(msptr) &&
!IsOper(source_p) &&
!add_channel_target(source_p, chptr))
{
sendto_one(source_p, form_str(ERR_TARGCHANGE),
me.name, source_p->name, chptr->chname);
return 0;
}
if(MyClient(source_p) && (chptr->mode.mode & MODE_TOPICLIMIT) && !is_any_op(msptr)) if(MyClient(source_p) && (chptr->mode.mode & MODE_TOPICLIMIT) && !is_any_op(msptr))
{ {
if(IsOverride(source_p)) if(IsOverride(source_p))

View File

@ -2287,6 +2287,7 @@ static struct ConfEntry conf_channel_table[] =
{ "use_knock", CF_YESNO, NULL, 0, &ConfigChannel.use_knock }, { "use_knock", CF_YESNO, NULL, 0, &ConfigChannel.use_knock },
{ "use_local_channels", CF_YESNO, NULL, 0, &ConfigChannel.use_local_channels }, { "use_local_channels", CF_YESNO, NULL, 0, &ConfigChannel.use_local_channels },
{ "resv_forcepart", CF_YESNO, NULL, 0, &ConfigChannel.resv_forcepart }, { "resv_forcepart", CF_YESNO, NULL, 0, &ConfigChannel.resv_forcepart },
{ "channel_target_change", CF_YESNO, NULL, 0, &ConfigChannel.channel_target_change },
{ "exempt_cmode_c", CF_YESNO, NULL, 0, &ConfigChannel.exempt_cmode_c }, { "exempt_cmode_c", CF_YESNO, NULL, 0, &ConfigChannel.exempt_cmode_c },
{ "exempt_cmode_C", CF_YESNO, NULL, 0, &ConfigChannel.exempt_cmode_C }, { "exempt_cmode_C", CF_YESNO, NULL, 0, &ConfigChannel.exempt_cmode_C },
{ "exempt_cmode_D", CF_YESNO, NULL, 0, &ConfigChannel.exempt_cmode_D }, { "exempt_cmode_D", CF_YESNO, NULL, 0, &ConfigChannel.exempt_cmode_D },

View File

@ -787,6 +787,7 @@ set_default_conf(void)
ConfigChannel.no_join_on_split = NO; ConfigChannel.no_join_on_split = NO;
ConfigChannel.no_create_on_split = YES; ConfigChannel.no_create_on_split = YES;
ConfigChannel.resv_forcepart = YES; ConfigChannel.resv_forcepart = YES;
ConfigChannel.channel_target_change = YES;
ConfigChannel.exempt_cmode_c = NO; ConfigChannel.exempt_cmode_c = NO;
ConfigChannel.exempt_cmode_C = NO; ConfigChannel.exempt_cmode_C = NO;

View File

@ -30,6 +30,8 @@
#include "hash.h" #include "hash.h"
#include "s_newconf.h" #include "s_newconf.h"
static int add_hashed_target(struct Client *source_p, uint32_t hashv);
struct Channel * struct Channel *
find_allowing_channel(struct Client *source_p, struct Client *target_p) find_allowing_channel(struct Client *source_p, struct Client *target_p)
{ {
@ -48,9 +50,7 @@ find_allowing_channel(struct Client *source_p, struct Client *target_p)
int int
add_target(struct Client *source_p, struct Client *target_p) add_target(struct Client *source_p, struct Client *target_p)
{ {
int i, j;
uint32_t hashv; uint32_t hashv;
uint32_t *targets;
/* can msg themselves or services without using any target slots */ /* can msg themselves or services without using any target slots */
if(source_p == target_p || IsService(target_p)) if(source_p == target_p || IsService(target_p))
@ -65,6 +65,24 @@ add_target(struct Client *source_p, struct Client *target_p)
return 1; return 1;
hashv = fnv_hash_upper((const unsigned char *)use_id(target_p), 32); hashv = fnv_hash_upper((const unsigned char *)use_id(target_p), 32);
return add_hashed_target(source_p, hashv);
}
int
add_channel_target(struct Client *source_p, struct Channel *chptr)
{
uint32_t hashv;
hashv = fnv_hash_upper((const unsigned char *)chptr->chname, 32);
return add_hashed_target(source_p, hashv);
}
static int
add_hashed_target(struct Client *source_p, uint32_t hashv)
{
int i, j;
uint32_t *targets;
targets = source_p->localClient->targets; targets = source_p->localClient->targets;
/* check for existing target, and move it to the head */ /* check for existing target, and move it to the head */