]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservnetevents.c
Get rid of ALL WARNINGS!
[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 int iscreate;
164 int dowelcome=0;
165
166 short modes=0;
167
168 /* If not registered or suspended, ignore */
169 if (!(rcp=cp->index->exts[chanservext]) || CIsSuspended(rcp))
170 return;
171
172 rcp->tripjoins++;
173 rcp->totaljoins++;
174 if (cp->users->totalusers > rcp->maxusers)
175 rcp->maxusers=cp->users->totalusers;
176 if (cp->users->totalusers > rcp->tripusers)
177 rcp->tripusers=cp->users->totalusers;
178
179 /* If their auth is deleted, pretend they don't exist */
180 rup=getreguserfromnick(np);
181 if (rup && (rup->status & QUSTAT_DEAD))
182 rup=NULL;
183
184 if (rup && (rcup=findreguseronchannel(rcp,rup)) && CUKnown(rcup) && cp->users->totalusers >= 3)
185 rcp->lastactive=time(NULL);
186
187 if (rcp->lastcountersync < (time(NULL) - COUNTERSYNCINTERVAL)) {
188 csdb_updatechannelcounters(rcp);
189 rcp->lastcountersync=time(NULL);
190 }
191
192 if (hooknum==HOOK_CHANNEL_CREATE) {
193 iscreate=1;
194 } else {
195 iscreate=0;
196 }
197
198 /* Check for "Q ban" */
199 if (!IsService(np) && cs_bancheck(np,cp)) {
200 /* They got kicked.. */
201 return;
202 }
203
204 /* Check for other ban lurking on channel which we are enforcing */
205 if (!IsService(np) && CIsEnforce(rcp) && nickbanned(np,cp)) {
206 localkickuser(chanservnick,cp,np,"Banned.");
207 return;
208 }
209
210 /* Check for +b chanlev flag */
211 if (!IsService(np) && rcup && CUIsBanned(rcup)) {
212 cs_banuser(NULL, cp->index, np, NULL);
213 cs_timerfunc(cp->index);
214 return;
215 }
216
217 /* Check for +k chan flag */
218 if (!IsService(np) && CIsKnownOnly(rcp) && !(rcup && CUKnown(rcup))) {
219 if (IsInviteOnly(cp) || (IsRegOnly(cp) && !IsAccount(np))) {
220 localkickuser(chanservnick,cp,np,"Authorised users only.");
221 } else {
222 cs_banuser(NULL, cp->index, np, "Authorised users only.");
223 cs_timerfunc(cp->index);
224 }
225 return;
226 }
227
228 if (!rup || !rcup) {
229 /* They're not a registered user, so deop if it is a create */
230 if (iscreate && !IsService(np)) {
231 modes |= MC_DEOP;
232 }
233 if (CIsVoiceAll(rcp)) {
234 modes |= MC_VOICE;
235 }
236
237 if (CIsWelcome(rcp)) {
238 dowelcome=1; /* Send welcome message */
239 } else if (!CIsJoined(rcp) && iscreate) {
240 dowelcome=2; /* Send a generic warning */
241 }
242 } else {
243 /* Update last use time */
244 rcup->usetime=getnettime();
245
246 /* DB update removed for efficiency..
247 * csdb_updatelastjoin(rcup); */
248
249 /* They are registered, let's see what to do with them */
250 if (CUIsOp(rcup) && (CIsAutoOp(rcp) || CUIsAutoOp(rcup) || CUIsProtect(rcup) || CIsProtect(rcp)) &&
251 !CUIsDeny(rcup)) {
252 /* Auto op */
253 if (!iscreate) {
254 modes |= MC_OP;
255 }
256 } else {
257 /* Not auto op */
258 if (iscreate && !CUIsOp(rcup) && !IsService(np)) {
259 modes |= MC_DEOP;
260 }
261
262 if (!CUIsQuiet(rcup) && /* Not +q */
263 ((CUIsVoice(rcup) && (CIsAutoVoice(rcp) || CUIsAutoVoice(rcup) ||
264 CIsProtect(rcp) || CUIsProtect(rcup))) || /* +[gp]v */
265 (CIsVoiceAll(rcp)))) { /* Or voice-all chan */
266 modes |= MC_VOICE;
267 }
268 }
269
270 if (CIsWelcome(rcp) && !CUIsHideWelcome(rcup)) {
271 dowelcome=1;
272 }
273 }
274
275 /* Actually do the mode change, if any */
276 if (modes) {
277 localsetmodes(chanservnick, cp, np, modes);
278 }
279
280 switch(dowelcome) {
281
282 case 1: if (rcp->welcome)
283 chanservsendmessage(np,"[%s] %s",cp->index->name->content, rcp->welcome->content);
284 break;
285
286 case 2: if (chanservnick) {
287 /* Channel x is protected by y */
288 chanservstdmessage(np,QM_PROTECTED,cp->index->name->content,chanservnick->nick);
289 }
290 break;
291 }
292
293 if (rup && rcup && CIsInfo(rcp) && UIsInfo(rcup->user) && !CUIsHideInfo(rcup) && chanservnick) {
294 if (rcup->info) {
295 /* Chan-specific info */
296 sendmessagetochannel(chanservnick, cp, "[%s] %s",np->nick, rcup->info->content);
297 } else if (rup->info) {
298 /* Default info */
299 sendmessagetochannel(chanservnick, cp, "[%s] %s",np->nick, rup->info->content);
300 }
301 }
302 }
303
304 /* cs_handlemodechange:
305 * Handle mode change on channel
306 */
307
308 void cs_handlemodechange(int hooknum, void *arg) {
309 void **arglist=(void **)arg;
310 channel *cp=(channel *)arglist[0];
311 int changeflags=(int)arglist[2];
312 regchan *rcp;
313
314 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
315 return;
316
317 if (changeflags & MODECHANGE_MODES)
318 rcp->status |= QCSTAT_MODECHECK;
319
320 if (changeflags & MODECHANGE_USERS)
321 rcp->status |= QCSTAT_OPCHECK;
322
323 if (changeflags & MODECHANGE_BANS)
324 rcp->status |= QCSTAT_BANCHECK;
325
326 cs_timerfunc(rcp->index);
327 }
328
329 void cs_handleburst(int hooknum, void *arg) {
330 channel *cp=(channel *)arg;
331 regchan *rcp;
332
333 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
334 return;
335
336 /* Check everything at some future time */
337 /* If autolimit is on, make sure the limit gets reset at that point too */
338 if (CIsAutoLimit(rcp)) {
339 rcp->limit=0;
340 }
341 cs_schedupdate(cp->index, 1, 5);
342 rcp->status |= (QCSTAT_OPCHECK | QCSTAT_MODECHECK | QCSTAT_BANCHECK);
343 rcp->lastbancheck=0; /* Force re-check of all bans on channel */
344 }
345
346 /* cs_handleopchange:
347 * Handle [+-][ov] event
348 */
349
350 void cs_handleopchange(int hooknum, void *arg) {
351 void **arglist=(void **)arg;
352 channel *cp=(channel *)arglist[0];
353 regchan *rcp;
354 regchanuser *rcup;
355 reguser *rup;
356 nick *target=(nick *)arglist[2];
357 short modes=0;
358
359 /* Check that the channel is registered and active */
360 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
361 return;
362
363 rup=getreguserfromnick(target);
364
365 switch(hooknum) {
366 case HOOK_CHANNEL_OPPED:
367 if (CIsBitch(rcp) && !IsService(target)) {
368 if (!rup || (rcup=findreguseronchannel(rcp,rup))==NULL || !CUIsOp(rcup) || CUIsDeny(rcup))
369 modes |= MC_DEOP;
370 }
371 break;
372
373 /* Open question:
374 * Should +b prevent extra voices?
375 * If not, should we have a seperate mode that does?
376 */
377
378 case HOOK_CHANNEL_DEOPPED:
379 if (CIsProtect(rcp)) {
380 if (rup && (rcup=findreguseronchannel(rcp,rup))!=NULL && CUIsOp(rcup) && !CUIsDeny(rcup))
381 modes |= MC_OP;
382 }
383 break;
384
385 case HOOK_CHANNEL_DEVOICED:
386 if (CIsProtect(rcp)) {
387 if (rcp && (rcup=findreguseronchannel(rcp,rup))!=NULL && CUIsVoice(rcup) && !CUIsQuiet(rcup))
388 modes |= MC_VOICE;
389 }
390 break;
391 }
392
393 if (modes)
394 localsetmodes(chanservnick, cp, target, modes);
395 }
396
397 /* cs_handlenewban:
398 * Handle ban being added to channel
399 */
400
401 void cs_handlenewban(int hooknum, void *arg) {
402 void **arglist=(void **)arg;
403 regchan *rcp;
404 channel *cp=(channel *)arglist[0];
405 chanban *cbp;
406 int i;
407 nick *np;
408
409 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
410 return;
411
412 if ((cbp=cp->bans)==NULL) {
413 Error("chanserv",ERR_WARNING,"Told ban added but no bans on channel?");
414 return;
415 }
416
417 if (CIsEnforce(rcp)) {
418 for (i=0;i<cp->users->hashsize;i++) {
419 if (cp->users->content[i]!=nouser) {
420 if ((np=getnickbynumeric(cp->users->content[i]))==NULL) {
421 Error("chanserv",ERR_WARNING,"Found user on channel %s who doesn't exist!",cp->index->name->content);
422 continue;
423 }
424 if (!IsService(np) && nickmatchban(np,cbp)) {
425 localkickuser(chanservnick,cp,np,"Banned.");
426 }
427 }
428 }
429 }
430 }
431
432 /* cs_handletopicchange:
433 * Handle topic change on channel
434 */
435
436 void cs_handletopicchange(int hooknum, void *arg) {
437 void **arglist=(void **)arg;
438 channel *cp=(channel *)arglist[0];
439 regchan *rcp;
440
441 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
442 return;
443
444 if (CIsForceTopic(rcp)) {
445 if (rcp->topic) {
446 /* Forced topic: change it back */
447 localsettopic(chanservnick, cp, rcp->topic->content);
448 }
449 } else if (CIsTopicSave(rcp)) {
450 if (rcp->topic) {
451 freesstring(rcp->topic);
452 }
453 if (cp->topic) {
454 rcp->topic=getsstring(cp->topic->content,TOPICLEN);
455 } else {
456 rcp->topic=NULL;
457 }
458 csdb_updatetopic(rcp);
459 }
460 }