]>
jfr.im git - irc/quakenet/newserv.git/blob - request/sqrequest.c
2 * S and Q request system!
4 * Depends on "chanstats" and "chanfix"
10 #include "request_block.h"
11 #include "../chanfix/chanfix.h"
12 #include "../chanstats/chanstats.h"
13 #include "../localuser/localuser.h"
14 #include "../lib/irc_string.h"
15 #include "../core/schedule.h"
21 #define QRLstate_IDLE 0x0 /* No request active */
22 #define QRLstate_AWAITINGCHAN 0x1 /* Awaiting "Users for channel.." */
23 #define QRLstate_AWAITINGUSER 0x2 /* Looking for our user in the list */
24 #define QRLstate_AWAITINGEND 0x3 /* Waiting for "End of chanlev" */
30 #define QR_SPAMSCAN 0x1
35 #define min(a,b) ((a > b) ? b : a)
37 typedef struct requestrec
{
38 unsigned int reqnumeric
; /* Who made the request */
39 chanindex
*cip
; /* Which channel the request is for */
40 int what
; /* Which service does the user want? */
41 int who
; /* Who are we talking to about CHANLEV? */
42 struct requestrec
*next
;
45 requestrec
*nextreql
, *lastreql
;
46 requestrec
*nextreqq
, *lastreqq
;
49 requestrec
*nextqreq
, *lastqreq
;
62 /* Check whether the user is blocked */
63 int qr_blockcheck(requestrec
*req
) {
67 np
= getnickbynumeric(req
->reqnumeric
);
69 /* user is not online anymore */
73 block
= rq_findblock(np
->authname
);
76 return 1; /* user is blocked */
81 unsigned int rq_countchanusers(channel
*cp
) {
84 for (i
=0;i
<cp
->users
->hashsize
;i
++) {
85 if (cp
->users
->content
[i
]==nouser
)
95 * Deal with outcome of a queued request. The request should be freed
96 * as part of the process.
99 void qr_result(requestrec
*req
, int outcome
, char *message
, ...) {
100 sstring
*user
, *password
;
105 nick
*lnp
, *qnp
, *np
, *tnp
, *snp
;
108 unsigned int unique
, total
;
110 /* Delete the request from the list first.. */
111 for (rh
=&nextreql
;*rh
;rh
=&((*rh
)->next
)) {
118 for (rh
=&nextreqq
;*rh
;rh
=&((*rh
)->next
)) {
125 /* If this was the last request (unlikely),
126 * we need to fix the last pointer */
129 for (lastreql
=nextreql
;lastreql
->next
;lastreql
=lastreql
->next
)
137 for (lastreqq
=nextreqq
;lastreqq
->next
;lastreqq
=lastreqq
->next
)
143 /* Check that the nick is still here. If not, drop the request. */
144 if (!(tnp
=np
=getnickbynumeric(req
->reqnumeric
))) {
149 if (rq_logfd
!= NULL
) {
153 if (req
->cip
->channel
) {
154 unique
= countuniquehosts(req
->cip
->channel
);
155 total
= rq_countchanusers(req
->cip
->channel
);
161 strftime(now
, sizeof(now
), "%c", localtime(&now_ts
));
162 fprintf(rq_logfd
, "%s: request (%s) for %s (%d unique users, "
163 "%d total users) from %s: Request was %s.\n", now
,
164 (req
->what
== QR_CSERVE
) ? RQ_QNICK
: RQ_SNICK
,
165 req
->cip
->name
->content
, unique
, total
, tnp
->nick
,
166 (outcome
== QR_OK
) ? "accepted" : "denied");
170 if (outcome
==QR_OK
) {
171 if (req
->what
== QR_CSERVE
) {
172 /* Delete L, add Q. Check that they both exist first, though. */
174 if (!(lnp
=getnickbynick(RQ_LNICK
)) || !(qnp
=getnickbynick(RQ_QNICK
))) {
175 sendnoticetouser(rqnick
, tnp
,
176 "Error: Cannot find %s and %s on the network. "
177 "Please request again later.", RQ_LNICK
, RQ_QNICK
);
182 /* /msg Q ADDCHAN <channel> <flags> <owners nick> <channeltype> */
183 sendmessagetouser(rqnick
, qnp
, "ADDCHAN %s +ap #%s upgrade",
184 req
->cip
->name
->content
,
187 sendnoticetouser(rqnick
, tnp
, "Adding %s to channel, please wait...",
189 } else if (req
->what
== QR_SPAMSCAN
) {
192 if (!(snp
=getnickbynick(RQ_SNICK
))) {
193 sendnoticetouser(rqnick
, tnp
,
194 "Error: Cannot find %s on the network. "
195 "Please request again later.", RQ_SNICK
);
201 sendnoticetouser(rqnick
, tnp
, "Requirements met, %s should be added. "
202 "Contact #help should further assistance be required.",
206 user
= (sstring
*)getcopyconfigitem("request", "user", "R", 30);
207 password
= (sstring
*)getcopyconfigitem("request", "password", "bla", 30);
208 sendmessagetouser(rqnick
, snp
, "AUTH %s %s", user
->content
, password
->content
);
210 freesstring(password
);
212 /* /msg S addchan <channel> default */
213 sendmessagetouser(rqnick
, snp
, "ADDCHAN %s default +op", req
->cip
->name
->content
);
215 /* we do not put the request into another queue, so free it here */
224 lastqreq
=nextqreq
=req
;
230 /* Don't free, it's in new queue now */
232 /* Sort out the message.. */
233 va_start(va
, message
);
234 vsnprintf(msgbuf
,511,message
,va
);
237 sendnoticetouser(rqnick
, tnp
, "%s", msgbuf
);
238 /* This is a failure message. Add disclaimer. */
239 /*sendnoticetouser(rqnick, tnp, "Do not complain about this result in #help or #feds.");*/
248 * Checks that a channel is beeeeg enough for teh Q
251 int qr_checksize(chanindex
*cip
, int what
) {
255 int i
, avg
, tot
=0, authedcount
=0, count
=0, uniquecount
, avgcount
;
260 return 0; /* this shouldn't ever happen */
266 /* make sure we can actually add Q */
267 if (what
== QR_CSERVE
) {
268 qbot
= getnickbynick(RQ_QNICK
);
273 if (QR_MAXQCHANS
!= 0 && qbot
->channels
->cursi
> QR_MAXQCHANS
)
274 return 0; /* no Q for you :p */
277 /* make sure that there are enough authed users */
278 for (i
=0;i
<cp
->users
->hashsize
;i
++) {
279 if (cp
->users
->content
[i
] != nouser
) {
280 np
= getnickbynumeric(cp
->users
->content
[i
]);
289 if (authedcount
* 100 / count
< ((what
== QR_CSERVE
) ? QR_AUTHEDPCT_CSERVE
: QR_AUTHEDPCT_SPAMSCAN
))
290 return 0; /* too few authed users */
292 if (!(csp
=cip
->exts
[csext
]))
295 for (i
=0;i
<HISTORYDAYS
;i
++) {
296 tot
+= csp
->lastdays
[i
];
299 uniquecount
= countuniquehosts(cp
);
300 avgcount
= tot
/ HISTORYDAYS
/ 10;
302 /* chan needs at least QR_MINUSERPCT% of the avg usercount, and can't have
303 * more than QR_MAXUSERPCT% */
304 if ((avgcount
* QR_MINUSERSPCT
/ 100 > uniquecount
) ||
305 (avgcount
* QR_MAXUSERSPCT
/ 100 < uniquecount
))
308 avg
= (what
== QR_CSERVE
) ? QR_REQUIREDSIZE_CSERVE
: QR_REQUIREDSIZE_SPAMSCAN
;
310 if (tot
> (avg
* 140))
316 /* This function deals with notices from L: basically we track the
317 * responses to the L chanlev requests we've been making until we can
318 * decide what to do with the requests.
320 * Here's the L chanlev format:
321 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Users for channel #twilightzone
322 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Authname Access flags
323 * 11:12 -L(TheLBot@lightweight.quakenet.org)- -----------------------------
324 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Bigfoot amno
325 * 11:12 -L(TheLBot@lightweight.quakenet.org)- End of chanlev for #twilightzone.
328 void qr_handlenotice(nick
*sender
, char *message
) {
331 requestrec
*rrp1
, *rrp2
;
333 int delrequest
= 0, state
, who
;
337 /* logcp = findchannel("#qnet.request");
340 sendmessagetochannel(rqnick, logcp, "%s: %s - %d %d %x %x", sender->nick, message, rlstate, rqstate, nextreql, nextreqq);
342 if (!ircd_strcmp(sender
->nick
, RQ_QNICK
) && nextqreq
) {
344 if (!ircd_strcmp(message
,"Done.")) {
345 /* Q added the channel: delete from L and tell the user. */
346 /* If L has conspired to vanish between the request and the outcome,
347 * we have a chan with Q and L... too bad. */
349 if ((np
=getnickbynick(RQ_LNICK
))) {
350 sendmessagetouser(rqnick
, np
, "SENDCHANLEV %s %s",
351 nextqreq
->cip
->name
->content
, RQ_QNICK
);
353 sendmessagetouser(rqnick
, np
, "DELCHAN %s",
354 nextqreq
->cip
->name
->content
);
357 if ((np
=getnickbynumeric(nextqreq
->reqnumeric
))) {
358 sendnoticetouser(rqnick
, np
, "Request completed. %s added.", RQ_QNICK
);
362 } else if (!ircd_strcmp(message
,"That channel already exists.")) {
363 if ((np
=getnickbynumeric(nextqreq
->reqnumeric
))) {
364 sendnoticetouser(rqnick
, np
,
365 "Your channel appears to have %s already "
366 "(it may be suspended).", RQ_QNICK
);
374 /* For either of the two messages above we want to delete the request
375 * at the head of the queue. */
379 nextqreq
=nextqreq
->next
;
387 if (!ircd_strcmp(sender
->nick
, RQ_LNICK
) || !ircd_strcmp(sender
->nick
, RQ_QNICK
)) {
388 who
= !ircd_strcmp(sender
->nick
, RQ_LNICK
) ? QR_L
: QR_Q
;
389 state
= (who
== QR_Q
) ? rqstate
: rlstate
;
390 nextreq
= (who
== QR_Q
) ? nextreqq
: nextreql
;
392 /* Message from L or Q */
395 /* We're idle, do nothing */
398 case QRLstate_AWAITINGCHAN
:
399 /* We're waiting for conformation of the channel name */
400 if ((!ircd_strncmp(message
,"Users for",9) && who
== QR_L
) ||
401 (!ircd_strncmp(message
,"Known users on",14) && who
== QR_Q
)
403 /* Looks like the right message. Let's find a channel name */
405 for (ch
=message
;*ch
;ch
++)
410 Error("qrequest",ERR_WARNING
,
411 "Unable to parse channel name from L/Q message: %s",message
);
415 /* chop off any remaining words */
424 if (!(cip
=findchanindex(ch
))) {
425 Error("qrequest",ERR_WARNING
,
426 "Unable to find channel from L/Q message: %s",ch
);
430 if (cip
==nextreq
->cip
) {
431 /* Ok, this is the correct channel, everything is proceeding
432 * exactly as I had forseen */
434 rlstate
= QRLstate_AWAITINGUSER
;
436 rqstate
= QRLstate_AWAITINGUSER
;
440 /* Uh-oh, not the channel we wanted. Something is fucked
441 * here. I think the only possible way out of this mess is
442 * to skip through in case we find a match for a later channel..
444 for (rrp1
=nextreq
;rrp1
;rrp1
=rrp1
->next
)
449 /* OK, we found a match further down the chain. This means
450 * that something bad has happened to every request between
451 * the head of the list and the one we just found - send
454 * Note weird loop head: qr_result will free up requests from
455 * the list as it goes, so we can just keep picking off the first
458 for(rrp2
=nextreq
;rrp2
;) {
462 Error("qrequest",ERR_WARNING
,
463 "Lost response for channel %s; skipping.",
464 rrp2
->cip
->name
->content
);
466 qr_result(rrp2
, QR_FAILED
,
467 "Sorry, an error occurred while processing your request.");
469 rrp2
= nextreq
= (who
== QR_Q
) ? nextreqq
: nextreql
;
473 /* We seem to be back in sync. */
475 rlstate
= QRLstate_AWAITINGUSER
;
477 rqstate
= QRLstate_AWAITINGUSER
;
481 /* Some form of hole in the space time continuum exists
482 * if we get here. Unclear how to proceed. */
485 /* No match - let's just ignore this completely */
486 Error("qrequest",ERR_WARNING
,
487 "Ignoring L/Q response for spurious channel %s",
495 case QRLstate_AWAITINGUSER
:
496 if ((!ircd_strncmp(message
, "End of chanlev",14) && who
== QR_L
) ||
497 (!ircd_strncmp(message
, "End of list.",12) && who
== QR_Q
)) {
498 /* Oh dear, we got to the end of the chanlev in this state.
499 * This means that we didn't find the user.
502 qr_result(nextreq
, QR_FAILED
,
503 "Error: You are not known on %s.",
504 nextreq
->cip
->name
->content
);
506 /* need to reset nextreq .. just in case
507 * qr_result has cleaned up records */
509 nextreq
= (who
== QR_Q
) ? nextreqq
: nextreql
;
513 rlstate
= QRLstate_AWAITINGUSER
;
515 rqstate
= QRLstate_AWAITINGUSER
;
518 rlstate
= QRLstate_IDLE
;
520 rqstate
= QRLstate_IDLE
;
527 /* Brutalise the message :-) */
530 while (*message
== ' ')
534 if (!(ch
=strchr(message
, ' ')))
539 if (!(np
=getnickbynumeric(nextreq
->reqnumeric
)))
542 if (ircd_strcmp(message
, np
->authname
)) {
543 /* This is not the user you are looking for */
547 /* Check for owner flag. Both branches of this if will
548 * take the request off the list, one way or the other. */
549 if (strchr(ch
, 'n')) {
550 /* They iz teh +n! */
552 /* Note: We're checking for blocks kind of late, so the request
553 system gets a chance to send other error messages first (like
554 'no chanstats', 'not known on channel', etc.). This is required
555 so that the user doesn't notice that he's being blocked. */
556 if (qr_checksize(nextreq
->cip
, nextreq
->what
) && !qr_blockcheck(nextreq
)) {
557 qr_result(nextreq
, QR_OK
, "OK");
559 if (nextreq
->what
== QR_CSERVE
) {
560 qr_result(nextreq
, QR_FAILED
,
561 "Error: You do not meet the requirements "
562 "for %s. Please continue to use %s.", RQ_QNICK
, RQ_LNICK
);
564 qr_result(nextreq
, QR_FAILED
,
565 "Error: Your channel does not require %s. "
566 "Try again later.", RQ_SNICK
);
572 qr_result(nextreq
, QR_FAILED
,
573 "Error: You don't hold the +n flag on %s.",
574 nextreq
->cip
->name
->content
);
579 /* OK, we found what we wanted so make sure we skip the rest */
581 rlstate
= QRLstate_AWAITINGEND
;
583 rqstate
= QRLstate_AWAITINGEND
;
589 case QRLstate_AWAITINGEND
:
590 if (!ircd_strncmp(message
, "End of chanlev",14) ||
591 !ircd_strncmp(message
, "End of list.",12)) {
592 /* Found end of list */
596 rlstate
= QRLstate_AWAITINGCHAN
;
598 rqstate
= QRLstate_AWAITINGCHAN
;
601 rlstate
= QRLstate_IDLE
;
603 rqstate
= QRLstate_IDLE
;
614 * This function deals with requests from users for Q.
615 * Some sanity checks are made and the request is
616 * added to the queue.
619 int qr_requestq(nick
*rqnick
, nick
*sender
, channel
*cp
, nick
*lnick
, nick
*qnick
) {
620 chanindex
*cip
= cp
->index
;
623 * - we have some form of channel stats for the channel
625 * Note that the actual channel stats will not be checked
626 * until we're sure the user has +n on the channel.
629 if (rq_isspam(sender
)) {
630 sendnoticetouser(rqnick
, sender
, "Error: Do not flood the request system."
631 " Try again in %s.", rq_longtoduration(rq_blocktime(sender
)));
636 if (!cip
->exts
[csext
]) {
637 sendnoticetouser(rqnick
, sender
,
638 "Error: No historical record exists for %s.",
646 /* Request stats from L */
647 sendmessagetouser(rqnick
, lnick
, "CHANLEV %s", cip
->name
->content
);
649 /* Sort out a request record */
651 lastreql
->next
= (requestrec
*)malloc(sizeof(requestrec
));
652 lastreql
=lastreql
->next
;
654 lastreql
=nextreql
=(requestrec
*)malloc(sizeof(requestrec
));
657 lastreql
->next
= NULL
;
659 lastreql
->what
= QR_CSERVE
;
660 lastreql
->who
= QR_L
;
661 lastreql
->reqnumeric
= sender
->numeric
;
663 if (rlstate
== QRLstate_IDLE
)
664 rlstate
= QRLstate_AWAITINGCHAN
;
666 sendnoticetouser(rqnick
, sender
,
667 "Checking your %s access. "
668 "This may take a while, please be patient...", RQ_LNICK
);
670 /* we don't know yet whether the request was successful */
674 int qr_instantrequestq(nick
*sender
, channel
*cp
) {
675 requestrec
*fakerequest
;
679 regop
*rolist
[QR_TOPX
];
681 if (!qr_checksize(cp
->index
, QR_CSERVE
))
684 cf
= cf_findchanfix(cp
->index
);
689 rocount
= cf_getsortedregops(cf
, QR_TOPX
, rolist
);
693 for (i
= 0; i
< min(QR_TOPX
, rocount
); i
++) {
694 if (cf_cmpregopnick(rolist
[i
], sender
)) {
700 /* not in top 5 - we don't have to worry about that error here
701 as the L request code will detect it again and send the user
702 an appropriate message */
706 /* allocate a fake request */
707 fakerequest
= (requestrec
*)malloc(sizeof(requestrec
));
709 fakerequest
->reqnumeric
= sender
->numeric
;
710 fakerequest
->cip
= cp
->index
;
711 fakerequest
->what
= QR_CSERVE
;
712 fakerequest
->who
= QR_L
; /* pretend that we asked L about the chanlev */
714 /* add it to the queue */
715 if (nextreql
== NULL
) {
716 fakerequest
->next
= NULL
;
717 nextreql
= fakerequest
;
718 lastreql
= fakerequest
;
720 fakerequest
->next
= nextreql
;
721 nextreql
= fakerequest
;
724 qr_result(fakerequest
, QR_OK
, "OK");
729 int qr_requests(nick
*rqnick
, nick
*sender
, channel
*cp
, nick
*lnick
, nick
*qnick
) {
730 chanindex
*cip
= cp
->index
;
732 requestrec
*nextreq
, *lastreq
;
734 if (rq_isspam(sender
)) {
735 sendnoticetouser(rqnick
, sender
, "Error: Do not flood the request system."
736 " Try again in %s.", rq_longtoduration(rq_blocktime(sender
)));
741 /* check which service is on the channel */
742 if (getnumerichandlefromchanhash(cp
->users
, lnick
->numeric
) != NULL
) {
746 /* Request stats from L */
747 sendmessagetouser(rqnick
, lnick
, "CHANLEV %s", cip
->name
->content
);
749 if (rlstate
== QRLstate_IDLE
)
750 rlstate
= QRLstate_AWAITINGCHAN
;
751 } else if (getnumerichandlefromchanhash(cp
->users
, qnick
->numeric
) != NULL
) {
755 /* Request stats from Q */
756 sendmessagetouser(rqnick
, qnick
, "CHANLEV %s", cip
->name
->content
);
758 if (rqstate
== QRLstate_IDLE
)
759 rqstate
= QRLstate_AWAITINGCHAN
;
760 } /* 'else' cannot happen as R has already checked whether the user has L or Q */
762 lastreq
= (who
== QR_Q
) ? lastreqq
: lastreql
;
763 nextreq
= (who
== QR_Q
) ? nextreqq
: nextreql
;
765 /* Sort out a request record */
767 lastreq
->next
= (requestrec
*)malloc(sizeof(requestrec
));
768 lastreq
=lastreq
->next
;
770 lastreq
=nextreq
=(requestrec
*)malloc(sizeof(requestrec
));
773 lastreq
->next
= NULL
;
775 lastreq
->what
= QR_SPAMSCAN
;
776 lastreq
->reqnumeric
= sender
->numeric
;
786 sendnoticetouser(rqnick
, sender
,
787 "Checking your %s access. "
788 "This may take a while, please be patient...",
789 who
== QR_Q
? RQ_QNICK
: RQ_LNICK
);
794 void qr_initrequest(void) {
795 nextreql
=lastreql
=NULL
;
796 nextreqq
=lastreqq
=NULL
;
797 nextqreq
=lastqreq
=NULL
;
800 void qr_finirequest(void) {
801 struct requestrec
*rp
;
805 nextreqq
=nextreqq
->next
;
811 nextreql
=nextreql
->next
;
817 nextqreq
=nextqreq
->next
;
822 void qr_requeststats(nick
*rqnick
, nick
*np
) {
823 sendnoticetouser(rqnick
, np
, "- Suspended (Q): %d", qr_suspended
);
824 sendnoticetouser(rqnick
, np
, "- No chanstats (Q/S): %d", qr_nohist
);
825 sendnoticetouser(rqnick
, np
, "- Too small (Q/S): %d", qr_toosmall
);
826 sendnoticetouser(rqnick
, np
, "- User was not on chanlev (Q/S): %d", qr_nochanlev
);
827 sendnoticetouser(rqnick
, np
, "- User was not the owner (Q/S): %d", qr_notowner
);