]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservnetevents.c
r729@blue (orig r504): slug | 2006-06-09 14:02:53 +0100
[irc/quakenet/newserv.git] / chanserv / chanservnetevents.c
1 /*
2 * chanservnetevents.c:
3 * Handles the bot reaction to network events (joins, parts, mode changes
4 * etc.)
5 */
6
7 #include "chanserv.h"
8
9 #include "../channel/channel.h"
10 #include "../nick/nick.h"
11 #include "../localuser/localuser.h"
12 #include "../localuser/localuserchannel.h"
13
14 #include <stdio.h>
15
16 /* cs_handlenick:
17 * This is for HOOK_NICK_NEWNICK and HOOK_NICK_ACCOUNT.
18 * Associate the nick with it's correct account.
19 */
20
21 void cs_handlenick(int hooknum, void *arg) {
22 nick *np=(nick *)arg;
23
24 cs_checknick(np);
25 }
26
27 void cs_handlesethost(int hooknum, void *arg) {
28 nick *np=arg;
29
30 cs_checknickbans(np);
31 }
32
33 void cs_handlelostnick(int hooknum, void *arg) {
34 nick *np=(nick *)arg;
35 nicklist **nlh;
36 nicklist *nlp;
37 reguser *rup;
38
39 if ((rup=getreguserfromnick(np))) {
40 for (nlh=&(rup->nicks);*nlh;nlh=&((*nlh)->next)) {
41 if ((*nlh)->np==np) {
42 nlp=*nlh;
43 *nlh=nlp->next;
44 freenicklist(nlp);
45 break;
46 }
47 }
48 if ((rup->status & QUSTAT_DEAD) && !rup->nicks) {
49 freereguser(rup);
50 }
51 }
52
53 if (getactiveuserfromnick(np))
54 freeactiveuser(getactiveuserfromnick(np));
55 }
56
57 /*
58 * cs_handlenewchannel:
59 * This is for the HOOK_CHANNEL_NEWCHANNEL message.
60 * A new channel has just been created on the network, associate
61 * with the registered channel (if one exists) unless it's suspended.
62 */
63
64 void cs_handlenewchannel(int hooknum, void *arg) {
65 channel *cp=(channel *)arg;
66 regchan *rcp;
67
68 /* Get the registered channel */
69 if ((rcp=(regchan *)cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
70 return;
71
72 /*
73 * If we're supposed to be joined, join ourselves..
74 */
75
76 if (CIsJoined(rcp) && (chanservnick!=NULL)) {
77 chanservjoinchan(cp);
78 }
79
80 /* This code interacts badly with bursts.. need to fix */
81
82 #if 0
83 /* We need to watch out for people sneaking into +k/i channels..
84 * This code relies on the fact that that user will already be in
85 * the channel at this point in time.. */
86 if (rcp->forcemodes & (CHANMODE_KEY | CHANMODE_INVITEONLY)) {
87 /* OK, this channel is keyed.. let's find out if the user is allowed to be here */
88 for (i=0;i<cp->users->hashsize;i++) {
89 if (cp->users->content[i]!=nouser && (np=getnickbynumeric(cp->users->content[i]))) {
90 if (IsService(np))
91 /* service (might even be us..) */
92 continue;
93
94 if ((rup=getreguserfromnick(np)) && (rcup=findreguseronchannel(rcp, rup)) &&
95 CUKnown(rcup) && !CUIsBanned(rcup))
96 /* legit user */
97 continue;
98
99 localkickuser(chanservnick, cp, np, "Private channel.");
100 }
101 }
102 }
103 #endif
104
105 /* Make sure the right modes are set/cleared */
106 cs_checkchanmodes(cp);
107
108 /* Start the timer rolling */
109 cs_timerfunc(cp->index);
110
111 /* If topicsave or forcetopic is set, update the topic */
112 if (CIsForceTopic(rcp) || CIsTopicSave(rcp)) {
113 localsettopic(chanservnick, cp, (rcp->topic) ? rcp->topic->content : "");
114 }
115 }
116
117 void cs_handlechanlostuser(int hooknum, void *arg) {
118 void **args=(void **)arg;
119 channel *cp=args[0];
120 regchan *rcp;
121
122 if (!(rcp=cp->index->exts[chanservext]) || CIsSuspended(rcp) || !chanservnick ||
123 (chanservnick==args[1]))
124 return;
125
126 if (!CIsJoined(rcp))
127 return;
128
129 if (cp->users->totalusers==2 &&
130 getnumerichandlefromchanhash(cp->users, chanservnick->numeric)) {
131 /* OK, Q is on the channel and not the one leaving.. */
132 rcp->lastpart=time(NULL);
133 cs_schedupdate(cp->index, 1, 5);
134 }
135 }
136
137
138 /*
139 * cs_handlelostchannel:
140 * This is for the HOOK_CHANNEL_LOSTCHANNEL message.
141 * A channel has just disappeared, clear our association with it.
142 */
143
144 void cs_handlelostchannel(int hooknum, void *arg) {
145 /* channel *cp=(channel *)arg; */
146
147 /* Do we actually need to do anything here? */
148 }
149
150 /*
151 * cs_handlejoin:
152 * A user joined a channel. See if we need to op/etc. them.
153 * Use this for JOIN or CREATE.
154 */
155
156 void cs_handlejoin(int hooknum, void *arg) {
157 void **arglist=(void **)arg;
158 channel *cp=(channel *)arglist[0];
159 nick *np=(nick *)arglist[1];
160 regchan *rcp;
161 reguser *rup;
162 regchanuser *rcup=NULL;
163 chanindex *cip;
164 int iscreate;
165 int dowelcome=0;
166
167 short modes=0;
168
169 /* If not registered or suspended, ignore */
170 if (!(rcp=cp->index->exts[chanservext]) || CIsSuspended(rcp))
171 return;
172
173 cip=cp->index;
174
175 rcp->tripjoins++;
176 rcp->totaljoins++;
177 if (cp->users->totalusers > rcp->maxusers)
178 rcp->maxusers=cp->users->totalusers;
179 if (cp->users->totalusers > rcp->tripusers)
180 rcp->tripusers=cp->users->totalusers;
181
182 /* If their auth is deleted, pretend they don't exist */
183 rup=getreguserfromnick(np);
184 if (rup && (rup->status & QUSTAT_DEAD))
185 rup=NULL;
186
187 if (rup && (rcup=findreguseronchannel(rcp,rup)) && CUKnown(rcup) && cp->users->totalusers >= 3)
188 rcp->lastactive=time(NULL);
189
190 if (rcp->lastcountersync < (time(NULL) - COUNTERSYNCINTERVAL)) {
191 csdb_updatechannelcounters(rcp);
192 rcp->lastcountersync=time(NULL);
193 }
194
195 if (hooknum==HOOK_CHANNEL_CREATE) {
196 iscreate=1;
197 } else {
198 iscreate=0;
199 }
200
201 /* Check for "Q ban" */
202 if (!IsService(np) && cs_bancheck(np,cp)) {
203 /* They got kicked.. */
204 return;
205 }
206
207 /* Check for other ban lurking on channel which we are enforcing */
208 if (!IsService(np) && CIsEnforce(rcp) && nickbanned(np,cp)) {
209 localkickuser(chanservnick,cp,np,"Banned.");
210 return;
211 }
212
213 /* Check for +b chanlev flag */
214 if (!IsService(np) && rcup && CUIsBanned(rcup)) {
215 cs_banuser(NULL, cip, np, NULL);
216 cs_timerfunc(cip);
217 return;
218 }
219
220 /* Check for +k chan flag */
221 if (!IsService(np) && CIsKnownOnly(rcp) && !(rcup && CUKnown(rcup))) {
222 if (IsInviteOnly(cp) || (IsRegOnly(cp) && !IsAccount(np))) {
223 localkickuser(chanservnick,cp,np,"Authorised users only.");
224 } else {
225 cs_banuser(NULL, cip, np, "Authorised users only.");
226 cs_timerfunc(cip);
227 }
228 return;
229 }
230
231 if (!rup || !rcup) {
232 /* They're not a registered user, so deop if it is a create */
233 if (iscreate && !IsService(np)) {
234 modes |= MC_DEOP;
235 }
236 if (CIsVoiceAll(rcp)) {
237 modes |= MC_VOICE;
238 }
239
240 if (CIsWelcome(rcp)) {
241 dowelcome=1; /* Send welcome message */
242 } else if (!CIsJoined(rcp) && iscreate) {
243 dowelcome=2; /* Send a generic warning */
244 }
245 } else {
246 /* Update last use time */
247 rcup->usetime=getnettime();
248
249 /* DB update removed for efficiency..
250 * csdb_updatelastjoin(rcup); */
251
252 /* They are registered, let's see what to do with them */
253 if (CUIsOp(rcup) && (CIsAutoOp(rcp) || CUIsAutoOp(rcup) || CUIsProtect(rcup) || CIsProtect(rcp)) &&
254 !CUIsDeny(rcup)) {
255 /* Auto op */
256 if (!iscreate) {
257 modes |= MC_OP;
258 }
259 } else {
260 /* Not auto op */
261 if (iscreate && !CUIsOp(rcup) && !IsService(np)) {
262 modes |= MC_DEOP;
263 }
264
265 if (!CUIsQuiet(rcup) && /* Not +q */
266 ((CUIsVoice(rcup) && (CIsAutoVoice(rcp) || CUIsAutoVoice(rcup) ||
267 CIsProtect(rcp) || CUIsProtect(rcup))) || /* +[gp]v */
268 (CIsVoiceAll(rcp)))) { /* Or voice-all chan */
269 modes |= MC_VOICE;
270 }
271 }
272
273 if (CIsWelcome(rcp) && !CUIsHideWelcome(rcup)) {
274 dowelcome=1;
275 }
276 }
277
278 /* Actually do the mode change, if any */
279 if (modes) {
280 localsetmodes(chanservnick, cp, np, modes);
281 }
282
283 switch(dowelcome) {
284
285 case 1: if (rcp->welcome)
286 chanservsendmessage(np,"[%s] %s",cip->name->content, rcp->welcome->content);
287 break;
288
289 case 2: if (chanservnick) {
290 /* Channel x is protected by y */
291 chanservstdmessage(np,QM_PROTECTED,cip->name->content,chanservnick->nick);
292 }
293 break;
294 }
295
296 if (rup && rcup && CIsInfo(rcp) && UIsInfo(rcup->user) && !CUIsHideInfo(rcup) && chanservnick) {
297 if (rcup->info) {
298 /* Chan-specific info */
299 sendmessagetochannel(chanservnick, cp, "[%s] %s",np->nick, rcup->info->content);
300 } else if (rup->info) {
301 /* Default info */
302 sendmessagetochannel(chanservnick, cp, "[%s] %s",np->nick, rup->info->content);
303 }
304 }
305 }
306
307 /* cs_handlemodechange:
308 * Handle mode change on channel
309 */
310
311 void cs_handlemodechange(int hooknum, void *arg) {
312 void **arglist=(void **)arg;
313 channel *cp=(channel *)arglist[0];
314 int changeflags=(int)arglist[2];
315 regchan *rcp;
316
317 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
318 return;
319
320 if (changeflags & MODECHANGE_MODES)
321 rcp->status |= QCSTAT_MODECHECK;
322
323 if (changeflags & MODECHANGE_USERS)
324 rcp->status |= QCSTAT_OPCHECK;
325
326 if (changeflags & MODECHANGE_BANS)
327 rcp->status |= QCSTAT_BANCHECK;
328
329 cs_timerfunc(rcp->index);
330 }
331
332 void cs_handleburst(int hooknum, void *arg) {
333 channel *cp=(channel *)arg;
334 regchan *rcp;
335
336 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
337 return;
338
339 /* Check everything at some future time */
340 /* If autolimit is on, make sure the limit gets reset at that point too */
341 if (CIsAutoLimit(rcp)) {
342 rcp->limit=0;
343 }
344 cs_schedupdate(cp->index, 1, 5);
345 rcp->status |= (QCSTAT_OPCHECK | QCSTAT_MODECHECK | QCSTAT_BANCHECK);
346 rcp->lastbancheck=0; /* Force re-check of all bans on channel */
347 }
348
349 /* cs_handleopchange:
350 * Handle [+-][ov] event
351 */
352
353 void cs_handleopchange(int hooknum, void *arg) {
354 void **arglist=(void **)arg;
355 channel *cp=(channel *)arglist[0];
356 regchan *rcp;
357 regchanuser *rcup;
358 reguser *rup;
359 nick *target=(nick *)arglist[2];
360 short modes=0;
361
362 /* Check that the channel is registered and active */
363 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
364 return;
365
366 rup=getreguserfromnick(target);
367
368 switch(hooknum) {
369 case HOOK_CHANNEL_OPPED:
370 if (CIsBitch(rcp) && !IsService(target)) {
371 if (!rup || (rcup=findreguseronchannel(rcp,rup))==NULL || !CUIsOp(rcup) || CUIsDeny(rcup))
372 modes |= MC_DEOP;
373 }
374 break;
375
376 /* Open question:
377 * Should +b prevent extra voices?
378 * If not, should we have a seperate mode that does?
379 */
380
381 case HOOK_CHANNEL_DEOPPED:
382 if (CIsProtect(rcp)) {
383 if (rup && (rcup=findreguseronchannel(rcp,rup))!=NULL && CUIsOp(rcup) && !CUIsDeny(rcup))
384 modes |= MC_OP;
385 }
386 break;
387
388 case HOOK_CHANNEL_DEVOICED:
389 if (CIsProtect(rcp)) {
390 if (rcp && (rcup=findreguseronchannel(rcp,rup))!=NULL && CUIsVoice(rcup) && !CUIsQuiet(rcup))
391 modes |= MC_VOICE;
392 }
393 break;
394 }
395
396 if (modes)
397 localsetmodes(chanservnick, cp, target, modes);
398 }
399
400 /* cs_handlenewban:
401 * Handle ban being added to channel
402 */
403
404 void cs_handlenewban(int hooknum, void *arg) {
405 void **arglist=(void **)arg;
406 regchan *rcp;
407 channel *cp=(channel *)arglist[0];
408 chanban *cbp;
409 int i;
410 nick *np;
411
412 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
413 return;
414
415 if ((cbp=cp->bans)==NULL) {
416 Error("chanserv",ERR_WARNING,"Told ban added but no bans on channel?");
417 return;
418 }
419
420 if (CIsEnforce(rcp)) {
421 for (i=0;i<cp->users->hashsize;i++) {
422 if (cp->users->content[i]!=nouser) {
423 if ((np=getnickbynumeric(cp->users->content[i]))==NULL) {
424 Error("chanserv",ERR_WARNING,"Found user on channel %s who doesn't exist!",cp->index->name->content);
425 continue;
426 }
427 if (!IsService(np) && nickmatchban(np,cbp)) {
428 localkickuser(chanservnick,cp,np,"Banned.");
429 }
430 }
431 }
432 }
433 }
434
435 /* cs_handletopicchange:
436 * Handle topic change on channel
437 */
438
439 void cs_handletopicchange(int hooknum, void *arg) {
440 void **arglist=(void **)arg;
441 channel *cp=(channel *)arglist[0];
442 regchan *rcp;
443
444 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
445 return;
446
447 if (CIsForceTopic(rcp)) {
448 if (rcp->topic) {
449 /* Forced topic: change it back */
450 localsettopic(chanservnick, cp, rcp->topic->content);
451 }
452 } else if (CIsTopicSave(rcp)) {
453 if (rcp->topic) {
454 freesstring(rcp->topic);
455 }
456 if (cp->topic) {
457 rcp->topic=getsstring(cp->topic->content,TOPICLEN);
458 } else {
459 rcp->topic=NULL;
460 }
461 csdb_updatetopic(rcp);
462 }
463 }