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