]>
jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservuser.c
c42c3a3257379067c2ce0a31b049665c3749291a
3 * This file maintains the functions associated with the
4 * user on the network relating to the channel service
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"
27 CommandTree
*cscommands
;
28 CommandTree
*csctcpcommands
;
30 /* Local prototypes */
31 void chanservuserhandler(nick
*target
, int message
, void **params
);
33 void chanservreguser(void *arg
) {
34 sstring
*csnick
,*csuser
,*cshost
,*csrealname
;
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
);
44 Error("chanserv",ERR_INFO
,"Connecting %s...",csnick
->content
);
46 chanservnick
=registerlocaluser(csnick
->content
,csuser
->content
,cshost
->content
,
47 csrealname
->content
,NULL
,
48 UMODE_INV
|UMODE_SERVICE
|UMODE_DEAF
,
49 &chanservuserhandler
);
54 freesstring(csrealname
);
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
)) {
60 /* This will do timestamp faffing even if it won't actually join */
61 chanservjoinchan(cip
->channel
);
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
: "");
71 Error("chanserv",ERR_INFO
,"Loaded and joined channels.");
73 if (chanserv_init_status
== CS_INIT_NOUSER
) {
74 /* If this is the first time, perform last init tasks */
79 void chanservuserhandler(nick
*target
, int message
, void **params
) {
90 scheduleoneshot(time(NULL
),&chanservreguser
,NULL
);
96 sender
=(nick
*)params
[0];
97 msg
=(char *)params
[1];
99 if (!(cargc
=splitline(msg
,cargv
,30,0)))
100 return; /* Ignore blank lines */
102 if (cargv
[0][0]==1) {
104 for (chp
=cargv
[0]+1;*chp
;chp
++) {
110 cmd
=findcommandintree(csctcpcommands
, cargv
[0]+1, 1);
112 rejoinline(cargv
[1],cargc
-1);
113 cmd
->handler((void *)sender
, cargc
-1, &(cargv
[1]));
116 cmd
=findcommandintree(cscommands
, cargv
[0], 1);
119 chanservstdmessage(sender
, QM_UNKNOWNCMD
, cargv
[0]);
123 if ((cmd
->level
& QCMD_SECURE
) && (message
!= LU_SECUREMSG
)) {
124 chanservstdmessage(sender
, QM_SECUREONLY
, cargv
[0], chanservnick
->nick
, myserver
->content
);
128 if ((cmd
->level
& QCMD_AUTHED
)) {
129 if (!(rup
=getreguserfromnick(sender
))) {
130 chanservstdmessage(sender
, QM_AUTHEDONLY
, cargv
[0]);
133 if (UIsSuspended(rup
) || (rup
->status
& QUSTAT_DEAD
)) {
134 chanservstdmessage(sender
, QM_BADAUTH
, cargv
[0]);
139 if ((cmd
->level
& QCMD_NOTAUTHED
) && (getreguserfromnick(sender
))) {
140 chanservstdmessage(sender
, QM_UNAUTHEDONLY
, cargv
[0]);
144 if ((cmd
->level
& QCMD_HELPER
) &&
145 (!(rup
=getreguserfromnick(sender
)) || !UHasHelperPriv(rup
))) {
146 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
150 if ((cmd
->level
& QCMD_OPER
) &&
151 (!IsOper(sender
) || !(rup
=getreguserfromnick(sender
)) || !UHasOperPriv(rup
))) {
152 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
156 if ((cmd
->level
& QCMD_ADMIN
) &&
157 (!IsOper(sender
) || !(rup
=getreguserfromnick(sender
)) || !UHasAdminPriv(rup
))) {
158 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
162 if ((cmd
->level
& QCMD_DEV
) &&
163 (!IsOper(sender
) || !(rup
=getreguserfromnick(sender
)) || !UIsDev(rup
))) {
164 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
168 if (cmd
->maxparams
< (cargc
-1)) {
169 rejoinline(cargv
[cmd
->maxparams
],cargc
-(cmd
->maxparams
));
170 cargc
=(cmd
->maxparams
)+1;
173 cmd
->handler((void *)sender
, cargc
-1, &(cargv
[1]));
182 void chanservcommandinit() {
183 cscommands
=newcommandtree();
184 csctcpcommands
=newcommandtree();
187 void chanservcommandclose() {
188 destroycommandtree(cscommands
);
189 destroycommandtree(csctcpcommands
);
192 void chanservaddcommand(char *command
, int flags
, int maxparams
, CommandHandler handler
, char *description
, const char *help
) {
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
));
201 summary
->def
=getsstring(description
, 250);
202 summary
->defhelp
=(char *)help
; /* Assume that help is a constant */
204 newcmd
->ext
=(void *)summary
;
205 loadcommandsummary(newcmd
);
208 void chanservaddctcpcommand(char *command
, CommandHandler handler
) {
209 addcommandtotree(csctcpcommands
, command
, 0, 1, handler
);
212 void chanservremovectcpcommand(char *command
, CommandHandler handler
) {
213 deletecommandfromtree(csctcpcommands
, command
, handler
);
216 void chanservremovecommand(char *command
, CommandHandler handler
) {
221 if (!(cmd
=findcommandintree(cscommands
, command
, 1))) {
222 Error("chanserv",ERR_WARNING
,"Tried to unregister unknown command %s",command
);
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
]);
235 deletecommandfromtree(cscommands
, command
, handler
);
238 void chanservjoinchan(channel
*cp
) {
246 /* Skip unregistered channels */
247 if (!(rcp
=cp
->index
->exts
[chanservext
]))
250 /* Check for a new timestamp */
251 if ((!rcp
->ltimestamp
) || (cp
->timestamp
< rcp
->ltimestamp
)) {
252 rcp
->ltimestamp
=cp
->timestamp
;
253 csdb_updatechanneltimestamp(rcp
);
256 /* We won't be doing any joining or parting if we're not online */
260 if ((CIsSuspended(rcp
) || !CIsJoined(rcp
)) && getnumerichandlefromchanhash(cp
->users
, chanservnick
->numeric
)) {
261 if(rcp
->suspendreason
) {
262 localpartchannel(chanservnick
, cp
, rcp
->suspendreason
->content
);
264 localpartchannel(chanservnick
, cp
, NULL
);
268 /* Right, we are definately going to either join the channel or at least
269 * burst some modes onto it.
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
273 * up later. For modes we use the forced modes, plus the default channel
274 * modes (unless any of those are explicitly denied) */
276 /* By default, we set the forcemodes and the default modes, but never denymodes */
277 themodes
= (CHANMODE_DEFAULT
| rcp
->forcemodes
) & ~rcp
->denymodes
;
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.
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
)) &&
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
);
300 /* We should be on the channel - join with our nick */
301 if (!CIsSuspended(rcp
) && CIsJoined(rcp
) && !getnumerichandlefromchanhash(cp
->users
, chanservnick
->numeric
)) {
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
);
308 /* We're not joining the channel - send the burst with no nick */
309 if (!CIsSuspended(rcp
) && !CIsJoined(rcp
) && (cp
->timestamp
> rcp
->ltimestamp
)) {
310 localburstontochannel(cp
, NULL
, rcp
->ltimestamp
, themodes
,
311 rcp
->limit
, (rcp
->key
)?rcp
->key
->content
:NULL
);
315 void chanservstdmessage(nick
*np
, int messageid
, ... ) {
326 if (getreguserfromnick(np
) == NULL
) {
330 rup
=getreguserfromnick(np
);
336 language
=rup
->languageid
;
339 if (csmessages
[language
][messageid
]) {
340 message
=csmessages
[language
][messageid
]->content
;
341 } else if (csmessages
[0][messageid
]) {
342 message
=csmessages
[0][messageid
]->content
;
344 message
=defaultmessages
[messageid
];
347 va_start(va
,messageid
);
348 vsnprintf(buf
,5000,message
,va
);
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') {
362 if (chanservnick
&& *buf2
) {
364 sendnoticetouser(chanservnick
,np
,"%s",buf2
);
366 sendmessagetouser(chanservnick
,np
,"%s",buf2
);
370 /* If we ran out of buffer, get out here */
383 void chanservsendmessage(nick
*np
, char *message
, ... ) {
384 char buf
[5010]; /* Very large buffer.. */
385 char buf2
[512], *bp
, *bp2
;
392 va_start(va
,message
);
393 vsnprintf(buf
,5000,message
,va
);
396 if (getreguserfromnick(np
) == NULL
) {
399 rup
=getreguserfromnick(np
);
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') {
418 if (chanservnick
&& *buf2
) {
420 sendnoticetouser(chanservnick
,np
,"%s",buf2
);
422 sendmessagetouser(chanservnick
,np
,"%s",buf2
);
426 /* If we ran out of buffer, get out here */
439 void chanservwallmessage(char *message
, ... ) {
440 char buf
[5010]; /* Very large buffer.. */
445 va_start(va
,message
);
446 vsnprintf(buf
,5000,message
,va
);
450 for (i
=0;i
<NICKHASHSIZE
;i
++)
451 for (np
=nicktable
[i
];np
;np
=np
->next
)
453 chanservsendmessage(np
, "%s", buf
);
456 void chanservkillstdmessage(nick
*target
, int messageid
, ... ) {
463 if (!(rup
=getreguserfromnick(target
)))
466 language
=rup
->languageid
;
468 if (csmessages
[language
][messageid
])
469 message
=csmessages
[language
][messageid
]->content
;
470 else if (csmessages
[0][messageid
])
471 message
=csmessages
[0][messageid
]->content
;
473 message
=defaultmessages
[messageid
];
475 va_start(va
, messageid
);
476 vsnprintf(buf
, 511, message
, va
);
478 killuser(chanservnick
, target
, buf
);
481 int checkpassword(reguser
*rup
, const char *pass
) {
482 if (!strncmp(rup
->password
, pass
, PASSLEN
))
487 int checkresponse(reguser
*rup
, const unsigned char *entropy
, const char *response
, CRAlgorithm algorithm
) {
488 char usernamel
[NICKLEN
+1], *dp
, *up
;
490 for(up
=rup
->username
,dp
=usernamel
;*up
;)
491 *dp
++ = ToLower(*up
++);
494 return algorithm(usernamel
, rup
->password
, cs_calcchallenge(entropy
), response
);
497 int checkhashpass(reguser
*rup
, const char *junk
, const char *hash
) {
498 char usernamel
[NICKLEN
+1], *dp
, *up
;
500 for(up
=rup
->username
,dp
=usernamel
;*up
;)
501 *dp
++ = ToLower(*up
++);
504 return cs_checkhashpass(usernamel
, rup
->password
, junk
, hash
);
507 int setpassword(reguser
*rup
, const char *pass
) {
508 strncpy(rup
->password
, pass
, PASSLEN
);
509 rup
->password
[PASSLEN
]='\0';
513 void cs_checknick(nick
*np
) {
516 char userhost
[USERLEN
+HOSTLEN
+3];
518 if (!(aup
=getactiveuserfromnick(np
))) {
520 np
->exts
[chanservnext
]=aup
;
523 assert(getactiveuserfromnick(np
));
525 if (IsAccount(np
) && np
->auth
) {
526 if (np
->auth
->exts
[chanservaext
]) {
527 cs_doallautomodes(np
);
529 /* Auto create user.. */
532 rup
->ID
=np
->auth
->userid
;
533 if (rup
->ID
> lastuserID
)
535 strncpy(rup
->username
,np
->authname
,NICKLEN
); rup
->username
[NICKLEN
]='\0';
536 rup
->created
=time(NULL
);
537 rup
->lastauth
=time(NULL
); /* questionable */
538 rup
->lastemailchange
=0;
539 rup
->flags
=QUFLAG_NOTICE
;
543 rup
->password
[0]='\0';
548 sprintf(userhost
,"%s@%s",np
->ident
,np
->host
->name
->content
);
549 rup
->lastuserhost
=getsstring(userhost
,USERLEN
+HOSTLEN
+1);
550 rup
->suspendreason
=NULL
;
556 addregusertohash(rup
);
558 csdb_createuser(rup
);
562 cs_checknickbans(np
);
565 void cs_checkchanmodes(channel
*cp
) {
568 localsetmodeinit (&changes
, cp
, chanservnick
);
569 cs_docheckchanmodes(cp
, &changes
);
570 localsetmodeflush (&changes
, 1);
573 void cs_docheckchanmodes(channel
*cp
, modechanges
*changes
) {
579 if ((rcp
=cp
->index
->exts
[chanservext
])==NULL
|| CIsSuspended(rcp
))
582 /* Take care of the simple modes */
583 localdosetmode_simple(changes
, rcp
->forcemodes
& ~(cp
->flags
), rcp
->denymodes
& cp
->flags
);
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
) {
589 Error("chanserv",ERR_WARNING
,"Key forced but no key specified for %s: cleared forcemode.",rcp
->index
->name
->content
);
590 rcp
->forcemodes
&= ~CHANMODE_KEY
;
591 csdb_updatechannel(rcp
);
593 localdosetmode_key(changes
, rcp
->key
->content
, MCB_ADD
);
597 /* Check for denied key */
598 if ((rcp
->denymodes
& CHANMODE_KEY
) && IsKey(cp
)) {
599 localdosetmode_key(changes
, NULL
, MCB_DEL
);
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
);
608 void cs_docheckopvoice(channel
*cp
, modechanges
*changes
) {
618 if ((rcp
=cp
->index
->exts
[chanservext
])==NULL
|| CIsSuspended(rcp
))
621 for (i
=0;i
<cp
->users
->hashsize
;i
++) {
622 if (cp
->users
->content
[i
]==nouser
)
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
);
631 if ((rup
=getreguserfromnick(np
)))
632 rcup
=findreguseronchannel(rcp
,rup
);
636 if (rcup
&& CUIsBanned(rcup
) && !IsService(np
)) {
637 cs_banuser(changes
, cp
->index
, np
, NULL
);
641 if (!IsService(np
) && CIsKnownOnly(rcp
) && !(rcup
&& CUKnown(rcup
))) {
642 cs_banuser(changes
, cp
->index
, np
, "Authorised users only.");
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
);
651 if (rcup
&& (CUIsProtect(rcup
) || CIsProtect(rcp
)) && CUIsOp(rcup
) && !CUIsDeny(rcup
))
652 localdosetmode_nick(changes
, np
, MC_OP
);
655 if (cp
->users
->content
[i
] & CUMODE_VOICE
) {
656 if (rcup
&& CUIsQuiet(rcup
))
657 localdosetmode_nick(changes
, np
, MC_DEVOICE
);
659 if (rcup
&& (CUIsProtect(rcup
) || CIsProtect(rcp
)) && CUIsVoice(rcup
) && !CUIsQuiet(rcup
) && !(cp
->users
->content
[i
] & CUMODE_OP
))
660 localdosetmode_nick(changes
, np
, MC_VOICE
);
665 void cs_doallautomodes(nick
*np
) {
671 if (!(rup
=getreguserfromnick(np
)))
674 for (rcup
=rup
->knownon
;rcup
;rcup
=rcup
->nextbyuser
) {
675 if (rcup
->chan
->index
->channel
) {
677 if ((lp
=getnumerichandlefromchanhash(rcup
->chan
->index
->channel
->users
, np
->numeric
))) {
678 /* User is on channel.. */
680 /* Update last use time */
681 rcup
->usetime
=getnettime();
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
);
688 if (!CUIsDeny(rcup
) && CUIsOp(rcup
) &&
689 (CUIsProtect(rcup
) || CIsProtect(rcup
->chan
) || CUIsAutoOp(rcup
)))
690 localdosetmode_nick(&changes
, np
, MC_OP
);
693 if (*lp
& CUMODE_VOICE
) {
695 localdosetmode_nick(&changes
, np
, MC_DEVOICE
);
697 if (!CUIsQuiet(rcup
) && CUIsVoice(rcup
) && !(*lp
& CUMODE_OP
) &&
698 (CUIsProtect(rcup
) || CIsProtect(rcup
->chan
) || CUIsAutoVoice(rcup
)))
699 localdosetmode_nick(&changes
, np
, MC_VOICE
);
701 localsetmodeflush(&changes
, 1);
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
);
712 void cs_checknickbans(nick
*np
) {
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
*));
726 if ((rcp
=ca
[j
]->index
->exts
[chanservext
]) && !CIsSuspended(rcp
) &&
727 CIsEnforce(rcp
) && nickbanned(np
, ca
[j
]))
728 localkickuser(chanservnick
, ca
[j
], np
, "Banned.");
734 void cs_checkbans(channel
*cp
) {
746 if ((rcp
=cp
->index
->exts
[chanservext
])==NULL
|| CIsSuspended(rcp
))
751 localsetmodeinit(&changes
, cp
, chanservnick
);
753 for (i
=0;i
<cp
->users
->hashsize
;i
++) {
754 if (cp
->users
->content
[i
]==nouser
)
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
);
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
);
772 localkickuser(chanservnick
,cp
,np
,rbp
->reason
?rbp
->reason
->content
:"Banned.");
777 if (rbp
) /* If we broke out of above loop (due to kick) rbp will be set.. */
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.");
785 rcp
->lastbancheck
=time(NULL
);
789 localsetmodeflush(&changes
,1);
794 * This function schedules an update check on a channel
796 void cs_schedupdate(chanindex
*cip
, int mintime
, int maxtime
) {
797 int delay
=mintime
+(rand()%(maxtime
-mintime
));
800 if (!(rcp
=cip
->exts
[chanservext
]) || CIsSuspended(rcp
))
803 if (rcp
->checksched
) {
804 deleteschedule(rcp
->checksched
, cs_timerfunc
, cip
);
807 rcp
->checksched
=scheduleoneshot(time(NULL
)+delay
, cs_timerfunc
, cip
);
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
819 * To force a limit update, set rcp->limit to 0..
822 void cs_timerfunc(void *arg
) {
824 channel
*cp
=cip
->channel
;
829 time_t now
=time(NULL
);
832 if (!(rcp
=cip
->exts
[chanservext
]))
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
;
843 if (!cp
|| CIsSuspended(rcp
))
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
)) {
851 /* Only chanserv left in this channel */
852 if (now
>= (rcp
->lastpart
+ LINGERTIME
)) {
854 localpartchannel(chanservnick
, cip
->channel
, "Empty Channel");
857 if (!nextsched
|| nextsched
> (rcp
->lastpart
+ LINGERTIME
))
858 nextsched
=rcp
->lastpart
+LINGERTIME
;
862 localsetmodeinit(&changes
, cp
, chanservnick
);
864 if (CIsAutoLimit(rcp
)) {
865 if (!rcp
->limit
|| rcp
->autoupdate
<= now
) {
867 rcp
->limit
=cp
->users
->totalusers
+rcp
->autolimit
;
868 rcp
->status
|= QCSTAT_MODECHECK
;
870 /* And set the schedule for the next update */
871 rcp
->autoupdate
= now
+ AUTOLIMIT_INTERVAL
;
874 if (!nextsched
|| rcp
->autoupdate
<= nextsched
)
875 nextsched
=rcp
->autoupdate
;
878 if (rcp
->status
& QCSTAT_OPCHECK
) {
879 rcp
->status
&= ~QCSTAT_OPCHECK
;
880 cs_docheckopvoice(cp
, &changes
);
883 if (rcp
->status
& QCSTAT_MODECHECK
) {
884 rcp
->status
&= ~QCSTAT_MODECHECK
;
885 cs_docheckchanmodes(cp
, &changes
);
888 if (rcp
->status
& QCSTAT_BANCHECK
) {
889 rcp
->status
&= ~QCSTAT_BANCHECK
;
893 /* This ban check is AFTER docheckopvoice in case checkopvoice set a
894 * ban which we need to automatically remove later.. */
896 if (rcp
->banduration
) {
897 for (cbp
=cp
->bans
;cbp
;cbp
=ncbp
) {
899 if (cbp
->timeset
+rcp
->banduration
<=now
) {
900 localdosetmode_ban(&changes
, bantostring(cbp
), MCB_DEL
);
902 if (!nextsched
|| cbp
->timeset
+rcp
->banduration
<= nextsched
) {
903 nextsched
=rcp
->banduration
+cbp
->timeset
;
909 /* Check for expiry of registered bans */
911 for (rbh
=&(rcp
->bans
);*rbh
;) {
913 verifyregchanban(rbp
);
914 if (rbp
->expiry
&& (rbp
->expiry
< now
)) {
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 */
921 /* Remove from list */
923 /* Free ban/string and update setby refcount, and free actual regban */
924 freesstring(rbp
->reason
);
925 freechanban(rbp
->cbp
);
928 if (rbp
->expiry
&& (!nextsched
|| rbp
->expiry
<= nextsched
)) {
929 nextsched
=rbp
->expiry
;
937 rcp
->checksched
=scheduleoneshot(nextsched
, cs_timerfunc
, arg
);
939 localsetmodeflush(&changes
, 1);
942 void cs_removechannel(regchan
*rcp
) {
945 regchanuser
*rcup
, *nrcup
;
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
);
958 for (rbp
=rcp
->bans
;rbp
;rbp
=nrbp
) {
960 freesstring(rbp
->reason
);
961 freechanban(rbp
->cbp
);
968 deleteschedule(rcp
->checksched
, cs_timerfunc
, rcp
->index
);
971 rcp
->flags
=QCFLAG_SUSPENDED
;
972 chanservjoinchan(cip
->channel
); /* Force off the channel */
975 csdb_deletechannel(rcp
);
977 freesstring(rcp
->welcome
);
978 freesstring(rcp
->topic
);
979 freesstring(rcp
->key
);
980 freesstring(rcp
->suspendreason
);
981 freesstring(rcp
->comment
);
985 cip
->exts
[chanservext
]=NULL
;
986 releasechanindex(cip
);
989 void cs_removeuser(reguser
*rup
) {
991 regchanuser
*rcup
, *nrcup
;
993 struct authname
*anp
;
995 /* Remove the user from all its channels */
996 for (rcup
=rup
->knownon
;rcup
;rcup
=nrcup
) {
997 nrcup
=rcup
->nextbyuser
;
998 freesstring(rcup
->info
);
1001 delreguserfromchannel(rcp
, rup
);
1003 for (i
=0;i
<REGCHANUSERHASHSIZE
;i
++) {
1004 if (rcp
->regusers
[i
])
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
);
1014 freeregchanuser(rcup
);
1018 delreguserfrommaildomain(rup
,rup
->domain
);
1019 freesstring(rup
->localpart
);
1020 freesstring(rup
->email
);
1021 freesstring(rup
->lastuserhost
);
1022 freesstring(rup
->suspendreason
);
1023 freesstring(rup
->comment
);
1024 freesstring(rup
->info
);
1026 csdb_deleteuser(rup
);
1028 removereguserfromhash(rup
);
1030 if ((anp
=findauthname(rup
->ID
)) && anp
->nicks
) {
1031 rup
->status
|= QUSTAT_DEAD
;
1037 int cs_bancheck(nick
*np
, channel
*cp
) {
1038 time_t now
=time(NULL
);
1040 modechanges changes
;
1043 if (!(rcp
=cp
->index
->exts
[chanservext
]))
1046 for (rbh
=&(rcp
->bans
);*rbh
;) {
1047 if ((*rbh
)->expiry
&& ((*rbh
)->expiry
< now
)) {
1049 csdb_deleteban(*rbh
);
1053 freesstring(rbp
->reason
);
1054 freechanban(rbp
->cbp
);
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
);
1066 localkickuser(chanservnick
, cp
, np
, (*rbh
)->reason
? (*rbh
)->reason
->content
: "Banned.");
1069 rbh
=&((*rbh
)->next
);
1076 void cs_setregban(chanindex
*cip
, regban
*rbp
) {
1077 modechanges changes
;
1084 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1085 localdosetmode_ban(&changes
, bantostring(rbp
->cbp
), MCB_ADD
);
1086 localsetmodeflush(&changes
, 1);
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
])) &&
1092 nickmatchban(np
, rbp
->cbp
))
1093 localkickuser(chanservnick
, cip
->channel
, np
, rbp
->reason
? rbp
->reason
->content
: "Banned.");
1099 void cs_banuser(modechanges
*changes
, chanindex
*cip
, nick
*np
, const char *reason
) {
1100 modechanges lchanges
;
1101 char banmask
[NICKLEN
+USERLEN
+HOSTLEN
+3];
1106 if (nickbanned(np
, cip
->channel
)) {
1107 localkickuser(chanservnick
, cip
->channel
, np
, reason
?reason
:"Banned.");
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
);
1121 sprintf(banmask
,"*!*@%s",np
->host
->name
->content
);
1125 localsetmodeinit(&lchanges
, cip
->channel
, chanservnick
);
1126 localdosetmode_ban(&lchanges
, banmask
, MCB_ADD
);
1127 localsetmodeflush(&lchanges
, 1);
1129 localdosetmode_ban(changes
, banmask
, MCB_ADD
);
1132 localkickuser(chanservnick
, cip
->channel
, np
, reason
?reason
:"Banned.");
1136 * cs_sanitisechanlev: Removes impossible combinations from chanlev flags.
1137 * chanservuser.c is probably not the right file for this, but nowhere better
1138 * presented itself...
1140 flag_t
cs_sanitisechanlev(flag_t flags
) {
1141 /* +m or +n cannot have any "punishment" flags */
1142 if (flags
& (QCUFLAG_MASTER
| QCUFLAG_OWNER
))
1143 flags
&= ~(QCUFLAG_BANNED
| QCUFLAG_QUIET
| QCUFLAG_DENY
);
1145 /* +d can't be +o */
1146 if (flags
& QCUFLAG_DENY
)
1147 flags
&= ~QCUFLAG_OP
;
1149 /* +q can't be +v */
1150 if (flags
& QCUFLAG_QUIET
)
1151 flags
&= ~QCUFLAG_VOICE
;
1153 /* +p trumps +a and +g */
1154 if (flags
& QCUFLAG_PROTECT
)
1155 flags
&= ~(QCUFLAG_AUTOOP
| QCUFLAG_AUTOVOICE
);
1157 /* -o can't be +a */
1158 if (!(flags
& QCUFLAG_OP
))
1159 flags
&= ~QCUFLAG_AUTOOP
;
1161 /* +a or -v can't be +g. +a implies +o at this stage (see above) */
1162 if (!(flags
& QCUFLAG_VOICE
) || (flags
& QCUFLAG_AUTOOP
))
1163 flags
&= ~QCUFLAG_AUTOVOICE
;
1165 /* +p requires +o or +v */
1166 if (!(flags
& (QCUFLAG_VOICE
| QCUFLAG_OP
)))
1167 flags
&= ~QCUFLAG_PROTECT
;
1169 /* The personal flags require one of +mnovk */
1170 if (!(flags
& (QCUFLAG_OWNER
| QCUFLAG_MASTER
| QCUFLAG_OP
| QCUFLAG_VOICE
| QCUFLAG_KNOWN
)))
1171 flags
&= ~QCUFLAGS_PERSONAL
;
1178 * This function does the standard "nick or #user" lookup.
1179 * If "sender" is not NULL, a suitable error message will
1180 * be sent if the lookup fails.
1181 * "sender" MUST be sent when a user is requesting a lookup
1182 * as there is some policy code here.
1185 reguser
*findreguser(nick
*sender
, const char *str
) {
1186 reguser
*rup
, *vrup
= getreguserfromnick(sender
);;
1195 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1198 if (!(rup
=findreguserbynick(str
+1)) && sender
)
1199 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1200 } else if (*str
=='&' && vrup
&& UHasHelperPriv(vrup
)) {
1203 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1206 if (!(rup
=findreguserbyID(atoi(str
+1))) && sender
)
1207 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1209 if (!(np
=getnickbynick(str
))) {
1211 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1214 if (!(rup
=getreguserfromnick(np
)) && sender
)
1215 chanservstdmessage(sender
, QM_USERNOTAUTHED
, str
);
1218 /* removed the suspended check from here, I don't see the point... */
1219 if (rup
&& (rup
->status
& QUSTAT_DEAD
)) {
1220 chanservstdmessage(sender
, QM_USERHASBADAUTH
, rup
->username
);
1228 * Unbans a mask from a channel, including permbans if user has correct privs.
1230 void cs_unbanfn(nick
*sender
, chanindex
*cip
, UnbanFN fn
, void *arg
, int removepermbans
) {
1232 chanban
**cbh
, *cbp
;
1234 modechanges changes
;
1237 rcp
=cip
->exts
[chanservext
];
1240 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1242 for (rbh
=&(rcp
->bans
); *rbh
; ) {
1244 if (fn(arg
, rbp
->cbp
)) {
1245 banstr
=bantostring(rbp
->cbp
);
1246 /* Check perms and remove */
1247 if(!removepermbans
) {
1248 chanservstdmessage(sender
, QM_WARNNOTREMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1250 } else if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, NULL
, 0, 1)) {
1251 chanservstdmessage(sender
, QM_NOTREMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1254 chanservstdmessage(sender
, QM_REMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1256 localdosetmode_ban(&changes
, banstr
, MCB_DEL
);
1257 /* Remove from database */
1258 csdb_deleteban(rbp
);
1259 /* Remove from list */
1261 /* Free ban/string and update setby refcount, and free actual regban */
1262 freesstring(rbp
->reason
);
1263 freechanban(rbp
->cbp
);
1272 for (cbh
=&(cip
->channel
->bans
); *cbh
; ) {
1276 banstr
=bantostring(cbp
);
1277 chanservstdmessage(sender
, QM_REMOVEDCHANBAN
, banstr
, cip
->name
->content
);
1278 localdosetmode_ban(&changes
, banstr
, MCB_DEL
);
1283 localsetmodeflush(&changes
,1);