X-Git-Url: https://jfr.im/git/irc/quakenet/newserv.git/blobdiff_plain/c3db6f7e2ed8432450c1ed4ad4989dd13eced351..d1b8e20047cf917eb9d56fdb17c195e5f896099f:/chanserv/chanservnetevents.c?ds=sidebyside diff --git a/chanserv/chanservnetevents.c b/chanserv/chanservnetevents.c index af52f64e..bed36d71 100644 --- a/chanserv/chanservnetevents.c +++ b/chanserv/chanservnetevents.c @@ -32,20 +32,12 @@ void cs_handlesethost(int hooknum, void *arg) { void cs_handlelostnick(int hooknum, void *arg) { nick *np=(nick *)arg; - nicklist **nlh; - nicklist *nlp; reguser *rup; if ((rup=getreguserfromnick(np))) { - for (nlh=&(rup->nicks);*nlh;nlh=&((*nlh)->next)) { - if ((*nlh)->np==np) { - nlp=*nlh; - *nlh=nlp->next; - freenicklist(nlp); - break; - } - } - if ((rup->status & QUSTAT_DEAD) && !rup->nicks) { + /* Clean up if this is the last user. auth->usercount is decremented + * AFTER the hook is sent... */ + if ((rup->status & QUSTAT_DEAD) && (np->auth->usercount==1)) { freereguser(rup); } } @@ -69,38 +61,8 @@ void cs_handlenewchannel(int hooknum, void *arg) { if ((rcp=(regchan *)cp->index->exts[chanservext])==NULL || CIsSuspended(rcp)) return; - /* - * If we're supposed to be joined, join ourselves.. - */ - - if (CIsJoined(rcp) && (chanservnick!=NULL)) { - chanservjoinchan(cp); - } - - /* This code interacts badly with bursts.. need to fix */ - -#if 0 - /* We need to watch out for people sneaking into +k/i channels.. - * This code relies on the fact that that user will already be in - * the channel at this point in time.. */ - if (rcp->forcemodes & (CHANMODE_KEY | CHANMODE_INVITEONLY)) { - /* OK, this channel is keyed.. let's find out if the user is allowed to be here */ - for (i=0;iusers->hashsize;i++) { - if (cp->users->content[i]!=nouser && (np=getnickbynumeric(cp->users->content[i]))) { - if (IsService(np)) - /* service (might even be us..) */ - continue; - - if ((rup=getreguserfromnick(np)) && (rcup=findreguseronchannel(rcp, rup)) && - CUKnown(rcup) && !CUIsBanned(rcup)) - /* legit user */ - continue; - - localkickuser(chanservnick, cp, np, "Private channel."); - } - } - } -#endif + /* chanservjoinchan() will deal with joining the channel and/or setting the timestamp */ + chanservjoinchan(cp); /* Make sure the right modes are set/cleared */ cs_checkchanmodes(cp); @@ -161,8 +123,9 @@ void cs_handlejoin(int hooknum, void *arg) { reguser *rup; regchanuser *rcup=NULL; chanindex *cip; - int iscreate; + int iscreate, isopped; int dowelcome=0; + unsigned long *lp; short modes=0; @@ -184,53 +147,72 @@ void cs_handlejoin(int hooknum, void *arg) { if (rup && (rup->status & QUSTAT_DEAD)) rup=NULL; - if (rup && (rcup=findreguseronchannel(rcp,rup)) && CUKnown(rcup) && cp->users->totalusers >= 3) + if (rup && (rcup=findreguseronchannel(rcp,rup)) && CUHasOpPriv(rcup) && cs_ischannelactive(cp, NULL)) rcp->lastactive=time(NULL); + + /* Update last use time */ + if (rcup) + rcup->usetime=getnettime(); if (rcp->lastcountersync < (time(NULL) - COUNTERSYNCINTERVAL)) { csdb_updatechannelcounters(rcp); rcp->lastcountersync=time(NULL); } + /* OK, this may be a CREATE but it's possible we have already bursted onto + * the channel and deopped them. So let's just check that out now. + * + * There's a distinction between "is it a create?" and "are they opped + * already?", since we need to send the generic "This is a Q9 channel" + * message on create even if we already deopped them. */ if (hooknum==HOOK_CHANNEL_CREATE) { iscreate=1; + if ((lp=getnumerichandlefromchanhash(cp->users, np->numeric)) && (*lp & CUMODE_OP)) + isopped=1; + else + isopped=0; } else { - iscreate=0; + isopped=iscreate=0; } - /* Check for "Q ban" */ - if (!IsService(np) && cs_bancheck(np,cp)) { - /* They got kicked.. */ - return; - } + /* Various things that can ban the user on join. Don't apply these to anyone + * with one of +k, +X, +o */ + if (!IsService(np) && !IsOper(np) && !IsXOper(np)) { + /* Check for "Q ban" */ + if (cs_bancheck(np,cp)) { + /* They got kicked.. */ + return; + } - /* Check for other ban lurking on channel which we are enforcing */ - if (!IsService(np) && CIsEnforce(rcp) && nickbanned(np,cp)) { - localkickuser(chanservnick,cp,np,"Banned."); - return; - } + /* Check for other ban lurking on channel which we are enforcing */ + if (CIsEnforce(rcp) && nickbanned(np,cp,1)) { + localkickuser(chanservnick,cp,np,"Banned."); + return; + } - /* Check for +b chanlev flag */ - if (!IsService(np) && rcup && CUIsBanned(rcup)) { - cs_banuser(NULL, cip, np, NULL); - cs_timerfunc(cip); - return; - } - - /* Check for +k chan flag */ - if (!IsService(np) && CIsKnownOnly(rcp) && !(rcup && CUKnown(rcup))) { - if (IsInviteOnly(cp) || (IsRegOnly(cp) && !IsAccount(np))) { - localkickuser(chanservnick,cp,np,"Authorised users only."); - } else { - cs_banuser(NULL, cip, np, "Authorised users only."); + /* Check for +b chanlev flag */ + if (rcup && CUIsBanned(rcup)) { + cs_banuser(NULL, cip, np, NULL); cs_timerfunc(cip); + return; + } + + /* Check for +k chan flag */ + if (CIsKnownOnly(rcp) && !(rcup && CUKnown(rcup))) { + /* Don't ban if they are already "visibly" banned for some reason. */ + if (IsInviteOnly(cp) || (IsRegOnly(cp) && !IsAccount(np))) { + localkickuser(chanservnick,cp,np,"Authorised users only."); + } else { + cs_banuser(NULL, cip, np, "Authorised users only."); + cs_timerfunc(cip); + } + return; } - return; } - + if (!rup || !rcup) { /* They're not a registered user, so deop if it is a create */ - if (iscreate && !IsService(np)) { + if (isopped && !IsService(np)) { modes |= MC_DEOP; } if (CIsVoiceAll(rcp)) { @@ -243,8 +225,6 @@ void cs_handlejoin(int hooknum, void *arg) { dowelcome=2; /* Send a generic warning */ } } else { - /* Update last use time */ - rcup->usetime=getnettime(); /* DB update removed for efficiency.. * csdb_updatelastjoin(rcup); */ @@ -253,12 +233,13 @@ void cs_handlejoin(int hooknum, void *arg) { if (CUIsOp(rcup) && (CIsAutoOp(rcp) || CUIsAutoOp(rcup) || CUIsProtect(rcup) || CIsProtect(rcp)) && !CUIsDeny(rcup)) { /* Auto op */ - if (!iscreate) { + if (!isopped) { modes |= MC_OP; + cs_logchanop(rcp, np->nick, rup); } } else { - /* Not auto op */ - if (iscreate && !CUIsOp(rcup) && !IsService(np)) { + /* Not auto op; deop them if they are opped and are not allowed them */ + if (isopped && !CUHasOpPriv(rcup) && !IsService(np)) { modes |= MC_DEOP; } @@ -293,11 +274,15 @@ void cs_handlejoin(int hooknum, void *arg) { break; } - if (rup && rcup && CIsInfo(rcp) && UIsInfo(rcup->user) && !CUIsHideInfo(rcup) && chanservnick) { - if (rcup->info) { + /* Display infoline if... (deep breath) user is registered, known on channel, + * user,channel,chanlev all +i and user,channel,chanlev all -s AND Q online */ + if (rup && rcup && + CIsInfo(rcp) && UIsInfo(rcup->user) && CUIsInfo(rcup) && + !CIsNoInfo(rcp) && !UIsNoInfo(rcup->user) && !CUIsNoInfo(rcup) && chanservnick) { + if (rcup->info && *(rcup->info->content)) { /* Chan-specific info */ sendmessagetochannel(chanservnick, cp, "[%s] %s",np->nick, rcup->info->content); - } else if (rup->info) { + } else if (rup->info && *(rup->info->content)) { /* Default info */ sendmessagetochannel(chanservnick, cp, "[%s] %s",np->nick, rup->info->content); } @@ -424,7 +409,7 @@ void cs_handlenewban(int hooknum, void *arg) { Error("chanserv",ERR_WARNING,"Found user on channel %s who doesn't exist!",cp->index->name->content); continue; } - if (!IsService(np) && nickmatchban(np,cbp)) { + if (!IsService(np) && nickmatchban(np,cbp,1)) { localkickuser(chanservnick,cp,np,"Banned."); } } @@ -445,10 +430,8 @@ void cs_handletopicchange(int hooknum, void *arg) { return; if (CIsForceTopic(rcp)) { - if (rcp->topic) { - /* Forced topic: change it back */ - localsettopic(chanservnick, cp, rcp->topic->content); - } + /* Forced topic: change it back even if blank */ + localsettopic(chanservnick, cp, (rcp->topic)?rcp->topic->content:""); } else if (CIsTopicSave(rcp)) { if (rcp->topic) { freesstring(rcp->topic); @@ -461,3 +444,48 @@ void cs_handletopicchange(int hooknum, void *arg) { csdb_updatetopic(rcp); } } + +/* + * active is defined as at least 2 real users (no snailbot) currently present + * and at least one op/master/owner. + * this is O(n) worst case, but very very likely to just be 2 checks. + */ +int cs_ischannelactive(channel *cp, regchan *rcp) { + int real_users = 0; + int seen_op = 0; + nick *np; + int i; + + for (i=0;iusers->hashsize;i++) { + if(cp->users->content[i]==nouser) + continue; + + if((np=getnickbynumeric(cp->users->content[i]))==NULL) + continue; + + if(NickOnServiceServer(np)) /* bad snailbot */ + continue; + + real_users++; + + if(rcp && !seen_op) { /* only look for ops if we haven't seen one yet */ + reguser *rup = getreguserfromnick(np); /* O(1) */ + if(rup) { + regchanuser *rcup = findreguseronchannel(rcp, rup); /* O(1) */ + if(rcup && CUHasOpPriv(rcup)) + seen_op = 1; + } + } + + /* so once we've seen X real users AND: + * - we're not looking for ops as a check had already been done by the caller + * - OR we're looking for ops AND we found them + * then the channel is active, and we're done + */ + if((real_users >= CLEANUP_MIN_CHAN_SIZE) && (!rcp || (rcp && seen_op))) + return 1; + } + + return 0; +} +