]>
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)
53 rqcommands
= newcommandtree();
55 addcommandtotree(rqcommands
, "showcommands", RQU_ANY
, 1, &rqcmd_showcommands
);
56 addcommandtotree(rqcommands
, "requestbot", RQU_ANY
, 1, &rqcmd_request
);
57 addcommandtotree(rqcommands
, "requestspamscan", RQU_ANY
, 1, &rqcmd_requestspamscan
);
58 addcommandtotree(rqcommands
, "requestop", RQU_ANY
, 2, &rqcmd_requestop
);
60 addcommandtotree(rqcommands
, "addblock", RQU_ACCOUNT
, 3, &rqcmd_addblock
);
61 addcommandtotree(rqcommands
, "delblock", RQU_ACCOUNT
, 1, &rqcmd_delblock
);
62 addcommandtotree(rqcommands
, "listblocks", RQU_ACCOUNT
, 1, &rqcmd_listblocks
);
63 addcommandtotree(rqcommands
, "stats", RQU_ACCOUNT
, 1, &rqcmd_stats
);
65 addcommandtotree(rqcommands
, "adduser", RQU_OPER
, 2, &rqcmd_adduser
);
66 addcommandtotree(rqcommands
, "deluser", RQU_OPER
, 1, &rqcmd_deluser
);
67 addcommandtotree(rqcommands
, "changelev", RQU_OPER
, 2, &rqcmd_changelev
);
68 addcommandtotree(rqcommands
, "userlist", RQU_OPER
, 1, &rqcmd_userlist
);
74 rq_logfd
= fopen(RQ_LOGFILE
, "a");
76 scheduleoneshot(time(NULL
) + 1, (ScheduleCallback
)&rq_registeruser
, NULL
);
80 deregisterlocaluser(rqnick
, NULL
);
82 deletecommandfromtree(rqcommands
, "showcommands", &rqcmd_showcommands
);
83 deletecommandfromtree(rqcommands
, "requestbot", &rqcmd_request
);
84 deletecommandfromtree(rqcommands
, "requestspamscan", &rqcmd_requestspamscan
);
85 deletecommandfromtree(rqcommands
, "requestop", &rqcmd_requestop
);
87 deletecommandfromtree(rqcommands
, "addblock", &rqcmd_addblock
);
88 deletecommandfromtree(rqcommands
, "delblock", &rqcmd_delblock
);
89 deletecommandfromtree(rqcommands
, "listblocks", &rqcmd_listblocks
);
90 deletecommandfromtree(rqcommands
, "stats", &rqcmd_stats
);
92 deletecommandfromtree(rqcommands
, "adduser", &rqcmd_adduser
);
93 deletecommandfromtree(rqcommands
, "deluser", &rqcmd_deluser
);
94 deletecommandfromtree(rqcommands
, "changelev", &rqcmd_changelev
);
95 deletecommandfromtree(rqcommands
, "userlist", &rqcmd_userlist
);
97 destroycommandtree(rqcommands
);
103 if (rq_logfd
!= NULL
)
106 deleteallschedules((ScheduleCallback
)&rq_registeruser
);
109 void rq_registeruser(void) {
112 rqnick
= registerlocaluser(RQ_REQUEST_NICK
, RQ_REQUEST_USER
, RQ_REQUEST_HOST
,
113 RQ_REQUEST_REAL
, RQ_REQUEST_AUTH
,
114 UMODE_ACCOUNT
| UMODE_SERVICE
| UMODE_OPER
,
117 cp
= findchannel(RQ_TLZ
);
120 localcreatechannel(rqnick
, RQ_TLZ
);
122 localjoinchannel(rqnick
, cp
);
125 char *rq_longtoduration(unsigned long interval
) {
126 static char buf
[100];
128 strncpy(buf
, longtoduration(interval
, 0), sizeof(buf
));
130 /* chop off last character if it's a space */
131 if (buf
[strlen(buf
)] == ' ')
132 buf
[strlen(buf
)] = '\0';
137 void rq_handler(nick
*target
, int type
, void **params
) {
149 cargc
= splitline(line
, cargv
, 30, 0);
154 cmd
= findcommandintree(rqcommands
, cargv
[0], 1);
157 sendnoticetouser(rqnick
, user
, "Unknown command.");
162 if ((cmd
->level
& RQU_OPER
) && !IsOper(user
)) {
163 sendnoticetouser(rqnick
, user
, "Sorry, this command is not "
164 "available to you.");
169 if ((cmd
->level
& RQU_ACCOUNT
) && (!IsAccount(user
) || ru_getlevel(user
) == 0) && !IsOper(user
)) {
170 sendnoticetouser(rqnick
, user
, "Sorry, this command is not "
171 "available to you.");
176 if (cargc
- 1 > cmd
->maxparams
)
177 rejoinline(cargv
[cmd
->maxparams
], cargc
- cmd
->maxparams
);
179 /* handle the command */
180 cmd
->handler((void*)user
, min(cargc
- 1, cmd
->maxparams
), &(cargv
[1]));
184 scheduleoneshot(time(NULL
) + 5, (ScheduleCallback
)&rq_registeruser
, NULL
);
188 qr_handlenotice(params
[0], params
[1]);
194 int rqcmd_showcommands(void *user
, int cargc
, char **cargv
) {
195 nick
* np
= (nick
*)user
;
197 Command
* cmdlist
[50];
199 n
= getcommandlist(rqcommands
, cmdlist
, 50);
201 sendnoticetouser(rqnick
, np
, "Available commands:");
202 sendnoticetouser(rqnick
, np
, "-------------------");
204 for (i
= 0; i
< n
; i
++) {
205 if ((cmdlist
[i
]->level
& RQU_OPER
) && !IsOper(np
))
208 if ((cmdlist
[i
]->level
& RQU_ACCOUNT
) && !(IsOper(np
) || (IsAccount(np
) && ru_getlevel(np
) > 0)))
211 sendnoticetouser(rqnick
, np
, "%s", cmdlist
[i
]->command
->content
);
214 sendnoticetouser(rqnick
, np
, "End of SHOWCOMMANDS");
219 int rq_genericrequestcheck(nick
*np
, char *channelname
, channel
**cp
, nick
**lnick
, nick
**qnick
) {
220 unsigned long *userhand
;
223 if (!IsAccount(np
)) {
224 sendnoticetouser(rqnick
, np
, "Error: You must be authed.");
229 *cp
= findchannel(channelname
);
232 sendnoticetouser(rqnick
, np
, "Error: Channel %s does not exist.",
238 *lnick
= getnickbynick(RQ_LNICK
);
240 if (*lnick
== NULL
|| findserver(RQ_LSERVER
) < 0) {
241 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
242 "Try again later.", RQ_LNICK
);
247 *qnick
= getnickbynick(RQ_QNICK
);
249 if (*qnick
== NULL
|| findserver(RQ_QSERVER
) < 0) {
250 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
251 "Try again later.", RQ_QNICK
);
256 userhand
= getnumerichandlefromchanhash((*cp
)->users
, np
->numeric
);
258 if (userhand
== NULL
) {
259 sendnoticetouser(rqnick
, np
, "Error: You're not on that channel.");
264 if ((*userhand
& CUMODE_OP
) == 0) {
265 sendnoticetouser(rqnick
, np
, "Error: You must be op'd on the channel to "
266 "request a service.");
271 block
= rq_findblock(channelname
);
274 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
275 "service to this channel.");
276 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
283 block
= rq_findblock(np
->authname
);
285 /* only tell the user if the block is going to expire in the next 48 hours
286 so we can have our fun with longterm blocks.
287 the request subsystems should deal with longterm blocks on their own */
288 if (block
!= NULL
&& block
->expires
< getnettime() + 3600 * 24 * 2) {
289 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
290 "service. Keep waiting for at least %s before you try again.",
291 rq_longtoduration(block
->expires
- getnettime()));
293 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
295 /* give them another 5 minutes to think about it */
296 block
->expires
+= 300;
307 int rqcmd_request(void *user
, int cargc
, char **cargv
) {
308 nick
*np
= (nick
*)user
;
310 unsigned long *lhand
, *qhand
;
317 sendnoticetouser(rqnick
, np
, "Syntax: requestbot <#channel>");
324 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &lnick
, &qnick
) == RQ_ERROR
) {
330 lhand
= getnumerichandlefromchanhash(cp
->users
, lnick
->numeric
);
332 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
335 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_QNICK
);
344 if (lhand
== NULL
&& qhand
== NULL
) {
345 /* try 'instant' Q request */
346 retval
= qr_instantrequestq(np
, cp
);
349 if (retval
== RQ_ERROR
) {
353 retval
= lr_requestl(rqnick
, np
, cp
, lnick
);
355 if (rq_logfd
!= NULL
) {
358 strftime(now
, sizeof(now
), "%c", localtime(&now_ts
));
360 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");
366 retval
= qr_requestq(rqnick
, np
, cp
, lnick
, qnick
);
370 if (retval
== RQ_ERROR
)
372 else if (retval
== RQ_OK
)
378 int rqcmd_requestspamscan(void *user
, int cargc
, char **cargv
) {
379 nick
*np
= (nick
*)user
;
381 nick
*lnick
, *qnick
, *snick
;
382 unsigned long *lhand
, *qhand
, *shand
;
386 sendnoticetouser(rqnick
, np
, "Syntax: requestspamscan <#channel>");
393 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &lnick
, &qnick
) == RQ_ERROR
) {
399 snick
= getnickbynick(RQ_SNICK
);
401 if (snick
== NULL
|| findserver(RQ_SSERVER
) < 0) {
402 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
403 "Try again later.", RQ_SNICK
);
410 /* does the user already have S on that channel? */
411 shand
= getnumerichandlefromchanhash(cp
->users
, snick
->numeric
);
414 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_SNICK
);
421 /* we need either L or Q */
422 lhand
= getnumerichandlefromchanhash(cp
->users
, lnick
->numeric
);
423 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
425 if (lhand
|| qhand
) {
426 /* great, now try to request */
427 retval
= qr_requests(rqnick
, np
, cp
, lnick
, qnick
);
431 else if (retval
== RQ_ERROR
)
436 /* channel apparently doesn't have L or Q */
438 sendnoticetouser(rqnick
, np
, "Error: You need %s or %s in order to be "
439 "able to request %s.", RQ_LNICK
, RQ_QNICK
, RQ_SNICK
);
447 int rqcmd_requestop(void *source
, int cargc
, char **cargv
) {
448 nick
*np2
, *np
= (nick
*)source
;
456 sendnoticetouser(rqnick
, np
, "Syntax: requestop <#channel> [nick]");
461 cp
= findchannel(cargv
[0]);
464 sendnoticetouser(rqnick
, np
, "Error: No such channel.");
470 user
= getnickbynick(cargv
[1]);
473 sendnoticetouser(rqnick
, np
, "Error: No such user.");
479 if (getnettime() - np
->timestamp
< 300) {
480 sendnoticetouser(rqnick
, np
, "Error: You connected %s ago. To"
481 " request ops you must have been on the network for"
482 " at least 5 minutes.",
483 rq_longtoduration(getnettime() - np
->timestamp
));
488 if (getnettime() - user
->timestamp
< 300) {
489 sendnoticetouser(rqnick
, np
, "Error: The nick you requested op for"
490 " connected %s ago. To request op, it must have"
491 "been on the network for at least 5 minutes.",
492 rq_longtoduration(getnettime() - user
->timestamp
));
497 hand
= getnumerichandlefromchanhash(cp
->users
, user
->numeric
);
500 sendnoticetouser(rqnick
, np
, "Error: User %s is not on channel %s.", user
->nick
, cargv
[0]);
508 localsetmodeinit(&changes
, cp
, rqnick
);
510 /* reop any services first */
511 for(a
=0;a
<cp
->users
->hashsize
;a
++) {
512 if(cp
->users
->content
[a
] != nouser
) {
513 np2
= getnickbynumeric(cp
->users
->content
[a
]);
515 if (IsService(np2
) && (np2
->nick
[1] == '\0') && !(cp
->users
->content
[a
] & CUMODE_OP
)) {
516 localdosetmode_nick(&changes
, np2
, MC_OP
);
522 localsetmodeflush(&changes
, 1);
526 sendnoticetouser(rqnick
, np
, "1 service was reopped.");
528 sendnoticetouser(rqnick
, np
, "%d services were reopped.", count
);
533 for (a
=0;a
<cp
->users
->hashsize
;a
++) {
534 if ((cp
->users
->content
[a
] != nouser
) && (cp
->users
->content
[a
] & CUMODE_OP
)) {
535 sendnoticetouser(rqnick
, np
, "There are ops on channel %s. This command can only be"
536 " used if there are no ops.", cargv
[0]);
542 if (sp_countsplitservers() > 0) {
543 sendnoticetouser(rqnick
, np
, "One or more servers are currently split. Wait until the"
544 " netsplit is over and try again.");
549 if (cf_wouldreop(user
, cp
)) {
550 localsetmodeinit(&changes
, cp
, rqnick
);
551 localdosetmode_nick(&changes
, user
, MC_OP
);
552 localsetmodeflush(&changes
, 1);
554 sendnoticetouser(rqnick
, np
, "Chanfix opped you on the specified channel.");
556 ret
= cf_fixchannel(cp
);
558 if (ret
== CFX_NOUSERSAVAILABLE
)
559 sendnoticetouser(rqnick
, np
, "Chanfix knows regular ops for that channel. They will"
560 " be opped when they return.");
562 sendnoticetouser(rqnick
, np
, "Chanfix has opped known ops for that channel.");
569 int rqcmd_addblock(void *user
, int cargc
, char **cargv
) {
570 nick
*np
= (nick
*)user
;
574 int level
= ru_getlevel(np
);
577 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
583 sendnoticetouser(rqnick
, np
, "Syntax: addblock <mask> <duration> <reason>");
588 block
= rq_findblock(cargv
[0]);
591 sendnoticetouser(rqnick
, np
, "That mask is already blocked by %s "
592 "(reason: %s).", block
->creator
->content
, block
->reason
->content
);
598 account
= np
->authname
;
602 expires
= getnettime() + durationtolong(cargv
[1]);
604 if (expires
> getnettime() + RQU_HELPER_MAXEXPIRE
&& level
< 30) {
605 sendnoticetouser(rqnick
, np
, "Maximum expiry time is %s.", rq_longtoduration(RQU_HELPER_MAXEXPIRE
));
610 rq_addblock(cargv
[0], cargv
[2], account
, 0, expires
);
612 sendnoticetouser(rqnick
, np
, "Blocked channels/accounts matching '%s' from "
613 "requesting a service.", cargv
[0]);
618 int rqcmd_delblock(void *user
, int cargc
, char **cargv
) {
619 nick
*np
= (nick
*)user
;
623 level
= ru_getlevel(np
);
626 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
632 sendnoticetouser(rqnick
, np
, "Syntax: delblock <mask>");
637 block
= rq_findblock(cargv
[0]);
639 if (block
!= NULL
&& level
< 50) {
640 if (ircd_strcmp(block
->creator
->content
, np
->authname
) != 0) {
641 sendnoticetouser(rqnick
, np
, "This block was created by someone else. You cannot remove it.");
647 result
= rq_removeblock(cargv
[0]);
650 sendnoticetouser(rqnick
, np
, "Block for '%s' was removed.", cargv
[0]);
654 sendnoticetouser(rqnick
, np
, "There is no such block.");
660 int rqcmd_listblocks(void *user
, int cargc
, char **cargv
) {
661 nick
*np
= (nick
*)user
;
665 level
= ru_getlevel(np
);
668 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
673 sendnoticetouser(rqnick
, np
, "Mask By Expires"
676 for (i
= 0; i
< rqblocks
.cursi
; i
++) {
677 block
= ((rq_block
*)rqblocks
.content
)[i
];
679 if (block
.expires
!= 0 && block
.expires
< getnettime())
680 continue; /* ignore blocks which have already expired,
681 rq_findblock will deal with them later on */
683 if (cargc
< 1 || match2strings(block
.pattern
->content
, cargv
[0]))
684 sendnoticetouser(rqnick
, np
, "%-11s %-9s %-25s %s",
685 block
.pattern
->content
, block
.creator
->content
,
686 rq_longtoduration(block
.expires
- getnettime()),
687 block
.reason
->content
);
690 sendnoticetouser(rqnick
, np
, "--- End of blocklist");
695 int rqcmd_stats(void *user
, int cargc
, char **cargv
) {
696 nick
*np
= (nick
*)user
;
697 int level
= ru_getlevel(np
);
700 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
705 sendnoticetouser(rqnick
, np
, "Total requests: %d", rq_count
);
706 sendnoticetouser(rqnick
, np
, "Successful requests: %d", rq_success
);
707 sendnoticetouser(rqnick
, np
, "Failed requests: %d", rq_failed
);
708 sendnoticetouser(rqnick
, np
, "- Blocked: %d", rq_blocked
);
710 lr_requeststats(rqnick
, np
);
711 qr_requeststats(rqnick
, np
);
716 int rqcmd_adduser(void *user
, int cargc
, char **cargv
) {
717 nick
*np
= (nick
*)user
;
721 sendnoticetouser(rqnick
, np
, "Syntax: adduser <account> <level>");
726 level
= atoi(cargv
[1]);
729 sendnoticetouser(rqnick
, np
, "Level must be a positive integer.");
734 result
= ru_create(cargv
[0], level
);
737 sendnoticetouser(rqnick
, np
, "User '%s' was added with level '%d'.", cargv
[0], level
);
741 sendnoticetouser(rqnick
, np
, "Something strange happened. Contact shroud.");
747 int rqcmd_deluser(void *user
, int cargc
, char **cargv
) {
748 nick
*np
= (nick
*)user
;
752 sendnoticetouser(rqnick
, np
, "Syntax: deluser <account>");
757 level
= ru_getlevel_str(cargv
[0]);
760 sendnoticetouser(rqnick
, np
, "There is no such user.");
765 ru_destroy(cargv
[0]);
767 sendnoticetouser(rqnick
, np
, "Done.");
772 int rqcmd_changelev(void *user
, int cargc
, char **cargv
) {
773 nick
*np
= (nick
*)user
;
777 sendnoticetouser(rqnick
, np
, "Syntax: changelev <account> <level>");
782 level
= atoi(cargv
[1]);
785 sendnoticetouser(rqnick
, np
, "Level must be a positive integer.");
790 if (ru_getlevel_str(cargv
[0]) <= 0) {
791 sendnoticetouser(rqnick
, np
, "Unknown user.");
796 result
= ru_setlevel(cargv
[0], level
);
799 sendnoticetouser(rqnick
, np
, "Done.");
803 sendnoticetouser(rqnick
, np
, "Something strange happened. Contact shroud.");
809 int rqcmd_userlist(void *user
, int cargc
, char **cargv
) {
810 nick
*np
= (nick
*)user
;
811 r_user_t
*userp
= r_userlist
;
813 sendnoticetouser(rqnick
, np
, "User Level");
816 sendnoticetouser(rqnick
, np
, "%s %d", userp
->name
, userp
->level
);
820 sendnoticetouser(rqnick
, np
, "--- End of USERS.");