]> jfr.im git - irc/quakenet/newserv.git/blame - control/control.c
Merged revisions 253 via svnmerge from
[irc/quakenet/newserv.git] / control / control.c
CommitLineData
c86edd1d
Q
1/*
2 * This is the first client module for newserv :)
3 *
4 * A very simple bot which should give people some ideas for how to
5 * implement stuff on this thing
6 */
7
8#include "../irc/irc_config.h"
9#include "../parser/parser.h"
10#include "../localuser/localuser.h"
11#include "../localuser/localuserchannel.h"
12#include "../nick/nick.h"
13#include "../lib/sstring.h"
14#include "../core/config.h"
15#include "../irc/irc.h"
16#include "../lib/splitline.h"
17#include "../channel/channel.h"
18#include "../lib/flags.h"
19#include "../core/schedule.h"
20#include "../lib/base64.h"
21#include "../core/modules.h"
22#include "control.h"
23
24#include <stdio.h>
25#include <string.h>
26#include <stdarg.h>
27
38cee035 28nick *hooknick;
c86edd1d 29
38cee035 30nick *mynick;
c86edd1d 31
38cee035
CP
32CommandTree *controlcmds;
33ControlMsg controlreply;
34ControlWall controlwall;
c86edd1d
Q
35
36void handlemessages(nick *target, int messagetype, void **args);
37int controlstatus(void *sender, int cargc, char **cargv);
38void controlconnect(void *arg);
39int controlwhois(void *sender, int cargc, char **cargv);
40int controlchannel(void *sender, int cargc, char **cargv);
41int relink(void *sender, int cargc, char **cargv);
42int die(void *sender, int cargc, char **cargv);
43int controlinsmod(void *sender, int cargc, char **cargv);
1fab6211 44int controllsmod(void *sender, int cargc, char **cargv);
c86edd1d 45int controlrehash(void *sender, int cargc, char **cargv);
c86edd1d 46int controlreload(void *sender, int cargc, char **cargv);
38cee035
CP
47int controlhelpcmd(void *sender, int cargc, char **cargv);
48void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...);
c86edd1d
Q
49
50void _init() {
51 controlcmds=newcommandtree();
38cee035
CP
52 controlreply=&controlmessage;
53 controlwall=&controlnoticeopers;
54
55 registercontrolhelpcmd("status",NO_DEVELOPER,1,&controlstatus,"Usage: status ?level?\nDisplays status information, increasing level gives more verbose information.");
56 registercontrolhelpcmd("whois",NO_OPERED,1,&controlwhois,"Usage: whois <nickname|#numeric>\nDisplays lots of information about the specified nickname or numeric.");
57 registercontrolhelpcmd("channel",NO_OPER,1,&controlchannel,"Usage: channel <#channel>\nDisplays channel information.");
58 registercontrolhelpcmd("relink",NO_DEVELOPER,1,&relink,"Usage: relink\nRelinks service to the network.");
59 registercontrolhelpcmd("die",NO_DEVELOPER,1,&die,"Usage: die <reason>\nTerminates the service.");
60 registercontrolhelpcmd("insmod",NO_DEVELOPER,1,&controlinsmod,"Usage: insmod <module>\nAdds a module to the running instance.");
61 registercontrolhelpcmd("rmmod",NO_DEVELOPER,1,&controlrmmod,"Usage: rmmod <module>\nRemoves a module from the running instance.");
62 registercontrolhelpcmd("lsmod",NO_DEVELOPER,0,&controllsmod,"Usage: lsmod\nLists currently running modules.");
63 registercontrolhelpcmd("rehash",NO_DEVELOPER,1,&controlrehash,"Usage: rehash\nReloads configuration file.");
64 registercontrolhelpcmd("showcommands",NO_ACCOUNT,0,&controlshowcommands,"Usage: showcommands\nShows all registered commands.");
65 registercontrolhelpcmd("reload",NO_DEVELOPER,1,&controlreload,"Usage: reload <module>\nReloads specified module.");
66 registercontrolhelpcmd("help",NO_ANYONE,1,&controlhelpcmd,"Usage: help <command>\nShows help for specified command.");
c86edd1d
Q
67
68 scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
69}
70
38cee035
CP
71void registercontrolhelpcmd(const char *name, int level, int maxparams, CommandHandler handler, char *help) {
72 addcommandhelptotree(controlcmds,name,level,maxparams,handler,help);
c86edd1d
Q
73}
74
75int deregistercontrolcmd(const char *name, CommandHandler handler) {
76 return deletecommandfromtree(controlcmds, name, handler);
77}
78
79void controlconnect(void *arg) {
80 sstring *cnick, *myident, *myhost, *myrealname, *myauthname;
81 channel *cp;
82
83 cnick=getcopyconfigitem("control","nick","C",NICKLEN);
84 myident=getcopyconfigitem("control","ident","control",NICKLEN);
85 myhost=getcopyconfigitem("control","hostname",myserver->content,HOSTLEN);
86 myrealname=getcopyconfigitem("control","realname","NewServ Control Service",REALLEN);
87 myauthname=getcopyconfigitem("control","authname","C",ACCOUNTLEN);
88
89 mynick=registerlocaluser(cnick->content,myident->content,myhost->content,myrealname->content,myauthname->content,UMODE_SERVICE|UMODE_DEAF|UMODE_OPER|UMODE_ACCOUNT,&handlemessages);
38cee035 90 triggerhook(HOOK_CONTROL_REGISTERED, mynick);
c86edd1d
Q
91 cp=findchannel("#twilightzone");
92 if (!cp) {
93 localcreatechannel(mynick,"#twilightzone");
94 } else {
95 localjoinchannel(mynick,cp);
96 localgetops(mynick,cp);
97 }
98
99 freesstring(cnick);
100 freesstring(myident);
101 freesstring(myhost);
102 freesstring(myrealname);
103 freesstring(myauthname);
104}
105
106void handlestats(int hooknum, void *arg) {
38cee035 107 controlreply(hooknick,"%s",(char *)arg);
c86edd1d
Q
108}
109
110int controlstatus(void *sender, int cargc, char **cargv) {
111 unsigned int level=5;
112
38cee035 113 hooknick=(nick *)sender;
c86edd1d
Q
114
115 if (cargc>0) {
116 level=strtoul(cargv[0],NULL,10);
117 }
118
119 registerhook(HOOK_CORE_STATSREPLY,&handlestats);
120 triggerhook(HOOK_CORE_STATSREQUEST,(void *)level);
121 deregisterhook(HOOK_CORE_STATSREPLY,&handlestats);
122 return CMD_OK;
123}
124
125int controlrehash(void *sender, int cargc, char **cargv) {
126 nick *np=(nick *)sender;
127
128 controlreply(np,"Rehashing the config file.");
129
130 rehashconfig();
131 triggerhook(HOOK_CORE_REHASH,(void *)0);
132 return CMD_OK;
133}
38cee035
CP
134
135void handlewhois(int hooknum, void *arg) {
136 controlreply(hooknick,"%s",(char *)arg);
137}
138
c86edd1d
Q
139int controlwhois(void *sender, int cargc, char **cargv) {
140 nick *target;
141 channel **channels;
142 char buf[BUFSIZE];
143 int i;
144
38cee035
CP
145 if (cargc<1)
146 return CMD_USAGE;
c86edd1d
Q
147
148 if (cargv[0][0]=='#') {
149 if (!(target=getnickbynumericstr(cargv[0]+1))) {
38cee035 150 controlreply(sender,"Sorry, couldn't find numeric %s",cargv[0]+1);
c86edd1d
Q
151 return CMD_ERROR;
152 }
153 } else {
154 if ((target=getnickbynick(cargv[0]))==NULL) {
38cee035 155 controlreply((nick *)sender,"Sorry, couldn't find that user");
c86edd1d
Q
156 return CMD_ERROR;
157 }
158 }
159
38cee035
CP
160 controlreply((nick *)sender,"Nick : %s",target->nick);
161 controlreply((nick *)sender,"Numeric : %s",longtonumeric(target->numeric,5));
162 controlreply((nick *)sender,"User@Host : %s@%s (%d user(s) on this host)",target->ident,target->host->name->content,target->host->clonecount);
c86edd1d
Q
163 if (IsSetHost(target)) {
164 if (target->shident) {
38cee035 165 controlreply((nick *)sender,"Fakehost : %s@%s",target->shident->content, target->sethost->content);
c86edd1d 166 } else {
38cee035 167 controlreply((nick *)sender,"Fakehost : %s",target->sethost->content);
c86edd1d
Q
168 }
169 }
38cee035
CP
170 controlreply((nick *)sender,"Timestamp : %lu",target->timestamp);
171 controlreply((nick *)sender,"IP address: %d.%d.%d.%d",(target->ipaddress)>>24,(target->ipaddress>>16)&255, (target->ipaddress>>8)&255,target->ipaddress&255);
172 controlreply((nick *)sender,"Realname : %s (%d user(s) have this realname)",target->realname->name->content,target->realname->usercount);
c86edd1d 173 if (target->umodes) {
38cee035 174 controlreply((nick *)sender,"Umode(s) : %s",printflags(target->umodes,umodeflags));
c86edd1d
Q
175 }
176 if (IsAccount(target)) {
38cee035 177 controlreply((nick *)sender,"Account : %s",target->authname);
c86edd1d 178 if (target->accountts)
38cee035 179 controlreply((nick *)sender,"AccountTS : %ld",target->accountts);
c86edd1d 180 }
38cee035
CP
181
182 hooknick=(nick *)sender;
183 registerhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
184 triggerhook(HOOK_CONTROL_WHOISREQUEST,target);
185 deregisterhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
186
c86edd1d 187 if (target->channels->cursi==0) {
38cee035 188 controlreply((nick *)sender,"Channels : none");
c86edd1d 189 } else if (target->channels->cursi>50) {
38cee035 190 controlreply((nick *)sender,"Channels : - (total: %d)",target->channels->cursi);
c86edd1d
Q
191 } else {
192 buf[0]='\0';
193 channels=(channel **)target->channels->content;
194 for (i=0;i<=target->channels->cursi;i++) {
195 if (!((i==target->channels->cursi) || ((70-strlen(buf))<channels[i]->index->name->length && strlen(buf)>0))) {
196 strcat(buf,channels[i]->index->name->content);
197 strcat(buf," ");
198 } else {
199 if (strlen(buf)==0) {
200 break;
201 } else {
38cee035 202 controlreply((nick *)sender,"Channels : %s",buf);
c86edd1d
Q
203 buf[0]='\0';
204 i--;
205 }
206 }
207 }
208 }
209
210 return CMD_OK;
211}
212
213int controlinsmod(void *sender, int cargc, char **cargv) {
38cee035
CP
214 if (cargc<1)
215 return CMD_USAGE;
c86edd1d
Q
216
217 switch(insmod(cargv[0])) {
218 case -1:
38cee035 219 controlreply((nick *)sender,"Unable to load module %s",cargv[0]);
c86edd1d
Q
220 return CMD_ERROR;
221
222 case 1:
38cee035 223 controlreply((nick *)sender,"Module %s already loaded, or name not valid",cargv[0]);
c86edd1d
Q
224 return CMD_ERROR;
225
226 case 0:
38cee035 227 controlreply((nick *)sender,"Module %s loaded.",cargv[0]);
c86edd1d
Q
228 return CMD_OK;
229
230 default:
38cee035 231 controlreply((nick *)sender,"An unknown error occured.");
c86edd1d
Q
232 return CMD_ERROR;
233 }
234}
235
236int controlrmmod(void *sender, int cargc, char **cargv) {
38cee035
CP
237 if (cargc<1)
238 return CMD_USAGE;
c86edd1d
Q
239
240 switch(rmmod(cargv[0])) {
241 case 1:
38cee035 242 controlreply((nick *)sender,"Module %s is not loaded.",cargv[0]);
c86edd1d
Q
243 return CMD_ERROR;
244
245 case 0:
38cee035 246 controlreply((nick *)sender,"Module %s unloaded.",cargv[0]);
c86edd1d
Q
247 return CMD_OK;
248
249 default:
38cee035 250 controlreply((nick *)sender,"An unknown error occured.");
c86edd1d
Q
251 return CMD_ERROR;
252 }
253}
254
1fab6211 255int controllsmod(void *sender, int cargc, char **cargv) {
256 int i=0;
257 char *ptr;
258
259 if (cargc < 1) { /* list all loaded modules */
260 ptr = lsmod(i);
38cee035 261 controlreply((nick *)sender,"Module");
1fab6211 262 while (ptr != NULL) {
38cee035 263 controlreply((nick *)sender,"%s", ptr);
1fab6211 264 ptr = lsmod(++i);
265 }
266 } else {
267 ptr = lsmod(getindex(cargv[0]));
38cee035 268 controlreply((nick *)sender,"Module \"%s\" %s", cargv[0], (ptr ? "is loaded." : "is NOT loaded."));
1fab6211 269 }
270 return CMD_OK;
271}
272
c86edd1d 273int controlreload(void *sender, int cargc, char **cargv) {
38cee035
CP
274 if (cargc<1)
275 return CMD_USAGE;
c86edd1d
Q
276
277 controlrmmod(sender, cargc, cargv);
278 return controlinsmod(sender, cargc, cargv);
279}
280
281int relink(void *sender, int cargc, char **cargv) {
282 if (cargc<1) {
38cee035
CP
283 controlreply((nick *)sender,"You must give a reason.");
284 return CMD_USAGE;
c86edd1d
Q
285 }
286
287 irc_send("%s SQ %s 0 :%s",mynumeric->content,myserver->content,cargv[0]);
288 irc_disconnected();
289
290 return CMD_OK;
291}
292
293int die(void *sender, int cargc, char **cargv) {
294 if (cargc<1) {
38cee035
CP
295 controlreply((nick *)sender,"You must give a reason.");
296 return CMD_USAGE;
c86edd1d
Q
297 }
298
299 irc_send("%s SQ %s 0 :%s",mynumeric->content,myserver->content,cargv[0]);
300 irc_disconnected();
301
302 exit(0);
303}
304
305int controlchannel(void *sender, int cargc, char **cargv) {
306 channel *cp;
307 nick *np;
308 chanban *cbp;
309 char buf[BUFSIZE];
310 char buf2[12];
311 int i,j;
312
38cee035
CP
313 if (cargc<1)
314 return CMD_USAGE;
c86edd1d
Q
315
316 if ((cp=findchannel(cargv[0]))==NULL) {
38cee035 317 controlreply((nick *)sender,"Couldn't find channel: %s",cargv[0]);
c86edd1d
Q
318 return CMD_ERROR;
319 }
320
321 if (IsLimit(cp)) {
322 sprintf(buf2,"%d",cp->limit);
323 }
324
38cee035 325 controlreply((nick *)sender,"Channel : %s",cp->index->name->content);
c86edd1d 326 if (cp->topic) {
38cee035
CP
327 controlreply((nick *)sender,"Topic : %s",cp->topic->content);
328 controlreply((nick *)sender,"T-time : %ld [%s]",cp->topictime,ctime(&(cp->topictime)));
c86edd1d 329 }
38cee035 330 controlreply((nick *)sender,"Mode(s) : %s %s%s%s",printflags(cp->flags,cmodeflags),IsLimit(cp)?buf2:"",
c86edd1d 331 IsLimit(cp)?" ":"",IsKey(cp)?cp->key->content:"");
38cee035 332 controlreply((nick *)sender,"Users : %d (hash size %d, utilisation %.1f%%); %d unique hosts",
c86edd1d
Q
333 cp->users->totalusers,cp->users->hashsize,((float)(100*cp->users->totalusers)/cp->users->hashsize),
334 countuniquehosts(cp));
335 i=0;
336 memset(buf,' ',90);
337 buf[72]='\0';
338 for (j=0;j<=cp->users->hashsize;j++) {
339 if (i==4 || j==cp->users->hashsize) {
340 if(i>0) {
38cee035 341 controlreply((nick *)sender,"Users : %s",buf);
c86edd1d
Q
342 }
343 i=0;
344 memset(buf,' ',72);
345 if (j==cp->users->hashsize)
346 break;
347 }
348 if (cp->users->content[j]!=nouser) {
349 np=getnickbynumeric(cp->users->content[j]);
350 sprintf(&buf[i*18],"%c%c%-15s ",cp->users->content[j]&CUMODE_VOICE?'+':' ',
351 cp->users->content[j]&CUMODE_OP?'@':' ', np?np->nick:"!BUG-NONICK!");
352 i++;
353 if (i<4)
354 buf[i*18]=' ';
355 }
356 }
357
358 for (cbp=cp->bans;cbp;cbp=cbp->next) {
38cee035 359 controlreply((nick *)sender,"Ban : %s",bantostringdebug(cbp));
c86edd1d
Q
360 }
361 return CMD_OK;
362}
363
364int controlshowcommands(void *sender, int cargc, char **cargv) {
365 nick *np=(nick *)sender;
366 Command *cmdlist[100];
367 int i,n;
368
369 n=getcommandlist(controlcmds,cmdlist,100);
370
371 controlreply(np,"The following commands are registered at present:");
372
373 for(i=0;i<n;i++) {
38cee035 374 controlreply(np,"%s",cmdlist[i]->command->content);
c86edd1d
Q
375 }
376
377 controlreply(np,"End of list.");
378 return CMD_OK;
379}
380
381void handlemessages(nick *target, int messagetype, void **args) {
382 Command *cmd;
383 char *cargv[50];
384 int cargc;
385 nick *sender;
386
387 switch(messagetype) {
388 case LU_PRIVMSG:
389 case LU_SECUREMSG:
390 /* If it's a message, first arg is nick and second is message */
391 sender=(nick *)args[0];
392
393 Error("control",ERR_INFO,"From: %s!%s@%s: %s",sender->nick,sender->ident,sender->host->name->content, (char *)args[1]);
394
395 /* Split the line into params */
396 cargc=splitline((char *)args[1],cargv,50,0);
397
398 if (!cargc) {
399 /* Blank line */
400 return;
401 }
402
403 cmd=findcommandintree(controlcmds,cargv[0],1);
404 if (cmd==NULL) {
38cee035 405 controlreply(sender,"Unknown command.");
c86edd1d
Q
406 return;
407 }
408
38cee035
CP
409 if (cmd->level>0 && !IsOper(sender)) {
410 controlreply(sender,"You need to be opered to use this command.");
c86edd1d
Q
411 return;
412 }
413
414 /* If we were doing "authed user tracking" here we'd put a check in for authlevel */
415
416 /* Check the maxargs */
417 if (cmd->maxparams<(cargc-1)) {
418 /* We need to do some rejoining */
419 rejoinline(cargv[cmd->maxparams],cargc-(cmd->maxparams));
420 cargc=(cmd->maxparams)+1;
421 }
422
38cee035
CP
423 if((cmd->handler)((void *)sender,cargc-1,&(cargv[1])) == CMD_USAGE)
424 controlhelp(sender, cmd);
c86edd1d
Q
425 break;
426
427 case LU_KILLED:
428 /* someone killed me? Bastards */
429 scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
430 mynick=NULL;
431 break;
432
433 default:
434 break;
435 }
436}
437
38cee035 438void controlmessage(nick *target, char *message, ... ) {
c86edd1d
Q
439 char buf[512];
440 va_list va;
441
442 if (mynick==NULL) {
443 return;
444 }
445
446 va_start(va,message);
447 vsnprintf(buf,512,message,va);
448 va_end(va);
449
450 sendmessagetouser(mynick,target,"%s",buf);
451}
452
453void controlchanmsg(channel *cp, char *message, ...) {
454 char buf[512];
455 va_list va;
456
457 if (mynick==NULL) {
458 return;
459 }
460
461 va_start(va,message);
462 vsnprintf(buf,512,message,va);
463 va_end(va);
464
465 sendmessagetochannel(mynick,cp,"%s",buf);
466}
467
468void controlnotice(nick *target, char *message, ... ) {
469 char buf[512];
470 va_list va;
471
472 if (mynick==NULL) {
473 return;
474 }
475
476 va_start(va,message);
477 vsnprintf(buf,512,message,va);
478 va_end(va);
479
480 sendnoticetouser(mynick,target,"%s",buf);
481}
482
38cee035
CP
483void controlspecialrmmod(void *arg) {
484 struct specialsched *a = (struct specialsched *)arg;
b015c3e9 485
38cee035
CP
486 a->schedule = NULL;
487 sstring *froo = a->modulename;
488
489 rmmod(froo->content);
490 freesstring(froo);
491}
492
493void controlspecialreloadmod(void *arg) {
494 struct specialsched *a = (struct specialsched *)arg;
495
496 a->schedule = NULL;
497 sstring *froo = a->modulename;
498
499 rmmod(froo->content);
500 insmod(froo->content);
501 freesstring(froo);
502}
503
504void controlhelp(nick *np, Command *cmd) {
505 char *cp = cmd->help, *sp = cp;
506 if(!cp || !*cp) {
507 controlreply(np, "Sorry, no help for this command.");
508 } else {
509 int finished = 0;
510 for(;;cp++) {
511 if(*cp == '\0' || *cp == '\n') {
512 if(*cp == '\0') {
513 finished = 1;
514 } else {
515 *cp = '\0';
516 }
517
518 if(sp != cp)
519 controlreply(np, "%s", sp);
520
521 if(finished)
522 break;
523
524 *cp = '\n';
525
526 sp = cp + 1;
527 }
528 }
529 }
530}
b015c3e9 531
38cee035
CP
532int controlhelpcmd(void *sender, int cargc, char **cargv) {
533 Command *cmd;
534 nick *np = (nick *)sender;
535
536 if (cargc<1)
537 return CMD_USAGE;
538
539 cmd=findcommandintree(controlcmds,cargv[0],1);
540 if (cmd==NULL) {
541 controlreply(np,"Unknown command.");
542 return CMD_ERROR;
543 }
544
545 controlhelp(np, cmd);
546 return CMD_OK;
b015c3e9 547}
a80cbef6
CP
548
549void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...) {
550 int i;
551 nick *np;
552 char broadcast[512];
553 va_list va;
554
555 va_start(va, format);
556 vsnprintf(broadcast, sizeof(broadcast), format, va);
557 va_end(va);
558
559 for(i=0;i<NICKHASHSIZE;i++)
560 for(np=nicktable[i];np;np=np->next)
561 if (IsOper(np))
562 controlnotice(np, "%s", broadcast);
563}