]>
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 "../control/control.h"
11 #include "../splitlist/splitlist.h"
13 #include "request_block.h"
15 #include "sqrequest.h"
19 CommandTree
*rqcommands
;
21 void rq_registeruser(void);
22 void rq_handler(nick
*target
, int type
, void **args
);
24 int rqcmd_showcommands(void *user
, int cargc
, char **cargv
);
25 int rqcmd_request(void *user
, int cargc
, char **cargv
);
26 int rqcmd_requestspamscan(void *user
, int cargc
, char **cargv
);
27 int rqcmd_addblock(void *user
, int cargc
, char **cargv
);
28 int rqcmd_delblock(void *user
, int cargc
, char **cargv
);
29 int rqcmd_listblocks(void *user
, int cargc
, char **cargv
);
30 int rqcmd_stats(void *user
, int cargc
, char **cargv
);
31 int rqcmd_requestop(void *user
, int cargc
, char **cargv
);
33 int rqcmd_adduser(void *user
, int cargc
, char **cargv
);
34 int rqcmd_deluser(void *user
, int cargc
, char **cargv
);
35 int rqcmd_changelev(void *user
, int cargc
, char **cargv
);
36 int rqcmd_userlist(void *user
, int cargc
, char **cargv
);
38 #define min(a,b) ((a > b) ? b : a)
50 rqcommands
= newcommandtree();
52 addcommandtotree(rqcommands
, "showcommands", RQU_ANY
, 1, &rqcmd_showcommands
);
53 addcommandtotree(rqcommands
, "requestbot", RQU_ANY
, 1, &rqcmd_request
);
54 addcommandtotree(rqcommands
, "requestspamscan", RQU_ANY
, 1, &rqcmd_requestspamscan
);
55 addcommandtotree(rqcommands
, "requestop", RQU_ANY
, 2, &rqcmd_requestop
);
57 addcommandtotree(rqcommands
, "addblock", RQU_ACCOUNT
, 3, &rqcmd_addblock
);
58 addcommandtotree(rqcommands
, "delblock", RQU_ACCOUNT
, 1, &rqcmd_delblock
);
59 addcommandtotree(rqcommands
, "listblocks", RQU_ACCOUNT
, 1, &rqcmd_listblocks
);
60 addcommandtotree(rqcommands
, "stats", RQU_ACCOUNT
, 1, &rqcmd_stats
);
62 addcommandtotree(rqcommands
, "adduser", RQU_OPER
, 2, &rqcmd_adduser
);
63 addcommandtotree(rqcommands
, "deluser", RQU_OPER
, 1, &rqcmd_deluser
);
64 addcommandtotree(rqcommands
, "changelev", RQU_OPER
, 2, &rqcmd_changelev
);
65 addcommandtotree(rqcommands
, "userlist", RQU_OPER
, 1, &rqcmd_userlist
);
71 rq_logfd
= fopen(RQ_LOGFILE
, "a");
73 scheduleoneshot(time(NULL
) + 1, (ScheduleCallback
)&rq_registeruser
, NULL
);
77 deregisterlocaluser(rqnick
, NULL
);
79 deletecommandfromtree(rqcommands
, "showcommands", &rqcmd_showcommands
);
80 deletecommandfromtree(rqcommands
, "requestbot", &rqcmd_request
);
81 deletecommandfromtree(rqcommands
, "requestspamscan", &rqcmd_requestspamscan
);
82 deletecommandfromtree(rqcommands
, "requestop", &rqcmd_requestop
);
84 deletecommandfromtree(rqcommands
, "addblock", &rqcmd_addblock
);
85 deletecommandfromtree(rqcommands
, "delblock", &rqcmd_delblock
);
86 deletecommandfromtree(rqcommands
, "listblocks", &rqcmd_listblocks
);
87 deletecommandfromtree(rqcommands
, "stats", &rqcmd_stats
);
89 deletecommandfromtree(rqcommands
, "adduser", &rqcmd_adduser
);
90 deletecommandfromtree(rqcommands
, "deluser", &rqcmd_deluser
);
91 deletecommandfromtree(rqcommands
, "changelev", &rqcmd_changelev
);
92 deletecommandfromtree(rqcommands
, "userlist", &rqcmd_userlist
);
94 destroycommandtree(rqcommands
);
100 if (rq_logfd
!= NULL
)
103 deleteallschedules((ScheduleCallback
)&rq_registeruser
);
106 void rq_registeruser(void) {
109 rqnick
= registerlocaluser(RQ_REQUEST_NICK
, RQ_REQUEST_USER
, RQ_REQUEST_HOST
,
110 RQ_REQUEST_REAL
, RQ_REQUEST_AUTH
,
111 UMODE_ACCOUNT
| UMODE_SERVICE
| UMODE_OPER
,
114 cp
= findchannel(RQ_TLZ
);
117 localcreatechannel(rqnick
, RQ_TLZ
);
119 localjoinchannel(rqnick
, cp
);
122 char *rq_longtoduration(unsigned long interval
) {
123 static char buf
[100];
125 strncpy(buf
, longtoduration(interval
, 0), sizeof(buf
));
127 /* chop off last character if it's a space */
128 if (buf
[strlen(buf
)] == ' ')
129 buf
[strlen(buf
)] = '\0';
134 void rq_handler(nick
*target
, int type
, void **params
) {
146 cargc
= splitline(line
, cargv
, 30, 0);
151 cmd
= findcommandintree(rqcommands
, cargv
[0], 1);
154 sendnoticetouser(rqnick
, user
, "Unknown command.");
159 if ((cmd
->level
& RQU_OPER
) && !IsOper(user
)) {
160 sendnoticetouser(rqnick
, user
, "Sorry, this command is not "
161 "available to you.");
166 if ((cmd
->level
& RQU_ACCOUNT
) && (!IsAccount(user
) || ru_getlevel(user
) == 0) && !IsOper(user
)) {
167 sendnoticetouser(rqnick
, user
, "Sorry, this command is not "
168 "available to you.");
173 if (cargc
- 1 > cmd
->maxparams
)
174 rejoinline(cargv
[cmd
->maxparams
], cargc
- cmd
->maxparams
);
176 /* handle the command */
177 cmd
->handler((void*)user
, min(cargc
- 1, cmd
->maxparams
), &(cargv
[1]));
181 scheduleoneshot(time(NULL
) + 5, (ScheduleCallback
)&rq_registeruser
, NULL
);
185 qr_handlenotice(params
[0], params
[1]);
191 int rqcmd_showcommands(void *user
, int cargc
, char **cargv
) {
192 nick
* np
= (nick
*)user
;
194 Command
* cmdlist
[50];
196 n
= getcommandlist(rqcommands
, cmdlist
, 50);
198 sendnoticetouser(rqnick
, np
, "Available commands:");
199 sendnoticetouser(rqnick
, np
, "-------------------");
201 for (i
= 0; i
< n
; i
++) {
202 if ((cmdlist
[i
]->level
& RQU_OPER
) && !IsOper(np
))
205 if ((cmdlist
[i
]->level
& RQU_ACCOUNT
) && !(IsOper(np
) || (IsAccount(np
) && ru_getlevel(np
) > 0)))
208 sendnoticetouser(rqnick
, np
, "%s", cmdlist
[i
]->command
->content
);
211 sendnoticetouser(rqnick
, np
, "End of SHOWCOMMANDS");
216 int rq_genericrequestcheck(nick
*np
, char *channelname
, channel
**cp
, nick
**lnick
, nick
**qnick
) {
217 unsigned long *userhand
;
220 if (!IsAccount(np
)) {
221 sendnoticetouser(rqnick
, np
, "Error: You must be authed.");
226 *cp
= findchannel(channelname
);
229 sendnoticetouser(rqnick
, np
, "Error: Channel %s does not exist.",
235 *lnick
= getnickbynick(RQ_LNICK
);
237 if (*lnick
== NULL
|| findserver(RQ_LSERVER
) < 0) {
238 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
239 "Try again later.", RQ_LNICK
);
244 *qnick
= getnickbynick(RQ_QNICK
);
246 if (*qnick
== NULL
|| findserver(RQ_QSERVER
) < 0) {
247 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
248 "Try again later.", RQ_QNICK
);
253 userhand
= getnumerichandlefromchanhash((*cp
)->users
, np
->numeric
);
255 if (userhand
== NULL
) {
256 sendnoticetouser(rqnick
, np
, "Error: You're not on that channel.");
261 if ((*userhand
& CUMODE_OP
) == 0) {
262 sendnoticetouser(rqnick
, np
, "Error: You must be op'd on the channel to "
263 "request a service.");
268 block
= rq_findblock(channelname
);
271 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
272 "service to this channel.");
273 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
280 block
= rq_findblock(np
->authname
);
282 /* only tell the user if the block is going to expire in the next 48 hours
283 so we can have our fun with longterm blocks.
284 the request subsystems should deal with longterm blocks on their own */
285 if (block
!= NULL
&& block
->expires
< getnettime() + 3600 * 24 * 2) {
286 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
287 "service. Keep waiting for at least %s before you try again.",
288 rq_longtoduration(block
->expires
- getnettime()));
290 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
292 /* give them another 5 minutes to think about it */
293 block
->expires
+= 300;
304 int rqcmd_request(void *user
, int cargc
, char **cargv
) {
305 nick
*np
= (nick
*)user
;
307 unsigned long *lhand
, *qhand
;
314 sendnoticetouser(rqnick
, np
, "Syntax: requestbot <#channel>");
321 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &lnick
, &qnick
) == RQ_ERROR
) {
327 lhand
= getnumerichandlefromchanhash(cp
->users
, lnick
->numeric
);
329 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
332 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_QNICK
);
341 if (lhand
== NULL
&& qhand
== NULL
) {
342 /* try 'instant' Q request */
343 retval
= qr_instantrequestq(np
, cp
);
346 if (retval
== RQ_ERROR
) {
350 retval
= lr_requestl(rqnick
, np
, cp
, lnick
);
352 if (rq_logfd
!= NULL
) {
355 strftime(now
, sizeof(now
), "%c", localtime(&now_ts
));
357 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");
363 retval
= qr_requestq(rqnick
, np
, cp
, lnick
, qnick
);
367 if (retval
== RQ_ERROR
)
369 else if (retval
== RQ_OK
)
375 int rqcmd_requestspamscan(void *user
, int cargc
, char **cargv
) {
376 nick
*np
= (nick
*)user
;
378 nick
*lnick
, *qnick
, *snick
;
379 unsigned long *lhand
, *qhand
, *shand
;
383 sendnoticetouser(rqnick
, np
, "Syntax: requestspamscan <#channel>");
390 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &lnick
, &qnick
) == RQ_ERROR
) {
396 snick
= getnickbynick(RQ_SNICK
);
398 if (snick
== NULL
|| findserver(RQ_SSERVER
) < 0) {
399 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
400 "Try again later.", RQ_SNICK
);
407 /* does the user already have S on that channel? */
408 shand
= getnumerichandlefromchanhash(cp
->users
, snick
->numeric
);
411 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_SNICK
);
418 /* we need either L or Q */
419 lhand
= getnumerichandlefromchanhash(cp
->users
, lnick
->numeric
);
420 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
422 if (lhand
|| qhand
) {
423 /* great, now try to request */
424 retval
= qr_requests(rqnick
, np
, cp
, lnick
, qnick
);
428 else if (retval
== RQ_ERROR
)
433 /* channel apparently doesn't have L or Q */
435 sendnoticetouser(rqnick
, np
, "Error: You need %s or %s in order to be "
436 "able to request %s.", RQ_LNICK
, RQ_QNICK
, RQ_SNICK
);
444 int rqcmd_requestop(void *source
, int cargc
, char **cargv
) {
445 nick
*np2
, *np
= (nick
*)source
;
453 sendnoticetouser(rqnick
, np
, "Syntax: requestop <#channel> [nick]");
458 cp
= findchannel(cargv
[0]);
461 sendnoticetouser(rqnick
, np
, "Error: No such channel.");
467 user
= getnickbynick(cargv
[1]);
470 sendnoticetouser(rqnick
, np
, "Error: No such user.");
476 if (getnettime() - np
->timestamp
< 300) {
477 sendnoticetouser(rqnick
, np
, "Error: You connected %s ago. To"
478 " request ops you must have been on the network for"
479 " at least 5 minutes.",
480 rq_longtoduration(getnettime() - np
->timestamp
));
485 if (getnettime() - user
->timestamp
< 300) {
486 sendnoticetouser(rqnick
, np
, "Error: The nick you requested op for"
487 " connected %s ago. To request op, it must have"
488 "been on the network for at least 5 minutes.",
489 rq_longtoduration(getnettime() - user
->timestamp
));
494 hand
= getnumerichandlefromchanhash(cp
->users
, user
->numeric
);
497 sendnoticetouser(rqnick
, np
, "Error: User %s is not on channel %s.", user
->nick
, cargv
[0]);
505 localsetmodeinit(&changes
, cp
, rqnick
);
507 /* reop any services first */
508 for(a
=0;a
<cp
->users
->hashsize
;a
++) {
509 if(cp
->users
->content
[a
] != nouser
) {
510 np2
= getnickbynumeric(cp
->users
->content
[a
]);
512 if (IsService(np2
) && !(cp
->users
->content
[a
] & CUMODE_OP
)) {
513 localdosetmode_nick(&changes
, np2
, MC_OP
);
519 localsetmodeflush(&changes
, 1);
523 sendnoticetouser(rqnick
, np
, "1 service was reopped.");
525 sendnoticetouser(rqnick
, np
, "%d services were reopped.", count
);
530 for (a
=0;a
<cp
->users
->hashsize
;a
++) {
531 if ((cp
->users
->content
[a
] != nouser
) && (cp
->users
->content
[a
] & CUMODE_OP
)) {
532 sendnoticetouser(rqnick
, np
, "There are ops on channel %s. This command can only be"
533 " used if there are no ops.", cargv
[0]);
539 if (sp_countsplitservers() > 0) {
540 sendnoticetouser(rqnick
, np
, "One or more servers are currently split. Wait until the"
541 " netsplit is over and try again.");
546 if (cf_wouldreop(user
, cp
)) {
547 localsetmodeinit(&changes
, cp
, rqnick
);
548 localdosetmode_nick(&changes
, user
, MC_OP
);
549 localsetmodeflush(&changes
, 1);
551 sendnoticetouser(rqnick
, np
, "Chanfix opped you on the specified channel.");
553 ret
= cf_fixchannel(cp
);
555 if (ret
== CFX_NOUSERSAVAILABLE
)
556 sendnoticetouser(rqnick
, np
, "Chanfix knows regular ops for that channel. They will"
557 " be opped when they return.");
559 sendnoticetouser(rqnick
, np
, "Chanfix has opped known ops for that channel.");
566 int rqcmd_addblock(void *user
, int cargc
, char **cargv
) {
567 nick
*np
= (nick
*)user
;
571 int level
= ru_getlevel(np
);
574 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
580 sendnoticetouser(rqnick
, np
, "Syntax: addblock <mask> <duration> <reason>");
585 block
= rq_findblock(cargv
[0]);
588 sendnoticetouser(rqnick
, np
, "That mask is already blocked by %s "
589 "(reason: %s).", block
->creator
->content
, block
->reason
->content
);
595 account
= np
->authname
;
599 expires
= getnettime() + durationtolong(cargv
[1]);
601 if (expires
> getnettime() + RQU_HELPER_MAXEXPIRE
&& level
< 30) {
602 sendnoticetouser(rqnick
, np
, "Maximum expiry time is %s.", rq_longtoduration(RQU_HELPER_MAXEXPIRE
));
607 rq_addblock(cargv
[0], cargv
[2], account
, 0, expires
);
609 sendnoticetouser(rqnick
, np
, "Blocked channels/accounts matching '%s' from "
610 "requesting a service.", cargv
[0]);
615 int rqcmd_delblock(void *user
, int cargc
, char **cargv
) {
616 nick
*np
= (nick
*)user
;
620 level
= ru_getlevel(np
);
623 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
629 sendnoticetouser(rqnick
, np
, "Syntax: delblock <mask>");
634 block
= rq_findblock(cargv
[0]);
636 if (block
!= NULL
&& level
< 50) {
637 if (ircd_strcmp(block
->creator
->content
, np
->authname
) != 0) {
638 sendnoticetouser(rqnick
, np
, "This block was created by someone else. You cannot remove it.");
644 result
= rq_removeblock(cargv
[0]);
647 sendnoticetouser(rqnick
, np
, "Block for '%s' was removed.", cargv
[0]);
651 sendnoticetouser(rqnick
, np
, "There is no such block.");
657 int rqcmd_listblocks(void *user
, int cargc
, char **cargv
) {
658 nick
*np
= (nick
*)user
;
662 level
= ru_getlevel(np
);
665 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
670 sendnoticetouser(rqnick
, np
, "Mask By Expires"
673 for (i
= 0; i
< rqblocks
.cursi
; i
++) {
674 block
= ((rq_block
*)rqblocks
.content
)[i
];
676 if (block
.expires
!= 0 && block
.expires
< getnettime())
677 continue; /* ignore blocks which have already expired,
678 rq_findblock will deal with them later on */
680 if (cargc
< 1 || match2strings(block
.pattern
->content
, cargv
[0]))
681 sendnoticetouser(rqnick
, np
, "%-11s %-9s %-25s %s",
682 block
.pattern
->content
, block
.creator
->content
,
683 rq_longtoduration(block
.expires
- getnettime()),
684 block
.reason
->content
);
687 sendnoticetouser(rqnick
, np
, "--- End of blocklist");
692 int rqcmd_stats(void *user
, int cargc
, char **cargv
) {
693 nick
*np
= (nick
*)user
;
694 int level
= ru_getlevel(np
);
697 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
702 sendnoticetouser(rqnick
, np
, "Total requests: %d", rq_count
);
703 sendnoticetouser(rqnick
, np
, "Successful requests: %d", rq_success
);
704 sendnoticetouser(rqnick
, np
, "Failed requests: %d", rq_failed
);
705 sendnoticetouser(rqnick
, np
, "- Blocked: %d", rq_blocked
);
707 lr_requeststats(rqnick
, np
);
708 qr_requeststats(rqnick
, np
);
713 int rqcmd_adduser(void *user
, int cargc
, char **cargv
) {
714 nick
*np
= (nick
*)user
;
718 sendnoticetouser(rqnick
, np
, "Syntax: adduser <account> <level>");
723 level
= atoi(cargv
[1]);
726 sendnoticetouser(rqnick
, np
, "Level must be a positive integer.");
731 result
= ru_create(cargv
[0], level
);
734 sendnoticetouser(rqnick
, np
, "User '%s' was added with level '%d'.", cargv
[0], level
);
738 sendnoticetouser(rqnick
, np
, "Something strange happened. Contact shroud.");
744 int rqcmd_deluser(void *user
, int cargc
, char **cargv
) {
745 nick
*np
= (nick
*)user
;
749 sendnoticetouser(rqnick
, np
, "Syntax: deluser <account>");
754 level
= ru_getlevel_str(cargv
[0]);
757 sendnoticetouser(rqnick
, np
, "There is no such user.");
762 ru_destroy(cargv
[0]);
764 sendnoticetouser(rqnick
, np
, "Done.");
769 int rqcmd_changelev(void *user
, int cargc
, char **cargv
) {
770 nick
*np
= (nick
*)user
;
774 sendnoticetouser(rqnick
, np
, "Syntax: changelev <account> <level>");
779 level
= atoi(cargv
[1]);
782 sendnoticetouser(rqnick
, np
, "Level must be a positive integer.");
787 if (ru_getlevel_str(cargv
[0]) <= 0) {
788 sendnoticetouser(rqnick
, np
, "Unknown user.");
793 result
= ru_setlevel(cargv
[0], level
);
796 sendnoticetouser(rqnick
, np
, "Done.");
800 sendnoticetouser(rqnick
, np
, "Something strange happened. Contact shroud.");
806 int rqcmd_userlist(void *user
, int cargc
, char **cargv
) {
807 nick
*np
= (nick
*)user
;
808 r_user_t
*userp
= r_userlist
;
810 sendnoticetouser(rqnick
, np
, "User Level");
813 sendnoticetouser(rqnick
, np
, "%s %d", userp
->name
, userp
->level
);
817 sendnoticetouser(rqnick
, np
, "--- End of USERS.");