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