]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservuser.c
47f432a04ab4d59f63cfb080ec28e94bb23dc35d
[irc/quakenet/newserv.git] / chanserv / chanservuser.c
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
9 #include "../core/hooks.h"
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 #include "../lib/irc_string.h"
20
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25
26 nick *chanservnick;
27 CommandTree *cscommands;
28 CommandTree *csctcpcommands;
29
30 /* Local prototypes */
31 void chanservuserhandler(nick *target, int message, void **params);
32
33 void chanservreguser(void *arg) {
34 sstring *csnick,*csuser,*cshost,*csrealname,*csaccount;
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 csaccount=getcopyconfigitem("chanserv","account",csnick&&csnick->content[0]?csnick->content:"Q",ACCOUNTLEN);
44
45 Error("chanserv",ERR_INFO,"Connecting %s...",csnick->content);
46
47 chanservnick=registerlocaluser(csnick->content,csuser->content,cshost->content,
48 csrealname->content,csaccount->content,
49 UMODE_INV|UMODE_SERVICE|UMODE_DEAF|UMODE_OPER|UMODE_ACCOUNT,
50 &chanservuserhandler);
51
52 freesstring(csnick);
53 freesstring(csuser);
54 freesstring(cshost);
55 freesstring(csrealname);
56 freesstring(csaccount);
57
58 /* Now join channels */
59 for (i=0;i<CHANNELHASHSIZE;i++) {
60 for (cip=chantable[i];cip;cip=cip->next) {
61 if (cip->channel && (rcp=cip->exts[chanservext]) && !CIsSuspended(rcp)) {
62 /* This will do timestamp faffing even if it won't actually join */
63 chanservjoinchan(cip->channel);
64 /* Do a check at some future time.. */
65 cs_schedupdate(cip, 1, 5);
66 rcp->status |= (QCSTAT_OPCHECK | QCSTAT_MODECHECK | QCSTAT_BANCHECK);
67 if (CIsForceTopic(rcp) || CIsTopicSave(rcp))
68 localsettopic(chanservnick, cip->channel, (rcp->topic) ? rcp->topic->content : "");
69 }
70 }
71 }
72
73 Error("chanserv",ERR_INFO,"Loaded and joined channels.");
74
75 if (chanserv_init_status == CS_INIT_NOUSER) {
76 /* If this is the first time, perform last init tasks */
77 chanserv_finalinit();
78 }
79 }
80
81 void chanservuserhandler(nick *target, int message, void **params) {
82 nick *sender;
83 char *msg;
84 Command *cmd;
85 char *cargv[30];
86 int cargc;
87 reguser *rup;
88 char *chp;
89
90 switch(message) {
91 case LU_KILLED:
92 scheduleoneshot(time(NULL),&chanservreguser,NULL);
93 chanservnick=NULL;
94 break;
95
96 case LU_PRIVMSG:
97 case LU_SECUREMSG:
98 sender=(nick *)params[0];
99 msg=(char *)params[1];
100
101 if (!(cargc=splitline(msg,cargv,30,0)))
102 return; /* Ignore blank lines */
103
104 if (cargv[0][0]==1) {
105 /* CTCP */
106 for (chp=cargv[0]+1;*chp;chp++) {
107 if (*chp=='\001') {
108 *chp='\0';
109 break;
110 }
111 }
112 cmd=findcommandintree(csctcpcommands, cargv[0]+1, 1);
113 if (cmd) {
114 cmd->calls++;
115 rejoinline(cargv[1],cargc-1);
116 cmd->handler((void *)sender, cargc-1, &(cargv[1]));
117 }
118 } else {
119 cmd=findcommandintree(cscommands, cargv[0], 1);
120
121 if (!cmd) {
122 chanservstdmessage(sender, QM_UNKNOWNCMD, cargv[0]);
123 break;
124 }
125
126 if ((cmd->level & QCMD_SECURE) && (message != LU_SECUREMSG)) {
127 chanservstdmessage(sender, QM_SECUREONLY, cargv[0], chanservnick->nick, myserver->content);
128 break;
129 }
130
131 if ((cmd->level & QCMD_AUTHED)) {
132 if (!(rup=getreguserfromnick(sender))) {
133 chanservstdmessage(sender, QM_AUTHEDONLY, cargv[0]);
134 break;
135 }
136 if (UIsSuspended(rup) || (rup->status & QUSTAT_DEAD)) {
137 chanservstdmessage(sender, QM_BADAUTH, cargv[0]);
138 break;
139 }
140 }
141
142 if ((cmd->level & QCMD_NOTAUTHED) && (getreguserfromnick(sender))) {
143 chanservstdmessage(sender, QM_UNAUTHEDONLY, cargv[0]);
144 break;
145 }
146
147 if ((cmd->level & QCMD_STAFF) &&
148 (!(rup=getreguserfromnick(sender)) || !UHasStaffPriv(rup))) {
149 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
150 break;
151 }
152
153 if ((cmd->level & QCMD_HELPER) &&
154 (!(rup=getreguserfromnick(sender)) || !UHasHelperPriv(rup))) {
155 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
156 break;
157 }
158
159 if ((cmd->level & QCMD_OPER) &&
160 (!IsOper(sender) || !(rup=getreguserfromnick(sender)) || !UHasOperPriv(rup))) {
161 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
162 break;
163 }
164
165 if ((cmd->level & QCMD_ADMIN) &&
166 (!IsOper(sender) || !(rup=getreguserfromnick(sender)) || !UHasAdminPriv(rup))) {
167 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
168 break;
169 }
170
171 if ((cmd->level & QCMD_DEV) &&
172 (!IsOper(sender) || !(rup=getreguserfromnick(sender)) || !UIsDev(rup))) {
173 chanservstdmessage(sender, QM_NOACCESS, cargv[0]);
174 break;
175 }
176
177 if ((cmd->level & QCMD_ACHIEVEMENTS) && !UIsDev(rup) &&
178 ((time(NULL) < ACHIEVEMENTS_START) ||
179 ((time(NULL) > ACHIEVEMENTS_END) && !UIsAchievements(rup)))) {
180 chanservstdmessage(sender, QM_UNKNOWNCMD, cargv[0]);
181 break;
182 }
183
184 if ((cmd->level & QCMD_TITLES) && !UIsDev(rup) &&
185 ((time(NULL) < ACHIEVEMENTS_START) ||
186 (time(NULL) > ACHIEVEMENTS_END))) {
187 chanservstdmessage(sender, QM_UNKNOWNCMD, cargv[0]);
188 break;
189 }
190
191 cmd->calls++;
192
193 if (cmd->maxparams < (cargc-1)) {
194 rejoinline(cargv[cmd->maxparams],cargc-(cmd->maxparams));
195 cargc=(cmd->maxparams)+1;
196 }
197
198 cmd->handler((void *)sender, cargc-1, &(cargv[1]));
199
200 triggerhook(HOOK_CHANSERV_CMD, sender);
201 }
202 break;
203
204 default:
205 break;
206 }
207 }
208
209 void chanservcommandinit() {
210 cscommands=newcommandtree();
211 csctcpcommands=newcommandtree();
212 }
213
214 void chanservcommandclose() {
215 destroycommandtree(cscommands);
216 destroycommandtree(csctcpcommands);
217 }
218
219 void chanservaddcommand(char *command, int flags, int maxparams, CommandHandler handler, char *description, const char *help) {
220 Command *newcmd;
221 cmdsummary *summary;
222
223 newcmd=addcommandtotree(cscommands, command, flags, maxparams, handler);
224 /* Allocate a summary record to put the description in */
225 summary=(cmdsummary *)malloc(sizeof(cmdsummary));
226 memset((void *)summary,0,sizeof(cmdsummary));
227
228 summary->def=getsstring(description, 250);
229 summary->defhelp=(char *)help; /* Assume that help is a constant */
230
231 newcmd->ext=(void *)summary;
232 loadcommandsummary(newcmd);
233 }
234
235 void chanservaddctcpcommand(char *command, CommandHandler handler) {
236 addcommandtotree(csctcpcommands, command, 0, 1, handler);
237 }
238
239 void chanservremovectcpcommand(char *command, CommandHandler handler) {
240 deletecommandfromtree(csctcpcommands, command, handler);
241 }
242
243 void chanservremovecommand(char *command, CommandHandler handler) {
244 Command *cmd;
245 cmdsummary *summary;
246 int i;
247
248 if (!(cmd=findcommandintree(cscommands, command, 1))) {
249 Error("chanserv",ERR_WARNING,"Tried to unregister unknown command %s",command);
250 return;
251 }
252
253 summary=(cmdsummary *)cmd->ext;
254 freesstring(summary->def);
255 for (i=0;i<MAXLANG;i++) {
256 if (summary->bylang[i])
257 freesstring(summary->bylang[i]);
258 }
259
260 free(summary);
261
262 deletecommandfromtree(cscommands, command, handler);
263 }
264
265 void chanservpartchan(channel *cp, char *reason) {
266 /* Sanity check that we exist and are on the channel.
267 *
268 * Note that we don't do any of the other usual sanity checks here; if
269 * this channel is unregged or suspended or whatever then all the more
270 * reason to get Q off it ASAP! */
271 if (!chanservnick || !cp || !cp->users || !getnumerichandlefromchanhash(cp->users, chanservnick->numeric))
272 return;
273
274 localpartchannel(chanservnick, cp, reason);
275 }
276
277 void chanservjoinchan(channel *cp) {
278 regchan *rcp;
279 unsigned int i;
280 nick *np;
281 reguser *rup;
282 regchanuser *rcup;
283 flag_t themodes = 0;
284
285 /* Skip unregistered channels */
286 if (!(rcp=cp->index->exts[chanservext]))
287 return;
288
289 /* Check for a new timestamp. But don't do anything stupid if the incoming timestamp is 0 */
290 if (cp->timestamp && ((!rcp->ltimestamp) || (cp->timestamp < rcp->ltimestamp))) {
291 rcp->ltimestamp=cp->timestamp;
292 csdb_updatechanneltimestamp(rcp);
293 }
294
295 /* We won't be doing any joining or parting if we're not online */
296 if (!chanservnick)
297 return;
298
299 /* In gerenal this function shouldn't be used any more as a reason to get
300 * Q to leave, but if it should be leaving then just part with no reason. */
301 if ((CIsSuspended(rcp) || !CIsJoined(rcp)) && getnumerichandlefromchanhash(cp->users, chanservnick->numeric)) {
302 localpartchannel(chanservnick, cp, NULL);
303 }
304
305 /* Right, we are definately going to either join the channel or at least
306 * burst some modes onto it.
307 *
308 * We will try and burst our view of the world; if the timestamps are
309 * actually equal this will be mostly ignored and we will have to fix it
310 * up later. For modes we use the forced modes, plus the default channel
311 * modes (unless any of those are explicitly denied) */
312
313 /* By default, we set the forcemodes and the default modes, but never denymodes..
314 * OK, actually we should only set the default modes if our timestamp is older.*/
315 if (cp->timestamp > rcp->ltimestamp)
316 themodes |= CHANMODE_DEFAULT;
317 else
318 themodes=0;
319
320 themodes = (themodes | rcp->forcemodes) & ~rcp->denymodes;
321
322 /* Now, if someone has just created a channel and we are going to set +i
323 * or +k on it, this will kick them off. This could be construed as a
324 * bit rude if it's their channel, so if there is only one person on the
325 * channel and they have a right to be there, burst with default modes
326 * only to avoid them being netrider kicked.
327 */
328 if (cp->users->totalusers==1) {
329 for (i=0;i<cp->users->hashsize;i++) {
330 if (cp->users->content[i] != nouser) {
331 if ((np=getnickbynumeric(cp->users->content[i]&CU_NUMERICMASK)) &&
332 (rup=getreguserfromnick(np)) &&
333 (rcup=findreguseronchannel(rcp,rup)) &&
334 CUKnown(rcup)) {
335 /* OK, there was one user, and they are known on this channel.
336 * Don't burst with +i or +k */
337 themodes &= ~(CHANMODE_INVITEONLY | CHANMODE_KEY);
338 }
339 }
340 }
341 }
342
343 /* We should be on the channel - join with our nick */
344 if (!CIsSuspended(rcp) && CIsJoined(rcp) && !getnumerichandlefromchanhash(cp->users, chanservnick->numeric)) {
345 /* If we pass the key parameter here but are not setting +k (see above)
346 * then localburstontochannel() will ignore the key */
347 localburstontochannel(cp, chanservnick, rcp->ltimestamp, themodes,
348 rcp->limit, (rcp->key)?rcp->key->content:NULL);
349 }
350
351 /* We're not joining the channel - send the burst with no nick */
352 if (!CIsSuspended(rcp) && !CIsJoined(rcp) && (cp->timestamp > rcp->ltimestamp)) {
353 localburstontochannel(cp, NULL, rcp->ltimestamp, themodes,
354 rcp->limit, (rcp->key)?rcp->key->content:NULL);
355 }
356 }
357
358 void chanservstdmessage(nick *np, int messageid, ... ) {
359 char buf[5010];
360 char buf2[512];
361 int notice;
362 reguser *rup;
363 int language;
364 va_list va, va2;
365 char *message, *messageargs;
366 char *bp2,*bp;
367 int len;
368
369 if (getreguserfromnick(np) == NULL) {
370 notice=1;
371 language=0;
372 } else {
373 rup=getreguserfromnick(np);
374 if(UIsNotice(rup)) {
375 notice=1;
376 } else {
377 notice=0;
378 }
379 language=rup->languageid;
380 }
381
382 if (csmessages[language][messageid]) {
383 message=csmessages[language][messageid]->content;
384 } else if (csmessages[0][messageid]) {
385 message=csmessages[0][messageid]->content;
386 } else {
387 message=defaultmessages[messageid*2];
388 }
389
390 messageargs=defaultmessages[messageid*2+1];
391
392 va_start(va,messageid);
393 va_copy(va2, va);
394 q9vsnprintf(buf,5000,message,messageargs,va);
395 va_end(va);
396
397 len=0;
398 bp2=buf2;
399 for (bp=buf; ;bp++) {
400 /* We send something if we hit a \n, fill the buffer or run out of source */
401 if (*bp=='\n' || len>490 || !*bp) {
402 if (*bp && *bp!='\n') {
403 bp--;
404 }
405
406 *bp2='\0';
407
408 if (chanservnick && *buf2) {
409 if (notice) {
410 sendnoticetouser(chanservnick,np,"%s",buf2);
411 } else {
412 sendmessagetouser(chanservnick,np,"%s",buf2);
413 }
414 }
415
416 /* If we ran out of buffer, get out here */
417 if (!*bp)
418 break;
419
420 bp2=buf2;
421 len=0;
422 } else {
423 len++;
424 *bp2++=*bp;
425 }
426 }
427
428 /* Special case: If it's a "not enough parameters" message, show the first line of help */
429 if (messageid==QM_NOTENOUGHPARAMS) {
430 char *command=va_arg(va2, char *);
431 cs_sendhelp(np, command, 1);
432 chanservstdmessage(np, QM_TYPEHELPFORHELP, command);
433 }
434
435 va_end(va2);
436 }
437
438 void chanservsendmessage_real(nick *np, int oneline, char *message, ... ) {
439 char buf[5010]; /* Very large buffer.. */
440 char buf2[512], *bp, *bp2;
441 int notice;
442 int len;
443 reguser *rup;
444
445 va_list va;
446
447 va_start(va,message);
448 vsnprintf(buf,5000,message,va);
449 va_end(va);
450
451 if (getreguserfromnick(np) == NULL) {
452 notice=1;
453 } else {
454 rup=getreguserfromnick(np);
455 if(UIsNotice(rup)) {
456 notice=1;
457 } else {
458 notice=0;
459 }
460 }
461
462 len=0;
463 bp2=buf2;
464 for (bp=buf; ;bp++) {
465 /* We send something if we hit a \n, fill the buffer or run out of source */
466 if (*bp=='\n' || len>490 || !*bp) {
467 if (*bp && *bp!='\n') {
468 bp--;
469 }
470
471 *bp2='\0';
472
473 if (chanservnick && *buf2) {
474 if (notice) {
475 sendnoticetouser(chanservnick,np,"%s",buf2);
476 } else {
477 sendmessagetouser(chanservnick,np,"%s",buf2);
478 }
479 }
480
481 /* If we ran out of buffer, get out here */
482 if (!*bp || (*bp=='\n' && oneline))
483 break;
484
485 bp2=buf2;
486 len=0;
487 } else {
488 len++;
489 *bp2++=*bp;
490 }
491 }
492 }
493
494 void chanservwallmessage(char *message, ... ) {
495 char buf[5010]; /* Very large buffer.. */
496 va_list va;
497 nick *np;
498 unsigned int i=0;
499
500 va_start(va,message);
501 vsnprintf(buf,5000,message,va);
502 va_end(va);
503
504 /* Scan for users */
505 for (i=0;i<NICKHASHSIZE;i++) {
506 for (np=nicktable[i];np;np=np->next) {
507 if (!IsOper(np)) /* optimisation, if VIEWWALLMESSAGE changes change this */
508 continue;
509
510 if (!cs_privcheck(QPRIV_VIEWWALLMESSAGE, np))
511 continue;
512
513 chanservsendmessage(np, "%s", buf);
514 }
515 }
516 }
517
518 void chanservkillstdmessage(nick *target, int messageid, ... ) {
519 char buf[512];
520 int language;
521 char *message, *messageargs;
522 va_list va;
523 reguser *rup;
524
525 if (!(rup=getreguserfromnick(target)))
526 language=0;
527 else
528 language=rup->languageid;
529
530 if (csmessages[language][messageid])
531 message=csmessages[language][messageid]->content;
532 else if (csmessages[0][messageid])
533 message=csmessages[0][messageid]->content;
534 else
535 message=defaultmessages[messageid*2];
536
537 messageargs=defaultmessages[messageid*2+1];
538 va_start(va, messageid);
539 q9vsnprintf(buf, 511, message, messageargs, va);
540 va_end(va);
541 killuser(chanservnick, target, "%s", buf);
542 }
543
544 int checkpassword(reguser *rup, const char *pass) {
545 if (!(*rup->password))
546 return 0;
547
548 if (!strncmp(rup->password, pass, PASSLEN))
549 return 1;
550 return 0;
551 }
552
553 int checkresponse(reguser *rup, const unsigned char *entropy, const char *response, CRAlgorithm algorithm) {
554 char usernamel[NICKLEN+1], *dp, *up;
555
556 if (!(*rup->password))
557 return 0;
558
559 for(up=rup->username,dp=usernamel;*up;)
560 *dp++ = ToLower(*up++);
561 *dp = '\0';
562
563 return algorithm(usernamel, rup->password, cs_calcchallenge(entropy), response);
564 }
565
566 int checkhashpass(reguser *rup, const char *junk, const char *hash) {
567 char usernamel[NICKLEN+1], *dp, *up;
568
569 for(up=rup->username,dp=usernamel;*up;)
570 *dp++ = ToLower(*up++);
571 *dp = '\0';
572
573 return cs_checkhashpass(usernamel, rup->password, junk, hash);
574 }
575
576 int setpassword(reguser *rup, const char *pass) {
577 strncpy(rup->password, pass, PASSLEN);
578 rup->password[PASSLEN]='\0';
579 return 1;
580 }
581
582 void cs_checknick(nick *np) {
583 activeuser* aup;
584 reguser *rup;
585 char userhost[USERLEN+HOSTLEN+3];
586
587 if (!(aup=getactiveuserfromnick(np))) {
588 aup=getactiveuser();
589 np->exts[chanservnext]=aup;
590 }
591
592 assert(getactiveuserfromnick(np));
593
594 if (IsAccount(np) && np->auth) {
595 if (np->auth->exts[chanservaext]) {
596 rup=getreguserfromnick(np);
597
598 /* safe? */
599 if(rup) {
600 if (UIsDelayedGline(rup)) {
601 /* delayed-gline - schedule the user's squelching */
602 deleteschedule(NULL, &chanservdgline, (void*)rup); /* icky, but necessary unless we stick more stuff in reguser structure */
603 scheduleoneshot(time(NULL)+rand()%900, &chanservdgline, (void*)rup);
604 } else if (UIsGline(rup)) {
605 /* instant-gline - lets be lazy and set a schedule expiring now :) */
606 deleteschedule(NULL, &chanservdgline, (void*)rup); /* icky, but necessary unless we stick more stuff in reguser structure */
607 scheduleoneshot(time(NULL), &chanservdgline, (void*)rup);
608 } else if(UHasSuspension(rup)) {
609 chanservkillstdmessage(np, QM_SUSPENDKILL);
610 return;
611 }
612 }
613 cs_doallautomodes(np);
614 } else {
615 /* Auto create user.. */
616 rup=getreguser();
617 rup->status=0;
618 rup->ID=np->auth->userid;
619 if (rup->ID > lastuserID)
620 lastuserID=rup->ID;
621 strncpy(rup->username,np->authname,NICKLEN); rup->username[NICKLEN]='\0';
622 rup->created=time(NULL);
623 rup->lastauth=0;
624 rup->lastemailchange=0;
625 rup->lastpasschange=0;
626 rup->flags=QUFLAG_NOTICE;
627 rup->languageid=0;
628 rup->suspendby=0;
629 rup->suspendexp=0;
630 rup->suspendtime=0;
631 rup->lockuntil=0;
632 rup->password[0]='\0';
633 rup->email=NULL;
634 rup->lastemail=NULL;
635 rup->localpart=NULL;
636 rup->domain=NULL;
637 rup->info=NULL;
638 sprintf(userhost,"%s@%s",np->ident,np->host->name->content);
639 rup->lastuserhost=getsstring(userhost,USERLEN+HOSTLEN+1);
640 rup->suspendreason=NULL;
641 rup->comment=NULL;
642 rup->knownon=NULL;
643 rup->checkshd=NULL;
644 rup->stealcount=0;
645 rup->fakeuser=NULL;
646 addregusertohash(rup);
647
648 csdb_createuser(rup);
649 }
650 }
651
652 cs_checknickbans(np);
653 }
654
655 void cs_checkchanmodes(channel *cp) {
656 modechanges changes;
657
658 localsetmodeinit (&changes, cp, chanservnick);
659 cs_docheckchanmodes(cp, &changes);
660 localsetmodeflush (&changes, 1);
661 }
662
663 void cs_docheckchanmodes(channel *cp, modechanges *changes) {
664 regchan *rcp;
665
666 if (!cp)
667 return;
668
669 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
670 return;
671
672 /* Take care of the simple modes */
673 localdosetmode_simple(changes, rcp->forcemodes & ~(cp->flags), rcp->denymodes & cp->flags);
674
675 /* Check for forced key. Note that we ALWAYS call localdosetmode_key
676 * in case the wrong key is set atm */
677 if (rcp->forcemodes & CHANMODE_KEY) {
678 if (!rcp->key) {
679 Error("chanserv",ERR_WARNING,"Key forced but no key specified for %s: cleared forcemode.",rcp->index->name->content);
680 rcp->forcemodes &= ~CHANMODE_KEY;
681 csdb_updatechannel(rcp);
682 } else {
683 localdosetmode_key(changes, rcp->key->content, MCB_ADD);
684 }
685 }
686
687 /* Check for denied key */
688 if ((rcp->denymodes & CHANMODE_KEY) && IsKey(cp)) {
689 localdosetmode_key(changes, NULL, MCB_DEL);
690 }
691
692 /* Check for forced limit. Always call in case of wrong limit */
693 if (rcp->forcemodes & CHANMODE_LIMIT) {
694 localdosetmode_limit(changes, rcp->limit, MCB_ADD);
695 }
696 }
697
698 /* Slightly misnamed function that checks each USER on the channel against channel
699 * settings. Possible actions are opping/deopping, voicing/devoicing, and banning
700 * for chanflag +k or chanlev flag +b */
701 void cs_docheckopvoice(channel *cp, modechanges *changes) {
702 regchan *rcp;
703 reguser *rup;
704 regchanuser *rcup;
705 nick *np;
706 int i;
707
708 if (!cp)
709 return;
710
711 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
712 return;
713
714 for (i=0;i<cp->users->hashsize;i++) {
715 if (cp->users->content[i]==nouser)
716 continue;
717
718 if ((np=getnickbynumeric(cp->users->content[i]))==NULL) {
719 Error("chanserv",ERR_ERROR,"Found non-existent numeric %lu on channel %s",cp->users->content[i],
720 cp->index->name->content);
721 continue;
722 }
723
724 if ((rup=getreguserfromnick(np)))
725 rcup=findreguseronchannel(rcp,rup);
726 else
727 rcup=NULL;
728
729 /* Various things that might ban the user - don't apply these to +o, +k or +X users */
730 if (!IsService(np) && !IsXOper(np) && !IsOper(np)) {
731 if (rcup && CUIsBanned(rcup)) {
732 cs_banuser(changes, cp->index, np, NULL);
733 continue;
734 }
735
736 /* chanflag +k checks; kick them if they "obviously" can't rejoin without a ban */
737 if (CIsKnownOnly(rcp) && !(rcup && CUKnown(rcup))) {
738 if (IsInviteOnly(cp) || (IsRegOnly(cp) && !IsAccount(np))) {
739 localkickuser(chanservnick,cp,np,"Authorised users only.");
740 } else {
741 cs_banuser(NULL, cp->index, np, "Authorised users only.");
742 }
743 continue;
744 }
745 }
746
747 if ((cp->users->content[i] & CUMODE_OP) && !IsService(np)) {
748 if ((CIsBitch(rcp) && (!rcup || !CUHasOpPriv(rcup))) ||
749 (rcup && CUIsDeny(rcup)))
750 localdosetmode_nick(changes, np, MC_DEOP);
751 } else {
752 if (rcup && (CUIsProtect(rcup) || CIsProtect(rcp)) && CUIsOp(rcup) && !CUIsDeny(rcup)) {
753 localdosetmode_nick(changes, np, MC_OP);
754 cs_logchanop(rcp, np->nick, rcup->user);
755 }
756 }
757
758 if (cp->users->content[i] & CUMODE_VOICE) {
759 if (rcup && CUIsQuiet(rcup))
760 localdosetmode_nick(changes, np, MC_DEVOICE);
761 } else {
762 if (rcup && (CUIsProtect(rcup) || CIsProtect(rcp)) && CUIsVoice(rcup) && !CUIsQuiet(rcup) && !(cp->users->content[i] & CUMODE_OP))
763 localdosetmode_nick(changes, np, MC_VOICE);
764 }
765 }
766 }
767
768 void cs_doallautomodes(nick *np) {
769 reguser *rup;
770 regchanuser *rcup;
771 unsigned long *lp;
772 modechanges changes;
773
774 if (!(rup=getreguserfromnick(np)))
775 return;
776
777 for (rcup=rup->knownon;rcup;rcup=rcup->nextbyuser) {
778 /* Skip suspended channels */
779 if (CIsSuspended(rcup->chan))
780 continue;
781
782 if (rcup->chan->index->channel) {
783 /* Channel exists */
784 if ((lp=getnumerichandlefromchanhash(rcup->chan->index->channel->users, np->numeric))) {
785 /* User is on channel.. */
786
787 /* Update last use time. Do early in case of ban. */
788 rcup->usetime=getnettime();
789
790 if (CUIsBanned(rcup)) {
791 cs_banuser(NULL, rcup->chan->index, np, NULL);
792 continue;
793 }
794
795 if (CUHasOpPriv(rcup) && cs_ischannelactive(rcup->chan->index->channel, NULL)) {
796 /* This meets the channel use criteria, update. */
797 rcup->chan->lastactive=time(NULL);
798
799 /* Don't spam the DB though for channels with lots of joins */
800 if (rcup->chan->lastcountersync < (time(NULL) - COUNTERSYNCINTERVAL)) {
801 csdb_updatechannelcounters(rcup->chan);
802 rcup->chan->lastcountersync=time(NULL);
803 }
804 }
805
806 localsetmodeinit(&changes, rcup->chan->index->channel, chanservnick);
807 if (*lp & CUMODE_OP) {
808 if (!IsService(np) && (CUIsDeny(rcup) || (CIsBitch(rcup->chan) && !CUHasOpPriv(rcup))))
809 localdosetmode_nick(&changes, np, MC_DEOP);
810 } else {
811 if (!CUIsDeny(rcup) && CUIsOp(rcup) &&
812 (CUIsProtect(rcup) || CIsProtect(rcup->chan) || CUIsAutoOp(rcup))) {
813 localdosetmode_nick(&changes, np, MC_OP);
814 cs_logchanop(rcup->chan, np->nick, rup);
815 }
816 }
817
818 if (*lp & CUMODE_VOICE) {
819 if (CUIsQuiet(rcup))
820 localdosetmode_nick(&changes, np, MC_DEVOICE);
821 } else {
822 if (!CUIsQuiet(rcup) && CUIsVoice(rcup) && !(*lp & CUMODE_OP) &&
823 (CUIsProtect(rcup) || CIsProtect(rcup->chan) || CUIsAutoVoice(rcup)))
824 localdosetmode_nick(&changes, np, MC_VOICE);
825 }
826 localsetmodeflush(&changes, 1);
827 } else {
828 /* Channel exists but user is not joined: invite if they are +j-b */
829 if (CUIsAutoInvite(rcup) && CUKnown(rcup) && !CUIsBanned(rcup)) {
830 localinvite(chanservnick, rcup->chan->index, np);
831 }
832 }
833 } /* if (rcup->chan->index->channel) */ else {
834 /* Channel doesn't currently exist - send invite anyway for +j */
835 if (CUIsAutoInvite(rcup) && CUKnown(rcup) && !CUIsBanned(rcup)) {
836 localinvite(chanservnick, rcup->chan->index, np);
837 }
838 }
839 } /* for */
840 }
841
842 void cs_checknickbans(nick *np) {
843 channel **ca;
844 regchan *rcp;
845 int i,j;
846
847 if (IsService(np) || IsOper(np) || IsXOper(np))
848 return;
849
850 /* Avoid races: memcpy the channel array */
851 i=np->channels->cursi;
852 ca=(channel **)malloc(i*sizeof(channel *));
853 memcpy(ca, np->channels->content,i*sizeof(channel *));
854
855 for (j=0;j<i;j++) {
856 if ((rcp=ca[j]->index->exts[chanservext]) && !CIsSuspended(rcp) &&
857 CIsEnforce(rcp) && nickbanned(np, ca[j], 1))
858 localkickuser(chanservnick, ca[j], np, "Banned.");
859 }
860
861 free(ca);
862 }
863
864 void cs_checkbans(channel *cp) {
865 regchan *rcp;
866 int i;
867 nick *np;
868 chanban *cbp;
869 regban *rbp;
870 time_t now;
871 modechanges changes;
872
873 if (!cp)
874 return;
875
876 if ((rcp=cp->index->exts[chanservext])==NULL || CIsSuspended(rcp))
877 return;
878
879 now=time(NULL);
880
881 localsetmodeinit(&changes, cp, chanservnick);
882
883 for (i=0;i<cp->users->hashsize;i++) {
884 if (cp->users->content[i]==nouser)
885 continue;
886
887 if ((np=getnickbynumeric(cp->users->content[i]))==NULL) {
888 Error("chanserv",ERR_ERROR,"Found numeric %lu on channel %s who doesn't exist.",
889 cp->users->content[i], cp->index->name->content);
890 continue;
891 }
892
893 if (IsService(np) || IsOper(np) || IsXOper(np))
894 continue;
895
896 for (rbp=rcp->bans;rbp;rbp=rbp->next) {
897 if (((!rbp->expiry) || (rbp->expiry <= now)) &&
898 nickmatchban(np, rbp->cbp, 1)) {
899 if (!nickbanned(np, cp, 1)) {
900 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_ADD);
901 }
902 localkickuser(chanservnick,cp,np,rbp->reason?rbp->reason->content:"Banned.");
903 break;
904 }
905 }
906
907 if (rbp) /* If we broke out of above loop (due to kick) rbp will be set.. */
908 continue;
909
910 if (CIsEnforce(rcp)) {
911 for (cbp=cp->bans;cbp;cbp=cbp->next) {
912 if ((cbp->timeset>=rcp->lastbancheck) && nickmatchban(np, cbp, 1))
913 localkickuser(chanservnick,cp,np,"Banned.");
914 }
915 rcp->lastbancheck=time(NULL);
916 }
917 }
918
919 localsetmodeflush(&changes,1);
920 }
921
922 /*
923 * cs_schedupdate:
924 * This function schedules an update check on a channel
925 */
926 void cs_schedupdate(chanindex *cip, int mintime, int maxtime) {
927 int delay=mintime+(rand()%(maxtime-mintime));
928 regchan *rcp;
929
930 if (!(rcp=cip->exts[chanservext]) || CIsSuspended(rcp))
931 return;
932
933 if (rcp->checksched) {
934 deleteschedule(rcp->checksched, cs_timerfunc, cip);
935 }
936
937 rcp->checksched=scheduleoneshot(time(NULL)+delay, cs_timerfunc, cip);
938 }
939
940 /*
941 * cs_timerfunc:
942 * This function does several things:
943 * * Updates auto-limit and/or removes bans as necessary
944 * * Schedules the next timed call
945 * * Does any pending op/ban/mode checks
946 * It is safe to use either as a target for a schedule() call, or to call
947 * directly when parameters change (e.g. autolimit settings or ban expire
948 * timers).
949 * To force a limit update, set rcp->limit to 0..
950 */
951
952 void cs_timerfunc(void *arg) {
953 chanindex *cip=arg;
954 channel *cp=cip->channel;
955 regchan *rcp;
956 chanban *cbp, *ncbp;
957 regban **rbh, *rbp;
958 time_t nextsched=0;
959 time_t now=time(NULL);
960 modechanges changes;
961
962 if (!(rcp=cip->exts[chanservext]))
963 return;
964
965 verifyregchan(rcp);
966
967 /* Always nullify the checksched even if the channel is suspended.. */
968 if (rcp->checksched) {
969 deleteschedule(rcp->checksched, cs_timerfunc, arg);
970 rcp->checksched=NULL;
971 }
972
973 if (!cp || CIsSuspended(rcp))
974 return;
975
976 /* Check if we need to leave the channel first */
977 if (chanservnick && CIsJoined(rcp) && cip->channel &&
978 cip->channel->users->totalusers==1 &&
979 getnumerichandlefromchanhash(cip->channel->users, chanservnick->numeric)) {
980
981 /* Only chanserv left in this channel */
982 if (now >= (rcp->lastpart + LINGERTIME)) {
983 /* Time to go */
984 localpartchannel(chanservnick, cip->channel, "Empty Channel");
985 return;
986 } else {
987 if (!nextsched || nextsched > (rcp->lastpart + LINGERTIME))
988 nextsched=rcp->lastpart+LINGERTIME;
989 }
990 }
991
992 localsetmodeinit(&changes, cp, chanservnick);
993
994 if (CIsAutoLimit(rcp)) {
995 if (!rcp->limit || rcp->autoupdate <= now) {
996 /* Only update the limit if there are <= (autolimit/2) or
997 * >= (autolimit * 1.5) slots free */
998
999 if ((cp->users->totalusers >= (rcp->limit - rcp->autolimit/2)) ||
1000 (cp->users->totalusers <= (rcp->limit - (3 * rcp->autolimit)/2))) {
1001 rcp->limit=cp->users->totalusers+rcp->autolimit;
1002 rcp->status |= QCSTAT_MODECHECK;
1003 }
1004
1005 /* And set the schedule for the next update */
1006 rcp->autoupdate = now + AUTOLIMIT_INTERVAL;
1007 }
1008
1009 if (!nextsched || rcp->autoupdate <= nextsched)
1010 nextsched=rcp->autoupdate;
1011 }
1012
1013 if (rcp->status & QCSTAT_OPCHECK) {
1014 rcp->status &= ~QCSTAT_OPCHECK;
1015 cs_docheckopvoice(cp, &changes);
1016 }
1017
1018 if (rcp->status & QCSTAT_MODECHECK) {
1019 rcp->status &= ~QCSTAT_MODECHECK;
1020 cs_docheckchanmodes(cp, &changes);
1021 }
1022
1023 if (rcp->status & QCSTAT_BANCHECK) {
1024 rcp->status &= ~QCSTAT_BANCHECK;
1025 cs_checkbans(cp);
1026 }
1027
1028 /* This ban check is AFTER docheckopvoice in case checkopvoice set a
1029 * ban which we need to automatically remove later.. */
1030
1031 if (rcp->banduration) {
1032 for (cbp=cp->bans;cbp;cbp=ncbp) {
1033 ncbp=cbp->next;
1034 if (cbp->timeset+rcp->banduration<=now) {
1035 localdosetmode_ban(&changes, bantostring(cbp), MCB_DEL);
1036 } else {
1037 if (!nextsched || cbp->timeset+rcp->banduration <= nextsched) {
1038 nextsched=rcp->banduration+cbp->timeset;
1039 }
1040 }
1041 }
1042 }
1043
1044 /* Check for expiry of registered bans */
1045 if (rcp->bans) {
1046 for (rbh=&(rcp->bans);*rbh;) {
1047 rbp=*rbh;
1048 verifyregchanban(rbp);
1049 if (rbp->expiry && (rbp->expiry < now)) {
1050 /* Expired ban */
1051 /* Remove ban if it's on the channel (localdosetmode_ban will silently
1052 * skip bans that don't exist) */
1053 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_DEL);
1054 /* Remove from database */
1055 csdb_deleteban(rbp);
1056 /* Remove from list */
1057 (*rbh)=rbp->next;
1058 /* Free ban/string and update setby refcount, and free actual regban */
1059 freesstring(rbp->reason);
1060 freechanban(rbp->cbp);
1061 freeregban(rbp);
1062 } else {
1063 if (rbp->expiry && (!nextsched || rbp->expiry <= nextsched)) {
1064 nextsched=rbp->expiry;
1065 }
1066 rbh=&(rbp->next);
1067 }
1068 }
1069 }
1070
1071 if (nextsched)
1072 rcp->checksched=scheduleoneshot(nextsched, cs_timerfunc, arg);
1073
1074 localsetmodeflush(&changes, 1);
1075 }
1076
1077 void cs_removechannel(regchan *rcp, char *reason) {
1078 int i;
1079 chanindex *cip;
1080 regchanuser *rcup, *nrcup;
1081 regban *rbp, *nrbp;
1082
1083 cip=rcp->index;
1084
1085 for (i=0;i<REGCHANUSERHASHSIZE;i++) {
1086 for (rcup=rcp->regusers[i];rcup;rcup=nrcup) {
1087 nrcup=rcup->nextbychan;
1088 delreguserfromchannel(rcp, rcup->user);
1089 freeregchanuser(rcup);
1090 }
1091 }
1092
1093 for (rbp=rcp->bans;rbp;rbp=nrbp) {
1094 nrbp=rbp->next;
1095 freesstring(rbp->reason);
1096 freechanban(rbp->cbp);
1097 freeregban(rbp);
1098 }
1099
1100 rcp->bans=NULL;
1101
1102 if (rcp->checksched)
1103 deleteschedule(rcp->checksched, cs_timerfunc, rcp->index);
1104
1105 if (cip->channel) {
1106 chanservpartchan(cip->channel, reason);
1107 }
1108
1109 csdb_deletechannel(rcp);
1110
1111 freesstring(rcp->welcome);
1112 freesstring(rcp->topic);
1113 freesstring(rcp->key);
1114 freesstring(rcp->suspendreason);
1115 freesstring(rcp->comment);
1116
1117 freeregchan(rcp);
1118
1119 cip->exts[chanservext]=NULL;
1120 releasechanindex(cip);
1121 }
1122
1123 /* Sender is who the DELCHAN is attributed to.. */
1124 int cs_removechannelifempty(nick *sender, regchan *rcp) {
1125 unsigned int i;
1126 regchanuser *rcup;
1127
1128 for (i=0;i<REGCHANUSERHASHSIZE;i++) {
1129 for (rcup=rcp->regusers[i];rcup;rcup=rcup->nextbychan) {
1130 if (rcup->flags & ~(QCUFLAGS_PUNISH))
1131 return 0;
1132 }
1133 }
1134
1135 cs_log(sender,"DELCHAN %s (Empty)",rcp->index->name->content);
1136 cs_removechannel(rcp, "Last user removed - channel deleted.");
1137
1138 return 1;
1139 }
1140
1141 void cs_removeuser(reguser *rup) {
1142 regchanuser *rcup, *nrcup;
1143 regchan *rcp;
1144 struct authname *anp;
1145
1146 /* Remove the user from all its channels */
1147 for (rcup=rup->knownon;rcup;rcup=nrcup) {
1148 nrcup=rcup->nextbyuser;
1149 rcp=rcup->chan;
1150
1151 delreguserfromchannel(rcp, rup);
1152 cs_removechannelifempty(NULL, rcp);
1153 }
1154
1155 if(rup->domain)
1156 delreguserfrommaildomain(rup,rup->domain);
1157 freesstring(rup->localpart);
1158 freesstring(rup->email);
1159 freesstring(rup->lastemail);
1160 freesstring(rup->lastuserhost);
1161 freesstring(rup->suspendreason);
1162 freesstring(rup->comment);
1163 freesstring(rup->info);
1164
1165 csdb_deleteuser(rup);
1166
1167 removereguserfromhash(rup);
1168
1169 if ((anp=findauthname(rup->ID)) && anp->nicks) {
1170 rup->status |= QUSTAT_DEAD;
1171 } else {
1172 freereguser(rup);
1173 }
1174 }
1175
1176 int cs_bancheck(nick *np, channel *cp) {
1177 time_t now=time(NULL);
1178 regban **rbh, *rbp;
1179 modechanges changes;
1180 regchan *rcp;
1181
1182 if (!(rcp=cp->index->exts[chanservext]))
1183 return 0;
1184
1185 for (rbh=&(rcp->bans);*rbh;) {
1186 if ((*rbh)->expiry && ((*rbh)->expiry < now)) {
1187 /* Expired ban */
1188 csdb_deleteban(*rbh);
1189 rbp=*rbh;
1190 (*rbh)=rbp->next;
1191
1192 freesstring(rbp->reason);
1193 freechanban(rbp->cbp);
1194 freeregban(rbp);
1195 } else if (nickmatchban(np,(*rbh)->cbp,1)) {
1196 /* This user matches this ban.. */
1197 if (!nickbanned(np,cp,1)) {
1198 /* Only bother putting the ban on the channel if they're not banned already */
1199 /* (might be covered by this ban or a different one.. doesn't really matter */
1200 localsetmodeinit(&changes, cp, chanservnick);
1201 localdosetmode_ban(&changes, bantostring((*rbh)->cbp), MCB_ADD);
1202 localsetmodeflush(&changes, 1);
1203 cs_timerfunc(cp->index);
1204 }
1205 localkickuser(chanservnick, cp, np, (*rbh)->reason ? (*rbh)->reason->content : "Banned.");
1206 return 1;
1207 } else {
1208 rbh=&((*rbh)->next);
1209 }
1210 }
1211
1212 return 0;
1213 }
1214
1215 void cs_setregban(chanindex *cip, regban *rbp) {
1216 modechanges changes;
1217 int i;
1218 nick *np;
1219
1220 if (!cip->channel)
1221 return;
1222
1223 localsetmodeinit(&changes, cip->channel, chanservnick);
1224 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_ADD);
1225 localsetmodeflush(&changes, 1);
1226
1227 for (i=0;(cip->channel) && i<cip->channel->users->hashsize;i++) {
1228 if (cip->channel->users->content[i]!=nouser &&
1229 (np=getnickbynumeric(cip->channel->users->content[i])) &&
1230 !IsService(np) && !IsOper(np) && !IsXOper(np) &&
1231 nickmatchban(np, rbp->cbp, 1))
1232 localkickuser(chanservnick, cip->channel, np, rbp->reason ? rbp->reason->content : "Banned.");
1233 }
1234
1235 cs_timerfunc(cip);
1236 }
1237
1238 void cs_banuser(modechanges *changes, chanindex *cip, nick *np, const char *reason) {
1239 modechanges lchanges;
1240 char banmask[NICKLEN+USERLEN+HOSTLEN+3];
1241
1242 if (!cip->channel)
1243 return;
1244
1245 if (nickbanned(np, cip->channel, 1)) {
1246 localkickuser(chanservnick, cip->channel, np, reason?reason:"Banned.");
1247 return;
1248 }
1249
1250 if (IsAccount(np)) {
1251 /* Ban their account.. */
1252 sprintf(banmask,"*!*@%s.%s",np->authname,HIS_HIDDENHOST);
1253 } else if (IsSetHost(np)) {
1254 /* sethosted: ban ident@host */
1255 sprintf(banmask,"*!%s@%s",np->shident->content,np->sethost->content);
1256 } else if (np->host->clonecount>3) {
1257 /* >3 clones, ban user@host */
1258 sprintf(banmask,"*!%s@%s",np->ident,np->host->name->content);
1259 } else {
1260 sprintf(banmask,"*!*@%s",np->host->name->content);
1261 }
1262
1263 if (!changes) {
1264 localsetmodeinit(&lchanges, cip->channel, chanservnick);
1265 localdosetmode_ban(&lchanges, banmask, MCB_ADD);
1266 localsetmodeflush(&lchanges, 1);
1267 } else {
1268 localdosetmode_ban(changes, banmask, MCB_ADD);
1269 }
1270
1271 localkickuser(chanservnick, cip->channel, np, reason?reason:"Banned.");
1272 }
1273
1274 /*
1275 * cs_sanitisechanlev: Removes impossible combinations from chanlev flags.
1276 * chanservuser.c is probably not the right file for this, but nowhere better
1277 * presented itself...
1278 */
1279 flag_t cs_sanitisechanlev(flag_t flags) {
1280 /* +m or +n cannot have any "punishment" flags */
1281 if (flags & (QCUFLAG_MASTER | QCUFLAG_OWNER))
1282 flags &= ~(QCUFLAGS_PUNISH);
1283
1284 /* +d can't be +o */
1285 if (flags & QCUFLAG_DENY)
1286 flags &= ~QCUFLAG_OP;
1287
1288 /* +q can't be +v */
1289 if (flags & QCUFLAG_QUIET)
1290 flags &= ~QCUFLAG_VOICE;
1291
1292 /* +p trumps +a and +g */
1293 if (flags & QCUFLAG_PROTECT)
1294 flags &= ~(QCUFLAG_AUTOOP | QCUFLAG_AUTOVOICE);
1295
1296 /* -o can't be +a */
1297 if (!(flags & QCUFLAG_OP))
1298 flags &= ~QCUFLAG_AUTOOP;
1299
1300 /* +a or -v can't be +g. +a implies +o at this stage (see above) */
1301 if (!(flags & QCUFLAG_VOICE) || (flags & QCUFLAG_AUTOOP))
1302 flags &= ~QCUFLAG_AUTOVOICE;
1303
1304 /* +p requires +o or +v */
1305 if (!(flags & (QCUFLAG_VOICE | QCUFLAG_OP)))
1306 flags &= ~QCUFLAG_PROTECT;
1307
1308 /* The personal flags require one of +mnovk, as does +t */
1309 if (!(flags & (QCUFLAG_OWNER | QCUFLAG_MASTER | QCUFLAG_OP | QCUFLAG_VOICE | QCUFLAG_KNOWN)))
1310 flags &= ~(QCUFLAGS_PERSONAL | QCUFLAG_TOPIC);
1311
1312 return flags;
1313 }
1314
1315 /*
1316 * findreguser:
1317 * This function does the standard "nick or #user" lookup.
1318 * If "sender" is not NULL, a suitable error message will
1319 * be sent if the lookup fails.
1320 * "sender" MUST be sent when a user is requesting a lookup
1321 * as there is some policy code here.
1322 */
1323
1324 reguser *findreguser(nick *sender, const char *str) {
1325 reguser *rup, *vrup = getreguserfromnick(sender);;
1326 nick *np;
1327
1328 if (!str || !*str)
1329 return NULL;
1330
1331 if (*str=='#') {
1332 if (str[1]=='\0') {
1333 if (sender)
1334 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1335 return NULL;
1336 }
1337 if (!(rup=findreguserbynick(str+1)) && sender)
1338 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1339 } else if (*str=='&' && vrup && UHasStaffPriv(vrup)) {
1340 if (str[1]=='\0') {
1341 if (sender)
1342 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1343 return NULL;
1344 }
1345 if (!(rup=findreguserbyID(atoi(str+1))) && sender)
1346 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1347 } else {
1348 if (!(np=getnickbynick(str))) {
1349 if (sender)
1350 chanservstdmessage(sender, QM_UNKNOWNUSER, str);
1351 return NULL;
1352 }
1353 if (!(rup=getreguserfromnick(np)) && sender)
1354 chanservstdmessage(sender, QM_USERNOTAUTHED, str);
1355 }
1356
1357 /* removed the suspended check from here, I don't see the point... */
1358 if (rup && (rup->status & QUSTAT_DEAD)) {
1359 chanservstdmessage(sender, QM_USERHASBADAUTH, rup->username);
1360 return NULL;
1361 }
1362
1363 return rup;
1364 }
1365
1366 /*
1367 * Unbans a mask from a channel, including permbans if user has correct privs.
1368 *
1369 * Return 0 if it works, 1 if it don't.
1370 */
1371 int cs_unbanfn(nick *sender, chanindex *cip, int (*fn)(void *arg, struct chanban *ban), void *arg, int removepermbans, int abortonfailure) {
1372 regban **rbh, *rbp;
1373 chanban **cbh, *cbp;
1374 regchan *rcp;
1375 modechanges changes;
1376 char *banstr;
1377
1378 rcp=cip->exts[chanservext];
1379
1380 if (cip->channel)
1381 localsetmodeinit(&changes, cip->channel, chanservnick);
1382
1383 for (rbh=&(rcp->bans); *rbh; ) {
1384 rbp=*rbh;
1385 if (fn(arg, rbp->cbp)) {
1386 banstr=bantostring(rbp->cbp);
1387 /* Check perms and remove */
1388 if(!removepermbans) {
1389 chanservstdmessage(sender, QM_WARNNOTREMOVEDPERMBAN, banstr, cip->name->content);
1390 rbh=&(rbp->next);
1391 } else if (!cs_checkaccess(sender, NULL, CA_MASTERPRIV, cip, NULL, 0, 1)) {
1392 chanservstdmessage(sender, QM_NOTREMOVEDPERMBAN, banstr, cip->name->content);
1393 if (abortonfailure) return 1; /* Just give up... */
1394 rbh=&(rbp->next);
1395 } else {
1396 chanservstdmessage(sender, QM_REMOVEDPERMBAN, banstr, cip->name->content);
1397 if (cip->channel)
1398 localdosetmode_ban(&changes, banstr, MCB_DEL);
1399 /* Remove from database */
1400 csdb_deleteban(rbp);
1401 /* Remove from list */
1402 (*rbh)=rbp->next;
1403 /* Free ban/string and update setby refcount, and free actual regban */
1404 freesstring(rbp->reason);
1405 freechanban(rbp->cbp);
1406 freeregban(rbp);
1407 }
1408 } else {
1409 rbh=&(rbp->next);
1410 }
1411 }
1412
1413 if (cip->channel) {
1414 for (cbh=&(cip->channel->bans); *cbh; ) {
1415 cbp=*cbh;
1416 if (fn(arg, cbp)) {
1417 /* Remove */
1418 banstr=bantostring(cbp);
1419 chanservstdmessage(sender, QM_REMOVEDCHANBAN, banstr, cip->name->content);
1420 localdosetmode_ban(&changes, banstr, MCB_DEL);
1421 } else {
1422 cbh=&(cbp->next);
1423 }
1424 }
1425 localsetmodeflush(&changes,1);
1426 }
1427
1428 return 0;
1429 }
1430
1431 /* Add entry to channel op history when someone gets ops. */
1432 void cs_logchanop(regchan *rcp, char *nick, reguser *rup) {
1433 strncpy(rcp->chanopnicks[rcp->chanoppos], nick, NICKLEN);
1434 rcp->chanopnicks[rcp->chanoppos][NICKLEN]='\0';
1435 rcp->chanopaccts[rcp->chanoppos]=rup->ID;
1436 rcp->chanoppos=(rcp->chanoppos+1)%CHANOPHISTORY;
1437 }
1438
1439 int checkreason(nick *np, char *reason) {
1440 if((strlen(reason) < MIN_REASONLEN) || !strchr(reason, ' ')) {
1441 chanservstdmessage(np, QM_REASONREQUIRED);
1442 return 0;
1443 }
1444
1445 return 1;
1446 }
1447
1448 regchan *cs_addchan(chanindex *cip, nick *sender, reguser *addedby, reguser *founder, flag_t flags, flag_t forcemodes, flag_t denymodes, short type) {
1449 regchan *rcp;
1450 regchanuser *rcup;
1451 void *args[3];
1452 int i;
1453
1454 if (cip->exts[chanservext])
1455 return NULL;
1456
1457 /* Initialise the channel */
1458 rcp=getregchan();
1459
1460 /* ID, index */
1461 rcp->ID=++lastchannelID;
1462 rcp->index=cip;
1463 cip->exts[chanservext]=rcp;
1464
1465 rcp->chantype=type;
1466 rcp->flags=flags;
1467 rcp->status=0;
1468 rcp->bans=NULL;
1469 rcp->lastcountersync=0;
1470
1471 rcp->limit=0;
1472 rcp->forcemodes=forcemodes;
1473 rcp->denymodes=denymodes;
1474
1475 if (CIsAutoLimit(rcp)) {
1476 rcp->forcemodes |= CHANMODE_LIMIT;
1477 }
1478
1479 rcp->autolimit=5;
1480 rcp->banstyle=0;
1481
1482 rcp->created=rcp->lastactive=rcp->statsreset=rcp->ostatsreset=time(NULL);
1483 rcp->banduration=0;
1484 rcp->autoupdate=0;
1485 rcp->lastbancheck=0;
1486
1487 /* Added by */
1488 rcp->addedby=addedby->ID;
1489
1490 /* Founder */
1491 rcp->founder=founder->ID;
1492
1493 /* Suspend by */
1494 rcp->suspendby=0;
1495 rcp->suspendtime=0;
1496
1497 rcp->totaljoins=rcp->tripjoins=rcp->otripjoins=rcp->maxusers=rcp->tripusers=rcp->otripusers=0;
1498 rcp->welcome=rcp->topic=rcp->key=rcp->suspendreason=rcp->comment=NULL;
1499
1500 /* Users */
1501 memset(rcp->regusers,0,REGCHANUSERHASHSIZE*sizeof(reguser *));
1502
1503 rcp->checksched=NULL;
1504 rcp->ltimestamp=0;
1505 for (i=0;i<CHANOPHISTORY;i++) {
1506 rcp->chanopnicks[i][0]='\0';
1507 rcp->chanopaccts[i]=0;
1508 }
1509 rcp->chanoppos=0;
1510
1511 /* Add new channel to db.. */
1512 csdb_createchannel(rcp);
1513
1514 /* Add the founder as +ano */
1515 rcup=getregchanuser();
1516 rcup->chan=rcp;
1517 rcup->user=founder;
1518 rcup->flags=(QCUFLAG_OWNER | QCUFLAG_OP | QCUFLAG_AUTOOP);
1519 rcup->usetime=0;
1520 rcup->info=NULL;
1521 rcup->changetime=time(NULL);
1522
1523 addregusertochannel(rcup);
1524 csdb_createchanuser(rcup);
1525 csdb_chanlevhistory_insert(rcp, sender, rcup->user, 0, rcup->flags);
1526
1527 args[0]=sender;
1528 args[1]=rcup;
1529 args[2]=(void *)0;
1530
1531 triggerhook(HOOK_CHANSERV_CHANLEVMOD, args);
1532
1533 /* If the channel exists, get the ball rolling */
1534 if (cip->channel) {
1535 chanservjoinchan(cip->channel);
1536 rcp->status |= QCSTAT_MODECHECK | QCSTAT_OPCHECK | QCSTAT_BANCHECK;
1537 cs_timerfunc(cip);
1538 }
1539
1540 return rcp;
1541 }