]> jfr.im git - irc/quakenet/newserv.git/blob - control/control.c
Free authname when it's no longer in use by noperserv.
[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 #include "control_policy.h"
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30
31 MODULE_VERSION("");
32
33 nick *hooknick;
34
35 nick *mynick;
36
37 CommandTree *controlcmds;
38 DestroyExt controldestroyext;
39 int noperserv_ext;
40
41 const flag no_commandflags[] = {
42 { 'o', __NO_OPER },
43 { 't', __NO_TRUST },
44 { 's', __NO_STAFF },
45 { 'S', __NO_SEC },
46 { 'd', __NO_DEVELOPER },
47 { 'L', __NO_LEGACY },
48 { 'O', __NO_OPERED },
49 { 'r', __NO_AUTHED },
50 { 'R', __NO_ACCOUNT },
51 { 'Y', __NO_RELAY },
52 { '\0', 0 }
53 };
54
55 const flag no_userflags[] = {
56 { 'o', __NO_OPER },
57 { 't', __NO_TRUST },
58 { 's', __NO_STAFF },
59 { 'S', __NO_SEC },
60 { 'd', __NO_DEVELOPER },
61 { 'Y', __NO_RELAY },
62 { '\0', 0 }
63 };
64
65 const flag no_noticeflags[] = {
66 { 'm', NL_MANAGEMENT }, /* hello, password, userflags, noticeflags */
67 { 't', NL_TRUSTS }, /* trust stuff... */
68 { 'k', NL_KICKKILLS }, /* KICK/KILL commands */
69 { 'I', NL_MISC }, /* misc commands */
70 { 'g', NL_GLINES }, /* GLINE commands */
71 { 'h', NL_HITS }, /* Where a gline or kill is set automatically by the bot */
72 { 'c', NL_CLONING }, /* Clone detection */
73 { 'C', NL_CLEARCHAN }, /* When someone clearchans */
74 { 'f', NL_FAKEUSERS }, /* Fakeuser addition */
75 { 'b', NL_BROADCASTS }, /* Broadcast/mbroadcast/sbroadcast */
76 { 'o', NL_OPERATIONS }, /* insmod/rmmod/etc */
77 { 'O', NL_OPERING }, /* when someone opers */
78 { 'n', NL_NOTICES }, /* turn off to receive notices instead of privmsgs */
79 { 'A', NL_ALL_COMMANDS }, /* all commands sent */
80 { '\0', 0 }
81 };
82
83 void controldestroycmdext(void *ext);
84 void handlemessages(nick *target, int messagetype, void **args);
85 int controlstatus(void *sender, int cargc, char **cargv);
86 void controlconnect(void *arg);
87 int controlwhois(void *sender, int cargc, char **cargv);
88 int controlchannel(void *sender, int cargc, char **cargv);
89 int relink(void *sender, int cargc, char **cargv);
90 int die(void *sender, int cargc, char **cargv);
91 int controlinsmod(void *sender, int cargc, char **cargv);
92 int controllsmod(void *sender, int cargc, char **cargv);
93 int controlrehash(void *sender, int cargc, char **cargv);
94 int controlreload(void *sender, int cargc, char **cargv);
95 int controlhelpcmd(void *sender, int cargc, char **cargv);
96 void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...) __attribute__ ((format (printf, 3, 4)));
97 void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...);
98 int controlcheckpermitted(flag_t level, nick *user);
99 void handlesignal(int hooknum, void *arg);
100 void noperserv_oper_detection(int hooknum, void *arg);
101 void noperserv_whois_handler(int hooknum, void *arg);
102 void noperserv_whois_account_handler(int hooknum, void *arg);
103
104 #define HOOK_CONTROL_WHOISREQUEST_AUTHNAME -1
105 #define HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER -2
106
107 static int init;
108
109 void _init() {
110 if(!noperserv_load_db())
111 return;
112
113 controlcmds=newcommandtree();
114 controldestroyext=&controldestroycmdext;
115
116 registercontrolhelpcmd("status",NO_DEVELOPER,1,&controlstatus,"Usage: status ?level?\nDisplays status information, increasing level gives more verbose information.");
117 registercontrolhelpcmd("whois",NO_OPERED,1,&controlwhois,"Usage: whois <nickname|#numeric>\nDisplays lots of information about the specified nickname or numeric.");
118 registercontrolhelpcmd("channel",NO_OPER,1,&controlchannel,"Usage: channel <#channel>\nDisplays channel information.");
119 registercontrolhelpcmd("relink",NO_DEVELOPER,1,&relink,"Usage: relink\nRelinks service to the network.");
120 registercontrolhelpcmd("die",NO_DEVELOPER,1,&die,"Usage: die <reason>\nTerminates the service.");
121 registercontrolhelpcmd("insmod",NO_DEVELOPER,1,&controlinsmod,"Usage: insmod <module>\nAdds a module to the running instance.");
122 registercontrolhelpcmd("rmmod",NO_DEVELOPER,1,&controlrmmod,"Usage: rmmod <module>\nRemoves a module from the running instance.");
123 registercontrolhelpcmd("lsmod",NO_OPER,0,&controllsmod,"Usage: lsmod\nLists currently running modules.");
124 registercontrolhelpcmd("rehash",NO_DEVELOPER,1,&controlrehash,"Usage: rehash\nReloads configuration file.");
125 registercontrolhelpcmd("showcommands",NO_ACCOUNT,0,&controlshowcommands,"Usage: showcommands\nShows all registered commands.");
126 registercontrolhelpcmd("reload",NO_DEVELOPER,1,&controlreload,"Usage: reload <module>\nReloads specified module.");
127 registercontrolhelpcmd("help",NO_ANYONE,1,&controlhelpcmd,"Usage: help <command>\nShows help for specified command.");
128
129 registerhook(HOOK_CORE_REHASH, &handlesignal);
130 registerhook(HOOK_CORE_SIGINT, &handlesignal);
131 registerhook(HOOK_NICK_MODEOPER, &noperserv_oper_detection);
132 registerhook(HOOK_CONTROL_WHOISREQUEST, &noperserv_whois_handler);
133
134 noperserv_ext = registerauthnameext("noperserv", 1);
135
136 scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
137
138 init = 1;
139 }
140
141 void _fini() {
142 if (!init)
143 return;
144
145 deleteallschedules(&controlconnect);
146 if (mynick) {
147 deregisterlocaluser(mynick,"Leaving");
148 }
149
150 deregistercontrolcmd("status",&controlstatus);
151 deregistercontrolcmd("whois",&controlwhois);
152 deregistercontrolcmd("channel",&controlchannel);
153 deregistercontrolcmd("relink",&relink);
154 deregistercontrolcmd("die",&die);
155 deregistercontrolcmd("insmod",&controlinsmod);
156 deregistercontrolcmd("rmmod",&controlrmmod);
157 deregistercontrolcmd("lsmod",&controllsmod);
158 deregistercontrolcmd("rehash",&controlrehash);
159 deregistercontrolcmd("showcommands",&controlshowcommands);
160 deregistercontrolcmd("reload",&controlreload);
161 deregistercontrolcmd("help",&controlhelpcmd);
162
163 destroycommandtree(controlcmds);
164
165 deregisterhook(HOOK_CORE_REHASH, &handlesignal);
166 deregisterhook(HOOK_CORE_SIGINT, &handlesignal);
167 deregisterhook(HOOK_NICK_MODEOPER, &noperserv_oper_detection);
168 deregisterhook(HOOK_CONTROL_WHOISREQUEST, &noperserv_whois_handler);
169
170 releaseauthnameext(noperserv_ext);
171
172 noperserv_cleanup_db();
173 }
174
175 void registercontrolhelpcmd(const char *name, int level, int maxparams, CommandHandler handler, char *helpstr) {
176 cmdhelp *help;
177 Command *newcmd;
178
179 newcmd = addcommandtotree(controlcmds,name,level,maxparams,handler);
180
181 if (helpstr) {
182 /* Allocate a help record */
183 help=(cmdhelp *)malloc(sizeof(cmdhelp));
184 if(!help) {
185 Error("control",ERR_ERROR,"Malloc failed: registercontrolhelpcmd");
186 return;
187 }
188 memset((void *)help,0,sizeof(cmdhelp));
189
190 /* this isn't an sstring atm, as sstring has a max length (512) */
191 int len=strlen(helpstr);
192 help->helpstr=(char *)malloc(len+1);
193 if(help->helpstr) {
194 strncpy(help->helpstr, helpstr, len);
195 help->helpstr[len] = '\0';
196 }
197 newcmd->ext=(void *)help;
198 newcmd->destroyext=controldestroyext;
199 }
200 }
201
202 void registercontrolhelpfunccmd(const char *name, int level, int maxparams, CommandHandler handler, CommandHelp helpcmd) {
203 cmdhelp *help;
204 Command *newcmd;
205
206 /* Allocate a help record */
207 help=(cmdhelp *)malloc(sizeof(cmdhelp));
208 if (!help) {
209 Error("control",ERR_ERROR,"Malloc failed: registercontrolhelpfunccmd");
210 return;
211 }
212 memset((void *)help,0,sizeof(cmdhelp));
213
214 help->helpcmd=helpcmd;
215
216 newcmd = addcommandexttotree(controlcmds,name,level,maxparams,handler, (void *)help);
217 newcmd->destroyext=controldestroyext;
218 }
219
220
221 int deregistercontrolcmd(const char *name, CommandHandler handler) {
222 return deletecommandfromtree(controlcmds, name, handler);
223 }
224
225 void controlconnect(void *arg) {
226 sstring *cnick, *myident, *myhost, *myrealname, *myauthname;
227 channel *cp;
228
229 cnick=getcopyconfigitem("control","nick","C",NICKLEN);
230 myident=getcopyconfigitem("control","ident","control",NICKLEN);
231 myhost=getcopyconfigitem("control","hostname",myserver->content,HOSTLEN);
232 myrealname=getcopyconfigitem("control","realname","NewServ Control Service",REALLEN);
233 myauthname=getcopyconfigitem("control","authname","C",ACCOUNTLEN);
234
235 mynick=registerlocaluser(cnick->content,myident->content,myhost->content,myrealname->content,myauthname->content,UMODE_SERVICE|UMODE_DEAF|UMODE_OPER|UMODE_ACCOUNT|UMODE_INV,&handlemessages);
236 triggerhook(HOOK_CONTROL_REGISTERED, mynick);
237 cp=findchannel("#twilightzone");
238 if (!cp) {
239 localcreatechannel(mynick,"#twilightzone");
240 } else {
241 localjoinchannel(mynick,cp);
242 localgetops(mynick,cp);
243 }
244
245 freesstring(cnick);
246 freesstring(myident);
247 freesstring(myhost);
248 freesstring(myrealname);
249 freesstring(myauthname);
250 }
251
252 void handlestats(int hooknum, void *arg) {
253 controlreply(hooknick,"%s",(char *)arg);
254 }
255
256 int controlstatus(void *sender, int cargc, char **cargv) {
257 unsigned long level=999;
258 hooknick=(nick *)sender;
259
260 if (cargc>0) {
261 level=strtoul(cargv[0],NULL,10);
262 }
263
264 registerhook(HOOK_CORE_STATSREPLY,&handlestats);
265
266 triggerhook(HOOK_CORE_STATSREQUEST,(void *)level);
267 deregisterhook(HOOK_CORE_STATSREPLY,&handlestats);
268 return CMD_OK;
269 }
270
271 int controlrehash(void *sender, int cargc, char **cargv) {
272 nick *np=(nick *)sender;
273
274 controlreply(np,"Rehashing the config file.");
275
276 rehashconfig();
277 triggerhook(HOOK_CORE_REHASH,(void *)0);
278 return CMD_OK;
279 }
280
281 void handlewhois(int hooknum, void *arg) {
282 controlreply(hooknick,"%s",(char *)arg);
283 }
284
285 static int controlwhois_plain(void *sender, int cargc, char **cargv) {
286 nick *target;
287 channel **channels;
288 char buf[BUFSIZE];
289 int i;
290
291 if (cargc<1)
292 return CMD_USAGE;
293
294 if (cargv[0][0]=='#') {
295 if (!(target=getnickbynumericstr(cargv[0]+1))) {
296 controlreply(sender,"Sorry, couldn't find numeric %s",cargv[0]+1);
297 return CMD_ERROR;
298 }
299 } else {
300 if ((target=getnickbynick(cargv[0]))==NULL) {
301 controlreply((nick *)sender,"Sorry, couldn't find that user");
302 return CMD_ERROR;
303 }
304 }
305
306 controlreply((nick *)sender,"Nick : %s",target->nick);
307 controlreply((nick *)sender,"Numeric : %s",longtonumeric(target->numeric,5));
308 controlreply((nick *)sender,"User@Host : %s@%s (%d user(s) on this host)",target->ident,target->host->name->content,target->host->clonecount);
309 if (IsSetHost(target)) {
310 if (target->shident) {
311 controlreply((nick *)sender,"Fakehost : %s@%s",target->shident->content, target->sethost->content);
312 } else {
313 controlreply((nick *)sender,"Fakehost : %s",target->sethost->content);
314 }
315 }
316 controlreply((nick *)sender,"Timestamp : %lu",target->timestamp);
317
318 /* HACK */
319 {
320 int ext = findnickext("signontracker");
321
322 if(ext >= 0) {
323 time_t signedon = (time_t)(target->exts[ext]);
324 if(signedon) {
325 controlreply((nick *)sender,"Signed on : %lu",signedon);
326 } else {
327 controlreply((nick *)sender,"Signed on : ???");
328 }
329 }
330 }
331 controlreply((nick *)sender,"IP address: %s",IPtostr(target->p_ipaddr));
332 controlreply((nick *)sender,"Realname : %s (%d user(s) have this realname)",target->realname->name->content,target->realname->usercount);
333 if (target->umodes) {
334 controlreply((nick *)sender,"Umode(s) : %s",printflags(target->umodes,umodeflags));
335 }
336 if (IsOper(target) && target->opername)
337 controlreply((nick *)sender,"Opered as : %s",target->opername->content);
338 if (IsAccount(target)) {
339 controlreply((nick *)sender,"Account : %s",target->authname);
340 if (target->accountts)
341 controlreply((nick *)sender,"AccountTS : %ld",target->accountts);
342 if (target->auth) {
343 controlreply((nick *)sender,"UserID : %ld",target->auth->userid);
344 if (target->auth->flags)
345 controlreply((nick *)sender,"AccFlags : %s",printflags(target->auth->flags,accountflags));
346 }
347 }
348
349 if (target->away) {
350 controlreply((nick *)sender, "Away : %s",target->away->content);
351 }
352
353 hooknick=(nick *)sender;
354 registerhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
355 triggerhook(HOOK_CONTROL_WHOISREQUEST,target);
356 deregisterhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
357
358 if (target->channels->cursi==0) {
359 controlreply((nick *)sender,"Channels : none");
360 } else if (target->channels->cursi>50) {
361 controlreply((nick *)sender,"Channels : - (total: %d)",target->channels->cursi);
362 } else {
363 buf[0]='\0';
364 channels=(channel **)target->channels->content;
365 for (i=0;i<=target->channels->cursi;i++) {
366 if (!((i==target->channels->cursi) || ((70-strlen(buf))<channels[i]->index->name->length && strlen(buf)>0))) {
367 strcat(buf,channels[i]->index->name->content);
368 strcat(buf," ");
369 } else {
370 if (strlen(buf)==0) {
371 break;
372 } else {
373 controlreply((nick *)sender,"Channels : %s",buf);
374 buf[0]='\0';
375 i--;
376 }
377 }
378 }
379 }
380
381 return CMD_OK;
382 }
383
384 int controlwhois(void *sender, int cargc, char **cargv) {
385 authname *an;
386 no_autheduser *au;
387 nick *np = (nick *)sender;
388
389 if(cargc < 1)
390 return controlwhois_plain(sender, cargc, cargv);
391
392 if(cargv[0][0] != '#') {
393 if(cargv[0][0] == '*')
394 cargv[0][0] = '#';
395 return controlwhois_plain(sender, cargc, cargv);
396 }
397
398 an = findauthnamebyname(cargv[0] + 1);
399 if(!an) {
400 controlreply(np, "Account not registered.");
401 return CMD_OK;
402 }
403
404 au = noperserv_get_autheduser(an);
405 if(!au) {
406 controlreply(np, "User does not have a NOperserv account.");
407 return CMD_OK;
408 }
409
410 controlreply(np, "Account : %s", au->authname->name);
411
412 hooknick = np;
413
414 registerhook(HOOK_CONTROL_WHOISREPLY, &handlewhois);
415 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER, (void *)au);
416 deregisterhook(HOOK_CONTROL_WHOISREPLY, &handlewhois);
417
418 controlreply(np, "Flags : %s", printflags(NOGetAuthLevel(au), no_userflags));
419
420 return CMD_OK;
421 }
422
423 void noperserv_whois_handler(int hooknum, void *arg) {
424 char message[100];
425 nick *np = (nick *)arg;
426 no_autheduser *au;
427 if(!np)
428 return;
429
430 if(IsAccount(np)) {
431 au = NOGetAuthedUser(np);
432 if(au) {
433 snprintf(message, sizeof(message), "Flags : %s", printflags(NOGetAuthLevel(au), no_userflags));
434 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER, (void *)au);
435 } else {
436 snprintf(message, sizeof(message), "Flags : (user not known)");
437 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHNAME, (void *)np->authname);
438 }
439 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
440 }
441 }
442
443 /* mmm, hacky */
444 void noperserv_whois_account_handler(int hooknum, void *arg) {
445 int count = 0, found = 0;
446 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 */
447 char accountspace[NICKLEN + 3]; /* space, comma, null */
448 char message[1024];
449 nick *np;
450
451 nickbuffer[0] = '\0';
452 if(hooknum == HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER) {
453 /* we can just read out the authed user linked list */
454 no_autheduser *au = (void *)arg;
455
456 if(au->authname->nicks)
457 found = 1;
458
459 for(np=au->authname->nicks;np;np=np->nextbyauthname) {
460 snprintf(accountspace, sizeof(accountspace), "%s%s", count++?", ":"", np->nick);
461 strncat(nickbuffer, accountspace, sizeof(nickbuffer));
462 nickbuffer[sizeof(nickbuffer) - 1] = '\0';
463
464 if(count >= NO_NICKS_PER_WHOIS_LINE) {
465 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
466 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
467 nickbuffer[0] = '\0';
468 count = 0;
469 }
470 }
471 } else {
472 /* inefficient way */
473 char *authname = (char *)arg;
474 int i = 0;
475 nick *sp;
476
477 for(;i<NICKHASHSIZE;i++)
478 for(sp=nicktable[i];sp;sp=sp->next)
479 if(IsAccount(sp) && !ircd_strcmp(sp->authname, authname)) {
480 found = 1;
481
482 snprintf(accountspace, sizeof(accountspace), "%s%s", count++?", ":"", sp->nick);
483 strncat(nickbuffer, accountspace, sizeof(nickbuffer));
484 nickbuffer[sizeof(nickbuffer) - 1] = '\0';
485
486 if(count >= NO_NICKS_PER_WHOIS_LINE) {
487 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
488 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
489 nickbuffer[0] = '\0';
490 count = 0;
491 }
492 }
493 }
494
495 if(!found) {
496 snprintf(message, sizeof(message), "Authed : (no nicks authed)");
497 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
498 } else if(nickbuffer[0]) {
499 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
500 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
501 }
502 }
503
504
505 int controlinsmod(void *sender, int cargc, char **cargv) {
506 if (cargc<1)
507 return CMD_USAGE;
508
509 switch(insmod(cargv[0])) {
510 case -1:
511 controlreply((nick *)sender,"Unable to load module %s",cargv[0]);
512 return CMD_ERROR;
513
514 case 1:
515 controlreply((nick *)sender,"Module %s already loaded, or name not valid",cargv[0]);
516 return CMD_ERROR;
517
518 case 0:
519 controlreply((nick *)sender,"Module %s loaded.",cargv[0]);
520 return CMD_OK;
521
522 default:
523 controlreply((nick *)sender,"An unknown error occured.");
524 return CMD_ERROR;
525 }
526 }
527
528 int controlrmmod(void *sender, int cargc, char **cargv) {
529 if (cargc<1)
530 return CMD_USAGE;
531
532 switch(rmmod(cargv[0], 1)) {
533 case 1:
534 controlreply((nick *)sender,"Module %s is not loaded.",cargv[0]);
535 return CMD_ERROR;
536
537 case 0:
538 controlreply((nick *)sender,"Module %s unloaded.",cargv[0]);
539 return CMD_OK;
540
541 default:
542 controlreply((nick *)sender,"An unknown error occured.");
543 return CMD_ERROR;
544 }
545 }
546
547 int controllsmod(void *sender, int cargc, char **cargv) {
548 int i=0;
549 char *ptr;
550
551 if (cargc < 1) { /* list all loaded modules */
552 const char *ver, *buildid;
553 time_t t, t2 = time(NULL);
554 ptr = lsmod(i, &ver, &buildid, &t);
555
556 /* 9999d 24h 59m 59s fbf2a4a69ee1-tip */
557 controlreply((nick *)sender,"Module Loaded for Version Build id");
558 while (ptr != NULL) {
559 controlreply((nick *)sender," %-40s %-17s %-30s %s", ptr, longtoduration(t2-t, 2), ver?ver:"", buildid?buildid:"");
560 ptr = lsmod(++i, &ver, &buildid, &t);
561 }
562 } else {
563 ptr = lsmod(getindex(cargv[0]), NULL, NULL, NULL);
564 controlreply((nick *)sender,"Module \"%s\" %s", cargv[0], (ptr ? "is loaded." : "is NOT loaded."));
565 }
566 return CMD_OK;
567 }
568
569 int controlreload(void *sender, int cargc, char **cargv) {
570 if (cargc<1)
571 return CMD_USAGE;
572
573 controlreply((nick *)sender,"Imma gonna try and reload %s",cargv[0]);
574
575 safereload(cargv[0]);
576
577 return CMD_OK;
578 }
579
580 int relink(void *sender, int cargc, char **cargv) {
581 if (cargc<1) {
582 controlreply((nick *)sender,"You must give a reason.");
583 return CMD_USAGE;
584 }
585
586 irc_send("%s SQ %s 0 :%s",mynumeric->content,myserver->content,cargv[0]);
587 irc_disconnected();
588
589 return CMD_OK;
590 }
591
592 int die(void *sender, int cargc, char **cargv) {
593 if (cargc<1 || (strlen(cargv[0]) < 10)) {
594 controlreply((nick *)sender,"You must give a reason.");
595 return CMD_USAGE;
596 }
597
598 controlwall(NO_OPER,NL_OPERATIONS,"DIE from %s: %s",((nick *)sender)->nick, cargv[0]);
599
600 newserv_shutdown_pending=1;
601
602 return CMD_OK;
603 }
604
605 int controlchannel(void *sender, int cargc, char **cargv) {
606 channel *cp;
607 nick *np;
608 chanban *cbp;
609 char buf[BUFSIZE];
610 char buf2[12];
611 int i,j, ops=0, voice=0;
612 char timebuf[30];
613
614 if (cargc<1)
615 return CMD_USAGE;
616
617 if ((cp=findchannel(cargv[0]))==NULL) {
618 controlreply((nick *)sender,"Couldn't find channel: %s",cargv[0]);
619 return CMD_ERROR;
620 }
621
622 if (IsLimit(cp)) {
623 sprintf(buf2,"%d",cp->limit);
624 }
625
626 controlreply((nick *)sender,"Channel : %s",cp->index->name->content);
627 strftime(timebuf, 30, "%d/%m/%y %H:%M", localtime(&(cp->timestamp)));
628 controlreply((nick *)sender,"C-time : %ld [%s]",cp->timestamp,timebuf);
629 if (cp->topic) {
630 controlreply((nick *)sender,"Topic : %s",cp->topic->content);
631 strftime(timebuf, 30, "%d/%m/%y %H:%M", localtime(&(cp->topictime)));
632 controlreply((nick *)sender,"T-time : %ld [%s]",cp->topictime,timebuf);
633 } else {
634 controlreply((nick *)sender,"Topic : (none)");
635 }
636 controlreply((nick *)sender,"Mode(s) : %s %s%s%s",printflags(cp->flags,cmodeflags),IsLimit(cp)?buf2:"",
637 IsLimit(cp)?" ":"",IsKey(cp)?cp->key->content:"");
638 controlreply((nick *)sender,"Users : %d (hash size %d, utilisation %.1f%%); %d unique hosts",
639 cp->users->totalusers,cp->users->hashsize,((float)(100*cp->users->totalusers)/cp->users->hashsize),
640 countuniquehosts(cp));
641 i=0;
642 memset(buf,' ',90);
643 buf[72]='\0';
644 for (j=0;j<=cp->users->hashsize;j++) {
645 if (i==4 || j==cp->users->hashsize) {
646 if(i>0) {
647 controlreply((nick *)sender,"Users : %s",buf);
648 }
649 i=0;
650 memset(buf,' ',72);
651 if (j==cp->users->hashsize)
652 break;
653 }
654 if (cp->users->content[j]!=nouser) {
655 if (cp->users->content[j]&CUMODE_OP)
656 ops++;
657 else if (cp->users->content[j]&CUMODE_VOICE)
658 voice++;
659 np=getnickbynumeric(cp->users->content[j]);
660 sprintf(&buf[i*18],"%c%c%-15s ",cp->users->content[j]&CUMODE_VOICE?'+':' ',
661 cp->users->content[j]&CUMODE_OP?'@':' ', np?np->nick:"!BUG-NONICK!");
662 i++;
663 if (i<4)
664 buf[i*18]=' ';
665 }
666 }
667 controlreply((nick *)sender, "Users : Opped: %d, Voiced: %d", ops,voice);
668 for (cbp=cp->bans;cbp;cbp=cbp->next) {
669 controlreply((nick *)sender,"Ban : %s",bantostringdebug(cbp));
670 }
671 return CMD_OK;
672 }
673
674 int controlshowcommands(void *sender, int cargc, char **cargv) {
675 nick *np = (nick *)sender;
676 Command *cmdlist[100];
677 int i, n;
678
679 n = getcommandlist(controlcmds, cmdlist, 100);
680
681 controlreply(np, "The following commands are registered at present:");
682
683 for(i=0;i<n;i++)
684 if(noperserv_policy_command_permitted(cmdlist[i]->level, np))
685 controlreply(np, " %-25s %s", cmdlist[i]->command->content, printflags(cmdlist[i]->level, no_commandflags));
686
687 controlreply(np, "End of list.");
688 return CMD_OK;
689 }
690
691 void handlemessages(nick *target, int messagetype, void **args) {
692 Command *cmd;
693 char *cargv[50];
694 int cargc;
695 nick *sender;
696
697 switch(messagetype) {
698 case LU_PRIVMSG:
699 case LU_SECUREMSG:
700 /* If it's a message, first arg is nick and second is message */
701 sender=(nick *)args[0];
702
703 Error("control",ERR_INFO,"From: %s!%s@%s: %s",sender->nick,sender->ident,sender->host->name->content, (char *)args[1]);
704
705 /* Split the line into params */
706 cargc=splitline((char *)args[1],cargv,50,0);
707
708 if (!cargc) {
709 /* Blank line */
710 return;
711 }
712
713 cmd=findcommandintree(controlcmds,cargv[0],1);
714 if (cmd==NULL) {
715 controlreply(sender,"Unknown command.");
716 return;
717 }
718
719 if (cmd->level>0 && !IsOper(sender)) {
720 controlreply(sender,"You need to be opered to use this command.");
721 return;
722 }
723
724 /* If we were doing "authed user tracking" here we'd put a check in for authlevel */
725
726 /* Check the maxargs */
727 if (cmd->maxparams<(cargc-1)) {
728 /* We need to do some rejoining */
729 rejoinline(cargv[cmd->maxparams],cargc-(cmd->maxparams));
730 cargc=(cmd->maxparams)+1;
731 }
732
733 if((cmd->handler)((void *)sender,cargc-1,&(cargv[1])) == CMD_USAGE)
734 controlhelp(sender, cmd);
735 break;
736
737 case LU_KILLED:
738 /* someone killed me? Bastards */
739 scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
740 mynick=NULL;
741 triggerhook(HOOK_CONTROL_REGISTERED, NULL);
742 break;
743
744 default:
745 break;
746 }
747 }
748
749 void controlmessage(nick *target, char *message, ... ) {
750 char buf[512];
751 va_list va;
752
753 if (mynick==NULL) {
754 return;
755 }
756
757 va_start(va,message);
758 vsnprintf(buf,512,message,va);
759 va_end(va);
760
761 sendmessagetouser(mynick,target,"%s",buf);
762 }
763
764 void controlchanmsg(channel *cp, char *message, ...) {
765 char buf[512];
766 va_list va;
767
768 if (mynick==NULL) {
769 return;
770 }
771
772 va_start(va,message);
773 vsnprintf(buf,512,message,va);
774 va_end(va);
775
776 sendmessagetochannel(mynick,cp,"%s",buf);
777 }
778
779 void controlnotice(nick *target, char *message, ... ) {
780 char buf[512];
781 va_list va;
782
783 if (mynick==NULL) {
784 return;
785 }
786
787 va_start(va,message);
788 vsnprintf(buf,512,message,va);
789 va_end(va);
790
791 sendnoticetouser(mynick,target,"%s",buf);
792 }
793
794 void controlreply(nick *np, char *format, ...) {
795 char buf[512];
796 va_list va;
797 no_autheduser *au = NOGetAuthedUser(np);
798
799 va_start(va, format);
800 vsnprintf(buf, sizeof(buf), format, va);
801 va_end(va);
802
803 if(au && !(NOGetNoticeLevel(au) & NL_NOTICES)) {
804 controlmessage(np, "%s", buf);
805 } else {
806 controlnotice(np, "%s", buf);
807 }
808 }
809
810 void controlwall(flag_t permissionlevel, flag_t noticelevel, char *format, ...) {
811 char buf[512];
812 va_list va;
813 char *flags = printflags(noticelevel, no_noticeflags) + 1;
814 int i;
815 authname *anp;
816 no_autheduser *au;
817 nick *np;
818
819 va_start(va, format);
820 vsnprintf(buf, sizeof(buf), format, va);
821 va_end(va);
822
823 Error("noperserv", ERR_INFO, "$%s$ %s", flags, buf);
824
825 for (i=0;i<AUTHNAMEHASHSIZE;i++) {
826 for (anp=authnametable[i];anp;anp=anp->next) {
827 au = noperserv_get_autheduser(anp);
828 if(!au)
829 continue;
830 if((NOGetNoticeLevel(au) & noticelevel) && !(NOGetAuthLevel(au) & __NO_RELAY)) {
831 for(np=anp->nicks;np;np=np->nextbyauthname)
832 if(noperserv_policy_command_permitted(permissionlevel, np))
833 controlreply(np, "$%s$ %s", flags, buf);
834 }
835 }
836 }
837 }
838
839 void controlspecialrmmod(void *arg) {
840 struct specialsched *a = (struct specialsched *)arg;
841 sstring *froo = a->modulename;
842
843 a->schedule = NULL;
844
845 rmmod(froo->content, 1);
846 freesstring(froo);
847 }
848
849 void controlspecialreloadmod(void *arg) {
850 struct specialsched *a = (struct specialsched *)arg;
851 sstring *froo = a->modulename;
852
853 a->schedule = NULL;
854
855 safereload(froo->content);
856 freesstring(froo);
857 }
858
859 void controlhelp(nick *np, Command *cmd) {
860 char *cp, *sp;
861 char *scp;
862 cmdhelp *help=(cmdhelp *)cmd->ext;
863
864 if (!help) {
865 controlreply(np, "Sorry, no help for this command.");
866 return;
867 }
868 if ( help->helpcmd ) {
869 (help->helpcmd)(np, cmd);
870 } else {
871 scp = help->helpstr;
872 if (!scp) {
873 controlreply(np, "Sorry, no help for this command.");
874 } else {
875 cp = scp;
876 sp = cp;
877 int finished = 0;
878 for(;;cp++) {
879 if(*cp == '\0' || *cp == '\n') {
880 if(*cp == '\0') {
881 finished = 1;
882 } else {
883 *cp = '\0';
884 }
885
886 if(sp != cp)
887 controlreply(np, "%s", sp);
888
889 if(finished)
890 break;
891
892 *cp = '\n';
893
894 sp = cp + 1;
895 }
896 }
897 }
898 }
899 }
900
901 int controlhelpcmd(void *sender, int cargc, char **cargv) {
902 Command *cmd;
903 nick *np = (nick *)sender;
904
905 if(cargc < 1)
906 return CMD_USAGE;
907
908 cmd = findcommandintree(controlcmds, cargv[0], 1);
909 if(!cmd || !noperserv_policy_command_permitted(cmd->level, np)) {
910 controlreply(np, "Unknown command or access denied.");
911 return CMD_ERROR;
912 }
913
914 controlhelp(np, cmd);
915 return CMD_OK;
916 }
917
918 void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...) {
919 int i;
920 nick *np;
921 char broadcast[512];
922 va_list va;
923
924 va_start(va, format);
925 vsnprintf(broadcast, sizeof(broadcast), format, va);
926 va_end(va);
927
928 for(i=0;i<NICKHASHSIZE;i++)
929 for(np=nicktable[i];np;np=np->next)
930 if (IsOper(np))
931 controlnotice(np, "%s", broadcast);
932 }
933
934 void controlnswall(int noticelevel, char *format, ...) {
935 char broadcast[512];
936 va_list va;
937
938 va_start(va, format);
939 vsnprintf(broadcast, sizeof(broadcast), format, va);
940 va_end(va);
941
942 controlwall(NO_OPER, noticelevel, "%s", broadcast);
943 }
944
945 int controlpermitted(flag_t level, nick *user) {
946 return noperserv_policy_command_permitted(level, user);
947 }
948
949 void handlesignal(int hooknum, void *arg) {
950 char *signal, *action;
951
952 if(hooknum == HOOK_CORE_SIGINT) {
953 signal = "INT";
954 action = "terminating";
955 } else {
956 long hupped = (long)arg;
957 if(!hupped)
958 return;
959
960 signal = "HUP";
961 action = "rehashing";
962 }
963
964 controlwall(NO_OPER, NL_OPERATIONS, "SIG%s received, %s...", signal, action);
965 }
966
967 void controldestroycmdext(void *ext) {
968 if ( ((cmdhelp *)ext)->helpstr)
969 free( ((cmdhelp *)ext)->helpstr);
970 free(ext);
971 }
972
973 char *controlid(nick *np) {
974 static char buf[512];
975
976 snprintf(buf, sizeof(buf), "%s!%s@%s/%s", np->nick, np->ident, np->host->name->content, np->authname);
977
978 return buf;
979 }
980
981 void noperserv_oper_detection(int hooknum, void *arg) {
982 nick *np = (nick *)arg;
983
984 if(np->umodes & UMODE_OPER) {
985 if(np->opername && strcmp(np->opername->content, "-")) {
986 controlwall(NO_OPER, NL_OPERING, "%s!%s@%s%s%s just OPERed as %s", np->nick, np->ident, np->host->name->content, IsAccount(np)?"/":"", IsAccount(np)?np->authname:"", np->opername->content);
987 } else {
988 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:"");
989 }
990 } else {
991 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:"");
992 }
993 }
994