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
);
327 retval
= lr_requestl(rqnick
, np
, cp
, qnick
);
329 if (rq_logfd
!= NULL
) {
332 strftime(now
, sizeof(now
), "%c", localtime(&now_ts
));
334 fprintf(rq_logfd
, "%s: request (%s) for %s from %s!%s@%s%s%s: Request was %s.\n",
335 now
, RQ_QNICK
, cp
->index
->name
->content
,
336 np
->nick
, np
->ident
, np
->host
->name
->content
, IsAccount(np
)?"/":"", IsAccount(np
)?np
->authname
:"",
337 (retval
== RQ_OK
) ? "accepted" : "denied");
341 if (retval
== RQ_ERROR
)
343 else if (retval
== RQ_OK
)
349 int rqcmd_requestspamscan(void *user
, int cargc
, char **cargv
) {
350 nick
*np
= (nick
*)user
;
353 unsigned long *qhand
, *shand
;
357 sendnoticetouser(rqnick
, np
, "Syntax: requestspamscan <#channel>");
364 if (rq_genericrequestcheck(np
, cargv
[0], &cp
, &qnick
) == RQ_ERROR
) {
370 snick
= getnickbynick(RQ_SNICK
);
372 if (snick
== NULL
|| findserver(RQ_SSERVER
) < 0) {
373 sendnoticetouser(rqnick
, np
, "Error: %s does not seem to be online. "
374 "Please try again later.", RQ_SNICK
);
381 /* does the user already have S on that channel? */
382 shand
= getnumerichandlefromchanhash(cp
->users
, snick
->numeric
);
385 sendnoticetouser(rqnick
, np
, "Error: %s is already on that channel.", RQ_SNICK
);
393 qhand
= getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
);
396 /* great, now try to request */
397 retval
= qr_requests(rqnick
, np
, cp
, qnick
);
401 else if (retval
== RQ_ERROR
)
406 /* channel apparently doesn't have Q */
408 sendnoticetouser(rqnick
, np
, "Error: You need %s in order to be "
409 "able to request %s.", RQ_QNICK
, RQ_SNICK
);
417 int rqcmd_requestop(void *source
, int cargc
, char **cargv
) {
418 nick
*np2
, *np
= (nick
*)source
;
426 sendnoticetouser(rqnick
, np
, "Syntax: requestop <#channel> [nick]");
431 cp
= findchannel(cargv
[0]);
434 sendnoticetouser(rqnick
, np
, "Error: Channel '%s' does not exist on the network.",
441 user
= getnickbynick(cargv
[1]);
444 sendnoticetouser(rqnick
, np
, "Error: No such user.");
450 if (getnettime() - np
->timestamp
< 300) {
451 sendnoticetouser(rqnick
, np
, "Error: You connected %s ago. To"
452 " request ops you must have been on the network for"
453 " at least 5 minutes.",
454 rq_longtoduration(getnettime() - np
->timestamp
));
459 if (getnettime() - user
->timestamp
< 300) {
460 sendnoticetouser(rqnick
, np
, "Error: The nick you requested op for"
461 " connected %s ago. To request op, it must have"
462 "been on the network for at least 5 minutes.",
463 rq_longtoduration(getnettime() - user
->timestamp
));
468 hand
= getnumerichandlefromchanhash(cp
->users
, user
->numeric
);
471 sendnoticetouser(rqnick
, np
, "Error: User %s is not on channel '%s'.", user
->nick
, cargv
[0]);
479 localsetmodeinit(&changes
, cp
, rqnick
);
481 /* reop any services first */
482 for(a
=0;a
<cp
->users
->hashsize
;a
++) {
483 if(cp
->users
->content
[a
] != nouser
) {
484 np2
= getnickbynumeric(cp
->users
->content
[a
]);
486 if (IsService(np2
) && (np2
->nick
[1] == '\0') && !(cp
->users
->content
[a
] & CUMODE_OP
)) {
487 localdosetmode_nick(&changes
, np2
, MC_OP
);
493 localsetmodeflush(&changes
, 1);
497 sendnoticetouser(rqnick
, np
, "1 service was reopped.");
499 sendnoticetouser(rqnick
, np
, "%d services were reopped.", count
);
504 for (a
=0;a
<cp
->users
->hashsize
;a
++) {
505 if ((cp
->users
->content
[a
] != nouser
) && (cp
->users
->content
[a
] & CUMODE_OP
)) {
506 sendnoticetouser(rqnick
, np
, "There are ops on channel '%s'. This command can only be"
507 " used if there are no ops.", cargv
[0]);
513 if (sp_countsplitservers(SERVERTYPEFLAG_USER_STATE
) > 0) {
514 sendnoticetouser(rqnick
, np
, "One or more servers are currently split. Wait until the"
515 " netsplit is over and try again.");
520 if (cf_wouldreop(user
, cp
)) {
521 localsetmodeinit(&changes
, cp
, rqnick
);
522 localdosetmode_nick(&changes
, user
, MC_OP
);
523 localsetmodeflush(&changes
, 1);
525 sendnoticetouser(rqnick
, np
, "Chanfix opped you on the specified channel.");
527 ret
= cf_fixchannel(cp
);
529 if (ret
== CFX_NOUSERSAVAILABLE
)
530 sendnoticetouser(rqnick
, np
, "Chanfix knows regular ops for that channel. They will"
531 " be opped when they return.");
533 sendnoticetouser(rqnick
, np
, "Chanfix has opped known ops for that channel.");
540 int rqcmd_addblock(void *user
, int cargc
, char **cargv
) {
541 nick
*np
= (nick
*)user
;
547 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
553 sendnoticetouser(rqnick
, np
, "Syntax: addblock <mask> <duration> <reason>");
558 block
= rq_findblock(cargv
[0]);
561 sendnoticetouser(rqnick
, np
, "That mask is already blocked by %s "
562 "(reason: %s).", block
->creator
->content
, block
->reason
->content
);
568 account
= np
->authname
;
572 expires
= getnettime() + durationtolong(cargv
[1]);
574 rq_addblock(cargv
[0], cargv
[2], account
, 0, expires
);
576 sendnoticetouser(rqnick
, np
, "Blocked channels/accounts matching '%s' from "
577 "requesting a service.", cargv
[0]);
582 int rqcmd_delblock(void *user
, int cargc
, char **cargv
) {
583 nick
*np
= (nick
*)user
;
587 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
593 sendnoticetouser(rqnick
, np
, "Syntax: delblock <mask>");
598 result
= rq_removeblock(cargv
[0]);
601 sendnoticetouser(rqnick
, np
, "Block for '%s' was removed.", cargv
[0]);
605 sendnoticetouser(rqnick
, np
, "There is no such block.");
611 int rqcmd_listblocks(void *user
, int cargc
, char **cargv
) {
612 nick
*np
= (nick
*)user
;
617 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
622 sendnoticetouser(rqnick
, np
, "Mask By Expires"
625 for (i
= 0; i
< rqblocks
.cursi
; i
++) {
626 block
= ((rq_block
*)rqblocks
.content
)[i
];
628 if (block
.expires
!= 0 && block
.expires
< getnettime())
629 continue; /* ignore blocks which have already expired,
630 rq_findblock will deal with them later on */
632 if (cargc
< 1 || match2strings(block
.pattern
->content
, cargv
[0]))
633 sendnoticetouser(rqnick
, np
, "%-11s %-9s %-25s %s",
634 block
.pattern
->content
, block
.creator
->content
,
635 rq_longtoduration(block
.expires
- getnettime()),
636 block
.reason
->content
);
639 sendnoticetouser(rqnick
, np
, "--- End of blocklist");
644 int rqcmd_stats(void *user
, int cargc
, char **cargv
) {
645 nick
*np
= (nick
*)user
;
648 sendnoticetouser(rqnick
, np
, "You do not have access to this command.");
653 sendnoticetouser(rqnick
, np
, "Total requests: %d", rq_count
);
654 sendnoticetouser(rqnick
, np
, "Successful requests: %d", rq_success
);
655 sendnoticetouser(rqnick
, np
, "Failed requests: %d", rq_failed
);
656 sendnoticetouser(rqnick
, np
, "- Blocked: %d", rq_blocked
);
658 lr_requeststats(rqnick
, np
);
659 qr_requeststats(rqnick
, np
);