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