]> jfr.im git - irc/quakenet/newserv.git/blame - request/request.c
Reorganise the JIT bit
[irc/quakenet/newserv.git] / request / request.c
CommitLineData
25b7d0fa
P
1 /* shroud's service request */
2
3#include <string.h>
4#include "../localuser/localuser.h"
5#include "../localuser/localuserchannel.h"
6#include "../core/schedule.h"
7#include "../lib/irc_string.h"
8#include "../lib/splitline.h"
9#include "../control/control.h"
10#include "request.h"
11#include "request_block.h"
12#include "lrequest.h"
13#include "sqrequest.h"
f3c45977 14#include "user.h"
25b7d0fa
P
15
16nick *rqnick;
17CommandTree *rqcommands;
18
19void rq_registeruser(void);
20void rq_handler(nick *target, int type, void **args);
21
22int rqcmd_showcommands(void *user, int cargc, char **cargv);
23int rqcmd_request(void *user, int cargc, char **cargv);
24int rqcmd_requestspamscan(void *user, int cargc, char **cargv);
25int rqcmd_addblock(void *user, int cargc, char **cargv);
26int rqcmd_delblock(void *user, int cargc, char **cargv);
27int rqcmd_listblocks(void *user, int cargc, char **cargv);
28int rqcmd_stats(void *user, int cargc, char **cargv);
29int rqcmd_legacyrequest(void *user, int cargc, char **cargv);
30
f3c45977
P
31int rqcmd_adduser(void *user, int cargc, char **cargv);
32int rqcmd_deluser(void *user, int cargc, char **cargv);
33int rqcmd_changelev(void *user, int cargc, char **cargv);
34int rqcmd_userlist(void *user, int cargc, char **cargv);
35
25b7d0fa
P
36#define min(a,b) ((a > b) ? b : a)
37
38/* stats counters */
39int rq_count = 0;
40int rq_failed = 0;
41int rq_success = 0;
42int rq_blocked = 0;
43
44void _init(void) {
45 rqcommands = newcommandtree();
46
47 addcommandtotree(rqcommands, "showcommands", RQU_ANY, 1, &rqcmd_showcommands);
48 addcommandtotree(rqcommands, "requestbot", RQU_ANY, 1, &rqcmd_request);
49 addcommandtotree(rqcommands, "requestspamscan", RQU_ANY, 1, &rqcmd_requestspamscan);
f3c45977
P
50 addcommandtotree(rqcommands, "addblock", RQU_ACCOUNT, 3, &rqcmd_addblock);
51 addcommandtotree(rqcommands, "delblock", RQU_ACCOUNT, 1, &rqcmd_delblock);
52 addcommandtotree(rqcommands, "listblocks", RQU_ACCOUNT, 1, &rqcmd_listblocks);
53 addcommandtotree(rqcommands, "stats", RQU_ACCOUNT, 1, &rqcmd_stats);
54
55 addcommandtotree(rqcommands, "adduser", RQU_OPER, 2, &rqcmd_adduser);
56 addcommandtotree(rqcommands, "deluser", RQU_OPER, 1, &rqcmd_deluser);
57 addcommandtotree(rqcommands, "changelev", RQU_OPER, 2, &rqcmd_changelev);
58 addcommandtotree(rqcommands, "userlist", RQU_OPER, 1, &rqcmd_userlist);
59
25b7d0fa
P
60 /* old legacy stuff */
61 addcommandtotree(rqcommands, "requestq", RQU_ANY, 1, &rqcmd_legacyrequest);
62
63 rq_initblocks();
64 qr_initrequest();
f3c45977 65 ru_load();
25b7d0fa
P
66
67 scheduleoneshot(time(NULL) + 1, (ScheduleCallback)&rq_registeruser, NULL);
68}
69
70void _fini(void) {
71 deregisterlocaluser(rqnick, NULL);
72
73 deletecommandfromtree(rqcommands, "showcommands", &rqcmd_showcommands);
74 deletecommandfromtree(rqcommands, "requestbot", &rqcmd_request);
75 deletecommandfromtree(rqcommands, "requestspamscan", &rqcmd_requestspamscan);
76 deletecommandfromtree(rqcommands, "addblock", &rqcmd_addblock);
77 deletecommandfromtree(rqcommands, "delblock", &rqcmd_delblock);
78 deletecommandfromtree(rqcommands, "listblocks", &rqcmd_listblocks);
79 deletecommandfromtree(rqcommands, "stats", &rqcmd_stats);
80
f3c45977
P
81 deletecommandfromtree(rqcommands, "adduser", &rqcmd_adduser);
82 deletecommandfromtree(rqcommands, "deluser", &rqcmd_deluser);
83 deletecommandfromtree(rqcommands, "changelev", &rqcmd_changelev);
84 deletecommandfromtree(rqcommands, "userlist", &rqcmd_userlist);
85
86
25b7d0fa
P
87 /* old legacy stuff */
88 deletecommandfromtree(rqcommands, "requestq", &rqcmd_legacyrequest);
89
90 destroycommandtree(rqcommands);
91
92 rq_finiblocks();
93 qr_finirequest();
f3c45977 94 ru_persist();
25b7d0fa
P
95
96 deleteallschedules((ScheduleCallback)&rq_registeruser);
97}
98
99void rq_registeruser(void) {
100 channel *cp;
101
102 rqnick = registerlocaluser(RQ_REQUEST_NICK, RQ_REQUEST_USER, RQ_REQUEST_HOST,
103 RQ_REQUEST_REAL, RQ_REQUEST_AUTH,
104 UMODE_ACCOUNT | UMODE_SERVICE | UMODE_OPER,
105 rq_handler);
106
107 cp = findchannel(RQ_TLZ);
108
109 if (cp == NULL)
110 localcreatechannel(rqnick, RQ_TLZ);
111 else
112 localjoinchannel(rqnick, cp);
113}
114
115char *rq_longtoduration(unsigned long interval) {
116 static char buf[100];
117
118 strncpy(buf, longtoduration(interval, 0), sizeof(buf));
119
120 /* chop off last character if it's a space */
121 if (buf[strlen(buf)] == ' ')
122 buf[strlen(buf)] = '\0';
123
124 return buf;
125}
126
127void rq_handler(nick *target, int type, void **params) {
128 Command* cmd;
129 nick* user;
130 char* line;
131 int cargc;
132 char* cargv[30];
133
134 switch (type) {
135 case LU_PRIVMSG:
136 case LU_SECUREMSG:
137 user = params[0];
138 line = params[1];
139 cargc = splitline(line, cargv, 30, 0);
140
141 if (cargc == 0)
142 return;
143
144 cmd = findcommandintree(rqcommands, cargv[0], 1);
145
146 if (cmd == NULL) {
147 sendnoticetouser(rqnick, user, "Unknown command.");
148
149 return;
150 }
151
f3c45977 152 if ((cmd->level & RQU_OPER) && !IsOper(user)) {
25b7d0fa
P
153 sendnoticetouser(rqnick, user, "Sorry, this command is not "
154 "available to you.");
155
156 return;
157 }
158
f3c45977
P
159 if ((cmd->level & RQU_ACCOUNT) && (!IsAccount(user) || ru_getlevel(user) == 0) && !IsOper(user)) {
160 sendnoticetouser(rqnick, user, "Sorry, this command is not "
161 "available to you.");
162
163 return;
164 }
165
25b7d0fa
P
166 if (cargc - 1 > cmd->maxparams)
167 rejoinline(cargv[cmd->maxparams], cargc - cmd->maxparams);
168
169 /* handle the command */
170 cmd->handler((void*)user, min(cargc - 1, cmd->maxparams), &(cargv[1]));
171
172 break;
173 case LU_KILLED:
174 scheduleoneshot(time(NULL) + 5, (ScheduleCallback)&rq_registeruser, NULL);
175
176 break;
177 case LU_PRIVNOTICE:
178 qr_handlenotice(params[0], params[1]);
179
180 break;
181 }
182}
183
184int rqcmd_showcommands(void *user, int cargc, char **cargv) {
185 int n, i;
186 Command* cmdlist[50];
187
188 n = getcommandlist(rqcommands, cmdlist, 50);
189
190 sendnoticetouser(rqnick, (nick*)user, "Available commands:");
191 sendnoticetouser(rqnick, (nick*)user, "-------------------");
192
193 for (i = 0; i < n; i++) {
f3c45977
P
194 if (((cmdlist[i]->level & RQU_OPER) == 0 || IsOper((nick*)user)) &&
195 (((cmdlist[i]->level & RQU_ACCOUNT) == 0 || (IsOper((nick*)user) || (IsAccount((nick*)user)) && ru_getlevel((nick*)user) > 0))))
25b7d0fa
P
196 sendnoticetouser(rqnick, (nick*)user, "%s", cmdlist[i]->command->content);
197 }
198
199 sendnoticetouser(rqnick, (nick*)user, "End of SHOWCOMMANDS");
200
201 return 0;
202}
203
204int rq_genericrequestcheck(nick *np, char *channelname, channel **cp, nick **lnick, nick **qnick) {
205 unsigned long *userhand;
206 rq_block *block;
207
208 if (!IsAccount(np)) {
209 sendnoticetouser(rqnick, np, "Error: You must be authed.");
210
211 return RQ_ERROR;
212 }
213
214 *cp = findchannel(channelname);
215
216 if (*cp == NULL) {
217 sendnoticetouser(rqnick, np, "Error: Channel %s does not exist.",
218 channelname);
219
220 return RQ_ERROR;
221 }
222
223 *lnick = getnickbynick(RQ_LNICK);
224
225 if (*lnick == NULL || findserver(RQ_LSERVER) < 0) {
226 sendnoticetouser(rqnick, np, "Error: %s does not seem to be online. "
227 "Try again later.", RQ_LNICK);
228
229 return RQ_ERROR;
230 }
231
232 *qnick = getnickbynick(RQ_QNICK);
233
234 if (*qnick == NULL || findserver(RQ_QSERVER) < 0) {
235 sendnoticetouser(rqnick, np, "Error: %s does not seem to be online. "
236 "Try again later.", RQ_QNICK);
237
238 return RQ_ERROR;
239 }
240
241 userhand = getnumerichandlefromchanhash((*cp)->users, np->numeric);
242
243 if (userhand == NULL) {
244 sendnoticetouser(rqnick, np, "Error: You're not on that channel.");
245
246 return RQ_ERROR;
247 }
248
249 if ((*userhand & CUMODE_OP) == 0) {
250 sendnoticetouser(rqnick, np, "Error: You must be op'd on the channel to "
251 "request a service.");
252
253 return RQ_ERROR;
254 }
255
256 block = rq_findblock(channelname);
257
258 if (block != NULL) {
259 sendnoticetouser(rqnick, np, "Error: You are not allowed to request a "
260 "service to this channel.");
261 sendnoticetouser(rqnick, np, "Reason: %s", block->reason->content);
262
263 rq_blocked++;
264
265 return RQ_ERROR;
266 }
267
268 block = rq_findblock(np->authname);
269
270 /* only tell the user if the block is going to expire in the next 48 hours
271 so we can have our fun with longterm blocks.
272 the request subsystems should deal with longterm blocks on their own */
273 if (block != NULL && block->expires < getnettime() + 3600 * 24 * 2) {
274 sendnoticetouser(rqnick, np, "Error: You are not allowed to request a "
275 "service. Keep waiting for at least %s before you try again.",
276 rq_longtoduration(block->expires - getnettime()));
277
278 sendnoticetouser(rqnick, np, "Reason: %s", block->reason->content);
279
280 /* give them another 5 minutes to think about it */
281 block->expires += 300;
282 rq_saveblocks();
283
284 rq_blocked++;
285
286 return RQ_ERROR;
287 }
288
289 return RQ_OK;
290}
291
292int rqcmd_request(void *user, int cargc, char **cargv) {
293 nick *np = (nick*)user;
294 nick *lnick, *qnick;
295 unsigned long *lhand, *qhand;
cbdd5aab 296 channel *cp, *logcp;
25b7d0fa
P
297 int retval;
298
299 if (cargc < 1) {
300 sendnoticetouser(rqnick, np, "Syntax: requestbot <#channel>");
301
302 return RQ_ERROR;
303 }
304
305 rq_count++;
306
307 if (rq_genericrequestcheck(np, cargv[0], &cp, &lnick, &qnick) == RQ_ERROR) {
308 rq_failed++;
309
310 return RQ_ERROR;
311 }
312
313 lhand = getnumerichandlefromchanhash(cp->users, lnick->numeric);
314
315 qhand = getnumerichandlefromchanhash(cp->users, qnick->numeric);
316
317 if (qhand != NULL) {
318 sendnoticetouser(rqnick, np, "Error: %s is already on that channel.", RQ_QNICK);
319
320 rq_failed++;
321
322 return RQ_ERROR;
323 }
324
325 retval = RQ_ERROR;
326
327 if (lhand == NULL && qhand == NULL) {
328 /* try 'instant' Q request */
329 retval = qr_instantrequestq(np, cp);
330 }
331
332 if (retval == RQ_ERROR) {
333 if (lhand == NULL) {
334 /* user 'wants' L */
335
336 retval = lr_requestl(rqnick, np, cp, lnick);
cbdd5aab
P
337
338 logcp = findchannel(RQ_LOGCHANNEL);
339
340 if (logcp) {
341 sendmessagetochannel(rqnick, logcp, "request (%s) for %s from %s: Request was %s.", RQ_LNICK, cp->index->name->content, np->nick, (retval == RQ_OK) ? "accepted" : "denied");
342 }
25b7d0fa
P
343 } else {
344 /* user 'wants' Q */
345
346 retval = qr_requestq(rqnick, np, cp, lnick, qnick);
347 }
348 }
349
350 if (retval == RQ_ERROR)
351 rq_failed++;
352 else if (retval == RQ_OK)
353 rq_success++;
354
355 return retval;
356}
357
358int rqcmd_requestspamscan(void *user, int cargc, char **cargv) {
359 nick *np = (nick*)user;
360 channel *cp;
361 nick *lnick, *qnick, *snick;
362 unsigned long *lhand, *qhand, *shand;
363 int retval;
364
365 if (cargc < 1) {
366 sendnoticetouser(rqnick, np, "Syntax: requestspamscan <#channel>");
367
368 return RQ_ERROR;
369 }
370
371 rq_count++;
372
373 if (rq_genericrequestcheck(np, cargv[0], &cp, &lnick, &qnick) == RQ_ERROR) {
374 rq_failed++;
375
376 return RQ_ERROR;
377 }
378
379 snick = getnickbynick(RQ_SNICK);
380
381 if (snick == NULL || findserver(RQ_SSERVER) < 0) {
382 sendnoticetouser(rqnick, np, "Error: %s does not seem to be online. "
383 "Try again later.", RQ_SNICK);
384
385 rq_failed++;
386
387 return RQ_ERROR;
388 }
389
390 /* does the user already have S on that channel? */
391 shand = getnumerichandlefromchanhash(cp->users, snick->numeric);
392
393 if (shand != NULL) {
394 sendnoticetouser(rqnick, np, "Error: %s is already on that channel.", RQ_SNICK);
395
396 rq_failed++;
397
398 return RQ_ERROR;
399 }
400
401 /* we need either L or Q */
402 lhand = getnumerichandlefromchanhash(cp->users, lnick->numeric);
403 qhand = getnumerichandlefromchanhash(cp->users, qnick->numeric);
404
405 if (lhand || qhand) {
406 /* great, now try to request */
407 retval = qr_requests(rqnick, np, cp, lnick, qnick);
408
409 if (retval == RQ_OK)
410 rq_success++;
411 else if (retval == RQ_ERROR)
412 rq_failed++;
413
414 return retval;
415 } else {
416 /* channel apparently doesn't have L or Q */
417
418 sendnoticetouser(rqnick, np, "Error: You need %s or %s in order to be "
419 "able to request %s.", RQ_LNICK, RQ_QNICK, RQ_SNICK);
420
421 rq_failed++;
422
423 return RQ_ERROR;
424 }
425}
426
427int rqcmd_addblock(void *user, int cargc, char **cargv) {
428 nick *np = (nick*)user;
429 rq_block *block;
430 time_t expires;
431 char *account;
f3c45977
P
432 int level = ru_getlevel(np);
433
434 if (level < 20) {
435 sendnoticetouser(rqnick, np, "You do not have access to this command.");
25b7d0fa 436
f3c45977
P
437 return RQ_ERROR;
438 }
439
25b7d0fa
P
440 if (cargc < 3) {
441 sendnoticetouser(rqnick, np, "Syntax: addblock <mask> <duration> <reason>");
442
443 return RQ_ERROR;
444 }
445
446 block = rq_findblock(cargv[0]);
447
448 if (block != NULL) {
449 sendnoticetouser(rqnick, np, "That mask is already blocked by %s "
450 "(reason: %s).", block->creator->content, block->reason->content);
451
452 return RQ_ERROR;
453 }
454
455 if (IsAccount(np))
456 account = np->authname;
457 else
458 account = "unknown";
459
460 expires = getnettime() + durationtolong(cargv[1]);
461
f3c45977
P
462 if (expires > getnettime() + RQU_HELPER_MAXEXPIRE && level < 30) {
463 sendnoticetouser(rqnick, np, "Maximum expiry time is %s.", rq_longtoduration(RQU_HELPER_MAXEXPIRE));
464
465 return RQ_ERROR;
466 }
467
25b7d0fa
P
468 rq_addblock(cargv[0], cargv[2], account, 0, expires);
469
470 sendnoticetouser(rqnick, np, "Blocked channels/accounts matching '%s' from "
471 "requesting a service.", cargv[0]);
472
473 return RQ_OK;
474}
475
476int rqcmd_delblock(void *user, int cargc, char **cargv) {
477 nick *np = (nick*)user;
f3c45977
P
478 int result, level;
479 rq_block *block;
480
481 level = ru_getlevel(np);
482
483 if (level < 20) {
484 sendnoticetouser(rqnick, np, "You do not have access to this command.");
25b7d0fa 485
f3c45977
P
486 return RQ_ERROR;
487 }
488
25b7d0fa 489 if (cargc < 1) {
f3c45977 490 sendnoticetouser(rqnick, np, "Syntax: delblock <mask>");
25b7d0fa
P
491
492 return RQ_ERROR;
493 }
494
f3c45977
P
495 block = rq_findblock(cargv[0]);
496
497 if (block != NULL && level < 50) {
498 if (ircd_strcmp(block->creator->content, np->authname) != 0) {
499 sendnoticetouser(rqnick, np, "This block was created by someone else. You cannot remove it.");
500
501 return RQ_ERROR;
502 }
503 }
504
25b7d0fa
P
505 result = rq_removeblock(cargv[0]);
506
507 if (result > 0) {
508 sendnoticetouser(rqnick, np, "Block for '%s' was removed.", cargv[0]);
509
510 return RQ_OK;
511 } else {
512 sendnoticetouser(rqnick, np, "There is no such block.");
513
514 return RQ_OK;
515 }
516}
517
518int rqcmd_listblocks(void *user, int cargc, char **cargv) {
519 nick *np = (nick*)user;
520 rq_block block;
f3c45977
P
521 int i, level;
522
523 level = ru_getlevel(np);
524
525 if (level < 10) {
526 sendnoticetouser(rqnick, np, "You do not have access to this command.");
25b7d0fa 527
f3c45977
P
528 return RQ_ERROR;
529 }
530
25b7d0fa
P
531 sendnoticetouser(rqnick, np, "Mask By Expires"
532 " Reason");
533
534 for (i = 0; i < rqblocks.cursi; i++) {
535 block = ((rq_block*)rqblocks.content)[i];
536
537 if (block.expires != 0 && block.expires < getnettime())
538 continue; /* ignore blocks which have already expired,
539 rq_findblock will deal with them later on */
540
541 if (cargc < 1 || match2strings(block.pattern->content, cargv[0]))
542 sendnoticetouser(rqnick, np, "%-11s %-9s %-25s %s",
543 block.pattern->content, block.creator->content,
544 rq_longtoduration(block.expires - getnettime()),
545 block.reason->content);
546 }
547
548 sendnoticetouser(rqnick, np, "--- End of blocklist");
549
550 return RQ_OK;
551}
552
553int rqcmd_stats(void *user, int cargc, char **cargv) {
554 nick *np = (nick*)user;
f3c45977
P
555 int level = ru_getlevel(np);
556
557 if (level < 10) {
558 sendnoticetouser(rqnick, np, "You do not have access to this command.");
25b7d0fa 559
f3c45977
P
560 return RQ_ERROR;
561 }
562
25b7d0fa
P
563 sendnoticetouser(rqnick, np, "Total requests: %d", rq_count);
564 sendnoticetouser(rqnick, np, "Successful requests: %d", rq_success);
565 sendnoticetouser(rqnick, np, "Failed requests: %d", rq_failed);
566 sendnoticetouser(rqnick, np, "- Blocked: %d", rq_blocked);
567
568 lr_requeststats(rqnick, np);
569 qr_requeststats(rqnick, np);
570
571 return RQ_OK;
572}
573
574int rqcmd_legacyrequest(void *user, int cargc, char **cargv) {
575 nick *np = (nick*)user;
576
577 sendnoticetouser(rqnick, np, "This command is no longer valid. Please use "
578 "/msg %s REQUESTBOT #channel instead.", RQ_REQUEST_NICK);
579
580 return RQ_OK;
581}
f3c45977
P
582
583int rqcmd_adduser(void *user, int cargc, char **cargv) {
584 nick *np = (nick*)user;
585 int result, level;
586
587 if (cargc < 2) {
588 sendnoticetouser(rqnick, np, "Syntax: adduser <account> <level>");
589
590 return RQ_ERROR;
591 }
592
593 level = atoi(cargv[1]);
594
595 if (level <= 0) {
596 sendnoticetouser(rqnick, np, "Level must be a positive integer.");
597
598 return RQ_ERROR;
599 }
600
601 result = ru_create(cargv[0], level);
602
603 if (result) {
604 sendnoticetouser(rqnick, np, "User '%s' was added with level '%d'.", cargv[0], level);
605
606 return RQ_OK;
607 } else {
608 sendnoticetouser(rqnick, np, "Something strange happened. Contact shroud.");
609
610 return RQ_ERROR;
611 }
612}
613
614int rqcmd_deluser(void *user, int cargc, char **cargv) {
615 nick *np = (nick*)user;
616 int level;
617
618 if (cargc < 1) {
619 sendnoticetouser(rqnick, np, "Syntax: deluser <account>");
620
621 return RQ_ERROR;
622 }
623
624 level = ru_getlevel_str(cargv[0]);
625
626 if (level <= 0) {
627 sendnoticetouser(rqnick, np, "There is no such user.");
628
629 return RQ_ERROR;
630 }
631
632 ru_destroy(cargv[0]);
633
634 sendnoticetouser(rqnick, np, "Done.");
635
636 return RQ_OK;
637}
638
639int rqcmd_changelev(void *user, int cargc, char **cargv) {
640 nick *np = (nick*)user;
641 int result, level;
642
643 if (cargc < 2) {
644 sendnoticetouser(rqnick, np, "Syntax: changelev <account> <level>");
645
646 return RQ_ERROR;
647 }
648
649 level = atoi(cargv[1]);
650
651 if (level <= 0) {
652 sendnoticetouser(rqnick, np, "Level must be a positive integer.");
653
654 return RQ_ERROR;
655 }
656
657 if (ru_getlevel_str(cargv[0]) <= 0) {
658 sendnoticetouser(rqnick, np, "Unknown user.");
659
660 return RQ_ERROR;
661 }
662
663 result = ru_setlevel(cargv[0], level);
664
665 if (result != 0) {
666 sendnoticetouser(rqnick, np, "Done.");
667
668 return RQ_OK;
669 } else {
670 sendnoticetouser(rqnick, np, "Something strange happened. Contact shroud.");
671
672 return RQ_ERROR;
673 }
674}
675
676int rqcmd_userlist(void *user, int cargc, char **cargv) {
677 nick *np = (nick*)user;
678 r_user_t *userp = r_userlist;
679
680 sendnoticetouser(rqnick, np, "User Level");
681
682 while (userp) {
683 sendnoticetouser(rqnick, np, "%s %d", userp->name, userp->level);
684 userp = userp->next;
685 }
686
687 sendnoticetouser(rqnick, np, "--- End of USERS.");
688
689 return RQ_OK;
690}
691