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