]>
jfr.im git - irc/quakenet/newserv.git/blob - request/request.c
1 /* shroud's service request */
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"
14 #include "request_block.h"
15 #include "request_fasttrack.h"
17 #include "sqrequest.h"
22 CommandTree
*rqcommands
;
24 void rq_registeruser(void);
25 void rq_handler(nick
*target
, int type
, void **args
);
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
);
36 #define min(a,b) ((a > b) ? b : a)
47 static int extloaded
= 0;
53 if(!rq_initfasttrack())
58 rqcommands
= newcommandtree();
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
);
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
);
72 rq_logfd
= fopen(RQ_LOGFILE
, "a");
74 scheduleoneshot(time(NULL
) + 1, (ScheduleCallback
)&rq_registeruser
, NULL
);
81 deregisterlocaluser(rqnick
, NULL
);
83 deletecommandfromtree(rqcommands
, "showcommands", &rqcmd_showcommands
);
84 deletecommandfromtree(rqcommands
, "requestbot", &rqcmd_request
);
85 deletecommandfromtree(rqcommands
, "requestspamscan", &rqcmd_requestspamscan
);
86 deletecommandfromtree(rqcommands
, "requestop", &rqcmd_requestop
);
88 deletecommandfromtree(rqcommands
, "addblock", &rqcmd_addblock
);
89 deletecommandfromtree(rqcommands
, "delblock", &rqcmd_delblock
);
90 deletecommandfromtree(rqcommands
, "listblocks", &rqcmd_listblocks
);
91 deletecommandfromtree(rqcommands
, "stats", &rqcmd_stats
);
93 destroycommandtree(rqcommands
);
102 deleteallschedules((ScheduleCallback
)&rq_registeruser
);
105 void rq_registeruser(void) {
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
,
113 cp
= findchannel(RQ_TLZ
);
116 localcreatechannel(rqnick
, RQ_TLZ
);
118 localjoinchannel(rqnick
, cp
);
121 char *rq_longtoduration(unsigned long interval
) {
122 static char buf
[100];
124 strncpy(buf
, longtoduration(interval
, 0), sizeof(buf
));
126 /* chop off last character if it's a space */
127 if (buf
[strlen(buf
)] == ' ')
128 buf
[strlen(buf
)] = '\0';
133 void rq_handler(nick
*target
, int type
, void **params
) {
145 cargc
= splitline(line
, cargv
, 30, 0);
150 cmd
= findcommandintree(rqcommands
, cargv
[0], 1);
153 sendnoticetouser(rqnick
, user
, "Unknown command.");
158 if ((cmd
->level
& RQU_OPER
) && !IsOper(user
)) {
159 sendnoticetouser(rqnick
, user
, "Sorry, this command is not "
160 "available to you.");
165 if (cargc
- 1 > cmd
->maxparams
)
166 rejoinline(cargv
[cmd
->maxparams
], cargc
- cmd
->maxparams
);
168 /* handle the command */
169 cmd
->handler((void*)user
, min(cargc
- 1, cmd
->maxparams
), &(cargv
[1]));
173 scheduleoneshot(time(NULL
) + 5, (ScheduleCallback
)&rq_registeruser
, NULL
);
177 qr_handle_notice(params
[0], params
[1]);
183 int rqcmd_showcommands(void *user
, int cargc
, char **cargv
) {
184 nick
* np
= (nick
*)user
;
186 Command
* cmdlist
[50];
188 n
= getcommandlist(rqcommands
, cmdlist
, 50);
190 sendnoticetouser(rqnick
, np
, "Available commands:");
191 sendnoticetouser(rqnick
, np
, "-------------------");
193 for (i
= 0; i
< n
; i
++) {
194 if ((cmdlist
[i
]->level
& RQU_OPER
) && !IsOper(np
))
197 sendnoticetouser(rqnick
, np
, "%s", cmdlist
[i
]->command
->content
);
200 sendnoticetouser(rqnick
, np
, "End of SHOWCOMMANDS");
205 int rq_genericrequestcheck(nick
*np
, char *channelname
, channel
**cp
, nick
**qnick
) {
206 unsigned long *userhand
;
209 if (!IsAccount(np
)) {
210 sendnoticetouser(rqnick
, np
, "Error: You must be authed to perform a service request.");
215 *cp
= findchannel(channelname
);
218 sendnoticetouser(rqnick
, np
, "Error: Channel '%s' does not exist on the network.",
224 *qnick
= getnickbynick(RQ_QNICK
);
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
);
233 userhand
= getnumerichandlefromchanhash((*cp
)->users
, np
->numeric
);
235 if (userhand
== NULL
) {
236 sendnoticetouser(rqnick
, np
, "Error: You're not on that channel.");
241 if ((*userhand
& CUMODE_OP
) == 0) {
242 sendnoticetouser(rqnick
, np
, "Error: You must be op'd on the channel to "
243 "request a service.");
248 block
= rq_findblock(channelname
);
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;
260 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
261 "service to '%s'.", channelname
);
263 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
270 block
= rq_findblock(np
->authname
);
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()));
280 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
282 /* give them another 5 minutes to think about it */
283 block
->expires
+= 300;
294 int rqcmd_request(void *user
, int cargc
, char **cargv
) {
295 nick
*np
= (nick
*)user
;
297 unsigned long *qhand
;
304 sendnoticetouser(rqnick
, np
, "Syntax: requestbot <#channel>");
311 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &qnick
) == RQ_ERROR
) {
317 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
320 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_QNICK
);
329 retval
= lr_requestl(rqnick
, np
, cp
, qnick
);
331 if (rq_logfd
!= NULL
) {
334 strftime(now
, sizeof(now
), "%c", localtime(&now_ts
));
336 fprintf(rq_logfd
, "%s: request (%s) for %s from %s!%s@%s%s%s: Request was %s.\n",
337 now
, RQ_QNICK
, cp
->index
->name
->content
,
338 np
->nick
, np
->ident
, np
->host
->name
->content
, IsAccount(np
)?"/":"", IsAccount(np
)?np
->authname
:"",
339 (retval
== RQ_OK
) ? "accepted" : "denied");
343 if (retval
== RQ_ERROR
)
345 else if (retval
== RQ_OK
)
351 int rqcmd_requestspamscan(void *user
, int cargc
, char **cargv
) {
352 nick
*np
= (nick
*)user
;
355 unsigned long *qhand
, *shand
;
359 sendnoticetouser(rqnick
, np
, "Syntax: requestspamscan <#channel>");
366 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &qnick
) == RQ_ERROR
) {
372 snick
= getnickbynick(RQ_SNICK
);
374 if (snick
== NULL
|| findserver(RQ_SSERVER
) < 0) {
375 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
376 "Please try again later.", RQ_SNICK
);
383 /* does the user already have S on that channel? */
384 shand
= getnumerichandlefromchanhash(cp
->users
, snick
->numeric
);
387 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_SNICK
);
395 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
398 /* great, now try to request */
399 retval
= qr_requests(rqnick
, np
, cp
, qnick
);
403 else if (retval
== RQ_ERROR
)
408 /* channel apparently doesn't have Q */
410 sendnoticetouser(rqnick
, np
, "Error: You need %s in order to be "
411 "able to request %s.", RQ_QNICK
, RQ_SNICK
);
419 int rqcmd_requestop(void *source
, int cargc
, char **cargv
) {
420 nick
*np2
, *np
= (nick
*)source
;
428 sendnoticetouser(rqnick
, np
, "Syntax: requestop <#channel> [nick]");
433 cp
= findchannel(cargv
[0]);
436 sendnoticetouser(rqnick
, np
, "Error: Channel '%s' does not exist on the network.",
443 user
= getnickbynick(cargv
[1]);
446 sendnoticetouser(rqnick
, np
, "Error: No such user.");
452 if (getnettime() - np
->timestamp
< 300) {
453 sendnoticetouser(rqnick
, np
, "Error: You connected %s ago. To"
454 " request ops you must have been on the network for"
455 " at least 5 minutes.",
456 rq_longtoduration(getnettime() - np
->timestamp
));
461 if (getnettime() - user
->timestamp
< 300) {
462 sendnoticetouser(rqnick
, np
, "Error: The nick you requested op for"
463 " connected %s ago. To request op, it must have"
464 "been on the network for at least 5 minutes.",
465 rq_longtoduration(getnettime() - user
->timestamp
));
470 hand
= getnumerichandlefromchanhash(cp
->users
, user
->numeric
);
473 sendnoticetouser(rqnick
, np
, "Error: User %s is not on channel '%s'.", user
->nick
, cargv
[0]);
481 localsetmodeinit(&changes
, cp
, rqnick
);
483 /* reop any services first */
484 for(a
=0;a
<cp
->users
->hashsize
;a
++) {
485 if(cp
->users
->content
[a
] != nouser
) {
486 np2
= getnickbynumeric(cp
->users
->content
[a
]);
488 if (IsService(np2
) && (np2
->nick
[1] == '\0') && !(cp
->users
->content
[a
] & CUMODE_OP
)) {
489 localdosetmode_nick(&changes
, np2
, MC_OP
);
495 localsetmodeflush(&changes
, 1);
499 sendnoticetouser(rqnick
, np
, "1 service was reopped.");
501 sendnoticetouser(rqnick
, np
, "%d services were reopped.", count
);
506 for (a
=0;a
<cp
->users
->hashsize
;a
++) {
507 if ((cp
->users
->content
[a
] != nouser
) && (cp
->users
->content
[a
] & CUMODE_OP
)) {
508 sendnoticetouser(rqnick
, np
, "There are ops on channel '%s'. This command can only be"
509 " used if there are no ops.", cargv
[0]);
515 if (sp_countsplitservers() > 0) {
516 sendnoticetouser(rqnick
, np
, "One or more servers are currently split. Wait until the"
517 " netsplit is over and try again.");
522 if (cf_wouldreop(user
, cp
)) {
523 localsetmodeinit(&changes
, cp
, rqnick
);
524 localdosetmode_nick(&changes
, user
, MC_OP
);
525 localsetmodeflush(&changes
, 1);
527 sendnoticetouser(rqnick
, np
, "Chanfix opped you on the specified channel.");
529 ret
= cf_fixchannel(cp
);
531 if (ret
== CFX_NOUSERSAVAILABLE
)
532 sendnoticetouser(rqnick
, np
, "Chanfix knows regular ops for that channel. They will"
533 " be opped when they return.");
535 sendnoticetouser(rqnick
, np
, "Chanfix has opped known ops for that channel.");
542 int rqcmd_addblock(void *user
, int cargc
, char **cargv
) {
543 nick
*np
= (nick
*)user
;
549 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
555 sendnoticetouser(rqnick
, np
, "Syntax: addblock <mask> <duration> <reason>");
560 block
= rq_findblock(cargv
[0]);
563 sendnoticetouser(rqnick
, np
, "That mask is already blocked by %s "
564 "(reason: %s).", block
->creator
->content
, block
->reason
->content
);
570 account
= np
->authname
;
574 expires
= getnettime() + durationtolong(cargv
[1]);
576 rq_addblock(cargv
[0], cargv
[2], account
, 0, expires
);
578 sendnoticetouser(rqnick
, np
, "Blocked channels/accounts matching '%s' from "
579 "requesting a service.", cargv
[0]);
584 int rqcmd_delblock(void *user
, int cargc
, char **cargv
) {
585 nick
*np
= (nick
*)user
;
589 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
595 sendnoticetouser(rqnick
, np
, "Syntax: delblock <mask>");
600 result
= rq_removeblock(cargv
[0]);
603 sendnoticetouser(rqnick
, np
, "Block for '%s' was removed.", cargv
[0]);
607 sendnoticetouser(rqnick
, np
, "There is no such block.");
613 int rqcmd_listblocks(void *user
, int cargc
, char **cargv
) {
614 nick
*np
= (nick
*)user
;
619 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
624 sendnoticetouser(rqnick
, np
, "Mask By Expires"
627 for (i
= 0; i
< rqblocks
.cursi
; i
++) {
628 block
= ((rq_block
*)rqblocks
.content
)[i
];
630 if (block
.expires
!= 0 && block
.expires
< getnettime())
631 continue; /* ignore blocks which have already expired,
632 rq_findblock will deal with them later on */
634 if (cargc
< 1 || match2strings(block
.pattern
->content
, cargv
[0]))
635 sendnoticetouser(rqnick
, np
, "%-11s %-9s %-25s %s",
636 block
.pattern
->content
, block
.creator
->content
,
637 rq_longtoduration(block
.expires
- getnettime()),
638 block
.reason
->content
);
641 sendnoticetouser(rqnick
, np
, "--- End of blocklist");
646 int rqcmd_stats(void *user
, int cargc
, char **cargv
) {
647 nick
*np
= (nick
*)user
;
650 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
655 sendnoticetouser(rqnick
, np
, "Total requests: %d", rq_count
);
656 sendnoticetouser(rqnick
, np
, "Successful requests: %d", rq_success
);
657 sendnoticetouser(rqnick
, np
, "Failed requests: %d", rq_failed
);
658 sendnoticetouser(rqnick
, np
, "- Blocked: %d", rq_blocked
);
660 lr_requeststats(rqnick
, np
);
661 qr_requeststats(rqnick
, np
);