]>
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"
16 #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 int rqcmd_adduser(void *user
, int cargc
, char **cargv
);
37 int rqcmd_deluser(void *user
, int cargc
, char **cargv
);
38 int rqcmd_changelev(void *user
, int cargc
, char **cargv
);
39 int rqcmd_userlist(void *user
, int cargc
, char **cargv
);
41 #define min(a,b) ((a > b) ? b : a)
52 static int extloaded
= 0;
60 rqcommands
= newcommandtree();
62 addcommandtotree(rqcommands
, "showcommands", RQU_ANY
, 1, &rqcmd_showcommands
);
63 addcommandtotree(rqcommands
, "requestbot", RQU_ANY
, 1, &rqcmd_request
);
64 addcommandtotree(rqcommands
, "requestspamscan", RQU_ANY
, 1, &rqcmd_requestspamscan
);
65 addcommandtotree(rqcommands
, "requestop", RQU_ANY
, 2, &rqcmd_requestop
);
67 addcommandtotree(rqcommands
, "addblock", RQU_ACCOUNT
, 3, &rqcmd_addblock
);
68 addcommandtotree(rqcommands
, "delblock", RQU_ACCOUNT
, 1, &rqcmd_delblock
);
69 addcommandtotree(rqcommands
, "listblocks", RQU_ACCOUNT
, 1, &rqcmd_listblocks
);
70 addcommandtotree(rqcommands
, "stats", RQU_ACCOUNT
, 1, &rqcmd_stats
);
72 addcommandtotree(rqcommands
, "adduser", RQU_OPER
, 2, &rqcmd_adduser
);
73 addcommandtotree(rqcommands
, "deluser", RQU_OPER
, 1, &rqcmd_deluser
);
74 addcommandtotree(rqcommands
, "changelev", RQU_OPER
, 2, &rqcmd_changelev
);
75 addcommandtotree(rqcommands
, "userlist", RQU_OPER
, 1, &rqcmd_userlist
);
80 rq_logfd
= fopen(RQ_LOGFILE
, "a");
82 scheduleoneshot(time(NULL
) + 1, (ScheduleCallback
)&rq_registeruser
, NULL
);
89 deregisterlocaluser(rqnick
, NULL
);
91 deletecommandfromtree(rqcommands
, "showcommands", &rqcmd_showcommands
);
92 deletecommandfromtree(rqcommands
, "requestbot", &rqcmd_request
);
93 deletecommandfromtree(rqcommands
, "requestspamscan", &rqcmd_requestspamscan
);
94 deletecommandfromtree(rqcommands
, "requestop", &rqcmd_requestop
);
96 deletecommandfromtree(rqcommands
, "addblock", &rqcmd_addblock
);
97 deletecommandfromtree(rqcommands
, "delblock", &rqcmd_delblock
);
98 deletecommandfromtree(rqcommands
, "listblocks", &rqcmd_listblocks
);
99 deletecommandfromtree(rqcommands
, "stats", &rqcmd_stats
);
101 deletecommandfromtree(rqcommands
, "adduser", &rqcmd_adduser
);
102 deletecommandfromtree(rqcommands
, "deluser", &rqcmd_deluser
);
103 deletecommandfromtree(rqcommands
, "changelev", &rqcmd_changelev
);
104 deletecommandfromtree(rqcommands
, "userlist", &rqcmd_userlist
);
106 destroycommandtree(rqcommands
);
112 if (rq_logfd
!= NULL
)
115 deleteallschedules((ScheduleCallback
)&rq_registeruser
);
118 void rq_registeruser(void) {
121 rqnick
= registerlocaluser(RQ_REQUEST_NICK
, RQ_REQUEST_USER
, RQ_REQUEST_HOST
,
122 RQ_REQUEST_REAL
, RQ_REQUEST_AUTH
,
123 UMODE_ACCOUNT
| UMODE_SERVICE
| UMODE_OPER
,
126 cp
= findchannel(RQ_TLZ
);
129 localcreatechannel(rqnick
, RQ_TLZ
);
131 localjoinchannel(rqnick
, cp
);
134 char *rq_longtoduration(unsigned long interval
) {
135 static char buf
[100];
137 strncpy(buf
, longtoduration(interval
, 0), sizeof(buf
));
139 /* chop off last character if it's a space */
140 if (buf
[strlen(buf
)] == ' ')
141 buf
[strlen(buf
)] = '\0';
146 void rq_handler(nick
*target
, int type
, void **params
) {
158 cargc
= splitline(line
, cargv
, 30, 0);
163 cmd
= findcommandintree(rqcommands
, cargv
[0], 1);
166 sendnoticetouser(rqnick
, user
, "Unknown command.");
171 if ((cmd
->level
& RQU_OPER
) && !IsOper(user
)) {
172 sendnoticetouser(rqnick
, user
, "Sorry, this command is not "
173 "available to you.");
178 if ((cmd
->level
& RQU_ACCOUNT
) && (!IsAccount(user
) || ru_getlevel(user
) == 0) && !IsOper(user
)) {
179 sendnoticetouser(rqnick
, user
, "Sorry, this command is not "
180 "available to you.");
185 if (cargc
- 1 > cmd
->maxparams
)
186 rejoinline(cargv
[cmd
->maxparams
], cargc
- cmd
->maxparams
);
188 /* handle the command */
189 cmd
->handler((void*)user
, min(cargc
- 1, cmd
->maxparams
), &(cargv
[1]));
193 scheduleoneshot(time(NULL
) + 5, (ScheduleCallback
)&rq_registeruser
, NULL
);
197 qr_handle_notice(params
[0], params
[1]);
203 int rqcmd_showcommands(void *user
, int cargc
, char **cargv
) {
204 nick
* np
= (nick
*)user
;
206 Command
* cmdlist
[50];
208 n
= getcommandlist(rqcommands
, cmdlist
, 50);
210 sendnoticetouser(rqnick
, np
, "Available commands:");
211 sendnoticetouser(rqnick
, np
, "-------------------");
213 for (i
= 0; i
< n
; i
++) {
214 if ((cmdlist
[i
]->level
& RQU_OPER
) && !IsOper(np
))
217 if ((cmdlist
[i
]->level
& RQU_ACCOUNT
) && !(IsOper(np
) || (IsAccount(np
) && ru_getlevel(np
) > 0)))
220 sendnoticetouser(rqnick
, np
, "%s", cmdlist
[i
]->command
->content
);
223 sendnoticetouser(rqnick
, np
, "End of SHOWCOMMANDS");
228 int rq_genericrequestcheck(nick
*np
, char *channelname
, channel
**cp
, nick
**lnick
, nick
**qnick
) {
229 unsigned long *userhand
;
232 if (!IsAccount(np
)) {
233 sendnoticetouser(rqnick
, np
, "Error: You must be authed.");
238 *cp
= findchannel(channelname
);
241 sendnoticetouser(rqnick
, np
, "Error: Channel %s does not exist.",
247 *lnick
= getnickbynick(RQ_LNICK
);
249 if (*lnick
== NULL
|| findserver(RQ_LSERVER
) < 0) {
250 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
251 "Try again later.", RQ_LNICK
);
256 *qnick
= getnickbynick(RQ_QNICK
);
258 if (*qnick
== NULL
|| findserver(RQ_QSERVER
) < 0) {
259 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
260 "Try again later.", RQ_QNICK
);
265 userhand
= getnumerichandlefromchanhash((*cp
)->users
, np
->numeric
);
267 if (userhand
== NULL
) {
268 sendnoticetouser(rqnick
, np
, "Error: You're not on that channel.");
273 if ((*userhand
& CUMODE_OP
) == 0) {
274 sendnoticetouser(rqnick
, np
, "Error: You must be op'd on the channel to "
275 "request a service.");
280 block
= rq_findblock(channelname
);
283 /* only say when block expires if <7 days */
284 if ( block
->expires
< getnettime() + 3600 * 24 * 7) {
285 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
286 "service to this channel. Keep waiting for at least %s before you try again.",
287 rq_longtoduration(block
->expires
- getnettime()));
288 /* give them another 5 minutes to think about it */
289 block
->expires
+= 300;
292 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
293 "service to this channel.");
295 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
302 block
= rq_findblock(np
->authname
);
304 /* only tell the user if the block is going to expire in the next 48 hours
305 so we can have our fun with longterm blocks.
306 the request subsystems should deal with longterm blocks on their own */
307 if (block
!= NULL
&& block
->expires
< getnettime() + 3600 * 24 * 2) {
308 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
309 "service. Keep waiting for at least %s before you try again.",
310 rq_longtoduration(block
->expires
- getnettime()));
312 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
314 /* give them another 5 minutes to think about it */
315 block
->expires
+= 300;
326 int rqcmd_request(void *user
, int cargc
, char **cargv
) {
327 nick
*np
= (nick
*)user
;
329 unsigned long *lhand
, *qhand
;
336 sendnoticetouser(rqnick
, np
, "Syntax: requestbot <#channel>");
343 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &lnick
, &qnick
) == RQ_ERROR
) {
349 lhand
= getnumerichandlefromchanhash(cp
->users
, lnick
->numeric
);
351 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
354 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_QNICK
);
363 if (lhand
== NULL
&& qhand
== NULL
) {
364 /* try 'instant' Q request */
365 retval
= qr_instantrequestq(np
, cp
);
368 if (retval
== RQ_ERROR
) {
372 retval
= lr_requestl(rqnick
, np
, cp
, lnick
);
374 if (rq_logfd
!= NULL
) {
377 strftime(now
, sizeof(now
), "%c", localtime(&now_ts
));
379 fprintf(rq_logfd
, "%s: request (%s) for %s from %s: Request was %s.\n", now
, RQ_LNICK
, cp
->index
->name
->content
, np
->nick
, (retval
== RQ_OK
) ? "accepted" : "denied");
385 retval
= qr_requestq(rqnick
, np
, cp
, lnick
, qnick
);
389 if (retval
== RQ_ERROR
)
391 else if (retval
== RQ_OK
)
397 int rqcmd_requestspamscan(void *user
, int cargc
, char **cargv
) {
398 nick
*np
= (nick
*)user
;
400 nick
*lnick
, *qnick
, *snick
;
401 unsigned long *lhand
, *qhand
, *shand
;
405 sendnoticetouser(rqnick
, np
, "Syntax: requestspamscan <#channel>");
412 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &lnick
, &qnick
) == RQ_ERROR
) {
418 snick
= getnickbynick(RQ_SNICK
);
420 if (snick
== NULL
|| findserver(RQ_SSERVER
) < 0) {
421 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
422 "Try again later.", RQ_SNICK
);
429 /* does the user already have S on that channel? */
430 shand
= getnumerichandlefromchanhash(cp
->users
, snick
->numeric
);
433 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_SNICK
);
440 /* we need either L or Q */
441 lhand
= getnumerichandlefromchanhash(cp
->users
, lnick
->numeric
);
442 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
444 if (lhand
|| qhand
) {
445 /* great, now try to request */
446 retval
= qr_requests(rqnick
, np
, cp
, lnick
, qnick
);
450 else if (retval
== RQ_ERROR
)
455 /* channel apparently doesn't have L or Q */
457 sendnoticetouser(rqnick
, np
, "Error: You need %s or %s in order to be "
458 "able to request %s.", RQ_LNICK
, RQ_QNICK
, RQ_SNICK
);
466 int rqcmd_requestop(void *source
, int cargc
, char **cargv
) {
467 nick
*np2
, *np
= (nick
*)source
;
475 sendnoticetouser(rqnick
, np
, "Syntax: requestop <#channel> [nick]");
480 cp
= findchannel(cargv
[0]);
483 sendnoticetouser(rqnick
, np
, "Error: No such channel.");
489 user
= getnickbynick(cargv
[1]);
492 sendnoticetouser(rqnick
, np
, "Error: No such user.");
498 if (getnettime() - np
->timestamp
< 300) {
499 sendnoticetouser(rqnick
, np
, "Error: You connected %s ago. To"
500 " request ops you must have been on the network for"
501 " at least 5 minutes.",
502 rq_longtoduration(getnettime() - np
->timestamp
));
507 if (getnettime() - user
->timestamp
< 300) {
508 sendnoticetouser(rqnick
, np
, "Error: The nick you requested op for"
509 " connected %s ago. To request op, it must have"
510 "been on the network for at least 5 minutes.",
511 rq_longtoduration(getnettime() - user
->timestamp
));
516 hand
= getnumerichandlefromchanhash(cp
->users
, user
->numeric
);
519 sendnoticetouser(rqnick
, np
, "Error: User %s is not on channel %s.", user
->nick
, cargv
[0]);
527 localsetmodeinit(&changes
, cp
, rqnick
);
529 /* reop any services first */
530 for(a
=0;a
<cp
->users
->hashsize
;a
++) {
531 if(cp
->users
->content
[a
] != nouser
) {
532 np2
= getnickbynumeric(cp
->users
->content
[a
]);
534 if (IsService(np2
) && (np2
->nick
[1] == '\0') && !(cp
->users
->content
[a
] & CUMODE_OP
)) {
535 localdosetmode_nick(&changes
, np2
, MC_OP
);
541 localsetmodeflush(&changes
, 1);
545 sendnoticetouser(rqnick
, np
, "1 service was reopped.");
547 sendnoticetouser(rqnick
, np
, "%d services were reopped.", count
);
552 for (a
=0;a
<cp
->users
->hashsize
;a
++) {
553 if ((cp
->users
->content
[a
] != nouser
) && (cp
->users
->content
[a
] & CUMODE_OP
)) {
554 sendnoticetouser(rqnick
, np
, "There are ops on channel %s. This command can only be"
555 " used if there are no ops.", cargv
[0]);
561 if (sp_countsplitservers() > 0) {
562 sendnoticetouser(rqnick
, np
, "One or more servers are currently split. Wait until the"
563 " netsplit is over and try again.");
568 if (cf_wouldreop(user
, cp
)) {
569 localsetmodeinit(&changes
, cp
, rqnick
);
570 localdosetmode_nick(&changes
, user
, MC_OP
);
571 localsetmodeflush(&changes
, 1);
573 sendnoticetouser(rqnick
, np
, "Chanfix opped you on the specified channel.");
575 ret
= cf_fixchannel(cp
);
577 if (ret
== CFX_NOUSERSAVAILABLE
)
578 sendnoticetouser(rqnick
, np
, "Chanfix knows regular ops for that channel. They will"
579 " be opped when they return.");
581 sendnoticetouser(rqnick
, np
, "Chanfix has opped known ops for that channel.");
588 int rqcmd_addblock(void *user
, int cargc
, char **cargv
) {
589 nick
*np
= (nick
*)user
;
593 int level
= ru_getlevel(np
);
596 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
602 sendnoticetouser(rqnick
, np
, "Syntax: addblock <mask> <duration> <reason>");
607 block
= rq_findblock(cargv
[0]);
610 sendnoticetouser(rqnick
, np
, "That mask is already blocked by %s "
611 "(reason: %s).", block
->creator
->content
, block
->reason
->content
);
617 account
= np
->authname
;
621 expires
= getnettime() + durationtolong(cargv
[1]);
623 if (expires
> getnettime() + RQU_HELPER_MAXEXPIRE
&& level
< 30) {
624 sendnoticetouser(rqnick
, np
, "Maximum expiry time is %s.", rq_longtoduration(RQU_HELPER_MAXEXPIRE
));
629 rq_addblock(cargv
[0], cargv
[2], account
, 0, expires
);
631 sendnoticetouser(rqnick
, np
, "Blocked channels/accounts matching '%s' from "
632 "requesting a service.", cargv
[0]);
637 int rqcmd_delblock(void *user
, int cargc
, char **cargv
) {
638 nick
*np
= (nick
*)user
;
642 level
= ru_getlevel(np
);
645 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
651 sendnoticetouser(rqnick
, np
, "Syntax: delblock <mask>");
656 block
= rq_findblock(cargv
[0]);
658 if (block
!= NULL
&& level
< 50) {
659 if (ircd_strcmp(block
->creator
->content
, np
->authname
) != 0) {
660 sendnoticetouser(rqnick
, np
, "This block was created by someone else. You cannot remove it.");
666 result
= rq_removeblock(cargv
[0]);
669 sendnoticetouser(rqnick
, np
, "Block for '%s' was removed.", cargv
[0]);
673 sendnoticetouser(rqnick
, np
, "There is no such block.");
679 int rqcmd_listblocks(void *user
, int cargc
, char **cargv
) {
680 nick
*np
= (nick
*)user
;
684 level
= ru_getlevel(np
);
687 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
692 sendnoticetouser(rqnick
, np
, "Mask By Expires"
695 for (i
= 0; i
< rqblocks
.cursi
; i
++) {
696 block
= ((rq_block
*)rqblocks
.content
)[i
];
698 if (block
.expires
!= 0 && block
.expires
< getnettime())
699 continue; /* ignore blocks which have already expired,
700 rq_findblock will deal with them later on */
702 if (cargc
< 1 || match2strings(block
.pattern
->content
, cargv
[0]))
703 sendnoticetouser(rqnick
, np
, "%-11s %-9s %-25s %s",
704 block
.pattern
->content
, block
.creator
->content
,
705 rq_longtoduration(block
.expires
- getnettime()),
706 block
.reason
->content
);
709 sendnoticetouser(rqnick
, np
, "--- End of blocklist");
714 int rqcmd_stats(void *user
, int cargc
, char **cargv
) {
715 nick
*np
= (nick
*)user
;
716 int level
= ru_getlevel(np
);
719 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
724 sendnoticetouser(rqnick
, np
, "Total requests: %d", rq_count
);
725 sendnoticetouser(rqnick
, np
, "Successful requests: %d", rq_success
);
726 sendnoticetouser(rqnick
, np
, "Failed requests: %d", rq_failed
);
727 sendnoticetouser(rqnick
, np
, "- Blocked: %d", rq_blocked
);
729 lr_requeststats(rqnick
, np
);
730 qr_requeststats(rqnick
, np
);
735 int rqcmd_adduser(void *user
, int cargc
, char **cargv
) {
736 nick
*np
= (nick
*)user
;
740 sendnoticetouser(rqnick
, np
, "Syntax: adduser <account> <level>");
745 level
= atoi(cargv
[1]);
748 sendnoticetouser(rqnick
, np
, "Level must be a positive integer.");
753 result
= ru_create(cargv
[0], level
);
756 sendnoticetouser(rqnick
, np
, "User '%s' was added with level '%d'.", cargv
[0], level
);
760 sendnoticetouser(rqnick
, np
, "Something strange happened. Contact shroud.");
766 int rqcmd_deluser(void *user
, int cargc
, char **cargv
) {
767 nick
*np
= (nick
*)user
;
771 sendnoticetouser(rqnick
, np
, "Syntax: deluser <account>");
776 level
= ru_getlevel_str(cargv
[0]);
779 sendnoticetouser(rqnick
, np
, "There is no such user.");
784 ru_destroy(cargv
[0]);
786 sendnoticetouser(rqnick
, np
, "Done.");
791 int rqcmd_changelev(void *user
, int cargc
, char **cargv
) {
792 nick
*np
= (nick
*)user
;
796 sendnoticetouser(rqnick
, np
, "Syntax: changelev <account> <level>");
801 level
= atoi(cargv
[1]);
804 sendnoticetouser(rqnick
, np
, "Level must be a positive integer.");
809 if (ru_getlevel_str(cargv
[0]) <= 0) {
810 sendnoticetouser(rqnick
, np
, "Unknown user.");
815 result
= ru_setlevel(cargv
[0], level
);
818 sendnoticetouser(rqnick
, np
, "Done.");
822 sendnoticetouser(rqnick
, np
, "Something strange happened. Contact shroud.");
828 int rqcmd_userlist(void *user
, int cargc
, char **cargv
) {
829 nick
*np
= (nick
*)user
;
830 r_user_t
*userp
= r_userlist
;
832 sendnoticetouser(rqnick
, np
, "User Level");
835 sendnoticetouser(rqnick
, np
, "%s %d", userp
->name
, userp
->level
);
839 sendnoticetouser(rqnick
, np
, "--- End of USERS.");