3 * Provides basic channel commands:
11 #include "../nick/nick.h"
12 #include "../lib/flags.h"
13 #include "../lib/irc_string.h"
14 #include "../channel/channel.h"
15 #include "../parser/parser.h"
16 #include "../irc/irc.h"
17 #include "../localuser/localuserchannel.h"
22 int csc_dochanlev(void *source
, int cargc
, char **cargv
);
23 int csc_dochanflags(void *source
, int cargc
, char **cargv
);
24 int csc_dochanmode(void *source
, int cargc
, char **cargv
);
25 int csc_doautolimit(void *source
, int cargc
, char **cargv
);
26 int csc_dobantimer(void *source
, int cargc
, char **cargv
);
27 int csc_doaddchan(void *source
, int cargc
, char **cargv
);
28 int csc_dosuspendchan(void *source
, int cargc
, char **cargv
);
29 int csc_dosuspendchanlist(void *source
, int cargc
, char **cargv
);
30 int csc_dounsuspendchan(void *source
, int cargc
, char **cargv
);
31 int csc_dodelchan(void *source
, int cargc
, char **cargv
);
32 int csc_dorenchan(void *source
, int cargc
, char **cargv
);
33 int csc_dowelcome(void *source
, int cargc
, char **cargv
);
34 int csc_doinvite(void *source
, int cargc
, char **cargv
);
35 int csc_doop(void *source
, int cargc
, char **cargv
);
36 int csc_dovoice(void *source
, int cargc
, char **cargv
);
37 int csc_dodeopall(void *source
, int cargc
, char **cargv
);
38 int csc_dounbanall(void *source
, int cargc
, char **cargv
);
39 int csc_doclearchan(void *source
, int cargc
, char **cargv
);
40 int csc_dorecover(void *source
, int cargc
, char **cargv
);
41 int csc_dounbanme(void *source
, int cargc
, char **cargv
);
42 int csc_dodevoiceall(void *source
, int cargc
, char **cargv
);
43 int csc_dosettopic(void *source
, int cargc
, char **cargv
);
44 int csc_dopermban(void *source
, int cargc
, char **cargv
);
45 int csc_dotempban(void *source
, int cargc
, char **cargv
);
46 int csc_dobanlist(void *source
, int cargc
, char **cargv
);
47 int csc_dounbanmask(void *source
, int cargc
, char **cargv
);
48 int csc_dobandel(void *source
, int cargc
, char **cargv
);
49 int csc_dochannelcomment(void *source
, int cargc
, char **cargv
);
50 int csc_dorejoin(void *source
, int cargc
, char **cargv
);
51 int csc_doadduser(void *source
, int cargc
, char **cargv
);
52 int csc_doremoveuser(void *source
, int cargc
, char **cargv
);
53 int csc_dobanclear(void *source
, int cargc
, char **cargv
);
54 int csc_dochantype(void *source
, int cargc
, char **cargv
);
55 int csc_dochanstat(void *source
, int cargc
, char **cargv
);
57 char *getchanmode(regchan
*rcp
);
60 chanservaddcommand("chanflags", QCMD_AUTHED
, 2, csc_dochanflags
, "Shows or changes the flags on a channel.");
61 chanservaddcommand("chanmode", QCMD_AUTHED
, 4, csc_dochanmode
, "Shows which modes are forced or denied on a channel.");
62 chanservaddcommand("chanlev", QCMD_AUTHED
, 3, csc_dochanlev
, "Shows or modifies user access on a channel.");
63 chanservaddcommand("autolimit", QCMD_AUTHED
, 2, csc_doautolimit
, "Shows or changes the autolimit threshold on a channel.");
64 chanservaddcommand("bantimer", QCMD_AUTHED
, 2, csc_dobantimer
, "Shows or changes the time after which bans are removed.");
65 chanservaddcommand("addchan", QCMD_OPER
, 4, csc_doaddchan
, "Adds a new channel to the bot.");
66 chanservaddcommand("suspendchan", QCMD_OPER
, 2, csc_dosuspendchan
, "Suspends a channel from the bot.");
67 chanservaddcommand("suspendchanlist", QCMD_HELPER
, 1, csc_dosuspendchanlist
, "Lists suspended channels.");
68 chanservaddcommand("unsuspendchan", QCMD_OPER
, 1, csc_dounsuspendchan
, "Unsuspends a channel from the bot.");
69 chanservaddcommand("delchan", QCMD_OPER
, 2, csc_dodelchan
, "Removes a channel from the bot.");
70 chanservaddcommand("renchan", QCMD_OPER
, 2, csc_dorenchan
, "Renames a channel on the bot.");
71 chanservaddcommand("welcome", QCMD_AUTHED
, 2, csc_dowelcome
, "Shows or changes the welcome message on a channel.");
72 chanservaddcommand("invite", QCMD_AUTHED
, 1, csc_doinvite
, "Invites you to a channel.");
73 chanservaddcommand("op", QCMD_AUTHED
, 20,csc_doop
, "Ops you or other users on channel(s).");
74 chanservaddcommand("voice", QCMD_AUTHED
, 20,csc_dovoice
, "Voices you or other users on channel(s).");
75 chanservaddcommand("deopall", QCMD_AUTHED
, 1, csc_dodeopall
, "Deops all users on channel.");
76 chanservaddcommand("devoiceall",QCMD_AUTHED
, 1, csc_dodevoiceall
,"Devoices all users on a channel.");
77 chanservaddcommand("unbanall", QCMD_AUTHED
, 1, csc_dounbanall
, "Removes all bans from a channel.");
78 chanservaddcommand("unbanme", QCMD_AUTHED
, 1, csc_dounbanme
, "Removes any bans affecting you from a channel.");
79 chanservaddcommand("clearchan", QCMD_AUTHED
, 1, csc_doclearchan
, "Removes all modes from a channel.");
80 chanservaddcommand("recover", QCMD_AUTHED
, 1, csc_dorecover
, "Recovers a channel (same as deopall, unbanall, clearchan).");
81 chanservaddcommand("settopic", QCMD_AUTHED
, 2, csc_dosettopic
, "Changes the topic on a channel.");
82 chanservaddcommand("permban", QCMD_AUTHED
, 3, csc_dopermban
, "Permanently bans a hostmask on a channel.");
83 chanservaddcommand("tempban", QCMD_AUTHED
, 4, csc_dotempban
, "Bans a hostmask on a channel for a specified time period.");
84 chanservaddcommand("banlist", QCMD_AUTHED
, 1, csc_dobanlist
, "Displays all persistent bans on a channel.");
85 chanservaddcommand("unbanmask", QCMD_AUTHED
, 2, csc_dounbanmask
, "Removes bans matching a particular mask from a channel.");
86 chanservaddcommand("bandel", QCMD_AUTHED
, 2, csc_dobandel
, "Removes a single ban from a channel.");
87 chanservaddcommand("banclear", QCMD_AUTHED
, 1, csc_dobanclear
, "Removes all bans from a channel including persistent bans.");
88 chanservaddcommand("channelcomment",QCMD_OPER
,2,csc_dochannelcomment
,"Shows or changes the staff comment for a channel.");
89 chanservaddcommand("rejoin", QCMD_OPER
, 1, csc_dorejoin
, "Makes the bot rejoin a channel.");
90 chanservaddcommand("adduser", QCMD_AUTHED
, 20,csc_doadduser
, "Adds one or more users to a channel as +aot.");
91 chanservaddcommand("removeuser",QCMD_AUTHED
, 20,csc_doremoveuser
,"Removes one or more users from a channel.");
92 chanservaddcommand("chantype", QCMD_OPER
, 2,csc_dochantype
, "Shows or changes a channel's type.");
93 chanservaddcommand("chanstat", QCMD_AUTHED
, 1,csc_dochanstat
, "Displays channel activity statistics.");
97 chanservremovecommand("chanflags", csc_dochanflags
);
98 chanservremovecommand("chanmode", csc_dochanmode
);
99 chanservremovecommand("chanlev", csc_dochanlev
);
100 chanservremovecommand("autolimit", csc_doautolimit
);
101 chanservremovecommand("bantimer", csc_dobantimer
);
102 chanservremovecommand("addchan", csc_doaddchan
);
103 chanservremovecommand("suspendchan",csc_dosuspendchan
);
104 chanservremovecommand("suspendchanlist",csc_dosuspendchanlist
);
105 chanservremovecommand("unsuspendchan",csc_dounsuspendchan
);
106 chanservremovecommand("delchan", csc_dodelchan
);
107 chanservremovecommand("renchan", csc_dorenchan
);
108 chanservremovecommand("welcome", csc_dowelcome
);
109 chanservremovecommand("invite", csc_doinvite
);
110 chanservremovecommand("op", csc_doop
);
111 chanservremovecommand("voice", csc_dovoice
);
112 chanservremovecommand("deopall", csc_dodeopall
);
113 chanservremovecommand("devoiceall",csc_dodevoiceall
);
114 chanservremovecommand("unbanall", csc_dounbanall
);
115 chanservremovecommand("unbanme", csc_dounbanme
);
116 chanservremovecommand("clearchan", csc_doclearchan
);
117 chanservremovecommand("recover", csc_dorecover
);
118 chanservremovecommand("settopic", csc_dosettopic
);
119 chanservremovecommand("permban", csc_dopermban
);
120 chanservremovecommand("tempban", csc_dotempban
);
121 chanservremovecommand("banlist", csc_dobanlist
);
122 chanservremovecommand("unbanmask", csc_dounbanmask
);
123 chanservremovecommand("bandel", csc_dobandel
);
124 chanservremovecommand("banclear", csc_dobanclear
);
125 chanservremovecommand("channelcomment",csc_dochannelcomment
);
126 chanservremovecommand("rejoin", csc_dorejoin
);
127 chanservremovecommand("adduser", csc_doadduser
);
128 chanservremovecommand("removeuser",csc_doremoveuser
);
129 chanservremovecommand("chantype", csc_dochantype
);
130 chanservremovecommand("chanstat", csc_dochanstat
);
133 int csc_dochanflags(void *source
, int cargc
, char **cargv
) {
136 reguser
*rup
=getreguserfromnick(sender
);
138 flag_t oldflags
,changemask
;
142 chanservstdmessage(sender
,QM_NOTENOUGHPARAMS
,"chanflags");
146 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
, NULL
,
147 "chanflags", QPRIV_VIEWCHANFLAGS
, 0)))
150 rcp
=cip
->exts
[chanservext
];
153 if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, "chanflags",
154 QPRIV_CHANGECHANFLAGS
, 0))
158 changemask
=QCFLAG_USERCONTROL
;
160 changemask
=QCFLAG_ALL
;
162 setflags(&rcp
->flags
, changemask
, cargv
[1], rcflags
, REJECT_NONE
);
164 /* We might need to do things in response to the flag changes.. */
166 if ((oldflags
^ rcp
->flags
) & (QCFLAG_JOINED
| QCFLAG_SUSPENDED
)) {
167 chanservjoinchan(cip
->channel
);
168 rcp
->status
|= (QCSTAT_OPCHECK
| QCSTAT_MODECHECK
| QCSTAT_BANCHECK
);
172 if (CIsEnforce(rcp
)) {
174 cs_checkbans(cip
->channel
);
177 if (CIsProtect(rcp
) || CIsBitch(rcp
) || CIsAutoOp(rcp
) || CIsAutoVoice(rcp
) || CIsKnownOnly(rcp
)) {
178 rcp
->status
|= QCSTAT_OPCHECK
;
184 if (CIsAutoLimit(rcp
) && !(oldflags
& QCFLAG_AUTOLIMIT
)) {
185 rcp
->forcemodes
|= CHANMODE_LIMIT
;
186 rcp
->denymodes
&= ~CHANMODE_LIMIT
;
191 if (!CIsAutoLimit(rcp
) && (oldflags
& QCFLAG_AUTOLIMIT
)) {
192 rcp
->forcemodes
&= ~CHANMODE_LIMIT
;
194 cs_checkchanmodes(cip
->channel
);
197 strcpy(flagbuf
,printflags(oldflags
, rcflags
));
198 cs_log(sender
,"CHANFLAGS %s %s (%s -> %s)",cip
->name
->content
,cargv
[1],flagbuf
,printflags(rcp
->flags
,rcflags
));
199 chanservstdmessage(sender
, QM_DONE
);
200 csdb_updatechannel(rcp
);
203 chanservstdmessage(sender
,QM_CURCHANFLAGS
,cip
->name
->content
,printflags(rcp
->flags
, rcflags
));
207 int csc_dochanmode(void *source
, int cargc
, char **cargv
) {
211 flag_t forceflags
,denyflags
;
213 int carg
=2,limdone
=0;
214 sstring
*newkey
=NULL
;
215 unsigned int newlim
=0;
218 chanservstdmessage(sender
,QM_NOTENOUGHPARAMS
,"chanmode");
222 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
,
223 NULL
, "chanmode", QPRIV_VIEWCHANMODES
, 0)))
226 rcp
=cip
->exts
[chanservext
];
229 if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
,
230 cip
, "chanmode", QPRIV_CHANGECHANMODES
, 0))
233 /* Save the current modes.. */
234 strcpy(buf1
,getchanmode(rcp
));
236 /* Pick out the + flags: start from 0 */
238 setflags(&forceflags
, CHANMODE_ALL
, cargv
[1], cmodeflags
, REJECT_NONE
);
240 /* Pick out the - flags: start from everything and invert afterwards.. */
241 denyflags
=CHANMODE_ALL
;
242 setflags(&denyflags
, CHANMODE_ALL
, cargv
[1], cmodeflags
, REJECT_NONE
);
243 denyflags
= (~denyflags
) & CHANMODE_ALL
;
245 forceflags
&= ~denyflags
; /* Can't force and deny the same mode (shouldn't be possible anyway) */
246 if (forceflags
& CHANMODE_SECRET
) {
247 forceflags
&= ~CHANMODE_PRIVATE
;
248 denyflags
|= CHANMODE_PRIVATE
;
250 if (forceflags
& CHANMODE_PRIVATE
) {
251 forceflags
&= ~CHANMODE_SECRET
;
252 denyflags
|= CHANMODE_SECRET
;
255 if ((forceflags
& CHANMODE_LIMIT
) &&
256 (!(forceflags
& CHANMODE_KEY
) || strrchr(cargv
[1],'l') < strrchr(cargv
[1],'k'))) {
258 chanservstdmessage(sender
,QM_NOTENOUGHPARAMS
,"chanmode");
261 newlim
=strtol(cargv
[carg
++],NULL
,10);
265 if (forceflags
& CHANMODE_KEY
) {
267 chanservstdmessage(sender
,QM_NOTENOUGHPARAMS
,"chanmode");
270 newkey
=getsstring(cargv
[carg
++], KEYLEN
);
273 if ((forceflags
& CHANMODE_LIMIT
) && !limdone
) {
275 chanservstdmessage(sender
,QM_NOTENOUGHPARAMS
,"chanmode");
278 newlim
=strtol(cargv
[carg
++],NULL
,10);
282 if (CIsAutoLimit(rcp
)) {
283 forceflags
|= CHANMODE_LIMIT
;
284 denyflags
&= ~CHANMODE_LIMIT
;
288 /* It parsed OK, so update the structure.. */
289 rcp
->forcemodes
=forceflags
;
290 rcp
->denymodes
=denyflags
;
292 freesstring(rcp
->key
);
296 chanservstdmessage(sender
, QM_DONE
);
297 cs_log(sender
,"CHANMODE %s %s (%s -> %s)",cip
->name
->content
,cargv
[1],buf1
,getchanmode(rcp
));
298 csdb_updatechannel(rcp
);
299 cs_checkchanmodes(cip
->channel
);
302 chanservstdmessage(sender
,QM_CURFORCEMODES
,cip
->name
->content
,getchanmode(rcp
));
307 char *getchanmode(regchan
*rcp
) {
308 static char buf1
[50];
311 if (rcp
->forcemodes
) {
312 strcpy(buf1
,printflags(rcp
->forcemodes
, cmodeflags
));
317 strcpy(buf2
,printflagdiff(CHANMODE_ALL
, ~(rcp
->denymodes
), cmodeflags
));
320 if (rcp
->forcemodes
& CHANMODE_LIMIT
) {
321 sprintf(buf2
, " %d",rcp
->limit
);
325 if (rcp
->forcemodes
& CHANMODE_KEY
) {
326 sprintf(buf2
, " %s",rcp
->key
->content
);
331 strcpy(buf1
,"(none)");
337 int compareflags(const void *u1
, const void *u2
) {
338 const regchanuser
*r1
=*(void **)u1
, *r2
=*(void **)u2
;
341 for (f1
=QCUFLAG_OWNER
;f1
;f1
>>=1)
345 for (f2
=QCUFLAG_OWNER
;f2
;f2
>>=1)
350 return ircd_strcmp(r1
->user
->username
, r2
->user
->username
);
356 int csc_dochanlev(void *source
, int cargc
, char **cargv
) {
360 regchanuser
*rcup
, *rcuplist
;
361 regchanuser
**rusers
;
362 reguser
*rup
=getreguserfromnick(sender
), *target
;
363 char time1
[15],time2
[15];
366 flag_t flagmask
, changemask
, flags
, oldflags
;
374 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "chanlev");
378 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_KNOWN
,
379 NULL
, "chanlev", QPRIV_VIEWFULLCHANLEV
, 0)))
382 rcp
=cip
->exts
[chanservext
];
383 rcup
=findreguseronchannel(rcp
, rup
);
385 /* Set flagmask for +v/+o users (can't see bans etc.) */
386 flagmask
= (QCUFLAG_OWNER
| QCUFLAG_MASTER
| QCUFLAG_OP
| QCUFLAG_VOICE
| QCUFLAG_AUTOVOICE
|
387 QCUFLAG_AUTOOP
| QCUFLAG_TOPIC
| QCUFLAG_SPAMCON
| QCUFLAG_PROTECT
| QCUFLAG_KNOWN
);
389 /* If user has +m or above, or helper access, show everything */
390 if (cs_privcheck(QPRIV_VIEWFULLCHANLEV
, sender
) || CUHasMasterPriv(rcup
)) {
391 flagmask
= QCUFLAG_ALL
;
396 /* One arg: list chanlev */
397 if (cs_privcheck(QPRIV_VIEWFULLCHANLEV
, sender
)) {
398 reguser
*founder
=NULL
, *addedby
=NULL
;
399 addedby
=findreguserbyID(rcp
->addedby
);
400 chanservstdmessage(sender
, QM_ADDEDBY
, addedby
? addedby
->username
: "(unknown)");
401 founder
=findreguserbyID(rcp
->founder
);
402 chanservstdmessage(sender
, QM_FOUNDER
, founder
? founder
->username
: "(unknown)");
403 chanservstdmessage(sender
, QM_CHANTYPE
, chantypes
[rcp
->chantype
]->content
);
407 for (i
=0,usercount
=0;i
<REGCHANUSERHASHSIZE
;i
++)
408 for (rcuplist
=rcp
->regusers
[i
];rcuplist
;rcuplist
=rcuplist
->nextbychan
)
412 rusers
=(regchanuser
**)malloc(usercount
* sizeof(regchanuser
*));
415 for (j
=i
=0;i
<REGCHANUSERHASHSIZE
;i
++) {
416 for (rcuplist
=rcp
->regusers
[i
];rcuplist
;rcuplist
=rcuplist
->nextbychan
) {
417 if (!(flags
=rcuplist
->flags
& flagmask
))
420 rusers
[j
++]=rcuplist
;
425 qsort(rusers
, j
, sizeof(regchanuser
*), compareflags
);
431 if (!(flags
=rcuplist
->flags
& flagmask
))
435 chanservstdmessage(sender
, QM_CHANLEVHEADER
, cip
->name
->content
);
437 chanservstdmessage(sender
, QM_CHANLEVCOLFULL
);
439 chanservstdmessage(sender
, QM_CHANLEVCOLSHORT
);
444 if (!rcuplist
->usetime
) {
445 strcpy(time1
,"Never");
447 tmp
=localtime(&(rcuplist
->usetime
));
448 strftime(time1
,15,"%d/%m/%y %H:%M",tmp
);
450 if (!rcuplist
->changetime
) {
451 strcpy(time2
, "Unknown");
453 tmp
=localtime(&(rcuplist
->changetime
));
454 strftime(time2
,15,"%d/%m/%y %H:%M",tmp
);
456 chanservsendmessage(sender
, " %-15s %-13s %-14s %-14s %s", rcuplist
->user
->username
,
457 printflags(flags
, rcuflags
), time1
, time2
, rcuplist
->info
?rcuplist
->info
->content
:"");
459 chanservsendmessage(sender
, " %-15s %s", rcuplist
->user
->username
, printflags(flags
, rcuflags
));
463 chanservstdmessage(sender
, QM_ENDOFLIST
);
465 chanservstdmessage(sender
, QM_NOUSERSONCHANLEV
, cip
->name
->content
);
470 /* 2 or more args.. relates to one specific user */
471 if (!(target
=findreguser(sender
, cargv
[1])))
472 return CMD_ERROR
; /* If there was an error, findreguser will have sent a message saying why.. */
474 rcuplist
=findreguseronchannel(rcp
, target
);
477 /* To change chanlev you have to either.. */
478 if (!( cs_privcheck(QPRIV_CHANGECHANLEV
, sender
) || /* Have override privilege */
479 (rcup
&& rcuplist
&& (rcup
==rcuplist
) && CUKnown(rcup
)) || /* Be manipulting yourself (oo er..) */
480 (rcup
&& CUHasMasterPriv(rcup
) && /* Have +m or +n on the channel */
481 !(rcuplist
&& CUIsOwner(rcuplist
) && !CUIsOwner(rcup
))) /* masters can't screw with owners */
483 chanservstdmessage(sender
, QM_NOACCESSONCHAN
, cip
->name
->content
, "chanlev");
488 rcuplist
=getregchanuser();
489 rcuplist
->user
=target
;
492 rcuplist
->changetime
=time(NULL
);
498 if (cs_privcheck(QPRIV_CHANGECHANLEV
, sender
)) {
499 /* Opers are allowed to change everything */
500 changemask
= QCUFLAG_ALL
;
504 /* Everyone can change their own flags (except +dqb), and turn +iwj on/off */
505 if (rcup
==rcuplist
) {
506 changemask
= (rcup
->flags
| QCUFLAG_HIDEWELCOME
| QCUFLAG_HIDEINFO
| QCUFLAG_AUTOINVITE
) &
507 ~(QCUFLAG_BANNED
| QCUFLAG_DENY
| QCUFLAG_QUIET
);
508 flagmask
|= (QCUFLAG_HIDEWELCOME
| QCUFLAG_HIDEINFO
| QCUFLAG_AUTOINVITE
);
511 /* Masters are allowed to manipulate +ovagtbqdpk */
512 if (CUHasMasterPriv(rcup
))
513 changemask
|= ( QCUFLAG_KNOWN
| QCUFLAG_OP
| QCUFLAG_VOICE
| QCUFLAG_AUTOOP
| QCUFLAG_AUTOVOICE
|
514 QCUFLAG_TOPIC
| QCUFLAG_BANNED
| QCUFLAG_QUIET
| QCUFLAG_DENY
| QCUFLAG_PROTECT
);
516 /* Owners are allowed to manipulate +ms as well */
518 changemask
|= ( QCUFLAG_MASTER
| QCUFLAG_SPAMCON
);
521 oldflags
=rcuplist
->flags
;
522 if (setflags(&(rcuplist
->flags
), changemask
, cargv
[2], rcuflags
, REJECT_UNKNOWN
| REJECT_DISALLOWED
)) {
523 chanservstdmessage(sender
, QM_INVALIDCHANLEVCHANGE
);
527 /* Now fix up some "impossible" combinations.. */
528 /* +m can't be any of +qdb */
529 if (CUHasMasterPriv(rcuplist
))
530 rcuplist
->flags
&= ~(QCUFLAG_BANNED
| QCUFLAG_QUIET
| QCUFLAG_DENY
);
533 if (CUIsDeny(rcuplist
))
534 rcuplist
->flags
&= ~QCUFLAG_OP
;
537 if (CUIsQuiet(rcuplist
))
538 rcuplist
->flags
&= ~QCUFLAG_VOICE
;
540 /* -o or +p can't be +a */
541 if (!CUIsOp(rcuplist
) || CUIsProtect(rcuplist
))
542 rcuplist
->flags
&= ~QCUFLAG_AUTOOP
;
544 /* +a or -v or +p can't be +g */
545 if (!CUIsVoice(rcuplist
) || CUIsAutoOp(rcuplist
) || CUIsProtect(rcuplist
))
546 rcuplist
->flags
&= ~QCUFLAG_AUTOVOICE
;
548 /* and -ov can't be +p */
549 if (!CUIsOp(rcuplist
) && !CUIsVoice(rcuplist
))
550 rcuplist
->flags
&= ~QCUFLAG_PROTECT
;
552 /* Check if anything "significant" has changed */
553 if ((oldflags
^ rcuplist
->flags
) & (QCUFLAG_OWNER
| QCUFLAG_MASTER
| QCUFLAG_OP
))
554 rcuplist
->changetime
=time(NULL
);
556 strcpy(flagbuf
,printflags(oldflags
,rcuflags
));
557 cs_log(sender
,"CHANLEV %s #%s %s (%s -> %s)",cip
->name
->content
,rcuplist
->user
->username
,cargv
[2],
558 flagbuf
,printflags(rcuplist
->flags
,rcuflags
));
560 /* Now see what we do next */
561 if (rcuplist
->flags
) {
562 /* User still valid: update or create */
564 addregusertochannel(rcuplist
);
565 csdb_createchanuser(rcuplist
);
567 csdb_updatechanuser(rcuplist
);
570 /* User has no flags: delete */
572 csdb_deletechanuser(rcuplist
);
573 delreguserfromchannel(rcp
, target
);
575 freeregchanuser(rcuplist
);
577 for (i
=0;i
<REGCHANUSERHASHSIZE
;i
++)
578 if (rcp
->regusers
[i
])
580 if (i
==REGCHANUSERHASHSIZE
) {
581 cs_log(sender
,"DELCHAN %s (Cleared chanlev)",cip
->name
->content
);
582 cs_removechannel(rcp
);
586 /* Say we've done it */
587 chanservstdmessage(sender
, QM_DONE
);
588 rcp
->status
|= QCSTAT_OPCHECK
;
592 if (rcuplist
&& (rcuplist
->flags
& flagmask
)) {
593 chanservstdmessage(sender
, QM_CHANUSERFLAGS
, cargv
[1], cip
->name
->content
,
594 printflags(rcuplist
->flags
& flagmask
, rcuflags
));
596 chanservstdmessage(sender
, QM_CHANUSERUNKNOWN
, cargv
[1], cip
->name
->content
);
603 int csc_doautolimit(void *source
, int cargc
, char **cargv
) {
610 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "autolimit");
614 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
,
615 NULL
, "autolimit", QPRIV_VIEWAUTOLIMIT
, 0)))
618 rcp
=cip
->exts
[chanservext
];
621 if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
,
622 cip
, "autolimit", QPRIV_CHANGEAUTOLIMIT
, 0))
625 oldlimit
=rcp
->autolimit
;
626 rcp
->autolimit
=strtol(cargv
[1],NULL
,10);
628 if (rcp
->autolimit
<1)
631 csdb_updatechannel(rcp
);
633 cs_log(sender
,"AUTOLIMIT %s %s (%d -> %d)",cip
->name
->content
,cargv
[1],oldlimit
,rcp
->autolimit
);
634 chanservstdmessage(sender
, QM_DONE
);
639 chanservstdmessage(sender
, QM_CHANAUTOLIMIT
, cargv
[0], rcp
->autolimit
);
643 int csc_dobantimer(void *source
, int cargc
, char **cargv
) {
650 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "bantimer");
654 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
, NULL
, "bantimer",
655 QPRIV_VIEWBANTIMER
, 0)))
658 rcp
=cip
->exts
[chanservext
];
661 if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, "bantimer",
662 QPRIV_CHANGEBANTIMER
, 0))
665 oldtimer
=rcp
->banduration
;
666 rcp
->banduration
=durationtolong(cargv
[1]);
668 if (rcp
->banduration
<0)
671 /* Arbitrary limit */
672 if (rcp
->banduration
> 31622400)
673 rcp
->banduration
= 31622400;
675 csdb_updatechannel(rcp
);
677 cs_log(sender
,"BANTIMER %s %s (%u -> %u)",cip
->name
->content
,cargv
[1],oldtimer
,rcp
->banduration
);
678 chanservstdmessage(sender
, QM_DONE
);
682 if (rcp
->banduration
)
683 chanservstdmessage(sender
, QM_CHANBANAUTOREMOVE
, cargv
[0], longtoduration(rcp
->banduration
, 1));
685 chanservstdmessage(sender
, QM_NOCHANBANAUTOREMOVE
, cargv
[0]);
690 int csc_dowelcome(void *source
, int cargc
, char **cargv
) {
697 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "welcome");
701 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
, NULL
, "welcome",
702 QPRIV_VIEWWELCOME
, 0)))
705 rcp
=cip
->exts
[chanservext
];
708 if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, "welcome",
709 QPRIV_CHANGEWELCOME
, 0))
712 oldwelcome
=rcp
->welcome
;
714 rcp
->welcome
=getsstring(cargv
[1], 500);
715 csdb_updatechannel(rcp
);
717 cs_log(sender
,"WELCOME %s %s (was %s)",cip
->name
->content
,rcp
->welcome
->content
,oldwelcome
?oldwelcome
->content
:"unset");
718 freesstring(oldwelcome
);
719 chanservstdmessage(sender
, QM_DONE
);
722 chanservstdmessage(sender
, QM_WELCOMEMESSAGEIS
, rcp
->index
->name
->content
,
723 rcp
->welcome
?rcp
->welcome
->content
:"(none)");
728 int csc_doaddchan(void *source
, int cargc
, char **cargv
) {
730 reguser
*rup
=getreguserfromnick(sender
);
742 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "addchan");
746 if (*cargv
[0] != '#') {
747 chanservstdmessage(sender
, QM_INVALIDCHANNAME
, cargv
[0]);
752 if (!(founder
=findreguser(sender
, cargv
[1])))
760 setflags(&flags
, QCFLAG_ALL
, cargv
[2], rcflags
, REJECT_NONE
);
762 flags
= (QCFLAG_JOINED
| QCFLAG_BITCH
| QCFLAG_PROTECT
| QCFLAG_ENFORCE
);
765 /* Pick up the chantype */
767 for (type
=CHANTYPES
-1;type
;type
--) {
768 if (!ircd_strcmp(chantypes
[type
]->content
, cargv
[3]))
772 chanservstdmessage(sender
, QM_UNKNOWNCHANTYPE
, cargv
[3]);
777 if (!(cip
=findorcreatechanindex(cargv
[0]))) {
778 chanservstdmessage(sender
, QM_INVALIDCHANNAME
, cargv
[0]);
782 if (cip
->exts
[chanservext
]) {
783 chanservstdmessage(sender
, QM_ALREADYREGISTERED
, cip
->name
->content
);
787 /* Initialise the channel */
791 rcp
->ID
=++lastchannelID
;
793 cip
->exts
[chanservext
]=rcp
;
799 rcp
->lastcountersync
=0;
802 rcp
->forcemodes
=CHANMODE_NOEXTMSG
| CHANMODE_TOPICLIMIT
;
805 if (CIsAutoLimit(rcp
)) {
806 rcp
->forcemodes
|= CHANMODE_LIMIT
;
812 rcp
->created
=rcp
->lastactive
=rcp
->statsreset
=rcp
->ostatsreset
=time(NULL
);
813 rcp
->banduration
=1800;
818 rcp
->addedby
=rup
->ID
;
821 rcp
->founder
=founder
->ID
;
826 rcp
->totaljoins
=rcp
->tripjoins
=rcp
->otripjoins
=rcp
->maxusers
=rcp
->tripusers
=rcp
->otripusers
=0;
827 rcp
->welcome
=rcp
->topic
=rcp
->key
=rcp
->suspendreason
=rcp
->comment
=NULL
;
830 memset(rcp
->regusers
,0,REGCHANUSERHASHSIZE
*sizeof(reguser
*));
832 rcp
->checksched
=NULL
;
835 /* Add new channel to db.. */
836 csdb_createchannel(rcp
);
838 /* Add the founder as +ano */
839 rcup
=getregchanuser();
842 rcup
->flags
=(QCUFLAG_OWNER
| QCUFLAG_OP
| QCUFLAG_AUTOOP
);
845 rcup
->changetime
=time(NULL
);
847 addregusertochannel(rcup
);
848 csdb_createchanuser(rcup
);
850 /* If the channel exists, get the ball rolling */
852 chanservjoinchan(cip
->channel
);
853 rcp
->status
|= QCSTAT_MODECHECK
| QCSTAT_OPCHECK
| QCSTAT_BANCHECK
;
857 cs_log(sender
, "ADDCHAN %s #%s %s %s",cip
->name
->content
,founder
->username
,printflags(rcp
->flags
,rcflags
), chantypes
[type
]->content
);
858 chanservstdmessage(sender
, QM_DONE
);
862 int csc_dosuspendchan(void *source
, int cargc
, char **cargv
) {
864 reguser
*rup
=getreguserfromnick(sender
);
872 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "suspendchan");
876 if (!(cip
=findchanindex(cargv
[0])) || !(rcp
=cip
->exts
[chanservext
])) {
877 chanservstdmessage(sender
, QM_UNKNOWNCHAN
, cargv
[0]);
881 if (CIsSuspended(rcp
)) {
882 chanservstdmessage(sender
, QM_CHANNELALREADYSUSPENDED
, cip
->name
->content
);
887 rcp
->suspendreason
= getsstring(cargv
[1], 250);
888 rcp
->suspendby
= rup
->ID
;
889 cs_log(sender
,"SUSPENDCHAN %s (%s)",cip
->name
->content
,rcp
->suspendreason
->content
);
890 chanservjoinchan(cip
->channel
);
892 csdb_updatechannel(rcp
);
893 chanservstdmessage(sender
, QM_DONE
);
898 int csc_dosuspendchanlist(void *source
, int cargc
, char **cargv
) {
900 reguser
*rup
=getreguserfromnick(sender
);
905 unsigned int count
=0;
911 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "suspendchanlist");
915 chanservstdmessage(sender
, QM_SUSPENDCHANLISTHEADER
);
916 for (i
=0; i
<CHANNELHASHSIZE
; i
++) {
917 for (cip
=chantable
[i
]; cip
; cip
=cip
->next
) {
918 if (!(rcp
=(regchan
*)cip
->exts
[chanservext
]))
921 if (!CIsSuspended(rcp
))
924 if ((rcp
->suspendby
!= rup
->ID
) && match(cargv
[0], cip
->name
->content
))
927 if (rcp
->suspendby
== rup
->ID
)
928 bywhom
=rup
->username
;
930 reguser
*trup
=findreguserbyID(rcp
->suspendby
);
932 bywhom
=trup
->username
;
937 chanservsendmessage(sender
, "%-30s %-15s %s", cip
->name
->content
, bywhom
, rcp
->suspendreason
->content
);
939 chanservstdmessage(sender
, QM_TOOMANYRESULTS
, 2000, "channels");
944 chanservstdmessage(sender
, QM_RESULTCOUNT
, count
, "channel", (count
==1)?"":"s");
949 int csc_dounsuspendchan(void *source
, int cargc
, char **cargv
) {
951 reguser
*rup
=getreguserfromnick(sender
);
959 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "unsuspendchan");
963 if (!(cip
=findchanindex(cargv
[0])) || !(rcp
=cip
->exts
[chanservext
])) {
964 chanservstdmessage(sender
, QM_UNKNOWNCHAN
, cargv
[0]);
968 if(!CIsSuspended(rcp
)) {
969 chanservstdmessage(sender
, QM_CHANNELNOTSUSPENDED
, cip
->name
->content
);
970 cs_log(sender
,"UNSUSPENDCHAN %s is not suspended",cip
->name
->content
);
974 CClearSuspended(rcp
);
975 cs_log(sender
,"UNSUSPENDCHAN %s (%s)",cip
->name
->content
,rcp
->suspendreason
->content
);
976 freesstring(rcp
->suspendreason
);
977 rcp
->suspendreason
= NULL
;
980 chanservjoinchan(cip
->channel
);
982 csdb_updatechannel(rcp
);
983 chanservstdmessage(sender
, QM_DONE
);
988 int csc_dodelchan(void *source
, int cargc
, char **cargv
) {
990 reguser
*rup
=getreguserfromnick(sender
);
998 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "delchan");
1002 if (!(cip
=findchanindex(cargv
[0])) || !(rcp
=cip
->exts
[chanservext
])) {
1003 chanservstdmessage(sender
, QM_UNKNOWNCHAN
, cargv
[0]);
1007 cs_log(sender
,"DELCHAN %s (%s)",cip
->name
->content
,cargc
>1?cargv
[1]:"");
1008 cs_removechannel(rcp
);
1009 chanservstdmessage(sender
, QM_DONE
);
1014 int csc_doinvite(void *source
, int cargc
, char **cargv
) {
1015 nick
*sender
=source
;
1019 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "invite");
1023 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_KNOWN
| CA_OFFCHAN
,
1024 NULL
, "invite", 0, 0)))
1028 localinvite(chanservnick
, cip
->channel
, sender
);
1030 chanservstdmessage(sender
, QM_DONE
);
1035 int csc_dosettopic(void *source
, int cargc
, char **cargv
) {
1036 nick
*sender
=source
;
1041 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "settopic");
1045 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_TOPICPRIV
,
1046 NULL
, "settopic", 0, 0)))
1049 rcp
=cip
->exts
[chanservext
];
1053 freesstring(rcp
->topic
);
1054 rcp
->topic
=getsstring(cargv
[1],TOPICLEN
);
1057 if (rcp
->topic
&& cip
->channel
) {
1058 localsettopic(chanservnick
, cip
->channel
, rcp
->topic
->content
);
1061 chanservstdmessage(sender
, QM_DONE
);
1062 csdb_updatechannel(rcp
);
1066 int csc_doop(void *source
, int cargc
, char **cargv
) {
1067 nick
*sender
=source
, *np
;
1068 reguser
*rup
=getreguserfromnick(sender
);
1075 modechanges changes
;
1081 /* No args: "op me on every channel you can */
1082 ca
=sender
->channels
->content
;
1083 for (i
=0;i
<sender
->channels
->cursi
;i
++) {
1084 if ((rcp
=ca
[i
]->index
->exts
[chanservext
]) && !CIsSuspended(rcp
)) {
1085 /* It's a Q channel */
1086 if (!(*(getnumerichandlefromchanhash(ca
[i
]->users
, sender
->numeric
)) &
1088 /* They're not opped */
1089 if ((rcup
=findreguseronchannel(rcp
, rup
)) && CUHasOpPriv(rcup
) &&
1091 /* And they have op priv on the chan: op them */
1092 localsetmodeinit(&changes
, ca
[i
], chanservnick
);
1093 localdosetmode_nick(&changes
, sender
, MC_OP
);
1094 localsetmodeflush(&changes
,1);
1100 chanservstdmessage(sender
, QM_DONE
);
1104 /* If there is at least one arg, the first is a channel */
1106 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
, NULL
, "op", 0, 0)))
1109 rcp
=cip
->exts
[chanservext
];
1112 /* Only one arg: "op me" */
1113 if (!cs_checkaccess(sender
, NULL
, CA_OPPRIV
| CA_DEOPPED
, cip
, "op", 0, 0))
1116 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1117 localdosetmode_nick(&changes
, sender
, MC_OP
);
1118 localsetmodeflush(&changes
,1);
1120 chanservstdmessage(sender
, QM_DONE
);
1124 /* Set up the modes */
1125 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1127 for(i
=1;i
<cargc
;i
++) {
1128 if (!(np
=getnickbynick(cargv
[i
]))) {
1129 chanservstdmessage(sender
, QM_UNKNOWNUSER
, cargv
[i
]);
1133 if (!(lp
=getnumerichandlefromchanhash(cip
->channel
->users
, np
->numeric
))) {
1134 chanservstdmessage(sender
, QM_USERNOTONCHAN
, np
->nick
, cip
->name
->content
);
1138 if (*lp
& CUMODE_OP
) {
1139 chanservstdmessage(sender
, QM_USEROPPEDONCHAN
, np
->nick
, cip
->name
->content
);
1143 rup
=getreguserfromnick(np
);
1145 rcup
=findreguseronchannel(rcp
,rup
);
1149 /* Bitch mode: check that this user is allowed to be opped.. */
1150 if ((CIsBitch(rcp
) && (!rcup
|| !CUHasOpPriv(rcup
))) || (rcup
&& CUIsDeny(rcup
))) {
1151 chanservstdmessage(sender
, QM_CANTOP
, np
->nick
, cip
->name
->content
);
1155 localdosetmode_nick(&changes
, np
, MC_OP
);
1158 localsetmodeflush(&changes
, 1);
1159 chanservstdmessage(sender
, QM_DONE
);
1164 int csc_dovoice(void *source
, int cargc
, char **cargv
) {
1165 nick
*sender
=source
, *np
;
1166 reguser
*rup
=getreguserfromnick(sender
);
1173 modechanges changes
;
1179 /* No args: "voice me on every channel you can */
1180 ca
=sender
->channels
->content
;
1181 for (i
=0;i
<sender
->channels
->cursi
;i
++) {
1182 if ((rcp
=ca
[i
]->index
->exts
[chanservext
]) && !CIsSuspended(rcp
)) {
1183 /* It's a Q channel */
1184 if (!(*(getnumerichandlefromchanhash(ca
[i
]->users
, sender
->numeric
)) &
1185 (CUMODE_OP
|CUMODE_VOICE
))) {
1186 /* They're not opped or voiced */
1187 rcup
=findreguseronchannel(rcp
, rup
);
1188 if ((!rcup
|| !CUIsQuiet(rcup
)) &&
1189 ((rcup
&& CUHasVoicePriv(rcup
)) ||
1190 (CIsVoiceAll(rcp
)))) {
1191 /* And they have voice priv on the chan (or it's autovoice):
1193 localsetmodeinit(&changes
, ca
[i
], chanservnick
);
1194 localdosetmode_nick(&changes
, sender
, MC_VOICE
);
1195 localsetmodeflush(&changes
,1);
1201 chanservstdmessage(sender
, QM_DONE
);
1205 /* If there is at least one arg, the first is a channel */
1207 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_VOICEPRIV
, NULL
, "voice", 0, 0)))
1211 /* Only one arg: "voice me" */
1212 if (!cs_checkaccess(sender
, NULL
, CA_VOICEPRIV
| CA_DEVOICED
, cip
,
1216 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1217 localdosetmode_nick(&changes
, sender
, MC_VOICE
);
1218 localsetmodeflush(&changes
,1);
1220 chanservstdmessage(sender
, QM_DONE
);
1224 if (!(cip
=cs_checkaccess(sender
, NULL
, CA_OPPRIV
, cip
, "voice", 0, 0)))
1227 rcp
=cip
->exts
[chanservext
];
1229 /* Set up the modes */
1230 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1232 for(i
=1;i
<cargc
;i
++) {
1233 if (!(np
=getnickbynick(cargv
[i
]))) {
1234 chanservstdmessage(sender
, QM_UNKNOWNUSER
, cargv
[i
]);
1238 if (!(lp
=getnumerichandlefromchanhash(cip
->channel
->users
, np
->numeric
))) {
1239 chanservstdmessage(sender
, QM_USERNOTONCHAN
, np
->nick
, cip
->name
->content
);
1243 if (*lp
& CUMODE_VOICE
) {
1244 chanservstdmessage(sender
, QM_USERVOICEDONCHAN
, np
->nick
, cip
->name
->content
);
1248 if ((rup
=getreguserfromnick(np
)) && (rcup
=findreguseronchannel(rcp
, rup
)) && CUIsQuiet(rcup
)) {
1249 chanservstdmessage(sender
, QM_CANTVOICE
, np
->nick
, cip
->name
->content
);
1253 localdosetmode_nick(&changes
, np
, MC_VOICE
);
1256 localsetmodeflush(&changes
, 1);
1257 chanservstdmessage(sender
, QM_DONE
);
1262 int csc_dodeopall(void *source
, int cargc
, char **cargv
) {
1263 nick
*sender
=source
,*np
;
1270 modechanges changes
;
1273 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "deopall");
1277 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "deopall",0, 0)))
1280 rcp
=cip
->exts
[chanservext
];
1283 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1285 for (i
=0,lp
=cip
->channel
->users
->content
;
1286 i
<cip
->channel
->users
->hashsize
;i
++,lp
++) {
1287 if (*lp
!=nouser
&& (*lp
& CUMODE_OP
)) {
1288 if (!(np
=getnickbynumeric(*lp
)) ||
1289 (!IsService(np
) && (!(rup
=getreguserfromnick(np
)) ||
1290 !(rcup
=findreguseronchannel(rcp
, rup
)) || !(CUHasOpPriv(rcup
)) ||
1291 !(CUIsProtect(rcup
) || CIsProtect(rcp
))))) {
1292 localdosetmode_nick(&changes
, np
, MC_DEOP
);
1297 localsetmodeflush(&changes
, 1);
1300 cs_log(sender
,"DEOPALL %s",cip
->name
->content
);
1301 chanservstdmessage(sender
, QM_DONE
);
1305 int csc_dodevoiceall(void *source
, int cargc
, char **cargv
) {
1306 nick
*sender
=source
,*np
;
1313 modechanges changes
;
1316 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "devoiceall");
1320 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "devoiceall",0, 0)))
1323 rcp
=cip
->exts
[chanservext
];
1326 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1328 for (i
=0,lp
=cip
->channel
->users
->content
;
1329 i
<cip
->channel
->users
->hashsize
;i
++,lp
++) {
1330 if (*lp
!=nouser
&& (*lp
& CUMODE_VOICE
)) {
1331 if (!(np
=getnickbynumeric(*lp
)) ||
1332 (!IsService(np
) && (!(rup
=getreguserfromnick(np
)) ||
1333 !(rcup
=findreguseronchannel(rcp
, rup
)) || !(CUHasVoicePriv(rcup
)) ||
1334 !(CUIsProtect(rcup
) || CIsProtect(rcp
))))) {
1335 localdosetmode_nick(&changes
, np
, MC_DEVOICE
);
1340 localsetmodeflush(&changes
, 1);
1343 cs_log(sender
,"DEVOICEALL %s",cip
->name
->content
);
1344 chanservstdmessage(sender
, QM_DONE
);
1348 int csc_dounbanall(void *source
, int cargc
, char **cargv
) {
1349 nick
*sender
=source
;
1352 modechanges changes
;
1355 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "unbanall");
1359 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "unbanall",0, 0)))
1362 rcp
=cip
->exts
[chanservext
];
1365 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1367 while (cip
->channel
->bans
) {
1368 localdosetmode_ban(&changes
, bantostring(cip
->channel
->bans
), MCB_DEL
);
1371 localsetmodeflush(&changes
, 1);
1374 cs_log(sender
,"UNBANALL %s",cip
->name
->content
);
1375 chanservstdmessage(sender
, QM_DONE
);
1379 int csc_dounbanme(void *source
, int cargc
, char **cargv
) {
1380 nick
*sender
=source
;
1383 modechanges changes
;
1387 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "unbanme");
1391 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
, NULL
, "unbanme", 0, 0)))
1394 rcp
=cip
->exts
[chanservext
];
1397 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1399 for (cbh
=&(cip
->channel
->bans
);*cbh
;) {
1400 if (nickmatchban(sender
, *cbh
))
1401 localdosetmode_ban(&changes
, bantostring(*cbh
), MCB_DEL
);
1403 cbh
=&((*cbh
)->next
);
1406 localsetmodeflush(&changes
, 1);
1409 cs_log(sender
,"UNBANME %s",cip
->name
->content
);
1410 chanservstdmessage(sender
, QM_DONE
);
1414 int csc_doclearchan(void *source
, int cargc
, char **cargv
) {
1415 nick
*sender
=source
;
1418 modechanges changes
;
1421 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "clearchan");
1425 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "clearchan",0, 0)))
1428 rcp
=cip
->exts
[chanservext
];
1431 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1432 localdosetmode_key(&changes
, NULL
, MCB_DEL
);
1433 localdosetmode_simple(&changes
, 0, cip
->channel
->flags
);
1434 cs_docheckchanmodes(cip
->channel
, &changes
);
1435 localsetmodeflush(&changes
, 1);
1438 cs_log(sender
,"CLEARCHAN %s",cip
->name
->content
);
1439 chanservstdmessage(sender
, QM_DONE
);
1443 int csc_dorecover(void *source
, int cargc
, char **cargv
) {
1444 nick
*sender
=source
,*np
;
1451 modechanges changes
;
1454 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "recover");
1458 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "recover",0, 0)))
1461 rcp
=cip
->exts
[chanservext
];
1464 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1467 localdosetmode_key(&changes
, NULL
, MCB_DEL
);
1468 localdosetmode_simple(&changes
, 0, cip
->channel
->flags
);
1469 cs_docheckchanmodes(cip
->channel
, &changes
);
1472 while (cip
->channel
->bans
) {
1473 localdosetmode_ban(&changes
, bantostring(cip
->channel
->bans
), MCB_DEL
);
1477 for (i
=0,lp
=cip
->channel
->users
->content
;
1478 i
<cip
->channel
->users
->hashsize
;i
++,lp
++) {
1479 if (*lp
!=nouser
&& (*lp
& CUMODE_OP
)) {
1480 if (!(np
=getnickbynumeric(*lp
)) ||
1481 (!IsService(np
) && (!(rup
=getreguserfromnick(np
)) ||
1482 !(rcup
=findreguseronchannel(rcp
, rup
)) || !(CUHasOpPriv(rcup
)) ||
1483 !(CUIsProtect(rcup
) || CIsProtect(rcp
))))) {
1484 localdosetmode_nick(&changes
, np
, MC_DEOP
);
1489 localsetmodeflush(&changes
, 1);
1492 cs_log(sender
,"RECOVER %s",cip
->name
->content
);
1493 chanservstdmessage(sender
, QM_DONE
);
1497 int csc_dopermban(void *source
, int cargc
, char **cargv
) {
1498 nick
*sender
=source
;
1502 reguser
*rup
=getreguserfromnick(sender
);
1505 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "permban");
1509 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "permban",0, 0)))
1512 rcp
=cip
->exts
[chanservext
];
1515 rbp
->ID
=++lastbanID
;
1516 rbp
->cbp
=makeban(cargv
[1]);
1520 rbp
->reason
=getsstring(cargv
[2],200);
1523 rbp
->next
=rcp
->bans
;
1526 cs_setregban(cip
, rbp
);
1527 csdb_createban(rcp
, rbp
);
1529 chanservstdmessage(sender
, QM_DONE
);
1533 int csc_dotempban(void *source
, int cargc
, char **cargv
) {
1534 nick
*sender
=source
;
1538 reguser
*rup
=getreguserfromnick(sender
);
1539 unsigned int duration
;
1542 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "tempban");
1546 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "tempban",0, 0)))
1549 rcp
=cip
->exts
[chanservext
];
1551 duration
=durationtolong(cargv
[2]);
1554 rbp
->ID
=++lastbanID
;
1555 rbp
->cbp
=makeban(cargv
[1]);
1557 rbp
->expiry
=time(NULL
)+duration
;
1559 rbp
->reason
=getsstring(cargv
[3],200);
1562 rbp
->next
=rcp
->bans
;
1565 cs_setregban(cip
, rbp
);
1566 csdb_createban(rcp
, rbp
);
1568 chanservstdmessage(sender
, QM_DONE
);
1572 int csc_dobanlist(void *source
, int cargc
, char **cargv
) {
1573 nick
*sender
=source
;
1583 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "banlist");
1587 if(!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
, NULL
, "banlist", 0, 0)))
1590 rcp
=cip
->exts
[chanservext
];
1592 if (rcp
->bans
|| cip
->channel
->bans
) {
1593 chanservstdmessage(sender
, QM_REGBANHEADER
, cip
->name
->content
);
1594 for(rbp
=rcp
->bans
;rbp
;rbp
=rbp
->next
) {
1595 rup
=findreguserbyID(rbp
->setby
);
1596 chanservsendmessage(sender
," #%-2d %-29s %-18s %-15s %s",++i
,bantostring(rbp
->cbp
),
1597 rbp
->expiry
?longtoduration(rbp
->expiry
-time(NULL
),0):"Permanent",
1598 rup
?rup
->username
:"<unknown>",
1599 rbp
->reason
?rbp
->reason
->content
:"");
1601 for (cbp
=cip
->channel
->bans
;cbp
;cbp
=cbp
->next
) {
1602 for (rbp
=rcp
->bans
;rbp
;rbp
=rbp
->next
) {
1603 if (banequal(rbp
->cbp
, cbp
))
1607 if (rcp
->banduration
) {
1608 exp
=(cbp
->timeset
+ rcp
->banduration
) - time(NULL
);
1612 chanservsendmessage(sender
, " #%-2d %-29s %-18s %-15s",++i
,bantostring(cbp
),
1613 exp
? longtoduration(exp
,0) : "Permanent",
1617 chanservstdmessage(sender
, QM_ENDOFLIST
);
1619 chanservstdmessage(sender
, QM_NOBANS
, cip
->name
->content
);
1625 int csc_dobandel(void *source
, int cargc
, char **cargv
) {
1626 nick
*sender
=source
;
1631 chanban
*theban
=NULL
;
1632 modechanges changes
;
1636 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "unban");
1640 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
, NULL
, "unban", 0, 0)))
1643 rcp
=cip
->exts
[chanservext
];
1645 /* OK, let's see what they want to remove.. */
1646 if (*cargv
[1]=='#') {
1647 /* Remove by ID number */
1648 if (!(banid
=strtoul(cargv
[1]+1, NULL
, 10))) {
1649 chanservstdmessage(sender
, QM_UNKNOWNBAN
, cargv
[1], cip
->name
->content
);
1653 /* Remove by ban string */
1654 theban
=makeban(cargv
[1]);
1658 for (rbh
=&(rcp
->bans
);*rbh
;rbh
=&((*rbh
)->next
)) {
1660 if ((banid
&& i
==banid
) ||
1661 (theban
&& banequal(theban
, (*rbh
)->cbp
))) {
1662 /* got it - they will need master access to remove this */
1665 if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, "unban", 0, 0))
1668 chanservstdmessage(sender
, QM_REMOVEDPERMBAN
, bantostring(rbp
->cbp
), cip
->name
->content
);
1670 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1671 localdosetmode_ban(&changes
, bantostring(rbp
->cbp
), MCB_DEL
);
1672 localsetmodeflush(&changes
, 1);
1675 /* Remove from database */
1676 csdb_deleteban(rbp
);
1677 /* Remove from list */
1679 /* Free ban/string and actual regban */
1680 freesstring(rbp
->reason
);
1681 freechanban(rbp
->cbp
);
1685 freechanban(theban
);
1691 /* If we've run out of registered bans, let's try channel bans */
1692 if (cip
->channel
&& cip
->channel
->bans
) {
1693 for (cbp
=cip
->channel
->bans
;cbp
;cbp
=cbp
->next
) {
1694 for (rbp
=rcp
->bans
;rbp
;rbp
=rbp
->next
) {
1695 if (banequal(rbp
->cbp
,cbp
))
1703 if ((banid
&& (i
==banid
)) ||
1704 (theban
&& banequal(theban
, cbp
))) {
1705 /* got it - this is just a channel ban */
1706 chanservstdmessage(sender
, QM_REMOVEDCHANBAN
, bantostring(cbp
), cip
->name
->content
);
1707 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1708 localdosetmode_ban(&changes
, cargv
[1], MCB_DEL
);
1709 localsetmodeflush(&changes
, 1);
1712 freechanban(theban
);
1719 chanservstdmessage(sender
, QM_UNKNOWNBAN
, cargv
[1], cip
->name
->content
);
1724 int csc_dobanclear(void *source
, int cargc
, char **cargv
) {
1725 nick
*sender
=source
;
1728 chanban
**cbh
, *cbp
;
1730 modechanges changes
;
1734 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "banclear");
1738 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "banclear", 0, 0)))
1741 rcp
=cip
->exts
[chanservext
];
1744 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1746 for (rbh
=&(rcp
->bans
); *rbh
; ) {
1748 banstr
=bantostring(rbp
->cbp
);
1749 chanservstdmessage(sender
, QM_REMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1751 localdosetmode_ban(&changes
, banstr
, MCB_DEL
);
1752 /* Remove from database */
1753 csdb_deleteban(rbp
);
1754 /* Remove from list */
1756 /* Free ban/string and update setby refcount, and free actual regban */
1757 freesstring(rbp
->reason
);
1758 freechanban(rbp
->cbp
);
1763 for (cbh
=&(cip
->channel
->bans
); *cbh
; ) {
1765 banstr
=bantostring(cbp
);
1766 chanservstdmessage(sender
, QM_REMOVEDCHANBAN
, banstr
, cip
->name
->content
);
1767 localdosetmode_ban(&changes
, banstr
, MCB_DEL
);
1769 localsetmodeflush(&changes
,1);
1772 chanservstdmessage(sender
, QM_DONE
);
1776 int csc_dounbanmask(void *source
, int cargc
, char **cargv
) {
1777 nick
*sender
=source
;
1780 chanban
**cbh
, *cbp
;
1783 modechanges changes
;
1787 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "unbanmask");
1791 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_OPPRIV
, NULL
, "unbanmask", 0, 0)))
1794 rcp
=cip
->exts
[chanservext
];
1795 theban
=makeban(cargv
[1]);
1798 localsetmodeinit(&changes
, cip
->channel
, chanservnick
);
1800 for (rbh
=&(rcp
->bans
); *rbh
; ) {
1802 if (banoverlap(theban
, rbp
->cbp
)) {
1803 banstr
=bantostring(rbp
->cbp
);
1804 /* Check perms and remove */
1805 if (!cs_checkaccess(sender
, NULL
, CA_MASTERPRIV
, cip
, NULL
, 0, 1)) {
1806 chanservstdmessage(sender
, QM_NOTREMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1809 chanservstdmessage(sender
, QM_REMOVEDPERMBAN
, banstr
, cip
->name
->content
);
1811 localdosetmode_ban(&changes
, banstr
, MCB_DEL
);
1812 /* Remove from database */
1813 csdb_deleteban(rbp
);
1814 /* Remove from list */
1816 /* Free ban/string and update setby refcount, and free actual regban */
1817 freesstring(rbp
->reason
);
1818 freechanban(rbp
->cbp
);
1827 for (cbh
=&(cip
->channel
->bans
); *cbh
; ) {
1829 if (banoverlap(theban
, cbp
)) {
1831 banstr
=bantostring(cbp
);
1832 chanservstdmessage(sender
, QM_REMOVEDCHANBAN
, banstr
, cip
->name
->content
);
1833 localdosetmode_ban(&changes
, banstr
, MCB_DEL
);
1838 localsetmodeflush(&changes
,1);
1842 chanservstdmessage(sender
, QM_DONE
);
1846 int csc_dorenchan(void *source
, int cargc
, char **cargv
) {
1847 nick
*sender
=source
;
1848 reguser
*rup
=getreguserfromnick(sender
);
1849 chanindex
*cip1
,*cip2
;
1856 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "renchan");
1860 if (!(cip1
=findchanindex(cargv
[0])) || !(rcp
=cip1
->exts
[chanservext
])) {
1861 chanservstdmessage(sender
, QM_UNKNOWNCHAN
, cargv
[0]);
1865 if (*cargv
[1] != '#') {
1866 chanservstdmessage(sender
, QM_INVALIDCHANNAME
, cargv
[0]);
1870 if (!(cip2
=findorcreatechanindex(cargv
[1])) || cip2
->exts
[chanservext
]) {
1871 chanservstdmessage(sender
, QM_ALREADYREGISTERED
, cip2
->name
->content
);
1875 cs_log(sender
,"RENCHAN %s -> %s",cip1
->name
->content
,cip2
->name
->content
);
1877 /* Remove from the channel. Don't bother if the channel doesn't exist. */
1878 if (!CIsSuspended(rcp
) && cip1
->channel
) {
1880 chanservjoinchan(cip1
->channel
);
1881 CClearSuspended(rcp
);
1884 cip1
->exts
[chanservext
]=NULL
;
1885 releasechanindex(cip1
);
1887 cip2
->exts
[chanservext
]=rcp
;
1889 if (cip2
->channel
) {
1890 chanservjoinchan(cip2
->channel
);
1893 csdb_updatechannel(rcp
);
1894 chanservstdmessage(sender
, QM_DONE
);
1899 int csc_dochannelcomment(void *source
, int cargc
, char **cargv
) {
1900 nick
*sender
=source
;
1901 reguser
*rup
=getreguserfromnick(sender
);
1911 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "channelcomment");
1915 if (!(cip
=findchanindex(cargv
[0])) || !(rcp
=cip
->exts
[chanservext
])) {
1916 chanservstdmessage(sender
, QM_UNKNOWNCHAN
, cargv
[0]);
1921 if (!ircd_strcmp(cargv
[1],"none")) {
1922 freesstring(rcp
->comment
);
1925 if (*cargv
[1]=='+') {
1927 strcpy(buf
,rcp
->comment
->content
);
1928 bufpos
=rcp
->comment
->length
;
1933 strncpy(buf
+bufpos
, cargv
[1]+1, 250-bufpos
);
1935 strncpy(buf
, cargv
[1], 250);
1938 freesstring(rcp
->comment
);
1939 rcp
->comment
=getsstring(buf
,250);
1941 csdb_updatechannel(rcp
);
1945 chanservstdmessage(sender
, QM_COMMENT
, cip
->name
->content
, rcp
->comment
->content
);
1947 chanservstdmessage(sender
, QM_NOCOMMENT
, cip
->name
->content
);
1952 int csc_dorejoin(void *source
, int cargc
, char **cargv
) {
1953 nick
*sender
=source
;
1958 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "rejoin");
1962 if (!(cip
=findchanindex(cargv
[0])) || !(rcp
=cip
->exts
[chanservext
])) {
1963 chanservstdmessage(sender
, QM_UNKNOWNCHAN
, cargv
[0]);
1967 if (CIsJoined(rcp
) && !CIsSuspended(rcp
)) {
1969 chanservjoinchan(cip
->channel
);
1970 CClearSuspended(rcp
);
1971 chanservjoinchan(cip
->channel
);
1974 chanservstdmessage(sender
, QM_DONE
);
1979 int csc_dochantype(void *source
, int cargc
, char **cargv
) {
1980 nick
*sender
=source
;
1986 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "chantype");
1990 if (!(cip
=findchanindex(cargv
[0])) || !(rcp
=cip
->exts
[chanservext
])) {
1991 chanservstdmessage(sender
, QM_UNKNOWNCHAN
, cargv
[0]);
1997 for (type
=CHANTYPES
-1;type
;type
--) {
1998 if (!ircd_strcmp(chantypes
[type
]->content
, cargv
[1]))
2002 chanservstdmessage(sender
, QM_UNKNOWNCHANTYPE
, cargv
[1]);
2007 csdb_updatechannel(rcp
);
2008 chanservstdmessage(sender
, QM_DONE
);
2011 chanservstdmessage(sender
, QM_CHANTYPEIS
, cip
->name
->content
, chantypes
[rcp
->chantype
]->content
);
2016 int csc_doadduser(void *source
, int cargc
, char **cargv
) {
2017 nick
*sender
=source
;
2025 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "adduser");
2029 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "adduser", QPRIV_CHANGECHANLEV
, 0)))
2032 rcp
=cip
->exts
[chanservext
];
2034 for (i
=1;i
<cargc
;i
++) {
2035 if (!(rup
=findreguser(sender
, cargv
[i
])))
2038 if ((rcup
=findreguseronchannel(rcp
, rup
))) {
2039 chanservstdmessage(sender
, QM_ALREADYKNOWNONCHAN
, cargv
[i
], cip
->name
->content
);
2043 rcup
=getregchanuser();
2046 rcup
->flags
= QCUFLAG_OP
| QCUFLAG_AUTOOP
| QCUFLAG_TOPIC
;
2047 rcup
->changetime
=time(NULL
);
2051 cs_log(sender
,"CHANLEV %s #%s +aot (+ -> +aot)",cip
->name
->content
,rup
->username
);
2052 addregusertochannel(rcup
);
2053 csdb_createchanuser(rcup
);
2056 rcp
->status
|= QCSTAT_OPCHECK
;
2059 chanservstdmessage(sender
, QM_DONE
);
2064 int csc_doremoveuser(void *source
, int cargc
, char **cargv
) {
2065 nick
*sender
=source
;
2074 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "removeuser");
2078 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
, NULL
, "adduser", QPRIV_CHANGECHANLEV
, 0)))
2081 if (cs_checkaccess(sender
, NULL
, CA_OWNERPRIV
, cip
, "adduser", QPRIV_CHANGECHANLEV
, 1))
2084 rcp
=cip
->exts
[chanservext
];
2086 for (i
=1;i
<cargc
;i
++) {
2087 if (!(rup
=findreguser(sender
, cargv
[i
])))
2090 if (!(rcup
=findreguseronchannel(rcp
, rup
))) {
2091 chanservstdmessage(sender
, QM_CHANUSERUNKNOWN
, cargv
[i
], cip
->name
->content
);
2095 if (CUIsOwner(rcup
)) {
2096 chanservstdmessage(sender
, QM_CANNOTREMOVEOWNER
, cargv
[i
], cip
->name
->content
);
2100 if (CUIsMaster(rcup
) && !isowner
&& (rup
!= getreguserfromnick(sender
))) {
2101 chanservstdmessage(sender
, QM_CANNOTREMOVEMASTER
, cargv
[i
], cip
->name
->content
);
2105 cs_log(sender
,"CHANLEV %s #%s -%s (%s -> +)",cip
->name
->content
,rup
->username
,
2106 printflags_noprefix(rcup
->flags
, rcuflags
), printflags(rcup
->flags
, rcuflags
));
2108 csdb_deletechanuser(rcup
);
2109 delreguserfromchannel(rcp
, rup
);
2112 rcp
->status
|= QCSTAT_OPCHECK
;
2115 chanservstdmessage(sender
, QM_DONE
);
2120 int csc_dochanstat(void *source
, int cargc
, char **cargv
) {
2121 nick
*sender
=source
;
2127 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "chanstat");
2131 if (!(cip
=cs_checkaccess(sender
, cargv
[0], CA_MASTERPRIV
,
2132 NULL
, "chanstat", QPRIV_VIEWFULLCHANLEV
, 0)))
2135 rcp
=cip
->exts
[chanservext
];
2137 chanservstdmessage(sender
, QM_STATSHEADER
, cip
->name
->content
);
2139 strftime(timebuf
, 30, "%d/%m/%y %H:%M", localtime(&(rcp
->created
)));
2140 chanservstdmessage(sender
, QM_STATSADDED
, timebuf
);
2142 /* Show opers founder/addedby/type info */
2143 if (cs_privcheck(QPRIV_VIEWFULLCHANLEV
, sender
)) {
2144 reguser
*founder
=NULL
, *addedby
=NULL
;
2146 strftime(timebuf
, 30, "%d/%m/%y %H:%M", localtime(&(rcp
->lastactive
)));
2147 chanservstdmessage(sender
, QM_STATSLASTACTIVE
, timebuf
);
2150 addedby
=findreguserbyID(rcp
->addedby
);
2151 chanservstdmessage(sender
, QM_ADDEDBY
, addedby
? addedby
->username
: "(unknown)");
2152 founder
=findreguserbyID(rcp
->founder
);
2153 chanservstdmessage(sender
, QM_FOUNDER
, founder
? founder
->username
: "(unknown)");
2154 chanservstdmessage(sender
, QM_CHANTYPE
, chantypes
[rcp
->chantype
]->content
);
2157 strftime(timebuf
, 30, "%d/%m/%y %H:%M", localtime(&(rcp
->created
)));
2159 chanservstdmessage(sender
, QM_STATSJOINS
, timebuf
, rcp
->maxusers
, rcp
->totaljoins
,
2160 (float)rcp
->totaljoins
/ ((time(NULL
)-rcp
->created
)/(3600*24)));
2162 strftime(timebuf
, 30, "%d/%m/%y %H:%M", localtime(&(rcp
->statsreset
)));
2164 chanservstdmessage(sender
, QM_STATSJOINS
, timebuf
, rcp
->tripusers
, rcp
->tripjoins
,
2165 (float)rcp
->tripjoins
/ ((time(NULL
)-rcp
->statsreset
)/(3600*24)));