]> jfr.im git - irc/quakenet/newserv.git/blame - request/sqrequest.c
fix: warning: format not a string literal and no format arguments
[irc/quakenet/newserv.git] / request / sqrequest.c
CommitLineData
25b7d0fa
P
1/*
2 * S and Q request system!
3 *
4 * Depends on "chanstats" and "chanfix"
5 */
6
052247fa 7#include <stdio.h>
25b7d0fa
P
8#include "request.h"
9#include "sqrequest.h"
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"
f011b15a 16#include "../core/config.h"
a421a6dc 17/*
0096e09a 18#include "../spamscan2/spamscan2.h"
a421a6dc 19*/
25b7d0fa
P
20
21#include <stdarg.h>
22#include <stdio.h>
23#include <string.h>
24
25#define QRLstate_IDLE 0x0 /* No request active */
26#define QRLstate_AWAITINGCHAN 0x1 /* Awaiting "Users for channel.." */
27#define QRLstate_AWAITINGUSER 0x2 /* Looking for our user in the list */
28#define QRLstate_AWAITINGEND 0x3 /* Waiting for "End of chanlev" */
29
30#define QR_FAILED 0x0
31#define QR_OK 0x1
32
33#define QR_CSERVE 0x0
34#define QR_SPAMSCAN 0x1
35
36#define QR_L 0x0
37#define QR_Q 0x1
38
39#define min(a,b) ((a > b) ? b : a)
40
41typedef struct requestrec {
42 unsigned int reqnumeric; /* Who made the request */
43 chanindex *cip; /* Which channel the request is for */
44 int what; /* Which service does the user want? */
45 int who; /* Who are we talking to about CHANLEV? */
46 struct requestrec *next;
47} requestrec;
48
49requestrec *nextreql, *lastreql;
50requestrec *nextreqq, *lastreqq;
51
52
b98ba21f 53static requestrec *nextqreq, *lastqreq;
25b7d0fa
P
54
55extern nick *rqnick;
56int rlstate;
57int rqstate;
58
59/* stats counters */
60int qr_suspended = 0;
61int qr_nohist = 0;
62int qr_toosmall = 0;
63int qr_nochanlev = 0;
64int qr_notowner = 0;
65
0096e09a
P
66int qr_a = 0;
67int qr_b = 0;
68int qr_c = 0;
69int qr_d = 0;
70int qr_e = 0;
71
25b7d0fa
P
72/* Check whether the user is blocked */
73int qr_blockcheck(requestrec *req) {
74 nick *np;
75 rq_block *block;
76
77 np = getnickbynumeric(req->reqnumeric);
78
79 /* user is not online anymore */
80 if (np == NULL)
81 return 0;
82
83 block = rq_findblock(np->authname);
84
85 if (block != NULL)
86 return 1; /* user is blocked */
87 else
88 return 0;
89}
90
052247fa
CP
91unsigned int rq_countchanusers(channel *cp) {
92 int i, count=0;
93
94 for (i=0;i<cp->users->hashsize;i++) {
95 if (cp->users->content[i]==nouser)
96 continue;
97
98 count++;
99 }
100
101 return count;
102}
103
25b7d0fa
P
104/*
105 * Deal with outcome of a queued request. The request should be freed
106 * as part of the process.
107 */
108
bb4b25ee 109static void qr_result(requestrec *req, int outcome, char failcode, char *message, ...) __attribute__ ((format (printf, 4, 5)));
b98ba21f 110static void qr_result(requestrec *req, int outcome, char failcode, char *message, ...) {
25b7d0fa
P
111 sstring *user, *password;
112 requestrec **rh;
113 char msgbuf[512];
114 va_list va;
680c487f 115 nick *np, *tnp, *snp;
052247fa
CP
116 char now[50];
117 time_t now_ts;
118 unsigned int unique, total;
119
25b7d0fa
P
120 /* Delete the request from the list first.. */
121 for (rh=&nextreql;*rh;rh=&((*rh)->next)) {
122 if (*rh==req) {
123 *rh=req->next;
124 break;
125 }
126 }
127
128 for (rh=&nextreqq;*rh;rh=&((*rh)->next)) {
129 if (*rh==req) {
130 *rh=req->next;
131 break;
132 }
133 }
134
135 /* If this was the last request (unlikely),
136 * we need to fix the last pointer */
137 if (lastreql==req) {
138 if (nextreql)
139 for (lastreql=nextreql;lastreql->next;lastreql=lastreql->next)
140 ; /* empty loop */
141 else
142 lastreql=NULL;
143 }
144
145 if (lastreqq==req) {
146 if (nextreqq)
147 for (lastreqq=nextreqq;lastreqq->next;lastreqq=lastreqq->next)
148 ; /* empty loop */
149 else
150 lastreqq=NULL;
151 }
152
153 /* Check that the nick is still here. If not, drop the request. */
154 if (!(tnp=np=getnickbynumeric(req->reqnumeric))) {
155 free(req);
156 return;
157 }
158
052247fa
CP
159 if (rq_logfd != NULL) {
160 now[0] = '\0';
161 now_ts = time(NULL);
162
163 if (req->cip->channel) {
164 unique = countuniquehosts(req->cip->channel);
165 total = rq_countchanusers(req->cip->channel);
166 } else {
167 unique = 0;
168 total = 0;
169 }
cbdd5aab 170
052247fa
CP
171 strftime(now, sizeof(now), "%c", localtime(&now_ts));
172 fprintf(rq_logfd, "%s: request (%s) for %s (%d unique users, "
0096e09a 173 "%d total users) from %s: Request was %s (%c).\n", now,
052247fa
CP
174 (req->what == QR_CSERVE) ? RQ_QNICK : RQ_SNICK,
175 req->cip->name->content, unique, total, tnp->nick,
0096e09a 176 (outcome == QR_OK) ? "accepted" : "denied", failcode);
052247fa 177 fflush(rq_logfd);
cbdd5aab
P
178 }
179
25b7d0fa 180 if (outcome==QR_OK) {
95440fe7 181 if (req->what == QR_SPAMSCAN) {
25b7d0fa
P
182 /* Add S */
183
184 if (!(snp=getnickbynick(RQ_SNICK))) {
185 sendnoticetouser(rqnick, tnp,
186 "Error: Cannot find %s on the network. "
187 "Please request again later.", RQ_SNICK);
188
189 free(req);
190 return;
191 }
192
193 sendnoticetouser(rqnick, tnp, "Requirements met, %s should be added. "
194 "Contact #help should further assistance be required.",
195 RQ_SNICK);
196
197 /* auth */
052247fa
CP
198 user = (sstring *)getcopyconfigitem("request", "user", "R", 30);
199 password = (sstring *)getcopyconfigitem("request", "password", "bla", 30);
25b7d0fa
P
200 sendmessagetouser(rqnick, snp, "AUTH %s %s", user->content, password->content);
201 freesstring(user);
202 freesstring(password);
203
204 /* /msg S addchan <channel> default */
a421a6dc 205 sendmessagetouser(rqnick, snp, "ADDCHAN %s default +o", req->cip->name->content);
0096e09a 206
a421a6dc 207/*
0096e09a
P
208{
209 spamscan_channelprofile *cp;
210 spamscan_channelsettings *cs;
211 spamscan_channelext *ce;
212 chanindex *sc_index;
213
214 cs = spamscan_getchannelsettings(req->cip->name->content, 0);
215
216 if ( !cs ) {
217 cp = spamscan_getchannelprofile("Default", 0);
218
219 if ( cp ) {
220 cs = spamscan_getchannelsettings(req->cip->name->content, 1);
221
222 if ( cs ) {
223 cs->cp = cp;
224 cs->addedby = spamscan_getaccountsettings("R", 0);
225 cs->flags = SPAMSCAN_CF_IGNOREOPS;
226
227 sc_index = findorcreatechanindex(req->cip->name->content);
228
229 if ( sc_index ) {
230 ce = spamscan_getchanext(sc_index, 1);
231 ce->cs = cs;
232
233 if ( s_nickname && !CFIsSuspended(cs) && sc_index->channel ) {
234 ce->joinedchan = 1;
235 localjoinchannel(s_nickname, sc_index->channel);
236 localgetops(s_nickname, sc_index->channel);
237 }
238 }
239
240 spamscan_insertchanneldb(cs);
241 }
242 }
243 }
244}
a421a6dc 245*/
25b7d0fa
P
246
247 /* we do not put the request into another queue, so free it here */
248 free(req);
249
250 return;
251 }
252
253 if (lastqreq)
254 lastqreq->next=req;
255 else
256 lastqreq=nextqreq=req;
257
258 req->next=NULL;
259
260 rq_success++;
261
262 /* Don't free, it's in new queue now */
263 } else {
264 /* Sort out the message.. */
265 va_start(va, message);
266 vsnprintf(msgbuf,511,message,va);
267 va_end(va);
268
269 sendnoticetouser(rqnick, tnp, "%s", msgbuf);
270 /* This is a failure message. Add disclaimer. */
271 /*sendnoticetouser(rqnick, tnp, "Do not complain about this result in #help or #feds.");*/
272 free(req);
273
274 rq_failed++;
275 }
276}
277
278/*
279 * qr_checksize:
280 * Checks that a channel is beeeeg enough for teh Q
281 */
282
b98ba21f 283static int qr_checksize(chanindex *cip, int what, char *failcode) {
25b7d0fa
P
284 chanstats *csp;
285 channel *cp;
052247fa
CP
286 nick *np, *qbot;
287 int i , avg, tot=0, authedcount=0, count=0, uniquecount, avgcount;
25b7d0fa
P
288
289 cp = cip->channel;
290
291 if (cp == NULL)
292 return 0; /* this shouldn't ever happen */
293
294#if QR_DEBUG
295 return 1;
296#endif
297
052247fa
CP
298 /* make sure we can actually add Q */
299 if (what == QR_CSERVE) {
300 qbot = getnickbynick(RQ_QNICK);
301
302 if (!qbot)
303 return 0;
304
0096e09a
P
305 if (QR_MAXQCHANS != 0 && qbot->channels->cursi > QR_MAXQCHANS) {
306 qr_a++;
307 *failcode = 'A';
052247fa 308 return 0; /* no Q for you :p */
0096e09a 309 }
052247fa
CP
310 }
311
25b7d0fa
P
312 /* make sure that there are enough authed users */
313 for (i=0;i<cp->users->hashsize;i++) {
314 if (cp->users->content[i] != nouser) {
315 np = getnickbynumeric(cp->users->content[i]);
316
317 if (IsAccount(np))
318 authedcount++;
319
320 count++;
321 }
322 }
323
0096e09a
P
324 int authedpct;
325
326 if (what == QR_CSERVE) {
327 if ( count <= QR_AUTHEDPCT_SCALE ) {
328 authedpct = QR_AUTHEDPCT_CSERVE;
329 } else if ( count >= QR_AUTHEDPCT_SCALEMAX ) {
330 authedpct = QR_AUTHEDPCT_CSERVEMIN;
331 } else {
332 authedpct = (QR_AUTHEDPCT_CSERVEMIN + (((QR_AUTHEDPCT_CSERVE - QR_AUTHEDPCT_CSERVEMIN) * (100 - (((count - QR_AUTHEDPCT_SCALE) * 100) / (QR_AUTHEDPCT_SCALEMAX - QR_AUTHEDPCT_SCALE)))) / 100));
333 }
334 }
335 else {
336 if ( count <= QR_AUTHEDPCT_SCALE ) {
337 authedpct = QR_AUTHEDPCT_SPAMSCAN;
338 } else if ( count >= QR_AUTHEDPCT_SCALEMAX ) {
339 authedpct = QR_AUTHEDPCT_SPAMSCANMIN;
340 } else {
341 authedpct = (QR_AUTHEDPCT_SPAMSCANMIN + (((QR_AUTHEDPCT_SPAMSCAN - QR_AUTHEDPCT_SPAMSCANMIN) * (100 - (((count - QR_AUTHEDPCT_SCALE) * 100) / (QR_AUTHEDPCT_SCALEMAX - QR_AUTHEDPCT_SCALE)))) / 100));
342 }
343 }
344
345 if (authedcount * 100 / count < authedpct) {
346 qr_b++;
347 *failcode = 'B';
25b7d0fa 348 return 0; /* too few authed users */
0096e09a 349 }
25b7d0fa
P
350
351 if (!(csp=cip->exts[csext]))
352 return 0;
353
354 for (i=0;i<HISTORYDAYS;i++) {
355 tot += csp->lastdays[i];
356 }
357
052247fa
CP
358 uniquecount = countuniquehosts(cp);
359 avgcount = tot / HISTORYDAYS / 10;
360
361 /* chan needs at least QR_MINUSERPCT% of the avg usercount, and can't have
362 * more than QR_MAXUSERPCT% */
0096e09a
P
363 if ( what == QR_CSERVE ) {
364 if ((avgcount * QR_MINUSERSPCT / 100 > uniquecount)) {
365 qr_c++;
366 *failcode = 'C';
367 return 0;
368 }
369 if ((avgcount * QR_MAXUSERSPCT / 100 < uniquecount)) {
370 qr_e++;
371 *failcode = 'E';
372 return 0;
373 }
374 }
375
25b7d0fa
P
376 avg = (what == QR_CSERVE) ? QR_REQUIREDSIZE_CSERVE : QR_REQUIREDSIZE_SPAMSCAN;
377
378 if (tot > (avg * 140))
379 return 1;
0096e09a
P
380 else {
381 qr_d++;
382 *failcode = 'D';
052247fa 383 return 0;
0096e09a 384 }
25b7d0fa
P
385}
386
387/* This function deals with notices from L: basically we track the
388 * responses to the L chanlev requests we've been making until we can
389 * decide what to do with the requests.
390 *
391 * Here's the L chanlev format:
392 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Users for channel #twilightzone
393 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Authname Access flags
394 * 11:12 -L(TheLBot@lightweight.quakenet.org)- -----------------------------
395 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Bigfoot amno
396 * 11:12 -L(TheLBot@lightweight.quakenet.org)- End of chanlev for #twilightzone.
397 */
398
b98ba21f 399void qr_handle_notice(nick *sender, char *message) {
25b7d0fa
P
400 char *ch, *chop;
401 chanindex *cip;
402 requestrec *rrp1, *rrp2;
403 nick *np;
404 int delrequest = 0, state, who;
405 requestrec *nextreq;
25b7d0fa 406
25b7d0fa
P
407 if (!ircd_strcmp(sender->nick, RQ_QNICK) && nextqreq) {
408 /* Message from Q */
409 if (!ircd_strcmp(message,"Done.")) {
410 /* Q added the channel: delete from L and tell the user. */
411 /* If L has conspired to vanish between the request and the outcome,
412 * we have a chan with Q and L... too bad. */
25b7d0fa
P
413
414 delrequest = 1;
415 } else if (!ircd_strcmp(message,"That channel already exists.")) {
25b7d0fa
P
416
417 delrequest = 1;
25b7d0fa
P
418 }
419
420 /* For either of the two messages above we want to delete the request
421 * at the head of the queue. */
422 if (delrequest) {
423 rrp1=nextqreq;
424
425 nextqreq=nextqreq->next;
426 if (!nextqreq)
427 lastqreq=NULL;
428
429 free(rrp1);
430 }
431 }
432
95440fe7
P
433 if (!ircd_strcmp(sender->nick, RQ_QNICK)) {
434 who = QR_Q;
25b7d0fa
P
435 state = (who == QR_Q) ? rqstate : rlstate;
436 nextreq = (who == QR_Q) ? nextreqq : nextreql;
437
438 /* Message from L or Q */
439 switch (state) {
440 case QRLstate_IDLE:
441 /* We're idle, do nothing */
442 return;
443
444 case QRLstate_AWAITINGCHAN:
445 /* We're waiting for conformation of the channel name */
446 if ((!ircd_strncmp(message,"Users for",9) && who == QR_L) ||
447 (!ircd_strncmp(message,"Known users on",14) && who == QR_Q)
448 ) {
449 /* Looks like the right message. Let's find a channel name */
25b7d0fa
P
450 for (ch=message;*ch;ch++)
451 if (*ch=='#')
452 break;
453
454 if (!*ch) {
455 Error("qrequest",ERR_WARNING,
456 "Unable to parse channel name from L/Q message: %s",message);
457 return;
458 }
459
460 /* chop off any remaining words */
461 chop = ch;
462 while (*(chop++)) {
95440fe7 463 if (*chop == ' ' || *chop == ':') {
25b7d0fa
P
464 *chop = '\0';
465 break;
466 }
467 }
25b7d0fa
P
468 if (!(cip=findchanindex(ch))) {
469 Error("qrequest",ERR_WARNING,
470 "Unable to find channel from L/Q message: %s",ch);
471 return;
472 }
473
474 if (cip==nextreq->cip) {
475 /* Ok, this is the correct channel, everything is proceeding
476 * exactly as I had forseen */
477 if (who == QR_L)
478 rlstate = QRLstate_AWAITINGUSER;
479 else
480 rqstate = QRLstate_AWAITINGUSER;
25b7d0fa
P
481 return;
482 } else {
483 /* Uh-oh, not the channel we wanted. Something is fucked
484 * here. I think the only possible way out of this mess is
485 * to skip through in case we find a match for a later channel..
486 */
487 for (rrp1=nextreq;rrp1;rrp1=rrp1->next)
488 if (rrp1->cip==cip)
489 break;
490
491 if (rrp1) {
492 /* OK, we found a match further down the chain. This means
493 * that something bad has happened to every request between
494 * the head of the list and the one we just found - send
495 * error responses.
496 *
497 * Note weird loop head: qr_result will free up requests from
498 * the list as it goes, so we can just keep picking off the first
499 * entry
500 */
f3c45977 501 for(rrp2=nextreq;rrp2;) {
25b7d0fa
P
502 if (rrp2==rrp1)
503 break;
504
505 Error("qrequest",ERR_WARNING,
506 "Lost response for channel %s; skipping.",
507 rrp2->cip->name->content);
508
0096e09a 509 qr_result(rrp2, QR_FAILED, 'X',
25b7d0fa 510 "Sorry, an error occurred while processing your request.");
f3c45977
P
511
512 rrp2 = nextreq = (who == QR_Q) ? nextreqq : nextreql;
25b7d0fa
P
513 }
514
515 if (rrp2) {
516 /* We seem to be back in sync. */
517 if (who == QR_L)
518 rlstate = QRLstate_AWAITINGUSER;
519 else
520 rqstate = QRLstate_AWAITINGUSER;
521
522 return;
523 }
524 /* Some form of hole in the space time continuum exists
525 * if we get here. Unclear how to proceed. */
526 return;
527 } else {
528 /* No match - let's just ignore this completely */
529 Error("qrequest",ERR_WARNING,
530 "Ignoring L/Q response for spurious channel %s",
531 cip->name->content);
532 return;
533 }
534 }
535 }
536 break;
537
538 case QRLstate_AWAITINGUSER:
539 if ((!ircd_strncmp(message, "End of chanlev",14) && who == QR_L) ||
540 (!ircd_strncmp(message, "End of list.",12) && who == QR_Q)) {
541 /* Oh dear, we got to the end of the chanlev in this state.
542 * This means that we didn't find the user.
543 */
0096e09a 544 qr_result(nextreq, QR_FAILED, 'X',
25b7d0fa
P
545 "Error: You are not known on %s.",
546 nextreq->cip->name->content);
547
548 /* need to reset nextreq .. just in case
549 * qr_result has cleaned up records */
550
551 nextreq = (who == QR_Q) ? nextreqq : nextreql;
552
553 if (nextreq) {
554 if (who == QR_L)
555 rlstate = QRLstate_AWAITINGUSER;
556 else
557 rqstate = QRLstate_AWAITINGUSER;
558 } else {
559 if (who == QR_L)
560 rlstate = QRLstate_IDLE;
561 else
562 rqstate = QRLstate_IDLE;
563 }
564
565 qr_nochanlev++;
566
567 return;
568 } else {
569 /* Brutalise the message :-) */
570
571 if (who == QR_Q) {
572 while (*message == ' ')
573 message++;
574 }
575
576 if (!(ch=strchr(message, ' ')))
577 return;
578
579 *ch++='\0';
580
581 if (!(np=getnickbynumeric(nextreq->reqnumeric)))
582 return;
583
584 if (ircd_strcmp(message, np->authname)) {
585 /* This is not the user you are looking for */
586 return;
587 }
25b7d0fa
P
588 /* Check for owner flag. Both branches of this if will
589 * take the request off the list, one way or the other. */
95440fe7
P
590
591 /* chop off any remaining words */
592 chop = ch;
593 while (*(chop++)) {
594 if (*chop != ' ' ) {
595 break;
596 }
597 }
598 /* chop off any remaining words */
599 ch = chop;
600 while (*(chop++)) {
601 if (*chop == ' ' || *chop == ':') {
602 *chop = '\0';
603 break;
604 }
605 }
606
607 if (strchr(ch, 'n')) {
0096e09a 608 char failcode;
25b7d0fa 609 /* They iz teh +n! */
25b7d0fa
P
610 /* Note: We're checking for blocks kind of late, so the request
611 system gets a chance to send other error messages first (like
612 'no chanstats', 'not known on channel', etc.). This is required
613 so that the user doesn't notice that he's being blocked. */
0096e09a
P
614 if (qr_checksize(nextreq->cip, nextreq->what, &failcode) && !qr_blockcheck(nextreq)) {
615 qr_result(nextreq, QR_OK, '-', "OK");
25b7d0fa 616 } else {
0096e09a
P
617 qr_result(nextreq, QR_FAILED, failcode,
618 "Error: Sorry, Your channel '%s' does not require %s. Please try again in a few days.", nextreq->cip->name->content, RQ_SNICK);
95440fe7 619
25b7d0fa
P
620 qr_toosmall++;
621 }
622 } else {
0096e09a 623 qr_result(nextreq, QR_FAILED, 'X',
25b7d0fa
P
624 "Error: You don't hold the +n flag on %s.",
625 nextreq->cip->name->content);
626
627 qr_notowner++;
628 }
629
630 /* OK, we found what we wanted so make sure we skip the rest */
631 if (who == QR_L)
632 rlstate = QRLstate_AWAITINGEND;
633 else
634 rqstate = QRLstate_AWAITINGEND;
635
636 return;
637 }
638 break;
639
640 case QRLstate_AWAITINGEND:
641 if (!ircd_strncmp(message, "End of chanlev",14) ||
642 !ircd_strncmp(message, "End of list.",12)) {
643 /* Found end of list */
644
645 if (nextreq) {
646 if (who == QR_L)
647 rlstate = QRLstate_AWAITINGCHAN;
648 else
649 rqstate = QRLstate_AWAITINGCHAN;
650 } else {
651 if (who == QR_L)
652 rlstate = QRLstate_IDLE;
653 else
654 rqstate = QRLstate_IDLE;
655 }
656
657 return;
658 }
659 break;
660 }
661 }
662}
663
664/*
665 * This function deals with requests from users for Q.
666 * Some sanity checks are made and the request is
667 * added to the queue.
668 */
669
670int qr_requestq(nick *rqnick, nick *sender, channel *cp, nick *lnick, nick *qnick) {
25b7d0fa
P
671 return RQ_UNKNOWN;
672}
673
674int qr_instantrequestq(nick *sender, channel *cp) {
675 requestrec *fakerequest;
676 chanfix *cf;
677 regop *ro;
678 int rocount, i;
0096e09a 679 char failcode;
25b7d0fa
P
680 regop *rolist[QR_TOPX];
681
0096e09a 682 if (!qr_checksize(cp->index, QR_CSERVE, &failcode))
25b7d0fa
P
683 return RQ_ERROR;
684
685 cf = cf_findchanfix(cp->index);
686
687 if (cf == NULL)
688 return RQ_ERROR;
689
690 rocount = cf_getsortedregops(cf, QR_TOPX, rolist);
691
692 ro = NULL;
693
694 for (i = 0; i < min(QR_TOPX, rocount); i++) {
695 if (cf_cmpregopnick(rolist[i], sender)) {
696 ro = rolist[i];
697 break;
698 }
699 }
700
701 /* not in top 5 - we don't have to worry about that error here
702 as the L request code will detect it again and send the user
703 an appropriate message */
704 if (ro == NULL)
705 return RQ_ERROR;
706
707 /* allocate a fake request */
708 fakerequest = (requestrec *)malloc(sizeof(requestrec));
709
710 fakerequest->reqnumeric = sender->numeric;
711 fakerequest->cip = cp->index;
712 fakerequest->what = QR_CSERVE;
713 fakerequest->who = QR_L; /* pretend that we asked L about the chanlev */
714
715 /* add it to the queue */
716 if (nextreql == NULL) {
717 fakerequest->next = NULL;
718 nextreql = fakerequest;
719 lastreql = fakerequest;
720 } else {
721 fakerequest->next = nextreql;
722 nextreql = fakerequest;
723 }
724
0096e09a 725 qr_result(fakerequest, QR_OK, '-', "OK");
25b7d0fa
P
726
727 return RQ_OK;
728}
729
95440fe7 730int qr_requests(nick *rqnick, nick *sender, channel *cp, nick *qnick) {
25b7d0fa 731 chanindex *cip = cp->index;
f011b15a 732 int who = 0;
25b7d0fa
P
733 requestrec *nextreq, *lastreq;
734
735 if (rq_isspam(sender)) {
736 sendnoticetouser(rqnick, sender, "Error: Do not flood the request system."
737 " Try again in %s.", rq_longtoduration(rq_blocktime(sender)));
738
739 return RQ_ERROR;
740 }
741
742 /* check which service is on the channel */
95440fe7 743 if (getnumerichandlefromchanhash(cp->users, qnick->numeric) != NULL) {
25b7d0fa
P
744 /* we've found Q */
745 who = QR_Q;
746
747 /* Request stats from Q */
748 sendmessagetouser(rqnick, qnick, "CHANLEV %s", cip->name->content);
749
750 if (rqstate == QRLstate_IDLE)
751 rqstate = QRLstate_AWAITINGCHAN;
752 } /* 'else' cannot happen as R has already checked whether the user has L or Q */
753
95440fe7
P
754 lastreq = lastreqq;
755 nextreq = nextreqq;
25b7d0fa
P
756
757 /* Sort out a request record */
758 if (lastreq) {
759 lastreq->next = (requestrec *)malloc(sizeof(requestrec));
760 lastreq=lastreq->next;
761 } else {
762 lastreq=nextreq=(requestrec *)malloc(sizeof(requestrec));
763 }
764
765 lastreq->next = NULL;
766 lastreq->cip = cip;
767 lastreq->what = QR_SPAMSCAN;
768 lastreq->reqnumeric = sender->numeric;
769
95440fe7
P
770 nextreqq = nextreq;
771 lastreqq = lastreq;
25b7d0fa 772
95440fe7 773 sendnoticetouser(rqnick, sender,
25b7d0fa
P
774 "Checking your %s access. "
775 "This may take a while, please be patient...",
95440fe7 776 RQ_QNICK);
25b7d0fa
P
777
778 return RQ_UNKNOWN;
779}
780
781void qr_initrequest(void) {
782 nextreql=lastreql=NULL;
783 nextreqq=lastreqq=NULL;
784 nextqreq=lastqreq=NULL;
785}
786
787void qr_finirequest(void) {
788 struct requestrec *rp;
789
790 while (nextreqq) {
791 rp=nextreqq;
792 nextreqq=nextreqq->next;
793 free(rp);
794 }
795
796 while (nextreql) {
797 rp=nextreql;
798 nextreql=nextreql->next;
799 free(rp);
800 }
801
802 while (nextqreq) {
803 rp=nextqreq;
804 nextqreq=nextqreq->next;
805 free(rp);
806 }
807}
808
809void qr_requeststats(nick *rqnick, nick *np) {
95440fe7
P
810 sendnoticetouser(rqnick, np, "- Suspended (S): %d", qr_suspended);
811 sendnoticetouser(rqnick, np, "- No chanstats (S): %d", qr_nohist);
812 sendnoticetouser(rqnick, np, "- Too small (S): %d", qr_toosmall);
813 sendnoticetouser(rqnick, np, "- User was not on chanlev (S): %d", qr_nochanlev);
814 sendnoticetouser(rqnick, np, "- User was not the owner (S): %d", qr_notowner);
0096e09a
P
815 sendnoticetouser(rqnick, np, "- A: %d", qr_a);
816 sendnoticetouser(rqnick, np, "- B: %d", qr_b);
817 sendnoticetouser(rqnick, np, "- C: %d", qr_c);
818 sendnoticetouser(rqnick, np, "- D: %d", qr_d);
819 sendnoticetouser(rqnick, np, "- E: %d", qr_e);
820
25b7d0fa 821}