]> jfr.im git - irc/quakenet/newserv.git/blame - chanserv/chanservuser.c
Add md5 again, add it to hmac too.
[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;
2df6316a 238 unsigned int i;
239 nick *np;
240 reguser *rup;
241 regchanuser *rcup;
242 flag_t themodes;
af87643b 243
a54e438d 244 /* Skip unregistered channels */
245 if (!(rcp=cp->index->exts[chanservext]))
246 return;
247
248 /* Check for a new timestamp */
249 if ((!rcp->ltimestamp) || (cp->timestamp < rcp->ltimestamp)) {
250 rcp->ltimestamp=cp->timestamp;
251 csdb_updatechanneltimestamp(rcp);
252 }
c86edd1d 253
a54e438d 254 /* We won't be doing any joining or parting if we're not online */
255 if (!chanservnick)
c86edd1d
Q
256 return;
257
258 if ((CIsSuspended(rcp) || !CIsJoined(rcp)) && getnumerichandlefromchanhash(cp->users, chanservnick->numeric)) {
334b567e
P
259 if(rcp->suspendreason) {
260 localpartchannel(chanservnick, cp, rcp->suspendreason->content);
261 } else {
262 localpartchannel(chanservnick, cp, NULL);
263 }
c86edd1d 264 }
2df6316a 265
266 /* Right, we are definately going to either join the channel or at least
267 * burst some modes onto it.
268 *
a54e438d 269 * We will try and burst our view of the world; if the timestamps are
270 * actually equal this will be mostly ignored and we will have to fix it
af87643b 271 * up later. For modes we use the forced modes, plus the default channel
272 * modes (unless any of those are explicitly denied) */
af87643b 273
2df6316a 274 /* By default, we set the forcemodes and the default modes, but never denymodes */
275 themodes = (CHANMODE_DEFAULT | rcp->forcemodes) & ~rcp->denymodes;
276
277 /* Now, if someone has just created a channel and we are going to set +i
278 * or +k on it, this will kick them off. This could be construed as a
279 * bit rude if it's their channel, so if there is only one person on the
280 * channel and they have a right to be there, burst with default modes
281 * only to avoid them being netrider kicked.
282 */
283 if (cp->users->totalusers==1) {
284 for (i=0;i<cp->users->hashsize;i++) {
285 if (cp->users->content[i] != nouser) {
286 if ((np=getnickbynumeric(cp->users->content[i]&CU_NUMERICMASK)) &&
287 (rup=getreguserfromnick(np)) &&
288 (rcup=findreguseronchannel(rcp,rup)) &&
289 CUKnown(rcup)) {
290 /* OK, there was one user, and they are known on this channel.
291 * Don't burst with +i or +k */
292 themodes &= ~(CHANMODE_INVITEONLY | CHANMODE_KEY);
af87643b 293 }
294 }
295 }
2df6316a 296 }
297
298 /* We should be on the channel - join with our nick */
299 if (!CIsSuspended(rcp) && CIsJoined(rcp) && !getnumerichandlefromchanhash(cp->users, chanservnick->numeric)) {
af87643b 300 /* If we pass the key parameter here but are not setting +k (see above)
301 * then localburstontochannel() will ignore the key */
302 localburstontochannel(cp, chanservnick, rcp->ltimestamp, themodes,
303 rcp->limit, (rcp->key)?rcp->key->content:NULL);
c86edd1d 304 }
2df6316a 305
306 /* We're not joining the channel - send the burst with no nick */
b263aa79 307 if (!CIsSuspended(rcp) && !CIsJoined(rcp) && (cp->timestamp > rcp->ltimestamp)) {
2df6316a 308 localburstontochannel(cp, NULL, rcp->ltimestamp, themodes,
309 rcp->limit, (rcp->key)?rcp->key->content:NULL);
b263aa79 310 }
c86edd1d
Q
311}
312
313void chanservstdmessage(nick *np, int messageid, ... ) {
314 char buf[5010];
315 char buf2[512];
316 int notice;
317 reguser *rup;
318 int language;
319 va_list va;
320 char *message;
321 char *bp2,*bp;
322 int len;
323
324 if (getreguserfromnick(np) == NULL) {
325 notice=1;
326 language=0;
327 } else {
328 rup=getreguserfromnick(np);
329 if(UIsNotice(rup)) {
330 notice=1;
331 } else {
332 notice=0;
333 }
334 language=rup->languageid;
335 }
336
337 if (csmessages[language][messageid]) {
338 message=csmessages[language][messageid]->content;
339 } else if (csmessages[0][messageid]) {
340 message=csmessages[0][messageid]->content;
341 } else {
342 message=defaultmessages[messageid];
343 }
344
345 va_start(va,messageid);
346 vsnprintf(buf,5000,message,va);
347 va_end(va);
348
349 len=0;
350 bp2=buf2;
351 for (bp=buf; ;bp++) {
352 /* We send something if we hit a \n, fill the buffer or run out of source */
353 if (*bp=='\n' || len>490 || !*bp) {
354 if (*bp && *bp!='\n') {
355 bp--;
356 }
357
358 *bp2='\0';
359
360 if (chanservnick && *buf2) {
361 if (notice) {
362 sendnoticetouser(chanservnick,np,"%s",buf2);
363 } else {
364 sendmessagetouser(chanservnick,np,"%s",buf2);
365 }
366 }
367
368 /* If we ran out of buffer, get out here */
369 if (!*bp)
370 break;
371
372 bp2=buf2;
373 len=0;
374 } else {
375 len++;
376 *bp2++=*bp;
377 }
378 }
379}
380
381void chanservsendmessage(nick *np, char *message, ... ) {
382 char buf[5010]; /* Very large buffer.. */
383 char buf2[512], *bp, *bp2;
384 int notice;
385 int len;
386 reguser *rup;
387
388 va_list va;
389
390 va_start(va,message);
391 vsnprintf(buf,5000,message,va);
392 va_end(va);
393
394 if (getreguserfromnick(np) == NULL) {
395 notice=1;
396 } else {
397 rup=getreguserfromnick(np);
398 if(UIsNotice(rup)) {
399 notice=1;
400 } else {
401 notice=0;
402 }
403 }
404
405 len=0;
406 bp2=buf2;
407 for (bp=buf; ;bp++) {
408 /* We send something if we hit a \n, fill the buffer or run out of source */
409 if (*bp=='\n' || len>490 || !*bp) {
410 if (*bp && *bp!='\n') {
411 bp--;
412 }
413
414 *bp2='\0';
415
416 if (chanservnick && *buf2) {
417 if (notice) {
418 sendnoticetouser(chanservnick,np,"%s",buf2);
419 } else {
420 sendmessagetouser(chanservnick,np,"%s",buf2);
421 }
422 }
423
424 /* If we ran out of buffer, get out here */
425 if (!*bp)
426 break;
427
428 bp2=buf2;
429 len=0;
430 } else {
431 len++;
432 *bp2++=*bp;
433 }
434 }
435}
436
437void chanservwallmessage(char *message, ... ) {
438 char buf[5010]; /* Very large buffer.. */
439 va_list va;
440 nick *np;
441 unsigned int i=0;
442
443 va_start(va,message);
444 vsnprintf(buf,5000,message,va);
445 va_end(va);
446
447 /* Scan for users */
448 for (i=0;i<NICKHASHSIZE;i++)
449 for (np=nicktable[i];np;np=np->next)
450 if (IsOper(np))
451 chanservsendmessage(np, "%s", buf);
452}
453
454void chanservkillstdmessage(nick *target, int messageid, ... ) {
455 char buf[512];
456 int language;
457 char* message;
458 va_list va;
459 reguser *rup;
460
461 if (!(rup=getreguserfromnick(target)))
462 language=0;
463 else
464 language=rup->languageid;
465
466 if (csmessages[language][messageid])
467 message=csmessages[language][messageid]->content;
468 else if (csmessages[0][messageid])
469 message=csmessages[0][messageid]->content;
470 else
471 message=defaultmessages[messageid];
472
473 va_start(va, messageid);
474 vsnprintf(buf, 511, message, va);
475 va_end(va);
476 killuser(chanservnick, target, buf);
477}
478
479int checkmasterpassword(reguser *rup, const char *pass) {
480 if (!strncmp(rup->masterpass, pass, PASSLEN))
481 return 1;
482 return 0;
483}
484
485int checkpassword(reguser *rup, const char *pass) {
486 if (!strncmp(rup->password, pass, PASSLEN))
487 return 1;
488 return 0;
489}
490
491int setmasterpassword(reguser *rup, const char *pass) {
492 strncpy(rup->masterpass, pass, PASSLEN);
493 rup->masterpass[PASSLEN]='\0';
494 return 1;
495}
496
497int setpassword(reguser *rup, const char *pass) {
498 strncpy(rup->password, pass, PASSLEN);
499 rup->password[PASSLEN]='\0';
500 return 1;
501}
502
503void cs_checknick(nick *np) {
504 activeuser* aup;
505 reguser *rup;
506 nicklist *nlp;
507 char userhost[USERLEN+HOSTLEN+3];
508
509 if (!(aup=getactiveuserfromnick(np))) {
510 aup=getactiveuser();
511 np->exts[chanservnext]=aup;
512 }
513
514 assert(getactiveuserfromnick(np));
515
516 if (IsAccount(np)) {
517 if ((rup=findreguserbynick(np->authname))!=NULL) {
518 aup->rup=rup;
519 nlp=getnicklist();
520 nlp->np=np;
521 nlp->next=rup->nicks;
522 rup->nicks=nlp;
32562540 523 triggerhook(HOOK_CHANSERV_SETUSERID, np);
c86edd1d
Q
524 cs_doallautomodes(np);
525 } else {
526 aup->rup=NULL;
527 /* Auto create user.. */
528 rup=getreguser();
529 rup->status=0;
46d48f37 530 rup->ID=++lastuserID;
c86edd1d
Q
531 strncpy(rup->username,np->authname,NICKLEN); rup->username[NICKLEN]='\0';
532 rup->created=time(NULL);
533 rup->lastauth=time(NULL);
534 rup->lastemailchange=0;
535 rup->flags=QUFLAG_NOTICE;
536 rup->languageid=0;
537 rup->suspendby=0;
fa350b40 538 rup->suspendexp=0;
c86edd1d
Q
539 rup->password[0]='\0';
540 rup->masterpass[0]='\0';
541 rup->email=NULL;
e3805f60
P
542 rup->localpart=NULL;
543 rup->domain=NULL;
c86edd1d
Q
544 rup->info=NULL;
545 sprintf(userhost,"%s@%s",np->ident,np->host->name->content);
546 rup->lastuserhost=getsstring(userhost,USERLEN+HOSTLEN+1);
547 rup->suspendreason=NULL;
548 rup->comment=NULL;
549 rup->knownon=NULL;
550 rup->checkshd=NULL;
551 rup->stealcount=0;
552 rup->fakeuser=NULL;
553 rup->nicks=getnicklist();
554 rup->nicks->np=np;
555 rup->nicks->next=NULL;
556 addregusertohash(rup);
557
558 csdb_createuser(rup);
559 aup->rup=rup;
560 }
561 } else {
562 aup->rup=NULL;
563 }
564
565 cs_checknickbans(np);
566}
567
568void cs_checkchanmodes(channel *cp) {
569 modechanges changes;
570
571 localsetmodeinit (&changes, cp, chanservnick);
572 cs_docheckchanmodes(cp, &changes);
573 localsetmodeflush (&changes, 1);
574}
575
576void cs_docheckchanmodes(channel *cp, modechanges *changes) {
577 regchan *rcp;
578
579 if (!cp)
580 return;
581
582 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
583 return;
584
585 /* Take care of the simple modes */
586 localdosetmode_simple(changes, rcp->forcemodes & ~(cp->flags), rcp->denymodes & cp->flags);
587
588 /* Check for forced key. Note that we ALWAYS call localdosetmode_key
589 * in case the wrong key is set atm */
590 if (rcp->forcemodes & CHANMODE_KEY) {
591 if (!rcp->key) {
592 Error("chanserv",ERR_WARNING,"Key forced but no key specified for %s: cleared forcemode.",rcp->index->name->content);
593 rcp->forcemodes &= ~CHANMODE_KEY;
a54e438d 594 csdb_updatechannel(rcp);
c86edd1d
Q
595 } else {
596 localdosetmode_key(changes, rcp->key->content, MCB_ADD);
597 }
598 }
599
600 /* Check for denied key */
601 if ((rcp->denymodes & CHANMODE_KEY) && IsKey(cp)) {
602 localdosetmode_key(changes, NULL, MCB_DEL);
603 }
604
605 /* Check for forced limit. Always call in case of wrong limit */
606 if (rcp->forcemodes & CHANMODE_LIMIT) {
607 localdosetmode_limit(changes, rcp->limit, MCB_ADD);
608 }
609}
610
611void cs_docheckopvoice(channel *cp, modechanges *changes) {
612 regchan *rcp;
613 reguser *rup;
614 regchanuser *rcup;
615 nick *np;
616 int i;
617
618 if (!cp)
619 return;
620
621 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
622 return;
623
624 for (i=0;i<cp->users->hashsize;i++) {
625 if (cp->users->content[i]==nouser)
626 continue;
627
628 if ((np=getnickbynumeric(cp->users->content[i]))==NULL) {
629 Error("chanserv",ERR_ERROR,"Found non-existent numeric %d on channel %s",cp->users->content[i],
630 cp->index->name->content);
631 continue;
632 }
633
634 if ((rup=getreguserfromnick(np)))
635 rcup=findreguseronchannel(rcp,rup);
636 else
637 rcup=NULL;
638
639 if (rcup && CUIsBanned(rcup) && !IsService(np)) {
640 cs_banuser(changes, cp->index, np, NULL);
641 continue;
642 }
643
644 if (!IsService(np) && CIsKnownOnly(rcp) && !(rcup && CUKnown(rcup))) {
645 cs_banuser(changes, cp->index, np, "Authorised users only.");
646 continue;
647 }
648
649 if ((cp->users->content[i] & CUMODE_OP) && !IsService(np)) {
650 if ((CIsBitch(rcp) && (!rcup || !CUHasOpPriv(rcup))) ||
651 (rcup && CUIsDeny(rcup)))
652 localdosetmode_nick(changes, np, MC_DEOP);
653 } else {
654 if (rcup && (CUIsProtect(rcup) || CIsProtect(rcp)) && CUIsOp(rcup) && !CUIsDeny(rcup))
655 localdosetmode_nick(changes, np, MC_OP);
656 }
657
658 if (cp->users->content[i] & CUMODE_VOICE) {
659 if (rcup && CUIsQuiet(rcup))
660 localdosetmode_nick(changes, np, MC_DEVOICE);
661 } else {
662 if (rcup && (CUIsProtect(rcup) || CIsProtect(rcp)) && CUIsVoice(rcup) && !CUIsQuiet(rcup) && !(cp->users->content[i] & CUMODE_OP))
663 localdosetmode_nick(changes, np, MC_VOICE);
664 }
665 }
666}
667
668void cs_doallautomodes(nick *np) {
669 reguser *rup;
670 regchanuser *rcup;
671 unsigned long *lp;
672 modechanges changes;
673
674 if (!(rup=getreguserfromnick(np)))
675 return;
676
677 for (rcup=rup->knownon;rcup;rcup=rcup->nextbyuser) {
678 if (rcup->chan->index->channel) {
679 /* Channel exists */
680 if ((lp=getnumerichandlefromchanhash(rcup->chan->index->channel->users, np->numeric))) {
db804373
P
681 /* User is on channel.. */
682
683 /* Update last use time */
684 rcup->usetime=getnettime();
685
c86edd1d
Q
686 localsetmodeinit(&changes, rcup->chan->index->channel, chanservnick);
687 if (*lp & CUMODE_OP) {
688 if (!IsService(np) && (CUIsDeny(rcup) || (CIsBitch(rcup->chan) && !CUHasOpPriv(rcup))))
689 localdosetmode_nick(&changes, np, MC_DEOP);
690 } else {
691 if (!CUIsDeny(rcup) && CUIsOp(rcup) &&
692 (CUIsProtect(rcup) || CIsProtect(rcup->chan) || CUIsAutoOp(rcup)))
693 localdosetmode_nick(&changes, np, MC_OP);
694 }
695
696 if (*lp & CUMODE_VOICE) {
697 if (CUIsQuiet(rcup))
698 localdosetmode_nick(&changes, np, MC_DEVOICE);
699 } else {
700 if (!CUIsQuiet(rcup) && CUIsVoice(rcup) && !(*lp & CUMODE_OP) &&
701 (CUIsProtect(rcup) || CIsProtect(rcup->chan) || CUIsAutoVoice(rcup)))
702 localdosetmode_nick(&changes, np, MC_VOICE);
703 }
704 localsetmodeflush(&changes, 1);
705 } else {
706 /* Channel exists but user is not joined: invite if they are +j-b */
707 if (CUIsAutoInvite(rcup) && CUKnown(rcup) && !CUIsBanned(rcup)) {
708 localinvite(chanservnick, rcup->chan->index->channel, np);
709 }
710 }
711 }
712 }
713}
714
715void cs_checknickbans(nick *np) {
716 channel **ca;
717 regchan *rcp;
718 int i,j;
719
720 if (IsService(np))
721 return;
722
723 /* Avoid races: memcpy the channel array */
724 i=np->channels->cursi;
725 ca=(channel **)malloc(i*sizeof(channel *));
726 memcpy(ca, np->channels->content,i*sizeof(channel *));
727
728 for (j=0;j<i;j++) {
729 if ((rcp=ca[j]->index->exts[chanservext]) && !CIsSuspended(rcp) &&
730 CIsEnforce(rcp) && nickbanned(np, ca[j]))
731 localkickuser(chanservnick, ca[j], np, "Banned.");
732 }
733
734 free(ca);
735}
736
737void cs_checkbans(channel *cp) {
738 regchan *rcp;
739 int i;
740 nick *np;
741 chanban *cbp;
742 regban *rbp;
743 time_t now;
744 modechanges changes;
745
746 if (!cp)
747 return;
748
749 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
750 return;
751
752 now=time(NULL);
753
754 localsetmodeinit(&changes, cp, chanservnick);
755
756 for (i=0;i<cp->users->hashsize;i++) {
757 if (cp->users->content[i]==nouser)
758 continue;
759
760 if ((np=getnickbynumeric(cp->users->content[i]))==NULL) {
761 Error("chanserv",ERR_ERROR,"Found numeric %d on channel %s who doesn't exist.",
762 cp->users->content[i], cp->index->name->content);
763 continue;
764 }
765
766 if (IsService(np))
767 continue;
768
769 for (rbp=rcp->bans;rbp;rbp=rbp->next) {
770 if (((!rbp->expiry) || (rbp->expiry <= now)) &&
771 nickmatchban(np, rbp->cbp)) {
772 if (!nickbanned(np, cp)) {
773 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_ADD);
774 }
775 localkickuser(chanservnick,cp,np,rbp->reason?rbp->reason->content:"Banned.");
776 break;
777 }
778 }
779
780 if (rbp) /* If we broke out of above loop (due to kick) rbp will be set.. */
781 continue;
782
783 if (CIsEnforce(rcp)) {
784 for (cbp=cp->bans;cbp;cbp=cbp->next) {
785 if ((cbp->timeset>=rcp->lastbancheck) && nickmatchban(np, cbp))
786 localkickuser(chanservnick,cp,np,"Banned.");
787 }
788 rcp->lastbancheck=time(NULL);
789 }
790 }
791
792 localsetmodeflush(&changes,1);
793}
794
795/*
796 * cs_schedupdate:
797 * This function schedules an update check on a channel
798 */
799void cs_schedupdate(chanindex *cip, int mintime, int maxtime) {
800 int delay=mintime+(rand()%(maxtime-mintime));
801 regchan *rcp;
802
803 if (!(rcp=cip->exts[chanservext]) || CIsSuspended(rcp))
804 return;
805
806 if (rcp->checksched) {
807 deleteschedule(rcp->checksched, cs_timerfunc, cip);
808 }
809
810 rcp->checksched=scheduleoneshot(time(NULL)+delay, cs_timerfunc, cip);
811}
812
813/*
814 * cs_timerfunc:
815 * This function does several things:
816 * * Updates auto-limit and/or removes bans as necessary
817 * * Schedules the next timed call
818 * * Does any pending op/ban/mode checks
819 * It is safe to use either as a target for a schedule() call, or to call
820 * directly when parameters change (e.g. autolimit settings or ban expire
821 * timers).
822 * To force a limit update, set rcp->limit to 0..
823 */
824
825void cs_timerfunc(void *arg) {
826 chanindex *cip=arg;
827 channel *cp=cip->channel;
828 regchan *rcp;
829 chanban *cbp, *ncbp;
830 regban **rbh, *rbp;
831 time_t nextsched=0;
832 time_t now=time(NULL);
833 modechanges changes;
834
835 if (!(rcp=cip->exts[chanservext]))
836 return;
837
838 verifyregchan(rcp);
839
840 /* Always nullify the checksched even if the channel is suspended.. */
841 if (rcp->checksched) {
842 deleteschedule(rcp->checksched, cs_timerfunc, arg);
843 rcp->checksched=NULL;
844 }
845
846 if (!cp || CIsSuspended(rcp))
847 return;
848
849 /* Check if we need to leave the channel first */
850 if (chanservnick && CIsJoined(rcp) && cip->channel &&
851 cip->channel->users->totalusers==1 &&
852 getnumerichandlefromchanhash(cip->channel->users, chanservnick->numeric)) {
853
854 /* Only chanserv left in this channel */
855 if (now >= (rcp->lastpart + LINGERTIME)) {
856 /* Time to go */
334b567e 857 localpartchannel(chanservnick, cip->channel, "Empty Channel");
c86edd1d
Q
858 return;
859 } else {
860 if (!nextsched || nextsched > (rcp->lastpart + LINGERTIME))
861 nextsched=rcp->lastpart+LINGERTIME;
862 }
863 }
864
865 localsetmodeinit(&changes, cp, chanservnick);
866
867 if (CIsAutoLimit(rcp)) {
868 if (!rcp->limit || rcp->autoupdate <= now) {
869 /* Update limit.. */
870 rcp->limit=cp->users->totalusers+rcp->autolimit;
871 rcp->status |= QCSTAT_MODECHECK;
872
873 /* And set the schedule for the next update */
874 rcp->autoupdate = now + AUTOLIMIT_INTERVAL;
875 }
876
877 if (!nextsched || rcp->autoupdate <= nextsched)
878 nextsched=rcp->autoupdate;
879 }
880
881 if (rcp->status & QCSTAT_OPCHECK) {
882 rcp->status &= ~QCSTAT_OPCHECK;
883 cs_docheckopvoice(cp, &changes);
884 }
885
886 if (rcp->status & QCSTAT_MODECHECK) {
887 rcp->status &= ~QCSTAT_MODECHECK;
888 cs_docheckchanmodes(cp, &changes);
889 }
890
891 if (rcp->status & QCSTAT_BANCHECK) {
892 rcp->status &= ~QCSTAT_BANCHECK;
893 cs_checkbans(cp);
894 }
895
896 /* This ban check is AFTER docheckopvoice in case checkopvoice set a
897 * ban which we need to automatically remove later.. */
898
899 if (rcp->banduration) {
900 for (cbp=cp->bans;cbp;cbp=ncbp) {
901 ncbp=cbp->next;
902 if (cbp->timeset+rcp->banduration<=now) {
903 localdosetmode_ban(&changes, bantostring(cbp), MCB_DEL);
904 } else {
905 if (!nextsched || cbp->timeset+rcp->banduration <= nextsched) {
906 nextsched=rcp->banduration+cbp->timeset;
907 }
908 }
909 }
910 }
911
912 /* Check for expiry of registered bans */
913 if (rcp->bans) {
914 for (rbh=&(rcp->bans);*rbh;) {
915 rbp=*rbh;
916 verifyregchanban(rbp);
917 if (rbp->expiry && (rbp->expiry < now)) {
918 /* Expired ban */
919 /* Remove ban if it's on the channel (localdosetmode_ban will silently
920 * skip bans that don't exist) */
921 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_DEL);
922 /* Remove from database */
923 csdb_deleteban(rbp);
924 /* Remove from list */
925 (*rbh)=rbp->next;
926 /* Free ban/string and update setby refcount, and free actual regban */
927 freesstring(rbp->reason);
928 freechanban(rbp->cbp);
929 freeregban(rbp);
930 } else {
931 if (rbp->expiry && (!nextsched || rbp->expiry <= nextsched)) {
932 nextsched=rbp->expiry;
933 }
934 rbh=&(rbp->next);
935 }
936 }
937 }
938
939 if (nextsched)
940 rcp->checksched=scheduleoneshot(nextsched, cs_timerfunc, arg);
941
942 localsetmodeflush(&changes, 1);
943}
944
945void cs_removechannel(regchan *rcp) {
946 int i;
947 chanindex *cip;
948 regchanuser *rcup, *nrcup;
949 regban *rbp, *nrbp;
950
951 cip=rcp->index;
952
953 for (i=0;i<REGCHANUSERHASHSIZE;i++) {
954 for (rcup=rcp->regusers[i];rcup;rcup=nrcup) {
955 nrcup=rcup->nextbychan;
956 delreguserfromchannel(rcp, rcup->user);
957 freeregchanuser(rcup);
958 }
959 }
960
961 for (rbp=rcp->bans;rbp;rbp=nrbp) {
962 nrbp=rbp->next;
963 freesstring(rbp->reason);
964 freechanban(rbp->cbp);
965 freeregban(rbp);
966 }
967
968 rcp->bans=NULL;
969
970 if (rcp->checksched)
971 deleteschedule(rcp->checksched, cs_timerfunc, rcp->index);
972
973 if (cip->channel) {
974 rcp->flags=QCFLAG_SUSPENDED;
975 chanservjoinchan(cip->channel); /* Force off the channel */
976 }
977
978 csdb_deletechannel(rcp);
979
980 freesstring(rcp->welcome);
981 freesstring(rcp->topic);
982 freesstring(rcp->key);
983 freesstring(rcp->suspendreason);
984 freesstring(rcp->comment);
985
986 freeregchan(rcp);
987
988 cip->exts[chanservext]=NULL;
989 releasechanindex(cip);
990}
991
992void cs_removeuser(reguser *rup) {
993 int i;
994 regchanuser *rcup, *nrcup;
995 regchan *rcp;
996
997 /* Remove the user from all its channels */
998 for (rcup=rup->knownon;rcup;rcup=nrcup) {
999 nrcup=rcup->nextbyuser;
1000 freesstring(rcup->info);
1001 rcp=rcup->chan;
1002
1003 delreguserfromchannel(rcp, rup);
1004
1005 for (i=0;i<REGCHANUSERHASHSIZE;i++) {
1006 if (rcp->regusers[i])
1007 break;
1008 }
1009
1010 if (i==REGCHANUSERHASHSIZE) {
1011 /* There are no users left on this channel! */
1012 cs_log(NULL, "DELCHAN %s (last user removed)",rcp->index->name->content);
1013 cs_removechannel(rcp);
1014 }
1015
1016 freeregchanuser(rcup);
1017 }
1018
e3805f60
P
1019 if(rup->domain)
1020 delreguserfrommaildomain(rup,rup->domain);
1021 freesstring(rup->localpart);
c86edd1d
Q
1022 freesstring(rup->email);
1023 freesstring(rup->lastuserhost);
1024 freesstring(rup->suspendreason);
1025 freesstring(rup->comment);
1026 freesstring(rup->info);
1027
1028 csdb_deleteuser(rup);
1029
1030 removereguserfromhash(rup);
1031
1032 if (rup->nicks) {
1033 rup->status |= QUSTAT_DEAD;
1034 } else {
1035 freereguser(rup);
1036 }
1037}
1038
1039int cs_bancheck(nick *np, channel *cp) {
1040 time_t now=time(NULL);
1041 regban **rbh, *rbp;
1042 modechanges changes;
1043 regchan *rcp;
1044
1045 if (!(rcp=cp->index->exts[chanservext]))
1046 return 0;
1047
1048 for (rbh=&(rcp->bans);*rbh;) {
1049 if ((*rbh)->expiry && ((*rbh)->expiry < now)) {
1050 /* Expired ban */
1051 csdb_deleteban(*rbh);
1052 rbp=*rbh;
1053 (*rbh)=rbp->next;
1054
1055 freesstring(rbp->reason);
1056 freechanban(rbp->cbp);
1057 freeregban(rbp);
1058 } else if (nickmatchban(np,(*rbh)->cbp)) {
1059 /* This user matches this ban.. */
1060 if (!nickbanned(np,cp)) {
1061 /* Only bother putting the ban on the channel if they're not banned already */
1062 /* (might be covered by this ban or a different one.. doesn't really matter */
1063 localsetmodeinit(&changes, cp, chanservnick);
1064 localdosetmode_ban(&changes, bantostring((*rbh)->cbp), MCB_ADD);
1065 localsetmodeflush(&changes, 1);
1066 cs_timerfunc(cp->index);
1067 }
1068 localkickuser(chanservnick, cp, np, (*rbh)->reason ? (*rbh)->reason->content : "Banned.");
1069 return 1;
1070 } else {
1071 rbh=&((*rbh)->next);
1072 }
1073 }
1074
1075 return 0;
1076}
1077
1078void cs_setregban(chanindex *cip, regban *rbp) {
1079 modechanges changes;
1080 int i;
1081 nick *np;
1082
1083 if (!cip->channel)
1084 return;
b263aa79 1085
c86edd1d
Q
1086 localsetmodeinit(&changes, cip->channel, chanservnick);
1087 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_ADD);
1088 localsetmodeflush(&changes, 1);
1089
1090 for (i=0;(cip->channel) && i<cip->channel->users->hashsize;i++) {
1091 if (cip->channel->users->content[i]!=nouser &&
1092 (np=getnickbynumeric(cip->channel->users->content[i])) &&
1093 !IsService(np) &&
1094 nickmatchban(np, rbp->cbp))
1095 localkickuser(chanservnick, cip->channel, np, rbp->reason ? rbp->reason->content : "Banned.");
1096 }
1097
1098 cs_timerfunc(cip);
1099}
1100
1101void cs_banuser(modechanges *changes, chanindex *cip, nick *np, const char *reason) {
1102 modechanges lchanges;
1103 char banmask[NICKLEN+USERLEN+HOSTLEN+3];
1104
1105 if (!cip->channel)
1106 return;
1107
1108 if (nickbanned(np, cip->channel)) {
1109 localkickuser(chanservnick, cip->channel, np, reason?reason:"Banned.");
1110 return;
1111 }
1112
1113 if (IsAccount(np)) {
1114 /* Ban their account.. */
1115 sprintf(banmask,"*!*@%s.%s",np->authname,HIS_HIDDENHOST);
1116 } else if (IsSetHost(np)) {
1117 /* sethosted: ban ident@host */
1118 sprintf(banmask,"*!%s@%s",np->shident->content,np->sethost->content);
1119 } else if (np->host->clonecount>3) {
1120 /* >3 clones, ban user@host */
1121 sprintf(banmask,"*!%s@%s",np->ident,np->host->name->content);
1122 } else {
1123 sprintf(banmask,"*!*@%s",np->host->name->content);
1124 }
1125
1126 if (!changes) {
1127 localsetmodeinit(&lchanges, cip->channel, chanservnick);
1128 localdosetmode_ban(&lchanges, banmask, MCB_ADD);
1129 localsetmodeflush(&lchanges, 1);
1130 } else {
1131 localdosetmode_ban(changes, banmask, MCB_ADD);
1132 }
1133
1134 localkickuser(chanservnick, cip->channel, np, reason?reason:"Banned.");
1135}
1136
b263aa79 1137/*
1138 * findreguser:
1139 * This function does the standard "nick or #user" lookup.
1140 * If "sender" is not NULL, a suitable error message will
1141 * be sent if the lookup fails.
1142 */
1143
1144reguser *findreguser(nick *sender, const char *str) {
1145 reguser *rup;
1146 nick *np;
1147
1148 if (!str || !*str)
1149 return NULL;
1150
1151 if (*str=='#') {
1152 if (str[1]=='\0') {
1153 if (sender)
1154 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1155 return NULL;
1156 }
1157 if (!(rup=findreguserbynick(str+1)) && sender)
1158 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1159 } else {
1160 if (!(np=getnickbynick(str))) {
1161 if (sender)
1162 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1163 return NULL;
1164 }
1165 if (!(rup=getreguserfromnick(np)) && sender)
1166 chanservstdmessage(sender, QM_USERNOTAUTHED, str);
1167 }
1168
1169 if (rup && (UIsSuspended(rup) || (rup->status & QUSTAT_DEAD))) {
1170 chanservstdmessage(sender, QM_USERHASBADAUTH, rup->username);
1171 return NULL;
1172 }
1173
1174 return rup;
1175}