mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-09 11:53:13 +02:00
- Added channelmode +j (jointhrottle), syntax: /mode #chan +j X:Y, and then it will
throttle the number of joins per-user to X in Y seconds. Idea from Angrywolf (who wrote a module that did this before). This might need some more testing :). It's enabled by default but can be #undef'ed in include/config.h (line 449).
This commit is contained in:
@@ -589,3 +589,7 @@
|
||||
- Fixed a bug with channel alias{}'s where using the format syntax caused a crash (#0002323)
|
||||
reported by Snake.
|
||||
- Made channel mode +S strip RGB color codes.
|
||||
- Added channelmode +j (jointhrottle), syntax: /mode #chan +j X:Y, and then it will
|
||||
throttle the number of joins per-user to X in Y seconds. Idea from Angrywolf (who
|
||||
wrote a module that did this before). This might need some more testing :).
|
||||
It's enabled by default but can be #undef'ed in include/config.h (line 449).
|
||||
|
||||
@@ -2375,6 +2375,10 @@ set {
|
||||
<td>Makes channel G rated. Checks for words listed in the Badword Blocks,
|
||||
and replaces them with the words specified</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div align="center">j <joins:seconds></div></td>
|
||||
<td>Throttles joins per-user to <i>joins</i> per <i>seconds</i> seconds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div align="center">M</div></td>
|
||||
<td>A registered nickname (+r) is required to talk</td>
|
||||
|
||||
@@ -165,6 +165,7 @@ help Chmodes {
|
||||
" I <nick!ident@host> = Overrides +i for matching users [h]";
|
||||
" f <floodparams> = Flood protection (for more info see /HELPOP CHMODEF) [o]";
|
||||
" i = A user must be invited to join the channel [h]";
|
||||
" j <joins:sec> = Throttle joins per-user to 'joins' per 'sec' seconds";
|
||||
" k <key> = Users must specify <key> to join [h]";
|
||||
" l <number of max users> = Channel may hold at most <number> of users [o]";
|
||||
" m = Moderated channel (only +vhoaq users may speak) [h]";
|
||||
|
||||
@@ -431,6 +431,7 @@
|
||||
/*
|
||||
* Extended channel modes. This extends the channel modes with yet another
|
||||
* 32 possible modes which can also be used in modules.
|
||||
* This is now pretty much required.
|
||||
*/
|
||||
#define EXTCMODE
|
||||
|
||||
@@ -440,6 +441,13 @@
|
||||
*/
|
||||
#define NEWCHFLOODPROT
|
||||
|
||||
/* JoinThrottle (chanmode +j): +j x:y throttles users to X joins per Y seconds (per-user).
|
||||
* In peak situations (eg: just after a server restart with thousand clients joining
|
||||
* hundreds of channels) it can use like ~200k, but in normal circumstances you should
|
||||
* count on just ~10-50k.
|
||||
*/
|
||||
#define JOINTHROTTLE
|
||||
|
||||
/* ------------------------- END CONFIGURATION SECTION -------------------- */
|
||||
#define MOTD MPATH
|
||||
#define RULES RPATH
|
||||
|
||||
@@ -467,6 +467,7 @@ extern MODVAR Cmode_t EXTMODE_NONOTICE;
|
||||
#ifdef STRIPBADWORDS
|
||||
extern MODVAR Cmode_t EXTMODE_STRIPBADWORDS;
|
||||
#endif
|
||||
extern MODVAR Cmode_t EXTMODE_JOINTHROTTLE;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
@@ -739,3 +740,9 @@ extern char *clean_ban_mask(char *, int, aClient *);
|
||||
extern void chanfloodtimer_stopchantimers(aChannel *chptr);
|
||||
extern int find_invex(aChannel *chptr, aClient *sptr);
|
||||
extern void DoMD5(unsigned char *mdout, unsigned char *src, unsigned long n);
|
||||
#ifdef JOINTHROTTLE
|
||||
aJFlood *cmodej_addentry(aClient *cptr, aChannel *chptr);
|
||||
void cmodej_delentry(aJFlood *e);
|
||||
void cmodej_deluserentries(aClient *cptr);
|
||||
void cmodej_delchannelentries(aChannel *chptr);
|
||||
#endif
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
|
||||
#define ERR_CHANOWNPRIVNEEDED 499
|
||||
|
||||
#define ERR_TOOMANYJOINS 500
|
||||
#define ERR_UMODEUNKNOWNFLAG 501
|
||||
#define ERR_USERSDONTMATCH 502
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ typedef struct _cmdoverride Cmdoverride;
|
||||
typedef struct SMember Member;
|
||||
typedef struct SMembership Membership;
|
||||
typedef struct SMembershipL MembershipL;
|
||||
typedef struct JFlood aJFlood;
|
||||
|
||||
#ifdef ZIP_LINKS
|
||||
typedef struct Zdata aZdata;
|
||||
@@ -754,6 +755,9 @@ struct User {
|
||||
unsigned char away_c; /* number of times away has been set */
|
||||
#endif
|
||||
} flood;
|
||||
#ifdef JOINTHROTTLE
|
||||
aJFlood *jflood;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Server {
|
||||
@@ -873,6 +877,12 @@ extern Cmode *CmodeAdd(Module *reserved, CmodeInfo req, Cmode_t *mode);
|
||||
extern void CmodeDel(Cmode *cmode);
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
EXTCM_PAR_HEADER
|
||||
unsigned short num;
|
||||
unsigned short t;
|
||||
} aModejEntry;
|
||||
|
||||
#define LISTENER_NORMAL 0x000001
|
||||
#define LISTENER_CLIENTSONLY 0x000002
|
||||
#define LISTENER_SERVERSONLY 0x000004
|
||||
@@ -1486,6 +1496,9 @@ struct Channel {
|
||||
Ban *banlist;
|
||||
Ban *exlist; /* exceptions */
|
||||
Ban *invexlist; /* invite list */
|
||||
#ifdef JOINTHROTTLE
|
||||
aJFlood *jflood;
|
||||
#endif
|
||||
char chname[1];
|
||||
};
|
||||
|
||||
@@ -1735,6 +1748,42 @@ typedef struct {
|
||||
unsigned parameters : 1;
|
||||
} aCtab;
|
||||
|
||||
#ifdef JOINTHROTTLE
|
||||
/** A jointhrottle item, this is a double linked list.
|
||||
* prev_u Previous entry of user
|
||||
* next_u Next entry of user
|
||||
* prev_c Previous entry of channel
|
||||
* next_c Next entry of channel
|
||||
* chptr The channel this entry applies to
|
||||
* cptr The user this entry applies to
|
||||
* firstjoin Timestamp of "first join" (since last timer reset)
|
||||
* numjoin Number of joins since that period
|
||||
* CLARIFICATION:
|
||||
* Why a double linked list? Well, the following operations need to be performed:
|
||||
* - if user quits, entry must be removed
|
||||
* - if channel is destroyed, entry must be removed
|
||||
* (and of course, more, but these are the most important ones affecting this decision)
|
||||
* While it would be possible to have a linked list only by user (for example),
|
||||
* that would mean that upon channel destroy ALL entries would have to be searched
|
||||
* trough, which might mean for example 800*8=6400 entries in a peak situation
|
||||
* (such as after a server restart and hundreds of clients connecting&joining).
|
||||
* For obvious reasons, that would be a very bad idea :).
|
||||
* So this costs us 2 pointers (8b on ia32) per entry, but in case of channel destroy
|
||||
* it means we only have for example 20 entries to scan trough rather than 2000.
|
||||
* Worth the extra memory :). -- Syzop
|
||||
* Note that in normal situations it won't be that bad since we will try to
|
||||
* regulary free up some entries.
|
||||
*/
|
||||
struct JFlood {
|
||||
aJFlood *prev_u, *next_u;
|
||||
aJFlood *prev_c, *next_c;
|
||||
aChannel *chptr;
|
||||
aClient *cptr;
|
||||
time_t firstjoin;
|
||||
unsigned short numjoins;
|
||||
};
|
||||
#endif
|
||||
|
||||
void init_throttling_hash();
|
||||
int hash_throttling(struct IN_ADDR *in);
|
||||
struct ThrottlingBucket *find_throttling_bucket(struct IN_ADDR *in);
|
||||
|
||||
@@ -1523,6 +1523,9 @@ void sub1_from_channel(aChannel *chptr)
|
||||
chanfloodtimer_stopchantimers(chptr);
|
||||
if (chptr->mode.floodprot)
|
||||
MyFree(chptr->mode.floodprot);
|
||||
#endif
|
||||
#ifdef JOINTHROTTLE
|
||||
cmodej_delchannelentries(chptr);
|
||||
#endif
|
||||
if (chptr->topic)
|
||||
MyFree(chptr->topic);
|
||||
|
||||
@@ -45,6 +45,10 @@ ID_Copyright("(C) Carsten Munk 2001");
|
||||
|
||||
MODVAR Event *events = NULL;
|
||||
|
||||
#ifdef JOINTHROTTLE
|
||||
extern EVENT(cmodej_cleanup_structs);
|
||||
#endif
|
||||
|
||||
void LockEventSystem(void)
|
||||
{
|
||||
}
|
||||
@@ -213,6 +217,9 @@ void SetupEvents(void)
|
||||
EventAddEx(NULL, "loop", 0, 0, loop_event, NULL);
|
||||
#ifndef NO_FDLIST
|
||||
EventAddEx(NULL, "fdlistcheck", 1, 0, e_check_fdlists, NULL);
|
||||
#endif
|
||||
#ifdef JOINTHROTTLE
|
||||
EventAddEx(NULL, "cmodej_cleanup_structs", 60, 0, cmodej_cleanup_structs, NULL);
|
||||
#endif
|
||||
UnlockEventSystem();
|
||||
}
|
||||
|
||||
+175
@@ -58,6 +58,18 @@ Cmode_t EXTMODE_NONOTICE = 0L;
|
||||
Cmode_t EXTMODE_STRIPBADWORDS = 0L;
|
||||
#endif
|
||||
|
||||
#ifdef JOINTHROTTLE
|
||||
/* cmode j stuff... */
|
||||
Cmode_t EXTMODE_JOINTHROTTLE = 0L;
|
||||
int cmodej_is_ok(aClient *sptr, aChannel *chptr, char *para, int type, int what);
|
||||
CmodeParam *cmodej_put_param(CmodeParam *r_in, char *param);
|
||||
char *cmodej_get_param(CmodeParam *r_in);
|
||||
char *cmodej_conv_param(char *param_in);
|
||||
void cmodej_free_param(CmodeParam *r);
|
||||
CmodeParam *cmodej_dup_struct(CmodeParam *r_in);
|
||||
int cmodej_sjoin_check(aChannel *chptr, CmodeParam *ourx, CmodeParam *theirx);
|
||||
#endif
|
||||
|
||||
void make_extcmodestr()
|
||||
{
|
||||
char *p;
|
||||
@@ -99,6 +111,21 @@ static void load_extendedchanmodes(void)
|
||||
req.flag = 'G';
|
||||
CmodeAdd(NULL, req, &EXTMODE_STRIPBADWORDS);
|
||||
#endif
|
||||
|
||||
#ifdef JOINTHROTTLE
|
||||
/* +j */
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.paracount = 1;
|
||||
req.is_ok = cmodej_is_ok;
|
||||
req.flag = 'j';
|
||||
req.put_param = cmodej_put_param;
|
||||
req.get_param = cmodej_get_param;
|
||||
req.conv_param = cmodej_conv_param;
|
||||
req.free_param = cmodej_free_param;
|
||||
req.dup_struct = cmodej_dup_struct;
|
||||
req.sjoin_check = cmodej_sjoin_check;
|
||||
CmodeAdd(NULL, req, &EXTMODE_JOINTHROTTLE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void extcmode_init(void)
|
||||
@@ -268,4 +295,152 @@ int extcmode_default_requirehalfop(aClient *cptr, aChannel *chptr, char *para, i
|
||||
return EX_DENY;
|
||||
}
|
||||
|
||||
#ifdef JOINTHROTTLE
|
||||
/*** CHANNEL MODE +j STUFF ******/
|
||||
int cmodej_is_ok(aClient *sptr, aChannel *chptr, char *para, int type, int what)
|
||||
{
|
||||
if ((type == EXCHK_ACCESS) || (type == EXCHK_ACCESS_ERR))
|
||||
{
|
||||
if (IsPerson(sptr) && is_chan_op(sptr, chptr))
|
||||
return EX_ALLOW;
|
||||
return EX_DENY;
|
||||
} else
|
||||
if (type == EXCHK_PARAM)
|
||||
{
|
||||
/* Check parameter.. syntax should be X:Y, X should be 1-255, Y should be 1-999 */
|
||||
char buf[32], *p;
|
||||
int num, t, fail = 0;
|
||||
|
||||
strlcpy(buf, para, sizeof(buf));
|
||||
p = strchr(buf, ':');
|
||||
if (!p)
|
||||
{
|
||||
fail = 1;
|
||||
} else {
|
||||
*p++ = '\0';
|
||||
num = atoi(buf);
|
||||
t = atoi(p);
|
||||
if ((num < 1) || (num > 255) || (t < 1) || (t > 999))
|
||||
fail = 1;
|
||||
}
|
||||
if (fail)
|
||||
{
|
||||
sendnotice(sptr, "Error in setting +j, syntax: +j <num>:<seconds>, where <num> must be 1-255, and <seconds> 1-999");
|
||||
return EX_DENY;
|
||||
}
|
||||
return EX_ALLOW;
|
||||
}
|
||||
|
||||
/* falltrough -- should not be used */
|
||||
return EX_DENY;
|
||||
}
|
||||
|
||||
CmodeParam *cmodej_put_param(CmodeParam *r_in, char *param)
|
||||
{
|
||||
aModejEntry *r = (aModejEntry *)r_in;
|
||||
char buf[32], *p;
|
||||
int num, t;
|
||||
|
||||
if (!r)
|
||||
{
|
||||
/* Need to create one */
|
||||
r = (aModejEntry *)malloc(sizeof(aModejEntry));
|
||||
memset(r, 0, sizeof(aModejEntry));
|
||||
r->flag = 'j';
|
||||
}
|
||||
strlcpy(buf, param, sizeof(buf));
|
||||
p = strchr(buf, ':');
|
||||
if (p)
|
||||
{
|
||||
*p++ = '\0';
|
||||
num = atoi(buf);
|
||||
t = atoi(p);
|
||||
if (num < 1) num = 1;
|
||||
if (num > 255) num = 255;
|
||||
if (t < 1) t = 1;
|
||||
if (t > 999) t = 999;
|
||||
r->num = num;
|
||||
r->t = t;
|
||||
} else {
|
||||
r->num = 0;
|
||||
r->t = 0;
|
||||
}
|
||||
return (CmodeParam *)r;
|
||||
}
|
||||
|
||||
char *cmodej_get_param(CmodeParam *r_in)
|
||||
{
|
||||
aModejEntry *r = (aModejEntry *)r_in;
|
||||
static char retbuf[16];
|
||||
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
snprintf(retbuf, sizeof(retbuf), "%hu:%hu", r->num, r->t);
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
char *cmodej_conv_param(char *param_in)
|
||||
{
|
||||
static char retbuf[32];
|
||||
char param[32], *p;
|
||||
int num, t, fail = 0;
|
||||
|
||||
strlcpy(param, param_in, sizeof(param));
|
||||
p = strchr(param, ':');
|
||||
if (!p)
|
||||
return NULL;
|
||||
*p++ = '\0';
|
||||
num = atoi(param);
|
||||
t = atoi(p);
|
||||
if (num < 1)
|
||||
num = 1;
|
||||
if (num > 255)
|
||||
num = 255;
|
||||
if (t < 1)
|
||||
t = 1;
|
||||
if (t > 999)
|
||||
t = 999;
|
||||
|
||||
snprintf(retbuf, sizeof(retbuf), "%d:%d", num, t);
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
void cmodej_free_param(CmodeParam *r)
|
||||
{
|
||||
MyFree(r);
|
||||
}
|
||||
|
||||
CmodeParam *cmodej_dup_struct(CmodeParam *r_in)
|
||||
{
|
||||
aModejEntry *r = (aModejEntry *)r_in;
|
||||
aModejEntry *w = (aModejEntry *)MyMalloc(sizeof(aModejEntry));
|
||||
|
||||
memcpy(w, r, sizeof(aModejEntry));
|
||||
return (CmodeParam *)w;
|
||||
}
|
||||
|
||||
int cmodej_sjoin_check(aChannel *chptr, CmodeParam *ourx, CmodeParam *theirx)
|
||||
{
|
||||
aModejEntry *our = (aModejEntry *)ourx;
|
||||
aModejEntry *their = (aModejEntry *)theirx;
|
||||
|
||||
if (our->t != their->t)
|
||||
{
|
||||
if (our->t > their->t)
|
||||
return EXSJ_WEWON;
|
||||
else
|
||||
return EXSJ_THEYWON;
|
||||
}
|
||||
else if (our->num != their->num)
|
||||
{
|
||||
if (our->num > their->num)
|
||||
return EXSJ_WEWON;
|
||||
else
|
||||
return EXSJ_THEYWON;
|
||||
} else
|
||||
return EXSJ_SAME;
|
||||
}
|
||||
#endif /* JOINTHROTTLE */
|
||||
|
||||
#endif /* EXTCMODE */
|
||||
|
||||
+1
-1
@@ -1208,7 +1208,7 @@ int InitwIRCD(int argc, char *argv[])
|
||||
#ifndef _WIN32
|
||||
fprintf(stderr, "%s", unreallogo);
|
||||
fprintf(stderr, " v%s\n", VERSIONONLY);
|
||||
fprintf(stderr, " using TRE %s\n", tre_version());
|
||||
fprintf(stderr, " using %s\n", tre_version());
|
||||
#ifdef USE_SSL
|
||||
fprintf(stderr, " using %s\n", OPENSSL_VERSION_TEXT);
|
||||
#endif
|
||||
|
||||
+149
@@ -550,5 +550,154 @@ ListStruct *del_ListItem(ListStruct *item, ListStruct **list) {
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef JOINTHROTTLE
|
||||
/** Adds a aJFlood entry to user & channel and returns entry.
|
||||
* NOTE: Does not check for already-existing-entry
|
||||
*/
|
||||
aJFlood *cmodej_addentry(aClient *cptr, aChannel *chptr)
|
||||
{
|
||||
aJFlood *e;
|
||||
|
||||
#ifdef DEBUGMODE
|
||||
if (!IsPerson(cptr))
|
||||
abort();
|
||||
|
||||
for (e=cptr->user->jflood; e; e=e->next_u)
|
||||
if (e->chptr == chptr)
|
||||
abort();
|
||||
|
||||
for (e=chptr->jflood; e; e=e->next_c)
|
||||
if (e->cptr == cptr)
|
||||
abort();
|
||||
#endif
|
||||
|
||||
e = MyMallocEx(sizeof(aJFlood));
|
||||
e->cptr = cptr;
|
||||
e->chptr = chptr;
|
||||
e->prev_u = e->prev_c = NULL;
|
||||
e->next_u = cptr->user->jflood;
|
||||
e->next_c = chptr->jflood;
|
||||
cptr->user->jflood = chptr->jflood = e;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/** Removes an individual entry from list and frees it.
|
||||
*/
|
||||
void cmodej_delentry(aJFlood *e)
|
||||
{
|
||||
/* remove from user.. */
|
||||
if (e->prev_u)
|
||||
e->prev_u->next_u = e->next_u;
|
||||
else
|
||||
e->cptr->user->jflood = e->next_u; /* new head */
|
||||
if (e->next_u)
|
||||
e->next_u->prev_u = e->prev_u;
|
||||
|
||||
/* remove from channel.. */
|
||||
if (e->prev_c)
|
||||
e->prev_c->next_c = e->next_c;
|
||||
else
|
||||
e->chptr->jflood = e->next_c; /* new head */
|
||||
if (e->next_c)
|
||||
e->next_c->prev_c = e->prev_c;
|
||||
|
||||
/* actually free it */
|
||||
MyFree(e);
|
||||
}
|
||||
|
||||
/** Removes all entries belonging to user from all lists and free them. */
|
||||
void cmodej_deluserentries(aClient *cptr)
|
||||
{
|
||||
aJFlood *e, *e_next;
|
||||
|
||||
for (e=cptr->user->jflood; e; e=e_next)
|
||||
{
|
||||
e_next = e->next_u;
|
||||
|
||||
/* remove from channel.. */
|
||||
if (e->prev_c)
|
||||
e->prev_c->next_c = e->next_c;
|
||||
else
|
||||
e->chptr->jflood = e->next_c; /* new head */
|
||||
if (e->next_c)
|
||||
e->next_c->prev_c = e->prev_c;
|
||||
|
||||
/* actually free it */
|
||||
MyFree(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes all entries belonging to channel from all lists and free them. */
|
||||
void cmodej_delchannelentries(aChannel *chptr)
|
||||
{
|
||||
aJFlood *e, *e_next;
|
||||
|
||||
for (e=chptr->jflood; e; e=e_next)
|
||||
{
|
||||
e_next = e->next_c;
|
||||
|
||||
/* remove from user.. */
|
||||
if (e->prev_u)
|
||||
e->prev_u->next_u = e->next_u;
|
||||
else
|
||||
e->cptr->user->jflood = e->next_u; /* new head */
|
||||
if (e->next_u)
|
||||
e->next_u->prev_u = e->prev_u;
|
||||
|
||||
/* actually free it */
|
||||
MyFree(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Regulary cleans up cmode-j user/chan structs */
|
||||
EVENT(cmodej_cleanup_structs)
|
||||
{
|
||||
aJFlood *e, *e_next;
|
||||
int i;
|
||||
aClient *cptr;
|
||||
aChannel *chptr;
|
||||
int t;
|
||||
CmodeParam *cmp;
|
||||
#ifdef DEBUGMODE
|
||||
int freed=0;
|
||||
#endif
|
||||
|
||||
for (chptr = channel; chptr; chptr=chptr->nextch)
|
||||
{
|
||||
if (!chptr->jflood)
|
||||
continue;
|
||||
t=0;
|
||||
/* t will be kept at 0 if not found or if mode not set,
|
||||
* but DO still check since there are entries left as indicated by ->jflood!
|
||||
*/
|
||||
if (chptr->mode.extmode & EXTMODE_JOINTHROTTLE)
|
||||
{
|
||||
for (cmp = chptr->mode.extmodeparam; cmp; cmp=cmp->next)
|
||||
if (cmp->flag == 'j')
|
||||
t = ((aModejEntry *)cmp)->t;
|
||||
}
|
||||
|
||||
for (e = chptr->jflood; e; e = e_next)
|
||||
{
|
||||
e_next = e->next_c;
|
||||
|
||||
if (e->firstjoin + t < TStime())
|
||||
{
|
||||
cmodej_delentry(e);
|
||||
#ifdef DEBUGMODE
|
||||
freed++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGMODE
|
||||
if (freed)
|
||||
ircd_log(LOG_ERROR, "cmodej_cleanup_structs: %d entries freed [%d bytes]", freed, freed * sizeof(aJFlood));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -51,6 +51,10 @@ DLLFUNC CMD_FUNC(_do_join);
|
||||
DLLFUNC int _can_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *key, char *link, char *parv[]);
|
||||
static int extended_operoverride(aClient *sptr, aChannel *chptr, char *key, int mval, char mchar);
|
||||
#define MAXBOUNCE 5 /** Most sensible */
|
||||
#ifdef JOINTHROTTLE
|
||||
static int isjthrottled(aClient *cptr, aChannel *chptr);
|
||||
static void cmodej_increase_usercounter(aClient *cptr, aChannel *chptr);
|
||||
#endif
|
||||
|
||||
/* Externs */
|
||||
extern MODVAR int spamf_ugly_vchanoverride;
|
||||
@@ -220,9 +224,97 @@ Ban *banned;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JOINTHROTTLE
|
||||
if (!IsAnOper(cptr) &&
|
||||
(chptr->mode.extmode & EXTMODE_JOINTHROTTLE) && isjthrottled(cptr, chptr))
|
||||
return ERR_TOOMANYJOINS;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef JOINTHROTTLE
|
||||
static int isjthrottled(aClient *cptr, aChannel *chptr)
|
||||
{
|
||||
CmodeParam *m;
|
||||
aJFlood *e;
|
||||
int num=0, t=0;
|
||||
|
||||
if (!MyClient(cptr))
|
||||
return 0;
|
||||
|
||||
for (m = chptr->mode.extmodeparam; m; m=m->next)
|
||||
if (m->flag == 'j')
|
||||
{
|
||||
num = ((aModejEntry *)m)->num;
|
||||
t = ((aModejEntry *)m)->t;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!num || !t)
|
||||
return 0;
|
||||
|
||||
/* Grab user<->chan entry.. */
|
||||
for (e = cptr->user->jflood; e; e=e->next_u)
|
||||
if (e->chptr == chptr)
|
||||
break;
|
||||
|
||||
if (!e)
|
||||
return 0; /* Not present, so cannot be throttled */
|
||||
|
||||
/* Ok... now the actual check:
|
||||
* if ([timer valid] && [one more join would exceed num])
|
||||
*/
|
||||
if (((TStime() - e->firstjoin) < t) && (e->numjoins == num))
|
||||
return 1; /* Throttled */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmodej_increase_usercounter(aClient *cptr, aChannel *chptr)
|
||||
{
|
||||
CmodeParam *m;
|
||||
aJFlood *e;
|
||||
int num=0, t=0;
|
||||
|
||||
if (!MyClient(cptr))
|
||||
return;
|
||||
|
||||
for (m = chptr->mode.extmodeparam; m; m=m->next)
|
||||
if (m->flag == 'j')
|
||||
{
|
||||
num = ((aModejEntry *)m)->num;
|
||||
t = ((aModejEntry *)m)->t;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!num || !t)
|
||||
return;
|
||||
|
||||
/* Grab user<->chan entry.. */
|
||||
for (e = cptr->user->jflood; e; e=e->next_u)
|
||||
if (e->chptr == chptr)
|
||||
break;
|
||||
|
||||
if (!e)
|
||||
{
|
||||
/* Allocate one */
|
||||
e = cmodej_addentry(cptr, chptr);
|
||||
e->firstjoin = TStime();
|
||||
e->numjoins = 1;
|
||||
} else
|
||||
if ((TStime() - e->firstjoin) < t) /* still valid? */
|
||||
{
|
||||
e->numjoins++;
|
||||
} else {
|
||||
/* reset :p */
|
||||
e->firstjoin = TStime();
|
||||
e->numjoins = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** m_join
|
||||
** parv[0] = sender prefix
|
||||
@@ -617,6 +709,9 @@ DLLFUNC CMD_FUNC(_do_join)
|
||||
me.name, parv[0], name);
|
||||
continue;
|
||||
}
|
||||
#ifdef JOINTHROTTLE
|
||||
cmodej_increase_usercounter(cptr, chptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
join_channel(chptr, cptr, sptr, flags);
|
||||
|
||||
+1
-1
@@ -556,7 +556,7 @@ static char *replies[] = {
|
||||
/* 497 */ NULL, /* ircu */
|
||||
/* 498 */ NULL, /* ircu */
|
||||
/* 499 ERR_CHANOWNPRIVNEEDED */ ":%s 499 %s %s :You're not a channel owner",
|
||||
/* 500 */ NULL,
|
||||
/* 500 ERR_TOOMANYJOINS */ ":%s 500 %s %s :Too many join requests. Please wait a while and try again.",
|
||||
/* 501 ERR_UMODEUNKNOWNFLAG */ ":%s 501 %s :Unknown MODE flag",
|
||||
/* 502 ERR_USERSDONTMATCH */ ":%s 502 %s :Cant change mode for other users",
|
||||
/* 503 */ NULL, /* austhex */
|
||||
|
||||
@@ -727,6 +727,9 @@ static void exit_one_client(aClient *cptr, aClient *sptr, aClient *from, char *c
|
||||
{
|
||||
RunHook2(HOOKTYPE_REMOTE_QUIT, sptr, comment);
|
||||
}
|
||||
#ifdef JOINTHROTTLE
|
||||
cmodej_deluserentries(sptr);
|
||||
#endif
|
||||
while ((mp = sptr->user->channel))
|
||||
remove_user_from_channel(sptr, mp->chptr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user