1 /* shroud's service request */
5 #include "../localuser/localuser.h"
6 #include "../localuser/localuserchannel.h"
7 #include "../core/config.h"
8 #include "../core/schedule.h"
9 #include "../lib/irc_string.h"
10 #include "../lib/splitline.h"
11 #include "../lib/version.h"
12 #include "../control/control.h"
13 #include "../splitlist/splitlist.h"
15 #include "request_block.h"
16 #include "request_fasttrack.h"
18 #include "sqrequest.h"
23 CommandTree
*rqcommands
;
25 void rq_registeruser(void);
26 void rq_handler(nick
*target
, int type
, void **args
);
28 int rqcmd_showcommands(void *user
, int cargc
, char **cargv
);
29 int rqcmd_request(void *user
, int cargc
, char **cargv
);
30 int rqcmd_requestspamscan(void *user
, int cargc
, char **cargv
);
31 int rqcmd_addblock(void *user
, int cargc
, char **cargv
);
32 int rqcmd_delblock(void *user
, int cargc
, char **cargv
);
33 int rqcmd_listblocks(void *user
, int cargc
, char **cargv
);
34 int rqcmd_stats(void *user
, int cargc
, char **cargv
);
35 int rqcmd_requestop(void *user
, int cargc
, char **cargv
);
37 #define min(a,b) ((a > b) ? b : a)
49 sstring
*rq_qserver
, *rq_qnick
, *rq_sserver
, *rq_snick
;
50 sstring
*rq_nick
, *rq_user
, *rq_host
, *rq_real
, *rq_auth
;
53 static int extloaded
= 0;
61 if(!rq_initfasttrack())
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
);
76 m
= getconfigitem("request", "authid");
80 rq_authid
= atoi(m
->content
);
82 rqcommands
= newcommandtree();
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
);
87 addcommandtotree(rqcommands
, "requestop", RQU_ANY
, 2, &rqcmd_requestop
);
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
);
96 rq_logfd
= fopen("logs/request.log", "a");
98 scheduleoneshot(time(NULL
) + 1, (ScheduleCallback
)&rq_registeruser
, NULL
);
105 deregisterlocaluser(rqnick
, NULL
);
107 deletecommandfromtree(rqcommands
, "showcommands", &rqcmd_showcommands
);
108 deletecommandfromtree(rqcommands
, "requestbot", &rqcmd_request
);
109 deletecommandfromtree(rqcommands
, "requestspamscan", &rqcmd_requestspamscan
);
110 deletecommandfromtree(rqcommands
, "requestop", &rqcmd_requestop
);
112 deletecommandfromtree(rqcommands
, "addblock", &rqcmd_addblock
);
113 deletecommandfromtree(rqcommands
, "delblock", &rqcmd_delblock
);
114 deletecommandfromtree(rqcommands
, "listblocks", &rqcmd_listblocks
);
115 deletecommandfromtree(rqcommands
, "stats", &rqcmd_stats
);
117 destroycommandtree(rqcommands
);
123 freesstring(rq_nick
);
124 freesstring(rq_user
);
125 freesstring(rq_host
);
126 freesstring(rq_real
);
127 freesstring(rq_auth
);
129 if (rq_logfd
!= NULL
)
132 deleteallschedules((ScheduleCallback
)&rq_registeruser
);
135 void rq_registeruser(void) {
138 rqnick
= registerlocaluserflags(rq_nick
->content
, rq_user
->content
, rq_host
->content
,
139 rq_real
->content
, rq_auth
->content
, rq_authid
, 0,
140 UMODE_ACCOUNT
| UMODE_SERVICE
| UMODE_OPER
,
143 cp
= findchannel("#twilightzone");
146 localcreatechannel(rqnick
, "#twilightzone");
148 localjoinchannel(rqnick
, cp
);
151 char *rq_longtoduration(unsigned long interval
) {
152 static char buf
[100];
154 strncpy(buf
, longtoduration(interval
, 0), sizeof(buf
));
156 /* chop off last character if it's a space */
157 if (buf
[strlen(buf
)] == ' ')
158 buf
[strlen(buf
)] = '\0';
163 void rq_handler(nick
*target
, int type
, void **params
) {
175 cargc
= splitline(line
, cargv
, 30, 0);
180 cmd
= findcommandintree(rqcommands
, cargv
[0], 1);
183 sendnoticetouser(rqnick
, user
, "Unknown command.");
188 if ((cmd
->level
& RQU_OPER
) && !IsOper(user
)) {
189 sendnoticetouser(rqnick
, user
, "Sorry, this command is not "
190 "available to you.");
195 if (cargc
- 1 > cmd
->maxparams
)
196 rejoinline(cargv
[cmd
->maxparams
], cargc
- cmd
->maxparams
);
198 /* handle the command */
199 cmd
->handler((void*)user
, min(cargc
- 1, cmd
->maxparams
), &(cargv
[1]));
203 scheduleoneshot(time(NULL
) + 5, (ScheduleCallback
)&rq_registeruser
, NULL
);
207 qr_handle_notice(params
[0], params
[1]);
213 int rqcmd_showcommands(void *user
, int cargc
, char **cargv
) {
214 nick
* np
= (nick
*)user
;
216 Command
* cmdlist
[50];
218 n
= getcommandlist(rqcommands
, cmdlist
, 50);
220 sendnoticetouser(rqnick
, np
, "Available commands:");
221 sendnoticetouser(rqnick
, np
, "-------------------");
223 for (i
= 0; i
< n
; i
++) {
224 if ((cmdlist
[i
]->level
& RQU_OPER
) && !IsOper(np
))
227 sendnoticetouser(rqnick
, np
, "%s", cmdlist
[i
]->command
->content
);
230 sendnoticetouser(rqnick
, np
, "End of SHOWCOMMANDS");
235 int rq_genericrequestcheck(nick
*np
, char *channelname
, channel
**cp
, nick
**qnick
) {
236 unsigned long *userhand
;
239 if (!IsAccount(np
)) {
240 sendnoticetouser(rqnick
, np
, "Error: You must be authed to perform a service request.");
245 *cp
= findchannel(channelname
);
248 sendnoticetouser(rqnick
, np
, "Error: Channel '%s' does not exist on the network.",
254 *qnick
= getnickbynick(rq_qnick
->content
);
256 if (*qnick
== NULL
|| findserver(rq_qserver
->content
) < 0) {
257 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
258 "Please try again later.", rq_qnick
->content
);
263 userhand
= getnumerichandlefromchanhash((*cp
)->users
, np
->numeric
);
265 if (userhand
== NULL
) {
266 sendnoticetouser(rqnick
, np
, "Error: You're not on that channel.");
271 if ((*userhand
& CUMODE_OP
) == 0) {
272 sendnoticetouser(rqnick
, np
, "Error: You must be op'd on the channel to "
273 "request a service.");
278 block
= rq_findblock(channelname
);
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 "
284 "service to '%s'. Keep waiting for at least %s before you try again.",
285 channelname
, rq_longtoduration(block
->expires
- getnettime()));
286 /* give them another 5 minutes to think about it */
287 block
->expires
+= 300;
290 sendnoticetouser(rqnick
, np
, "Error: You are not allowed to request a "
291 "service to '%s'.", channelname
);
293 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
300 block
= rq_findblock(np
->authname
);
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()));
310 sendnoticetouser(rqnick
, np
, "Reason: %s", block
->reason
->content
);
312 /* give them another 5 minutes to think about it */
313 block
->expires
+= 300;
324 int rqcmd_request(void *user
, int cargc
, char **cargv
) {
325 nick
*np
= (nick
*)user
;
327 unsigned long *qhand
;
334 sendnoticetouser(rqnick
, np
, "Syntax: requestbot <#channel>");
341 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &qnick
) == RQ_ERROR
) {
347 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
350 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", rq_qnick
->content
);
357 retval
= lr_requestl(rqnick
, np
, cp
, qnick
);
359 if (rq_logfd
!= NULL
) {
362 strftime(now
, sizeof(now
), "%c", localtime(&now_ts
));
364 fprintf(rq_logfd
, "%s: request (%s) for %s from %s!%s@%s%s%s: Request was %s.\n",
365 now
, rq_qnick
->content
, cp
->index
->name
->content
,
366 np
->nick
, np
->ident
, np
->host
->name
->content
, IsAccount(np
)?"/":"", IsAccount(np
)?np
->authname
:"",
367 (retval
== RQ_OK
) ? "accepted" : "denied");
371 if (retval
== RQ_ERROR
)
373 else if (retval
== RQ_OK
)
379 int rqcmd_requestspamscan(void *user
, int cargc
, char **cargv
) {
380 nick
*np
= (nick
*)user
;
383 unsigned long *qhand
, *shand
;
387 sendnoticetouser(rqnick
, np
, "Syntax: requestspamscan <#channel>");
394 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &qnick
) == RQ_ERROR
) {
400 snick
= getnickbynick(rq_snick
->content
);
402 if (snick
== NULL
|| findserver(rq_sserver
->content
) < 0) {
403 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
404 "Please try again later.", rq_snick
->content
);
411 /* does the user already have S on that channel? */
412 shand
= getnumerichandlefromchanhash(cp
->users
, snick
->numeric
);
415 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", rq_snick
->content
);
423 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
426 /* great, now try to request */
427 retval
= qr_requests(rqnick
, np
, cp
, qnick
);
431 else if (retval
== RQ_ERROR
)
436 /* channel apparently doesn't have Q */
438 sendnoticetouser(rqnick
, np
, "Error: You need %s in order to be "
439 "able to request %s.", rq_qnick
->content
, rq_snick
->content
);
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: Channel '%s' does not exist on the network.",
471 user
= getnickbynick(cargv
[1]);
474 sendnoticetouser(rqnick
, np
, "Error: No such user.");
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
));
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
));
498 hand
= getnumerichandlefromchanhash(cp
->users
, user
->numeric
);
501 sendnoticetouser(rqnick
, np
, "Error: User %s is not on channel '%s'.", user
->nick
, cargv
[0]);
509 localsetmodeinit(&changes
, cp
, rqnick
);
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
]);
516 if (IsService(np2
) && (np2
->nick
[1] == '\0') && !(cp
->users
->content
[a
] & CUMODE_OP
)) {
517 localdosetmode_nick(&changes
, np2
, MC_OP
);
523 localsetmodeflush(&changes
, 1);
527 sendnoticetouser(rqnick
, np
, "1 service was reopped.");
529 sendnoticetouser(rqnick
, np
, "%d services were reopped.", count
);
534 for (a
=0;a
<cp
->users
->hashsize
;a
++) {
535 if ((cp
->users
->content
[a
] != nouser
) && (cp
->users
->content
[a
] & CUMODE_OP
)) {
536 sendnoticetouser(rqnick
, np
, "There are ops on channel '%s'. This command can only be"
537 " used if there are no ops.", cargv
[0]);
543 if (sp_countsplitservers(SERVERTYPEFLAG_USER_STATE
) > 0) {
544 sendnoticetouser(rqnick
, np
, "One or more servers are currently split. Wait until the"
545 " netsplit is over and try again.");
550 if (cf_wouldreop(user
, cp
)) {
551 localsetmodeinit(&changes
, cp
, rqnick
);
552 localdosetmode_nick(&changes
, user
, MC_OP
);
553 localsetmodeflush(&changes
, 1);
555 sendnoticetouser(rqnick
, np
, "Chanfix opped you on the specified channel.");
557 ret
= cf_fixchannel(cp
);
559 if (ret
== CFX_NOUSERSAVAILABLE
)
560 sendnoticetouser(rqnick
, np
, "Chanfix knows regular ops for that channel. They will"
561 " be opped when they return.");
563 sendnoticetouser(rqnick
, np
, "Chanfix has opped known ops for that channel.");
570 int rqcmd_addblock(void *user
, int cargc
, char **cargv
) {
571 nick
*np
= (nick
*)user
;
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 rq_addblock(cargv
[0], cargv
[2], account
, 0, expires
);
606 sendnoticetouser(rqnick
, np
, "Blocked channels/accounts matching '%s' from "
607 "requesting a service.", cargv
[0]);
612 int rqcmd_delblock(void *user
, int cargc
, char **cargv
) {
613 nick
*np
= (nick
*)user
;
617 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
623 sendnoticetouser(rqnick
, np
, "Syntax: delblock <mask>");
628 result
= rq_removeblock(cargv
[0]);
631 sendnoticetouser(rqnick
, np
, "Block for '%s' was removed.", cargv
[0]);
635 sendnoticetouser(rqnick
, np
, "There is no such block.");
641 int rqcmd_listblocks(void *user
, int cargc
, char **cargv
) {
642 nick
*np
= (nick
*)user
;
647 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
652 sendnoticetouser(rqnick
, np
, "Mask By Expires"
655 for (i
= 0; i
< rqblocks
.cursi
; i
++) {
656 block
= ((rq_block
*)rqblocks
.content
)[i
];
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 */
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
);
669 sendnoticetouser(rqnick
, np
, "--- End of blocklist");
674 int rqcmd_stats(void *user
, int cargc
, char **cargv
) {
675 nick
*np
= (nick
*)user
;
678 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
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
);
688 lr_requeststats(rqnick
, np
);
689 qr_requeststats(rqnick
, np
);