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