]> jfr.im git - irc/quakenet/newserv.git/blame - noperserv/noperserv_hooks.c
Lua version now excludes "Lua engine", at least for MODULEVERSION.
[irc/quakenet/newserv.git] / noperserv / noperserv_hooks.c
CommitLineData
3e3692bf
CP
1#include "../control/control.h"
2#include "../localuser/localuser.h"
3#include "../core/schedule.h"
43e82ceb 4#include "../core/modules.h"
3e3692bf
CP
5#include "../lib/splitline.h"
6#include "../lib/flags.h"
7#include "../lib/irc_string.h"
8#include "../lib/strlfunc.h"
9
10#include "noperserv.h"
11#include "noperserv_db.h"
12#include "noperserv_hooks.h"
13#include "noperserv_policy.h"
14
15#include <stdlib.h>
16#include <string.h>
17#include <stdarg.h>
18
19struct storedhook {
20 CommandHandler old;
21 sstring *name;
a8d791b4
CP
22 sstring *oldhelp;
23 sstring *newhelp;
3e3692bf
CP
24 struct storedhook *next;
25} storedhook;
26
27struct storedhook *storedhooks = NULL;
28
29int firsttime = 0;
30nick *replynick = NULL;
31
32UserMessageHandler oldhandler;
33ControlMsg oldreply;
34ControlWall oldwall;
35
36void noperserv_trap_registration(int hooknum, void *arg);
37int noperserv_showcommands(void *sender, int cargc, char **cargv);
38int noperserv_rmmod(void *sender, int cargc, char **cargv);
39int noperserv_reload(void *sender, int cargc, char **cargv);
40int noperserv_whois(void *sender, int cargc, char **cargv);
41int noperserv_help(void *sender, int cargc, char **cargv);
42void noperserv_whois_handler(int hooknum, void *arg);
43void noperserv_whois_account_handler(int hooknum, void *arg);
44void noperserv_handle_messages(nick *target, int messagetype, void **args);
45void noperserv_reply(nick *np, char *format, ...);
46void noperserv_wall(flag_t permissionlevel, flag_t noticelevel, char *format, ...);
47
48struct specialsched special;
49
50#define HOOK_CONTROL_WHOISREQUEST_AUTHNAME -1
51#define HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER -2
52
53void noperserv_setup_hooks(void) {
54 oldreply = controlreply;
55 controlreply = &noperserv_reply;
56
57 oldwall = controlwall;
58 controlwall = &noperserv_wall;
59
62a602c3 60 memset(&special, 0, sizeof(struct specialsched));
3e3692bf
CP
61
62 if(!mynick) {
63 registerhook(HOOK_CONTROL_REGISTERED, &noperserv_trap_registration);
64 } else {
65 noperserv_trap_registration(0, (void *)mynick);
66 }
67
68 registerhook(HOOK_CONTROL_WHOISREQUEST, &noperserv_whois_handler);
69}
70
71int noperserv_hook_command(char *command, CommandHandler newcommand, char *newhelp) {
72 struct storedhook *newhook;
73 Command *fetchcommand = findcommandintree(controlcmds, command, 1);
74
75 if(!fetchcommand)
76 return 1;
77
78 newhook = (struct storedhook *)malloc(sizeof(struct storedhook));
79 if(!newhook)
80 return 1;
81
82 newhook->name = getsstring(command, strlen(command));
83 if(!newhook->name) {
84 free(newhook);
85 return 1;
86 }
87
88 newhook->old = fetchcommand->handler;
89 if(newhelp) {
a8d791b4 90 newhook->newhelp = getsstring(newhelp, 512);
3e3692bf
CP
91 if(!newhook->newhelp) {
92 freesstring(newhook->name);
93 free(newhook);
a8d791b4 94 return 1;
3e3692bf 95 }
3e3692bf
CP
96 newhook->oldhelp = fetchcommand->help;
97 fetchcommand->help = newhook->newhelp;
98 } else {
99 newhook->newhelp = NULL;
100 }
101
102 newhook->next = storedhooks;
103 storedhooks = newhook;
104
105 fetchcommand->handler = newcommand;
106
107 return 0;
108}
109
110void noperserv_unhook_all_commands(void) {
111 struct storedhook *nh, *ch = storedhooks;
112 Command *fetchcommand;
113
114 while(ch) {
115 if(ch->old && (fetchcommand = findcommandintree(controlcmds, ch->name->content, 1))) {
116 fetchcommand->handler = ch->old;
117 if(ch->newhelp) {
118 fetchcommand->help = ch->oldhelp;
a8d791b4 119 freesstring(ch->newhelp);
3e3692bf
CP
120 }
121 }
122 nh = ch->next;
123 freesstring(ch->name);
124 free(ch);
125 ch = nh;
126 }
127}
128
129void noperserv_cleanup_hooks(void) {
130 deregisterhook(HOOK_CONTROL_WHOISREQUEST, &noperserv_whois_handler);
131 deregisterhook(HOOK_CONTROL_REGISTERED, &noperserv_trap_registration);
132
133 if(firsttime) {
134 noperserv_unhook_all_commands();
135 firsttime = 0;
136 }
137
138 if(oldhandler)
139 hooklocaluserhandler(mynick, oldhandler);
140
141 controlwall = oldwall;
142 controlreply = oldreply;
143}
144
145void noperserv_trap_registration(int hooknum, void *arg) {
146 oldhandler = hooklocaluserhandler((nick *)arg, &noperserv_handle_messages);
147 if(!oldhandler)
148 return;
149
150 if(!firsttime) {
151 firsttime = 1;
152 noperserv_hook_command("rmmod", &noperserv_rmmod, NULL);
153 noperserv_hook_command("reload", &noperserv_reload, NULL);
154 noperserv_hook_command("showcommands", &noperserv_showcommands, NULL);
155 noperserv_hook_command("whois", &noperserv_whois, "Usage: whois <nickname|#authname|*numeric>\nDisplays lots of information about the specified nickname, auth name or numeric.");
156 noperserv_hook_command("help", &noperserv_help, NULL);
157 }
158}
159
160CommandHandler noperserv_find_hook(char *command) {
161 struct storedhook *hh = storedhooks;
162 for(;hh;hh=hh->next)
163 if(!ircd_strcmp(hh->name->content, command))
164 return hh->old;
165
166 return NULL;
167}
168
43e82ceb
CP
169int noperserv_modules_loaded(char *mask) {
170 int i;
171 char *ptr;
172
2fb74c5e 173 for(i=0,ptr=lsmod(i,NULL,NULL,NULL);ptr;ptr=lsmod(++i,NULL,NULL,NULL))
43e82ceb
CP
174 if(match2strings(mask, ptr))
175 return 1;
176
177 return 0;
178}
179
3e3692bf
CP
180int noperserv_specialmod(nick *np, char *command, ScheduleCallback reloadhandler, int cargc, char **cargv) {
181 CommandHandler oldcommand = noperserv_find_hook(command);
182 if(cargc < 1) {
183 if(oldcommand)
184 return oldcommand(np, cargc, cargv);
185 return CMD_ERROR;
186 }
187
188 if(!strcmp(cargv[0], "noperserv")) {
189 if(special.schedule) {
190 controlreply(np, "Previous attempt at un/reload still in progress.");
191 return CMD_OK;
192 } else {
193 special.modulename = getsstring(cargv[0], strlen(cargv[0]));
194 if(!special.modulename) {
195 controlreply(np, "Unable to copy module name. Seek cow herd to trample on server.");
196 return CMD_ERROR;
197 } else {
198 special.schedule = scheduleoneshot(time(NULL) + 1, reloadhandler, &special);
199 if(!special.schedule) {
200 freesstring(special.modulename);
201 special.modulename = NULL;
202 controlreply(np, "Unable to allocate schedule. Seek cow herd to trample on server.");
203 return CMD_ERROR;
204 }
205 controlreply(np, "Special case un/reload in <1 second, no response will be sent, standby. . .");
206 return CMD_OK;
207 }
208 }
209 } else {
210 if(oldcommand)
211 return oldcommand(np, cargc, cargv);
212 return CMD_ERROR;
213 }
214}
215
216int noperserv_rmmod(void *sender, int cargc, char **cargv) {
217 return noperserv_specialmod(sender, "rmmod", &controlspecialrmmod, cargc, cargv);
218}
219
220int noperserv_reload(void *sender, int cargc, char **cargv) {
221 return noperserv_specialmod(sender, "reload", &controlspecialreloadmod, cargc, cargv);
222}
223
224void noperserv_whois_hook(int hooknum, void *arg) {
225 controlreply(replynick, "%s", (char *)arg);
226}
227
228int noperserv_whois(void *sender, int cargc, char **cargv) {
229 no_autheduser *au;
230 nick *np = (nick *)sender;
231 CommandHandler oldwhois = noperserv_find_hook("whois");
232
233 if(cargc < 1) {
234 if(oldwhois)
235 return oldwhois(sender, cargc, cargv);
236 return CMD_ERROR;
237 }
238
239 if(cargv[0][0] != '#') {
240 if(cargv[0][0] == '*')
241 cargv[0][0] = '#';
242 if(oldwhois)
243 return oldwhois(sender, cargc, cargv);
244 return CMD_ERROR;
245 }
246
247 au = noperserv_get_autheduser(cargv[0] + 1);
248 if(!au) {
249 controlreply(np, "Account not registered.");
250 return CMD_OK;
251 }
252
253 controlreply(np, "Account : %s", au->authname->content);
254
255 replynick = np;
256
257 registerhook(HOOK_CONTROL_WHOISREPLY, &noperserv_whois_hook);
258 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER, (void *)au);
259 deregisterhook(HOOK_CONTROL_WHOISREPLY, &noperserv_whois_hook);
260
261 controlreply(np, "Flags : %s", printflags(NOGetAuthLevel(au), no_userflags));
262
263 return CMD_OK;
264}
265
266int noperserv_showcommands(void *sender, int cargc, char **cargv) {
267 nick *np = (nick *)sender;
268 Command *cmdlist[100];
269 int i, n;
270
271 n = getcommandlist(controlcmds, cmdlist, 100);
272
273 controlreply(np, "The following commands are registered at present:");
274
275 for(i=0;i<n;i++)
ad4fd3ca
P
276 if(noperserv_policy_command_permitted(cmdlist[i]->level, np))
277 controlreply(np, "%s (%s)", cmdlist[i]->command->content, printflags(cmdlist[i]->level, no_commandflags));
3e3692bf
CP
278
279 controlreply(np, "End of list.");
280 return CMD_OK;
281}
282
283void noperserv_whois_handler(int hooknum, void *arg) {
284 char message[100];
285 nick *np = (nick *)arg;
286 no_autheduser *au;
287 if(!np)
288 return;
289
290 if(IsAccount(np)) {
291 au = NOGetAuthedUser(np);
292 if(au) {
293 snprintf(message, sizeof(message), "Flags : %s", printflags(NOGetAuthLevel(au), no_userflags));
294 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER, (void *)au);
295 } else {
296 snprintf(message, sizeof(message), "Flags : (user not known)");
297 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHNAME, (void *)np->authname);
298 }
299 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
300 }
301}
302
303/* mmm, hacky */
304void noperserv_whois_account_handler(int hooknum, void *arg) {
305 int count = 0, found = 0;
306 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 */
307 char accountspace[NICKLEN + 3]; /* space, comma, null */
308 char message[1024];
309
310 nickbuffer[0] = '\0';
311 if(hooknum == HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER) {
312 /* we can just read out the authed user linked list */
313 no_autheduser *au = (void *)arg;
314 no_nicklist *nl = au->nick;
315
316 if(nl)
317 found = 1;
318
319 for(;nl;nl=nl->next) {
320 snprintf(accountspace, sizeof(accountspace), "%s%s", count++?", ":"", nl->nick->nick);
321 strlcat(nickbuffer, accountspace, sizeof(nickbuffer));
322
323 if(count >= NO_NICKS_PER_WHOIS_LINE) {
324 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
325 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
326 nickbuffer[0] = '\0';
327 count = 0;
328 }
329 }
330 } else {
331 /* inefficient way */
332 char *authname = (char *)arg;
333 int i = 0;
334 nick *sp;
335
336 for(;i<NICKHASHSIZE;i++)
337 for(sp=nicktable[i];sp;sp=sp->next)
338 if(IsAccount(sp) && !ircd_strcmp(sp->authname, authname)) {
339 found = 1;
340
341 snprintf(accountspace, sizeof(accountspace), "%s%s", count++?", ":"", sp->nick);
342 strlcat(nickbuffer, accountspace, sizeof(nickbuffer));
343
344 if(count >= NO_NICKS_PER_WHOIS_LINE) {
345 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
346 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
347 nickbuffer[0] = '\0';
348 count = 0;
349 }
350 }
351 }
352
353 if(!found) {
354 snprintf(message, sizeof(message), "Authed : (no nicks authed)");
355 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
356 } else if(nickbuffer[0]) {
357 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
358 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
359 }
360}
361
362/* Obviously pinched from control.c */
363void noperserv_handle_messages(nick *target, int messagetype, void **args) {
364 Command *cmd;
365 char *cargv[50];
366 int cargc;
367 nick *sender;
368
369 switch(messagetype) {
370 case LU_PRIVMSG: /* override these two commands only */
371 case LU_SECUREMSG:
372 /* If it's a message, first arg is nick and second is message */
373 sender = (nick *)args[0];
374
375 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]);
376
377 /* Split the line into params */
378 cargc = splitline((char *)args[1], cargv, 50, 0);
379
380 if(!cargc) /* Blank line */
381 return;
382
383 cmd = findcommandintree(controlcmds,cargv[0],1);
384 if(!cmd) {
385 controlreply(sender, "Unknown command.");
386 return;
387 }
388
389 /* If we were doing "authed user tracking" here we'd put a check in for authlevel */
390 /* Here it is! */
391 if (!noperserv_policy_command_permitted(cmd->level, sender)) {
392 controlreply(sender, "Access denied.");
393 return;
394 }
395
396 /* Check the maxargs */
397 if(cmd->maxparams < (cargc - 1)) {
398 /* We need to do some rejoining */
399 rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams));
400 cargc = (cmd->maxparams) + 1;
401 }
402
403 if((cmd->handler)((void *)sender,cargc-1,&(cargv[1])) == CMD_USAGE)
404 controlhelp(sender, cmd);
405
406 break;
407 default:
408 if(oldhandler)
409 oldhandler(target, messagetype, args);
410 break;
411 }
412}
413
414void noperserv_reply(nick *np, char *format, ...) {
415 char buf[512];
416 va_list va;
417 no_autheduser *au = NOGetAuthedUser(np);
418
419 va_start(va, format);
420 vsnprintf(buf, sizeof(buf), format, va);
421 va_end(va);
422
423 if(au && !(NOGetNoticeLevel(au) & NL_NOTICES)) {
424 controlmessage(np, "%s", buf);
425 } else {
426 controlnotice(np, "%s", buf);
427 }
428}
429
430int noperserv_help(void *sender, int cargc, char **cargv) {
431 Command *cmd;
432 nick *np = (nick *)sender;
433
434 if(cargc < 1)
435 return CMD_USAGE;
436
437 cmd = findcommandintree(controlcmds, cargv[0], 1);
438 if(!cmd) {
439 controlreply(np, "Unknown command.");
440 return CMD_ERROR;
441 }
442
443 if(!noperserv_policy_command_permitted(cmd->level, np)) {
444 controlreply(np, "Access denied.");
445 return CMD_ERROR;
446 }
447
448 controlhelp(np, cmd);
449 return CMD_OK;
450}
451
452void noperserv_wall(flag_t permissionlevel, flag_t noticelevel, char *format, ...) {
453 char buf[512];
454 va_list va;
455 no_autheduser *au = authedusers;
456 no_nicklist *nl;
457 char *flags = printflags(noticelevel, no_noticeflags) + 1;
458
459 va_start(va, format);
460 vsnprintf(buf, sizeof(buf), format, va);
461 va_end(va);
462
463 Error("noperserv", ERR_INFO, "$%s$ %s", flags, buf);
464
465 for(;au;au=au->next) {
01c8f85b 466 if((NOGetNoticeLevel(au) & noticelevel) && !(NOGetAuthLevel(au) & __NO_RELAY)) {
3e3692bf
CP
467 for(nl=au->nick;nl;nl=nl->next)
468 if(noperserv_policy_command_permitted(permissionlevel, nl->nick))
469 controlreply(nl->nick, "$%s$ %s", flags, buf);
470 }
471 }
472}