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