]>
jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanservuser.c
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
,*csaccount
;
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
);
45 Error("chanserv",ERR_INFO
,"Connecting %s...",csnick
->content
);
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
);
55 freesstring(csrealname
);
56 freesstring(csaccount
);
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
: "");
73 Error("chanserv",ERR_INFO
,"Loaded and joined channels.");
75 if (chanserv_init_status
== CS_INIT_NOUSER
) {
76 /* If this is the first time, perform last init tasks */
81 void chanservuserhandler(nick
*target
, int message
, void **params
) {
92 scheduleoneshot(time(NULL
),&chanservreguser
,NULL
);
98 sender
=(nick
*)params
[0];
99 msg
=(char *)params
[1];
101 if (!(cargc
=splitline(msg
,cargv
,30,0)))
102 return; /* Ignore blank lines */
104 if (cargv
[0][0]==1) {
106 for (chp
=cargv
[0]+1;*chp
;chp
++) {
112 cmd
=findcommandintree(csctcpcommands
, cargv
[0]+1, 1);
115 rejoinline(cargv
[1],cargc
-1);
116 cmd
->handler((void *)sender
, cargc
-1, &(cargv
[1]));
119 cmd
=findcommandintree(cscommands
, cargv
[0], 1);
122 chanservstdmessage(sender
, QM_UNKNOWNCMD
, cargv
[0]);
126 if ((cmd
->level
& QCMD_SECURE
) && (message
!= LU_SECUREMSG
)) {
127 chanservstdmessage(sender
, QM_SECUREONLY
, cargv
[0], chanservnick
->nick
, myserver
->content
);
131 if ((cmd
->level
& QCMD_AUTHED
)) {
132 if (!(rup
=getreguserfromnick(sender
))) {
133 chanservstdmessage(sender
, QM_AUTHEDONLY
, cargv
[0]);
136 if (UIsSuspended(rup
) || (rup
->status
& QUSTAT_DEAD
)) {
137 chanservstdmessage(sender
, QM_BADAUTH
, cargv
[0]);
142 if ((cmd
->level
& QCMD_NOTAUTHED
) && (getreguserfromnick(sender
))) {
143 chanservstdmessage(sender
, QM_UNAUTHEDONLY
, cargv
[0]);
147 if ((cmd
->level
& QCMD_STAFF
) &&
148 (!(rup
=getreguserfromnick(sender
)) || !UHasStaffPriv(rup
))) {
149 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
153 if ((cmd
->level
& QCMD_HELPER
) &&
154 (!(rup
=getreguserfromnick(sender
)) || !UHasHelperPriv(rup
))) {
155 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
159 if ((cmd
->level
& QCMD_OPER
) &&
160 (!IsOper(sender
) || !(rup
=getreguserfromnick(sender
)) || !UHasOperPriv(rup
))) {
161 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
165 if ((cmd
->level
& QCMD_ADMIN
) &&
166 (!IsOper(sender
) || !(rup
=getreguserfromnick(sender
)) || !UHasAdminPriv(rup
))) {
167 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
171 if ((cmd
->level
& QCMD_DEV
) &&
172 (!IsOper(sender
) || !(rup
=getreguserfromnick(sender
)) || !UIsDev(rup
))) {
173 chanservstdmessage(sender
, QM_NOACCESS
, cargv
[0]);
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]);
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]);
193 if (cmd
->maxparams
< (cargc
-1)) {
194 rejoinline(cargv
[cmd
->maxparams
],cargc
-(cmd
->maxparams
));
195 cargc
=(cmd
->maxparams
)+1;
198 cmd
->handler((void *)sender
, cargc
-1, &(cargv
[1]));
200 triggerhook(HOOK_CHANSERV_CMD
, sender
);
209 void chanservcommandinit() {
210 cscommands
=newcommandtree();
211 csctcpcommands
=newcommandtree();
214 void chanservcommandclose() {
215 destroycommandtree(cscommands
);
216 destroycommandtree(csctcpcommands
);
219 void chanservaddcommand(char *command
, int flags
, int maxparams
, CommandHandler handler
, char *description
, const char *help
) {
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
));
228 summary
->def
=getsstring(description
, 250);
229 summary
->defhelp
=(char *)help
; /* Assume that help is a constant */
231 newcmd
->ext
=(void *)summary
;
232 loadcommandsummary(newcmd
);
235 void chanservaddctcpcommand(char *command
, CommandHandler handler
) {
236 addcommandtotree(csctcpcommands
, command
, 0, 1, handler
);
239 void chanservremovectcpcommand(char *command
, CommandHandler handler
) {
240 deletecommandfromtree(csctcpcommands
, command
, handler
);
243 void chanservremovecommand(char *command
, CommandHandler handler
) {
248 if (!(cmd
=findcommandintree(cscommands
, command
, 1))) {
249 Error("chanserv",ERR_WARNING
,"Tried to unregister unknown command %s",command
);
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
]);
262 deletecommandfromtree(cscommands
, command
, handler
);
265 void chanservpartchan(channel
*cp
, char *reason
) {
266 /* Sanity check that we exist and are on the channel.
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
))
274 localpartchannel(chanservnick
, cp
, reason
);
277 void chanservjoinchan(channel
*cp
) {
285 /* Skip unregistered channels */
286 if (!(rcp
=cp
->index
->exts
[chanservext
]))
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
);
295 /* We won't be doing any joining or parting if we're not online */
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
);
305 /* Right, we are definately going to either join the channel or at least
306 * burst some modes onto it.
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) */
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
;
320 themodes
= (themodes
| rcp
->forcemodes
) & ~rcp
->denymodes
;
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.
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
)) &&
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
);
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
);
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
);
358 static void __chanservstdvmessage(nick
*np
, reguser
*rup
, int messageid
, int max_line_len
, void (*callback
)(nick
*, char *), ...) {
360 va_start(va
, callback
);
361 chanservstdvmessage(np
, rup
, messageid
, max_line_len
, callback
, va
);
365 void chanservstdvmessage(nick
*np
, reguser
*rup
, int messageid
, int max_line_len
, void (*callback
)(nick
*, char *), va_list va
) {
370 char *message
, *messageargs
;
374 if(max_line_len
<= 0)
375 max_line_len
= 490 + max_line_len
;
380 language
=rup
->languageid
;
383 if (csmessages
[language
][messageid
]) {
384 message
=csmessages
[language
][messageid
]->content
;
385 } else if (csmessages
[0][messageid
]) {
386 message
=csmessages
[0][messageid
]->content
;
388 message
=defaultmessages
[messageid
*2];
391 messageargs
=defaultmessages
[messageid
*2+1];
394 q9vsnprintf(buf
,5000,message
,messageargs
,va
);
398 for (bp
=buf
; ;bp
++) {
399 /* We send something if we hit a \n, fill the buffer or run out of source */
400 if (*bp
=='\n' || len
>max_line_len
|| !*bp
) {
401 if (*bp
&& *bp
!='\n') {
407 if (chanservnick
&& *buf2
)
410 /* If we ran out of buffer, get out here */
422 /* Special case: If it's a "not enough parameters" message, show the first line of help */
423 if (messageid
==QM_NOTENOUGHPARAMS
) {
424 char *command
=va_arg(va2
, char *);
425 cs_sendhelp(np
, command
, 1);
426 __chanservstdvmessage(np
, rup
, QM_TYPEHELPFORHELP
, max_line_len
, callback
, command
);
432 static void message_callback(nick
*np
, char *buf
) {
433 sendmessagetouser(chanservnick
,np
,"%s",buf
);
436 static void notice_callback(nick
*np
, char *buf
) {
437 sendnoticetouser(chanservnick
,np
,"%s",buf
);
440 void chanservstdmessage(nick
*np
, int messageid
, ...) {
445 rup
= getreguserfromnick(np
);
446 notice
= rup
== NULL
? 1 : UIsNotice(rup
);
448 va_start(va
, messageid
);
449 chanservstdvmessage(np
, rup
, messageid
, 0, notice
? notice_callback
: message_callback
, va
);
453 void chanservsendmessage_real(nick
*np
, int oneline
, char *message
, ... ) {
454 char buf
[5010]; /* Very large buffer.. */
455 char buf2
[512], *bp
, *bp2
;
462 va_start(va
,message
);
463 vsnprintf(buf
,5000,message
,va
);
466 if (getreguserfromnick(np
) == NULL
) {
469 rup
=getreguserfromnick(np
);
479 for (bp
=buf
; ;bp
++) {
480 /* We send something if we hit a \n, fill the buffer or run out of source */
481 if (*bp
=='\n' || len
>490 || !*bp
) {
482 if (*bp
&& *bp
!='\n') {
488 if (chanservnick
&& *buf2
) {
490 sendnoticetouser(chanservnick
,np
,"%s",buf2
);
492 sendmessagetouser(chanservnick
,np
,"%s",buf2
);
496 /* If we ran out of buffer, get out here */
497 if (!*bp
|| (*bp
=='\n' && oneline
))
509 void chanservwallmessage(char *message
, ... ) {
510 char buf
[5010]; /* Very large buffer.. */
515 va_start(va
,message
);
516 vsnprintf(buf
,5000,message
,va
);
520 for (i
=0;i
<NICKHASHSIZE
;i
++) {
521 for (np
=nicktable
[i
];np
;np
=np
->next
) {
522 if (!IsOper(np
)) /* optimisation, if VIEWWALLMESSAGE changes change this */
525 if (!cs_privcheck(QPRIV_VIEWWALLMESSAGE
, np
))
528 chanservsendmessage(np
, "%s", buf
);
533 void chanservkillstdmessage(nick
*target
, int messageid
, ... ) {
536 char *message
, *messageargs
;
540 if (!(rup
=getreguserfromnick(target
)))
543 language
=rup
->languageid
;
545 if (csmessages
[language
][messageid
])
546 message
=csmessages
[language
][messageid
]->content
;
547 else if (csmessages
[0][messageid
])
548 message
=csmessages
[0][messageid
]->content
;
550 message
=defaultmessages
[messageid
*2];
552 messageargs
=defaultmessages
[messageid
*2+1];
553 va_start(va
, messageid
);
554 q9vsnprintf(buf
, 511, message
, messageargs
, va
);
556 killuser(chanservnick
, target
, "%s", buf
);
559 int checkpassword(reguser
*rup
, const char *pass
) {
560 if (!(*rup
->password
))
563 if (!strncmp(rup
->password
, pass
, PASSLEN
))
568 int checkresponse(reguser
*rup
, const unsigned char *entropy
, const char *response
, CRAlgorithm algorithm
) {
569 char usernamel
[NICKLEN
+1], *dp
, *up
;
571 if (!(*rup
->password
))
574 for(up
=rup
->username
,dp
=usernamel
;*up
;)
575 *dp
++ = ToLower(*up
++);
578 return algorithm(usernamel
, rup
->password
, cs_calcchallenge(entropy
), response
);
581 int checkhashpass(reguser
*rup
, const char *junk
, const char *hash
) {
582 char usernamel
[NICKLEN
+1], *dp
, *up
;
584 for(up
=rup
->username
,dp
=usernamel
;*up
;)
585 *dp
++ = ToLower(*up
++);
588 return cs_checkhashpass(usernamel
, rup
->password
, junk
, hash
);
591 int setpassword(reguser
*rup
, const char *pass
) {
592 strncpy(rup
->password
, pass
, PASSLEN
);
593 rup
->password
[PASSLEN
]='\0';
597 void cs_checknick(nick
*np
) {
600 char userhost
[USERLEN
+HOSTLEN
+3];
602 if (!(aup
=getactiveuserfromnick(np
))) {
604 np
->exts
[chanservnext
]=aup
;
607 assert(getactiveuserfromnick(np
));
609 if (IsAccount(np
) && np
->auth
) {
610 if (np
->auth
->exts
[chanservaext
]) {
611 rup
=getreguserfromnick(np
);
615 if (UIsDelayedGline(rup
)) {
616 /* delayed-gline - schedule the user's squelching */
617 deleteschedule(NULL
, &chanservdgline
, (void*)rup
); /* icky, but necessary unless we stick more stuff in reguser structure */
618 scheduleoneshot(time(NULL
)+rand()%900
, &chanservdgline
, (void*)rup
);
619 } else if (UIsGline(rup
)) {
620 /* instant-gline - lets be lazy and set a schedule expiring now :) */
621 deleteschedule(NULL
, &chanservdgline
, (void*)rup
); /* icky, but necessary unless we stick more stuff in reguser structure */
622 scheduleoneshot(time(NULL
), &chanservdgline
, (void*)rup
);
623 } else if(UHasSuspension(rup
)) {
624 chanservkillstdmessage(np
, QM_SUSPENDKILL
);
628 cs_doallautomodes(np
);
630 /* Auto create user.. */
633 rup
->ID
=np
->auth
->userid
;
634 if (rup
->ID
> lastuserID
)
636 strncpy(rup
->username
,np
->authname
,NICKLEN
); rup
->username
[NICKLEN
]='\0';
637 rup
->created
=time(NULL
);
639 rup
->lastemailchange
=0;
640 rup
->lastpasschange
=0;
641 rup
->flags
=QUFLAG_NOTICE
;
647 rup
->password
[0]='\0';
653 sprintf(userhost
,"%s@%s",np
->ident
,np
->host
->name
->content
);
654 rup
->lastuserhost
=getsstring(userhost
,USERLEN
+HOSTLEN
+1);
655 rup
->suspendreason
=NULL
;
661 addregusertohash(rup
);
663 csdb_createuser(rup
);
667 cs_checknickbans(np
);
670 void cs_checkchanmodes(channel
*cp
) {
673 localsetmodeinit (&changes
, cp
, chanservnick
);
674 cs_docheckchanmodes(cp
, &changes
);
675 localsetmodeflush (&changes
, 1);
678 void cs_docheckchanmodes(channel
*cp
, modechanges
*changes
) {
684 if ((rcp
=cp
->index
->exts
[chanservext
])==NULL
|| CIsSuspended(rcp
))
687 /* Take care of the simple modes */
688 localdosetmode_simple(changes
, rcp
->forcemodes
& ~(cp
->flags
), rcp
->denymodes
& cp
->flags
);
690 /* Check for forced key. Note that we ALWAYS call localdosetmode_key
691 * in case the wrong key is set atm */
692 if (rcp
->forcemodes
& CHANMODE_KEY
) {
694 Error("chanserv",ERR_WARNING
,"Key forced but no key specified for %s: cleared forcemode.",rcp
->index
->name
->content
);
695 rcp
->forcemodes
&= ~CHANMODE_KEY
;
696 csdb_updatechannel(rcp
);
698 localdosetmode_key(changes
, rcp
->key
->content
, MCB_ADD
);
702 /* Check for denied key */
703 if ((rcp
->denymodes
& CHANMODE_KEY
) && IsKey(cp
)) {
704 localdosetmode_key(changes
, NULL
, MCB_DEL
);
707 /* Check for forced limit. Always call in case of wrong limit */
708 if (rcp
->forcemodes
& CHANMODE_LIMIT
) {
709 localdosetmode_limit(changes
, rcp
->limit
, MCB_ADD
);
713 /* Slightly misnamed function that checks each USER on the channel against channel
714 * settings. Possible actions are opping/deopping, voicing/devoicing, and banning
715 * for chanflag +k or chanlev flag +b */
716 void cs_docheckopvoice(channel
*cp
, modechanges
*changes
) {
726 if ((rcp
=cp
->index
->exts
[chanservext
])==NULL
|| CIsSuspended(rcp
))
729 for (i
=0;i
<cp
->users
->hashsize
;i
++) {
730 if (cp
->users
->content
[i
]==nouser
)
733 if ((np
=getnickbynumeric(cp
->users
->content
[i
]))==NULL
) {
734 Error("chanserv",ERR_ERROR
,"Found non-existent numeric %lu on channel %s",cp
->users
->content
[i
],
735 cp
->index
->name
->content
);
739 if ((rup
=getreguserfromnick(np
)))
740 rcup
=findreguseronchannel(rcp
,rup
);
744 /* Various things that might ban the user - don't apply these to +o, +k or +X users */
745 if (!IsService(np
) && !IsXOper(np
) && !IsOper(np
)) {
746 if (rcup
&& CUIsBanned(rcup
)) {
747 cs_banuser(changes
, cp
->index
, np
, NULL
);
751 /* chanflag +k checks; kick them if they "obviously" can't rejoin without a ban */
752 if (CIsKnownOnly(rcp
) && !(rcup
&& CUKnown(rcup
))) {
753 if (IsInviteOnly(cp
) || (IsRegOnly(cp
) && !IsAccount(np
))) {
754 localkickuser(chanservnick
,cp
,np
,"Authorised users only.");
756 cs_banuser(NULL
, cp
->index
, np
, "Authorised users only.");
762 if ((cp
->users
->content
[i
] & CUMODE_OP
) && !IsService(np
)) {
763 if ((CIsBitch(rcp
) && (!rcup
|| !CUHasOpPriv(rcup
))) ||
764 (rcup
&& CUIsDeny(rcup
)))
765 localdosetmode_nick(changes
, np
, MC_DEOP
);
767 if (rcup
&& (CUIsProtect(rcup
) || CIsProtect(rcp
)) && CUIsOp(rcup
) && !CUIsDeny(rcup
)) {
768 localdosetmode_nick(changes
, np
, MC_OP
);
769 cs_logchanop(rcp
, np
->nick
, rcup
->user
);
773 if (cp
->users
->content
[i
] & CUMODE_VOICE
) {
774 if (rcup
&& CUIsQuiet(rcup
))
775 localdosetmode_nick(changes
, np
, MC_DEVOICE
);
777 if (rcup
&& (CUIsProtect(rcup
) || CIsProtect(rcp
)) && CUIsVoice(rcup
) && !CUIsQuiet(rcup
) && !(cp
->users
->content
[i
] & CUMODE_OP
))
778 localdosetmode_nick(changes
, np
, MC_VOICE
);
783 void cs_doallautomodes(nick
*np
) {
789 if (!(rup
=getreguserfromnick(np
)))
792 for (rcup
=rup
->knownon
;rcup
;rcup
=rcup
->nextbyuser
) {
793 /* Skip suspended channels */
794 if (CIsSuspended(rcup
->chan
))
797 if (rcup
->chan
->index
->channel
) {
799 if ((lp
=getnumerichandlefromchanhash(rcup
->chan
->index
->channel
->users
, np
->numeric
))) {
800 /* User is on channel.. */
802 /* Update last use time. Do early in case of ban. */
803 rcup
->usetime
=getnettime();
805 if (CUIsBanned(rcup
)) {
806 cs_banuser(NULL
, rcup
->chan
->index
, np
, NULL
);
810 if (CUHasOpPriv(rcup
) && cs_ischannelactive(rcup
->chan
->index
->channel
, NULL
)) {
811 /* This meets the channel use criteria, update. */
812 rcup
->chan
->lastactive
=time(NULL
);
814 /* Don't spam the DB though for channels with lots of joins */
815 if (rcup
->chan
->lastcountersync
< (time(NULL
) - COUNTERSYNCINTERVAL
)) {
816 csdb_updatechannelcounters(rcup
->chan
);
817 rcup
->chan
->lastcountersync
=time(NULL
);
821 localsetmodeinit(&changes
, rcup
->chan
->index
->channel
, chanservnick
);
822 if (*lp
& CUMODE_OP
) {
823 if (!IsService(np
) && (CUIsDeny(rcup
) || (CIsBitch(rcup
->chan
) && !CUHasOpPriv(rcup
))))
824 localdosetmode_nick(&changes
, np
, MC_DEOP
);
826 if (!CUIsDeny(rcup
) && CUIsOp(rcup
) &&
827 (CUIsProtect(rcup
) || CIsProtect(rcup
->chan
) || CUIsAutoOp(rcup
))) {
828 localdosetmode_nick(&changes
, np
, MC_OP
);
829 cs_logchanop(rcup
->chan
, np
->nick
, rup
);
833 if (*lp
& CUMODE_VOICE
) {
835 localdosetmode_nick(&changes
, np
, MC_DEVOICE
);
837 if (!CUIsQuiet(rcup
) && CUIsVoice(rcup
) && !(*lp
& CUMODE_OP
) &&
838 (CUIsProtect(rcup
) || CIsProtect(rcup
->chan
) || CUIsAutoVoice(rcup
)))
839 localdosetmode_nick(&changes
, np
, MC_VOICE
);
841 localsetmodeflush(&changes
, 1);
843 /* Channel exists but user is not joined: invite if they are +j-b */
844 if (CUIsAutoInvite(rcup
) && CUKnown(rcup
) && !CUIsBanned(rcup
)) {
845 localinvite(chanservnick
, rcup
->chan
->index
, np
);
848 } /* if (rcup->chan->index->channel) */ else {
849 /* Channel doesn't currently exist - send invite anyway for +j */
850 if (CUIsAutoInvite(rcup
) && CUKnown(rcup
) && !CUIsBanned(rcup
)) {
851 localinvite(chanservnick
, rcup
->chan
->index
, np
);
857 void cs_checknickbans(nick
*np
) {
862 if (IsService(np
) || IsOper(np
) || IsXOper(np
))
865 /* Avoid races: memcpy the channel array */
866 i
=np
->channels
->cursi
;
867 ca
=(channel
**)malloc(i
*sizeof(channel
*));
868 memcpy(ca
, np
->channels
->content
,i
*sizeof(channel
*));
871 if ((rcp
=ca
[j
]->index
->exts
[chanservext
]) && !CIsSuspended(rcp
) &&
872 CIsEnforce(rcp
) && nickbanned(np
, ca
[j
], 1))
873 localkickuser(chanservnick
, ca
[j
], np
, "Banned.");
879 void cs_checkbans(channel
*cp
) {
891 if ((rcp
=cp
->index
->exts
[chanservext
])==NULL
|| CIsSuspended(rcp
))
896 localsetmodeinit(&changes
, cp
, chanservnick
);
898 for (i
=0;i
<cp
->users
->hashsize
;i
++) {
899 if (cp
->users
->content
[i
]==nouser
)
902 if ((np
=getnickbynumeric(cp
->users
->content
[i
]))==NULL
) {
903 Error("chanserv",ERR_ERROR
,"Found numeric %lu on channel %s who doesn't exist.",
904 cp
->users
->content
[i
], cp
->index
->name
->content
);
908 if (IsService(np
) || IsOper(np
) || IsXOper(np
))
911 for (rbp
=rcp
->bans
;rbp
;rbp
=rbp
->next
) {
912 if (((!rbp
->expiry
) || (rbp
->expiry
<= now
)) &&
913 nickmatchban(np
, rbp
->cbp
, 1)) {
914 if (!nickbanned(np
, cp
, 1)) {
915 localdosetmode_ban(&changes
, bantostring(rbp
->cbp
), MCB_ADD
);
917 localkickuser(chanservnick
,cp
,np
,rbp
->reason
?rbp
->reason
->content
:"Banned.");
922 if (rbp
) /* If we broke out of above loop (due to kick) rbp will be set.. */
925 if (CIsEnforce(rcp
)) {
926 for (cbp
=cp
->bans
;cbp
;cbp
=cbp
->next
) {
927 if ((cbp
->timeset
>=rcp
->lastbancheck
) && nickmatchban(np
, cbp
, 1))
928 localkickuser(chanservnick
,cp
,np
,"Banned.");
930 rcp
->lastbancheck
=time(NULL
);
934 localsetmodeflush(&changes
,1);
939 * This function schedules an update check on a channel
941 void cs_schedupdate(chanindex
*cip
, int mintime
, int maxtime
) {
942 int delay
=mintime
+(rand()%(maxtime
-mintime
));
945 if (!(rcp
=cip
->exts
[chanservext
]) || CIsSuspended(rcp
))
948 if (rcp
->checksched
) {
949 deleteschedule(rcp
->checksched
, cs_timerfunc
, cip
);
952 rcp
->checksched
=scheduleoneshot(time(NULL
)+delay
, cs_timerfunc
, cip
);
957 * This function does several things:
958 * * Updates auto-limit and/or removes bans as necessary
959 * * Schedules the next timed call
960 * * Does any pending op/ban/mode checks
961 * It is safe to use either as a target for a schedule() call, or to call
962 * directly when parameters change (e.g. autolimit settings or ban expire
964 * To force a limit update, set rcp->limit to 0..
967 void cs_timerfunc(void *arg
) {
969 channel
*cp
=cip
->channel
;
974 time_t now
=time(NULL
);
977 if (!(rcp
=cip
->exts
[chanservext
]))
982 /* Always nullify the checksched even if the channel is suspended.. */
983 if (rcp
->checksched
) {
984 deleteschedule(rcp
->checksched
, cs_timerfunc
, arg
);
985 rcp
->checksched
=NULL
;
988 if (!cp
|| CIsSuspended(rcp
))
991 /* Check if we need to leave the channel first */
992 if (chanservnick
&& CIsJoined(rcp
) && cip
->channel
&&
993 cip
->channel
->users
->totalusers
==1 &&
994 getnumerichandlefromchanhash(cip
->channel
->users
, chanservnick
->numeric
)) {
996 /* Only chanserv left in this channel */
997 if (now
>= (rcp
->lastpart
+ LINGERTIME
)) {
999 localpartchannel(chanservnick
, cip
->channel
, "Empty Channel");
1002 if (!nextsched
|| nextsched
> (rcp
->lastpart
+ LINGERTIME
))
1003 nextsched
=rcp
->lastpart
+LINGERTIME
;
1007 localsetmodeinit(&changes
, cp
, chanservnick
);
1009 if (CIsAutoLimit(rcp
)) {
1010 if (!rcp
->limit
|| rcp
->autoupdate
<= now
) {
1011 /* Only update the limit if there are <= (autolimit/2) or
1012 * >= (autolimit * 1.5) slots free */
1014 if ((cp
->users
->totalusers
>= (rcp
->limit
- rcp
->autolimit
/2)) ||
1015 (cp
->users
->totalusers
<= (rcp
->limit
- (3 * rcp
->autolimit
)/2))) {
1016 rcp
->limit
=cp
->users
->totalusers
+rcp
->autolimit
;
1017 rcp
->status
|= QCSTAT_MODECHECK
;
1020 /* And set the schedule for the next update */
1021 rcp
->autoupdate
= now
+ AUTOLIMIT_INTERVAL
;
1024 if (!nextsched
|| rcp
->autoupdate
<= nextsched
)
1025 nextsched
=rcp
->autoupdate
;
1028 if (rcp
->status
& QCSTAT_OPCHECK
) {
1029 rcp
->status
&= ~QCSTAT_OPCHECK
;
1030 cs_docheckopvoice(cp
, &changes
);
1033 if (rcp
->status
& QCSTAT_MODECHECK
) {
1034 rcp
->status
&= ~QCSTAT_MODECHECK
;
1035 cs_docheckchanmodes(cp
, &changes
);
1038 if (rcp
->status
& QCSTAT_BANCHECK
) {
1039 rcp
->status
&= ~QCSTAT_BANCHECK
;
1043 /* This ban check is AFTER docheckopvoice in case checkopvoice set a
1044 * ban which we need to automatically remove later.. */
1046 if (rcp
->banduration
) {
1047 for (cbp
=cp
->bans
;cbp
;cbp
=ncbp
) {
1049 if (cbp
->timeset
+rcp
->banduration
<=now
) {
1050 localdosetmode_ban(&changes
, bantostring(cbp
), MCB_DEL
);
1052 if (!nextsched
|| cbp
->timeset
+rcp
->banduration
<= nextsched
) {
1053 nextsched
=rcp
->banduration
+cbp
->timeset
;
1059 /* Check for expiry of registered bans */
1061 for (rbh
=&(rcp
->bans
);*rbh
;) {
1063 verifyregchanban(rbp
);
1064 if (rbp
->expiry
&& (rbp
->expiry
< now
)) {
1066 /* Remove ban if it's on the channel (localdosetmode_ban will silently
1067 * skip bans that don't exist) */
1068 localdosetmode_ban(&changes
, bantostring(rbp
->cbp
), MCB_DEL
);
1069 /* Remove from database */
1070 csdb_deleteban(rbp
);
1071 /* Remove from list */
1073 /* Free ban/string and update setby refcount, and free actual regban */
1074 freesstring(rbp
->reason
);
1075 freechanban(rbp
->cbp
);
1078 if (rbp
->expiry
&& (!nextsched
|| rbp
->expiry
<= nextsched
)) {
1079 nextsched
=rbp
->expiry
;
1087 rcp
->checksched
=scheduleoneshot(nextsched
, cs_timerfunc
, arg
);
1089 localsetmodeflush(&changes
, 1);
1092 void cs_removechannel(regchan
*rcp
, char *reason
) {
1095 regchanuser
*rcup
, *nrcup
;
1100 for (i
=0;i
<REGCHANUSERHASHSIZE
;i
++) {
1101 for (rcup
=rcp
->regusers
[i
];rcup
;rcup
=nrcup
) {
1102 nrcup
=rcup
->nextbychan
;
1103 delreguserfromchannel(rcp
, rcup
->user
);
1104 freeregchanuser(rcup
);
1108 for (rbp
=rcp
->bans
;rbp
;rbp
=nrbp
) {
1110 freesstring(rbp
->reason
);
1111 freechanban(rbp
->cbp
);
1117 if (rcp
->checksched
)
1118 deleteschedule(rcp
->checksched
, cs_timerfunc
, rcp
->index
);
1121 chanservpartchan(cip
->channel
, reason
);
1124 csdb_deletechannel(rcp
);
1126 freesstring(rcp
->welcome
);
1127 freesstring(rcp
->topic
);
1128 freesstring(rcp
->key
);
1129 freesstring(rcp
->suspendreason
);
1130 freesstring(rcp
->comment
);
1134 cip
->exts
[chanservext
]=NULL
;
1135 releasechanindex(cip
);
1138 /* Sender is who the DELCHAN is attributed to.. */
1139 int cs_removechannelifempty(nick
*sender
, regchan
*rcp
) {
1143 for (i
=0;i
<REGCHANUSERHASHSIZE
;i
++) {
1144 for (rcup
=rcp
->regusers
[i
];rcup
;rcup
=rcup
->nextbychan
) {
1145 if (rcup
->flags
& ~(QCUFLAGS_PUNISH
))
1151 * don't cleanup the last channel to prevent channel id reuse.
1152 * the channel will be orphaned but will be cleaned up by cleanup eventually
1154 if(rcp
->ID
== lastchannelID
) {
1155 cs_log(sender
,"DELCHAN FAILED %s (last id)",rcp
->index
->name
->content
);
1159 cs_log(sender
,"DELCHAN %s (Empty)",rcp
->index
->name
->content
);
1160 cs_removechannel(rcp
, "Last user removed - channel deleted.");
1165 void cs_removeuser(reguser
*rup
) {
1166 regchanuser
*rcup
, *nrcup
;
1168 struct authname
*anp
;
1170 /* Remove the user from all its channels */
1171 for (rcup
=rup
->knownon
;rcup
;rcup
=nrcup
) {
1172 nrcup
=rcup
->nextbyuser
;
1175 delreguserfromchannel(rcp
, rup
);
1176 cs_removechannelifempty(NULL
, rcp
);
1180 delreguserfrommaildomain(rup
,rup
->domain
);
1181 freesstring(rup
->localpart
);
1182 freesstring(rup
->email
);
1183 freesstring(rup
->lastemail
);
1184 freesstring(rup
->lastuserhost
);
1185 freesstring(rup
->suspendreason
);
1186 freesstring(rup
->comment
);
1187 freesstring(rup
->info
);
1189 csdb_deleteuser(rup
);
1191 removereguserfromhash(rup
);
1193 if ((anp
=findauthname(rup
->ID
)) && anp
->nicks
) {
1194 rup
->status
|= QUSTAT_DEAD
;
1200 int cs_bancheck(nick
*np
, channel
*cp
) {
1201 time_t now
=time(NULL
);
1203 modechanges changes
;
1206 if (!(rcp
=cp
->index
->exts
[chanservext
]))
1209 for (rbh
=&(rcp
->bans
);*rbh
;) {
1210 if ((*rbh
)->expiry
&& ((*rbh
)->expiry
< now
)) {
1212 csdb_deleteban(*rbh
);
1216 freesstring(rbp
->reason
);
1217 freechanban(rbp
->cbp
);
1219 } else if (nickmatchban(np
,(*rbh
)->cbp
,1)) {
1220 /* This user matches this ban.. */
1221 if (!nickbanned(np
,cp
,1)) {
1222 /* Only bother putting the ban on the channel if they're not banned already */
1223 /* (might be covered by this ban or a different one.. doesn't really matter */
1224 localsetmodeinit(&changes
, cp
, chanservnick
);
1225 localdosetmode_ban(&changes
, bantostring((*rbh
)->cbp
), MCB_ADD
);
1226 localsetmodeflush(&changes
, 1);
1227 cs_timerfunc(cp
->index
);
1229 localkickuser(chanservnick
, cp
, np
, (*rbh
)->reason
? (*rbh
)->reason
->content
: "Banned.");
1232 rbh
=&((*rbh
)->next
);
1239 void cs_setregban(chanindex
*cip
, regban
*rbp
) {
1240 modechanges changes
;
1247 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1248 localdosetmode_ban(&changes
, bantostring(rbp
->cbp
), MCB_ADD
);
1249 localsetmodeflush(&changes
, 1);
1251 for (i
=0;(cip
->channel
) && i
<cip
->channel
->users
->hashsize
;i
++) {
1252 if (cip
->channel
->users
->content
[i
]!=nouser
&&
1253 (np
=getnickbynumeric(cip
->channel
->users
->content
[i
])) &&
1254 !IsService(np
) && !IsOper(np
) && !IsXOper(np
) &&
1255 nickmatchban(np
, rbp
->cbp
, 1))
1256 localkickuser(chanservnick
, cip
->channel
, np
, rbp
->reason
? rbp
->reason
->content
: "Banned.");
1262 void cs_banuser(modechanges
*changes
, chanindex
*cip
, nick
*np
, const char *reason
) {
1263 modechanges lchanges
;
1264 char banmask
[NICKLEN
+USERLEN
+HOSTLEN
+3];
1269 if (nickbanned(np
, cip
->channel
, 1)) {
1270 localkickuser(chanservnick
, cip
->channel
, np
, reason
?reason
:"Banned.");
1274 if (IsAccount(np
)) {
1275 /* Ban their account.. */
1276 sprintf(banmask
,"*!*@%s.%s",np
->authname
,HIS_HIDDENHOST
);
1277 } else if (IsSetHost(np
)) {
1278 /* sethosted: ban ident@host */
1279 sprintf(banmask
,"*!%s@%s",np
->shident
->content
,np
->sethost
->content
);
1280 } else if (np
->host
->clonecount
>3) {
1281 /* >3 clones, ban user@host */
1282 sprintf(banmask
,"*!%s@%s",np
->ident
,np
->host
->name
->content
);
1284 sprintf(banmask
,"*!*@%s",np
->host
->name
->content
);
1288 localsetmodeinit(&lchanges
, cip
->channel
, chanservnick
);
1289 localdosetmode_ban(&lchanges
, banmask
, MCB_ADD
);
1290 localsetmodeflush(&lchanges
, 1);
1292 localdosetmode_ban(changes
, banmask
, MCB_ADD
);
1295 localkickuser(chanservnick
, cip
->channel
, np
, reason
?reason
:"Banned.");
1299 * cs_sanitisechanlev: Removes impossible combinations from chanlev flags.
1300 * chanservuser.c is probably not the right file for this, but nowhere better
1301 * presented itself...
1303 flag_t
cs_sanitisechanlev(flag_t flags
) {
1304 /* +m or +n cannot have any "punishment" flags */
1305 if (flags
& (QCUFLAG_MASTER
| QCUFLAG_OWNER
))
1306 flags
&= ~(QCUFLAGS_PUNISH
);
1308 /* +d can't be +o */
1309 if (flags
& QCUFLAG_DENY
)
1310 flags
&= ~QCUFLAG_OP
;
1312 /* +q can't be +v */
1313 if (flags
& QCUFLAG_QUIET
)
1314 flags
&= ~QCUFLAG_VOICE
;
1316 /* +p trumps +a and +g */
1317 if (flags
& QCUFLAG_PROTECT
)
1318 flags
&= ~(QCUFLAG_AUTOOP
| QCUFLAG_AUTOVOICE
);
1320 /* -o can't be +a */
1321 if (!(flags
& QCUFLAG_OP
))
1322 flags
&= ~QCUFLAG_AUTOOP
;
1324 /* +a or -v can't be +g. +a implies +o at this stage (see above) */
1325 if (!(flags
& QCUFLAG_VOICE
) || (flags
& QCUFLAG_AUTOOP
))
1326 flags
&= ~QCUFLAG_AUTOVOICE
;
1328 /* +p requires +o or +v */
1329 if (!(flags
& (QCUFLAG_VOICE
| QCUFLAG_OP
)))
1330 flags
&= ~QCUFLAG_PROTECT
;
1332 /* The personal flags require one of +mnovk, as does +t */
1333 if (!(flags
& (QCUFLAG_OWNER
| QCUFLAG_MASTER
| QCUFLAG_OP
| QCUFLAG_VOICE
| QCUFLAG_KNOWN
)))
1334 flags
&= ~(QCUFLAGS_PERSONAL
| QCUFLAG_TOPIC
);
1341 * This function does the standard "nick or #user" lookup.
1342 * If "sender" is not NULL, a suitable error message will
1343 * be sent if the lookup fails.
1344 * "sender" MUST be sent when a user is requesting a lookup
1345 * as there is some policy code here.
1348 reguser
*findreguser(nick
*sender
, const char *str
) {
1349 reguser
*rup
, *vrup
= getreguserfromnick(sender
);;
1358 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1361 if (!(rup
=findreguserbynick(str
+1)) && sender
)
1362 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1363 } else if (*str
=='&' && vrup
&& UHasStaffPriv(vrup
)) {
1366 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1369 if (!(rup
=findreguserbyID(atoi(str
+1))) && sender
)
1370 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1372 if (!(np
=getnickbynick(str
))) {
1374 chanservstdmessage(sender
, QM_UNKNOWNUSER
, str
);
1377 if (!(rup
=getreguserfromnick(np
)) && sender
)
1378 chanservstdmessage(sender
, QM_USERNOTAUTHED
, str
);
1381 /* removed the suspended check from here, I don't see the point... */
1382 if (rup
&& (rup
->status
& QUSTAT_DEAD
)) {
1383 chanservstdmessage(sender
, QM_USERHASBADAUTH
, rup
->username
);
1391 * Unbans a mask from a channel, including permbans if user has correct privs.
1393 * Return 0 if it works, 1 if it don't.
1395 int cs_unbanfn(nick
*sender
, chanindex
*cip
, int (*fn
)(void *arg
, struct chanban
*ban
), void *arg
, int removepermbans
, int abortonfailure
) {
1397 chanban
**cbh
, *cbp
;
1399 modechanges changes
;
1402 rcp
=cip
->exts
[chanservext
];
1405 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1407 for (rbh
=&(rcp
->bans
); *rbh
; ) {
1409 if (fn(arg
, rbp
->cbp
)) {
1410 banstr
=bantostring(rbp
->cbp
);
1411 /* Check perms and remove */
1412 if(!removepermbans
) {
1413 chanservstdmessage(sender
, QM_WARNNOTREMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1415 } else if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, NULL
, 0, 1)) {
1416 chanservstdmessage(sender
, QM_NOTREMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1417 if (abortonfailure
) return 1; /* Just give up... */
1420 chanservstdmessage(sender
, QM_REMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1422 localdosetmode_ban(&changes
, banstr
, MCB_DEL
);
1423 /* Remove from database */
1424 csdb_deleteban(rbp
);
1425 /* Remove from list */
1427 /* Free ban/string and update setby refcount, and free actual regban */
1428 freesstring(rbp
->reason
);
1429 freechanban(rbp
->cbp
);
1438 for (cbh
=&(cip
->channel
->bans
); *cbh
; ) {
1442 banstr
=bantostring(cbp
);
1443 chanservstdmessage(sender
, QM_REMOVEDCHANBAN
, banstr
, cip
->name
->content
);
1444 localdosetmode_ban(&changes
, banstr
, MCB_DEL
);
1449 localsetmodeflush(&changes
,1);
1455 /* Add entry to channel op history when someone gets ops. */
1456 void cs_logchanop(regchan
*rcp
, char *nick
, reguser
*rup
) {
1457 strncpy(rcp
->chanopnicks
[rcp
->chanoppos
], nick
, NICKLEN
);
1458 rcp
->chanopnicks
[rcp
->chanoppos
][NICKLEN
]='\0';
1459 rcp
->chanopaccts
[rcp
->chanoppos
]=rup
->ID
;
1460 rcp
->chanoppos
=(rcp
->chanoppos
+1)%CHANOPHISTORY
;
1463 int checkreason(nick
*np
, char *reason
) {
1464 if((strlen(reason
) < MIN_REASONLEN
) || !strchr(reason
, ' ')) {
1465 chanservstdmessage(np
, QM_REASONREQUIRED
);
1472 regchan
*cs_addchan(chanindex
*cip
, nick
*sender
, reguser
*addedby
, reguser
*founder
, flag_t flags
, flag_t forcemodes
, flag_t denymodes
, short type
) {
1478 if (cip
->exts
[chanservext
])
1481 /* Initialise the channel */
1485 rcp
->ID
=++lastchannelID
;
1487 cip
->exts
[chanservext
]=rcp
;
1493 rcp
->lastcountersync
=0;
1496 rcp
->forcemodes
=forcemodes
;
1497 rcp
->denymodes
=denymodes
;
1499 if (CIsAutoLimit(rcp
)) {
1500 rcp
->forcemodes
|= CHANMODE_LIMIT
;
1506 rcp
->created
=rcp
->lastactive
=rcp
->statsreset
=rcp
->ostatsreset
=time(NULL
);
1509 rcp
->lastbancheck
=0;
1512 rcp
->addedby
=addedby
->ID
;
1515 rcp
->founder
=founder
->ID
;
1521 rcp
->totaljoins
=rcp
->tripjoins
=rcp
->otripjoins
=rcp
->maxusers
=rcp
->tripusers
=rcp
->otripusers
=0;
1522 rcp
->welcome
=rcp
->topic
=rcp
->key
=rcp
->suspendreason
=rcp
->comment
=NULL
;
1525 memset(rcp
->regusers
,0,REGCHANUSERHASHSIZE
*sizeof(reguser
*));
1527 rcp
->checksched
=NULL
;
1529 for (i
=0;i
<CHANOPHISTORY
;i
++) {
1530 rcp
->chanopnicks
[i
][0]='\0';
1531 rcp
->chanopaccts
[i
]=0;
1535 /* Add new channel to db.. */
1536 csdb_createchannel(rcp
);
1538 /* Add the founder as +ano */
1539 rcup
=getregchanuser();
1542 rcup
->flags
=(QCUFLAG_OWNER
| QCUFLAG_OP
| QCUFLAG_AUTOOP
);
1545 rcup
->changetime
=time(NULL
);
1547 addregusertochannel(rcup
);
1548 csdb_createchanuser(rcup
);
1549 csdb_chanlevhistory_insert(rcp
, sender
, rcup
->user
, 0, rcup
->flags
);
1555 triggerhook(HOOK_CHANSERV_CHANLEVMOD
, args
);
1557 /* If the channel exists, get the ball rolling */
1559 chanservjoinchan(cip
->channel
);
1560 rcp
->status
|= QCSTAT_MODECHECK
| QCSTAT_OPCHECK
| QCSTAT_BANCHECK
;