]> jfr.im git - irc/quakenet/newserv.git/blob - request/sqrequest.c
r592@blue (orig r482): cruicky | 2006-05-04 15:00:58 +0100
[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
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <string.h>
20
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" */
25
26 #define QR_FAILED 0x0
27 #define QR_OK 0x1
28
29 #define QR_CSERVE 0x0
30 #define QR_SPAMSCAN 0x1
31
32 #define QR_L 0x0
33 #define QR_Q 0x1
34
35 #define min(a,b) ((a > b) ? b : a)
36
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;
43 } requestrec;
44
45 requestrec *nextreql, *lastreql;
46 requestrec *nextreqq, *lastreqq;
47
48
49 requestrec *nextqreq, *lastqreq;
50
51 extern nick *rqnick;
52 int rlstate;
53 int rqstate;
54
55 /* stats counters */
56 int qr_suspended = 0;
57 int qr_nohist = 0;
58 int qr_toosmall = 0;
59 int qr_nochanlev = 0;
60 int qr_notowner = 0;
61
62 /* Check whether the user is blocked */
63 int qr_blockcheck(requestrec *req) {
64 nick *np;
65 rq_block *block;
66
67 np = getnickbynumeric(req->reqnumeric);
68
69 /* user is not online anymore */
70 if (np == NULL)
71 return 0;
72
73 block = rq_findblock(np->authname);
74
75 if (block != NULL)
76 return 1; /* user is blocked */
77 else
78 return 0;
79 }
80
81 unsigned int rq_countchanusers(channel *cp) {
82 int i, count=0;
83
84 for (i=0;i<cp->users->hashsize;i++) {
85 if (cp->users->content[i]==nouser)
86 continue;
87
88 count++;
89 }
90
91 return count;
92 }
93
94 /*
95 * Deal with outcome of a queued request. The request should be freed
96 * as part of the process.
97 */
98
99 void qr_result(requestrec *req, int outcome, char *message, ...) {
100 sstring *user, *password;
101 requestrec **rh;
102 char msgbuf[512];
103 va_list va;
104 channel *cplog;
105 nick *lnp, *qnp, *np, *tnp, *snp;
106 char now[50];
107 time_t now_ts;
108 unsigned int unique, total;
109
110 /* Delete the request from the list first.. */
111 for (rh=&nextreql;*rh;rh=&((*rh)->next)) {
112 if (*rh==req) {
113 *rh=req->next;
114 break;
115 }
116 }
117
118 for (rh=&nextreqq;*rh;rh=&((*rh)->next)) {
119 if (*rh==req) {
120 *rh=req->next;
121 break;
122 }
123 }
124
125 /* If this was the last request (unlikely),
126 * we need to fix the last pointer */
127 if (lastreql==req) {
128 if (nextreql)
129 for (lastreql=nextreql;lastreql->next;lastreql=lastreql->next)
130 ; /* empty loop */
131 else
132 lastreql=NULL;
133 }
134
135 if (lastreqq==req) {
136 if (nextreqq)
137 for (lastreqq=nextreqq;lastreqq->next;lastreqq=lastreqq->next)
138 ; /* empty loop */
139 else
140 lastreqq=NULL;
141 }
142
143 /* Check that the nick is still here. If not, drop the request. */
144 if (!(tnp=np=getnickbynumeric(req->reqnumeric))) {
145 free(req);
146 return;
147 }
148
149 if (rq_logfd != NULL) {
150 now[0] = '\0';
151 now_ts = time(NULL);
152
153 if (req->cip->channel) {
154 unique = countuniquehosts(req->cip->channel);
155 total = rq_countchanusers(req->cip->channel);
156 } else {
157 unique = 0;
158 total = 0;
159 }
160
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");
167 fflush(rq_logfd);
168 }
169
170 if (outcome==QR_OK) {
171 if (req->what == QR_CSERVE) {
172 /* Delete L, add Q. Check that they both exist first, though. */
173
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);
178 free(req);
179 return;
180 }
181
182 /* /msg Q ADDCHAN <channel> <flags> <owners nick> <channeltype> */
183 sendmessagetouser(rqnick, qnp, "ADDCHAN %s +ap #%s upgrade",
184 req->cip->name->content,
185 np->authname);
186
187 sendnoticetouser(rqnick, tnp, "Adding %s to channel, please wait...",
188 RQ_QNICK);
189 } else if (req->what == QR_SPAMSCAN) {
190 /* Add S */
191
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);
196
197 free(req);
198 return;
199 }
200
201 sendnoticetouser(rqnick, tnp, "Requirements met, %s should be added. "
202 "Contact #help should further assistance be required.",
203 RQ_SNICK);
204
205 /* auth */
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);
209 freesstring(user);
210 freesstring(password);
211
212 /* /msg S addchan <channel> default */
213 sendmessagetouser(rqnick, snp, "ADDCHAN %s default +op", req->cip->name->content);
214
215 /* we do not put the request into another queue, so free it here */
216 free(req);
217
218 return;
219 }
220
221 if (lastqreq)
222 lastqreq->next=req;
223 else
224 lastqreq=nextqreq=req;
225
226 req->next=NULL;
227
228 rq_success++;
229
230 /* Don't free, it's in new queue now */
231 } else {
232 /* Sort out the message.. */
233 va_start(va, message);
234 vsnprintf(msgbuf,511,message,va);
235 va_end(va);
236
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.");*/
240 free(req);
241
242 rq_failed++;
243 }
244 }
245
246 /*
247 * qr_checksize:
248 * Checks that a channel is beeeeg enough for teh Q
249 */
250
251 int qr_checksize(chanindex *cip, int what) {
252 chanstats *csp;
253 channel *cp;
254 nick *np, *qbot;
255 int i , avg, tot=0, authedcount=0, count=0, uniquecount, avgcount;
256
257 cp = cip->channel;
258
259 if (cp == NULL)
260 return 0; /* this shouldn't ever happen */
261
262 #if QR_DEBUG
263 return 1;
264 #endif
265
266 /* make sure we can actually add Q */
267 if (what == QR_CSERVE) {
268 qbot = getnickbynick(RQ_QNICK);
269
270 if (!qbot)
271 return 0;
272
273 if (QR_MAXQCHANS != 0 && qbot->channels->cursi > QR_MAXQCHANS)
274 return 0; /* no Q for you :p */
275 }
276
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]);
281
282 if (IsAccount(np))
283 authedcount++;
284
285 count++;
286 }
287 }
288
289 if (authedcount * 100 / count < ((what == QR_CSERVE) ? QR_AUTHEDPCT_CSERVE : QR_AUTHEDPCT_SPAMSCAN))
290 return 0; /* too few authed users */
291
292 if (!(csp=cip->exts[csext]))
293 return 0;
294
295 for (i=0;i<HISTORYDAYS;i++) {
296 tot += csp->lastdays[i];
297 }
298
299 uniquecount = countuniquehosts(cp);
300 avgcount = tot / HISTORYDAYS / 10;
301
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))
306 return 0;
307
308 avg = (what == QR_CSERVE) ? QR_REQUIREDSIZE_CSERVE : QR_REQUIREDSIZE_SPAMSCAN;
309
310 if (tot > (avg * 140))
311 return 1;
312 else
313 return 0;
314 }
315
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.
319 *
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.
326 */
327
328 void qr_handlenotice(nick *sender, char *message) {
329 char *ch, *chop;
330 chanindex *cip;
331 requestrec *rrp1, *rrp2;
332 nick *np;
333 int delrequest = 0, state, who;
334 requestrec *nextreq;
335 channel *logcp;
336
337 /* logcp = findchannel("#qnet.request");
338
339 if (logcp)
340 sendmessagetochannel(rqnick, logcp, "%s: %s - %d %d %x %x", sender->nick, message, rlstate, rqstate, nextreql, nextreqq);
341 */
342 if (!ircd_strcmp(sender->nick, RQ_QNICK) && nextqreq) {
343 /* Message from Q */
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. */
348
349 if ((np=getnickbynick(RQ_LNICK))) {
350 sendmessagetouser(rqnick, np, "SENDCHANLEV %s %s",
351 nextqreq->cip->name->content, RQ_QNICK);
352
353 sendmessagetouser(rqnick, np, "DELCHAN %s",
354 nextqreq->cip->name->content);
355 }
356
357 if ((np=getnickbynumeric(nextqreq->reqnumeric))) {
358 sendnoticetouser(rqnick, np, "Request completed. %s added.", RQ_QNICK);
359 }
360
361 delrequest = 1;
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);
367
368 qr_suspended++;
369
370 delrequest = 1;
371 }
372 }
373
374 /* For either of the two messages above we want to delete the request
375 * at the head of the queue. */
376 if (delrequest) {
377 rrp1=nextqreq;
378
379 nextqreq=nextqreq->next;
380 if (!nextqreq)
381 lastqreq=NULL;
382
383 free(rrp1);
384 }
385 }
386
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;
391
392 /* Message from L or Q */
393 switch (state) {
394 case QRLstate_IDLE:
395 /* We're idle, do nothing */
396 return;
397
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)
402 ) {
403 /* Looks like the right message. Let's find a channel name */
404
405 for (ch=message;*ch;ch++)
406 if (*ch=='#')
407 break;
408
409 if (!*ch) {
410 Error("qrequest",ERR_WARNING,
411 "Unable to parse channel name from L/Q message: %s",message);
412 return;
413 }
414
415 /* chop off any remaining words */
416 chop = ch;
417 while (*(chop++)) {
418 if (*chop == ' ') {
419 *chop = '\0';
420 break;
421 }
422 }
423
424 if (!(cip=findchanindex(ch))) {
425 Error("qrequest",ERR_WARNING,
426 "Unable to find channel from L/Q message: %s",ch);
427 return;
428 }
429
430 if (cip==nextreq->cip) {
431 /* Ok, this is the correct channel, everything is proceeding
432 * exactly as I had forseen */
433 if (who == QR_L)
434 rlstate = QRLstate_AWAITINGUSER;
435 else
436 rqstate = QRLstate_AWAITINGUSER;
437
438 return;
439 } else {
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..
443 */
444 for (rrp1=nextreq;rrp1;rrp1=rrp1->next)
445 if (rrp1->cip==cip)
446 break;
447
448 if (rrp1) {
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
452 * error responses.
453 *
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
456 * entry
457 */
458 for(rrp2=nextreq;rrp2;) {
459 if (rrp2==rrp1)
460 break;
461
462 Error("qrequest",ERR_WARNING,
463 "Lost response for channel %s; skipping.",
464 rrp2->cip->name->content);
465
466 qr_result(rrp2, QR_FAILED,
467 "Sorry, an error occurred while processing your request.");
468
469 rrp2 = nextreq = (who == QR_Q) ? nextreqq : nextreql;
470 }
471
472 if (rrp2) {
473 /* We seem to be back in sync. */
474 if (who == QR_L)
475 rlstate = QRLstate_AWAITINGUSER;
476 else
477 rqstate = QRLstate_AWAITINGUSER;
478
479 return;
480 }
481 /* Some form of hole in the space time continuum exists
482 * if we get here. Unclear how to proceed. */
483 return;
484 } else {
485 /* No match - let's just ignore this completely */
486 Error("qrequest",ERR_WARNING,
487 "Ignoring L/Q response for spurious channel %s",
488 cip->name->content);
489 return;
490 }
491 }
492 }
493 break;
494
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.
500 */
501
502 qr_result(nextreq, QR_FAILED,
503 "Error: You are not known on %s.",
504 nextreq->cip->name->content);
505
506 /* need to reset nextreq .. just in case
507 * qr_result has cleaned up records */
508
509 nextreq = (who == QR_Q) ? nextreqq : nextreql;
510
511 if (nextreq) {
512 if (who == QR_L)
513 rlstate = QRLstate_AWAITINGUSER;
514 else
515 rqstate = QRLstate_AWAITINGUSER;
516 } else {
517 if (who == QR_L)
518 rlstate = QRLstate_IDLE;
519 else
520 rqstate = QRLstate_IDLE;
521 }
522
523 qr_nochanlev++;
524
525 return;
526 } else {
527 /* Brutalise the message :-) */
528
529 if (who == QR_Q) {
530 while (*message == ' ')
531 message++;
532 }
533
534 if (!(ch=strchr(message, ' ')))
535 return;
536
537 *ch++='\0';
538
539 if (!(np=getnickbynumeric(nextreq->reqnumeric)))
540 return;
541
542 if (ircd_strcmp(message, np->authname)) {
543 /* This is not the user you are looking for */
544 return;
545 }
546
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! */
551
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");
558 } else {
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);
563 } else {
564 qr_result(nextreq, QR_FAILED,
565 "Error: Your channel does not require %s. "
566 "Try again later.", RQ_SNICK);
567 }
568
569 qr_toosmall++;
570 }
571 } else {
572 qr_result(nextreq, QR_FAILED,
573 "Error: You don't hold the +n flag on %s.",
574 nextreq->cip->name->content);
575
576 qr_notowner++;
577 }
578
579 /* OK, we found what we wanted so make sure we skip the rest */
580 if (who == QR_L)
581 rlstate = QRLstate_AWAITINGEND;
582 else
583 rqstate = QRLstate_AWAITINGEND;
584
585 return;
586 }
587 break;
588
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 */
593
594 if (nextreq) {
595 if (who == QR_L)
596 rlstate = QRLstate_AWAITINGCHAN;
597 else
598 rqstate = QRLstate_AWAITINGCHAN;
599 } else {
600 if (who == QR_L)
601 rlstate = QRLstate_IDLE;
602 else
603 rqstate = QRLstate_IDLE;
604 }
605
606 return;
607 }
608 break;
609 }
610 }
611 }
612
613 /*
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.
617 */
618
619 int qr_requestq(nick *rqnick, nick *sender, channel *cp, nick *lnick, nick *qnick) {
620 chanindex *cip = cp->index;
621
622 /* Check:
623 * - we have some form of channel stats for the channel
624 *
625 * Note that the actual channel stats will not be checked
626 * until we're sure the user has +n on the channel.
627 */
628
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)));
632
633 return RQ_ERROR;
634 }
635
636 if (!cip->exts[csext]) {
637 sendnoticetouser(rqnick, sender,
638 "Error: No historical record exists for %s.",
639 cip->name->content);
640
641 qr_nohist++;
642
643 return RQ_ERROR;
644 }
645
646 /* Request stats from L */
647 sendmessagetouser(rqnick, lnick, "CHANLEV %s", cip->name->content);
648
649 /* Sort out a request record */
650 if (lastreql) {
651 lastreql->next = (requestrec *)malloc(sizeof(requestrec));
652 lastreql=lastreql->next;
653 } else {
654 lastreql=nextreql=(requestrec *)malloc(sizeof(requestrec));
655 }
656
657 lastreql->next = NULL;
658 lastreql->cip = cip;
659 lastreql->what = QR_CSERVE;
660 lastreql->who = QR_L;
661 lastreql->reqnumeric = sender->numeric;
662
663 if (rlstate == QRLstate_IDLE)
664 rlstate = QRLstate_AWAITINGCHAN;
665
666 sendnoticetouser(rqnick, sender,
667 "Checking your %s access. "
668 "This may take a while, please be patient...", RQ_LNICK);
669
670 /* we don't know yet whether the request was successful */
671 return RQ_UNKNOWN;
672 }
673
674 int qr_instantrequestq(nick *sender, channel *cp) {
675 requestrec *fakerequest;
676 chanfix *cf;
677 regop *ro;
678 int rocount, i;
679 regop *rolist[QR_TOPX];
680
681 if (!qr_checksize(cp->index, QR_CSERVE))
682 return RQ_ERROR;
683
684 cf = cf_findchanfix(cp->index);
685
686 if (cf == NULL)
687 return RQ_ERROR;
688
689 rocount = cf_getsortedregops(cf, QR_TOPX, rolist);
690
691 ro = NULL;
692
693 for (i = 0; i < min(QR_TOPX, rocount); i++) {
694 if (cf_cmpregopnick(rolist[i], sender)) {
695 ro = rolist[i];
696 break;
697 }
698 }
699
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 */
703 if (ro == NULL)
704 return RQ_ERROR;
705
706 /* allocate a fake request */
707 fakerequest = (requestrec *)malloc(sizeof(requestrec));
708
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 */
713
714 /* add it to the queue */
715 if (nextreql == NULL) {
716 fakerequest->next = NULL;
717 nextreql = fakerequest;
718 lastreql = fakerequest;
719 } else {
720 fakerequest->next = nextreql;
721 nextreql = fakerequest;
722 }
723
724 qr_result(fakerequest, QR_OK, "OK");
725
726 return RQ_OK;
727 }
728
729 int qr_requests(nick *rqnick, nick *sender, channel *cp, nick *lnick, nick *qnick) {
730 chanindex *cip = cp->index;
731 int who;
732 requestrec *nextreq, *lastreq;
733
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)));
737
738 return RQ_ERROR;
739 }
740
741 /* check which service is on the channel */
742 if (getnumerichandlefromchanhash(cp->users, lnick->numeric) != NULL) {
743 /* we've found L */
744 who = QR_L;
745
746 /* Request stats from L */
747 sendmessagetouser(rqnick, lnick, "CHANLEV %s", cip->name->content);
748
749 if (rlstate == QRLstate_IDLE)
750 rlstate = QRLstate_AWAITINGCHAN;
751 } else if (getnumerichandlefromchanhash(cp->users, qnick->numeric) != NULL) {
752 /* we've found Q */
753 who = QR_Q;
754
755 /* Request stats from Q */
756 sendmessagetouser(rqnick, qnick, "CHANLEV %s", cip->name->content);
757
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 */
761
762 lastreq = (who == QR_Q) ? lastreqq : lastreql;
763 nextreq = (who == QR_Q) ? nextreqq : nextreql;
764
765 /* Sort out a request record */
766 if (lastreq) {
767 lastreq->next = (requestrec *)malloc(sizeof(requestrec));
768 lastreq=lastreq->next;
769 } else {
770 lastreq=nextreq=(requestrec *)malloc(sizeof(requestrec));
771 }
772
773 lastreq->next = NULL;
774 lastreq->cip = cip;
775 lastreq->what = QR_SPAMSCAN;
776 lastreq->reqnumeric = sender->numeric;
777
778 if (who == QR_Q) {
779 nextreqq = nextreq;
780 lastreqq = lastreq;
781 } else {
782 nextreql = nextreq;
783 lastreql = lastreq;
784 }
785
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);
790
791 return RQ_UNKNOWN;
792 }
793
794 void qr_initrequest(void) {
795 nextreql=lastreql=NULL;
796 nextreqq=lastreqq=NULL;
797 nextqreq=lastqreq=NULL;
798 }
799
800 void qr_finirequest(void) {
801 struct requestrec *rp;
802
803 while (nextreqq) {
804 rp=nextreqq;
805 nextreqq=nextreqq->next;
806 free(rp);
807 }
808
809 while (nextreql) {
810 rp=nextreql;
811 nextreql=nextreql->next;
812 free(rp);
813 }
814
815 while (nextqreq) {
816 rp=nextqreq;
817 nextqreq=nextqreq->next;
818 free(rp);
819 }
820 }
821
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);
828 }