nick *victim;
channel *cp;
- if (cargc<1) {
- controlreply(sender,"Usage: carrot channel and/or user");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
if ((victim=getnickbynick(cargv[0]))!=NULL) {
controlreply(victim,"%cACTION ger %s en morot%c",1,victim->nick,1);
controlreply(sender,"Used carrot in %s.",cp->index->name->content);
} else {
controlreply(sender,"Couldn't find %s.",cargv[0]);
- return;
}
return CMD_OK;
}
void _init() {
- registercontrolcmd("carrot",10,2,ca_carrot);
+ registercontrolhelpcmd("carrot",NO_OPERED,2,ca_carrot,"Usage: carrot <#channel|user> ?user?");
}
void _fini() {
regchansearchdisp("topic", cs_desctopic);
regchansearchdisp("services", cs_descservices);
- registercontrolcmd("chansearch",10,19,&dochansearch);
+ registercontrolhelpcmd("chansearch",NO_OPER,19,&dochansearch,"Usage: chansearch <criteria>\nSearches for channels with specified criteria.\nSend chanstats with no arguments for more information.");
}
void _fini() {
regchansearchfunc("moderated", 0, cs_moderated);
regchansearchfunc("modes", 1, cs_modes);
- registercontrolcmd("chansearch",10,19,&dochansearch);
+ registercontrolhelpcmd("chansearch",NO_OPER,19,&dochansearch,
+ "Usage: chansearch <search terms>\n"
+ " Valid search terms are: name, exists, size, nick, namelen, keyed, secret, invite\n"
+ " Terms can be inverted with !");
}
void finichansearch() {
int offset;
int res;
- if (cargc<1) {
- controlreply(sender,"Usage: chansearch (search terms)");
- controlreply(sender," Valid search terms are: name, exists, size, nick, namelen, keyed, secret, invite");
- controlreply(sender," Terms can be inverted with !");
- return CMD_OK;
- }
+ if (cargc<1)
+ return CMD_USAGE;
for (i=0;i<cargc;) {
if (cargv[i][0]=='!') {
#include <string.h>
#include <stdarg.h>
-nick *mynick;
+nick *hooknick;
-nick *statsnick;
+nick *mynick;
-CommandTree *controlcmds;
+CommandTree *controlcmds;
+ControlMsg controlreply;
+ControlWall controlwall;
void handlemessages(nick *target, int messagetype, void **args);
int controlstatus(void *sender, int cargc, char **cargv);
int relink(void *sender, int cargc, char **cargv);
int die(void *sender, int cargc, char **cargv);
int controlinsmod(void *sender, int cargc, char **cargv);
-int controlrmmod(void *sender, int cargc, char **cargv);
int controllsmod(void *sender, int cargc, char **cargv);
int controlrehash(void *sender, int cargc, char **cargv);
-int controlshowcommands(void *sender, int cargc, char **cargv);
int controlreload(void *sender, int cargc, char **cargv);
+int controlhelpcmd(void *sender, int cargc, char **cargv);
+void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...);
void _init() {
controlcmds=newcommandtree();
-
- addcommandtotree(controlcmds,"status",10,1,&controlstatus);
- addcommandtotree(controlcmds,"whois",10,1,&controlwhois);
- addcommandtotree(controlcmds,"channel",10,1,&controlchannel);
- addcommandtotree(controlcmds,"relink",10,1,&relink);
- addcommandtotree(controlcmds,"die",10,1,&die);
- addcommandtotree(controlcmds,"insmod",10,1,&controlinsmod);
- addcommandtotree(controlcmds,"rmmod",10,1,&controlrmmod);
- addcommandtotree(controlcmds,"lsmod",10,1,&controllsmod);
- addcommandtotree(controlcmds,"rehash",10,1,&controlrehash);
- addcommandtotree(controlcmds,"showcommands",10,0,&controlshowcommands);
- addcommandtotree(controlcmds,"reload",10,1,&controlreload);
+ controlreply=&controlmessage;
+ controlwall=&controlnoticeopers;
+
+ registercontrolhelpcmd("status",NO_DEVELOPER,1,&controlstatus,"Usage: status ?level?\nDisplays status information, increasing level gives more verbose information.");
+ registercontrolhelpcmd("whois",NO_OPERED,1,&controlwhois,"Usage: whois <nickname|#numeric>\nDisplays lots of information about the specified nickname or numeric.");
+ registercontrolhelpcmd("channel",NO_OPER,1,&controlchannel,"Usage: channel <#channel>\nDisplays channel information.");
+ registercontrolhelpcmd("relink",NO_DEVELOPER,1,&relink,"Usage: relink\nRelinks service to the network.");
+ registercontrolhelpcmd("die",NO_DEVELOPER,1,&die,"Usage: die <reason>\nTerminates the service.");
+ registercontrolhelpcmd("insmod",NO_DEVELOPER,1,&controlinsmod,"Usage: insmod <module>\nAdds a module to the running instance.");
+ registercontrolhelpcmd("rmmod",NO_DEVELOPER,1,&controlrmmod,"Usage: rmmod <module>\nRemoves a module from the running instance.");
+ registercontrolhelpcmd("lsmod",NO_DEVELOPER,0,&controllsmod,"Usage: lsmod\nLists currently running modules.");
+ registercontrolhelpcmd("rehash",NO_DEVELOPER,1,&controlrehash,"Usage: rehash\nReloads configuration file.");
+ registercontrolhelpcmd("showcommands",NO_ACCOUNT,0,&controlshowcommands,"Usage: showcommands\nShows all registered commands.");
+ registercontrolhelpcmd("reload",NO_DEVELOPER,1,&controlreload,"Usage: reload <module>\nReloads specified module.");
+ registercontrolhelpcmd("help",NO_ANYONE,1,&controlhelpcmd,"Usage: help <command>\nShows help for specified command.");
scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
}
-void registercontrolcmd(const char *name, int level, int maxparams, CommandHandler handler) {
- addcommandtotree(controlcmds,name,level,maxparams,handler);
+void registercontrolhelpcmd(const char *name, int level, int maxparams, CommandHandler handler, char *help) {
+ addcommandhelptotree(controlcmds,name,level,maxparams,handler,help);
}
int deregistercontrolcmd(const char *name, CommandHandler handler) {
myauthname=getcopyconfigitem("control","authname","C",ACCOUNTLEN);
mynick=registerlocaluser(cnick->content,myident->content,myhost->content,myrealname->content,myauthname->content,UMODE_SERVICE|UMODE_DEAF|UMODE_OPER|UMODE_ACCOUNT,&handlemessages);
+ triggerhook(HOOK_CONTROL_REGISTERED, mynick);
cp=findchannel("#twilightzone");
if (!cp) {
localcreatechannel(mynick,"#twilightzone");
}
void handlestats(int hooknum, void *arg) {
- sendmessagetouser(mynick,statsnick,"%s",(char *)arg);
+ controlreply(hooknick,"%s",(char *)arg);
}
int controlstatus(void *sender, int cargc, char **cargv) {
unsigned int level=5;
- statsnick=(nick *)sender;
+ hooknick=(nick *)sender;
if (cargc>0) {
level=strtoul(cargv[0],NULL,10);
triggerhook(HOOK_CORE_REHASH,(void *)0);
return CMD_OK;
}
-
+
+void handlewhois(int hooknum, void *arg) {
+ controlreply(hooknick,"%s",(char *)arg);
+}
+
int controlwhois(void *sender, int cargc, char **cargv) {
nick *target;
channel **channels;
char buf[BUFSIZE];
int i;
- if (cargc<1) {
- sendmessagetouser(mynick,(nick *)sender,"Usage: whois <user>");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
if (cargv[0][0]=='#') {
if (!(target=getnickbynumericstr(cargv[0]+1))) {
- sendmessagetouser(mynick,sender,"Sorry, couldn't find numeric %s",cargv[0]+1);
+ controlreply(sender,"Sorry, couldn't find numeric %s",cargv[0]+1);
return CMD_ERROR;
}
} else {
if ((target=getnickbynick(cargv[0]))==NULL) {
- sendmessagetouser(mynick,(nick *)sender,"Sorry, couldn't find that user");
+ controlreply((nick *)sender,"Sorry, couldn't find that user");
return CMD_ERROR;
}
}
- sendmessagetouser(mynick,(nick *)sender,"Nick : %s",target->nick);
- sendmessagetouser(mynick,(nick *)sender,"Numeric : %s",longtonumeric(target->numeric,5));
- sendmessagetouser(mynick,(nick *)sender,"User@Host : %s@%s (%d user(s) on this host)",target->ident,target->host->name->content,target->host->clonecount);
+ controlreply((nick *)sender,"Nick : %s",target->nick);
+ controlreply((nick *)sender,"Numeric : %s",longtonumeric(target->numeric,5));
+ controlreply((nick *)sender,"User@Host : %s@%s (%d user(s) on this host)",target->ident,target->host->name->content,target->host->clonecount);
if (IsSetHost(target)) {
if (target->shident) {
- sendmessagetouser(mynick,(nick *)sender,"Fakehost : %s@%s",target->shident->content, target->sethost->content);
+ controlreply((nick *)sender,"Fakehost : %s@%s",target->shident->content, target->sethost->content);
} else {
- sendmessagetouser(mynick,(nick *)sender,"Fakehost : %s",target->sethost->content);
+ controlreply((nick *)sender,"Fakehost : %s",target->sethost->content);
}
}
- sendmessagetouser(mynick,(nick *)sender,"Timestamp : %lu",target->timestamp);
- sendmessagetouser(mynick,(nick *)sender,"IP address: %d.%d.%d.%d",(target->ipaddress)>>24,(target->ipaddress>>16)&255, (target->ipaddress>>8)&255,target->ipaddress&255);
- sendmessagetouser(mynick,(nick *)sender,"Realname : %s (%d user(s) have this realname)",target->realname->name->content,target->realname->usercount);
+ controlreply((nick *)sender,"Timestamp : %lu",target->timestamp);
+ controlreply((nick *)sender,"IP address: %d.%d.%d.%d",(target->ipaddress)>>24,(target->ipaddress>>16)&255, (target->ipaddress>>8)&255,target->ipaddress&255);
+ controlreply((nick *)sender,"Realname : %s (%d user(s) have this realname)",target->realname->name->content,target->realname->usercount);
if (target->umodes) {
- sendmessagetouser(mynick,(nick *)sender,"Umode(s) : %s",printflags(target->umodes,umodeflags));
+ controlreply((nick *)sender,"Umode(s) : %s",printflags(target->umodes,umodeflags));
}
if (IsAccount(target)) {
- sendmessagetouser(mynick,(nick *)sender,"Account : %s",target->authname);
+ controlreply((nick *)sender,"Account : %s",target->authname);
if (target->accountts)
- sendmessagetouser(mynick,(nick *)sender,"AccountTS : %ld",target->accountts);
+ controlreply((nick *)sender,"AccountTS : %ld",target->accountts);
}
+
+ hooknick=(nick *)sender;
+ registerhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
+ triggerhook(HOOK_CONTROL_WHOISREQUEST,target);
+ deregisterhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
+
if (target->channels->cursi==0) {
- sendmessagetouser(mynick,(nick *)sender,"Channels : none");
+ controlreply((nick *)sender,"Channels : none");
} else if (target->channels->cursi>50) {
- sendmessagetouser(mynick,(nick *)sender,"Channels : - (total: %d)",target->channels->cursi);
+ controlreply((nick *)sender,"Channels : - (total: %d)",target->channels->cursi);
} else {
buf[0]='\0';
channels=(channel **)target->channels->content;
if (strlen(buf)==0) {
break;
} else {
- sendmessagetouser(mynick,(nick *)sender,"Channels : %s",buf);
+ controlreply((nick *)sender,"Channels : %s",buf);
buf[0]='\0';
i--;
}
}
int controlinsmod(void *sender, int cargc, char **cargv) {
- if (cargc<1) {
- sendmessagetouser(mynick,(nick *)sender,"Usage: insmod <modulename>");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
switch(insmod(cargv[0])) {
case -1:
- sendmessagetouser(mynick,(nick *)sender,"Unable to load module %s",cargv[0]);
+ controlreply((nick *)sender,"Unable to load module %s",cargv[0]);
return CMD_ERROR;
case 1:
- sendmessagetouser(mynick,(nick *)sender,"Module %s already loaded, or name not valid",cargv[0]);
+ controlreply((nick *)sender,"Module %s already loaded, or name not valid",cargv[0]);
return CMD_ERROR;
case 0:
- sendmessagetouser(mynick,(nick *)sender,"Module %s loaded.",cargv[0]);
+ controlreply((nick *)sender,"Module %s loaded.",cargv[0]);
return CMD_OK;
default:
- sendmessagetouser(mynick,(nick *)sender,"An unknown error occured.");
+ controlreply((nick *)sender,"An unknown error occured.");
return CMD_ERROR;
}
}
int controlrmmod(void *sender, int cargc, char **cargv) {
- if (cargc<1) {
- sendmessagetouser(mynick,(nick *)sender,"Usage: rmmod <modulename>");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
switch(rmmod(cargv[0])) {
case 1:
- sendmessagetouser(mynick,(nick *)sender,"Module %s is not loaded.",cargv[0]);
+ controlreply((nick *)sender,"Module %s is not loaded.",cargv[0]);
return CMD_ERROR;
case 0:
- sendmessagetouser(mynick,(nick *)sender,"Module %s unloaded.",cargv[0]);
+ controlreply((nick *)sender,"Module %s unloaded.",cargv[0]);
return CMD_OK;
default:
- sendmessagetouser(mynick,(nick *)sender,"An unknown error occured.");
+ controlreply((nick *)sender,"An unknown error occured.");
return CMD_ERROR;
}
}
if (cargc < 1) { /* list all loaded modules */
ptr = lsmod(i);
- sendmessagetouser(mynick,(nick *)sender,"Module");
+ controlreply((nick *)sender,"Module");
while (ptr != NULL) {
- sendmessagetouser(mynick,(nick *)sender,"%s", ptr);
+ controlreply((nick *)sender,"%s", ptr);
ptr = lsmod(++i);
}
} else {
ptr = lsmod(getindex(cargv[0]));
- sendmessagetouser(mynick,(nick *)sender,"Module \"%s\" %s", cargv[0], (ptr ? "is loaded." : "is NOT loaded."));
+ controlreply((nick *)sender,"Module \"%s\" %s", cargv[0], (ptr ? "is loaded." : "is NOT loaded."));
}
return CMD_OK;
}
int controlreload(void *sender, int cargc, char **cargv) {
- if (cargc<1) {
- sendmessagetouser(mynick,(nick *)sender,"Usage: reload <modulename>");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
controlrmmod(sender, cargc, cargv);
return controlinsmod(sender, cargc, cargv);
int relink(void *sender, int cargc, char **cargv) {
if (cargc<1) {
- sendmessagetouser(mynick,(nick *)sender,"You must give a reason.");
- return CMD_ERROR;
+ controlreply((nick *)sender,"You must give a reason.");
+ return CMD_USAGE;
}
irc_send("%s SQ %s 0 :%s",mynumeric->content,myserver->content,cargv[0]);
int die(void *sender, int cargc, char **cargv) {
if (cargc<1) {
- sendmessagetouser(mynick,(nick *)sender,"You must give a reason.");
- return CMD_ERROR;
+ controlreply((nick *)sender,"You must give a reason.");
+ return CMD_USAGE;
}
irc_send("%s SQ %s 0 :%s",mynumeric->content,myserver->content,cargv[0]);
char buf2[12];
int i,j;
- if (cargc<1) {
- sendmessagetouser(mynick,(nick *)sender,"Usage: channel #chan");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
if ((cp=findchannel(cargv[0]))==NULL) {
- sendmessagetouser(mynick,(nick *)sender,"Couldn't find channel: %s",cargv[0]);
+ controlreply((nick *)sender,"Couldn't find channel: %s",cargv[0]);
return CMD_ERROR;
}
sprintf(buf2,"%d",cp->limit);
}
- sendmessagetouser(mynick,(nick *)sender,"Channel : %s",cp->index->name->content);
+ controlreply((nick *)sender,"Channel : %s",cp->index->name->content);
if (cp->topic) {
- sendmessagetouser(mynick,(nick *)sender,"Topic : %s",cp->topic->content);
- sendmessagetouser(mynick,(nick *)sender,"T-time : %ld [%s]",cp->topictime,ctime(&(cp->topictime)));
+ controlreply((nick *)sender,"Topic : %s",cp->topic->content);
+ controlreply((nick *)sender,"T-time : %ld [%s]",cp->topictime,ctime(&(cp->topictime)));
}
- sendmessagetouser(mynick,(nick *)sender,"Mode(s) : %s %s%s%s",printflags(cp->flags,cmodeflags),IsLimit(cp)?buf2:"",
+ controlreply((nick *)sender,"Mode(s) : %s %s%s%s",printflags(cp->flags,cmodeflags),IsLimit(cp)?buf2:"",
IsLimit(cp)?" ":"",IsKey(cp)?cp->key->content:"");
- sendmessagetouser(mynick,(nick *)sender,"Users : %d (hash size %d, utilisation %.1f%%); %d unique hosts",
+ controlreply((nick *)sender,"Users : %d (hash size %d, utilisation %.1f%%); %d unique hosts",
cp->users->totalusers,cp->users->hashsize,((float)(100*cp->users->totalusers)/cp->users->hashsize),
countuniquehosts(cp));
i=0;
for (j=0;j<=cp->users->hashsize;j++) {
if (i==4 || j==cp->users->hashsize) {
if(i>0) {
- sendmessagetouser(mynick,(nick *)sender,"Users : %s",buf);
+ controlreply((nick *)sender,"Users : %s",buf);
}
i=0;
memset(buf,' ',72);
}
for (cbp=cp->bans;cbp;cbp=cbp->next) {
- sendmessagetouser(mynick,(nick *)sender,"Ban : %s",bantostringdebug(cbp));
+ controlreply((nick *)sender,"Ban : %s",bantostringdebug(cbp));
}
return CMD_OK;
}
controlreply(np,"The following commands are registered at present:");
for(i=0;i<n;i++) {
- controlreply(np,"%s (level %d)",cmdlist[i]->command->content,cmdlist[i]->level);
+ controlreply(np,"%s",cmdlist[i]->command->content);
}
controlreply(np,"End of list.");
cmd=findcommandintree(controlcmds,cargv[0],1);
if (cmd==NULL) {
- sendmessagetouser(mynick,sender,"Unknown command.");
+ controlreply(sender,"Unknown command.");
return;
}
- if (cmd->level>=10 && !IsOper(sender)) {
- sendmessagetouser(mynick,sender,"You need to be opered to use this command.");
+ if (cmd->level>0 && !IsOper(sender)) {
+ controlreply(sender,"You need to be opered to use this command.");
return;
}
cargc=(cmd->maxparams)+1;
}
- (cmd->handler)((void *)sender,cargc-1,&(cargv[1]));
+ if((cmd->handler)((void *)sender,cargc-1,&(cargv[1])) == CMD_USAGE)
+ controlhelp(sender, cmd);
break;
case LU_KILLED:
}
}
-void controlreply(nick *target, char *message, ... ) {
+void controlmessage(nick *target, char *message, ... ) {
char buf[512];
va_list va;
sendnoticetouser(mynick,target,"%s",buf);
}
-/* Send a notice to all opers, O(n) and a notice otherwise we'll get infinite loops with services */
-void controlnoticeopers(char *format, ...) {
+void controlspecialrmmod(void *arg) {
+ struct specialsched *a = (struct specialsched *)arg;
+
+ a->schedule = NULL;
+ sstring *froo = a->modulename;
+
+ rmmod(froo->content);
+ freesstring(froo);
+}
+
+void controlspecialreloadmod(void *arg) {
+ struct specialsched *a = (struct specialsched *)arg;
+
+ a->schedule = NULL;
+ sstring *froo = a->modulename;
+
+ rmmod(froo->content);
+ insmod(froo->content);
+ freesstring(froo);
+}
+
+void controlhelp(nick *np, Command *cmd) {
+ char *cp = cmd->help, *sp = cp;
+ if(!cp || !*cp) {
+ controlreply(np, "Sorry, no help for this command.");
+ } else {
+ int finished = 0;
+ for(;;cp++) {
+ if(*cp == '\0' || *cp == '\n') {
+ if(*cp == '\0') {
+ finished = 1;
+ } else {
+ *cp = '\0';
+ }
+
+ if(sp != cp)
+ controlreply(np, "%s", sp);
+
+ if(finished)
+ break;
+
+ *cp = '\n';
+
+ sp = cp + 1;
+ }
+ }
+ }
+}
+
+int controlhelpcmd(void *sender, int cargc, char **cargv) {
+ Command *cmd;
+ nick *np = (nick *)sender;
+
+ if (cargc<1)
+ return CMD_USAGE;
+
+ cmd=findcommandintree(controlcmds,cargv[0],1);
+ if (cmd==NULL) {
+ controlreply(np,"Unknown command.");
+ return CMD_ERROR;
+ }
+
+ controlhelp(np, cmd);
+ return CMD_OK;
+}
+
+void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...) {
int i;
nick *np;
- char broadcast[BUFSIZE];
+ char broadcast[512];
va_list va;
-
+
va_start(va, format);
vsnprintf(broadcast, sizeof(broadcast), format, va);
va_end(va);
#include "../nick/nick.h"
#include "../channel/channel.h"
-void registercontrolcmd(const char *name, int level, int maxparams, CommandHandler handler);
+void registercontrolhelpcmd(const char *name, int level, int maxparams, CommandHandler handler, char *help);
int deregistercontrolcmd(const char *name, CommandHandler handler);
-void controlreply(nick *target, char *message, ... );
+void controlmessage(nick *target, char *message, ... );
void controlchanmsg(channel *cp, char *message, ...);
void controlnotice(nick *target, char *message, ...);
-void controlnoticeopers(char *format, ...);
+int controlshowcommands(void *sender, int cargc, char **cargv);
+int controlrmmod(void *sender, int cargc, char **cargv);
+void controlspecialrmmod(void *arg);
+void controlspecialreloadmod(void *arg);
+void controlhelp(nick *np, Command *cmd);
+
+#define registercontrolcmd(a, b, c, d) registercontrolhelpcmd(a, b, c, d, NULL)
+
+typedef void (*ControlMsg)(nick *, char *, ... );
+typedef void (*ControlWall)(flag_t, flag_t, char *, ...);
+
+extern ControlMsg controlreply;
+extern ControlWall controlwall;
+
+extern nick *mynick;
+
+extern CommandTree *controlcmds;
+
+struct specialsched {
+ sstring *modulename;
+ void *schedule;
+} specialsched;
+
+/* NEVER USE THE FOLLOWING IN COMMANDS, you'll end up missing bits off and users'll end up being able to gline people */
+#define __NO_ANYONE 0x000
+#define __NO_AUTHED 0x001 /* must be authed with the network, don't know what use this is really */
+#define __NO_OPERED 0x002 /* just means that they MUST be /oper'ed, for hello -- part of LEGACY */
+#define __NO_ACCOUNT 0x004 /* for hello, must have a user account */
+#define __NO_LEGACY 0x008 /* reserved for old newserv commands, their level is 10 */
+#define __NO_STAFF 0x010 /* +s */
+#define __NO_TRUST 0x020 /* +t */
+#define __NO_OPER 0x040 /* +O */
+#define __NO_SEC 0x080 /* +w */
+#define __NO_DEVELOPER 0x100 /* +d */
+
+/* These are dangerous, they don't include requiring /OPER or STAFF status, be careful */
+#define NOD_ACCOUNT __NO_ACCOUNT | NO_AUTHED /* must contain authed else account won't be checked */
+#define NOD_STAFF __NO_STAFF | NOD_ACCOUNT
+#define NOD_TRUST __NO_TRUST | NOD_ACCOUNT
+#define NOD_OPER __NO_OPER | NOD_ACCOUNT
+#define NOD_SEC __NO_SEC | NOD_ACCOUNT
+#define NOD_DEVELOPER __NO_DEVELOPER | NOD_ACCOUNT
+
+/* These ones are safe to use */
+#define NO_ANYONE __NO_ANYONE /* don't have to be authed to Q, or us, or opered or anything */
+#define NO_AUTHED __NO_AUTHED /* must be authed to Q */
+#define NO_ACCOUNT NOD_ACCOUNT /* must have an account on the bot */
+#define NO_OPERED __NO_OPERED /* must be /opered */
+#define NO_STAFF NOD_STAFF /* must be authed to Q and have staff level on bot */
+#define NO_OPER NO_OPERED | NOD_OPER /* must be authed to Q, /opered, and have oper level on bot */
+#define NO_DEVELOPER NO_OPERED | NOD_DEVELOPER /* must be authed to Q, /opered, and have dev level on bot */
+#define NO_TRUST_STAFF NO_STAFF | NOD_TRUST /* must be authed to Q, and have staff and trust level on bot */
+#define NO_TRUST_OPER NO_OPER | NOD_TRUST /* must be authed to Q, /opered, and have trust and oper levels on bot */
+#define NO_SEC_STAFF NO_STAFF | NOD_SEC /* must be authed to Q, and have staff and sec level on bot */
+#define NO_SEC_OPER NO_OPER | NOD_SEC /* must be authed to Q, /opered, and have sec and oper levels on bot */
+
+#define NO_ALL_FLAGS __NO_STAFF | __NO_TRUST | __NO_OPER | __NO_SEC | __NO_DEVELOPER
+#define NO_OPER_FLAGS __NO_STAFF
+#define NO_DEV_FLAGS NO_ALL_FLAGS
+
+#define NL_MANAGEMENT 0x0001 /* hello, password, userflags, noticeflags */
+#define NL_TRUSTS 0x0002 /* trust stuff... */
+#define NL_KICKS 0x0004 /* KICK command */
+#define NL_KILLS 0x0008 /* KILL command */
+#define NL_GLINES 0x0010 /* GLINE commands */
+#define NL_HITS 0x0020 /* Where a gline or kill is set automatically by the bot */
+#define NL_CLONING 0x0040 /* Clone detection */
+#define NL_CLEARCHAN 0x0080 /* When someone clearchans */
+#define NL_FAKEUSERS 0x0100 /* Fakeuser addition */
+#define NL_BROADCASTS 0x0200 /* Broadcast/mbroadcast/sbroadcast */
+#define NL_OPERATIONS 0x0400 /* insmod/rmmod/etc */
+#define NL_OPERING 0x0800 /* when someone opers */
+#define NL_NOTICES 0x1000 /* turn off to receive privmsgs instead of notices */
+#define NL_ALL_COMMANDS 0x2000 /* every single command sent */
#endif
#define HOOK_NICK_ACCOUNT 304 /* Argument is nick* */
#define HOOK_NICK_QUIT 305 /* Argument is void*[2] (nick, reason) */
#define HOOK_NICK_SETHOST 306 /* Argument is nick* */
+#define HOOK_NICK_MODEOPER 307 /* Argument is void*[2] (nick, modes) */
#define HOOK_CHANNEL_BURST 400 /* Argument is channel pointer */
#define HOOK_CHANNEL_CREATE 401 /* Argument is void*[2] (channel, nick) */
#define HOOK_CHANSERV_DBLOADED 500 /* No arg */
+#define HOOK_CONTROL_REGISTERED 600 /* Argument is nick* */
+#define HOOK_CONTROL_WHOISREQUEST 601 /* Argument is nick* */
+#define HOOK_CONTROL_WHOISREPLY 602 /* Argument is char* */
+
typedef void (*HookCallback)(int, void *);
void inithooks();
int do_countusers(void *source, int cargc, char **cargv) {
nick *sender=(nick *)source, *np;
host *hp;
- unsigned int i=0,count=0;
+ unsigned int count=0;
char *chp,*host,*ident;
- if (cargc<1) {
- controlreply(sender, "Usage: countusers <user@host or host>");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
for (chp=cargv[0]; ;chp++) {
if (*chp=='@') {
}
void _init() {
- registercontrolcmd("countusers", 10, 1, do_countusers);
+ registercontrolhelpcmd("countusers", NO_OPER, 1, do_countusers, "Usage: countusers <hostmask>\nReturns users on specified hostmask.");
}
void _fini() {
int dofsck(void *source, int cargc, char **cargv);
void _init() {
- registercontrolcmd("fsck",10,0,dofsck);
+ registercontrolhelpcmd("fsck",NO_DEVELOPER,0,dofsck, "Usage: fsck\nRuns internal structure check.");
}
void _fini() {
nick *victim;
channel *cp;
- if (cargc<1) {
- controlreply(sender,"Usage: horse <target>");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
if ((victim=getnickbynick(cargv[0]))!=NULL) {
controlreply(victim," _ ___,;;;^");
}
void _init() {
- registercontrolcmd("horse",10,2,ho_horse);
+ registercontrolhelpcmd("horse",NO_OPERED,2,ho_horse,"Usage: horse <target>\nSpams a horse at target.");
}
void _fini() {
li_killyoungest(hp->nicks);
} while (hp->clonecount > LI_CLONEMAX);
- registercontrolcmd("victims", 10, 0, li_stats);
+ registercontrolhelpcmd("victims", NO_OPER, 0, li_stats, "Usage: victims\nShows the amount of clients victimised by lameisp.");
registerhook(HOOK_NICK_NEWNICK, &li_nick);
}
controlreply((nick *)source, "Victims: %d clients", li_victims);
return CMD_OK;
-}
\ No newline at end of file
+}
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+#if !defined(u_char)
+typedef u_int8_t u_char;
+#endif
+
+#if !defined(u_int)
+typedef u_int32_t u_int;
+#endif
+
typedef union {
u_char c[64];
u_int l[16];
/* Nickname / channel operations */
registersearchterm("modes",modes_parse);
- registercontrolcmd("nicksearch",10,4,do_nicksearch);
+ registercontrolhelpcmd("nicksearch",NO_OPER,4,do_nicksearch, "Usage: nicksearch <criteria>\nSearches for nicknames with the given criteria.");
}
void _fini() {
char *ch;
int arg=0;
- if (cargc<1) {
- controlreply(sender,"Usage: nicksearch (criteria)");
- return CMD_ERROR;
- }
+ if (cargc<1)
+ return CMD_USAGE;
if (*cargv[0] == '-') {
/* options */
case 'l':
if (cargc<arg) {
controlreply(sender,"Error: -l switch requires an argument");
- return CMD_ERROR;
+ return CMD_USAGE;
}
limit=strtoul(cargv[arg++],NULL,10);
break;
return CMD_OK;
}
oldflags=np->umodes;
+ if (strchr(cargv[1],'o')) {
+ void *harg[2];
+ harg[0]=np;
+ harg[1]=cargv[1];
+ triggerhook(HOOK_NICK_MODEOPER,harg);
+ }
setflags(&(np->umodes),UMODE_ALL,cargv[1],umodeflags,REJECT_NONE);
if (strchr(cargv[1],'h')) { /* Have to allow +h twice.. */
/* +-h: just the freesstring() calls for the -h case */
--- /dev/null
+
+.PHONY: all
+all: noperserv.so noperserv_commands.so
+
+noperserv.so: noperserv.o noperserv_db.o noperserv_hooks.o noperserv_policy.o
+ ld -shared -Bdynamic ${LIBPGSQL} -o $@ $^
+
+noperserv_commands.so: noperserv_commands.o
+ ld -shared -Bdynamic ${LIBPGSQL} -o $@ $^
--- /dev/null
+/*
+ * NOperserv v0.01
+ *
+ * A replacement for Germania's ageing Operservice2
+ *
+ * Copyright (C) 2005 Chris Porter.
+ */
+
+#include "../localuser/localuser.h"
+#include "../lib/irc_string.h"
+#include "../lib/strlfunc.h"
+#include "noperserv.h"
+#include "noperserv_db.h"
+#include "noperserv_hooks.h"
+#include "noperserv_policy.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#define FLAGBUFLEN 100
+
+#define NO_FOUND_NICKNAME 1
+#define NO_FOUND_AUTHNAME 2
+
+const flag no_commandflags[] = {
+ { 'o', __NO_OPER },
+ { 't', __NO_TRUST },
+ { 's', __NO_STAFF },
+ { 'S', __NO_SEC },
+ { 'd', __NO_DEVELOPER },
+ { 'L', __NO_LEGACY },
+ { 'O', __NO_OPERED },
+ { 'r', __NO_AUTHED },
+ { 'R', __NO_ACCOUNT },
+ { '\0', 0 }
+ };
+
+const flag no_userflags[] = {
+ { 'o', __NO_OPER },
+ { 't', __NO_TRUST },
+ { 's', __NO_STAFF },
+ { 'S', __NO_SEC },
+ { 'd', __NO_DEVELOPER },
+ { '\0', 0 }
+ };
+
+const flag no_noticeflags[] = {
+ { 'm', NL_MANAGEMENT }, /* hello, password, userflags, noticeflags */
+ { 't', NL_TRUSTS }, /* trust stuff... */
+ { 'k', NL_KICKS }, /* KICK command */
+ { 'K', NL_KILLS }, /* KILL command */
+ { 'g', NL_GLINES }, /* GLINE commands */
+ { 'h', NL_HITS }, /* Where a gline or kill is set automatically by the bot */
+ { 'c', NL_CLONING }, /* Clone detection */
+ { 'C', NL_CLEARCHAN }, /* When someone clearchans */
+ { 'f', NL_FAKEUSERS }, /* Fakeuser addition */
+ { 'b', NL_BROADCASTS }, /* Broadcast/mbroadcast/sbroadcast */
+ { 'o', NL_OPERATIONS }, /* insmod/rmmod/etc */
+ { 'O', NL_OPERING }, /* when someone opers */
+ { 'n', NL_NOTICES }, /* turn off to receive notices instead of privmsgs */
+ { 'A', NL_ALL_COMMANDS }, /* all commands sent */
+ { '\0', 0 }
+ };
+
+int noperserv_hello(void *sender, int cargc, char **cargv);
+int noperserv_noticeflags(void *sender, int cargc, char **cargv);
+int noperserv_userflags(void *sender, int cargc, char **cargv);
+int noperserv_deluser(void *sender, int cargc, char **cargv);
+void noperserv_oper_detection(int hooknum, void *arg);
+void noperserv_reply(nick *np, char *format, ...);
+
+int init = 0;
+
+void _init() {
+ if(!noperserv_load_db())
+ return;
+
+ noperserv_ext = registernickext("noperserv");
+
+ noperserv_setup_hooks();
+
+ registercontrolhelpcmd("hello", NO_OPERED | NO_AUTHED, 1, &noperserv_hello, "Syntax: HELLO ?nickname|#authname?\nCreates an account on the service for the specified nick, or if one isn't supplied, your nickname.");
+ registercontrolhelpcmd("userflags", NO_ACCOUNT, 2, &noperserv_userflags, "Syntax: USERFLAGS <nickname|#authname> ?modifications?\nViews and modifies user permissions.\nIf no nickname or authname is supplied, you are substituted for it.\nIf no flags are supplied, flags are just displayed instead of modified.");
+ registercontrolhelpcmd("noticeflags", NO_ACCOUNT, 1, &noperserv_noticeflags,
+ "Syntax: NOTICEFLAGS ?(nickname|#authname)|flags?\n"
+ " This command can view and modify your own notice flags, and view that of other users.\n"
+ " Flags:\n"
+ " +m: Management (hello, password, userflags, noticeflags)\n"
+ " +t: Trusts\n"
+ " +k: KICK command\n"
+ " +K: KILL command\n"
+ " +g: GLINE commands\n"
+ " +h: Shows when glines are played automatically (hits)\n"
+ " +c: Clone information\n"
+ " +C: CLEARCHAN command\n"
+ " +f: FAKEUSER command\n"
+ " +b: BROADCAST commands\n"
+ " +o: Operation commands, such as insmod, rmmod, die, etc\n"
+ " +O: /OPER\n"
+ " +n: Sends notices instead of privmsgs\n"
+ " +A: Every single command sent to the service\n"
+ );
+
+ registercontrolhelpcmd("deluser", NO_OPERED | NO_ACCOUNT, 2, &noperserv_deluser, "Syntax: DELUSER <nickname|#authname>\nDeletes the specified user.");
+ registerhook(HOOK_NICK_MODEOPER, &noperserv_oper_detection);
+
+ init = 1;
+}
+
+#ifdef BROKEN_DLCLOSE
+void __fini() {
+#else
+void _fini() {
+#endif
+ if(!init)
+ return;
+
+ deregisterhook(HOOK_NICK_MODEOPER, &noperserv_oper_detection);
+
+ deregistercontrolcmd("noticeflags", &noperserv_noticeflags);
+ deregistercontrolcmd("userflags", &noperserv_userflags);
+ deregistercontrolcmd("noticeflags", &noperserv_noticeflags);
+
+ noperserv_cleanup_hooks();
+
+ noperserv_cleanup_db();
+
+ releasenickext(noperserv_ext);
+}
+
+/* @test */
+int noperserv_hello(void *sender, int cargc, char **cargv) {
+ char *newaccount;
+ no_autheduser *au;
+ int i;
+ nick *np = (nick *)sender, *np2, *target = NULL;
+
+ if(cargc == 0) {
+ newaccount = np->authname;
+ } else {
+ if(cargv[0][0] == '#') {
+ nick *np2;
+ for(i=0;i<NICKHASHSIZE;i++)
+ for(np2=nicktable[i];np2;np2=np2->next)
+ if(IsAccount(np2) && !ircd_strcmp(cargv[0] + 1, np2->authname)) {
+ target = np2;
+ newaccount = target->authname;
+ break;
+ }
+ if(!target) {
+ controlreply(np, "Cannot find anyone with that authname on the network.");
+ return CMD_ERROR;
+ }
+ } else {
+ target = getnickbynick(cargv[0]);
+ if(!target) {
+ controlreply(np, "Supplied nickname is not on the network.");
+ return CMD_ERROR;
+ }
+ if(!IsAccount(target)) {
+ controlreply(np, "Supplied user is not authed with the network.");
+ return CMD_ERROR;
+ }
+ newaccount = target->authname;
+ }
+ }
+ au = noperserv_get_autheduser(newaccount);
+ if(au) {
+ controlreply(np, "Authname already registered.");
+ return CMD_ERROR;
+ }
+
+ au = noperserv_new_autheduser(newaccount);
+ if(!au) {
+ controlreply(np, "Memory allocation error.");
+ return CMD_ERROR;
+ }
+
+ if(noperserv_get_autheduser_count() == 1) {
+ au->authlevel = NO_FIRST_USER_LEVEL;
+ au->noticelevel = NO_FIRST_USER_DEFAULT_NOTICELEVEL;
+ } else {
+ au->authlevel = NO_DEFAULT_LEVEL;
+ au->noticelevel = NO_DEFAULT_NOTICELEVEL;
+ }
+
+ au->id = noperserv_next_autheduser_id();
+ noperserv_update_autheduser(au);
+
+ for(i=0;i<NICKHASHSIZE;i++)
+ for(np2=nicktable[i];np2;np2=np2->next)
+ if(IsAccount(np2) && !ircd_strcmp(newaccount, np2->authname)) {
+ noperserv_add_to_autheduser(np2, au);
+ controlreply(np2, "An account has been created for you (auth %s).", au->authname->content);
+ if(NOGetAuthLevel(au))
+ controlreply(np2, "User flags: %s", printflags(NOGetAuthLevel(au), no_userflags));
+ controlreply(np2, "Notice flags: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
+ }
+
+ if(ircd_strcmp(np->authname, newaccount)) { /* send a message to the person who HELLO'ed if we haven't already been told */
+ controlreply(np, "Account created for auth %s.", au->authname->content);
+ if(NOGetAuthLevel(au))
+ controlreply(np, "User flags: %s", printflags(NOGetAuthLevel(au), no_userflags));
+ controlreply(np, "Notice flags: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
+ controlreply(np, "Instructions sent to all authed users.");
+ } else if(au->nick && au->nick->next) { /* if we have already been told, tell the user it was sent to more than themselves */
+ controlreply(np, "Instructions sent to all authed users.");
+ }
+
+ controlwall(NO_OPERED, NL_MANAGEMENT, "%s/%s just HELLO'ed: %s", np->nick, np->authname, au->authname->content);
+ return CMD_OK;
+}
+
+no_autheduser *noperserv_autheduser_from_command(nick *np, char *command, int *typefound, char **returned) {
+ no_autheduser *au;
+ if(command[0] == '#') {
+ au = noperserv_get_autheduser(command + 1);
+ if(!au) {
+ controlreply(np, "Authname not found.");
+ } else {
+ *typefound = NO_FOUND_AUTHNAME;
+ *returned = au->authname->content;
+ return au;
+ }
+ } else {
+ nick *np2 = getnickbynick(command);
+ if(!np2) {
+ controlreply(np, "Nickname not on the network.");
+ return CMD_OK;
+ }
+ if(!IsAccount(np2)) {
+ controlreply(np, "User is not authed with the network.");
+ return CMD_OK;
+ }
+ au = NOGetAuthedUser(np2);
+ if(!au) {
+ controlreply(np, "User does not have an account.");
+ } else {
+ *typefound = NO_FOUND_NICKNAME;
+ *returned = np2->nick;
+ return au;
+ }
+ }
+
+ return NULL;
+}
+
+int noperserv_noticeflags(void *sender, int cargc, char **cargv) {
+ nick *np = (nick *)sender;
+ no_autheduser *au;
+
+ if(cargc == 1) {
+ if((cargv[0][0] == '+') || (cargv[0][0] == '-')) {
+ int ret;
+ au = NOGetAuthedUser(np);
+ flag_t fwas = NOGetNoticeLevel(au), permittedchanges = noperserv_policy_permitted_noticeflags(au);
+
+ ret = setflags(&au->noticelevel, permittedchanges, cargv[0], no_noticeflags, REJECT_DISALLOWED | REJECT_UNKNOWN);
+ if(ret != REJECT_UNKNOWN) {
+ if(ret == REJECT_DISALLOWED) {
+ flag_t fnow = fwas;
+ setflags(&fnow, NL_ALL, cargv[0], no_noticeflags, REJECT_NONE);
+ if(fnow == fwas) {
+ controlreply(np, "No changes made to existing flags.");
+ } else {
+ char ourflags[FLAGBUFLEN], ournoticeflags[FLAGBUFLEN];
+ controlreply(np, "Flag alterations denied.");
+
+ strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
+ strlcpy(ournoticeflags, printflags(NOGetNoticeLevel(au), no_noticeflags), sizeof(ournoticeflags));
+ controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to NOTICEFLAGS (%s): %s", np->nick, np->authname, ourflags, ournoticeflags, printflagdiff(fwas, fnow, no_noticeflags));
+ return CMD_ERROR;
+ }
+ } else if(ret == REJECT_NONE) {
+ if(NOGetNoticeLevel(au) == fwas) {
+ controlreply(np, "No changes made to existing flags.");
+ } else {
+ char ourflags[FLAGBUFLEN], ournoticeflags[FLAGBUFLEN], diff[FLAGBUFLEN * 2 + 1], finalflags[FLAGBUFLEN];
+ no_nicklist *nl = au->nick;
+ noperserv_update_autheduser(au);
+ controlreply(np, "Flag alterations complete.");
+
+ strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
+ strlcpy(ournoticeflags, printflags(fwas, no_noticeflags), sizeof(ournoticeflags));
+ strlcpy(diff, printflagdiff(fwas, NOGetNoticeLevel(au), no_noticeflags), sizeof(diff));
+ controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used NOTICEFLAGS (%s): %s", np->nick, np->authname, ourflags, ournoticeflags, diff);
+
+ strlcpy(finalflags, printflags(NOGetNoticeLevel(au), no_noticeflags), sizeof(finalflags));
+ for(;nl;nl=nl->next)
+ if(nl->nick != np) {
+ controlreply(nl->nick, "!!! %s just used NOTICEFLAGS (%s): %s", np->nick, ournoticeflags, diff);
+ controlreply(nl->nick, "Your notice flags are %s", finalflags);
+ }
+ }
+ }
+ } else {
+ controlreply(np, "Unknown flag(s) supplied.");
+ return CMD_ERROR;
+ }
+ } else {
+ int typefound;
+ char *itemfound;
+ au = noperserv_autheduser_from_command(np, cargv[0], &typefound, &itemfound);
+ if(!au)
+ return CMD_ERROR;
+
+ if(au != NOGetAuthedUser(np)) {
+ controlreply(np, "Notice flags for %s %s are: %s", typefound==NO_FOUND_NICKNAME?"user":"authname", itemfound, printflags(NOGetNoticeLevel(au), no_noticeflags));
+ return CMD_OK;
+ }
+ }
+ } else {
+ au = NOGetAuthedUser(np);
+ }
+
+ if(!au) /* shouldn't happen */
+ return CMD_ERROR;
+
+ controlreply(np, "Your notice flags are: %s", printflags(NOGetNoticeLevel(au), no_noticeflags));
+
+ return CMD_OK;
+}
+
+/* @test */
+int noperserv_deluser(void *sender, int cargc, char **cargv) {
+ nick *np = (nick *)sender;
+ no_autheduser *target /* target user */, *au = NOGetAuthedUser(np); /* user executing command */
+ char *userreturned = NULL; /* nickname or authname of the target, pulled from the db */
+ int typefound; /* whether it was an authname or a username */
+ no_nicklist *nl;
+ char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN], deleteduser[NOMax(ACCOUNTLEN, NICKLEN) + 1];
+
+ if(cargc != 1)
+ return CMD_USAGE;
+
+ target = noperserv_autheduser_from_command(np, cargv[0], &typefound, &userreturned);
+ if(!target)
+ return CMD_ERROR;
+
+ strlcpy(targetflags, printflags(NOGetAuthLevel(target), no_userflags), sizeof(targetflags));
+ strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags));
+
+ /* we have to copy it as it might point to an autheduser, which we're about to delete */
+ strlcpy(deleteduser, userreturned, sizeof(deleteduser));
+
+ /* we have to check if target != au, because if successful policy_modification_permitted just returns the flags we're allowed
+ to modify, if we have no flags we won't be able to delete ourselves */
+ if((target != au) && !noperserv_policy_permitted_modifications(au, target)) {
+ controlreply(np, "Deletion denied.");
+ controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to DELUSER %s (%s)", np->nick, np->authname, ourflags, target->authname->content, targetflags);
+
+ return CMD_ERROR;
+ }
+
+ for(nl=target->nick;nl;nl=nl->next)
+ if(nl->nick != np)
+ controlreply(nl->nick, "!!! %s/%s (%s) just DELUSERed you.", np->nick, np->authname, ourflags);
+
+ noperserv_delete_autheduser(target);
+
+ controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used DELUSER on %s (%s)", np->nick, np->authname, ourflags, target->authname->content, targetflags);
+
+ if(target == au) {
+ controlreply(np, "You have been deleted.");
+ } else {
+ controlreply(np, "%s %s deleted.", typefound==NO_FOUND_AUTHNAME?"Auth":"User", deleteduser);
+ }
+
+ return CMD_OK;
+}
+
+/* @test */
+/* this command needs LOTS of checking */
+int noperserv_userflags(void *sender, int cargc, char **cargv) {
+ nick *np = (nick *)sender;
+ no_autheduser *au = NOGetAuthedUser(np), *target = NULL;
+ char *flags = NULL, *nicktarget = NULL;
+ int typefound;
+
+ if(cargc == 0) {
+ target = au;
+ } else if(cargc == 1) {
+ if((cargv[0][0] == '+') || (cargv[0][0] == '-')) { /* modify our own */
+ flags = cargv[0];
+ target = au;
+ } else { /* viewing someone elses */
+ nicktarget = cargv[0];
+ }
+ } else if(cargc == 2) {
+ nicktarget = cargv[0];
+ flags = cargv[1];
+ } else {
+ return CMD_USAGE;
+ }
+
+ if(nicktarget) {
+ target = noperserv_autheduser_from_command(np, nicktarget, &typefound, &nicktarget);
+ if(!target)
+ return CMD_ERROR;
+ }
+
+ if(flags) {
+ int ret;
+ flag_t permitted = noperserv_policy_permitted_modifications(au, target), fwas = NOGetAuthLevel(target), fours = NOGetAuthLevel(au);
+
+ ret = setflags(&target->authlevel, permitted, flags, no_userflags, REJECT_DISALLOWED | REJECT_UNKNOWN);
+ if(ret != REJECT_UNKNOWN) {
+ if(ret == REJECT_DISALLOWED) {
+ flag_t fnow = fwas;
+ setflags(&fnow, NO_ALL_FLAGS, flags, no_userflags, REJECT_NONE);
+ if(fnow == fwas) {
+ controlreply(np, "No changes made to existing flags.");
+ } else {
+ char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN];
+ controlreply(np, "Flag alterations denied.");
+
+ strlcpy(targetflags, printflags(fwas, no_userflags), sizeof(targetflags));
+ strlcpy(ourflags, printflags(fours, no_userflags), sizeof(ourflags));
+
+ controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to use USERFLAGS on %s (%s): %s", np->nick, np->authname, ourflags, target->authname->content, targetflags, printflagdiff(fwas, fnow, no_userflags));
+ return CMD_ERROR;
+ }
+ } else if(ret == REJECT_NONE) {
+ if(NOGetAuthLevel(target) == fwas) {
+ controlreply(np, "No changes made to existing flags.");
+ } else {
+ char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN], finalflags[FLAGBUFLEN];
+ no_nicklist *nl = target->nick;
+
+ noperserv_policy_update_noticeflags(fwas, target);
+ noperserv_update_autheduser(target);
+
+ controlreply(np, "Flag alterations complete.");
+
+ strlcpy(targetflags, printflags(fwas, no_userflags), sizeof(targetflags));
+ strlcpy(ourflags, printflags(fours, no_userflags), sizeof(ourflags));
+
+ controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used USERFLAGS on %s (%s): %s", np->nick, np->authname, ourflags, target->authname->content, targetflags, printflagdiff(fwas, NOGetAuthLevel(target), no_userflags));
+
+ strlcpy(finalflags, printflags(NOGetAuthLevel(target), no_userflags), sizeof(finalflags));
+ for(;nl;nl=nl->next)
+ if(nl->nick != np) {
+ controlreply(nl->nick, "!!! %s/%s (%s) just used USERFLAGS on you (%s): %s", np->nick, np->authname, ourflags, targetflags, printflagdiff(fwas, NOGetAuthLevel(target), no_userflags));
+ controlreply(nl->nick, "Your user flags are now: %s", finalflags);
+ controlreply(nl->nick, "Your notice flags are now: %s", printflags(target->noticelevel, no_noticeflags));
+ }
+ }
+ }
+ } else {
+ controlreply(np, "Unknown flag(s) supplied.");
+ return CMD_ERROR;
+ }
+ }
+
+ if(target != au) {
+ controlreply(np, "User flags for %s %s: %s", typefound==NO_FOUND_AUTHNAME?"auth":"user", nicktarget, printflags(NOGetAuthLevel(target), no_userflags));
+ controlreply(np, "Notice flags for %s %s: %s", typefound==NO_FOUND_AUTHNAME?"auth":"user", nicktarget, printflags(target->noticelevel, no_noticeflags));
+ } else {
+ controlreply(np, "Your user flags are: %s", printflags(NOGetAuthLevel(target), no_userflags));
+ controlreply(np, "Your notice flags are: %s", printflags(target->noticelevel, no_noticeflags));
+ }
+
+ return CMD_OK;
+}
+
+void noperserv_oper_detection(int hooknum, void *arg) {
+ void **args = (void **)arg;
+ nick *np = args[0];
+ char *modestr = args[1];
+ flag_t after = np->umodes;
+
+ setflags(&after, UMODE_ALL, modestr, umodeflags, REJECT_NONE);
+ if(np->umodes & UMODE_OPER) {
+ if(!(after & UMODE_OPER))
+ controlwall(NO_OPER, NL_OPERING, "%s!%s@%s%s%s just DEOPERed", np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"");
+ } else {
+ if(after & UMODE_OPER)
+ controlwall(NO_OPER, NL_OPERING, "%s!%s@%s%s%s just OPERed", np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"");
+ }
+}
--- /dev/null
+#ifndef __NOPERSERV_H
+#define __NOPERSERV_H
+
+#include "../control/control.h"
+#include "../noperserv/noperserv_db.h"
+#include "../lib/flags.h"
+
+int noperserv_ext;
+
+extern const flag no_userflags[];
+extern const flag no_noticeflags[];
+extern const flag no_commandflags[];
+
+#define NO_NICKS_PER_WHOIS_LINE 3
+
+#define NOGetAuthedUser(user) (no_autheduser *)(user->exts[noperserv_ext])
+#define NOGetAuthLevel(user) user->authlevel
+#define NOGetNoticeLevel(user) user->noticelevel
+#define NOMax(a, b) (a>b?a:b)
+#define NOMin(a, b) (a<b?b:a)
+
+#endif
--- /dev/null
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+#include <string.h>\r
+#include <time.h>\r
+\r
+#include "../control/control.h"\r
+#include "../nick/nick.h"\r
+#include "../localuser/localuserchannel.h"\r
+\r
+int controlkill(void *sender, int cargc, char **cargv);\r
+int controlopchan(void *sender, int cargc, char **cargv);\r
+int controlkick(void *sender, int cargc, char **cargv);\r
+\r
+void _init() {\r
+ registercontrolhelpcmd("kill",NO_OPER,2,&controlkill,"Usage: kill nick <reason>\nKill specificed user.");\r
+ registercontrolhelpcmd("opchan",NO_OPER,2,&controlopchan,"Usage: opchan channel nick\nGive user +o on channel.");\r
+ registercontrolhelpcmd("kick",NO_OPER,3,&controlkick,"Usage: kick channel user <reason>\nKick a user from the given channel");\r
+}\r
+\r
+void _fini() {\r
+ deregistercontrolcmd("kill",controlkill); \r
+ deregistercontrolcmd("opchan",controlopchan);\r
+ deregistercontrolcmd("kick",controlkick);\r
+}\r
+\r
+int controlkick(void *sender, int cargc, char **cargv) {\r
+ nick *np=(nick *)sender;\r
+ nick *victim;\r
+ channel *cp;\r
+ modechanges changes;\r
+ nick *target;\r
+\r
+ if (cargc<2) {\r
+ controlreply(sender,"Usage: kick channel user <reason>");\r
+ return CMD_ERROR;\r
+ }\r
+\r
+ if ((cp=findchannel(cargv[0]))!=NULL) {\r
+ if (cargv[1][0]=='#') {\r
+ if (!(target=getnickbynumericstr(cargv[1]+1))) {\r
+ controlreply(np,"Sorry, couldn't find numeric %s",cargv[0]+1);\r
+ return CMD_ERROR;\r
+ }\r
+ } else {\r
+ if ((target=getnickbynick(cargv[1]))==NULL) {\r
+ controlreply(np,"Sorry, couldn't find that user");\r
+ return CMD_ERROR;\r
+ }\r
+ }\r
+\r
+ if(cargc > 2) {\r
+ irc_send("%s K %s %s :%s",mynumeric->content,cp->index->name->content,longtonumeric(target->numeric,5),cargv[2]);\r
+ } else {\r
+ irc_send("%s K %s %s :Kicked",mynumeric->content,cp->index->name->content,longtonumeric(target->numeric,5));\r
+ }\r
+ delnickfromchannel(cp, target->numeric, 1);\r
+\r
+ controlreply(sender,"Put Kick for %s from %s.", target->nick, cp->index->name->content);\r
+ controlwall(NO_OPER, NL_KICKS, "%s/%s sent KICK for %s!%s@%s from %s", np->nick, np->authname, target->nick, target->ident, target->host->name->content,cp->index->name->content);\r
+\r
+ } else {\r
+ controlreply(np,"Couldn't find channel %s.",cargv[0]);\r
+ return;\r
+ }\r
+\r
+ return CMD_OK;\r
+}\r
+\r
+int controlopchan(void *source, int cargc, char **cargv) {\r
+ nick *sender=(nick *)source;\r
+ nick *victim;\r
+ channel *cp;\r
+ modechanges changes;\r
+ nick *target;\r
+ unsigned long *lp;\r
+\r
+ if (cargc<2) {\r
+ controlreply(sender,"Usage: opchan channel user");\r
+ return CMD_ERROR;\r
+ }\r
+ \r
+ if ((cp=findchannel(cargv[0]))!=NULL) {\r
+ if (cargv[1][0]=='#') {\r
+ if (!(target=getnickbynumericstr(cargv[1]+1))) {\r
+ controlreply(sender,"Sorry, couldn't find numeric %s",cargv[0]+1);\r
+ return CMD_ERROR;\r
+ }\r
+ } else {\r
+ if ((target=getnickbynick(cargv[1]))==NULL) {\r
+ controlreply((nick *)sender,"Sorry, couldn't find that user");\r
+ return CMD_ERROR;\r
+ }\r
+ }\r
+\r
+ if ((lp=getnumerichandlefromchanhash(cp->users,target->numeric))==NULL) {\r
+ controlreply((nick *)sender,"Sorry, User not on channel");\r
+ return CMD_ERROR;\r
+ }\r
+\r
+ (*lp)|=CUMODE_OP;\r
+ irc_send("%s OM %s +o %s",mynumeric->content,cp->index->name->content,longtonumeric(target->numeric,5));\r
+ controlreply(sender,"Put mode +o %s on %s.", target->nick, cp->index->name->content); \r
+ } else {\r
+ controlreply(sender,"Couldn't find channel %s.",cargv[0]);\r
+ return;\r
+ }\r
+ \r
+ return CMD_OK;\r
+}\r
+\r
+int controlkill(void *sender, int cargc, char **cargv) {\r
+ nick *target;\r
+ char buf[BUFSIZE];\r
+ int i;\r
+ nick *np = (nick *)sender;\r
+ \r
+ if (cargc<1) {\r
+ controlreply(np,"Usage: kill <user> <reason>");\r
+ return CMD_ERROR;\r
+ }\r
+ \r
+ if (cargv[0][0]=='#') {\r
+ if (!(target=getnickbynumericstr(cargv[0]+1))) {\r
+ controlreply(np,"Sorry, couldn't find numeric %s",cargv[0]+1);\r
+ return CMD_ERROR;\r
+ }\r
+ } else {\r
+ if ((target=getnickbynick(cargv[0]))==NULL) {\r
+ controlreply(np,"Sorry, couldn't find that user");\r
+ return CMD_ERROR;\r
+ }\r
+ }\r
+\r
+ killuser(NULL, target, (cargc>1)?cargv[1]:"Killed");\r
+ controlreply(np,"KILL sent.");\r
+ controlwall(NO_OPER, NL_KILLS, "%s/%s sent KILL for %s!%s@%s (%s)", np->nick, np->authname, target->nick, target->ident, target->host->name->content,(cargc>1)?cargv[1]:"Killed");\r
+\r
+ return CMD_OK;\r
+}\r
--- /dev/null
+/*
+ * NOperserv v0.01
+ *
+ * A replacement for Germania's ageing Operservice2
+ * DB functions
+ *
+ * Copyright (C) 2005 Chris Porter.
+ */
+
+#include "../nick/nick.h"
+#include "../core/error.h"
+#include "../lib/irc_string.h"
+#include "../core/schedule.h"
+#include "../pqsql/pqsql.h"
+
+#include "noperserv.h"
+#include "noperserv_db.h"
+
+#include <libpq-fe.h>
+#include <stdlib.h>
+
+int db_loaded = 0;
+unsigned long loadedusers = 0;
+
+unsigned long lastuserid;
+
+no_autheduser *authedusers = NULL;
+
+void noperserv_create_tables(void);
+
+void noperserv_free_user(no_autheduser *au);
+void noperserv_load_users(PGconn *dbconn, void *arg);
+
+void noperserv_check_nick(nick *np);
+void noperserv_nick_account(int hooknum, void *arg);
+void noperserv_quit_account(int hooknum, void *arg);
+
+void nopserserv_delete_from_autheduser(nick *np, no_autheduser *au);
+
+int noperserv_load_db(void) {
+ if(!pqconnected())
+ return 0;
+
+ if(db_loaded)
+ noperserv_cleanup_db();
+
+ db_loaded = 1;
+
+ authedusers = NULL;
+
+ noperserv_create_tables();
+
+ pqasyncquery(noperserv_load_users, NULL,
+ "SELECT ID, authname, flags, noticelevel FROM noperserv.users");
+
+ return 1;
+}
+
+void noperserv_load_users(PGconn *dbconn, void *arg) {
+ PGresult *pgres = PQgetResult(dbconn);
+ int rows, i;
+ no_autheduser *nu;
+ nick *np;
+
+ if(PQresultStatus(pgres) != PGRES_TUPLES_OK) {
+ Error("noperserv", ERR_ERROR, "Error loading user list.");
+ return;
+ }
+
+ rows = PQntuples(pgres);
+ lastuserid = 0;
+
+ for(i=0;i<rows;i++) {
+ nu = noperserv_new_autheduser(PQgetvalue(pgres, i, 1));
+ if(!nu)
+ continue;
+
+ nu->id = strtoul(PQgetvalue(pgres, i, 0), NULL, 10);
+ nu->authlevel = strtoul(PQgetvalue(pgres, i, 2), NULL, 10);
+ nu->noticelevel = strtoul(PQgetvalue(pgres, i, 3), NULL, 10);
+ nu->newuser = 0;
+ if(nu->id > lastuserid)
+ lastuserid = nu->id;
+ }
+
+ Error("noperserv", ERR_INFO, "Loaded %d users", loadedusers);
+
+ for(i=0;i<NICKHASHSIZE;i++)
+ for(np=nicktable[i];np;np=np->next)
+ if(IsAccount(np))
+ noperserv_check_nick(np);
+
+ registerhook(HOOK_NICK_ACCOUNT, &noperserv_nick_account);
+ registerhook(HOOK_NICK_NEWNICK, &noperserv_nick_account);
+ registerhook(HOOK_NICK_LOSTNICK, &noperserv_quit_account);
+}
+
+void noperserv_create_tables(void) {
+ pqcreatequery("CREATE SCHEMA noperserv");
+ pqcreatequery(
+ "CREATE TABLE noperserv.users ("
+ "ID INT NOT NULL,"
+ "authname VARCHAR(%d) NOT NULL,"
+ "flags INT NOT NULL,"
+ "noticelevel INT NOT NULL,"
+ "PRIMARY KEY (ID))", ACCOUNTLEN);
+}
+
+void noperserv_cleanup_db(void) {
+ no_autheduser *ap, *np;
+
+ deregisterhook(HOOK_NICK_LOSTNICK, &noperserv_quit_account);
+ deregisterhook(HOOK_NICK_NEWNICK, &noperserv_nick_account);
+ deregisterhook(HOOK_NICK_ACCOUNT, &noperserv_nick_account);
+
+ ap = authedusers;
+ while(ap) {
+ np = ap->next;
+ noperserv_free_user(ap);
+ ap = np;
+ }
+}
+
+no_autheduser *noperserv_new_autheduser(char *authname) {
+ no_autheduser *au = (no_autheduser *)malloc(sizeof(no_autheduser));
+ if(!au)
+ return NULL;
+
+ au->authname = getsstring(authname, ACCOUNTLEN);
+ if(!au->authname) {
+ free(au);
+ return NULL;
+ }
+
+ loadedusers++;
+ au->newuser = 1;
+ au->nick = NULL;
+
+ au->next = authedusers;
+ authedusers = au;
+
+ return au;
+}
+
+void noperserv_delete_autheduser(no_autheduser *au) {
+ no_autheduser *ap = authedusers, *lp = NULL;
+
+ if(!au->newuser)
+ pqquery("DELETE FROM noperserv.users WHERE id = %d", au->id);
+
+ for(;ap;lp=ap,ap=ap->next) {
+ if(ap == au) {
+ if(lp) {
+ lp->next = ap->next;
+ } else {
+ authedusers = ap->next;
+ }
+ noperserv_free_user(ap);
+ return;
+ }
+ }
+}
+
+void noperserv_update_autheduser(no_autheduser *au) {
+ if(au->newuser) {
+ char escapedauthname[ACCOUNTLEN * 2 + 1];
+ PQescapeString(escapedauthname, au->authname->content, au->authname->length);
+ pqquery("INSERT INTO noperserv.users (id, authname, flags, noticelevel) VALUES (%lu,'%s',%lu,%lu)", au->id, au->authname->content, NOGetAuthLevel(au), NOGetNoticeLevel(au));
+ au->newuser = 0;
+ } else {
+ pqquery("UPDATE noperserv.users SET flags = %lu, noticelevel = %lu WHERE id = %lu", NOGetAuthLevel(au), NOGetNoticeLevel(au), au->id);
+ }
+}
+
+void noperserv_free_user(no_autheduser *au) {
+ no_nicklist *cp = au->nick, *np;
+
+ while(cp) {
+ cp->nick->exts[noperserv_ext] = NULL;
+ np = cp->next;
+ free(cp);
+ cp = np;
+ }
+
+ freesstring(au->authname);
+ free(au);
+
+ loadedusers--;
+}
+
+void noperserv_check_nick(nick *np) {
+ no_autheduser *au = noperserv_get_autheduser(np->authname);
+ if(au)
+ noperserv_add_to_autheduser(np, au);
+}
+
+void noperserv_nick_account(int hooknum, void *arg) {
+ noperserv_check_nick((nick *)arg);
+}
+
+void noperserv_quit_account(int hooknum, void *arg) {
+ nick *np = (void *)arg;
+ no_autheduser *au = NOGetAuthedUser(np);
+ no_nicklist *nl, *ln = NULL;
+ if(!au)
+ return;
+
+ for(nl=au->nick;nl;ln=nl,nl=nl->next)
+ if(nl->nick == np) {
+ if(ln) {
+ ln->next = nl->next;
+ } else {
+ au->nick = nl->next;
+ }
+ free(nl);
+ break;
+ }
+}
+
+no_autheduser *noperserv_get_autheduser(char *authname) {
+ no_autheduser *au = authedusers;
+
+ for(;au;au=au->next)
+ if(!ircd_strcmp(authname, au->authname->content))
+ return au;
+
+ return NULL;
+}
+
+unsigned long noperserv_get_autheduser_count(void) {
+ return loadedusers;
+}
+
+unsigned long noperserv_next_autheduser_id(void) {
+ return ++lastuserid;
+}
+
+void noperserv_add_to_autheduser(nick *np, no_autheduser *au) {
+ no_nicklist *nl = (no_nicklist *)malloc(sizeof(no_nicklist));
+ if(!nl)
+ return;
+
+ np->exts[noperserv_ext] = au;
+
+ nl->nick = np;
+
+ nl->next = au->nick;
+ au->nick = nl;
+}
+
+void nopserserv_delete_from_autheduser(nick *np, no_autheduser *au) {
+ no_nicklist *cp = au->nick, *lp = NULL;
+
+ for(;cp;lp=cp,cp=cp->next)
+ if(cp->nick == np) {
+ if(lp) {
+ lp->next = cp->next;
+ } else {
+ au->nick = cp->next;
+ }
+ free(cp);
+ break;
+ }
+}
--- /dev/null
+#ifndef __NOPERSERV_STRUCTS_H
+#define __NOPERSERV_STRUCTS_H
+
+typedef unsigned long no_tableid;
+
+typedef struct no_nicklist {
+ nick *nick;
+ struct no_nicklist *next;
+} no_nicklist;
+
+typedef struct no_autheduser {
+ unsigned newuser: 1;
+ sstring *authname;
+ flag_t authlevel;
+ flag_t noticelevel;
+ no_tableid id;
+ struct no_autheduser *next;
+ no_nicklist *nick;
+} no_autheduser;
+
+int noperserv_load_db(void);
+void noperserv_cleanup_db(void);
+
+extern no_autheduser *authedusers;
+
+void noperserv_delete_autheduser(no_autheduser *au);
+no_autheduser *noperserv_new_autheduser(char *authname);
+no_autheduser *noperserv_get_autheduser(char *authname);
+void noperserv_update_autheduser(no_autheduser *au);
+void noperserv_add_to_autheduser(nick *np, no_autheduser *au);
+
+unsigned long noperserv_get_autheduser_count(void);
+unsigned long noperserv_next_autheduser_id(void);
+
+#endif
--- /dev/null
+#include "../control/control.h"
+#include "../localuser/localuser.h"
+#include "../core/schedule.h"
+#include "../lib/splitline.h"
+#include "../lib/flags.h"
+#include "../lib/irc_string.h"
+#include "../lib/strlfunc.h"
+
+#include "noperserv.h"
+#include "noperserv_db.h"
+#include "noperserv_hooks.h"
+#include "noperserv_policy.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+struct storedhook {
+ CommandHandler old;
+ sstring *name;
+ char *oldhelp;
+ char *newhelp;
+ struct storedhook *next;
+} storedhook;
+
+struct storedhook *storedhooks = NULL;
+
+int firsttime = 0;
+nick *replynick = NULL;
+
+UserMessageHandler oldhandler;
+ControlMsg oldreply;
+ControlWall oldwall;
+
+void noperserv_trap_registration(int hooknum, void *arg);
+int noperserv_showcommands(void *sender, int cargc, char **cargv);
+int noperserv_rmmod(void *sender, int cargc, char **cargv);
+int noperserv_reload(void *sender, int cargc, char **cargv);
+int noperserv_whois(void *sender, int cargc, char **cargv);
+int noperserv_help(void *sender, int cargc, char **cargv);
+void noperserv_whois_handler(int hooknum, void *arg);
+void noperserv_whois_account_handler(int hooknum, void *arg);
+void noperserv_handle_messages(nick *target, int messagetype, void **args);
+void noperserv_reply(nick *np, char *format, ...);
+void noperserv_wall(flag_t permissionlevel, flag_t noticelevel, char *format, ...);
+
+struct specialsched special;
+
+#define HOOK_CONTROL_WHOISREQUEST_AUTHNAME -1
+#define HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER -2
+
+void noperserv_setup_hooks(void) {
+ oldreply = controlreply;
+ controlreply = &noperserv_reply;
+
+ oldwall = controlwall;
+ controlwall = &noperserv_wall;
+
+ memset(&special, 0, sizeof(specialsched));
+
+ if(!mynick) {
+ registerhook(HOOK_CONTROL_REGISTERED, &noperserv_trap_registration);
+ } else {
+ noperserv_trap_registration(0, (void *)mynick);
+ }
+
+ registerhook(HOOK_CONTROL_WHOISREQUEST, &noperserv_whois_handler);
+}
+
+int noperserv_hook_command(char *command, CommandHandler newcommand, char *newhelp) {
+ struct storedhook *newhook;
+ Command *fetchcommand = findcommandintree(controlcmds, command, 1);
+
+ if(!fetchcommand)
+ return 1;
+
+ newhook = (struct storedhook *)malloc(sizeof(struct storedhook));
+ if(!newhook)
+ return 1;
+
+ newhook->name = getsstring(command, strlen(command));
+ if(!newhook->name) {
+ free(newhook);
+ return 1;
+ }
+
+ newhook->old = fetchcommand->handler;
+ if(newhelp) {
+ int len = strlen(newhelp) + 1;
+ newhook->newhelp = (char *)malloc(len);
+ if(!newhook->newhelp) {
+ freesstring(newhook->name);
+ free(newhook);
+ }
+ strlcpy(newhook->newhelp, newhelp, len);
+ newhook->oldhelp = fetchcommand->help;
+ fetchcommand->help = newhook->newhelp;
+ } else {
+ newhook->newhelp = NULL;
+ }
+
+ newhook->next = storedhooks;
+ storedhooks = newhook;
+
+ fetchcommand->handler = newcommand;
+
+ return 0;
+}
+
+void noperserv_unhook_all_commands(void) {
+ struct storedhook *nh, *ch = storedhooks;
+ Command *fetchcommand;
+
+ while(ch) {
+ if(ch->old && (fetchcommand = findcommandintree(controlcmds, ch->name->content, 1))) {
+ fetchcommand->handler = ch->old;
+ if(ch->newhelp) {
+ fetchcommand->help = ch->oldhelp;
+ free(ch->newhelp);
+ }
+ }
+ nh = ch->next;
+ freesstring(ch->name);
+ free(ch);
+ ch = nh;
+ }
+}
+
+void noperserv_cleanup_hooks(void) {
+ deregisterhook(HOOK_CONTROL_WHOISREQUEST, &noperserv_whois_handler);
+ deregisterhook(HOOK_CONTROL_REGISTERED, &noperserv_trap_registration);
+
+ if(firsttime) {
+ noperserv_unhook_all_commands();
+ firsttime = 0;
+ }
+
+ if(oldhandler)
+ hooklocaluserhandler(mynick, oldhandler);
+
+ controlwall = oldwall;
+ controlreply = oldreply;
+}
+
+void noperserv_trap_registration(int hooknum, void *arg) {
+ oldhandler = hooklocaluserhandler((nick *)arg, &noperserv_handle_messages);
+ if(!oldhandler)
+ return;
+
+ if(!firsttime) {
+ firsttime = 1;
+ noperserv_hook_command("rmmod", &noperserv_rmmod, NULL);
+ noperserv_hook_command("reload", &noperserv_reload, NULL);
+ noperserv_hook_command("showcommands", &noperserv_showcommands, NULL);
+ noperserv_hook_command("whois", &noperserv_whois, "Usage: whois <nickname|#authname|*numeric>\nDisplays lots of information about the specified nickname, auth name or numeric.");
+ noperserv_hook_command("help", &noperserv_help, NULL);
+ }
+}
+
+CommandHandler noperserv_find_hook(char *command) {
+ struct storedhook *hh = storedhooks;
+ for(;hh;hh=hh->next)
+ if(!ircd_strcmp(hh->name->content, command))
+ return hh->old;
+
+ return NULL;
+}
+
+int noperserv_specialmod(nick *np, char *command, ScheduleCallback reloadhandler, int cargc, char **cargv) {
+ CommandHandler oldcommand = noperserv_find_hook(command);
+ if(cargc < 1) {
+ if(oldcommand)
+ return oldcommand(np, cargc, cargv);
+ return CMD_ERROR;
+ }
+
+ if(!strcmp(cargv[0], "noperserv")) {
+ if(special.schedule) {
+ controlreply(np, "Previous attempt at un/reload still in progress.");
+ return CMD_OK;
+ } else {
+ special.modulename = getsstring(cargv[0], strlen(cargv[0]));
+ if(!special.modulename) {
+ controlreply(np, "Unable to copy module name. Seek cow herd to trample on server.");
+ return CMD_ERROR;
+ } else {
+ special.schedule = scheduleoneshot(time(NULL) + 1, reloadhandler, &special);
+ if(!special.schedule) {
+ freesstring(special.modulename);
+ special.modulename = NULL;
+ controlreply(np, "Unable to allocate schedule. Seek cow herd to trample on server.");
+ return CMD_ERROR;
+ }
+ controlreply(np, "Special case un/reload in <1 second, no response will be sent, standby. . .");
+ return CMD_OK;
+ }
+ }
+ } else {
+ if(oldcommand)
+ return oldcommand(np, cargc, cargv);
+ return CMD_ERROR;
+ }
+}
+
+int noperserv_rmmod(void *sender, int cargc, char **cargv) {
+ return noperserv_specialmod(sender, "rmmod", &controlspecialrmmod, cargc, cargv);
+}
+
+int noperserv_reload(void *sender, int cargc, char **cargv) {
+ return noperserv_specialmod(sender, "reload", &controlspecialreloadmod, cargc, cargv);
+}
+
+void noperserv_whois_hook(int hooknum, void *arg) {
+ controlreply(replynick, "%s", (char *)arg);
+}
+
+int noperserv_whois(void *sender, int cargc, char **cargv) {
+ no_autheduser *au;
+ nick *np = (nick *)sender;
+ CommandHandler oldwhois = noperserv_find_hook("whois");
+
+ if(cargc < 1) {
+ if(oldwhois)
+ return oldwhois(sender, cargc, cargv);
+ return CMD_ERROR;
+ }
+
+ if(cargv[0][0] != '#') {
+ if(cargv[0][0] == '*')
+ cargv[0][0] = '#';
+ if(oldwhois)
+ return oldwhois(sender, cargc, cargv);
+ return CMD_ERROR;
+ }
+
+ au = noperserv_get_autheduser(cargv[0] + 1);
+ if(!au) {
+ controlreply(np, "Account not registered.");
+ return CMD_OK;
+ }
+
+ controlreply(np, "Account : %s", au->authname->content);
+
+ replynick = np;
+
+ registerhook(HOOK_CONTROL_WHOISREPLY, &noperserv_whois_hook);
+ noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER, (void *)au);
+ deregisterhook(HOOK_CONTROL_WHOISREPLY, &noperserv_whois_hook);
+
+ controlreply(np, "Flags : %s", printflags(NOGetAuthLevel(au), no_userflags));
+
+ return CMD_OK;
+}
+
+int noperserv_showcommands(void *sender, int cargc, char **cargv) {
+ nick *np = (nick *)sender;
+ Command *cmdlist[100];
+ int i, n;
+
+ n = getcommandlist(controlcmds, cmdlist, 100);
+
+ controlreply(np, "The following commands are registered at present:");
+
+ for(i=0;i<n;i++)
+ controlreply(np, "%s (%s)", cmdlist[i]->command->content, printflags(cmdlist[i]->level, no_commandflags));
+
+ controlreply(np, "End of list.");
+ return CMD_OK;
+}
+
+void noperserv_whois_handler(int hooknum, void *arg) {
+ char message[100];
+ nick *np = (nick *)arg;
+ no_autheduser *au;
+ if(!np)
+ return;
+
+ if(IsAccount(np)) {
+ au = NOGetAuthedUser(np);
+ if(au) {
+ snprintf(message, sizeof(message), "Flags : %s", printflags(NOGetAuthLevel(au), no_userflags));
+ noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER, (void *)au);
+ } else {
+ snprintf(message, sizeof(message), "Flags : (user not known)");
+ noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHNAME, (void *)np->authname);
+ }
+ triggerhook(HOOK_CONTROL_WHOISREPLY, message);
+ }
+}
+
+/* mmm, hacky */
+void noperserv_whois_account_handler(int hooknum, void *arg) {
+ int count = 0, found = 0;
+ char nickbuffer[(NICKLEN + 2) * NO_NICKS_PER_WHOIS_LINE - 1]; /* since we don't need space or comma for the first item we're fine NULL wise */
+ char accountspace[NICKLEN + 3]; /* space, comma, null */
+ char message[1024];
+
+ nickbuffer[0] = '\0';
+ if(hooknum == HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER) {
+ /* we can just read out the authed user linked list */
+ no_autheduser *au = (void *)arg;
+ no_nicklist *nl = au->nick;
+
+ if(nl)
+ found = 1;
+
+ for(;nl;nl=nl->next) {
+ snprintf(accountspace, sizeof(accountspace), "%s%s", count++?", ":"", nl->nick->nick);
+ strlcat(nickbuffer, accountspace, sizeof(nickbuffer));
+
+ if(count >= NO_NICKS_PER_WHOIS_LINE) {
+ snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
+ triggerhook(HOOK_CONTROL_WHOISREPLY, message);
+ nickbuffer[0] = '\0';
+ count = 0;
+ }
+ }
+ } else {
+ /* inefficient way */
+ char *authname = (char *)arg;
+ int i = 0;
+ nick *sp;
+
+ for(;i<NICKHASHSIZE;i++)
+ for(sp=nicktable[i];sp;sp=sp->next)
+ if(IsAccount(sp) && !ircd_strcmp(sp->authname, authname)) {
+ found = 1;
+
+ snprintf(accountspace, sizeof(accountspace), "%s%s", count++?", ":"", sp->nick);
+ strlcat(nickbuffer, accountspace, sizeof(nickbuffer));
+
+ if(count >= NO_NICKS_PER_WHOIS_LINE) {
+ snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
+ triggerhook(HOOK_CONTROL_WHOISREPLY, message);
+ nickbuffer[0] = '\0';
+ count = 0;
+ }
+ }
+ }
+
+ if(!found) {
+ snprintf(message, sizeof(message), "Authed : (no nicks authed)");
+ triggerhook(HOOK_CONTROL_WHOISREPLY, message);
+ } else if(nickbuffer[0]) {
+ snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
+ triggerhook(HOOK_CONTROL_WHOISREPLY, message);
+ }
+}
+
+/* Obviously pinched from control.c */
+void noperserv_handle_messages(nick *target, int messagetype, void **args) {
+ Command *cmd;
+ char *cargv[50];
+ int cargc;
+ nick *sender;
+
+ switch(messagetype) {
+ case LU_PRIVMSG: /* override these two commands only */
+ case LU_SECUREMSG:
+ /* If it's a message, first arg is nick and second is message */
+ sender = (nick *)args[0];
+
+ controlwall(NO_DEVELOPER, NL_ALL_COMMANDS, "From: %s!%s@%s%s%s: %s", sender->nick, sender->ident, sender->host->name->content, IsAccount(sender)?"/":"", IsAccount(sender)?sender->authname:"", (char *)args[1]);
+
+ /* Split the line into params */
+ cargc = splitline((char *)args[1], cargv, 50, 0);
+
+ if(!cargc) /* Blank line */
+ return;
+
+ cmd = findcommandintree(controlcmds,cargv[0],1);
+ if(!cmd) {
+ controlreply(sender, "Unknown command.");
+ return;
+ }
+
+ /* If we were doing "authed user tracking" here we'd put a check in for authlevel */
+ /* Here it is! */
+ if (!noperserv_policy_command_permitted(cmd->level, sender)) {
+ controlreply(sender, "Access denied.");
+ return;
+ }
+
+ /* Check the maxargs */
+ if(cmd->maxparams < (cargc - 1)) {
+ /* We need to do some rejoining */
+ rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams));
+ cargc = (cmd->maxparams) + 1;
+ }
+
+ if((cmd->handler)((void *)sender,cargc-1,&(cargv[1])) == CMD_USAGE)
+ controlhelp(sender, cmd);
+
+ break;
+ default:
+ if(oldhandler)
+ oldhandler(target, messagetype, args);
+ break;
+ }
+}
+
+void noperserv_reply(nick *np, char *format, ...) {
+ char buf[512];
+ va_list va;
+ no_autheduser *au = NOGetAuthedUser(np);
+
+ va_start(va, format);
+ vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+
+ if(au && !(NOGetNoticeLevel(au) & NL_NOTICES)) {
+ controlmessage(np, "%s", buf);
+ } else {
+ controlnotice(np, "%s", buf);
+ }
+}
+
+int noperserv_help(void *sender, int cargc, char **cargv) {
+ Command *cmd;
+ nick *np = (nick *)sender;
+
+ if(cargc < 1)
+ return CMD_USAGE;
+
+ cmd = findcommandintree(controlcmds, cargv[0], 1);
+ if(!cmd) {
+ controlreply(np, "Unknown command.");
+ return CMD_ERROR;
+ }
+
+ if(!noperserv_policy_command_permitted(cmd->level, np)) {
+ controlreply(np, "Access denied.");
+ return CMD_ERROR;
+ }
+
+ controlhelp(np, cmd);
+ return CMD_OK;
+}
+
+void noperserv_wall(flag_t permissionlevel, flag_t noticelevel, char *format, ...) {
+ char buf[512];
+ va_list va;
+ no_autheduser *au = authedusers;
+ no_nicklist *nl;
+ char *flags = printflags(noticelevel, no_noticeflags) + 1;
+
+ va_start(va, format);
+ vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+
+ Error("noperserv", ERR_INFO, "$%s$ %s", flags, buf);
+
+ for(;au;au=au->next) {
+ if(NOGetNoticeLevel(au) & noticelevel) {
+ for(nl=au->nick;nl;nl=nl->next)
+ if(noperserv_policy_command_permitted(permissionlevel, nl->nick))
+ controlreply(nl->nick, "$%s$ %s", flags, buf);
+ }
+ }
+}
--- /dev/null
+void noperserv_setup_hooks(void);\r
+void noperserv_cleanup_hooks(void);\r
--- /dev/null
+#include "../control/control.h"
+#include "noperserv.h"
+#include "noperserv_db.h"
+#include "noperserv_policy.h"
+
+/* command access */
+int noperserv_policy_command_permitted(flag_t level, nick *user) {
+ no_autheduser *au;
+ if(level == __NO_ANYONE)
+ return 1;
+ if((level & __NO_OPERED) && !IsOper(user))
+ return 0;
+ if(level & __NO_AUTHED) {
+ if(!IsAccount(user))
+ return 0;
+ if(level & __NO_ACCOUNT) {
+ if(!(au = NOGetAuthedUser(user)))
+ return 0;
+ if((level & __NO_DEVELOPER) && !NOIsDeveloper(au)) {
+ return 0;
+ } else if((level & __NO_OPER) && !NOIsLeastOper(au)) {
+ return 0;
+ } else if((level & __NO_STAFF) && !NOIsLeastStaff(au)) {
+ return 0;
+ }
+ if ((level & __NO_SEC) && !NOIsLeastSec(au))
+ return 0;
+ if ((level & __NO_TRUST) && !NOIsLeastTrust(au))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* return userflags permitted for each level */
+flag_t noperserv_policy_permitted_noticeflags(no_autheduser *target) {
+ flag_t result = NL_PEONIC_FLAGS;
+ if(NOIsDeveloper(target))
+ result |= NL_DEV_FLAGS;
+ if(NOIsLeastOper(target))
+ result |= NL_OPER_FLAGS;
+ if(NOIsLeastSec(target))
+ result |= NL_SEC_FLAGS;
+ if(NOIsLeastTrust(target))
+ result |= NL_TRUST_FLAGS;
+
+ return result;
+}
+
+/* @logic */
+/* updates target's noticeflags according to their new userflags, unsetting unpermitted and setting new permitted flags */
+void noperserv_policy_update_noticeflags(flag_t fwas, no_autheduser *target) {
+ flag_t newflags = NOGetNoticeLevel(target);
+
+ newflags &= noperserv_policy_permitted_noticeflags(target); /* unset flags we're not supposed to have */
+
+ /* and add flags we're allowed */
+ if(!(fwas & __NO_OPER) && NOIsLeastOper(target))
+ newflags |= NL_OPER_FLAGS;
+ if(!(fwas & __NO_SEC) && NOIsLeastSec(target))
+ newflags |= NL_SEC_FLAGS;
+ if(!(fwas & __NO_TRUST) && NOIsLeastTrust(target))
+ newflags |= NL_TRUST_FLAGS;
+ if(!(fwas & __NO_DEVELOPER) && NOIsDeveloper(target))
+ newflags |= NL_DEV_FLAGS;
+
+ target->noticelevel = newflags;
+}
+
+/* is au allowed to modified targets flags */
+flag_t noperserv_policy_permitted_modifications(no_autheduser *au, no_autheduser *target) {
+ flag_t permitted = 0;
+
+ /* @policy */
+ if(NOIsLeastOper(au)) {
+ permitted |= NO_OPER_FLAGS;
+ if(target == au) /* let opers remove their own oper flag */
+ permitted |= __NO_OPER;
+ }
+ if(target == au) {
+ if(NOIsLeastSec(au))
+ permitted |= __NO_SEC;
+ if(NOIsLeastTrust(au))
+ permitted |= __NO_TRUST;
+ }
+
+ if(NOIsDeveloper(au))
+ permitted |= NO_DEV_FLAGS;
+
+ if((target != au) && NOIsLeastOper(target) && !NOIsDeveloper(au))
+ return 0;
+
+ return permitted;
+}
--- /dev/null
+#ifndef __NOPERSERV_POLICY_H
+#define __NOPERSERV_POLICY_H
+
+int noperserv_policy_command_permitted(flag_t level, nick *user);
+flag_t noperserv_policy_permitted_noticeflags(no_autheduser *target);
+void noperserv_policy_update_noticeflags(flag_t fwas, no_autheduser *target);
+flag_t noperserv_policy_permitted_modifications(no_autheduser *au, no_autheduser *target);
+
+#define NO_DEFAULT_LEVEL 0
+#define NO_FIRST_USER_LEVEL __NO_DEVELOPER | __NO_OPER | __NO_STAFF | NO_DEFAULT_LEVEL
+#define NO_DEFAULT_NOTICELEVEL NL_NOTICES
+#define NO_FIRST_USER_DEFAULT_NOTICELEVEL NL_ALL | NO_DEFAULT_NOTICELEVEL
+
+#define NOIsStaff(user) (NOGetAuthLevel(user) & __NO_STAFF)
+#define NOIsTrust(user) (NOGetAuthLevel(user) & __NO_TRUST)
+#define NOIsSec(user) (NOGetAuthLevel(user) & __NO_SEC)
+#define NOIsOper(user) (NOGetAuthLevel(user) & __NO_OPER)
+#define NOIsDeveloper(user) (NOGetAuthLevel(user) & __NO_DEVELOPER)
+
+#define NOIsLeastStaff(user) (NOGetAuthLevel(user) & (__NO_DEVELOPER | __NO_OPER | __NO_STAFF))
+#define NOIsLeastOper(user) (NOGetAuthLevel(user) & (__NO_OPER | __NO_DEVELOPER))
+#define NOIsLeastTrust(user) (NOGetAuthLevel(user) & (__NO_DEVELOPER | __NO_TRUST))
+#define NOIsLeastSec(user) (NOGetAuthLevel(user) & (__NO_DEVELOPER | __NO_SEC))
+
+#define NL_PEONIC_FLAGS NL_NOTICES
+#define NL_ALL NL_MANAGEMENT | NL_TRUSTS | NL_KICKS | NL_KILLS | NL_GLINES | NL_HITS | NL_CLONING | NL_CLEARCHAN | NL_FAKEUSERS | NL_BROADCASTS | NL_OPERATIONS | NL_OPERING | NL_ALL_COMMANDS
+#define NL_OPER_FLAGS NL_MANAGEMENT | NL_TRUSTS | NL_KICKS | NL_KILLS | NL_GLINES | NL_HITS | NL_CLONING | NL_CLEARCHAN | NL_FAKEUSERS | NL_BROADCASTS | NL_OPERATIONS | NL_OPERING
+#define NL_SEC_FLAGS NL_CLONING
+#define NL_TRUST_FLAGS NL_TRUSTS | NL_CLONING
+#define NL_DEV_FLAGS NL_ALL_COMMANDS
+
+#endif
}
/*
- * addcommandtotree:
+ * addcommandhelptotree:
*
- * This installs a specific command in a tree.
+ * This installs a specific command in a tree, with a help paramater.
*
* This function builds the Command structure in addition to
* installing it in the tree
*/
-Command *addcommandtotree(CommandTree *ct, const char *cmdname, int level, int maxparams, CommandHandler handler) {
+Command *addcommandhelptotree(CommandTree *ct, const char *cmdname, int level, int maxparams, CommandHandler handler, const char *help) {
Command *nc, *c;
int i;
nc->handler=handler;
nc->ext=NULL;
nc->next=NULL;
-
+ if (help) {
+ int len=strlen(help);
+ nc->help=(char *)malloc(len+1);
+ if(nc->help) {
+ strncpy(nc->help, help, len);
+ nc->help[len] = '\0';
+ }
+ } else {
+ nc->help=NULL;
+ }
+
/* Sanity check the string */
for (i=0;i<nc->command->length;i++) {
nc->command->content[i]=toupper(nc->command->content[i]);
if (nc->command->content[i]<'A' || nc->command->content[i]>'Z') {
/* Someone tried to register an invalid command name */
freesstring(nc->command);
+ if(nc->help)
+ free(nc->help);
free(nc);
return NULL;
}
} else if (insertcommand(nc,ct,0)) {
/* Erk, that didn't work.. */
freesstring(nc->command);
+ if(nc->help)
+ free(nc->help);
free(nc);
return NULL;
}
c=*ch;
(*ch)=(Command *)((*ch)->next);
freesstring(c->command);
+ if(c->help)
+ free(c->help);
free(c);
return 0;
}
c=*ch;
(*ch)=(Command *)((*ch)->next);
freesstring(c->command);
+ if(c->help)
+ free(c->help);
free(c);
return 0;
}
#define CMD_OK 0
#define CMD_ERROR 1
#define CMD_LAST 2
+#define CMD_USAGE 3
/* Generic CommandHandler type
* void * = pointer to some relevant object to identify where the message came from
typedef struct Command {
sstring *command; /* Name of the command/token/thing */
+ char *help; /* Help information, sorry splidge! */
int level; /* "level" required to use the command/token/thing */
int maxparams; /* Maximum number of parameters for the command/token/thing */
CommandHandler handler; /* Function to deal with the message */
CommandTree *newcommandtree();
void destroycommandtree(CommandTree *ct);
-Command *addcommandtotree(CommandTree *ct, const char *cmdname, int level, int maxparams, CommandHandler handler);
+Command *addcommandhelptotree(CommandTree *ct, const char *cmdname, int level, int maxparams, CommandHandler handler, const char *help);
int deletecommandfromtree(CommandTree *ct, const char *cmdname, CommandHandler handler);
Command *findcommandintree(CommandTree *ct, const char *cmdname, int strictcheck);
int getcommandlist(CommandTree *ct, Command **commandlist, int maxcommands);
+#define addcommandtotree(a, b, c, d, e) addcommandhelptotree(a, b, c, d, e, NULL)
+
#endif
--- /dev/null
+
+.PHONY: all
+all: pqsql.so
+
+pqsql.so: pqsql.o
+ ld -shared -Bdynamic ${LIBPGSQL} -o $@ $^
+
--- /dev/null
+/*
+ * PQSQL module
+ *
+ * 99% of the handling is stolen from Q9.
+ */
+
+#include "../core/config.h"
+#include "../core/error.h"
+#include "../irc/irc_config.h"
+#include "../core/events.h"
+#include "../core/hooks.h"
+#include "pqsql.h"
+
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <stdarg.h>
+
+typedef struct pqasyncquery_s {
+ sstring *query;
+ void *tag;
+ PQQueryHandler handler;
+ int flags;
+ struct pqasyncquery_s *next;
+} pqasyncquery_s;
+
+pqasyncquery_s *queryhead = NULL, *querytail = NULL;
+
+int dbconnected = 0;
+PGconn *dbconn;
+
+void dbhandler(int fd, short revents);
+void dbstatus(int hooknum, void *arg);
+void disconnectdb(void);
+void connectdb(void);
+
+void _init(void) {
+ connectdb();
+}
+
+void _fini(void) {
+ disconnectdb();
+}
+
+void connectdb(void) {
+ sstring *dbhost, *dbusername, *dbpassword, *dbdatabase, *dbport;
+ char connectstr[1024];
+
+ if(pqconnected())
+ return;
+
+ /* stolen from chanserv as I'm lazy */
+ dbhost = getcopyconfigitem("pqsql", "host", "localhost", HOSTLEN);
+ dbusername = getcopyconfigitem("pqsql", "username", "newserv", 20);
+ dbpassword = getcopyconfigitem("pqsql", "password", "moo", 20);
+ dbdatabase = getcopyconfigitem("pqsql", "database", "newserv", 20);
+ dbport = getcopyconfigitem("pqsql", "port", "431", 8);
+
+ if(!dbhost || !dbusername || !dbpassword || !dbdatabase || !dbport) {
+ /* freesstring allows NULL */
+ freesstring(dbhost);
+ freesstring(dbusername);
+ freesstring(dbpassword);
+ freesstring(dbdatabase);
+ freesstring(dbport);
+ return;
+ }
+
+ snprintf(connectstr, sizeof(connectstr), "dbname=%s user=%s password=%s", dbdatabase->content, dbusername->content, dbpassword->content);
+
+ freesstring(dbhost);
+ freesstring(dbusername);
+ freesstring(dbpassword);
+ freesstring(dbdatabase);
+ freesstring(dbport);
+
+ Error("pqsql", ERR_INFO, "Attempting database connection: %s", connectstr);
+
+ /* Blocking connect for now.. */
+ dbconn = PQconnectdb(connectstr);
+
+ if (!dbconn || (PQstatus(dbconn) != CONNECTION_OK))
+ return;
+
+ Error("pqsql", ERR_INFO, "Connected!");
+
+ dbconnected = 1;
+
+ PQsetnonblocking(dbconn, 1);
+
+ /* this kicks ass, thanks splidge! */
+ registerhandler(PQsocket(dbconn), POLLIN, dbhandler);
+ registerhook(HOOK_CORE_STATSREQUEST, dbstatus);
+}
+
+void dbhandler(int fd, short revents) {
+ PGresult *res;
+ pqasyncquery_s *qqp;
+
+ if(revents & POLLIN) {
+ PQconsumeInput(dbconn);
+
+ if(!PQisBusy(dbconn)) { /* query is complete */
+ if(queryhead->handler)
+ (queryhead->handler)(dbconn, queryhead->tag);
+
+ while((res = PQgetResult(dbconn))) {
+ switch(PQresultStatus(res)) {
+ case PGRES_TUPLES_OK:
+ Error("pqsql", ERR_WARNING, "Unhandled tuples output (query: %s)", queryhead->query->content);
+ break;
+
+ case PGRES_NONFATAL_ERROR:
+ case PGRES_FATAL_ERROR:
+ /* if a create query returns an error assume it went ok, paul will winge about this */
+ if(!(queryhead->flags & QH_CREATE))
+ Error("pqsql", ERR_WARNING, "Unhandled error response (query: %s)", queryhead->query->content);
+ break;
+
+ default:
+ break;
+ }
+
+ PQclear(res);
+ }
+
+ /* Free the query and advance */
+ qqp = queryhead;
+ if(queryhead == querytail)
+ querytail = NULL;
+
+ queryhead = queryhead->next;
+
+ freesstring(qqp->query);
+ free(qqp);
+
+ if(queryhead) { /* Submit the next query */
+ PQsendQuery(dbconn, queryhead->query->content);
+ PQflush(dbconn);
+ }
+ }
+ }
+}
+
+/* sorry Q9 */
+void pqasyncqueryf(PQQueryHandler handler, void *tag, int flags, char *format, ...) {
+ char querybuf[8192];
+ va_list va;
+ int len;
+ pqasyncquery_s *qp;
+
+ if(!pqconnected())
+ return;
+
+ va_start(va, format);
+ len = vsnprintf(querybuf, sizeof(querybuf), format, va);
+ va_end(va);
+
+ /* PPA: no check here... */
+ qp = (pqasyncquery_s *)malloc(sizeof(pqasyncquery_s));
+ if(!qp)
+ return;
+
+ qp->query = getsstring(querybuf, len);
+ qp->tag = tag;
+ qp->handler = handler;
+ qp->next = NULL; /* shove them at the end */
+ qp->flags = flags;
+
+ if(querytail) {
+ querytail->next = qp;
+ querytail = qp;
+ } else {
+ querytail = queryhead = qp;
+ PQsendQuery(dbconn, qp->query->content);
+ PQflush(dbconn);
+ }
+}
+
+void disconnectdb(void) {
+ pqasyncquery_s *qqp = queryhead, *nqqp;
+
+ if(!pqconnected())
+ return;
+
+ /* do this first else we may get conflicts */
+ deregisterhandler(PQsocket(dbconn), 0);
+
+ /* Throw all the queued queries away, beware of data malloc()ed inside the query item.. */
+ while(qqp) {
+ nqqp = qqp->next;
+ freesstring(qqp->query);
+ free(qqp);
+ qqp = nqqp;
+ }
+
+ deregisterhook(HOOK_CORE_STATSREQUEST, dbstatus);
+ PQfinish(dbconn);
+ dbconn = NULL; /* hmm? */
+
+ dbconnected = 0;
+}
+
+/* more stolen code from Q9 */
+void dbstatus(int hooknum, void *arg) {
+ if ((int)arg > 10) {
+ int i = 0;
+ pqasyncquery_s *qqp;
+ char message[100];
+
+ if(queryhead)
+ for(qqp=queryhead;qqp;qqp=qqp->next)
+ i++;
+
+ snprintf(message, sizeof(message), "PQSQL : %6d database queries queued.",i);
+
+ triggerhook(HOOK_CORE_STATSREPLY, message);
+ }
+}
+
+int pqconnected(void) {
+ return dbconnected;
+}
--- /dev/null
+#ifndef __PQSQL_DB_H
+#define __PQSQL_DB_H
+
+#include <libpq-fe.h>
+
+#define QH_CREATE 0x01
+
+typedef void (*PQQueryHandler)(PGconn *, void *);
+
+void pqasyncqueryf(PQQueryHandler handler, void *tag, int flags, char *format, ...);
+
+#define pqasyncquery(handler, tag, format, ...) pqasyncqueryf(handler, tag, 0, format , ##__VA_ARGS__)
+#define pqcreatequery(format, ...) pqasyncqueryf(NULL, NULL, QH_CREATE, format , ##__VA_ARGS__)
+#define pqquery(format, ...) pqasyncquery(NULL, NULL, format , ##__VA_ARGS__)
+
+int pqconnected(void);
+
+#endif
rg_logevent(np, "regexgline", "%s %d %d %s", cargv[0], expiry, count, cargv[3]);
controlreply(np, "Added regexgline: %s (expires in: %s, hit %d user%s): %s", cargv[0], expirybuf, count, (count!=1)?"s":"", cargv[3]);
- controlnoticeopers("%s added regexgline: %s (expires in: %s, hit %d user%s): %s", np->nick, cargv[0], expirybuf, count, (count!=1)?"s":"", cargv[3]);
+ controlwall(NO_OPER, NL_GLINES, "%s added regexgline: %s (expires in: %s, hit %d user%s): %s", np->nick, cargv[0], expirybuf, count, (count!=1)?"s":"", cargv[3]);
return CMD_OK;
}
}
if (count > 0) {
controlreply(np, "Deleted (matched: %d).", count);
- controlnoticeopers("%s removed regexgline: %s (matches: %d)", np->nick, cargv[0], count);
+ controlwall(NO_OPER, NL_GLINES, "%s removed regexgline: %s (matches: %d)", np->nick, cargv[0], count);
} else {
controlreply(np, "No glines matched: %s", cargv[0]);
}