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