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