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