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);
}
}
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;i<cp->users->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);
reguser *rup;
regchanuser *rcup=NULL;
chanindex *cip;
- int iscreate;
+ int iscreate, isopped;
int dowelcome=0;
+ unsigned long *lp;
short modes=0;
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)) {
dowelcome=2; /* Send a generic warning */
}
} else {
- /* Update last use time */
- rcup->usetime=getnettime();
/* DB update removed for efficiency..
* csdb_updatelastjoin(rcup); */
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;
}
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);
}
void cs_handlemodechange(int hooknum, void *arg) {
void **arglist=(void **)arg;
channel *cp=(channel *)arglist[0];
- int changeflags=(int)arglist[2];
+ long changeflags=(long)arglist[2];
regchan *rcp;
if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
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.");
}
}
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);
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;i<cp->users->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;
+}
+