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