* Depends on "chanstats" and "chanfix"
*/
+#include <stdio.h>
#include "request.h"
#include "sqrequest.h"
#include "request_block.h"
#include "../localuser/localuser.h"
#include "../lib/irc_string.h"
#include "../core/schedule.h"
+#include "../core/config.h"
+#include "../spamscan2/spamscan2.h"
#include <stdarg.h>
#include <stdio.h>
requestrec *nextreqq, *lastreqq;
-requestrec *nextqreq, *lastqreq;
+static requestrec *nextqreq, *lastqreq;
extern nick *rqnick;
int rlstate;
int qr_nochanlev = 0;
int qr_notowner = 0;
+int qr_a = 0;
+int qr_b = 0;
+int qr_c = 0;
+int qr_d = 0;
+int qr_e = 0;
+
/* Check whether the user is blocked */
int qr_blockcheck(requestrec *req) {
nick *np;
return 0;
}
+unsigned int rq_countchanusers(channel *cp) {
+ int i, count=0;
+
+ for (i=0;i<cp->users->hashsize;i++) {
+ if (cp->users->content[i]==nouser)
+ continue;
+
+ count++;
+ }
+
+ return count;
+}
+
/*
* Deal with outcome of a queued request. The request should be freed
* as part of the process.
*/
-void qr_result(requestrec *req, int outcome, char *message, ...) {
+static void qr_result(requestrec *req, int outcome, char failcode, char *message, ...) {
sstring *user, *password;
requestrec **rh;
char msgbuf[512];
va_list va;
- channel *cplog;
- nick *lnp, *qnp, *np, *tnp, *snp;
-
+ nick *np, *tnp, *snp;
+ char now[50];
+ time_t now_ts;
+ unsigned int unique, total;
+
/* Delete the request from the list first.. */
for (rh=&nextreql;*rh;rh=&((*rh)->next)) {
if (*rh==req) {
return;
}
- cplog = findchannel(RQ_LOGCHANNEL);
+ if (rq_logfd != NULL) {
+ now[0] = '\0';
+ now_ts = time(NULL);
+
+ if (req->cip->channel) {
+ unique = countuniquehosts(req->cip->channel);
+ total = rq_countchanusers(req->cip->channel);
+ } else {
+ unique = 0;
+ total = 0;
+ }
- if (cplog) {
- sendmessagetochannel(rqnick, cplog, "request (%s) for %s from %s: Request was %s.", (req->what == QR_CSERVE) ? RQ_QNICK : RQ_SNICK, req->cip->name->content, tnp->nick, (outcome == QR_OK) ? "accepted" : "denied");
+ strftime(now, sizeof(now), "%c", localtime(&now_ts));
+ fprintf(rq_logfd, "%s: request (%s) for %s (%d unique users, "
+ "%d total users) from %s: Request was %s (%c).\n", now,
+ (req->what == QR_CSERVE) ? RQ_QNICK : RQ_SNICK,
+ req->cip->name->content, unique, total, tnp->nick,
+ (outcome == QR_OK) ? "accepted" : "denied", failcode);
+ fflush(rq_logfd);
}
if (outcome==QR_OK) {
- if (req->what == QR_CSERVE) {
- /* Delete L, add Q. Check that they both exist first, though. */
-
- if (!(lnp=getnickbynick(RQ_LNICK)) || !(qnp=getnickbynick(RQ_QNICK))) {
- sendnoticetouser(rqnick, tnp,
- "Error: Cannot find %s and %s on the network. "
- "Please request again later.", RQ_LNICK, RQ_QNICK);
- free(req);
- return;
- }
-
- /* /msg Q ADDCHAN <channel> <flags> <owners nick> <channeltype> */
- sendmessagetouser(rqnick, qnp, "ADDCHAN %s +ap #%s upgrade",
- req->cip->name->content,
- np->authname);
-
- sendnoticetouser(rqnick, tnp, "Adding %s to channel, please wait...",
- RQ_QNICK);
- } else if (req->what == QR_SPAMSCAN) {
+ if (req->what == QR_SPAMSCAN) {
/* Add S */
if (!(snp=getnickbynick(RQ_SNICK))) {
RQ_SNICK);
/* auth */
- user = getcopyconfigitem("request", "user", "R", 30);
- password = getcopyconfigitem("request", "password", "bla", 30);
+ user = (sstring *)getcopyconfigitem("request", "user", "R", 30);
+ password = (sstring *)getcopyconfigitem("request", "password", "bla", 30);
sendmessagetouser(rqnick, snp, "AUTH %s %s", user->content, password->content);
freesstring(user);
freesstring(password);
/* /msg S addchan <channel> default */
- sendmessagetouser(rqnick, snp, "ADDCHAN %s default", req->cip->name->content);
+ //sendmessagetouser(rqnick, snp, "ADDCHAN %s default +op", req->cip->name->content);
+
+{
+ spamscan_channelprofile *cp;
+ spamscan_channelsettings *cs;
+ spamscan_channelext *ce;
+ chanindex *sc_index;
+
+ cs = spamscan_getchannelsettings(req->cip->name->content, 0);
+
+ if ( !cs ) {
+ cp = spamscan_getchannelprofile("Default", 0);
+
+ if ( cp ) {
+ cs = spamscan_getchannelsettings(req->cip->name->content, 1);
+
+ if ( cs ) {
+ cs->cp = cp;
+ cs->addedby = spamscan_getaccountsettings("R", 0);
+ cs->flags = SPAMSCAN_CF_IGNOREOPS;
+
+ sc_index = findorcreatechanindex(req->cip->name->content);
+
+ if ( sc_index ) {
+ ce = spamscan_getchanext(sc_index, 1);
+ ce->cs = cs;
+
+ if ( s_nickname && !CFIsSuspended(cs) && sc_index->channel ) {
+ ce->joinedchan = 1;
+ localjoinchannel(s_nickname, sc_index->channel);
+ localgetops(s_nickname, sc_index->channel);
+ }
+ }
+
+ spamscan_insertchanneldb(cs);
+ }
+ }
+ }
+}
/* we do not put the request into another queue, so free it here */
free(req);
* Checks that a channel is beeeeg enough for teh Q
*/
-int qr_checksize(chanindex *cip, int what) {
+static int qr_checksize(chanindex *cip, int what, char *failcode) {
chanstats *csp;
channel *cp;
- nick *np;
- int i , avg, tot=0, authedcount=0, count=0;
+ nick *np, *qbot;
+ int i , avg, tot=0, authedcount=0, count=0, uniquecount, avgcount;
cp = cip->channel;
return 1;
#endif
+ /* make sure we can actually add Q */
+ if (what == QR_CSERVE) {
+ qbot = getnickbynick(RQ_QNICK);
+
+ if (!qbot)
+ return 0;
+
+ if (QR_MAXQCHANS != 0 && qbot->channels->cursi > QR_MAXQCHANS) {
+ qr_a++;
+ *failcode = 'A';
+ return 0; /* no Q for you :p */
+ }
+ }
+
/* make sure that there are enough authed users */
for (i=0;i<cp->users->hashsize;i++) {
if (cp->users->content[i] != nouser) {
}
}
- if (authedcount * 100 / count < QR_AUTHEDPCT)
+ int authedpct;
+
+ if (what == QR_CSERVE) {
+ if ( count <= QR_AUTHEDPCT_SCALE ) {
+ authedpct = QR_AUTHEDPCT_CSERVE;
+ } else if ( count >= QR_AUTHEDPCT_SCALEMAX ) {
+ authedpct = QR_AUTHEDPCT_CSERVEMIN;
+ } else {
+ authedpct = (QR_AUTHEDPCT_CSERVEMIN + (((QR_AUTHEDPCT_CSERVE - QR_AUTHEDPCT_CSERVEMIN) * (100 - (((count - QR_AUTHEDPCT_SCALE) * 100) / (QR_AUTHEDPCT_SCALEMAX - QR_AUTHEDPCT_SCALE)))) / 100));
+ }
+ }
+ else {
+ if ( count <= QR_AUTHEDPCT_SCALE ) {
+ authedpct = QR_AUTHEDPCT_SPAMSCAN;
+ } else if ( count >= QR_AUTHEDPCT_SCALEMAX ) {
+ authedpct = QR_AUTHEDPCT_SPAMSCANMIN;
+ } else {
+ authedpct = (QR_AUTHEDPCT_SPAMSCANMIN + (((QR_AUTHEDPCT_SPAMSCAN - QR_AUTHEDPCT_SPAMSCANMIN) * (100 - (((count - QR_AUTHEDPCT_SCALE) * 100) / (QR_AUTHEDPCT_SCALEMAX - QR_AUTHEDPCT_SCALE)))) / 100));
+ }
+ }
+
+ if (authedcount * 100 / count < authedpct) {
+ qr_b++;
+ *failcode = 'B';
return 0; /* too few authed users */
+ }
if (!(csp=cip->exts[csext]))
return 0;
tot += csp->lastdays[i];
}
+ uniquecount = countuniquehosts(cp);
+ avgcount = tot / HISTORYDAYS / 10;
+
+ /* chan needs at least QR_MINUSERPCT% of the avg usercount, and can't have
+ * more than QR_MAXUSERPCT% */
+ if ( what == QR_CSERVE ) {
+ if ((avgcount * QR_MINUSERSPCT / 100 > uniquecount)) {
+ qr_c++;
+ *failcode = 'C';
+ return 0;
+ }
+ if ((avgcount * QR_MAXUSERSPCT / 100 < uniquecount)) {
+ qr_e++;
+ *failcode = 'E';
+ return 0;
+ }
+ }
+
avg = (what == QR_CSERVE) ? QR_REQUIREDSIZE_CSERVE : QR_REQUIREDSIZE_SPAMSCAN;
if (tot > (avg * 140))
return 1;
-
- return 0;
+ else {
+ qr_d++;
+ *failcode = 'D';
+ return 0;
+ }
}
/* This function deals with notices from L: basically we track the
* 11:12 -L(TheLBot@lightweight.quakenet.org)- End of chanlev for #twilightzone.
*/
-void qr_handlenotice(nick *sender, char *message) {
+void qr_handle_notice(nick *sender, char *message) {
char *ch, *chop;
chanindex *cip;
requestrec *rrp1, *rrp2;
nick *np;
int delrequest = 0, state, who;
requestrec *nextreq;
- channel *logcp;
-/* logcp = findchannel("#qnet.request");
-
- if (logcp)
- sendmessagetochannel(rqnick, logcp, "%s: %s - %d %d %x %x", sender->nick, message, rlstate, rqstate, nextreql, nextreqq);
-*/
if (!ircd_strcmp(sender->nick, RQ_QNICK) && nextqreq) {
/* Message from Q */
if (!ircd_strcmp(message,"Done.")) {
/* Q added the channel: delete from L and tell the user. */
/* If L has conspired to vanish between the request and the outcome,
* we have a chan with Q and L... too bad. */
-
- if ((np=getnickbynick(RQ_LNICK))) {
- sendmessagetouser(rqnick, np, "SENDCHANLEV %s %s",
- nextqreq->cip->name->content, RQ_QNICK);
-
- sendmessagetouser(rqnick, np, "DELCHAN %s",
- nextqreq->cip->name->content);
- }
-
- if ((np=getnickbynumeric(nextqreq->reqnumeric))) {
- sendnoticetouser(rqnick, np, "Request completed. %s added.", RQ_QNICK);
- }
delrequest = 1;
} else if (!ircd_strcmp(message,"That channel already exists.")) {
- if ((np=getnickbynumeric(nextqreq->reqnumeric))) {
- sendnoticetouser(rqnick, np,
- "Your channel appears to have %s already "
- "(it may be suspended).", RQ_QNICK);
-
- qr_suspended++;
delrequest = 1;
- }
}
/* For either of the two messages above we want to delete the request
}
}
- if (!ircd_strcmp(sender->nick, RQ_LNICK) || !ircd_strcmp(sender->nick, RQ_QNICK)) {
- who = !ircd_strcmp(sender->nick, RQ_LNICK) ? QR_L : QR_Q;
+ if (!ircd_strcmp(sender->nick, RQ_QNICK)) {
+ who = QR_Q;
state = (who == QR_Q) ? rqstate : rlstate;
nextreq = (who == QR_Q) ? nextreqq : nextreql;
(!ircd_strncmp(message,"Known users on",14) && who == QR_Q)
) {
/* Looks like the right message. Let's find a channel name */
-
for (ch=message;*ch;ch++)
if (*ch=='#')
break;
/* chop off any remaining words */
chop = ch;
while (*(chop++)) {
- if (*chop == ' ') {
+ if (*chop == ' ' || *chop == ':') {
*chop = '\0';
break;
}
}
-
if (!(cip=findchanindex(ch))) {
Error("qrequest",ERR_WARNING,
"Unable to find channel from L/Q message: %s",ch);
rlstate = QRLstate_AWAITINGUSER;
else
rqstate = QRLstate_AWAITINGUSER;
-
return;
} else {
/* Uh-oh, not the channel we wanted. Something is fucked
"Lost response for channel %s; skipping.",
rrp2->cip->name->content);
- qr_result(rrp2, QR_FAILED,
+ qr_result(rrp2, QR_FAILED, 'X',
"Sorry, an error occurred while processing your request.");
rrp2 = nextreq = (who == QR_Q) ? nextreqq : nextreql;
/* Oh dear, we got to the end of the chanlev in this state.
* This means that we didn't find the user.
*/
-
- qr_result(nextreq, QR_FAILED,
+ qr_result(nextreq, QR_FAILED, 'X',
"Error: You are not known on %s.",
nextreq->cip->name->content);
/* This is not the user you are looking for */
return;
}
-
/* Check for owner flag. Both branches of this if will
* take the request off the list, one way or the other. */
- if (strchr(ch, 'n')) {
+
+ /* chop off any remaining words */
+ chop = ch;
+ while (*(chop++)) {
+ if (*chop != ' ' ) {
+ break;
+ }
+ }
+ /* chop off any remaining words */
+ ch = chop;
+ while (*(chop++)) {
+ if (*chop == ' ' || *chop == ':') {
+ *chop = '\0';
+ break;
+ }
+ }
+
+ if (strchr(ch, 'n')) {
+ char failcode;
/* They iz teh +n! */
-
/* Note: We're checking for blocks kind of late, so the request
system gets a chance to send other error messages first (like
'no chanstats', 'not known on channel', etc.). This is required
so that the user doesn't notice that he's being blocked. */
- if (qr_checksize(nextreq->cip, nextreq->what) && !qr_blockcheck(nextreq)) {
- qr_result(nextreq, QR_OK, "OK");
+ if (qr_checksize(nextreq->cip, nextreq->what, &failcode) && !qr_blockcheck(nextreq)) {
+ qr_result(nextreq, QR_OK, '-', "OK");
} else {
- if (nextreq->what == QR_CSERVE) {
- qr_result(nextreq, QR_FAILED,
- "Error: You do not meet the requirements "
- "for %s. Please continue to use %s.", RQ_QNICK, RQ_LNICK);
- } else {
- qr_result(nextreq, QR_FAILED,
- "Error: Your channel does not require %s. "
- "Try again later.", RQ_SNICK);
- }
-
+ qr_result(nextreq, QR_FAILED, failcode,
+ "Error: Sorry, Your channel '%s' does not require %s. Please try again in a few days.", nextreq->cip->name->content, RQ_SNICK);
+
qr_toosmall++;
}
} else {
- qr_result(nextreq, QR_FAILED,
+ qr_result(nextreq, QR_FAILED, 'X',
"Error: You don't hold the +n flag on %s.",
nextreq->cip->name->content);
*/
int qr_requestq(nick *rqnick, nick *sender, channel *cp, nick *lnick, nick *qnick) {
- chanindex *cip = cp->index;
-
- /* Check:
- * - we have some form of channel stats for the channel
- *
- * Note that the actual channel stats will not be checked
- * until we're sure the user has +n on the channel.
- */
-
- if (rq_isspam(sender)) {
- sendnoticetouser(rqnick, sender, "Error: Do not flood the request system."
- " Try again in %s.", rq_longtoduration(rq_blocktime(sender)));
-
- return RQ_ERROR;
- }
-
- if (!cip->exts[csext]) {
- sendnoticetouser(rqnick, sender,
- "Error: No historical record exists for %s.",
- cip->name->content);
-
- qr_nohist++;
-
- return RQ_ERROR;
- }
-
- /* Request stats from L */
- sendmessagetouser(rqnick, lnick, "CHANLEV %s", cip->name->content);
-
- /* Sort out a request record */
- if (lastreql) {
- lastreql->next = (requestrec *)malloc(sizeof(requestrec));
- lastreql=lastreql->next;
- } else {
- lastreql=nextreql=(requestrec *)malloc(sizeof(requestrec));
- }
-
- lastreql->next = NULL;
- lastreql->cip = cip;
- lastreql->what = QR_CSERVE;
- lastreql->who = QR_L;
- lastreql->reqnumeric = sender->numeric;
-
- if (rlstate == QRLstate_IDLE)
- rlstate = QRLstate_AWAITINGCHAN;
-
- sendnoticetouser(rqnick, sender,
- "Checking your %s access. "
- "This may take a while, please be patient...", RQ_LNICK);
-
- /* we don't know yet whether the request was successful */
return RQ_UNKNOWN;
}
chanfix *cf;
regop *ro;
int rocount, i;
+ char failcode;
regop *rolist[QR_TOPX];
- if (!qr_checksize(cp->index, QR_CSERVE))
+ if (!qr_checksize(cp->index, QR_CSERVE, &failcode))
return RQ_ERROR;
cf = cf_findchanfix(cp->index);
nextreql = fakerequest;
}
- qr_result(fakerequest, QR_OK, "OK");
+ qr_result(fakerequest, QR_OK, '-', "OK");
return RQ_OK;
}
-int qr_requests(nick *rqnick, nick *sender, channel *cp, nick *lnick, nick *qnick) {
+int qr_requests(nick *rqnick, nick *sender, channel *cp, nick *qnick) {
chanindex *cip = cp->index;
- int who;
+ int who = 0;
requestrec *nextreq, *lastreq;
if (rq_isspam(sender)) {
}
/* check which service is on the channel */
- if (getnumerichandlefromchanhash(cp->users, lnick->numeric) != NULL) {
- /* we've found L */
- who = QR_L;
-
- /* Request stats from L */
- sendmessagetouser(rqnick, lnick, "CHANLEV %s", cip->name->content);
-
- if (rlstate == QRLstate_IDLE)
- rlstate = QRLstate_AWAITINGCHAN;
- } else if (getnumerichandlefromchanhash(cp->users, qnick->numeric) != NULL) {
+ if (getnumerichandlefromchanhash(cp->users, qnick->numeric) != NULL) {
/* we've found Q */
who = QR_Q;
rqstate = QRLstate_AWAITINGCHAN;
} /* 'else' cannot happen as R has already checked whether the user has L or Q */
- lastreq = (who == QR_Q) ? lastreqq : lastreql;
- nextreq = (who == QR_Q) ? nextreqq : nextreql;
+ lastreq = lastreqq;
+ nextreq = nextreqq;
/* Sort out a request record */
if (lastreq) {
lastreq->what = QR_SPAMSCAN;
lastreq->reqnumeric = sender->numeric;
- if (who == QR_Q) {
- nextreqq = nextreq;
- lastreqq = lastreq;
- } else {
- nextreql = nextreq;
- lastreql = lastreq;
- }
+ nextreqq = nextreq;
+ lastreqq = lastreq;
- sendnoticetouser(rqnick, sender,
+ sendnoticetouser(rqnick, sender,
"Checking your %s access. "
"This may take a while, please be patient...",
- who == QR_Q ? RQ_QNICK : RQ_LNICK);
+ RQ_QNICK);
return RQ_UNKNOWN;
}
}
void qr_requeststats(nick *rqnick, nick *np) {
- sendnoticetouser(rqnick, np, "- Suspended (Q): %d", qr_suspended);
- sendnoticetouser(rqnick, np, "- No chanstats (Q/S): %d", qr_nohist);
- sendnoticetouser(rqnick, np, "- Too small (Q/S): %d", qr_toosmall);
- sendnoticetouser(rqnick, np, "- User was not on chanlev (Q/S): %d", qr_nochanlev);
- sendnoticetouser(rqnick, np, "- User was not the owner (Q/S): %d", qr_notowner);
+ 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, "- A: %d", qr_a);
+ sendnoticetouser(rqnick, np, "- B: %d", qr_b);
+ sendnoticetouser(rqnick, np, "- C: %d", qr_c);
+ sendnoticetouser(rqnick, np, "- D: %d", qr_d);
+ sendnoticetouser(rqnick, np, "- E: %d", qr_e);
+
}