.PHONY: all
all: request.so
-request.so: lrequest.o request.o request_block.o sqrequest.o user.o
+request.so: lrequest.o request.o request_block.o request_fasttrack.o sqrequest.o user.o
#include "request.h"
#include "lrequest.h"
#include "request_block.h"
+#include "request_fasttrack.h"
#include "../localuser/localuser.h"
/* stats counters */
cf = cf_findchanfix(cp->index);
- if (cf == NULL) {
- sendnoticetouser(svc, np, "Sorry, your channel '%s' was created recently. "
- "Please try again in an hour.", cp->index->name->content);
+ if(cf) {
+ rocount = cf_getsortedregops(cf, LR_TOPX, rolist);
- lr_noregops++;
+ ro = NULL;
- return RQ_ERROR;
- }
-
- rocount = cf_getsortedregops(cf, LR_TOPX, rolist);
-
- ro = NULL;
-
- for (i = 0; i < min(LR_TOPX, rocount); i++) {
- if (cf_cmpregopnick(rolist[i], np)) {
- ro = rolist[i];
- break;
+ for (i = 0; i < min(LR_TOPX, rocount); i++) {
+ if (cf_cmpregopnick(rolist[i], np)) {
+ ro = rolist[i];
+ break;
+ }
}
- }
- if (ro == NULL) {
- sendnoticetouser(svc, np, "Sorry, you must be one of the top %d ops "
- "for the channel '%s'.", LR_TOPX, cp->index->name->content);
+ if (ro == NULL) {
+ sendnoticetouser(svc, np, "Sorry, you must be one of the top %d ops "
+ "for the channel '%s'.", LR_TOPX, cp->index->name->content);
- lr_top5++;
+ lr_top5++;
- return RQ_ERROR;
+ return RQ_ERROR;
+ }
}
- /* treat blocked users as if their score is too low */
- if (ro->score < LR_CFSCORE || rq_findblock(np->authname)) {
- if (rq_isspam(np)) {
- sendnoticetouser(svc, np, "Do not flood the request system. "
- "Try again in %s.", rq_longtoduration(rq_blocktime(np)));
+ if(!rq_tryfasttrack(np)) {
+ if (cf == NULL) {
+ sendnoticetouser(svc, np, "Sorry, your channel '%s' was created recently. "
+ "Please try again in an hour.", cp->index->name->content);
- lr_floodattempts++;
+ lr_noregops++;
return RQ_ERROR;
}
- sendnoticetouser(svc, np, "Sorry, you do not meet the "
- "%s request requirements; please try again in an hour, "
- "see http://www.quakenet.org/faq/faq.php?c=1&f=6#6", RQ_QNICK);
+ /* treat blocked users as if their score is too low */
+ if (ro->score < LR_CFSCORE || rq_findblock(np->authname)) {
+ sendnoticetouser(svc, np, "Sorry, you do not meet the "
+ "%s request requirements; please try again in an hour, "
+ "see http://www.quakenet.org/faq/faq.php?c=1&f=6#6", RQ_QNICK);
- lr_scoretoolow++;
+ lr_scoretoolow++;
- return RQ_ERROR;
+ return RQ_ERROR;
+ }
}
-
sendmessagetouser(svc, qnick, "addchan %s #%s +jp upgrade %s", cp->index->name->content,
np->authname, np->nick);
#include "../splitlist/splitlist.h"
#include "request.h"
#include "request_block.h"
+#include "request_fasttrack.h"
#include "lrequest.h"
#include "sqrequest.h"
#include "user.h"
if(!rq_initblocks())
return;
+ if(!rq_initfasttrack())
+ return;
+
extloaded = 1;
rqcommands = newcommandtree();
destroycommandtree(rqcommands);
rq_finiblocks();
+ rq_finifasttrack();
qr_finirequest();
ru_persist();
/* array of blocks */
array rqblocks;
-/* our anti-flood nick extension */
-int rqnext;
-
/* are we currently loading blocks? */
int rq_loading;
-void rqhook_lostnick(int hook, void *arg);
-
int rq_initblocks(void) {
- rqnext = registernickext("request");
- if(rqnext < 0)
- return 0;
-
array_init(&rqblocks, sizeof(rq_block));
array_setlim1(&rqblocks, 5);
array_setlim2(&rqblocks, 20);
rq_addblock("#qnet*", "Reserved for QuakeNet use only.", "request", 0, 0);
rq_addblock("#help*", "Reserved for QuakeNet use only.", "request", 0, 0);
- registerhook(HOOK_NICK_LOSTNICK, &rqhook_lostnick);
-
return 1;
}
void rq_finiblocks(void) {
int i;
rq_block block;
- nick *nip;
for (i = 0; i < rqblocks.cursi; i++) {
block = ((rq_block*)rqblocks.content)[i];
}
array_free(&rqblocks);
-
- for (i=0; i<NICKHASHSIZE; i++)
- for (nip=nicktable[i]; nip; nip=nip->next)
- free(nip->exts[rqnext]);
-
- deregisterhook(HOOK_NICK_LOSTNICK, &rqhook_lostnick);
-
- releasenickext(rqnext);
-}
-
-void rqhook_lostnick(int hook, void *arg) {
- nick *np = (nick*)arg;
-
- free(np->exts[rqnext]);
-}
-
-int rq_isspam(nick *np) {
- rq_flood *lf;
-
- if (np->exts[rqnext] == NULL) {
- np->exts[rqnext] = lf = (rq_flood*)malloc(sizeof(rq_flood));
-
- lf->count = 1;
- lf->created = getnettime();
- lf->expire = 0;
-
- return 0;
- } else {
- lf = np->exts[rqnext];
-
- lf->count -= (getnettime() - lf->created) / (RQ_SPAMBLOCK / RQ_SPAMCOUNT);
-
- if (lf->count < 0)
- lf->count = 0;
-
- if (lf->count > RQ_SPAMCOUNT && lf->expire > getnettime()) {
- return 1;
- } else {
- lf->count++;
-
- if (lf->count > RQ_SPAMCOUNT) {
- lf->expire = getnettime() + RQ_SPAMBLOCK;
-
- rq_addblock(np->authname, "Flooding the request system.", "request", 0, getnettime() + 3600);
-
- return 1;
- }
-
- return 0;
- }
- }
-}
-
-time_t rq_blocktime(nick *np) {
- if (np->exts[rqnext] == NULL)
- return 0;
- else
- return ((rq_flood*)np->exts[rqnext])->expire - getnettime();
}
rq_block *rq_findblock(const char *pattern) {
#include "../nick/nick.h"
#include "../channel/channel.h"
-typedef struct {
- int count;
- time_t created;
- time_t expire;
-} rq_flood;
-
typedef struct {
sstring *pattern;
sstring *reason;
#define RQ_BLOCKFILE "data/rqblocks"
#define RQ_BLOCKLEN 256
-#define RQ_SPAMCOUNT 5
-#define RQ_SPAMBLOCK 3600
-
int rq_initblocks(void);
void rq_finiblocks(void);
rq_block *rq_findblock(const char *pattern);
void rq_addblock(const char *pattern, const char *reason, const char *creator, time_t created, time_t expires);
int rq_removeblock(const char *pattern);
-
-/* anti-spam blocks */
-int rq_isspam(nick *np);
-time_t rq_blocktime(nick *np);
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "../core/schedule.h"
+#include "../irc/irc.h"
+#include "../lib/irc_string.h"
+#include "request_fasttrack.h"
+
+typedef struct rq_fasttrack {
+ unsigned long userid;
+
+ unsigned int targets;
+ time_t refill_time;
+
+ struct rq_fasttrack *next;
+} rq_fasttrack;
+
+static rq_fasttrack *ftlist;
+
+/* our fast-track extension */
+int rqnext;
+
+static void rq_cleanup_fasttrack(void *arg);
+static void rqhook_account(int hook, void *arg);
+
+int rq_initfasttrack(void) {
+ rqnext = registernickext("request_fasttrack");
+ if(rqnext < 0)
+ return 0;
+
+ registerhook(HOOK_NICK_NEWNICK, &rqhook_account);
+ registerhook(HOOK_NICK_ACCOUNT, &rqhook_account);
+
+ schedulerecurring(time(NULL)+1, 0, 3600, rq_cleanup_fasttrack, NULL);
+
+ return 1;
+}
+
+void rq_finifasttrack(void) {
+ rq_fasttrack *ft;
+
+ deregisterhook(HOOK_NICK_NEWNICK, &rqhook_account);
+ deregisterhook(HOOK_NICK_ACCOUNT, &rqhook_account);
+
+ for(ft=ftlist;ft;ft=ft->next)
+ free(ft);
+
+ releasenickext(rqnext);
+}
+
+static void rqhook_account(int hook, void *arg) {
+ nick *np = (nick *)arg;
+ rq_fasttrack *ft;
+
+ /* Auth might be null for the newnick hook. */
+ if(!np->auth)
+ return;
+
+ /* Try to find an existing fasttrack record for this user. */
+ for(ft=ftlist;ft;ft=ft->next) {
+ if(np->auth->userid==ft->userid) {
+ np->exts[rqnext] = ft;
+ break;
+ }
+ }
+}
+
+static void rq_cleanup_fasttrack(void *arg) {
+
+}
+
+static rq_fasttrack *rq_getfasttrack(nick *np) {
+ rq_fasttrack *ft;
+
+ /* Use an existing fast-track record if the nick has one. */
+ if(np->exts[rqnext])
+ return np->exts[rqnext];
+
+ if(!np->auth)
+ return NULL;
+
+ ft = malloc(sizeof(rq_fasttrack));
+
+ if(!ft)
+ return NULL;
+
+ ft->userid = np->auth->userid;
+ ft->targets = 0;
+ ft->refill_time = 0;
+
+ np->exts[rqnext] = ft;
+
+ return ft;
+}
+
+int rq_tryfasttrack(nick *np) {
+ rq_fasttrack *ft = rq_getfasttrack(np);
+
+ /* Don't fast-track if we can't find a fast-track record. */
+ if(!ft)
+ return 0;
+
+ /* Refill targets if necessary. */
+ if(getnettime() > ft->refill_time) {
+ ft->targets = RQ_FASTTRACK_TARGETS;
+ ft->refill_time = getnettime() + RQ_FASTTRACK_TIMEOUT;
+ }
+
+ /* Check if we have a free target. */
+ if(ft->targets==0)
+ return 0;
+
+ ft->targets--;
+ return 1;
+}
+
--- /dev/null
+#include "../nick/nick.h"
+#include "../channel/channel.h"
+
+#define RQ_FASTTRACK_TARGETS 2
+#define RQ_FASTTRACK_TIMEOUT 60
+
+int rq_initfasttrack(void);
+void rq_finifasttrack(void);
+
+int rq_tryfasttrack(nick *np);
int qr_requests(nick *rqnick, nick *sender, channel *cp, nick *qnick) {
chanindex *cip = cp->index;
- int who = 0;
requestrec *nextreq, *lastreq;
- if (rq_isspam(sender)) {
- sendnoticetouser(rqnick, sender, "Do not flood the request system."
- " Try again in %s.", rq_longtoduration(rq_blocktime(sender)));
-
- return RQ_ERROR;
- }
-
/* check which service is on the channel */
if (getnumerichandlefromchanhash(cp->users, qnick->numeric) != NULL) {
- /* we've found Q */
- who = QR_Q;
-
/* Request stats from Q */
sendmessagetouser(rqnick, qnick, "CHANLEV %s", cip->name->content);