]> jfr.im git - irc/quakenet/newserv.git/blame - chanserv/chanservuser.c
Added CHANMODE_DEFAULT to indicate the default modes.
[irc/quakenet/newserv.git] / chanserv / chanservuser.c
CommitLineData
c86edd1d
Q
1/*
2 * chanservuser.c:
3 * This file maintains the functions associated with the
4 * user on the network relating to the channel service
5 */
6
7#include "chanserv.h"
8
32562540 9#include "../core/hooks.h"
c86edd1d
Q
10#include "../core/schedule.h"
11#include "../core/config.h"
12#include "../localuser/localuser.h"
13#include "../localuser/localuserchannel.h"
14#include "../irc/irc_config.h"
15#include "../lib/sstring.h"
16#include "../nick/nick.h"
17#include "../parser/parser.h"
18#include "../lib/splitline.h"
19
20#include <string.h>
21#include <stdio.h>
22#include <stdarg.h>
23#include <stdlib.h>
24
25nick *chanservnick;
26CommandTree *cscommands;
27CommandTree *csctcpcommands;
28
29/* Local prototypes */
30void chanservuserhandler(nick *target, int message, void **params);
31
32void chanservreguser(void *arg) {
33 sstring *csnick,*csuser,*cshost,*csrealname;
34 chanindex *cip;
35 regchan *rcp;
36 int i;
37
38 csnick=getcopyconfigitem("chanserv","nick","Q",NICKLEN);
39 csuser=getcopyconfigitem("chanserv","user","TheQBot",USERLEN);
40 cshost=getcopyconfigitem("chanserv","host","some.host",HOSTLEN);
41 csrealname=getcopyconfigitem("chanserv","realname","ChannelService",REALLEN);
42
316959c1 43 Error("chanserv",ERR_INFO,"Connecting %s...",csnick->content);
44
c86edd1d
Q
45 chanservnick=registerlocaluser(csnick->content,csuser->content,cshost->content,
46 csrealname->content,NULL,
47 UMODE_INV|UMODE_SERVICE|UMODE_DEAF,
48 &chanservuserhandler);
49
50 freesstring(csnick);
51 freesstring(csuser);
52 freesstring(cshost);
53 freesstring(csrealname);
54
55 /* Now join channels */
56 for (i=0;i<CHANNELHASHSIZE;i++) {
57 for (cip=chantable[i];cip;cip=cip->next) {
58 if (cip->channel && (rcp=cip->exts[chanservext]) && !CIsSuspended(rcp)) {
316959c1 59 /* This will do timestamp faffing even if it won't actually join */
60 chanservjoinchan(cip->channel);
c86edd1d
Q
61 /* Do a check at some future time.. */
62 cs_schedupdate(cip, 1, 5);
63 rcp->status |= (QCSTAT_OPCHECK | QCSTAT_MODECHECK | QCSTAT_BANCHECK);
64 if (CIsForceTopic(rcp) || CIsTopicSave(rcp))
65 localsettopic(chanservnick, cip->channel, (rcp->topic) ? rcp->topic->content : "");
66 }
67 }
68 }
69
316959c1 70 Error("chanserv",ERR_INFO,"Loaded and joined channels.");
71
c86edd1d
Q
72 if (chanserv_init_status == CS_INIT_NOUSER) {
73 /* If this is the first time, perform last init tasks */
74 chanserv_finalinit();
75 }
76}
77
78void chanservuserhandler(nick *target, int message, void **params) {
79 nick *sender;
80 char *msg;
81 Command *cmd;
82 char *cargv[30];
83 int cargc;
84 reguser *rup;
85 char *chp;
86
87 switch(message) {
88 case LU_KILLED:
89 scheduleoneshot(time(NULL),&chanservreguser,NULL);
90 chanservnick=NULL;
91 break;
92
93 case LU_PRIVMSG:
94 case LU_SECUREMSG:
95 sender=(nick *)params[0];
96 msg=(char *)params[1];
97
98 if (!(cargc=splitline(msg,cargv,30,0)))
99 return; /* Ignore blank lines */
100
101 if (cargv[0][0]==1) {
102 /* CTCP */
103 for (chp=cargv[0]+1;*chp;chp++) {
104 if (*chp=='\001') {
105 *chp='\0';
106 break;
107 }
108 }
109 cmd=findcommandintree(csctcpcommands, cargv[0]+1, 1);
110 if (cmd) {
111 rejoinline(cargv[1],cargc-1);
112 cmd->handler((void *)sender, cargc-1, &(cargv[1]));
113 }
114 } else {
115 cmd=findcommandintree(cscommands, cargv[0], 1);
116
117 if (!cmd) {
118 chanservstdmessage(sender, QM_UNKNOWNCMD, cargv[0]);
119 break;
120 }
121
122 if ((cmd->level & QCMD_SECURE) && (message != LU_SECUREMSG)) {
123 chanservstdmessage(sender, QM_SECUREONLY, cargv[0], chanservnick->nick, myserver->content);
124 break;
125 }
126
127 if ((cmd->level & QCMD_AUTHED)) {
128 if (!(rup=getreguserfromnick(sender))) {
129 chanservstdmessage(sender, QM_AUTHEDONLY, cargv[0]);
130 break;
131 }
132 if (UIsSuspended(rup) || (rup->status & QUSTAT_DEAD)) {
133 chanservstdmessage(sender, QM_BADAUTH, cargv[0]);
134 break;
135 }
136 }
137
138 if ((cmd->level & QCMD_NOTAUTHED) && (getreguserfromnick(sender))) {
139 chanservstdmessage(sender, QM_UNAUTHEDONLY, cargv[0]);
140 break;
141 }
142
143 if ((cmd->level & QCMD_HELPER) &&
144 (!(rup=getreguserfromnick(sender)) || !UHasHelperPriv(rup))) {
145 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
146 break;
147 }
148
149 if ((cmd->level & QCMD_OPER) &&
150 (!IsOper(sender) || !(rup=getreguserfromnick(sender)) || !UHasOperPriv(rup))) {
151 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
152 break;
153 }
154
155 if ((cmd->level & QCMD_ADMIN) &&
156 (!IsOper(sender) || !(rup=getreguserfromnick(sender)) || !UHasAdminPriv(rup))) {
157 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
158 break;
159 }
160
161 if ((cmd->level & QCMD_DEV) &&
162 (!IsOper(sender) || !(rup=getreguserfromnick(sender)) || !UIsDev(rup))) {
163 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
164 break;
165 }
166
167 if (cmd->maxparams < (cargc-1)) {
168 rejoinline(cargv[cmd->maxparams],cargc-(cmd->maxparams));
169 cargc=(cmd->maxparams)+1;
170 }
171
172 cmd->handler((void *)sender, cargc-1, &(cargv[1]));
173 }
174 break;
175
176 default:
177 break;
178 }
179}
180
181void chanservcommandinit() {
182 cscommands=newcommandtree();
183 csctcpcommands=newcommandtree();
184}
185
186void chanservcommandclose() {
187 destroycommandtree(cscommands);
188 destroycommandtree(csctcpcommands);
189}
190
191void chanservaddcommand(char *command, int flags, int maxparams, CommandHandler handler, char *description) {
192 Command *newcmd;
193 cmdsummary *summary;
194
195 newcmd=addcommandtotree(cscommands, command, flags, maxparams, handler);
196 /* Allocate a summary record to put the description in */
197 summary=(cmdsummary *)malloc(sizeof(cmdsummary));
198 memset((void *)summary,0,sizeof(cmdsummary));
199
200 summary->def=getsstring(description, 250);
201
202 newcmd->ext=(void *)summary;
203 loadcommandsummary(newcmd);
204}
205
206void chanservaddctcpcommand(char *command, CommandHandler handler) {
207 addcommandtotree(csctcpcommands, command, 0, 1, handler);
208}
209
210void chanservremovectcpcommand(char *command, CommandHandler handler) {
211 deletecommandfromtree(csctcpcommands, command, handler);
212}
213
214void chanservremovecommand(char *command, CommandHandler handler) {
215 Command *cmd;
216 cmdsummary *summary;
217 int i;
218
219 if (!(cmd=findcommandintree(cscommands, command, 1))) {
220 Error("chanserv",ERR_WARNING,"Tried to unregister unknown command %s",command);
221 return;
222 }
223
224 summary=(cmdsummary *)cmd->ext;
225 freesstring(summary->def);
226 for (i=0;i<MAXLANG;i++) {
227 if (summary->bylang[i])
228 freesstring(summary->bylang[i]);
229 }
230
231 free(summary);
232
233 deletecommandfromtree(cscommands, command, handler);
234}
235
236void chanservjoinchan(channel *cp) {
237 regchan *rcp;
a54e438d 238
239 /* Skip unregistered channels */
240 if (!(rcp=cp->index->exts[chanservext]))
241 return;
242
243 /* Check for a new timestamp */
244 if ((!rcp->ltimestamp) || (cp->timestamp < rcp->ltimestamp)) {
245 rcp->ltimestamp=cp->timestamp;
246 csdb_updatechanneltimestamp(rcp);
247 }
c86edd1d 248
a54e438d 249 /* We won't be doing any joining or parting if we're not online */
250 if (!chanservnick)
c86edd1d
Q
251 return;
252
253 if ((CIsSuspended(rcp) || !CIsJoined(rcp)) && getnumerichandlefromchanhash(cp->users, chanservnick->numeric)) {
334b567e
P
254 if(rcp->suspendreason) {
255 localpartchannel(chanservnick, cp, rcp->suspendreason->content);
256 } else {
257 localpartchannel(chanservnick, cp, NULL);
258 }
c86edd1d
Q
259 }
260
a54e438d 261 /* OK, we're going to join the channel. Since our timestamp must be less
262 * than or equal to the one already there it should be OK to burst on.
263 *
264 * We will try and burst our view of the world; if the timestamps are
265 * actually equal this will be mostly ignored and we will have to fix it
266 * up later */
c86edd1d 267 if (!CIsSuspended(rcp) && CIsJoined(rcp) && !getnumerichandlefromchanhash(cp->users, chanservnick->numeric)) {
a54e438d 268 localburstontochannel(cp, chanservnick, rcp->ltimestamp, rcp->forcemodes, rcp->limit, (rcp->key)?rcp->key->content:NULL);
c86edd1d 269 }
b263aa79 270
271 /* Maybe we're not joining, but the timestamp is wrong. Fix that too.
272 *
273 * XXX: Actually, let's not do this until we've considered the obvious
274 * problem that this will make it impossible to re-establish a +k/+i
275 * enforced channel which has become empty...
276 */
277/*
278 if (!CIsSuspended(rcp) && !CIsJoined(rcp) && (cp->timestamp > rcp->ltimestamp)) {
279 localburstontochannel(cp, NULL, rcp->ltimestamp, rcp->forcemodes, rcp->limit, (rcp->key)?rcp->key->content:NULL);
280 }
281 */
c86edd1d
Q
282}
283
284void chanservstdmessage(nick *np, int messageid, ... ) {
285 char buf[5010];
286 char buf2[512];
287 int notice;
288 reguser *rup;
289 int language;
290 va_list va;
291 char *message;
292 char *bp2,*bp;
293 int len;
294
295 if (getreguserfromnick(np) == NULL) {
296 notice=1;
297 language=0;
298 } else {
299 rup=getreguserfromnick(np);
300 if(UIsNotice(rup)) {
301 notice=1;
302 } else {
303 notice=0;
304 }
305 language=rup->languageid;
306 }
307
308 if (csmessages[language][messageid]) {
309 message=csmessages[language][messageid]->content;
310 } else if (csmessages[0][messageid]) {
311 message=csmessages[0][messageid]->content;
312 } else {
313 message=defaultmessages[messageid];
314 }
315
316 va_start(va,messageid);
317 vsnprintf(buf,5000,message,va);
318 va_end(va);
319
320 len=0;
321 bp2=buf2;
322 for (bp=buf; ;bp++) {
323 /* We send something if we hit a \n, fill the buffer or run out of source */
324 if (*bp=='\n' || len>490 || !*bp) {
325 if (*bp && *bp!='\n') {
326 bp--;
327 }
328
329 *bp2='\0';
330
331 if (chanservnick && *buf2) {
332 if (notice) {
333 sendnoticetouser(chanservnick,np,"%s",buf2);
334 } else {
335 sendmessagetouser(chanservnick,np,"%s",buf2);
336 }
337 }
338
339 /* If we ran out of buffer, get out here */
340 if (!*bp)
341 break;
342
343 bp2=buf2;
344 len=0;
345 } else {
346 len++;
347 *bp2++=*bp;
348 }
349 }
350}
351
352void chanservsendmessage(nick *np, char *message, ... ) {
353 char buf[5010]; /* Very large buffer.. */
354 char buf2[512], *bp, *bp2;
355 int notice;
356 int len;
357 reguser *rup;
358
359 va_list va;
360
361 va_start(va,message);
362 vsnprintf(buf,5000,message,va);
363 va_end(va);
364
365 if (getreguserfromnick(np) == NULL) {
366 notice=1;
367 } else {
368 rup=getreguserfromnick(np);
369 if(UIsNotice(rup)) {
370 notice=1;
371 } else {
372 notice=0;
373 }
374 }
375
376 len=0;
377 bp2=buf2;
378 for (bp=buf; ;bp++) {
379 /* We send something if we hit a \n, fill the buffer or run out of source */
380 if (*bp=='\n' || len>490 || !*bp) {
381 if (*bp && *bp!='\n') {
382 bp--;
383 }
384
385 *bp2='\0';
386
387 if (chanservnick && *buf2) {
388 if (notice) {
389 sendnoticetouser(chanservnick,np,"%s",buf2);
390 } else {
391 sendmessagetouser(chanservnick,np,"%s",buf2);
392 }
393 }
394
395 /* If we ran out of buffer, get out here */
396 if (!*bp)
397 break;
398
399 bp2=buf2;
400 len=0;
401 } else {
402 len++;
403 *bp2++=*bp;
404 }
405 }
406}
407
408void chanservwallmessage(char *message, ... ) {
409 char buf[5010]; /* Very large buffer.. */
410 va_list va;
411 nick *np;
412 unsigned int i=0;
413
414 va_start(va,message);
415 vsnprintf(buf,5000,message,va);
416 va_end(va);
417
418 /* Scan for users */
419 for (i=0;i<NICKHASHSIZE;i++)
420 for (np=nicktable[i];np;np=np->next)
421 if (IsOper(np))
422 chanservsendmessage(np, "%s", buf);
423}
424
425void chanservkillstdmessage(nick *target, int messageid, ... ) {
426 char buf[512];
427 int language;
428 char* message;
429 va_list va;
430 reguser *rup;
431
432 if (!(rup=getreguserfromnick(target)))
433 language=0;
434 else
435 language=rup->languageid;
436
437 if (csmessages[language][messageid])
438 message=csmessages[language][messageid]->content;
439 else if (csmessages[0][messageid])
440 message=csmessages[0][messageid]->content;
441 else
442 message=defaultmessages[messageid];
443
444 va_start(va, messageid);
445 vsnprintf(buf, 511, message, va);
446 va_end(va);
447 killuser(chanservnick, target, buf);
448}
449
450int checkmasterpassword(reguser *rup, const char *pass) {
451 if (!strncmp(rup->masterpass, pass, PASSLEN))
452 return 1;
453 return 0;
454}
455
456int checkpassword(reguser *rup, const char *pass) {
457 if (!strncmp(rup->password, pass, PASSLEN))
458 return 1;
459 return 0;
460}
461
462int setmasterpassword(reguser *rup, const char *pass) {
463 strncpy(rup->masterpass, pass, PASSLEN);
464 rup->masterpass[PASSLEN]='\0';
465 return 1;
466}
467
468int setpassword(reguser *rup, const char *pass) {
469 strncpy(rup->password, pass, PASSLEN);
470 rup->password[PASSLEN]='\0';
471 return 1;
472}
473
474void cs_checknick(nick *np) {
475 activeuser* aup;
476 reguser *rup;
477 nicklist *nlp;
478 char userhost[USERLEN+HOSTLEN+3];
479
480 if (!(aup=getactiveuserfromnick(np))) {
481 aup=getactiveuser();
482 np->exts[chanservnext]=aup;
483 }
484
485 assert(getactiveuserfromnick(np));
486
487 if (IsAccount(np)) {
488 if ((rup=findreguserbynick(np->authname))!=NULL) {
489 aup->rup=rup;
490 nlp=getnicklist();
491 nlp->np=np;
492 nlp->next=rup->nicks;
493 rup->nicks=nlp;
32562540 494 triggerhook(HOOK_CHANSERV_SETUSERID, np);
c86edd1d
Q
495 cs_doallautomodes(np);
496 } else {
497 aup->rup=NULL;
498 /* Auto create user.. */
499 rup=getreguser();
500 rup->status=0;
501 rup->ID=++lastuserID;
502 strncpy(rup->username,np->authname,NICKLEN); rup->username[NICKLEN]='\0';
503 rup->created=time(NULL);
504 rup->lastauth=time(NULL);
505 rup->lastemailchange=0;
506 rup->flags=QUFLAG_NOTICE;
507 rup->languageid=0;
508 rup->suspendby=0;
509 rup->password[0]='\0';
510 rup->masterpass[0]='\0';
511 rup->email=NULL;
e3805f60
P
512 rup->localpart=NULL;
513 rup->domain=NULL;
c86edd1d
Q
514 rup->info=NULL;
515 sprintf(userhost,"%s@%s",np->ident,np->host->name->content);
516 rup->lastuserhost=getsstring(userhost,USERLEN+HOSTLEN+1);
517 rup->suspendreason=NULL;
518 rup->comment=NULL;
519 rup->knownon=NULL;
520 rup->checkshd=NULL;
521 rup->stealcount=0;
522 rup->fakeuser=NULL;
523 rup->nicks=getnicklist();
524 rup->nicks->np=np;
525 rup->nicks->next=NULL;
526 addregusertohash(rup);
527
528 csdb_createuser(rup);
529 aup->rup=rup;
530 }
531 } else {
532 aup->rup=NULL;
533 }
534
535 cs_checknickbans(np);
536}
537
538void cs_checkchanmodes(channel *cp) {
539 modechanges changes;
540
541 localsetmodeinit (&changes, cp, chanservnick);
542 cs_docheckchanmodes(cp, &changes);
543 localsetmodeflush (&changes, 1);
544}
545
546void cs_docheckchanmodes(channel *cp, modechanges *changes) {
547 regchan *rcp;
548
549 if (!cp)
550 return;
551
552 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
553 return;
554
555 /* Take care of the simple modes */
556 localdosetmode_simple(changes, rcp->forcemodes & ~(cp->flags), rcp->denymodes & cp->flags);
557
558 /* Check for forced key. Note that we ALWAYS call localdosetmode_key
559 * in case the wrong key is set atm */
560 if (rcp->forcemodes & CHANMODE_KEY) {
561 if (!rcp->key) {
562 Error("chanserv",ERR_WARNING,"Key forced but no key specified for %s: cleared forcemode.",rcp->index->name->content);
563 rcp->forcemodes &= ~CHANMODE_KEY;
a54e438d 564 csdb_updatechannel(rcp);
c86edd1d
Q
565 } else {
566 localdosetmode_key(changes, rcp->key->content, MCB_ADD);
567 }
568 }
569
570 /* Check for denied key */
571 if ((rcp->denymodes & CHANMODE_KEY) && IsKey(cp)) {
572 localdosetmode_key(changes, NULL, MCB_DEL);
573 }
574
575 /* Check for forced limit. Always call in case of wrong limit */
576 if (rcp->forcemodes & CHANMODE_LIMIT) {
577 localdosetmode_limit(changes, rcp->limit, MCB_ADD);
578 }
579}
580
581void cs_docheckopvoice(channel *cp, modechanges *changes) {
582 regchan *rcp;
583 reguser *rup;
584 regchanuser *rcup;
585 nick *np;
586 int i;
587
588 if (!cp)
589 return;
590
591 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
592 return;
593
594 for (i=0;i<cp->users->hashsize;i++) {
595 if (cp->users->content[i]==nouser)
596 continue;
597
598 if ((np=getnickbynumeric(cp->users->content[i]))==NULL) {
599 Error("chanserv",ERR_ERROR,"Found non-existent numeric %d on channel %s",cp->users->content[i],
600 cp->index->name->content);
601 continue;
602 }
603
604 if ((rup=getreguserfromnick(np)))
605 rcup=findreguseronchannel(rcp,rup);
606 else
607 rcup=NULL;
608
609 if (rcup && CUIsBanned(rcup) && !IsService(np)) {
610 cs_banuser(changes, cp->index, np, NULL);
611 continue;
612 }
613
614 if (!IsService(np) && CIsKnownOnly(rcp) && !(rcup && CUKnown(rcup))) {
615 cs_banuser(changes, cp->index, np, "Authorised users only.");
616 continue;
617 }
618
619 if ((cp->users->content[i] & CUMODE_OP) && !IsService(np)) {
620 if ((CIsBitch(rcp) && (!rcup || !CUHasOpPriv(rcup))) ||
621 (rcup && CUIsDeny(rcup)))
622 localdosetmode_nick(changes, np, MC_DEOP);
623 } else {
624 if (rcup && (CUIsProtect(rcup) || CIsProtect(rcp)) && CUIsOp(rcup) && !CUIsDeny(rcup))
625 localdosetmode_nick(changes, np, MC_OP);
626 }
627
628 if (cp->users->content[i] & CUMODE_VOICE) {
629 if (rcup && CUIsQuiet(rcup))
630 localdosetmode_nick(changes, np, MC_DEVOICE);
631 } else {
632 if (rcup && (CUIsProtect(rcup) || CIsProtect(rcp)) && CUIsVoice(rcup) && !CUIsQuiet(rcup) && !(cp->users->content[i] & CUMODE_OP))
633 localdosetmode_nick(changes, np, MC_VOICE);
634 }
635 }
636}
637
638void cs_doallautomodes(nick *np) {
639 reguser *rup;
640 regchanuser *rcup;
641 unsigned long *lp;
642 modechanges changes;
643
644 if (!(rup=getreguserfromnick(np)))
645 return;
646
647 for (rcup=rup->knownon;rcup;rcup=rcup->nextbyuser) {
648 if (rcup->chan->index->channel) {
649 /* Channel exists */
650 if ((lp=getnumerichandlefromchanhash(rcup->chan->index->channel->users, np->numeric))) {
651
652 /* User is on channel.. */
653 localsetmodeinit(&changes, rcup->chan->index->channel, chanservnick);
654 if (*lp & CUMODE_OP) {
655 if (!IsService(np) && (CUIsDeny(rcup) || (CIsBitch(rcup->chan) && !CUHasOpPriv(rcup))))
656 localdosetmode_nick(&changes, np, MC_DEOP);
657 } else {
658 if (!CUIsDeny(rcup) && CUIsOp(rcup) &&
659 (CUIsProtect(rcup) || CIsProtect(rcup->chan) || CUIsAutoOp(rcup)))
660 localdosetmode_nick(&changes, np, MC_OP);
661 }
662
663 if (*lp & CUMODE_VOICE) {
664 if (CUIsQuiet(rcup))
665 localdosetmode_nick(&changes, np, MC_DEVOICE);
666 } else {
667 if (!CUIsQuiet(rcup) && CUIsVoice(rcup) && !(*lp & CUMODE_OP) &&
668 (CUIsProtect(rcup) || CIsProtect(rcup->chan) || CUIsAutoVoice(rcup)))
669 localdosetmode_nick(&changes, np, MC_VOICE);
670 }
671 localsetmodeflush(&changes, 1);
672 } else {
673 /* Channel exists but user is not joined: invite if they are +j-b */
674 if (CUIsAutoInvite(rcup) && CUKnown(rcup) && !CUIsBanned(rcup)) {
675 localinvite(chanservnick, rcup->chan->index->channel, np);
676 }
677 }
678 }
679 }
680}
681
682void cs_checknickbans(nick *np) {
683 channel **ca;
684 regchan *rcp;
685 int i,j;
686
687 if (IsService(np))
688 return;
689
690 /* Avoid races: memcpy the channel array */
691 i=np->channels->cursi;
692 ca=(channel **)malloc(i*sizeof(channel *));
693 memcpy(ca, np->channels->content,i*sizeof(channel *));
694
695 for (j=0;j<i;j++) {
696 if ((rcp=ca[j]->index->exts[chanservext]) && !CIsSuspended(rcp) &&
697 CIsEnforce(rcp) && nickbanned(np, ca[j]))
698 localkickuser(chanservnick, ca[j], np, "Banned.");
699 }
700
701 free(ca);
702}
703
704void cs_checkbans(channel *cp) {
705 regchan *rcp;
706 int i;
707 nick *np;
708 chanban *cbp;
709 regban *rbp;
710 time_t now;
711 modechanges changes;
712
713 if (!cp)
714 return;
715
716 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
717 return;
718
719 now=time(NULL);
720
721 localsetmodeinit(&changes, cp, chanservnick);
722
723 for (i=0;i<cp->users->hashsize;i++) {
724 if (cp->users->content[i]==nouser)
725 continue;
726
727 if ((np=getnickbynumeric(cp->users->content[i]))==NULL) {
728 Error("chanserv",ERR_ERROR,"Found numeric %d on channel %s who doesn't exist.",
729 cp->users->content[i], cp->index->name->content);
730 continue;
731 }
732
733 if (IsService(np))
734 continue;
735
736 for (rbp=rcp->bans;rbp;rbp=rbp->next) {
737 if (((!rbp->expiry) || (rbp->expiry <= now)) &&
738 nickmatchban(np, rbp->cbp)) {
739 if (!nickbanned(np, cp)) {
740 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_ADD);
741 }
742 localkickuser(chanservnick,cp,np,rbp->reason?rbp->reason->content:"Banned.");
743 break;
744 }
745 }
746
747 if (rbp) /* If we broke out of above loop (due to kick) rbp will be set.. */
748 continue;
749
750 if (CIsEnforce(rcp)) {
751 for (cbp=cp->bans;cbp;cbp=cbp->next) {
752 if ((cbp->timeset>=rcp->lastbancheck) && nickmatchban(np, cbp))
753 localkickuser(chanservnick,cp,np,"Banned.");
754 }
755 rcp->lastbancheck=time(NULL);
756 }
757 }
758
759 localsetmodeflush(&changes,1);
760}
761
762/*
763 * cs_schedupdate:
764 * This function schedules an update check on a channel
765 */
766void cs_schedupdate(chanindex *cip, int mintime, int maxtime) {
767 int delay=mintime+(rand()%(maxtime-mintime));
768 regchan *rcp;
769
770 if (!(rcp=cip->exts[chanservext]) || CIsSuspended(rcp))
771 return;
772
773 if (rcp->checksched) {
774 deleteschedule(rcp->checksched, cs_timerfunc, cip);
775 }
776
777 rcp->checksched=scheduleoneshot(time(NULL)+delay, cs_timerfunc, cip);
778}
779
780/*
781 * cs_timerfunc:
782 * This function does several things:
783 * * Updates auto-limit and/or removes bans as necessary
784 * * Schedules the next timed call
785 * * Does any pending op/ban/mode checks
786 * It is safe to use either as a target for a schedule() call, or to call
787 * directly when parameters change (e.g. autolimit settings or ban expire
788 * timers).
789 * To force a limit update, set rcp->limit to 0..
790 */
791
792void cs_timerfunc(void *arg) {
793 chanindex *cip=arg;
794 channel *cp=cip->channel;
795 regchan *rcp;
796 chanban *cbp, *ncbp;
797 regban **rbh, *rbp;
798 time_t nextsched=0;
799 time_t now=time(NULL);
800 modechanges changes;
801
802 if (!(rcp=cip->exts[chanservext]))
803 return;
804
805 verifyregchan(rcp);
806
807 /* Always nullify the checksched even if the channel is suspended.. */
808 if (rcp->checksched) {
809 deleteschedule(rcp->checksched, cs_timerfunc, arg);
810 rcp->checksched=NULL;
811 }
812
813 if (!cp || CIsSuspended(rcp))
814 return;
815
816 /* Check if we need to leave the channel first */
817 if (chanservnick && CIsJoined(rcp) && cip->channel &&
818 cip->channel->users->totalusers==1 &&
819 getnumerichandlefromchanhash(cip->channel->users, chanservnick->numeric)) {
820
821 /* Only chanserv left in this channel */
822 if (now >= (rcp->lastpart + LINGERTIME)) {
823 /* Time to go */
334b567e 824 localpartchannel(chanservnick, cip->channel, "Empty Channel");
c86edd1d
Q
825 return;
826 } else {
827 if (!nextsched || nextsched > (rcp->lastpart + LINGERTIME))
828 nextsched=rcp->lastpart+LINGERTIME;
829 }
830 }
831
832 localsetmodeinit(&changes, cp, chanservnick);
833
834 if (CIsAutoLimit(rcp)) {
835 if (!rcp->limit || rcp->autoupdate <= now) {
836 /* Update limit.. */
837 rcp->limit=cp->users->totalusers+rcp->autolimit;
838 rcp->status |= QCSTAT_MODECHECK;
839
840 /* And set the schedule for the next update */
841 rcp->autoupdate = now + AUTOLIMIT_INTERVAL;
842 }
843
844 if (!nextsched || rcp->autoupdate <= nextsched)
845 nextsched=rcp->autoupdate;
846 }
847
848 if (rcp->status & QCSTAT_OPCHECK) {
849 rcp->status &= ~QCSTAT_OPCHECK;
850 cs_docheckopvoice(cp, &changes);
851 }
852
853 if (rcp->status & QCSTAT_MODECHECK) {
854 rcp->status &= ~QCSTAT_MODECHECK;
855 cs_docheckchanmodes(cp, &changes);
856 }
857
858 if (rcp->status & QCSTAT_BANCHECK) {
859 rcp->status &= ~QCSTAT_BANCHECK;
860 cs_checkbans(cp);
861 }
862
863 /* This ban check is AFTER docheckopvoice in case checkopvoice set a
864 * ban which we need to automatically remove later.. */
865
866 if (rcp->banduration) {
867 for (cbp=cp->bans;cbp;cbp=ncbp) {
868 ncbp=cbp->next;
869 if (cbp->timeset+rcp->banduration<=now) {
870 localdosetmode_ban(&changes, bantostring(cbp), MCB_DEL);
871 } else {
872 if (!nextsched || cbp->timeset+rcp->banduration <= nextsched) {
873 nextsched=rcp->banduration+cbp->timeset;
874 }
875 }
876 }
877 }
878
879 /* Check for expiry of registered bans */
880 if (rcp->bans) {
881 for (rbh=&(rcp->bans);*rbh;) {
882 rbp=*rbh;
883 verifyregchanban(rbp);
884 if (rbp->expiry && (rbp->expiry < now)) {
885 /* Expired ban */
886 /* Remove ban if it's on the channel (localdosetmode_ban will silently
887 * skip bans that don't exist) */
888 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_DEL);
889 /* Remove from database */
890 csdb_deleteban(rbp);
891 /* Remove from list */
892 (*rbh)=rbp->next;
893 /* Free ban/string and update setby refcount, and free actual regban */
894 freesstring(rbp->reason);
895 freechanban(rbp->cbp);
896 freeregban(rbp);
897 } else {
898 if (rbp->expiry && (!nextsched || rbp->expiry <= nextsched)) {
899 nextsched=rbp->expiry;
900 }
901 rbh=&(rbp->next);
902 }
903 }
904 }
905
906 if (nextsched)
907 rcp->checksched=scheduleoneshot(nextsched, cs_timerfunc, arg);
908
909 localsetmodeflush(&changes, 1);
910}
911
912void cs_removechannel(regchan *rcp) {
913 int i;
914 chanindex *cip;
915 regchanuser *rcup, *nrcup;
916 regban *rbp, *nrbp;
917
918 cip=rcp->index;
919
920 for (i=0;i<REGCHANUSERHASHSIZE;i++) {
921 for (rcup=rcp->regusers[i];rcup;rcup=nrcup) {
922 nrcup=rcup->nextbychan;
923 delreguserfromchannel(rcp, rcup->user);
924 freeregchanuser(rcup);
925 }
926 }
927
928 for (rbp=rcp->bans;rbp;rbp=nrbp) {
929 nrbp=rbp->next;
930 freesstring(rbp->reason);
931 freechanban(rbp->cbp);
932 freeregban(rbp);
933 }
934
935 rcp->bans=NULL;
936
937 if (rcp->checksched)
938 deleteschedule(rcp->checksched, cs_timerfunc, rcp->index);
939
940 if (cip->channel) {
941 rcp->flags=QCFLAG_SUSPENDED;
942 chanservjoinchan(cip->channel); /* Force off the channel */
943 }
944
945 csdb_deletechannel(rcp);
946
947 freesstring(rcp->welcome);
948 freesstring(rcp->topic);
949 freesstring(rcp->key);
950 freesstring(rcp->suspendreason);
951 freesstring(rcp->comment);
952
953 freeregchan(rcp);
954
955 cip->exts[chanservext]=NULL;
956 releasechanindex(cip);
957}
958
959void cs_removeuser(reguser *rup) {
960 int i;
961 regchanuser *rcup, *nrcup;
962 regchan *rcp;
963
964 /* Remove the user from all its channels */
965 for (rcup=rup->knownon;rcup;rcup=nrcup) {
966 nrcup=rcup->nextbyuser;
967 freesstring(rcup->info);
968 rcp=rcup->chan;
969
970 delreguserfromchannel(rcp, rup);
971
972 for (i=0;i<REGCHANUSERHASHSIZE;i++) {
973 if (rcp->regusers[i])
974 break;
975 }
976
977 if (i==REGCHANUSERHASHSIZE) {
978 /* There are no users left on this channel! */
979 cs_log(NULL, "DELCHAN %s (last user removed)",rcp->index->name->content);
980 cs_removechannel(rcp);
981 }
982
983 freeregchanuser(rcup);
984 }
985
e3805f60
P
986 if(rup->domain)
987 delreguserfrommaildomain(rup,rup->domain);
988 freesstring(rup->localpart);
c86edd1d
Q
989 freesstring(rup->email);
990 freesstring(rup->lastuserhost);
991 freesstring(rup->suspendreason);
992 freesstring(rup->comment);
993 freesstring(rup->info);
994
995 csdb_deleteuser(rup);
996
997 removereguserfromhash(rup);
998
999 if (rup->nicks) {
1000 rup->status |= QUSTAT_DEAD;
1001 } else {
1002 freereguser(rup);
1003 }
1004}
1005
1006int cs_bancheck(nick *np, channel *cp) {
1007 time_t now=time(NULL);
1008 regban **rbh, *rbp;
1009 modechanges changes;
1010 regchan *rcp;
1011
1012 if (!(rcp=cp->index->exts[chanservext]))
1013 return 0;
1014
1015 for (rbh=&(rcp->bans);*rbh;) {
1016 if ((*rbh)->expiry && ((*rbh)->expiry < now)) {
1017 /* Expired ban */
1018 csdb_deleteban(*rbh);
1019 rbp=*rbh;
1020 (*rbh)=rbp->next;
1021
1022 freesstring(rbp->reason);
1023 freechanban(rbp->cbp);
1024 freeregban(rbp);
1025 } else if (nickmatchban(np,(*rbh)->cbp)) {
1026 /* This user matches this ban.. */
1027 if (!nickbanned(np,cp)) {
1028 /* Only bother putting the ban on the channel if they're not banned already */
1029 /* (might be covered by this ban or a different one.. doesn't really matter */
1030 localsetmodeinit(&changes, cp, chanservnick);
1031 localdosetmode_ban(&changes, bantostring((*rbh)->cbp), MCB_ADD);
1032 localsetmodeflush(&changes, 1);
1033 cs_timerfunc(cp->index);
1034 }
1035 localkickuser(chanservnick, cp, np, (*rbh)->reason ? (*rbh)->reason->content : "Banned.");
1036 return 1;
1037 } else {
1038 rbh=&((*rbh)->next);
1039 }
1040 }
1041
1042 return 0;
1043}
1044
1045void cs_setregban(chanindex *cip, regban *rbp) {
1046 modechanges changes;
1047 int i;
1048 nick *np;
1049
1050 if (!cip->channel)
1051 return;
b263aa79 1052
c86edd1d
Q
1053 localsetmodeinit(&changes, cip->channel, chanservnick);
1054 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_ADD);
1055 localsetmodeflush(&changes, 1);
1056
1057 for (i=0;(cip->channel) && i<cip->channel->users->hashsize;i++) {
1058 if (cip->channel->users->content[i]!=nouser &&
1059 (np=getnickbynumeric(cip->channel->users->content[i])) &&
1060 !IsService(np) &&
1061 nickmatchban(np, rbp->cbp))
1062 localkickuser(chanservnick, cip->channel, np, rbp->reason ? rbp->reason->content : "Banned.");
1063 }
1064
1065 cs_timerfunc(cip);
1066}
1067
1068void cs_banuser(modechanges *changes, chanindex *cip, nick *np, const char *reason) {
1069 modechanges lchanges;
1070 char banmask[NICKLEN+USERLEN+HOSTLEN+3];
1071
1072 if (!cip->channel)
1073 return;
1074
1075 if (nickbanned(np, cip->channel)) {
1076 localkickuser(chanservnick, cip->channel, np, reason?reason:"Banned.");
1077 return;
1078 }
1079
1080 if (IsAccount(np)) {
1081 /* Ban their account.. */
1082 sprintf(banmask,"*!*@%s.%s",np->authname,HIS_HIDDENHOST);
1083 } else if (IsSetHost(np)) {
1084 /* sethosted: ban ident@host */
1085 sprintf(banmask,"*!%s@%s",np->shident->content,np->sethost->content);
1086 } else if (np->host->clonecount>3) {
1087 /* >3 clones, ban user@host */
1088 sprintf(banmask,"*!%s@%s",np->ident,np->host->name->content);
1089 } else {
1090 sprintf(banmask,"*!*@%s",np->host->name->content);
1091 }
1092
1093 if (!changes) {
1094 localsetmodeinit(&lchanges, cip->channel, chanservnick);
1095 localdosetmode_ban(&lchanges, banmask, MCB_ADD);
1096 localsetmodeflush(&lchanges, 1);
1097 } else {
1098 localdosetmode_ban(changes, banmask, MCB_ADD);
1099 }
1100
1101 localkickuser(chanservnick, cip->channel, np, reason?reason:"Banned.");
1102}
1103
b263aa79 1104/*
1105 * findreguser:
1106 * This function does the standard "nick or #user" lookup.
1107 * If "sender" is not NULL, a suitable error message will
1108 * be sent if the lookup fails.
1109 */
1110
1111reguser *findreguser(nick *sender, const char *str) {
1112 reguser *rup;
1113 nick *np;
1114
1115 if (!str || !*str)
1116 return NULL;
1117
1118 if (*str=='#') {
1119 if (str[1]=='\0') {
1120 if (sender)
1121 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1122 return NULL;
1123 }
1124 if (!(rup=findreguserbynick(str+1)) && sender)
1125 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1126 } else {
1127 if (!(np=getnickbynick(str))) {
1128 if (sender)
1129 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1130 return NULL;
1131 }
1132 if (!(rup=getreguserfromnick(np)) && sender)
1133 chanservstdmessage(sender, QM_USERNOTAUTHED, str);
1134 }
1135
1136 if (rup && (UIsSuspended(rup) || (rup->status & QUSTAT_DEAD))) {
1137 chanservstdmessage(sender, QM_USERHASBADAUTH, rup->username);
1138 return NULL;
1139 }
1140
1141 return rup;
1142}