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