csuser=getcopyconfigitem("chanserv","user","TheQBot",USERLEN);
cshost=getcopyconfigitem("chanserv","host","some.host",HOSTLEN);
csrealname=getcopyconfigitem("chanserv","realname","ChannelService",REALLEN);
- csaccount=getcopyconfigitem("chanserv","account",csnick&&csnick->content&&csnick->content[0]?csnick->content:"Q",ACCOUNTLEN);
+ csaccount=getcopyconfigitem("chanserv","account",csnick&&csnick->content[0]?csnick->content:"Q",ACCOUNTLEN);
Error("chanserv",ERR_INFO,"Connecting %s...",csnick->content);
}
cmd=findcommandintree(csctcpcommands, cargv[0]+1, 1);
if (cmd) {
+ cmd->calls++;
rejoinline(cargv[1],cargc-1);
cmd->handler((void *)sender, cargc-1, &(cargv[1]));
}
break;
}
+ if ((cmd->level & QCMD_ACHIEVEMENTS) && !UIsDev(rup) &&
+ ((time(NULL) < ACHIEVEMENTS_START) ||
+ ((time(NULL) > ACHIEVEMENTS_END) && !UIsAchievements(rup)))) {
+ chanservstdmessage(sender, QM_UNKNOWNCMD, cargv[0]);
+ break;
+ }
+
+ if ((cmd->level & QCMD_TITLES) && !UIsDev(rup) &&
+ ((time(NULL) < ACHIEVEMENTS_START) ||
+ (time(NULL) > ACHIEVEMENTS_END))) {
+ chanservstdmessage(sender, QM_UNKNOWNCMD, cargv[0]);
+ break;
+ }
+
+ cmd->calls++;
+
if (cmd->maxparams < (cargc-1)) {
rejoinline(cargv[cmd->maxparams],cargc-(cmd->maxparams));
cargc=(cmd->maxparams)+1;
}
cmd->handler((void *)sender, cargc-1, &(cargv[1]));
+
+ triggerhook(HOOK_CHANSERV_CMD, sender);
}
break;
deletecommandfromtree(cscommands, command, handler);
}
+void chanservpartchan(channel *cp, char *reason) {
+ /* Sanity check that we exist and are on the channel.
+ *
+ * Note that we don't do any of the other usual sanity checks here; if
+ * this channel is unregged or suspended or whatever then all the more
+ * reason to get Q off it ASAP! */
+ if (!chanservnick || !cp || !cp->users || !getnumerichandlefromchanhash(cp->users, chanservnick->numeric))
+ return;
+
+ localpartchannel(chanservnick, cp, reason);
+}
+
void chanservjoinchan(channel *cp) {
regchan *rcp;
unsigned int i;
if (!chanservnick)
return;
+ /* In gerenal this function shouldn't be used any more as a reason to get
+ * Q to leave, but if it should be leaving then just part with no reason. */
if ((CIsSuspended(rcp) || !CIsJoined(rcp)) && getnumerichandlefromchanhash(cp->users, chanservnick->numeric)) {
- if(rcp->suspendreason) {
- char buf[512];
- snprintf(buf, sizeof(buf), "Channel suspended: %s", rcp->suspendreason->content);
- localpartchannel(chanservnick, cp, buf);
- } else {
- localpartchannel(chanservnick, cp, "Channel suspended");
- }
+ localpartchannel(chanservnick, cp, NULL);
}
/* Right, we are definately going to either join the channel or at least
}
}
-void chanservstdmessage(nick *np, int messageid, ... ) {
+static void __chanservstdvmessage(nick *np, reguser *rup, int messageid, int max_line_len, void (*callback)(nick *, char *), ...) {
+ va_list va;
+ va_start(va, callback);
+ chanservstdvmessage(np, rup, messageid, max_line_len, callback, va);
+ va_end(va);
+}
+
+void chanservstdvmessage(nick *np, reguser *rup, int messageid, int max_line_len, void (*callback)(nick *, char *), va_list va) {
char buf[5010];
char buf2[512];
- int notice;
- reguser *rup;
int language;
- va_list va, va2;
+ va_list va2;
char *message, *messageargs;
char *bp2,*bp;
int len;
- if (getreguserfromnick(np) == NULL) {
- notice=1;
+ if(max_line_len <= 0)
+ max_line_len = 490 + max_line_len;
+
+ if (rup == NULL) {
language=0;
} else {
- rup=getreguserfromnick(np);
- if(UIsNotice(rup)) {
- notice=1;
- } else {
- notice=0;
- }
language=rup->languageid;
}
messageargs=defaultmessages[messageid*2+1];
- va_start(va,messageid);
va_copy(va2, va);
q9vsnprintf(buf,5000,message,messageargs,va);
- va_end(va);
len=0;
bp2=buf2;
for (bp=buf; ;bp++) {
/* We send something if we hit a \n, fill the buffer or run out of source */
- if (*bp=='\n' || len>490 || !*bp) {
+ if (*bp=='\n' || len>max_line_len || !*bp) {
if (*bp && *bp!='\n') {
bp--;
}
*bp2='\0';
- if (chanservnick && *buf2) {
- if (notice) {
- sendnoticetouser(chanservnick,np,"%s",buf2);
- } else {
- sendmessagetouser(chanservnick,np,"%s",buf2);
- }
- }
+ if (chanservnick && *buf2)
+ callback(np, buf2);
/* If we ran out of buffer, get out here */
if (!*bp)
if (messageid==QM_NOTENOUGHPARAMS) {
char *command=va_arg(va2, char *);
cs_sendhelp(np, command, 1);
- chanservstdmessage(np, QM_TYPEHELPFORHELP, command);
+ __chanservstdvmessage(np, rup, QM_TYPEHELPFORHELP, max_line_len, callback, command);
}
va_end(va2);
}
+static void message_callback(nick *np, char *buf) {
+ sendmessagetouser(chanservnick,np,"%s",buf);
+}
+
+static void notice_callback(nick *np, char *buf) {
+ sendnoticetouser(chanservnick,np,"%s",buf);
+}
+
+void chanservstdmessage(nick *np, int messageid, ...) {
+ reguser *rup;
+ va_list va;
+ int notice;
+
+ rup = getreguserfromnick(np);
+ notice = rup == NULL ? 1 : UIsNotice(rup);
+
+ va_start(va, messageid);
+ chanservstdvmessage(np, rup, messageid, 0, notice ? notice_callback : message_callback, va);
+ va_end(va);
+}
+
void chanservsendmessage_real(nick *np, int oneline, char *message, ... ) {
char buf[5010]; /* Very large buffer.. */
char buf2[512], *bp, *bp2;
va_start(va, messageid);
q9vsnprintf(buf, 511, message, messageargs, va);
va_end(va);
- killuser(chanservnick, target, buf);
+ killuser(chanservnick, target, "%s", buf);
}
int checkpassword(reguser *rup, const char *pass) {
if ((lp=getnumerichandlefromchanhash(rcup->chan->index->channel->users, np->numeric))) {
/* User is on channel.. */
- if (CUKnown(rcup) && rcup->chan->index->channel->users->totalusers >= 3) {
+ /* Update last use time. Do early in case of ban. */
+ rcup->usetime=getnettime();
+
+ if (CUIsBanned(rcup)) {
+ cs_banuser(NULL, rcup->chan->index, np, NULL);
+ continue;
+ }
+
+ if (CUHasOpPriv(rcup) && cs_ischannelactive(rcup->chan->index->channel, NULL)) {
/* This meets the channel use criteria, update. */
rcup->chan->lastactive=time(NULL);
}
}
- /* Update last use time */
- rcup->usetime=getnettime();
-
localsetmodeinit(&changes, rcup->chan->index->channel, chanservnick);
if (*lp & CUMODE_OP) {
if (!IsService(np) && (CUIsDeny(rcup) || (CIsBitch(rcup->chan) && !CUHasOpPriv(rcup))))
} else {
/* Channel exists but user is not joined: invite if they are +j-b */
if (CUIsAutoInvite(rcup) && CUKnown(rcup) && !CUIsBanned(rcup)) {
- localinvite(chanservnick, rcup->chan->index->channel, np);
+ localinvite(chanservnick, rcup->chan->index, np);
}
}
- }
- }
+ } /* if (rcup->chan->index->channel) */ else {
+ /* Channel doesn't currently exist - send invite anyway for +j */
+ if (CUIsAutoInvite(rcup) && CUKnown(rcup) && !CUIsBanned(rcup)) {
+ localinvite(chanservnick, rcup->chan->index, np);
+ }
+ }
+ } /* for */
}
void cs_checknickbans(nick *np) {
for (j=0;j<i;j++) {
if ((rcp=ca[j]->index->exts[chanservext]) && !CIsSuspended(rcp) &&
- CIsEnforce(rcp) && nickbanned_visible(np, ca[j]))
+ CIsEnforce(rcp) && nickbanned(np, ca[j], 1))
localkickuser(chanservnick, ca[j], np, "Banned.");
}
for (rbp=rcp->bans;rbp;rbp=rbp->next) {
if (((!rbp->expiry) || (rbp->expiry <= now)) &&
- nickmatchban_visible(np, rbp->cbp)) {
- if (!nickbanned_visible(np, cp)) {
+ nickmatchban(np, rbp->cbp, 1)) {
+ if (!nickbanned(np, cp, 1)) {
localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_ADD);
}
localkickuser(chanservnick,cp,np,rbp->reason?rbp->reason->content:"Banned.");
if (CIsEnforce(rcp)) {
for (cbp=cp->bans;cbp;cbp=cbp->next) {
- if ((cbp->timeset>=rcp->lastbancheck) && nickmatchban_visible(np, cbp))
+ if ((cbp->timeset>=rcp->lastbancheck) && nickmatchban(np, cbp, 1))
localkickuser(chanservnick,cp,np,"Banned.");
}
rcp->lastbancheck=time(NULL);
localsetmodeflush(&changes, 1);
}
-void cs_removechannel(regchan *rcp) {
+void cs_removechannel(regchan *rcp, char *reason) {
int i;
chanindex *cip;
regchanuser *rcup, *nrcup;
deleteschedule(rcp->checksched, cs_timerfunc, rcp->index);
if (cip->channel) {
- rcp->flags=QCFLAG_SUSPENDED;
- chanservjoinchan(cip->channel); /* Force off the channel */
+ chanservpartchan(cip->channel, reason);
}
csdb_deletechannel(rcp);
return 0;
}
}
-
+
+ /*
+ * don't cleanup the last channel to prevent channel id reuse.
+ * the channel will be orphaned but will be cleaned up by cleanup eventually
+ */
+ if(rcp->ID == lastchannelID) {
+ cs_log(sender,"DELCHAN FAILED %s (last id)",rcp->index->name->content);
+ return 0;
+ }
+
cs_log(sender,"DELCHAN %s (Empty)",rcp->index->name->content);
- cs_removechannel(rcp);
+ cs_removechannel(rcp, "Last user removed - channel deleted.");
return 1;
}
freesstring(rbp->reason);
freechanban(rbp->cbp);
freeregban(rbp);
- } else if (nickmatchban_visible(np,(*rbh)->cbp)) {
+ } else if (nickmatchban(np,(*rbh)->cbp,1)) {
/* This user matches this ban.. */
- if (!nickbanned_visible(np,cp)) {
+ if (!nickbanned(np,cp,1)) {
/* Only bother putting the ban on the channel if they're not banned already */
/* (might be covered by this ban or a different one.. doesn't really matter */
localsetmodeinit(&changes, cp, chanservnick);
if (cip->channel->users->content[i]!=nouser &&
(np=getnickbynumeric(cip->channel->users->content[i])) &&
!IsService(np) && !IsOper(np) && !IsXOper(np) &&
- nickmatchban_visible(np, rbp->cbp))
+ nickmatchban(np, rbp->cbp, 1))
localkickuser(chanservnick, cip->channel, np, rbp->reason ? rbp->reason->content : "Banned.");
}
if (!cip->channel)
return;
- if (nickbanned_visible(np, cip->channel)) {
+ if (nickbanned(np, cip->channel, 1)) {
localkickuser(chanservnick, cip->channel, np, reason?reason:"Banned.");
return;
}
*
* Return 0 if it works, 1 if it don't.
*/
-int cs_unbanfn(nick *sender, chanindex *cip, UnbanFN fn, void *arg, int removepermbans, int abortonfailure) {
+int cs_unbanfn(nick *sender, chanindex *cip, int (*fn)(void *arg, struct chanban *ban), void *arg, int removepermbans, int abortonfailure) {
regban **rbh, *rbp;
chanban **cbh, *cbp;
regchan *rcp;
return 1;
}
+
+regchan *cs_addchan(chanindex *cip, nick *sender, reguser *addedby, reguser *founder, flag_t flags, flag_t forcemodes, flag_t denymodes, short type) {
+ regchan *rcp;
+ regchanuser *rcup;
+ void *args[3];
+ int i;
+
+ if (cip->exts[chanservext])
+ return NULL;
+
+ /* Initialise the channel */
+ rcp=getregchan();
+
+ /* ID, index */
+ rcp->ID=++lastchannelID;
+ rcp->index=cip;
+ cip->exts[chanservext]=rcp;
+
+ rcp->chantype=type;
+ rcp->flags=flags;
+ rcp->status=0;
+ rcp->bans=NULL;
+ rcp->lastcountersync=0;
+
+ rcp->limit=0;
+ rcp->forcemodes=forcemodes;
+ rcp->denymodes=denymodes;
+
+ if (CIsAutoLimit(rcp)) {
+ rcp->forcemodes |= CHANMODE_LIMIT;
+ }
+
+ rcp->autolimit=5;
+ rcp->banstyle=0;
+
+ rcp->created=rcp->lastactive=rcp->statsreset=rcp->ostatsreset=time(NULL);
+ rcp->banduration=0;
+ rcp->autoupdate=0;
+ rcp->lastbancheck=0;
+
+ /* Added by */
+ rcp->addedby=addedby->ID;
+
+ /* Founder */
+ rcp->founder=founder->ID;
+
+ /* Suspend by */
+ rcp->suspendby=0;
+ rcp->suspendtime=0;
+
+ rcp->totaljoins=rcp->tripjoins=rcp->otripjoins=rcp->maxusers=rcp->tripusers=rcp->otripusers=0;
+ rcp->welcome=rcp->topic=rcp->key=rcp->suspendreason=rcp->comment=NULL;
+
+ /* Users */
+ memset(rcp->regusers,0,REGCHANUSERHASHSIZE*sizeof(reguser *));
+
+ rcp->checksched=NULL;
+ rcp->ltimestamp=0;
+ for (i=0;i<CHANOPHISTORY;i++) {
+ rcp->chanopnicks[i][0]='\0';
+ rcp->chanopaccts[i]=0;
+ }
+ rcp->chanoppos=0;
+
+ /* Add new channel to db.. */
+ csdb_createchannel(rcp);
+
+ /* Add the founder as +ano */
+ rcup=getregchanuser();
+ rcup->chan=rcp;
+ rcup->user=founder;
+ rcup->flags=(QCUFLAG_OWNER | QCUFLAG_OP | QCUFLAG_AUTOOP);
+ rcup->usetime=0;
+ rcup->info=NULL;
+ rcup->changetime=time(NULL);
+
+ addregusertochannel(rcup);
+ csdb_createchanuser(rcup);
+ csdb_chanlevhistory_insert(rcp, sender, rcup->user, 0, rcup->flags);
+
+ args[0]=sender;
+ args[1]=rcup;
+ args[2]=(void *)0;
+
+ triggerhook(HOOK_CHANSERV_CHANLEVMOD, args);
+
+ /* If the channel exists, get the ball rolling */
+ if (cip->channel) {
+ chanservjoinchan(cip->channel);
+ rcp->status |= QCSTAT_MODECHECK | QCSTAT_OPCHECK | QCSTAT_BANCHECK;
+ cs_timerfunc(cip);
+ }
+
+ return rcp;
+}