]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Merged revisions 249 via svnmerge from
authorChris Porter <redacted>
Mon, 31 Oct 2005 14:44:00 +0000 (14:44 +0000)
committerChris Porter <redacted>
Mon, 31 Oct 2005 14:44:00 +0000 (14:44 +0000)
https://svn.quakenet.org/svn/dev-com/N/trunk

........
r249 | slug | 2005-10-31 14:43:35 +0000 (Mon, 31 Oct 2005) | 2 lines

Damned constants.

........

28 files changed:
carrot/carrot.c
chansearch/chansearch.c
chanstats/chansearch.c
control/control.c
control/control.h
core/hooks.h
countusers/countusers.c
fsck/fsck.c
horse/horse.c
lameisp/lameisp.c
lib/sha1.c
newsearch/newsearch.c
nick/nickhandlers.c
noperserv/Makefile [new file with mode: 0644]
noperserv/noperserv.c [new file with mode: 0644]
noperserv/noperserv.h [new file with mode: 0644]
noperserv/noperserv_commands.c [new file with mode: 0644]
noperserv/noperserv_db.c [new file with mode: 0644]
noperserv/noperserv_db.h [new file with mode: 0644]
noperserv/noperserv_hooks.c [new file with mode: 0644]
noperserv/noperserv_hooks.h [new file with mode: 0644]
noperserv/noperserv_policy.c [new file with mode: 0644]
noperserv/noperserv_policy.h [new file with mode: 0644]
noperserv/noperserv_psql.c [new file with mode: 0644]
noperserv/noperserv_psql.h [new file with mode: 0644]
parser/parser.c
parser/parser.h
regexgline/regexgline.c

index ce89788acbf533d40c692bc4bcea1a962f37228e..e39bef28f1105c0bcfb697caa2db72230969894f 100644 (file)
@@ -7,10 +7,8 @@ int ca_carrot(void *source, int cargc, char **cargv) {
   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);
