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