]>
jfr.im git - irc/quakenet/newserv.git/blob - qrequest/qrequest.c
4 * Depends on "chanstats"
7 #include "../nick/nick.h"
8 #include "../channel/channel.h"
9 #include "../chanstats/chanstats.h"
10 #include "../localuser/localuser.h"
11 #include "../lib/irc_string.h"
12 #include "../core/schedule.h"
19 #define QR_user "qrequest"
20 #define QR_host "qrequest.quakenet.org"
26 #define QRLstate_IDLE 0x0 /* No request active */
27 #define QRLstate_AWAITINGCHAN 0x1 /* Awaiting "Users for channel.." */
28 #define QRLstate_AWAITINGUSER 0x2 /* Looking for our user in the list */
29 #define QRLstate_AWAITINGEND 0x3 /* Waiting for "End of chanlev" */
34 #define QREQUIREDSIZE 50
36 typedef struct requestrec
{
37 unsigned int reqnumeric
; /* Who made the request */
38 unsigned int tellnumeric
; /* Who we are talking to about the request */
39 chanindex
*cip
; /* Which channel the request is for */
40 struct requestrec
*next
;
43 requestrec
*nextreq
, *lastreq
;
44 requestrec
*nextqreq
, *lastqreq
;
49 void qr_handler(nick
*me
, int type
, void **args
);
51 void qr_registeruser(void *arg
) {
52 qr_np
=registerlocaluser(QR_nick
, QR_user
, QR_host
, "Q Request 0.01",
53 QR_acct
, UMODE_ACCOUNT
|UMODE_OPER
, qr_handler
);
57 * Deal with outcome of a queued request. The request should be freed
58 * as part of the process.
61 void qr_result(requestrec
*req
, int outcome
, char *message
, ...) {
65 nick
*lnp
, *qnp
, *np
, *tnp
;
67 /* Delete the request from the list first.. */
68 for (rh
=&nextreq
;*rh
;rh
=&((*rh
)->next
)) {
75 /* If this was the last request (unlikely),
76 * we need to fix the last pointer */
79 for (lastreq
=nextreq
;lastreq
->next
;lastreq
=lastreq
->next
)
85 /* Check that the nick is still here. If not, drop the request. */
86 if (!(np
=getnickbynumeric(req
->reqnumeric
)) ||
87 !(tnp
=getnickbynumeric(req
->tellnumeric
))) {
93 /* Delete L, add Q. Check that they both exist first, though. */
95 if (!(lnp
=getnickbynick(L_nick
)) || !(qnp
=getnickbynick(Q_nick
))) {
96 sendnoticetouser(qr_np
, tnp
,
97 "Sorry, cannot find Q and L on the network. "
98 "Please request again later.");
103 /* /msg Q ADDCHAN <channel> <flags> <owners nick> <channeltype> */
104 sendmessagetouser(qr_np
, qnp
, "ADDCHAN %s +ap #%s upgrade",
105 req
->cip
->name
->content
,
108 sendnoticetouser(qr_np
, tnp
, "Adding Q to channel, please wait...");
113 lastqreq
=nextqreq
=req
;
117 /* Don't free, it's in new queue now */
119 /* Sort out the message.. */
120 va_start(va
, message
);
121 vsnprintf(msgbuf
,511,message
,va
);
124 sendnoticetouser(qr_np
, tnp
, "%s", msgbuf
);
125 /* This is a failure message. Add disclaimer. */
126 sendnoticetouser(qr_np
, tnp
, "Please do not complain about this result.");
133 * Checks that a channel is beeeeg enough for teh Q
136 int qr_checksize(chanindex
*cip
) {
140 if (!(csp
=cip
->exts
[csext
]))
143 for (i
=0;i
<HISTORYDAYS
;i
++) {
144 tot
+= csp
->lastdays
[i
];
147 if (tot
> (QREQUIREDSIZE
* 140))
153 /* This function deals with notices from L: basically we track the
154 * responses to the L chanlev requests we've been making until we can
155 * decide what to do with the requests.
157 * Here's the L chanlev format:
158 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Users for channel #twilightzone
159 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Authname Access flags
160 * 11:12 -L(TheLBot@lightweight.quakenet.org)- -----------------------------
161 * 11:12 -L(TheLBot@lightweight.quakenet.org)- Bigfoot amno
162 * 11:12 -L(TheLBot@lightweight.quakenet.org)- End of chanlev for #twilightzone.
165 void qr_handlenotice(nick
*sender
, char *message
) {
168 requestrec
*rrp1
, *rrp2
;
171 if (!ircd_strcmp(sender
->nick
, Q_nick
)) {
174 /* ERROR ERROR ERROR */
178 if (!ircd_strcmp(message
,"Done.")) {
179 /* Q added the channel: delete from L and tell the user. */
180 /* If L has conspired to vanish between the request and the outcome,
181 * we have a chan with Q and L... too bad. */
183 if ((np
=getnickbynick(L_nick
))) {
184 sendmessagetouser(qr_np
, np
, "SENDCHANLEV %s %s",
185 nextqreq
->cip
->name
->content
, Q_nick
);
187 sendmessagetouser(qr_np
, np
, "DELCHAN %s",
188 nextqreq
->cip
->name
->content
);
191 if ((np
=getnickbynumeric(nextqreq
->tellnumeric
))) {
192 sendnoticetouser(qr_np
, np
, "Request completed. Q added and L deleted.");
194 } else if (!ircd_strcmp(message
,"That channel already exists.")) {
195 if ((np
=getnickbynumeric(nextqreq
->tellnumeric
))) {
196 sendnoticetouser(qr_np
, np
,
197 "Your channel appears to have Q already "
198 "(it may be suspended).");
204 /* For either of the two messages above we want to delete the request
205 * at the head of the queue. */
208 nextqreq
=nextqreq
->next
;
213 } else if (!ircd_strcmp(sender
->nick
, L_nick
)) {
217 /* We're idle, do nothing */
220 case QRLstate_AWAITINGCHAN
:
221 /* We're waiting for conformation of the channel name */
222 if (!ircd_strncmp(message
,"Users for",9)) {
223 /* Looks like the right message. Let's find a channel name */
225 for (ch
=message
;*ch
;ch
++)
230 Error("qrequest",ERR_WARNING
,
231 "Unable to parse channel name from L message: %s",message
);
235 if (!(cip
=findchanindex(ch
))) {
236 Error("qrequest",ERR_WARNING
,
237 "Unable to find channel from L message: %s",ch
);
241 if (cip
==nextreq
->cip
) {
242 /* Ok, this is the correct channel, everything is proceeding
243 * exactly as I had forseen */
244 qrlstate
= QRLstate_AWAITINGUSER
;
247 /* Uh-oh, not the channel we wanted. Something is fucked
248 * here. I think the only possible way out of this mess is
249 * to skip through in case we find a match for a later channel..
251 for (rrp1
=nextreq
;rrp1
;rrp1
=rrp1
->next
)
256 /* OK, we found a match further down the chain. This means
257 * that something bad has happened to every request between
258 * the head of the list and the one we just found - send
261 * Note weird loop head: qr_result will free up requests from
262 * the list as it goes, so we can just keep picking off the first
265 for(rrp2
=nextreq
;rrp2
;rrp2
=nextreq
) {
269 Error("qrequest",ERR_WARNING
,
270 "Lost response for channel %s; skipping.",
271 rrp2
->cip
->name
->content
);
273 qr_result(rrp2
, QR_FAILED
,
274 "Sorry, an error occurred while processing your request.");
278 /* We seem to be back in sync. */
279 qrlstate
=QRLstate_AWAITINGUSER
;
282 /* Some form of hole in the space time continuum exists
283 * if we get here. Unclear how to proceed. */
286 /* No match - let's just ignore this completely */
287 Error("qrequest",ERR_WARNING
,
288 "Ignoring L response for spurious channel %s",
296 case QRLstate_AWAITINGUSER
:
297 if (!ircd_strncmp(message
, "End of chanlev",14)) {
298 /* Oh dear, we got to the end of the chanlev in this state.
299 * This means that we didn't find the user.
302 qr_result(nextreq
, QR_FAILED
,
303 "Sorry, you are not known on %s.",
304 nextreq
->cip
->name
->content
);
307 qrlstate
=QRLstate_AWAITINGCHAN
;
309 qrlstate
=QRLstate_IDLE
;
313 /* Brutalise the message :-) */
315 if (!(ch
=strchr(message
, ' ')))
320 if (!(np
=getnickbynumeric(nextreq
->reqnumeric
)))
323 if (ircd_strcmp(message
, np
->authname
)) {
324 /* This is not the user you are looking for */
328 /* Check for owner flag. Both branches of this if will
329 * take the request off the list, one way or the other. */
330 if (strchr(ch
, 'n')) {
331 /* They iz teh +n! */
332 if (qr_checksize(nextreq
->cip
)) {
333 qr_result(nextreq
, QR_OK
, "OK");
335 qr_result(nextreq
, QR_FAILED
,
336 "Sorry, your channel is not large enough to request Q. Please continue to use L instead.");
339 qr_result(nextreq
, QR_FAILED
,
340 "Sorry, you don't hold the +n flag on %s.",
341 nextreq
->cip
->name
->content
);
344 /* OK, we found what we wanted so make sure we skip the rest */
345 qrlstate
=QRLstate_AWAITINGEND
;
351 case QRLstate_AWAITINGEND
:
352 if (!ircd_strncmp(message
, "End of chanlev",14)) {
353 /* Found end of list */
356 qrlstate
=QRLstate_AWAITINGCHAN
;
358 qrlstate
=QRLstate_IDLE
;
368 * This function deals with requests from users for Q.
369 * Some sanity checks are made (on channel, opped) and the
370 * request is added to the queue.
373 void qr_handlemsg(nick
*sender
, char *message
) {
380 if (!ircd_strncmp(message
,"requestq ",9)) {
381 /* Looks like a sensible request. */
382 if (!(ch
=strchr(message
,'#'))) {
383 sendnoticetouser(qr_np
, sender
,
384 "Usage: requestq #channel");
388 /* If an oper is sending the request, allow them to specify
389 * a second parameter indicating which user they are making the
390 * request on behalf of. All status messages will be sent to the
391 * oper issuing "requestq", but the move will be done on behalf of
394 if (IsOper(sender
) && (ch2
=strchr(ch
,' '))) {
396 if (!(requester
=getnickbynick(ch2
))) {
397 sendnoticetouser(qr_np
,sender
,"Can't find user: %s",ch2
);
409 * - L is on the channel
410 * - user is on the channel
411 * - user is opped on the channel
412 * - we have some form of channel stats for the channel
414 * Note that the actual channel stats will not be checked
415 * until we're sure the user has +n on the channel.
418 if (!IsAccount(requester
)) {
419 sendnoticetouser(qr_np
, sender
,
420 "Sorry, you must be authed to make a request.");
424 if (!(cip
=findchanindex(ch
)) || !cip
->channel
) {
425 sendnoticetouser(qr_np
, sender
, "Unable to find channel %s.",ch
);
429 if (!(lnp
=getnickbynick(L_nick
))) {
430 sendnoticetouser(qr_np
, sender
,
431 "Can't find L on the network, please try later.");
435 if (!getnickbynick(Q_nick
)) {
436 sendnoticetouser(qr_np
, sender
,
437 "Can't find Q on the network, please try later.");
441 if (!getnumerichandlefromchanhash(cip
->channel
->users
, lnp
->numeric
)) {
442 sendnoticetouser(qr_np
, sender
,
443 "L is not on %s.", cip
->name
->content
);
447 if (!(lp
=getnumerichandlefromchanhash(cip
->channel
->users
,
448 requester
->numeric
))) {
449 sendnoticetouser(qr_np
, sender
,
450 "You are not on %s.", cip
->name
->content
);
454 if (!(*lp
& CUMODE_OP
)) {
455 sendnoticetouser(qr_np
, sender
,
456 "You are not opped on %s.", cip
->name
->content
);
460 if (!cip
->exts
[csext
]) {
461 sendnoticetouser(qr_np
, sender
,
462 "Sorry, no historical record exists for %s.",
467 /* Request stats from L */
468 sendmessagetouser(qr_np
, lnp
, "CHANLEV %s", cip
->name
->content
);
470 /* Sort out a request record */
472 lastreq
->next
= (requestrec
*)malloc(sizeof(requestrec
));
473 lastreq
=lastreq
->next
;
475 lastreq
=nextreq
=(requestrec
*)malloc(sizeof(requestrec
));
478 lastreq
->next
= NULL
;
480 lastreq
->reqnumeric
= requester
->numeric
;
481 lastreq
->tellnumeric
= sender
->numeric
;
483 if (qrlstate
== QRLstate_IDLE
)
484 qrlstate
= QRLstate_AWAITINGCHAN
;
486 sendnoticetouser(qr_np
, sender
,
487 "Checking your L access. "
488 "This may take a while, please be patient...");
492 void qr_handler(nick
*me
, int type
, void **args
) {
497 scheduleoneshot(time(NULL
)+1, qr_registeruser
, NULL
);
501 qr_handlenotice(args
[0], args
[1]);
505 qr_handlemsg(args
[0], args
[1]);
511 nextreq
=lastreq
=NULL
;
512 nextqreq
=lastqreq
=NULL
;
514 qr_registeruser(NULL
);
518 struct requestrec
*rp
;
522 nextreq
=nextreq
->next
;
528 nextqreq
=nextqreq
->next
;
533 deregisterlocaluser(qr_np
, NULL
);
535 deleteallschedules(qr_registeruser
);