@@ -25,14 +23,13 @@ int ca_carrot(void *source, int cargc, char **cargv) {
     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() {
index 734c884bf5b00475219b2fc2a86894bb91b96b1b..4adfcc7b6eafe61dea97452f99a8510b4d10d451 100644 (file)
@@ -56,7 +56,7 @@ void _init() {
   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() {
index bb0d3c1e656ed59b14a4953a8e2b0763c75acdb2..3f4564a2f1e3ec2009c43eb96b613a1356a6c9fc 100644 (file)
@@ -46,7 +46,10 @@ void initchansearch() {
   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() {
@@ -73,12 +76,8 @@ int dochansearch(void *source, int cargc, char **cargv) {
   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]=='!') {
index de8b031b9cac5b2637c85d76544a93a9730158e6..ed07a99441b16f89c3b9f64facaf71d8dcb99de1 100644 (file)
 #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);
@@ -39,32 +41,35 @@ int controlchannel(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) {
@@ -82,6 +87,7 @@ void controlconnect(void *arg) {
   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");
@@ -98,13 +104,13 @@ void controlconnect(void *arg) {
 }
 
 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);
@@ -125,55 +131,63 @@ int controlrehash(void *sender, int cargc, char **cargv) {
   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;
@@ -185,7 +199,7 @@ int controlwhois(void *sender, int cargc, char **cargv) {
         if (strlen(buf)==0) {
           break;
         } else {
-          sendmessagetouser(mynick,(nick *)sender,"Channels  : %s",buf);
+          controlreply((nick *)sender,"Channels  : %s",buf);
           buf[0]='\0';
           i--;
         }
@@ -197,47 +211,43 @@ int controlwhois(void *sender, int cargc, char **cargv) {
 }
 
 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;
   }
 }
@@ -248,23 +258,21 @@ int controllsmod(void *sender, int cargc, char **cargv) {
 
   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);
@@ -272,8 +280,8 @@ int controlreload(void *sender, int cargc, char **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]);
@@ -284,8 +292,8 @@ int relink(void *sender, int cargc, char **cargv) {
 
 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]);
@@ -302,13 +310,11 @@ int controlchannel(void *sender, int cargc, char **cargv) {
   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;
   }
   
@@ -316,14 +322,14 @@ int controlchannel(void *sender, int cargc, char **cargv) {
     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;
@@ -332,7 +338,7 @@ int controlchannel(void *sender, int cargc, char **cargv) {
   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);
@@ -350,7 +356,7 @@ int controlchannel(void *sender, int cargc, char **cargv) {
   }
     
   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;
 }
@@ -365,7 +371,7 @@ int controlshowcommands(void *sender, int cargc, char **cargv) {
   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.");
@@ -396,12 +402,12 @@ void handlemessages(nick *target, int messagetype, void **args) {
                
       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;
       }
       
@@ -414,7 +420,8 @@ void handlemessages(nick *target, int messagetype, void **args) {
         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:
@@ -428,7 +435,7 @@ void handlemessages(nick *target, int messagetype, void **args) {
   }
 }
 
-void controlreply(nick *target, char *message, ... ) {
+void controlmessage(nick *target, char *message, ... ) {
   char buf[512];
   va_list va;
     
@@ -473,13 +480,78 @@ void controlnotice(nick *target, char *message, ... ) {
   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);
index bbc63c4d37ddf795a7f9671bce5f43976ca4e491..248e8970a7d7dc596be960577145a7d74c06aeca 100644 (file)
@@ -6,11 +6,84 @@
 #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  
index 483574f72ad729b9e98b1449325aeef113f99b00..1c256d394b1a3193d898aa590bf832c4079d4900 100644 (file)
@@ -27,6 +27,7 @@
 #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();
index 2c3e3ee7ec8774145f1e424dab5a1be85201465f..31826ee7f6a4c4f3daa1c4430c8e4dd3ab6dc01f 100644 (file)
@@ -7,13 +7,11 @@
 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=='@') {
@@ -51,7 +49,7 @@ int do_countusers(void *source, int cargc, char **cargv) {
 } 
 
 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() {
index 5cec1c915409898ce603177927337254bb67858f..1f5bda035f42e8434b4ec75aefa48aba88e6bc4a 100644 (file)
@@ -8,7 +8,7 @@
 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() {
index d3c347d620c0a557cad38969224e20ede0ad4c5d..67d7206775223b75bf65fafa7d9bd4338430ccb8 100644 (file)
@@ -7,10 +7,8 @@ int ho_horse(void *source, int cargc, char **cargv) {
   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,"       _ ___,;;;^");
@@ -32,7 +30,7 @@ int ho_horse(void *source, int cargc, char **cargv) {
 }
 
 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() {
index 993f2d9e762b2e3559cf5ed671f026bd61a3a913..92957d74980f8f6681b20c1bd9eb6758da026a1e 100644 (file)
@@ -36,7 +36,7 @@ void _init() {
               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);
 }
 
@@ -68,4 +68,4 @@ int li_stats(void *source, int cargc, char **cargv) {
   controlreply((nick *)source, "Victims: %d clients", li_victims);
   
   return CMD_OK;
-}
\ No newline at end of file
+}
index 52cde648f490037306d7b8dcb259765562790139..2172392fa8e09c2bb144001011d9959fc8c7ee08 100644 (file)
@@ -48,6 +48,14 @@ static char rcsid[] = "$OpenBSD: sha1.c,v 1.12 2003/07/21 20:37:08 millert Exp $
 #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];
index 466559ced750ffcf19d2796b9b7244dccedea219..85dd2bd823395520b91d83720d19528a489eae32 100644 (file)
@@ -47,7 +47,7 @@ void _init() {
   /* 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() {
@@ -78,10 +78,8 @@ int do_nicksearch(void *source, int cargc, char **cargv) {
   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 */
@@ -92,7 +90,7 @@ int do_nicksearch(void *source, int cargc, char **cargv) {
       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;
index 6d467e00687b66cde859a6352819291e31bcb139..037edc1a3a9cb56b83a0a15e5647f64a18d4ce67 100644 (file)
@@ -239,6 +239,12 @@ int handleusermodemsg(void *source, int cargc, char **cargv) {
       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 */
diff --git a/noperserv/Makefile b/noperserv/Makefile
new file mode 100644 (file)
index 0000000..3702203
--- /dev/null
@@ -0,0 +1,9 @@
+
+.PHONY: all
+all: noperserv.so noperserv_commands.so
+
+noperserv.so: noperserv.o noperserv_psql.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 $@ $^
diff --git a/noperserv/noperserv.c b/noperserv/noperserv.c
new file mode 100644 (file)
index 0000000..cd8f17d
--- /dev/null
@@ -0,0 +1,472 @@
+/* 
+ * 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 "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, ...);
+
+void _init() {
+  noperserv_ext = registernickext("noperserv");
+
+  noperserv_load_db();
+
+  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);
+}
+
+#ifdef BROKEN_DLCLOSE
+void __fini() {
+#else
+void _fini() {
+#endif
+  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:"");
+  }
+}
diff --git a/noperserv/noperserv.h b/noperserv/noperserv.h
new file mode 100644 (file)
index 0000000..1297db9
--- /dev/null
@@ -0,0 +1,22 @@
+#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  
diff --git a/noperserv/noperserv_commands.c b/noperserv/noperserv_commands.c
new file mode 100644 (file)
index 0000000..be30344
--- /dev/null
@@ -0,0 +1,140 @@
+#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
diff --git a/noperserv/noperserv_db.c b/noperserv/noperserv_db.c
new file mode 100644 (file)
index 0000000..b2bb95f
--- /dev/null
@@ -0,0 +1,269 @@
+/* 
+ * 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 "noperserv.h"
+#include "noperserv_psql.h"
+#include "noperserv_db.h"
+
+#include <libpq-fe.h>
+#include <stdlib.h>
+
+int dontclose = 0;
+int odb_connected = 0; /* seperate from the db one */
+unsigned long loadedusers = 0;
+
+unsigned long lastuserid;
+
+no_autheduser *authedusers = NULL;
+
+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);
+void noperserv_create_tables(void);
+
+void noperserv_load_db(void) {
+  if(odb_connected) {
+    dontclose = 1;
+    noperserv_cleanup_db();
+  } else {
+    if(noperserv_connect_db(&noperserv_create_tables)) {
+      Error("noperserv", ERR_ERROR, "Unable to connect to database!");
+      return;
+    }
+
+    odb_connected = 1;
+  }
+
+  authedusers = NULL;
+
+  noperserv_async_query(noperserv_load_users, NULL,
+    "SELECT ID, authname, flags, noticelevel FROM users");
+}
+
+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) {
+  noperserv_sync_query(
+    "CREATE TABLE 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;
+  }
+
+  /* other stuff */
+  if(!dontclose && odb_connected)
+    noperserv_disconnect_db();
+
+  dontclose = 0;
+}
+
+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)
+    noperserv_query("DELETE FROM 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);
+    noperserv_query("INSERT INTO users (id, authname, flags, noticelevel) VALUES (%lu,'%s',%lu,%lu)", au->id, au->authname->content, NOGetAuthLevel(au), NOGetNoticeLevel(au));
+    au->newuser = 0;
+  } else {
+    noperserv_query("UPDATE 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;
+    }
+}
diff --git a/noperserv/noperserv_db.h b/noperserv/noperserv_db.h
new file mode 100644 (file)
index 0000000..49d6f3d
--- /dev/null
@@ -0,0 +1,35 @@
+#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;
+
+void 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
diff --git a/noperserv/noperserv_hooks.c b/noperserv/noperserv_hooks.c
new file mode 100644 (file)
index 0000000..c0d0238
--- /dev/null
@@ -0,0 +1,460 @@
+#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);
+    }
+  }
+}
diff --git a/noperserv/noperserv_hooks.h b/noperserv/noperserv_hooks.h
new file mode 100644 (file)
index 0000000..9cc39dd
--- /dev/null
@@ -0,0 +1,2 @@
+void noperserv_setup_hooks(void);\r
+void noperserv_cleanup_hooks(void);\r
diff --git a/noperserv/noperserv_policy.c b/noperserv/noperserv_policy.c
new file mode 100644 (file)
index 0000000..c7fdffe
--- /dev/null
@@ -0,0 +1,95 @@
+#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;
+}
diff --git a/noperserv/noperserv_policy.h b/noperserv/noperserv_policy.h
new file mode 100644 (file)
index 0000000..169d730
--- /dev/null
@@ -0,0 +1,32 @@
+#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
diff --git a/noperserv/noperserv_psql.c b/noperserv/noperserv_psql.c
new file mode 100644 (file)
index 0000000..4e6159d
--- /dev/null
@@ -0,0 +1,222 @@
+/* 
+ * NOperserv v0.01
+ *
+ * A replacement for Germania's ageing Operservice2
+ * PSQL functions
+ *
+ * Copyright (C) 2005 Chris Porter.
+ * 99% of the PGSQL handling is stolen from Q9, copyright (C) David Mansell.
+ */
+
+#include "../core/config.h"
+#include "../core/error.h"
+#include "../irc/irc_config.h"
+#include "../core/events.h"
+#include "../core/hooks.h"
+#include "noperserv_psql.h"
+
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <stdarg.h>
+
+typedef struct no_asyncquery {
+  sstring *query;
+  void *tag;
+  NoQueryHandler handler;
+  struct no_asyncquery *next;
+} no_asyncquery;
+
+no_asyncquery *queryhead = NULL, *querytail = NULL;
+
+int db_connected = 0;
+PGconn *no_dbconn;
+
+void noperserv_db_handler(int fd, short revents);
+void noperserv_db_status(int hooknum, void *arg);
+
+int noperserv_connect_db(NoCreateHandler createtables) {
+  sstring *dbhost, *dbusername, *dbpassword, *dbdatabase, *dbport;
+  char connectstr[1024];
+
+  if(db_connected)
+    return 1;
+
+  /* stolen from chanserv as I'm lazy */
+  dbhost = getcopyconfigitem("noperserv", "dbhost", "localhost", HOSTLEN);
+  dbusername = getcopyconfigitem("noperserv", "dbusername", "noperserv", 20);
+  dbpassword = getcopyconfigitem("noperserv", "dbpassword", "moo", 20);
+  dbdatabase = getcopyconfigitem("noperserv", "dbdatabase", "noperserv", 20);
+  dbport = getcopyconfigitem("noperserv", "dbport", "3306", 8);
+
+  if(!dbhost || !dbusername || !dbpassword || !dbdatabase || !dbport) {
+    /* freesstring allows NULL */
+    freesstring(dbhost);
+    freesstring(dbusername);
+    freesstring(dbpassword);
+    freesstring(dbdatabase);
+    freesstring(dbport);
+    return 2;
+  }
+
+  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("noperserv", ERR_INFO, "Attempting database connection: %s", connectstr);
+
+  /* Blocking connect for now.. */
+  no_dbconn = PQconnectdb(connectstr);
+  
+  if (!no_dbconn || (PQstatus(no_dbconn) != CONNECTION_OK))
+    return 1;
+
+  db_connected = 1;
+
+  if(createtables)
+    createtables();
+
+  PQsetnonblocking(no_dbconn, 1);
+
+  /* this kicks ass, thanks splidge! */
+  registerhandler(PQsocket(no_dbconn), POLLIN, noperserv_db_handler);
+  registerhook(HOOK_CORE_STATSREQUEST, noperserv_db_status);
+
+  return 0;
+}
+
+void noperserv_db_handler(int fd, short revents) {
+  PGresult *res;
+  no_asyncquery *qqp;
+
+  if(revents & POLLIN) {
+    PQconsumeInput(no_dbconn);
+    
+    if(!PQisBusy(no_dbconn)) { /* Query is complete */
+      if(queryhead->handler)
+        (queryhead->handler)(no_dbconn, queryhead->tag);
+
+      while((res = PQgetResult(no_dbconn))) {
+        switch(PQresultStatus(res)) {
+          case PGRES_TUPLES_OK:
+            Error("noperserv", ERR_WARNING, "Unhandled tuples output (query: %s)", queryhead->query->content);
+            break;
+
+          case PGRES_NONFATAL_ERROR:
+          case PGRES_FATAL_ERROR:
+            Error("noperserv", 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(no_dbconn, queryhead->query->content);
+        PQflush(no_dbconn);
+      }
+    }
+  }
+}
+
+/* sorry Q9 */
+void noperserv_async_query(NoQueryHandler handler, void *tag, char *format, ...) {
+  char querybuf[8192];
+  va_list va;
+  int len;
+  no_asyncquery *qp;
+
+  if(!db_connected)
+    return;
+
+  va_start(va, format);
+  len = vsnprintf(querybuf, sizeof(querybuf), format, va);
+  va_end(va);
+
+  qp = (no_asyncquery *)malloc(sizeof(no_asyncquery));
+  qp->query = getsstring(querybuf, len);
+  qp->tag = tag;
+  qp->handler = handler;
+  qp->next = NULL; /* shove them at the end */
+
+  if(querytail) {
+    querytail->next = qp;
+    querytail = qp;
+  } else {
+    querytail = queryhead = qp;
+    PQsendQuery(no_dbconn, qp->query->content);
+    PQflush(no_dbconn);
+  }
+}
+
+void noperserv_sync_query(char *format, ...){
+  char querybuf[8192];
+  va_list va;
+  int len;
+
+  if(!db_connected)
+    return;
+
+  va_start(va, format);
+  len = vsnprintf(querybuf, sizeof(querybuf), format, va);
+  va_end(va);
+
+  PQclear(PQexec(no_dbconn, querybuf));
+}
+
+void noperserv_disconnect_db(void) {
+  no_asyncquery *qqp = queryhead, *nqqp;
+
+  if(!db_connected)
+    return;
+
+  /* do this first else we may get conflicts */
+  deregisterhandler(PQsocket(no_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, noperserv_db_status);
+  PQfinish(no_dbconn);
+  no_dbconn = NULL; /* hmm? */
+
+  db_connected = 0;
+}
+
+/* more stolen code from Q9 */
+void noperserv_db_status(int hooknum, void *arg) {
+  if ((int)arg > 10) {
+    int i = 0;
+    no_asyncquery *qqp;
+    char message[100];
+
+    if(queryhead)
+      for(qqp=queryhead;qqp;qqp=qqp->next)
+        i++;
+     
+    snprintf(message, sizeof(message), "NOServ  : %6d database queries queued.",i);
+    
+    triggerhook(HOOK_CORE_STATSREPLY, message);
+  }  
+}
diff --git a/noperserv/noperserv_psql.h b/noperserv/noperserv_psql.h
new file mode 100644 (file)
index 0000000..66124e5
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __NOPERSERV_DB_H
+#define __NOPERSERV_DB_H
+
+#include <libpq-fe.h>
+
+typedef void (*NoQueryHandler)(PGconn *, void *);
+typedef void (*NoCreateHandler)(void);
+
+void noperserv_async_query(NoQueryHandler handler, void *tag, char *format, ...);
+#define noperserv_query(format, ...) noperserv_async_query(NULL, NULL, format, __VA_ARGS__)
+void noperserv_sync_query(char *format, ...);
+void noperserv_disconnect_db(void);
+int noperserv_connect_db(NoCreateHandler createtables);
+
+#endif
index 125f9c0072b1e19a94b4091df112d2e7d9add843..90111f40e949db543f24846daa464ebb44ac988e 100644 (file)
@@ -74,15 +74,15 @@ int countcommandtree(CommandTree *ct) {
 }
 
 /* 
- * 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;
   
@@ -94,13 +94,25 @@ Command *addcommandtotree(CommandTree *ct, const char *cmdname, int level, int m
   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;    
     }
@@ -114,6 +126,8 @@ Command *addcommandtotree(CommandTree *ct, const char *cmdname, int level, int m
   } else if (insertcommand(nc,ct,0)) {
     /* Erk, that didn't work.. */
     freesstring(nc->command);
+    if(nc->help)
+      free(nc->help);
     free(nc);
     return NULL;
   }
@@ -207,6 +221,8 @@ int deletecommand(sstring *cmdname, CommandTree *ct, int depth, CommandHandler h
         c=*ch;
         (*ch)=(Command *)((*ch)->next);
         freesstring(c->command);
+        if(c->help)
+          free(c->help);
         free(c);
         return 0;
       }
@@ -224,6 +240,8 @@ int deletecommand(sstring *cmdname, CommandTree *ct, int depth, CommandHandler h
         c=*ch;
         (*ch)=(Command *)((*ch)->next);
         freesstring(c->command);
+        if(c->help)
+          free(c->help);
         free(c);
         return 0;
       }
index bce50aa30cf01aa1045b8535c861169dc2e18fb9..1aa030548ea465acd18e788818e215f11a23af3d 100644 (file)
@@ -21,6 +21,7 @@
 #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
@@ -32,6 +33,7 @@ typedef int (*CommandHandler)(void *, int, char**);
  
 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 */
@@ -47,9 +49,11 @@ typedef struct CommandTree {
 
 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
index 09c9501185d80f1545b9618ab6e839d0eca04437..add5e0540050939aca431d8edecdef1d7786bc39 100644 (file)
@@ -293,7 +293,7 @@ int rg_gline(void *source, int cargc, char **cargv) {
 
   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;
 }
@@ -372,7 +372,7 @@ int rg_delgline(void *source, int cargc, char **cargv) {
   }
   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]);
   }