X-Git-Url: https://jfr.im/git/irc/quakenet/newserv.git/blobdiff_plain/1bb4c08e90274c34eb03720fb0eda246e2dc0c86..78fdeaf6a300fd4b0a7a06987f712a3ecdd104d3:/chanserv/chanservuser.c diff --git a/chanserv/chanservuser.c b/chanserv/chanservuser.c index b21b6fec..04280500 100644 --- a/chanserv/chanservuser.c +++ b/chanserv/chanservuser.c @@ -40,7 +40,7 @@ void chanservreguser(void *arg) { 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); @@ -111,6 +111,7 @@ void chanservuserhandler(nick *target, int message, void **params) { } cmd=findcommandintree(csctcpcommands, cargv[0]+1, 1); if (cmd) { + cmd->calls++; rejoinline(cargv[1],cargc-1); cmd->handler((void *)sender, cargc-1, &(cargv[1])); } @@ -143,6 +144,12 @@ void chanservuserhandler(nick *target, int message, void **params) { break; } + if ((cmd->level & QCMD_STAFF) && + (!(rup=getreguserfromnick(sender)) || !UHasStaffPriv(rup))) { + chanservstdmessage(sender, QM_NOACCESS, cargv[0]); + break; + } + if ((cmd->level & QCMD_HELPER) && (!(rup=getreguserfromnick(sender)) || !UHasHelperPriv(rup))) { chanservstdmessage(sender, QM_NOACCESS, cargv[0]); @@ -167,12 +174,30 @@ void chanservuserhandler(nick *target, int message, void **params) { 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; @@ -237,6 +262,18 @@ void chanservremovecommand(char *command, CommandHandler handler) { 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; @@ -259,12 +296,10 @@ void chanservjoinchan(channel *cp) { 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) { - localpartchannel(chanservnick, cp, rcp->suspendreason->content); - } else { - localpartchannel(chanservnick, cp, NULL); - } + localpartchannel(chanservnick, cp, NULL); } /* Right, we are definately going to either join the channel or at least @@ -461,16 +496,23 @@ void chanservwallmessage(char *message, ... ) { va_list va; nick *np; unsigned int i=0; - + va_start(va,message); vsnprintf(buf,5000,message,va); va_end(va); /* Scan for users */ - for (i=0;inext) - if (IsOper(np)) - chanservsendmessage(np, "%s", buf); + for (i=0;inext) { + if (!IsOper(np)) /* optimisation, if VIEWWALLMESSAGE changes change this */ + continue; + + if (!cs_privcheck(QPRIV_VIEWWALLMESSAGE, np)) + continue; + + chanservsendmessage(np, "%s", buf); + } + } } void chanservkillstdmessage(nick *target, int messageid, ... ) { @@ -496,7 +538,7 @@ void chanservkillstdmessage(nick *target, int messageid, ... ) { 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) { @@ -580,6 +622,7 @@ void cs_checknick(nick *np) { rup->created=time(NULL); rup->lastauth=0; rup->lastemailchange=0; + rup->lastpasschange=0; rup->flags=QUFLAG_NOTICE; rup->languageid=0; rup->suspendby=0; @@ -673,7 +716,7 @@ void cs_docheckopvoice(channel *cp, modechanges *changes) { continue; if ((np=getnickbynumeric(cp->users->content[i]))==NULL) { - Error("chanserv",ERR_ERROR,"Found non-existent numeric %d on channel %s",cp->users->content[i], + Error("chanserv",ERR_ERROR,"Found non-existent numeric %lu on channel %s",cp->users->content[i], cp->index->name->content); continue; } @@ -741,7 +784,15 @@ void cs_doallautomodes(nick *np) { 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); @@ -752,9 +803,6 @@ void cs_doallautomodes(nick *np) { } } - /* 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)))) @@ -779,11 +827,16 @@ void cs_doallautomodes(nick *np) { } 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) { @@ -801,7 +854,7 @@ void cs_checknickbans(nick *np) { for (j=0;jindex->exts[chanservext]) && !CIsSuspended(rcp) && - CIsEnforce(rcp) && nickbanned_visible(np, ca[j])) + CIsEnforce(rcp) && nickbanned(np, ca[j], 1)) localkickuser(chanservnick, ca[j], np, "Banned."); } @@ -832,7 +885,7 @@ void cs_checkbans(channel *cp) { continue; if ((np=getnickbynumeric(cp->users->content[i]))==NULL) { - Error("chanserv",ERR_ERROR,"Found numeric %d on channel %s who doesn't exist.", + Error("chanserv",ERR_ERROR,"Found numeric %lu on channel %s who doesn't exist.", cp->users->content[i], cp->index->name->content); continue; } @@ -842,8 +895,8 @@ void cs_checkbans(channel *cp) { 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."); @@ -856,7 +909,7 @@ void cs_checkbans(channel *cp) { 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); @@ -1021,7 +1074,7 @@ void cs_timerfunc(void *arg) { localsetmodeflush(&changes, 1); } -void cs_removechannel(regchan *rcp) { +void cs_removechannel(regchan *rcp, char *reason) { int i; chanindex *cip; regchanuser *rcup, *nrcup; @@ -1050,8 +1103,7 @@ void cs_removechannel(regchan *rcp) { 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); @@ -1079,9 +1131,18 @@ int cs_removechannelifempty(nick *sender, regchan *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; } @@ -1140,9 +1201,9 @@ int cs_bancheck(nick *np, channel *cp) { 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); @@ -1176,7 +1237,7 @@ void cs_setregban(chanindex *cip, regban *rbp) { 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."); } @@ -1190,7 +1251,7 @@ void cs_banuser(modechanges *changes, chanindex *cip, nick *np, const char *reas 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; } @@ -1284,7 +1345,7 @@ reguser *findreguser(nick *sender, const char *str) { } if (!(rup=findreguserbynick(str+1)) && sender) chanservstdmessage(sender, QM_UNKNOWNUSER, str); - } else if (*str=='&' && vrup && UHasHelperPriv(vrup)) { + } else if (*str=='&' && vrup && UHasStaffPriv(vrup)) { if (str[1]=='\0') { if (sender) chanservstdmessage(sender, QM_UNKNOWNUSER, str); @@ -1316,7 +1377,7 @@ reguser *findreguser(nick *sender, const char *str) { * * 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; @@ -1383,3 +1444,107 @@ void cs_logchanop(regchan *rcp, char *nick, reguser *rup) { rcp->chanopaccts[rcp->chanoppos]=rup->ID; rcp->chanoppos=(rcp->chanoppos+1)%CHANOPHISTORY; } + +int checkreason(nick *np, char *reason) { + if((strlen(reason) < MIN_REASONLEN) || !strchr(reason, ' ')) { + chanservstdmessage(np, QM_REASONREQUIRED); + return 0; + } + + 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;ichanopnicks[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; +}