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