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