reguser *founder;
flag_t flags;
short type=0;
- unsigned int i;
+ unsigned int i, count;
void *args[3];
if (!rup)
chanservstdmessage(notify, QM_ALREADYREGISTERED, cip->name->content);
return CMD_ERROR;
}
-
+
+ count = 0;
+
+ for (rcup=founder->knownon;rcup;rcup=rcup->nextbyuser)
+ count++;
+
+ if (count > MAXCHANNELS) {
+ chanservstdmessage(sender, QM_TOOMANYCHANNELS, cip->name->content);
+ if (notify)
+ chanservstdmessage(sender, QM_TOOMANYCHANNELS, cip->name->content);
+ return CMD_ERROR;
+ }
+
/* Initialise the channel */
rcp=getregchan();
int csc_doadduser(void *source, int cargc, char **cargv) {
nick *sender=source;
chanindex *cip;
- regchanuser *rcup, *rcuplist;
+ regchanuser *rcup, *trcup, *rcuplist;
regchan *rcp;
reguser *rup;
flag_t addflags;
char *flagbuf;
- unsigned int count=0;
+ unsigned int chanlevcount=0, channelcount=0;
int added=0;
int i, foundflags=0;
void *args[3];
flagbuf=printflags(addflags, rcuflags);
/* ugh */
- for (count=i=0;i<REGCHANUSERHASHSIZE;i++)
+ for (chanlevcount=i=0;i<REGCHANUSERHASHSIZE;i++)
for (rcuplist=rcp->regusers[i];rcuplist;rcuplist=rcuplist->nextbychan)
- count++;
+ chanlevcount++;
/* If we found flags don't try to add them as a user as well.. */
for (i=1+foundflags;i<cargc;i++) {
continue;
}
- if(count++ >= MAXCHANLEVS) {
+ if(chanlevcount++ >= MAXCHANLEVS) {
chanservstdmessage(sender, QM_TOOMANYCHANLEVS);
chanservstdmessage(sender, QM_DONE);
return CMD_OK;
}
+ channelcount=0;
+ for (trcup=rup->knownon;trcup;trcup=trcup->nextbyuser)
+ channelcount++;
+
+ if(channelcount >= MAXCHANNELS) {
+ chanservstdmessage(sender, QM_TOOMANYCHANNELS);
+ return CMD_ERROR;
+ }
+
rcup=getregchanuser();
rcup->chan=rcp;
rcup->user=rup;
nick *sender=source;
chanindex *cip;
regchan *rcp;
- regchanuser *rcup, *rcuplist;
+ regchanuser *rcup, *trcup, *rcuplist;
regchanuser **rusers;
reguser *rup=getreguserfromnick(sender), *target;
char time1[TIMELEN],time2[TIMELEN];
if (!rcuplist) {
/* new user, we could store a count instead... that's probably better... */
- unsigned int count;
+ unsigned int chanlevcount, channelcount;
- for (count=i=0;i<REGCHANUSERHASHSIZE;i++)
+ for (chanlevcount=i=0;i<REGCHANUSERHASHSIZE;i++)
for (rcuplist=rcp->regusers[i];rcuplist;rcuplist=rcuplist->nextbychan)
- count++;
+ chanlevcount++;
- if(count >= MAXCHANLEVS) {
+ if(chanlevcount >= MAXCHANLEVS) {
chanservstdmessage(sender, QM_TOOMANYCHANLEVS);
return CMD_ERROR;
}
-
+
+ channelcount=0;
+ for (trcup=target->knownon;trcup;trcup=trcup->nextbyuser)
+ channelcount++;
+
+ if(channelcount >= MAXCHANNELS) {
+ chanservstdmessage(sender, QM_TOOMANYCHANNELS);
+ return CMD_ERROR;
+ }
+
rcuplist=getregchanuser();
rcuplist->user=target;
rcuplist->chan=rcp;
#define MAXCHANLEVS 500
#define MAXBANS 50
+/* Maximum number of channels a user may be known on */
+#define MAXCHANNELS 500
+
/* Sources of entropy and standard length defines */
#define ENTROPYSOURCE "/dev/urandom"
#define ENTROPYLEN 8
msg(QM_NOCHANBANAUTOREMOVE, "Bans on $0 will not be automatically removed.", "s"),
msg(QM_INVALIDCHANNAME, "$0 is not a valid channel name.", "s"),
msg(QM_ALREADYREGISTERED, "$0 is already registered.", "s"),
+ msg(QM_TOOMANYCHANNELS, "User is known on too many channels.", ""),
msg(QM_CURUSERFLAGS, "User flags for $0: $1", "ss"),
msg(QM_WELCOMEMESSAGEIS, "Welcome message for $0: $1", "ss"),
msg(QM_GLOBALINFO, "Default info line: $0", "s"),
#define DEPFILE "modules.dep"
-#define MAXMODULES 100
+#define MAXMODULES 200
/* Module dependency stuff.
*
+#define CS_NODB
#include "../chanserv/chanserv.h"
static nick *fakeq;
--- /dev/null
+@include@ @includel@../build.mk@includel@
+
+.PHONY: all
+all: invalidbans.so
+
+invalidbans.so: invalidbans.o
--- /dev/null
+#include <string.h>
+#include "../core/schedule.h"
+#include "../control/control.h"
+#include "../lib/irc_string.h"
+#include "../localuser/localuserchannel.h"
+#include "../lib/version.h"
+
+MODULE_VERSION("");
+
+static int ib_nickext;
+
+typedef struct ibnick {
+ time_t timeout;
+ void *sched;
+} ibnick;
+
+static void ib_clear_ext(void *arg) {
+ nick *np = arg;
+
+ if (!np->exts[ib_nickext])
+ return;
+
+ free(np->exts[ib_nickext]);
+ np->exts[ib_nickext] = NULL;
+}
+
+static void ib_hook_newnick(int hooknum, void *arg) {
+ nick *np = arg;
+ np->exts[ib_nickext] = NULL;
+}
+
+static void ib_hook_lostnick(int hooknum, void *arg) {
+ nick *np = arg;
+ ibnick *inp = np->exts[ib_nickext];
+
+ if (!inp)
+ return;
+
+ deleteschedule(inp->sched, ib_clear_ext, np);
+ free(np->exts[ib_nickext]);
+}
+
+static void ib_hook_modechange(int hooknum, void *arg) {
+ void **arglist=(void **)arg;
+ channel *cp=(channel *)arglist[0];
+ nick *np=(nick *)arglist[1];
+ long changeflags=(long)arglist[2];
+ chanban *cbp;
+ const char *p;
+ int colons, colonsnext;
+ modechanges changes;
+ ibnick *inp;
+ char *mask, *pos;
+ int slot, i;
+ array bans;
+
+ if (!(changeflags & MODECHANGE_BANS))
+ return;
+
+ inp = np->exts[ib_nickext];
+
+ /* Ignore the mode change if the same user has recently
+ * set/unset a channel ban. */
+ if (inp && inp->timeout > time(NULL))
+ return;
+
+ if (inp) {
+ deleteschedule(inp->sched, ib_clear_ext, np);
+ free(inp);
+ np->exts[ib_nickext] = NULL;
+ }
+
+ array_init(&bans, 512);
+
+ for (cbp = cp->bans; cbp; cbp = cbp->next) {
+ if (!cbp->host)
+ continue;
+
+ colons = 0;
+ colonsnext = 0;
+
+ for (p = cbp->host->content; *p; p++) {
+ if (*p == ':') {
+ colons++;
+
+ if (*(p + 1) == ':')
+ colonsnext = 1;
+ }
+ }
+
+ if (colons - colonsnext >= 8) {
+ slot = array_getfreeslot(&bans);
+ mask = ((char *)bans.content) + slot * 512;
+ strncpy(mask, bantostring(cbp), 512);
+ }
+ }
+
+ if (bans.cursi > 0) {
+ localsetmodeinit(&changes, cp, NULL);
+
+ for (i = 0; i < bans.cursi; i++) {
+ mask = ((char *)bans.content) + i * 512;
+
+ pos = strchr(mask, '@');
+
+ if (!pos)
+ continue; /* This should never happen. */
+
+ pos++; /* Skip over the @ sign. */
+
+ for (; *pos; pos++) {
+ if (*pos != ':') {
+ *pos = '?';
+ break;
+ }
+ }
+
+ localdosetmode_ban(&changes, mask, MCB_ADD);
+ }
+
+ localsetmodeflush(&changes, 1);
+
+ /* Ignore the user for a short amount of time. If it's a bot
+ * it'll probably try re-setting the ban immediately. */
+ inp = malloc(sizeof(ibnick));
+ inp->timeout = time(NULL) + 15;
+ inp->sched = scheduleoneshot(inp->timeout + 1, ib_clear_ext, np);
+ np->exts[ib_nickext] = inp;
+ }
+
+ array_free(&bans);
+}
+
+void _init() {
+ registerhook(HOOK_NICK_NEWNICK, &ib_hook_newnick);
+ registerhook(HOOK_NICK_LOSTNICK, &ib_hook_lostnick);
+ registerhook(HOOK_CHANNEL_MODECHANGE, &ib_hook_modechange);
+
+ ib_nickext = registernickext("invalidbans");
+}
+
+void _fini () {
+ deregisterhook(HOOK_NICK_NEWNICK, &ib_hook_newnick);
+ deregisterhook(HOOK_NICK_LOSTNICK, &ib_hook_lostnick);
+ deregisterhook(HOOK_CHANNEL_MODECHANGE, &ib_hook_modechange);
+
+ releasenickext(ib_nickext);
+}
+
if (ctx->searchcmd == reg_chansearch) {
cip = (chanindex *)theinput;
cip->marker = localdata->marker;
- localdata->count += cip->channel->users->totalusers;
+ if (cip->channel != NULL)
+ localdata->count += cip->channel->users->totalusers;
}
else {
np = (nick *)theinput;
}
base64toip(cargv[cargc-3], &ipaddress);
- if (!irc_in_addr_valid(&ipaddress)) {
- Error("nick",ERR_ERROR,"Received NICK with invalid ipaddress for %s from %s.",cargv[0],sender);
- return CMD_ERROR;
- }
/* At this stage the nick is cleared to proceed */
np=newnick();
.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
#include "request.h"
#include "lrequest.h"
#include "request_block.h"
+#include "request_fasttrack.h"
#include "../localuser/localuser.h"
/* stats counters */
-int lr_noregops = 0;
-int lr_scoretoolow = 0;
int lr_top5 = 0;
-int lr_floodattempts = 0;
+int lr_notargets = 0;
#define min(a,b) ((a > b) ? b : a)
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++;
-
- 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)));
-
- lr_floodattempts++;
+ lr_top5++;
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 they're out of targets */
+ if(rq_findblock(np->authname) || !rq_tryfasttrack(np)) {
+ sendnoticetouser(svc, np, "Sorry, you may not request %s for another "
+ "channel at this time. Please try again in an hour.", RQ_QNICK);
- lr_scoretoolow++;
+ lr_notargets++;
return RQ_ERROR;
}
-
sendmessagetouser(svc, qnick, "addchan %s #%s +jp upgrade %s", cp->index->name->content,
np->authname, np->nick);
}
void lr_requeststats(nick *rqnick, nick *np) {
- sendnoticetouser(rqnick, np, "- No registered ops (Q): %d", lr_noregops);
- sendnoticetouser(rqnick, np, "- Score too low (Q): %d", lr_scoretoolow);
+ sendnoticetouser(rqnick, np, "- Too many requests (Q): %d", lr_notargets);
sendnoticetouser(rqnick, np, "- Not in top%d (Q): %d", LR_TOPX, lr_top5);
- sendnoticetouser(rqnick, np, "- Floods (Q): %d", lr_floodattempts);
}
#include "../splitlist/splitlist.h"
#include "request.h"
#include "request_block.h"
+#include "request_fasttrack.h"
#include "lrequest.h"
#include "sqrequest.h"
-#include "user.h"
MODULE_VERSION("");
int rqcmd_stats(void *user, int cargc, char **cargv);
int rqcmd_requestop(void *user, int cargc, char **cargv);
-int rqcmd_adduser(void *user, int cargc, char **cargv);
-int rqcmd_deluser(void *user, int cargc, char **cargv);
-int rqcmd_changelev(void *user, int cargc, char **cargv);
-int rqcmd_userlist(void *user, int cargc, char **cargv);
-
#define min(a,b) ((a > b) ? b : a)
/* stats counters */
if(!rq_initblocks())
return;
+ if(!rq_initfasttrack())
+ return;
+
extloaded = 1;
rqcommands = newcommandtree();
addcommandtotree(rqcommands, "requestspamscan", RQU_ANY, 1, &rqcmd_requestspamscan);
addcommandtotree(rqcommands, "requestop", RQU_ANY, 2, &rqcmd_requestop);
- addcommandtotree(rqcommands, "addblock", RQU_ACCOUNT, 3, &rqcmd_addblock);
- addcommandtotree(rqcommands, "delblock", RQU_ACCOUNT, 1, &rqcmd_delblock);
- addcommandtotree(rqcommands, "listblocks", RQU_ACCOUNT, 1, &rqcmd_listblocks);
- addcommandtotree(rqcommands, "stats", RQU_ACCOUNT, 1, &rqcmd_stats);
-
- addcommandtotree(rqcommands, "adduser", RQU_OPER, 2, &rqcmd_adduser);
- addcommandtotree(rqcommands, "deluser", RQU_OPER, 1, &rqcmd_deluser);
- addcommandtotree(rqcommands, "changelev", RQU_OPER, 2, &rqcmd_changelev);
- addcommandtotree(rqcommands, "userlist", RQU_OPER, 1, &rqcmd_userlist);
+ addcommandtotree(rqcommands, "addblock", RQU_OPER, 3, &rqcmd_addblock);
+ addcommandtotree(rqcommands, "delblock", RQU_OPER, 1, &rqcmd_delblock);
+ addcommandtotree(rqcommands, "listblocks", RQU_OPER, 1, &rqcmd_listblocks);
+ addcommandtotree(rqcommands, "stats", RQU_OPER, 1, &rqcmd_stats);
qr_initrequest();
- ru_load();
rq_logfd = fopen(RQ_LOGFILE, "a");
deletecommandfromtree(rqcommands, "listblocks", &rqcmd_listblocks);
deletecommandfromtree(rqcommands, "stats", &rqcmd_stats);
- deletecommandfromtree(rqcommands, "adduser", &rqcmd_adduser);
- deletecommandfromtree(rqcommands, "deluser", &rqcmd_deluser);
- deletecommandfromtree(rqcommands, "changelev", &rqcmd_changelev);
- deletecommandfromtree(rqcommands, "userlist", &rqcmd_userlist);
-
destroycommandtree(rqcommands);
rq_finiblocks();
+ rq_finifasttrack();
qr_finirequest();
- ru_persist();
if (rq_logfd != NULL)
fclose(rq_logfd);
channel *cp;
rqnick = registerlocaluserflags(RQ_REQUEST_NICK, RQ_REQUEST_USER, RQ_REQUEST_HOST,
- RQ_REQUEST_REAL, RQ_REQUEST_AUTH, 1780711, 0,
+ RQ_REQUEST_REAL, RQ_REQUEST_AUTH, RQ_REQUEST_AUTHID, 0,
UMODE_ACCOUNT | UMODE_SERVICE | UMODE_OPER,
rq_handler);
return;
}
- if ((cmd->level & RQU_ACCOUNT) && (!IsAccount(user) || ru_getlevel(user) == 0) && !IsOper(user)) {
- sendnoticetouser(rqnick, user, "Sorry, this command is not "
- "available to you.");
-
- return;
- }
-
if (cargc - 1 > cmd->maxparams)
rejoinline(cargv[cmd->maxparams], cargc - cmd->maxparams);
if ((cmdlist[i]->level & RQU_OPER) && !IsOper(np))
continue;
- if ((cmdlist[i]->level & RQU_ACCOUNT) && !(IsOper(np) || (IsAccount(np) && ru_getlevel(np) > 0)))
- continue;
-
sendnoticetouser(rqnick, np, "%s", cmdlist[i]->command->content);
}
rq_block *block;
time_t expires;
char *account;
- int level = ru_getlevel(np);
- if (level < 20) {
+ if (!IsOper(np)) {
sendnoticetouser(rqnick, np, "You do not have access to this command.");
return RQ_ERROR;
expires = getnettime() + durationtolong(cargv[1]);
- if (expires > getnettime() + RQU_HELPER_MAXEXPIRE && level < 30) {
- sendnoticetouser(rqnick, np, "Maximum expiry time is %s.", rq_longtoduration(RQU_HELPER_MAXEXPIRE));
-
- return RQ_ERROR;
- }
-
rq_addblock(cargv[0], cargv[2], account, 0, expires);
sendnoticetouser(rqnick, np, "Blocked channels/accounts matching '%s' from "
int rqcmd_delblock(void *user, int cargc, char **cargv) {
nick *np = (nick*)user;
- int result, level;
- rq_block *block;
+ int result;
- level = ru_getlevel(np);
-
- if (level < 20) {
+ if (!IsOper(np)) {
sendnoticetouser(rqnick, np, "You do not have access to this command.");
return RQ_ERROR;
return RQ_ERROR;
}
- block = rq_findblock(cargv[0]);
-
- if (block != NULL && level < 50) {
- if (ircd_strcmp(block->creator->content, np->authname) != 0) {
- sendnoticetouser(rqnick, np, "This block was created by someone else. You cannot remove it.");
-
- return RQ_ERROR;
- }
- }
-
result = rq_removeblock(cargv[0]);
if (result > 0) {
int rqcmd_listblocks(void *user, int cargc, char **cargv) {
nick *np = (nick*)user;
rq_block block;
- int i, level;
+ int i;
- level = ru_getlevel(np);
-
- if (level < 10) {
+ if (!IsOper(np)) {
sendnoticetouser(rqnick, np, "You do not have access to this command.");
return RQ_ERROR;
int rqcmd_stats(void *user, int cargc, char **cargv) {
nick *np = (nick*)user;
- int level = ru_getlevel(np);
- if (level < 10) {
+ if (!IsOper(np)) {
sendnoticetouser(rqnick, np, "You do not have access to this command.");
return RQ_ERROR;
return RQ_OK;
}
-int rqcmd_adduser(void *user, int cargc, char **cargv) {
- nick *np = (nick*)user;
- int result, level;
-
- if (cargc < 2) {
- sendnoticetouser(rqnick, np, "Syntax: adduser <account> <level>");
-
- return RQ_ERROR;
- }
-
- level = atoi(cargv[1]);
-
- if (level <= 0) {
- sendnoticetouser(rqnick, np, "Level must be a positive integer.");
-
- return RQ_ERROR;
- }
-
- result = ru_create(cargv[0], level);
-
- if (result) {
- sendnoticetouser(rqnick, np, "User '%s' was added with level '%d'.", cargv[0], level);
-
- return RQ_OK;
- } else {
- sendnoticetouser(rqnick, np, "Something strange happened. Contact shroud.");
-
- return RQ_ERROR;
- }
-}
-
-int rqcmd_deluser(void *user, int cargc, char **cargv) {
- nick *np = (nick*)user;
- int level;
-
- if (cargc < 1) {
- sendnoticetouser(rqnick, np, "Syntax: deluser <account>");
-
- return RQ_ERROR;
- }
-
- level = ru_getlevel_str(cargv[0]);
-
- if (level <= 0) {
- sendnoticetouser(rqnick, np, "There is no such user.");
-
- return RQ_ERROR;
- }
-
- ru_destroy(cargv[0]);
-
- sendnoticetouser(rqnick, np, "Done.");
-
- return RQ_OK;
-}
-
-int rqcmd_changelev(void *user, int cargc, char **cargv) {
- nick *np = (nick*)user;
- int result, level;
-
- if (cargc < 2) {
- sendnoticetouser(rqnick, np, "Syntax: changelev <account> <level>");
-
- return RQ_ERROR;
- }
-
- level = atoi(cargv[1]);
-
- if (level <= 0) {
- sendnoticetouser(rqnick, np, "Level must be a positive integer.");
-
- return RQ_ERROR;
- }
-
- if (ru_getlevel_str(cargv[0]) <= 0) {
- sendnoticetouser(rqnick, np, "Unknown user.");
-
- return RQ_ERROR;
- }
-
- result = ru_setlevel(cargv[0], level);
-
- if (result != 0) {
- sendnoticetouser(rqnick, np, "Done.");
-
- return RQ_OK;
- } else {
- sendnoticetouser(rqnick, np, "Something strange happened. Contact shroud.");
-
- return RQ_ERROR;
- }
-}
-
-int rqcmd_userlist(void *user, int cargc, char **cargv) {
- nick *np = (nick*)user;
- r_user_t *userp = r_userlist;
-
- sendnoticetouser(rqnick, np, "User Level");
-
- while (userp) {
- sendnoticetouser(rqnick, np, "%s %d", userp->name, userp->level);
- userp = userp->next;
- }
-
- sendnoticetouser(rqnick, np, "--- End of USERS.");
-
- return RQ_OK;
-}
-
#define RQ_QSERVER "CServe.quakenet.org"
#define RQ_QNICK "Q"
-#define RQ_SSERVER "services.de.quakenet.org"
+#define RQ_SSERVER "services2.uk.quakenet.org"
#define RQ_SNICK "S"
#define RQ_REQUEST_NICK "R"
#define RQ_REQUEST_HOST "request.quakenet.org"
#define RQ_REQUEST_REAL "Service Request v0.23"
#define RQ_REQUEST_AUTH "R"
+#define RQ_REQUEST_AUTHID 1780711
#define RQU_ANY 0
#define RQU_OPER 1
-#define RQU_ACCOUNT 2
-/* one week by default */
-#define RQU_HELPER_MAXEXPIRE 604800
-
-#define RQ_USERFILE "data/rqusers"
#define RQ_LOGFILE "logs/request.log"
#define RQ_OK 0
/* 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, *next;
+
+ deregisterhook(HOOK_NICK_NEWNICK, &rqhook_account);
+ deregisterhook(HOOK_NICK_ACCOUNT, &rqhook_account);
+
+ for(ft=ftlist;ft;) {
+ next = ft->next;
+ free(ft);
+ ft = next;
+ }
+
+ 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) {
+ time_t now = getnettime();
+ rq_fasttrack **pft, *ft;
+ int j;
+ nick *tnp;
+
+ now = getnettime();
+
+ pft = &ftlist;
+
+ for(ft=*pft;*pft;pft=&((*pft)->next)) {
+ int foundnick = 0;
+
+ for(j=0;j<NICKHASHSIZE && !foundnick;j++) {
+ for(tnp=nicktable[j];tnp;tnp=tnp->next) {
+ if(tnp->exts[rqnext]==ft) {
+ foundnick = 1;
+ break;
+ }
+ }
+ }
+
+ if(!foundnick && ft->refill_time < now) {
+ *pft = ft->next;
+ free(ft);
+ }
+
+ if (!*pft)
+ break;
+ }
+}
+
+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;
+
+ ft->next = ftlist;
+ ftlist = ft;
+
+ 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 * 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);
void qr_requeststats(nick *rqnick, nick *np) {
sendnoticetouser(rqnick, np, "- Suspended (S): %d", qr_suspended);
- sendnoticetouser(rqnick, np, "- No chanstats (S): %d", qr_nohist);
- sendnoticetouser(rqnick, np, "- Too small (S): %d", qr_toosmall);
- sendnoticetouser(rqnick, np, "- User was not on chanlev (S): %d", qr_nochanlev);
- sendnoticetouser(rqnick, np, "- User was not the owner (S): %d", qr_notowner);
+ sendnoticetouser(rqnick, np, "- No chanstats (S): %d", qr_nohist);
+ sendnoticetouser(rqnick, np, "- Too small (S): %d", qr_toosmall);
+ sendnoticetouser(rqnick, np, "- User was not on chanlev (S): %d", qr_nochanlev);
+ sendnoticetouser(rqnick, np, "- User was not the owner (S): %d", qr_notowner);
sendnoticetouser(rqnick, np, "- A: %d", qr_a);
sendnoticetouser(rqnick, np, "- B: %d", qr_b);
sendnoticetouser(rqnick, np, "- C: %d", qr_c);
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-
-#include "../irc/irc_config.h"
-#include "../lib/irc_string.h"
-#include "../lib/strlfunc.h"
-#include "../nick/nick.h"
-#include "request.h"
-#include "user.h"
-
-r_user_t *r_userlist = NULL;
-int ru_loading = 0;
-
-r_user_t *ru_find(char *name);
-
-int ru_create(char *name, unsigned int level) {
- r_user_t *user, *trav;
-
- if (ru_setlevel(name, level) != 0)
- return 1;
-
- user = (r_user_t*)malloc(sizeof(r_user_t));
-
- if (user == NULL)
- return 0;
-
- user->next = NULL;
- strlcpy(user->name, name, sizeof(user->name));
- user->level = level;
-
- if (r_userlist == NULL)
- r_userlist = user;
- else {
- trav = r_userlist;
-
- while (trav->next)
- trav = trav->next;
-
- trav->next = user;
- }
-
- ru_persist();
-
- return 1;
-}
-
-void ru_destroy(char *name) {
- r_user_t *puser;
- r_user_t *user = r_userlist;
-
- if (user && ircd_strcmp(user->name, name) == 0) {
- free(r_userlist);
-
- r_userlist = NULL;
-
- ru_persist();
-
- return;
- }
-
- if (user == NULL)
- return;
-
- while (user && user->next) {
- if (ircd_strcmp(user->next->name, name) == 0) {
- puser = user->next;
- user->next = user->next->next;
-
- free(puser);
- }
-
- user = user->next;
- }
-
- ru_persist();
-}
-
-int ru_parseline(char *line) {
- char name[ACCOUNTLEN];
- unsigned int level;
- int result;
-
- if (sscanf(line, "%s %u", name, &level) < 2)
- return 0;
-
- ru_loading = 1;
- result = ru_create(name, level);
- ru_loading = 0;
-
- return result;
-}
-
-int ru_load(void) {
- char line[4096];
- FILE *rudata;
- int count;
-
- rudata = fopen(RQ_USERFILE, "r");
-
- if (rudata == NULL)
- return 0;
-
- count = 0;
-
- while (!feof(rudata)) {
- if (fgets(line, sizeof(line), rudata) == NULL)
- break;
-
- if (line[strlen(line) - 1] == '\n')
- line[strlen(line) - 1] = '\0';
-
- if (line[strlen(line) - 1] == '\r')
- line[strlen(line) - 1] = '\0';
-
- if (line[0] != '\0') {
- if (ru_parseline(line))
- count++;
- }
- }
-
- fclose(rudata);
-
- return count;
-}
-
-int ru_persist(void) {
- FILE *rudata;
- int count = 0;
- r_user_t *user = r_userlist;
-
- if (ru_loading)
- return 0;
-
- rudata = fopen(RQ_USERFILE, "w");
-
- if (rudata == NULL)
- return 0;
-
- while (user) {
- fprintf(rudata, "%s %u\n", user->name, user->level);
-
- user = user->next;
- }
-
- fclose(rudata);
-
- return count;
-}
-
-r_user_t *ru_find(char *name) {
- r_user_t *user = r_userlist;
-
- while (user) {
- if (ircd_strcmp(user->name, name) == 0)
- return user;
-
- user = user->next;
- }
-
- return NULL;
-}
-
-unsigned int ru_getlevel(nick *np) {
- if (IsOper(np))
- return 999;
- else if (!IsAccount(np))
- return 0;
-
- return ru_getlevel_str(np->authname);
-}
-
-unsigned int ru_getlevel_str(char *name) {
- r_user_t *user = ru_find(name);
-
- if (user)
- return user->level;
- else
- return 0;
-}
-
-int ru_setlevel(char *name, unsigned int level) {
- r_user_t *user = ru_find(name);
-
- if (user) {
- user->level = level;
-
- ru_persist();
-
- return 1;
- } else
- return 0;
-}
+++ /dev/null
-/* R user system */
-
-typedef struct r_user_s {
- struct r_user_s *next;
- char name[ACCOUNTLEN];
- unsigned int level;
-} r_user_t;
-
-extern r_user_t *r_userlist;
-
-int ru_load(void);
-int ru_persist(void);
-
-int ru_create(char *name, unsigned int level);
-void ru_destroy(char *name);
-unsigned int ru_getlevel(nick *np);
-unsigned int ru_getlevel_str(char *name);
-int ru_setlevel(char *name, unsigned int level);
--- /dev/null
+@include@ @includel@../build.mk@includel@
+.PHONY: all
+all: whowas.so
+
+whowas.so: whowas.o
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "../core/hooks.h"
+#include "../control/control.h"
+#include "../irc/irc.h"
+#include "../lib/irc_string.h"
+#include "whowas.h"
+
+static whowas *wwhead, *wwtail;
+static int wwcount;
+
+int ww_cmdwhowas(void *source, int cargc, char **cargv) {
+ nick *np = source;
+ char *pattern;
+ whowas *ww;
+ char hostmask[WW_MASKLEN+1];
+ char timebuf[30];
+ int matches = 0, limit = 500;
+
+ if(cargc<1)
+ return CMD_USAGE;
+
+ pattern = cargv[0];
+
+ if(cargc>1)
+ limit = strtol(cargv[1], NULL, 10);
+
+ for(ww=wwhead;ww;ww=ww->next) {
+ snprintf(hostmask, sizeof(hostmask), "%s!%s@%s", ww->nick, ww->ident, ww->host);
+
+ if (match2strings(pattern, hostmask)) {
+ matches++;
+
+ if(matches<=limit) {
+ strftime(timebuf, 30, "%d/%m/%y %H:%M:%S", localtime(&(ww->seen)));
+
+ controlreply(np, "[%s] %s (%s): %s", timebuf, hostmask, ww->realname, ww->reason->content);
+ } else if(matches==limit+1) {
+ controlreply(np, "--- More than %d matches, skipping the rest", limit);
+ }
+ }
+ }
+
+ controlreply(np, "--- Found %d entries.", matches);
+
+ return CMD_OK;
+}
+
+void ww_handlequitorkill(int hooknum, void *arg) {
+ void **args=arg;
+ nick *np=args[0];
+ char *reason=args[1];
+ char *rreason;
+ char resbuf[512];
+ whowas *ww;
+ time_t now;
+
+ time(&now);
+
+ /* Clean up old records. */
+ while((ww = wwtail) && (ww->seen < now - WW_MAXAGE || wwcount >= WW_MAXENTRIES)) {
+ wwtail = ww->prev;
+
+ if (ww->prev)
+ ww->prev->next = NULL;
+ else
+ wwhead = ww->prev;
+
+ wwcount--;
+ free(ww);
+ }
+
+ /* Create a new record. */
+ ww = malloc(sizeof(whowas));
+ strncpy(ww->nick, np->nick, NICKLEN);
+ strncpy(ww->ident, np->ident, USERLEN);
+ strncpy(ww->host, np->host->name->content, HOSTLEN);
+ strncpy(ww->realname, np->realname->name->content, REALLEN);
+ ww->seen = getnettime();
+
+ if(hooknum==HOOK_NICK_KILL && (rreason=strchr(reason,' '))) {
+ sprintf(resbuf,"Killed%s",rreason);
+ reason=resbuf;
+ }
+
+ ww->reason = getsstring(reason, WW_REASONLEN);
+
+ if(wwhead)
+ wwhead->prev = ww;
+
+ ww->next = wwhead;
+ wwhead = ww;
+
+ ww->prev = NULL;
+
+ if(!wwtail)
+ wwtail = ww;
+
+ wwcount++;
+}
+
+void _init(void) {
+ registerhook(HOOK_NICK_QUIT, ww_handlequitorkill);
+ registerhook(HOOK_NICK_KILL, ww_handlequitorkill);
+
+ registercontrolhelpcmd("whowas", NO_OPER, 2, &ww_cmdwhowas, "Usage: whowas <mask> ?limit?\nLooks up information about recently disconnected users.");
+}
+
+void _fini(void) {
+ whowas *ww;
+
+ deregisterhook(HOOK_NICK_QUIT, ww_handlequitorkill);
+ deregisterhook(HOOK_NICK_KILL, ww_handlequitorkill);
+
+ deregistercontrolcmd("whowas", &ww_cmdwhowas);
+
+ while((ww = wwhead)) {
+ wwhead = ww->next;
+ free(ww);
+ }
+}
--- /dev/null
+#define WW_MAXAGE 3600
+#define WW_MAXENTRIES 100000
+#define WW_MASKLEN (HOSTLEN + USERLEN + NICKLEN)
+#define WW_REASONLEN 512
+
+typedef struct whowas {
+ char nick[NICKLEN+1];
+ char ident[USERLEN+1];
+ char host[HOSTLEN+1];
+ char realname[REALLEN+1];
+ sstring *reason;
+
+ time_t seen;
+
+ struct whowas *next;
+ struct whowas *prev;
+} whowas;