]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chancmds.c
Added support for remembering the oldest-ever timestamp seen for a channel.
[irc/quakenet/newserv.git] / chanserv / chancmds.c
1 /*
2 * chancmds.c:
3 * Provides basic channel commands:
4 * CHANLEV
5 * WHOIS
6 * CHANFLAGS
7 * etc.
8 */
9
10 #include "chanserv.h"
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"
18
19 #include <string.h>
20 #include <stdio.h>
21
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);
56
57 char *getchanmode(regchan *rcp);
58
59 void _init() {
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.");
94 }
95
96 void _fini() {
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);
131 }
132
133 int csc_dochanflags(void *source, int cargc, char **cargv) {
134 regchan *rcp;
135 nick *sender=source;
136 reguser *rup=getreguserfromnick(sender);
137 chanindex *cip;
138 flag_t oldflags,changemask;
139 char flagbuf[20];
140
141 if (cargc<1) {
142 chanservstdmessage(sender,QM_NOTENOUGHPARAMS,"chanflags");
143 return CMD_ERROR;
144 }
145
146 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV, NULL,
147 "chanflags", QPRIV_VIEWCHANFLAGS, 0)))
148 return CMD_ERROR;
149
150 rcp=cip->exts[chanservext];
151
152 if (cargc>1) {
153 if (!cs_checkaccess(sender, NULL, CA_MASTERPRIV, cip, "chanflags",
154 QPRIV_CHANGECHANFLAGS, 0))
155 return CMD_ERROR;
156
157 oldflags=rcp->flags;
158 changemask=QCFLAG_USERCONTROL;
159 if (UIsDev(rup)) {
160 changemask=QCFLAG_ALL;
161 }
162 setflags(&rcp->flags, changemask, cargv[1], rcflags, REJECT_NONE);
163
164 /* We might need to do things in response to the flag changes.. */
165 if (cip->channel) {
166 if ((oldflags ^ rcp->flags) & (QCFLAG_JOINED | QCFLAG_SUSPENDED)) {
167 chanservjoinchan(cip->channel);
168 rcp->status |= (QCSTAT_OPCHECK | QCSTAT_MODECHECK | QCSTAT_BANCHECK);
169 rcp->lastbancheck=0;
170 cs_timerfunc(cip);
171 } else {
172 if (CIsEnforce(rcp)) {
173 rcp->lastbancheck=0;
174 cs_checkbans(cip->channel);
175 }
176
177 if (CIsProtect(rcp) || CIsBitch(rcp) || CIsAutoOp(rcp) || CIsAutoVoice(rcp) || CIsKnownOnly(rcp)) {
178 rcp->status |= QCSTAT_OPCHECK;
179 cs_timerfunc(cip);
180 }
181 }
182 }
183
184 if (CIsAutoLimit(rcp) && !(oldflags & QCFLAG_AUTOLIMIT)) {
185 rcp->forcemodes |= CHANMODE_LIMIT;
186 rcp->denymodes &= ~CHANMODE_LIMIT;
187 rcp->limit=0;
188 cs_timerfunc(cip);
189 }
190
191 if (!CIsAutoLimit(rcp) && (oldflags & QCFLAG_AUTOLIMIT)) {
192 rcp->forcemodes &= ~CHANMODE_LIMIT;
193 if (cip->channel)
194 cs_checkchanmodes(cip->channel);
195 }
196
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);
201 }
202
203 chanservstdmessage(sender,QM_CURCHANFLAGS,cip->name->content,printflags(rcp->flags, rcflags));
204 return CMD_OK;
205 }
206
207 int csc_dochanmode(void *source, int cargc, char **cargv) {
208 regchan *rcp;
209 nick *sender=source;
210 chanindex *cip;
211 flag_t forceflags,denyflags;
212 char buf1[60];
213 int carg=2,limdone=0;
214 sstring *newkey=NULL;
215 unsigned int newlim=0;
216
217 if (cargc<1) {
218 chanservstdmessage(sender,QM_NOTENOUGHPARAMS,"chanmode");
219 return CMD_ERROR;
220 }
221
222 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV,
223 NULL, "chanmode", QPRIV_VIEWCHANMODES, 0)))
224 return CMD_ERROR;
225
226 rcp=cip->exts[chanservext];
227
228 if (cargc>1) {
229 if (!cs_checkaccess(sender, NULL, CA_MASTERPRIV,
230 cip, "chanmode", QPRIV_CHANGECHANMODES, 0))
231 return CMD_ERROR;
232
233 /* Save the current modes.. */
234 strcpy(buf1,getchanmode(rcp));
235
236 /* Pick out the + flags: start from 0 */
237 forceflags=0;
238 setflags(&forceflags, CHANMODE_ALL, cargv[1], cmodeflags, REJECT_NONE);
239
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;
244
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;
249 }
250 if (forceflags & CHANMODE_PRIVATE) {
251 forceflags &= ~CHANMODE_SECRET;
252 denyflags |= CHANMODE_SECRET;
253 }
254
255 if ((forceflags & CHANMODE_LIMIT) &&
256 (!(forceflags & CHANMODE_KEY) || strrchr(cargv[1],'l') < strrchr(cargv[1],'k'))) {
257 if (cargc<=carg) {
258 chanservstdmessage(sender,QM_NOTENOUGHPARAMS,"chanmode");
259 return CMD_ERROR;
260 }
261 newlim=strtol(cargv[carg++],NULL,10);
262 limdone=1;
263 }
264
265 if (forceflags & CHANMODE_KEY) {
266 if (cargc<=carg) {
267 chanservstdmessage(sender,QM_NOTENOUGHPARAMS,"chanmode");
268 return CMD_ERROR;
269 }
270 newkey=getsstring(cargv[carg++], KEYLEN);
271 }
272
273 if ((forceflags & CHANMODE_LIMIT) && !limdone) {
274 if (cargc<=carg) {
275 chanservstdmessage(sender,QM_NOTENOUGHPARAMS,"chanmode");
276 return CMD_ERROR;
277 }
278 newlim=strtol(cargv[carg++],NULL,10);
279 limdone=1;
280 }
281
282 if (CIsAutoLimit(rcp)) {
283 forceflags |= CHANMODE_LIMIT;
284 denyflags &= ~CHANMODE_LIMIT;
285 newlim=rcp->limit;
286 }
287
288 /* It parsed OK, so update the structure.. */
289 rcp->forcemodes=forceflags;
290 rcp->denymodes=denyflags;
291 if (rcp->key)
292 freesstring(rcp->key);
293 rcp->key=newkey;
294 rcp->limit=newlim;
295
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);
300 }
301
302 chanservstdmessage(sender,QM_CURFORCEMODES,cip->name->content,getchanmode(rcp));
303
304 return CMD_OK;
305 }
306
307 char *getchanmode(regchan *rcp) {
308 static char buf1[50];
309 char buf2[30];
310
311 if (rcp->forcemodes) {
312 strcpy(buf1,printflags(rcp->forcemodes, cmodeflags));
313 } else {
314 buf1[0]='\0';
315 }
316
317 strcpy(buf2,printflagdiff(CHANMODE_ALL, ~(rcp->denymodes), cmodeflags));
318 strcat(buf1, buf2);
319
320 if (rcp->forcemodes & CHANMODE_LIMIT) {
321 sprintf(buf2, " %d",rcp->limit);
322 strcat(buf1, buf2);
323 }
324
325 if (rcp->forcemodes & CHANMODE_KEY) {
326 sprintf(buf2, " %s",rcp->key->content);
327 strcat(buf1, buf2);
328 }
329
330 if (*buf1=='\0') {
331 strcpy(buf1,"(none)");
332 }
333
334 return buf1;
335 }
336
337 int compareflags(const void *u1, const void *u2) {
338 const regchanuser *r1=*(void **)u1, *r2=*(void **)u2;
339 flag_t f1,f2;
340
341 for (f1=QCUFLAG_OWNER;f1;f1>>=1)
342 if (r1->flags & f1)
343 break;
344
345 for (f2=QCUFLAG_OWNER;f2;f2>>=1)
346 if (r2->flags & f2)
347 break;
348
349 if (f1==f2) {
350 return ircd_strcmp(r1->user->username, r2->user->username);
351 } else {
352 return f2-f1;
353 }
354 }
355
356 int csc_dochanlev(void *source, int cargc, char **cargv) {
357 nick *sender=source;
358 chanindex *cip;
359 regchan *rcp;
360 regchanuser *rcup, *rcuplist;
361 regchanuser **rusers;
362 reguser *rup=getreguserfromnick(sender), *target;
363 char time1[15],time2[15];
364 char flagbuf[30];
365 struct tm *tmp;
366 flag_t flagmask, changemask, flags, oldflags;
367 int showtimes=0;
368 int donehead=0;
369 int i,j;
370 int newuser=0;
371 int usercount;
372
373 if (cargc<1) {
374 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "chanlev");
375 return CMD_ERROR;
376 }
377
378 if (!(cip=cs_checkaccess(sender, cargv[0], CA_KNOWN,
379 NULL, "chanlev", QPRIV_VIEWFULLCHANLEV, 0)))
380 return CMD_ERROR;
381
382 rcp=cip->exts[chanservext];
383 rcup=findreguseronchannel(rcp, rup);
384
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);
388
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;
392 showtimes=1;
393 }
394
395 if (cargc==1) {
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);
404 }
405
406 /* Count users */
407 for (i=0,usercount=0;i<REGCHANUSERHASHSIZE;i++)
408 for (rcuplist=rcp->regusers[i];rcuplist;rcuplist=rcuplist->nextbychan)
409 usercount++;
410
411 /* Allocate array */
412 rusers=(regchanuser **)malloc(usercount * sizeof(regchanuser *));
413
414 /* Fill array */
415 for (j=i=0;i<REGCHANUSERHASHSIZE;i++) {
416 for (rcuplist=rcp->regusers[i];rcuplist;rcuplist=rcuplist->nextbychan) {
417 if (!(flags=rcuplist->flags & flagmask))
418 continue;
419
420 rusers[j++]=rcuplist;
421 }
422 }
423
424 /* Sort */
425 qsort(rusers, j, sizeof(regchanuser *), compareflags);
426
427 /* List */
428 for (i=0;i<j;i++) {
429 rcuplist=rusers[i];
430
431 if (!(flags=rcuplist->flags & flagmask))
432 continue;
433
434 if (!donehead) {
435 chanservstdmessage(sender, QM_CHANLEVHEADER, cip->name->content);
436 if (showtimes)
437 chanservstdmessage(sender, QM_CHANLEVCOLFULL);
438 else
439 chanservstdmessage(sender, QM_CHANLEVCOLSHORT);
440 donehead=1;
441 }
442
443 if (showtimes) {
444 if (!rcuplist->usetime) {
445 strcpy(time1,"Never");
446 } else {
447 tmp=localtime(&(rcuplist->usetime));
448 strftime(time1,15,"%d/%m/%y %H:%M",tmp);
449 }
450 if (!rcuplist->changetime) {
451 strcpy(time2, "Unknown");
452 } else {
453 tmp=localtime(&(rcuplist->changetime));
454 strftime(time2,15,"%d/%m/%y %H:%M",tmp);
455 }
456 chanservsendmessage(sender, " %-15s %-13s %-14s %-14s %s", rcuplist->user->username,
457 printflags(flags, rcuflags), time1, time2, rcuplist->info?rcuplist->info->content:"");
458 } else
459 chanservsendmessage(sender, " %-15s %s", rcuplist->user->username, printflags(flags, rcuflags));
460 }
461
462 if (donehead) {
463 chanservstdmessage(sender, QM_ENDOFLIST);
464 } else {
465 chanservstdmessage(sender, QM_NOUSERSONCHANLEV, cip->name->content);
466 }
467
468 free(rusers);
469 } else {
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.. */
473
474 rcuplist=findreguseronchannel(rcp, target);
475
476 if (cargc>2) {
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 */
482 )) {
483 chanservstdmessage(sender, QM_NOACCESSONCHAN, cip->name->content, "chanlev");
484 return CMD_ERROR;
485 }
486
487 if (!rcuplist) {
488 rcuplist=getregchanuser();
489 rcuplist->user=target;
490 rcuplist->chan=rcp;
491 rcuplist->flags=0;
492 rcuplist->changetime=time(NULL);
493 rcuplist->usetime=0;
494 rcuplist->info=NULL;
495 newuser=1;
496 }
497
498 if (cs_privcheck(QPRIV_CHANGECHANLEV, sender)) {
499 /* Opers are allowed to change everything */
500 changemask = QCUFLAG_ALL;
501 } else {
502 changemask=0;
503
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);
509 }
510
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);
515
516 /* Owners are allowed to manipulate +ms as well */
517 if (CUIsOwner(rcup))
518 changemask |= ( QCUFLAG_MASTER | QCUFLAG_SPAMCON );
519 }
520
521 oldflags=rcuplist->flags;
522 if (setflags(&(rcuplist->flags), changemask, cargv[2], rcuflags, REJECT_UNKNOWN | REJECT_DISALLOWED)) {
523 chanservstdmessage(sender, QM_INVALIDCHANLEVCHANGE);
524 return CMD_ERROR;
525 }
526
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);
531
532 /* +d can't be +o */
533 if (CUIsDeny(rcuplist))
534 rcuplist->flags &= ~QCUFLAG_OP;
535
536 /* +q can't be +v */
537 if (CUIsQuiet(rcuplist))
538 rcuplist->flags &= ~QCUFLAG_VOICE;
539
540 /* -o or +p can't be +a */
541 if (!CUIsOp(rcuplist) || CUIsProtect(rcuplist))
542 rcuplist->flags &= ~QCUFLAG_AUTOOP;
543
544 /* +a or -v or +p can't be +g */
545 if (!CUIsVoice(rcuplist) || CUIsAutoOp(rcuplist) || CUIsProtect(rcuplist))
546 rcuplist->flags &= ~QCUFLAG_AUTOVOICE;
547
548 /* and -ov can't be +p */
549 if (!CUIsOp(rcuplist) && !CUIsVoice(rcuplist))
550 rcuplist->flags &= ~QCUFLAG_PROTECT;
551
552 /* Check if anything "significant" has changed */
553 if ((oldflags ^ rcuplist->flags) & (QCUFLAG_OWNER | QCUFLAG_MASTER | QCUFLAG_OP))
554 rcuplist->changetime=time(NULL);
555
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));
559
560 /* Now see what we do next */
561 if (rcuplist->flags) {
562 /* User still valid: update or create */
563 if (newuser) {
564 addregusertochannel(rcuplist);
565 csdb_createchanuser(rcuplist);
566 } else {
567 csdb_updatechanuser(rcuplist);
568 }
569 } else {
570 /* User has no flags: delete */
571 if (!newuser) {
572 csdb_deletechanuser(rcuplist);
573 delreguserfromchannel(rcp, target);
574 }
575 freeregchanuser(rcuplist);
576 rcuplist=NULL;
577 for (i=0;i<REGCHANUSERHASHSIZE;i++)
578 if (rcp->regusers[i])
579 break;
580 if (i==REGCHANUSERHASHSIZE) {
581 cs_log(sender,"DELCHAN %s (Cleared chanlev)",cip->name->content);
582 cs_removechannel(rcp);
583 }
584 }
585
586 /* Say we've done it */
587 chanservstdmessage(sender, QM_DONE);
588 rcp->status |= QCSTAT_OPCHECK;
589 cs_timerfunc(cip);
590 }
591
592 if (rcuplist && (rcuplist->flags & flagmask)) {
593 chanservstdmessage(sender, QM_CHANUSERFLAGS, cargv[1], cip->name->content,
594 printflags(rcuplist->flags & flagmask, rcuflags));
595 } else {
596 chanservstdmessage(sender, QM_CHANUSERUNKNOWN, cargv[1], cip->name->content);
597 }
598 }
599
600 return CMD_OK;
601 }
602
603 int csc_doautolimit(void *source, int cargc, char **cargv) {
604 nick *sender=source;
605 chanindex *cip;
606 regchan *rcp;
607 int oldlimit;
608
609 if (cargc<1) {
610 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "autolimit");
611 return CMD_ERROR;
612 }
613
614 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV,
615 NULL, "autolimit", QPRIV_VIEWAUTOLIMIT, 0)))
616 return CMD_ERROR;
617
618 rcp=cip->exts[chanservext];
619
620 if (cargc>1) {
621 if (!cs_checkaccess(sender, NULL, CA_MASTERPRIV,
622 cip, "autolimit", QPRIV_CHANGEAUTOLIMIT, 0))
623 return CMD_ERROR;
624
625 oldlimit=rcp->autolimit;
626 rcp->autolimit=strtol(cargv[1],NULL,10);
627
628 if (rcp->autolimit<1)
629 rcp->autolimit=1;
630
631 csdb_updatechannel(rcp);
632
633 cs_log(sender,"AUTOLIMIT %s %s (%d -> %d)",cip->name->content,cargv[1],oldlimit,rcp->autolimit);
634 chanservstdmessage(sender, QM_DONE);
635 rcp->limit=0;
636 cs_timerfunc(cip);
637 }
638
639 chanservstdmessage(sender, QM_CHANAUTOLIMIT, cargv[0], rcp->autolimit);
640 return CMD_OK;
641 }
642
643 int csc_dobantimer(void *source, int cargc, char **cargv) {
644 nick *sender=source;
645 chanindex *cip;
646 regchan *rcp;
647 int oldtimer;
648
649 if (cargc<1) {
650 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "bantimer");
651 return CMD_ERROR;
652 }
653
654 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV, NULL, "bantimer",
655 QPRIV_VIEWBANTIMER, 0)))
656 return CMD_ERROR;
657
658 rcp=cip->exts[chanservext];
659
660 if (cargc>1) {
661 if (!cs_checkaccess(sender, NULL, CA_MASTERPRIV, cip, "bantimer",
662 QPRIV_CHANGEBANTIMER, 0))
663 return CMD_ERROR;
664
665 oldtimer=rcp->banduration;
666 rcp->banduration=durationtolong(cargv[1]);
667
668 if (rcp->banduration<0)
669 rcp->banduration=0;
670
671 /* Arbitrary limit */
672 if (rcp->banduration > 31622400)
673 rcp->banduration = 31622400;
674
675 csdb_updatechannel(rcp);
676
677 cs_log(sender,"BANTIMER %s %s (%u -> %u)",cip->name->content,cargv[1],oldtimer,rcp->banduration);
678 chanservstdmessage(sender, QM_DONE);
679 cs_timerfunc(cip);
680 }
681
682 if (rcp->banduration)
683 chanservstdmessage(sender, QM_CHANBANAUTOREMOVE, cargv[0], longtoduration(rcp->banduration, 1));
684 else
685 chanservstdmessage(sender, QM_NOCHANBANAUTOREMOVE, cargv[0]);
686
687 return CMD_OK;
688 }
689
690 int csc_dowelcome(void *source, int cargc, char **cargv) {
691 nick *sender=source;
692 chanindex *cip;
693 regchan *rcp;
694 sstring *oldwelcome;
695
696 if (cargc<1) {
697 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "welcome");
698 return CMD_ERROR;
699 }
700
701 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV, NULL, "welcome",
702 QPRIV_VIEWWELCOME, 0)))
703 return CMD_ERROR;
704
705 rcp=cip->exts[chanservext];
706
707 if (cargc>1) {
708 if (!cs_checkaccess(sender, NULL, CA_MASTERPRIV, cip, "welcome",
709 QPRIV_CHANGEWELCOME, 0))
710 return CMD_ERROR;
711
712 oldwelcome=rcp->welcome;
713
714 rcp->welcome=getsstring(cargv[1], 500);
715 csdb_updatechannel(rcp);
716
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);
720 }
721
722 chanservstdmessage(sender, QM_WELCOMEMESSAGEIS, rcp->index->name->content,
723 rcp->welcome?rcp->welcome->content:"(none)");
724
725 return CMD_OK;
726 }
727
728 int csc_doaddchan(void *source, int cargc, char **cargv) {
729 nick *sender=source;
730 reguser *rup=getreguserfromnick(sender);
731 chanindex *cip;
732 regchan *rcp;
733 regchanuser *rcup;
734 reguser *founder;
735 flag_t flags;
736 short type=0;
737
738 if (!rup)
739 return CMD_ERROR;
740
741 if (cargc<1) {
742 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "addchan");
743 return CMD_ERROR;
744 }
745
746 if (*cargv[0] != '#') {
747 chanservstdmessage(sender, QM_INVALIDCHANNAME, cargv[0]);
748 return CMD_ERROR;
749 }
750
751 if (cargc>1) {
752 if (!(founder=findreguser(sender, cargv[1])))
753 return CMD_ERROR;
754 } else {
755 founder=rup;
756 }
757
758 if (cargc>2) {
759 flags=0;
760 setflags(&flags, QCFLAG_ALL, cargv[2], rcflags, REJECT_NONE);
761 } else {
762 flags = (QCFLAG_JOINED | QCFLAG_BITCH | QCFLAG_PROTECT | QCFLAG_ENFORCE);
763 }
764
765 /* Pick up the chantype */
766 if (cargc>3) {
767 for (type=CHANTYPES-1;type;type--) {
768 if (!ircd_strcmp(chantypes[type]->content, cargv[3]))
769 break;
770 }
771 if (!type) {
772 chanservstdmessage(sender, QM_UNKNOWNCHANTYPE, cargv[3]);
773 return CMD_ERROR;
774 }
775 }
776
777 if (!(cip=findorcreatechanindex(cargv[0]))) {
778 chanservstdmessage(sender, QM_INVALIDCHANNAME, cargv[0]);
779 return CMD_ERROR;
780 }
781
782 if (cip->exts[chanservext]) {
783 chanservstdmessage(sender, QM_ALREADYREGISTERED, cip->name->content);
784 return CMD_ERROR;
785 }
786
787 /* Initialise the channel */
788 rcp=getregchan();
789
790 /* ID, index */
791 rcp->ID=++lastchannelID;
792 rcp->index=cip;
793 cip->exts[chanservext]=rcp;
794
795 rcp->chantype=type;
796 rcp->flags=flags;
797 rcp->status=0;
798 rcp->bans=NULL;
799 rcp->lastcountersync=0;
800
801 rcp->limit=0;
802 rcp->forcemodes=CHANMODE_NOEXTMSG | CHANMODE_TOPICLIMIT;
803 rcp->denymodes=0;
804
805 if (CIsAutoLimit(rcp)) {
806 rcp->forcemodes |= CHANMODE_LIMIT;
807 }
808
809 rcp->autolimit=5;
810 rcp->banstyle=0;
811
812 rcp->created=rcp->lastactive=rcp->statsreset=rcp->ostatsreset=time(NULL);
813 rcp->banduration=1800;
814 rcp->autoupdate=0;
815 rcp->lastbancheck=0;
816
817 /* Added by */
818 rcp->addedby=rup->ID;
819
820 /* Founder */
821 rcp->founder=founder->ID;
822
823 /* Suspend by */
824 rcp->suspendby=0;
825
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;
828
829 /* Users */
830 memset(rcp->regusers,0,REGCHANUSERHASHSIZE*sizeof(reguser *));
831
832 rcp->checksched=NULL;
833 rcp->ltimestamp=0;
834
835 /* Add new channel to db.. */
836 csdb_createchannel(rcp);
837
838 /* Add the founder as +ano */
839 rcup=getregchanuser();
840 rcup->chan=rcp;
841 rcup->user=founder;
842 rcup->flags=(QCUFLAG_OWNER | QCUFLAG_OP | QCUFLAG_AUTOOP);
843 rcup->usetime=0;
844 rcup->info=NULL;
845 rcup->changetime=time(NULL);
846
847 addregusertochannel(rcup);
848 csdb_createchanuser(rcup);
849
850 /* If the channel exists, get the ball rolling */
851 if (cip->channel) {
852 chanservjoinchan(cip->channel);
853 rcp->status |= QCSTAT_MODECHECK | QCSTAT_OPCHECK | QCSTAT_BANCHECK;
854 cs_timerfunc(cip);
855 }
856
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);
859 return CMD_OK;
860 }
861
862 int csc_dosuspendchan(void *source, int cargc, char **cargv) {
863 nick *sender=source;
864 reguser *rup=getreguserfromnick(sender);
865 chanindex *cip;
866 regchan *rcp;
867
868 if (!rup)
869 return CMD_ERROR;
870
871 if (cargc<2) {
872 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "suspendchan");
873 return CMD_ERROR;
874 }
875
876 if (!(cip=findchanindex(cargv[0])) || !(rcp=cip->exts[chanservext])) {
877 chanservstdmessage(sender, QM_UNKNOWNCHAN, cargv[0]);
878 return CMD_ERROR;
879 }
880
881 if (CIsSuspended(rcp)) {
882 chanservstdmessage(sender, QM_CHANNELALREADYSUSPENDED, cip->name->content);
883 return CMD_ERROR;
884 }
885
886 CSetSuspended(rcp);
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);
891
892 csdb_updatechannel(rcp);
893 chanservstdmessage(sender, QM_DONE);
894
895 return CMD_OK;
896 }
897
898 int csc_dosuspendchanlist(void *source, int cargc, char **cargv) {
899 nick *sender=source;
900 reguser *rup=getreguserfromnick(sender);
901 chanindex *cip;
902 regchan *rcp;
903 int i;
904 char *bywhom;
905 unsigned int count=0;
906
907 if (!rup)
908 return CMD_ERROR;
909
910 if (cargc < 1) {
911 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "suspendchanlist");
912 return CMD_ERROR;
913 }
914
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]))
919 continue;
920
921 if (!CIsSuspended(rcp))
922 continue;
923
924 if ((rcp->suspendby != rup->ID) && match(cargv[0], cip->name->content))
925 continue;
926
927 if (rcp->suspendby == rup->ID)
928 bywhom=rup->username;
929 else {
930 reguser *trup=findreguserbyID(rcp->suspendby);
931 if (trup)
932 bywhom=trup->username;
933 else
934 bywhom="unknown";
935 }
936 count++;
937 chanservsendmessage(sender, "%-30s %-15s %s", cip->name->content, bywhom, rcp->suspendreason->content);
938 if (count >= 2000) {
939 chanservstdmessage(sender, QM_TOOMANYRESULTS, 2000, "channels");
940 return CMD_ERROR;
941 }
942 }
943 }
944 chanservstdmessage(sender, QM_RESULTCOUNT, count, "channel", (count==1)?"":"s");
945
946 return CMD_OK;
947 }
948
949 int csc_dounsuspendchan(void *source, int cargc, char **cargv) {
950 nick *sender=source;
951 reguser *rup=getreguserfromnick(sender);
952 chanindex *cip;
953 regchan *rcp;
954
955 if (!rup)
956 return CMD_ERROR;
957
958 if (cargc<1) {
959 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "unsuspendchan");
960 return CMD_ERROR;
961 }
962
963 if (!(cip=findchanindex(cargv[0])) || !(rcp=cip->exts[chanservext])) {
964 chanservstdmessage(sender, QM_UNKNOWNCHAN, cargv[0]);
965 return CMD_ERROR;
966 }
967
968 if(!CIsSuspended(rcp)) {
969 chanservstdmessage(sender, QM_CHANNELNOTSUSPENDED, cip->name->content);
970 cs_log(sender,"UNSUSPENDCHAN %s is not suspended",cip->name->content);
971 return CMD_ERROR;
972 }
973
974 CClearSuspended(rcp);
975 cs_log(sender,"UNSUSPENDCHAN %s (%s)",cip->name->content,rcp->suspendreason->content);
976 freesstring(rcp->suspendreason);
977 rcp->suspendreason = NULL;
978 rcp->suspendby = 0;
979
980 chanservjoinchan(cip->channel);
981
982 csdb_updatechannel(rcp);
983 chanservstdmessage(sender, QM_DONE);
984
985 return CMD_OK;
986 }
987
988 int csc_dodelchan(void *source, int cargc, char **cargv) {
989 nick *sender=source;
990 reguser *rup=getreguserfromnick(sender);
991 chanindex *cip;
992 regchan *rcp;
993
994 if (!rup)
995 return CMD_ERROR;
996
997 if (cargc<1) {
998 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "delchan");
999 return CMD_ERROR;
1000 }
1001
1002 if (!(cip=findchanindex(cargv[0])) || !(rcp=cip->exts[chanservext])) {
1003 chanservstdmessage(sender, QM_UNKNOWNCHAN, cargv[0]);
1004 return CMD_ERROR;
1005 }
1006
1007 cs_log(sender,"DELCHAN %s (%s)",cip->name->content,cargc>1?cargv[1]:"");
1008 cs_removechannel(rcp);
1009 chanservstdmessage(sender, QM_DONE);
1010
1011 return CMD_OK;
1012 }
1013
1014 int csc_doinvite(void *source, int cargc, char **cargv) {
1015 nick *sender=source;
1016 chanindex *cip;
1017
1018 if (cargc<1) {
1019 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "invite");
1020 return CMD_ERROR;
1021 }
1022
1023 if (!(cip=cs_checkaccess(sender, cargv[0], CA_KNOWN | CA_OFFCHAN,
1024 NULL, "invite", 0, 0)))
1025 return CMD_ERROR;
1026
1027 if (cip->channel) {
1028 localinvite(chanservnick, cip->channel, sender);
1029 }
1030 chanservstdmessage(sender, QM_DONE);
1031
1032 return CMD_OK;
1033 }
1034
1035 int csc_dosettopic(void *source, int cargc, char **cargv) {
1036 nick *sender=source;
1037 chanindex *cip;
1038 regchan *rcp;
1039
1040 if (cargc<1) {
1041 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "settopic");
1042 return CMD_ERROR;
1043 }
1044
1045 if (!(cip=cs_checkaccess(sender, cargv[0], CA_TOPICPRIV,
1046 NULL, "settopic", 0, 0)))
1047 return CMD_ERROR;
1048
1049 rcp=cip->exts[chanservext];
1050
1051 if (cargc>1) {
1052 if (rcp->topic)
1053 freesstring(rcp->topic);
1054 rcp->topic=getsstring(cargv[1],TOPICLEN);
1055 }
1056
1057 if (rcp->topic && cip->channel) {
1058 localsettopic(chanservnick, cip->channel, rcp->topic->content);
1059 }
1060
1061 chanservstdmessage(sender, QM_DONE);
1062 csdb_updatechannel(rcp);
1063 return CMD_OK;
1064 }
1065
1066 int csc_doop(void *source, int cargc, char **cargv) {
1067 nick *sender=source, *np;
1068 reguser *rup=getreguserfromnick(sender);
1069 chanindex *cip;
1070 regchan *rcp=NULL;
1071 regchanuser *rcup;
1072 channel **ca;
1073 unsigned long *lp;
1074 int i;
1075 modechanges changes;
1076
1077 if (!rup)
1078 return CMD_ERROR;
1079
1080 if (cargc==0) {
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)) &
1087 CUMODE_OP)) {
1088 /* They're not opped */
1089 if ((rcup=findreguseronchannel(rcp, rup)) && CUHasOpPriv(rcup) &&
1090 !CUIsDeny(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);
1095 }
1096 }
1097 }
1098 }
1099
1100 chanservstdmessage(sender, QM_DONE);
1101 return CMD_OK;
1102 }
1103
1104 /* If there is at least one arg, the first is a channel */
1105
1106 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV, NULL, "op", 0, 0)))
1107 return CMD_ERROR;
1108
1109 rcp=cip->exts[chanservext];
1110
1111 if (cargc==1) {
1112 /* Only one arg: "op me" */
1113 if (!cs_checkaccess(sender, NULL, CA_OPPRIV | CA_DEOPPED, cip, "op", 0, 0))
1114 return CMD_ERROR;
1115
1116 localsetmodeinit(&changes, cip->channel, chanservnick);
1117 localdosetmode_nick(&changes, sender, MC_OP);
1118 localsetmodeflush(&changes,1);
1119
1120 chanservstdmessage(sender, QM_DONE);
1121 return CMD_OK;
1122 }
1123
1124 /* Set up the modes */
1125 localsetmodeinit(&changes, cip->channel, chanservnick);
1126
1127 for(i=1;i<cargc;i++) {
1128 if (!(np=getnickbynick(cargv[i]))) {
1129 chanservstdmessage(sender, QM_UNKNOWNUSER, cargv[i]);
1130 continue;
1131 }
1132
1133 if (!(lp=getnumerichandlefromchanhash(cip->channel->users, np->numeric))) {
1134 chanservstdmessage(sender, QM_USERNOTONCHAN, np->nick, cip->name->content);
1135 continue;
1136 }
1137
1138 if (*lp & CUMODE_OP) {
1139 chanservstdmessage(sender, QM_USEROPPEDONCHAN, np->nick, cip->name->content);
1140 continue;
1141 }
1142
1143 rup=getreguserfromnick(np);
1144 if (rup)
1145 rcup=findreguseronchannel(rcp,rup);
1146 else
1147 rcup=NULL;
1148
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);
1152 continue;
1153 }
1154
1155 localdosetmode_nick(&changes, np, MC_OP);
1156 }
1157
1158 localsetmodeflush(&changes, 1);
1159 chanservstdmessage(sender, QM_DONE);
1160
1161 return CMD_OK;
1162 }
1163
1164 int csc_dovoice(void *source, int cargc, char **cargv) {
1165 nick *sender=source, *np;
1166 reguser *rup=getreguserfromnick(sender);
1167 chanindex *cip;
1168 regchan *rcp=NULL;
1169 regchanuser *rcup;
1170 channel **ca;
1171 unsigned long *lp;
1172 int i;
1173 modechanges changes;
1174
1175 if (!rup)
1176 return CMD_ERROR;
1177
1178 if (cargc==0) {
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):
1192 * voice them */
1193 localsetmodeinit(&changes, ca[i], chanservnick);
1194 localdosetmode_nick(&changes, sender, MC_VOICE);
1195 localsetmodeflush(&changes,1);
1196 }
1197 }
1198 }
1199 }
1200
1201 chanservstdmessage(sender, QM_DONE);
1202 return CMD_OK;
1203 }
1204
1205 /* If there is at least one arg, the first is a channel */
1206
1207 if (!(cip=cs_checkaccess(sender, cargv[0], CA_VOICEPRIV, NULL, "voice", 0, 0)))
1208 return CMD_ERROR;
1209
1210 if (cargc==1) {
1211 /* Only one arg: "voice me" */
1212 if (!cs_checkaccess(sender, NULL, CA_VOICEPRIV | CA_DEVOICED, cip,
1213 "voice", 0, 0))
1214 return CMD_ERROR;
1215
1216 localsetmodeinit(&changes, cip->channel, chanservnick);
1217 localdosetmode_nick(&changes, sender, MC_VOICE);
1218 localsetmodeflush(&changes,1);
1219
1220 chanservstdmessage(sender, QM_DONE);
1221 return CMD_OK;
1222 }
1223
1224 if (!(cip=cs_checkaccess(sender, NULL, CA_OPPRIV, cip, "voice", 0, 0)))
1225 return CMD_ERROR;
1226
1227 rcp=cip->exts[chanservext];
1228
1229 /* Set up the modes */
1230 localsetmodeinit(&changes, cip->channel, chanservnick);
1231
1232 for(i=1;i<cargc;i++) {
1233 if (!(np=getnickbynick(cargv[i]))) {
1234 chanservstdmessage(sender, QM_UNKNOWNUSER, cargv[i]);
1235 continue;
1236 }
1237
1238 if (!(lp=getnumerichandlefromchanhash(cip->channel->users, np->numeric))) {
1239 chanservstdmessage(sender, QM_USERNOTONCHAN, np->nick, cip->name->content);
1240 continue;
1241 }
1242
1243 if (*lp & CUMODE_VOICE) {
1244 chanservstdmessage(sender, QM_USERVOICEDONCHAN, np->nick, cip->name->content);
1245 continue;
1246 }
1247
1248 if ((rup=getreguserfromnick(np)) && (rcup=findreguseronchannel(rcp, rup)) && CUIsQuiet(rcup)) {
1249 chanservstdmessage(sender, QM_CANTVOICE, np->nick, cip->name->content);
1250 continue;
1251 }
1252
1253 localdosetmode_nick(&changes, np, MC_VOICE);
1254 }
1255
1256 localsetmodeflush(&changes, 1);
1257 chanservstdmessage(sender, QM_DONE);
1258
1259 return CMD_OK;
1260 }
1261
1262 int csc_dodeopall(void *source, int cargc, char **cargv) {
1263 nick *sender=source,*np;
1264 reguser *rup;
1265 regchanuser *rcup;
1266 regchan *rcp;
1267 chanindex *cip;
1268 unsigned long *lp;
1269 int i;
1270 modechanges changes;
1271
1272 if (cargc<1) {
1273 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "deopall");
1274 return CMD_ERROR;
1275 }
1276
1277 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "deopall",0, 0)))
1278 return CMD_ERROR;
1279
1280 rcp=cip->exts[chanservext];
1281
1282 if (cip->channel) {
1283 localsetmodeinit(&changes, cip->channel, chanservnick);
1284
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);
1293 }
1294 }
1295 }
1296
1297 localsetmodeflush(&changes, 1);
1298 }
1299
1300 cs_log(sender,"DEOPALL %s",cip->name->content);
1301 chanservstdmessage(sender, QM_DONE);
1302 return CMD_OK;
1303 }
1304
1305 int csc_dodevoiceall(void *source, int cargc, char **cargv) {
1306 nick *sender=source,*np;
1307 reguser *rup;
1308 regchanuser *rcup;
1309 regchan *rcp;
1310 chanindex *cip;
1311 unsigned long *lp;
1312 int i;
1313 modechanges changes;
1314
1315 if (cargc<1) {
1316 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "devoiceall");
1317 return CMD_ERROR;
1318 }
1319
1320 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "devoiceall",0, 0)))
1321 return CMD_ERROR;
1322
1323 rcp=cip->exts[chanservext];
1324
1325 if (cip->channel) {
1326 localsetmodeinit(&changes, cip->channel, chanservnick);
1327
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);
1336 }
1337 }
1338 }
1339
1340 localsetmodeflush(&changes, 1);
1341 }
1342
1343 cs_log(sender,"DEVOICEALL %s",cip->name->content);
1344 chanservstdmessage(sender, QM_DONE);
1345 return CMD_OK;
1346 }
1347
1348 int csc_dounbanall(void *source, int cargc, char **cargv) {
1349 nick *sender=source;
1350 regchan *rcp;
1351 chanindex *cip;
1352 modechanges changes;
1353
1354 if (cargc<1) {
1355 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "unbanall");
1356 return CMD_ERROR;
1357 }
1358
1359 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "unbanall",0, 0)))
1360 return CMD_ERROR;
1361
1362 rcp=cip->exts[chanservext];
1363
1364 if (cip->channel) {
1365 localsetmodeinit(&changes, cip->channel, chanservnick);
1366
1367 while (cip->channel->bans) {
1368 localdosetmode_ban(&changes, bantostring(cip->channel->bans), MCB_DEL);
1369 }
1370
1371 localsetmodeflush(&changes, 1);
1372 }
1373
1374 cs_log(sender,"UNBANALL %s",cip->name->content);
1375 chanservstdmessage(sender, QM_DONE);
1376 return CMD_OK;
1377 }
1378
1379 int csc_dounbanme(void *source, int cargc, char **cargv) {
1380 nick *sender=source;
1381 regchan *rcp;
1382 chanindex *cip;
1383 modechanges changes;
1384 chanban **cbh;
1385
1386 if (cargc<1) {
1387 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "unbanme");
1388 return CMD_ERROR;
1389 }
1390
1391 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV, NULL, "unbanme", 0, 0)))
1392 return CMD_ERROR;
1393
1394 rcp=cip->exts[chanservext];
1395
1396 if (cip->channel) {
1397 localsetmodeinit(&changes, cip->channel, chanservnick);
1398
1399 for (cbh=&(cip->channel->bans);*cbh;) {
1400 if (nickmatchban(sender, *cbh))
1401 localdosetmode_ban(&changes, bantostring(*cbh), MCB_DEL);
1402 else
1403 cbh=&((*cbh)->next);
1404 }
1405
1406 localsetmodeflush(&changes, 1);
1407 }
1408
1409 cs_log(sender,"UNBANME %s",cip->name->content);
1410 chanservstdmessage(sender, QM_DONE);
1411 return CMD_OK;
1412 }
1413
1414 int csc_doclearchan(void *source, int cargc, char **cargv) {
1415 nick *sender=source;
1416 regchan *rcp;
1417 chanindex *cip;
1418 modechanges changes;
1419
1420 if (cargc<1) {
1421 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "clearchan");
1422 return CMD_ERROR;
1423 }
1424
1425 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "clearchan",0, 0)))
1426 return CMD_ERROR;
1427
1428 rcp=cip->exts[chanservext];
1429
1430 if (cip->channel) {
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);
1436 }
1437
1438 cs_log(sender,"CLEARCHAN %s",cip->name->content);
1439 chanservstdmessage(sender, QM_DONE);
1440 return CMD_OK;
1441 }
1442
1443 int csc_dorecover(void *source, int cargc, char **cargv) {
1444 nick *sender=source,*np;
1445 reguser *rup;
1446 regchanuser *rcup;
1447 regchan *rcp;
1448 chanindex *cip;
1449 unsigned long *lp;
1450 int i;
1451 modechanges changes;
1452
1453 if (cargc<1) {
1454 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "recover");
1455 return CMD_ERROR;
1456 }
1457
1458 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "recover",0, 0)))
1459 return CMD_ERROR;
1460
1461 rcp=cip->exts[chanservext];
1462
1463 if (cip->channel) {
1464 localsetmodeinit(&changes, cip->channel, chanservnick);
1465
1466 /* clearchan */
1467 localdosetmode_key(&changes, NULL, MCB_DEL);
1468 localdosetmode_simple(&changes, 0, cip->channel->flags);
1469 cs_docheckchanmodes(cip->channel, &changes);
1470
1471 /* unbanall */
1472 while (cip->channel->bans) {
1473 localdosetmode_ban(&changes, bantostring(cip->channel->bans), MCB_DEL);
1474 }
1475
1476 /* deopall */
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);
1485 }
1486 }
1487 }
1488
1489 localsetmodeflush(&changes, 1);
1490 }
1491
1492 cs_log(sender,"RECOVER %s",cip->name->content);
1493 chanservstdmessage(sender, QM_DONE);
1494 return CMD_OK;
1495 }
1496
1497 int csc_dopermban(void *source, int cargc, char **cargv) {
1498 nick *sender=source;
1499 chanindex *cip;
1500 regban *rbp;
1501 regchan *rcp;
1502 reguser *rup=getreguserfromnick(sender);
1503
1504 if (cargc<2) {
1505 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "permban");
1506 return CMD_ERROR;
1507 }
1508
1509 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "permban",0, 0)))
1510 return CMD_ERROR;
1511
1512 rcp=cip->exts[chanservext];
1513
1514 rbp=getregban();
1515 rbp->ID=++lastbanID;
1516 rbp->cbp=makeban(cargv[1]);
1517 rbp->setby=rup->ID;
1518 rbp->expiry=0;
1519 if (cargc>2)
1520 rbp->reason=getsstring(cargv[2],200);
1521 else
1522 rbp->reason=NULL;
1523 rbp->next=rcp->bans;
1524 rcp->bans=rbp;
1525
1526 cs_setregban(cip, rbp);
1527 csdb_createban(rcp, rbp);
1528
1529 chanservstdmessage(sender, QM_DONE);
1530 return CMD_OK;
1531 }
1532
1533 int csc_dotempban(void *source, int cargc, char **cargv) {
1534 nick *sender=source;
1535 chanindex *cip;
1536 regban *rbp;
1537 regchan *rcp;
1538 reguser *rup=getreguserfromnick(sender);
1539 unsigned int duration;
1540
1541 if (cargc<3) {
1542 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "tempban");
1543 return CMD_ERROR;
1544 }
1545
1546 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "tempban",0, 0)))
1547 return CMD_ERROR;
1548
1549 rcp=cip->exts[chanservext];
1550
1551 duration=durationtolong(cargv[2]);
1552
1553 rbp=getregban();
1554 rbp->ID=++lastbanID;
1555 rbp->cbp=makeban(cargv[1]);
1556 rbp->setby=rup->ID;
1557 rbp->expiry=time(NULL)+duration;
1558 if (cargc>3)
1559 rbp->reason=getsstring(cargv[3],200);
1560 else
1561 rbp->reason=NULL;
1562 rbp->next=rcp->bans;
1563 rcp->bans=rbp;
1564
1565 cs_setregban(cip, rbp);
1566 csdb_createban(rcp, rbp);
1567
1568 chanservstdmessage(sender, QM_DONE);
1569 return CMD_OK;
1570 }
1571
1572 int csc_dobanlist(void *source, int cargc, char **cargv) {
1573 nick *sender=source;
1574 chanindex *cip;
1575 regchan *rcp;
1576 regban *rbp;
1577 reguser *rup;
1578 chanban *cbp;
1579 int i=0;
1580 int exp;
1581
1582 if (cargc<1) {
1583 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "banlist");
1584 return CMD_ERROR;
1585 }
1586
1587 if(!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV, NULL, "banlist", 0, 0)))
1588 return CMD_ERROR;
1589
1590 rcp=cip->exts[chanservext];
1591
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:"");
1600 }
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))
1604 break;
1605 }
1606 if (!rbp) {
1607 if (rcp->banduration) {
1608 exp=(cbp->timeset + rcp->banduration) - time(NULL);
1609 } else {
1610 exp=0;
1611 }
1612 chanservsendmessage(sender, " #%-2d %-29s %-18s %-15s",++i,bantostring(cbp),
1613 exp ? longtoduration(exp,0) : "Permanent",
1614 "(channel ban)");
1615 }
1616 }
1617 chanservstdmessage(sender, QM_ENDOFLIST);
1618 } else {
1619 chanservstdmessage(sender, QM_NOBANS, cip->name->content);
1620 }
1621
1622 return CMD_OK;
1623 }
1624
1625 int csc_dobandel(void *source, int cargc, char **cargv) {
1626 nick *sender=source;
1627 chanindex *cip;
1628 regban **rbh, *rbp;
1629 chanban *cbp;
1630 regchan *rcp;
1631 chanban *theban=NULL;
1632 modechanges changes;
1633 int i,banid=0;
1634
1635 if (cargc<2) {
1636 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "unban");
1637 return CMD_ERROR;
1638 }
1639
1640 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV, NULL, "unban", 0, 0)))
1641 return CMD_ERROR;
1642
1643 rcp=cip->exts[chanservext];
1644
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);
1650 return CMD_ERROR;
1651 }
1652 } else {
1653 /* Remove by ban string */
1654 theban=makeban(cargv[1]);
1655 }
1656
1657 i=0;
1658 for (rbh=&(rcp->bans);*rbh;rbh=&((*rbh)->next)) {
1659 i++;
1660 if ((banid && i==banid) ||
1661 (theban && banequal(theban, (*rbh)->cbp))) {
1662 /* got it - they will need master access to remove this */
1663 rbp=*rbh;
1664
1665 if (!cs_checkaccess(sender, NULL, CA_MASTERPRIV, cip, "unban", 0, 0))
1666 return CMD_ERROR;
1667
1668 chanservstdmessage(sender, QM_REMOVEDPERMBAN, bantostring(rbp->cbp), cip->name->content);
1669 if (cip->channel) {
1670 localsetmodeinit(&changes, cip->channel, chanservnick);
1671 localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_DEL);
1672 localsetmodeflush(&changes, 1);
1673 }
1674
1675 /* Remove from database */
1676 csdb_deleteban(rbp);
1677 /* Remove from list */
1678 (*rbh)=rbp->next;
1679 /* Free ban/string and actual regban */
1680 freesstring(rbp->reason);
1681 freechanban(rbp->cbp);
1682 freeregban(rbp);
1683
1684 if (theban)
1685 freechanban(theban);
1686
1687 return CMD_OK;
1688 }
1689 }
1690
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))
1696 break;
1697 }
1698
1699 if (rbp)
1700 continue;
1701
1702 i++;
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);
1710
1711 if (theban)
1712 freechanban(theban);
1713
1714 return CMD_OK;
1715 }
1716 }
1717 }
1718
1719 chanservstdmessage(sender, QM_UNKNOWNBAN, cargv[1], cip->name->content);
1720
1721 return CMD_OK;
1722 }
1723
1724 int csc_dobanclear(void *source, int cargc, char **cargv) {
1725 nick *sender=source;
1726 chanindex *cip;
1727 regban **rbh, *rbp;
1728 chanban **cbh, *cbp;
1729 regchan *rcp;
1730 modechanges changes;
1731 char *banstr;
1732
1733 if (cargc<1) {
1734 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "banclear");
1735 return CMD_ERROR;
1736 }
1737
1738 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "banclear", 0, 0)))
1739 return CMD_ERROR;
1740
1741 rcp=cip->exts[chanservext];
1742
1743 if (cip->channel)
1744 localsetmodeinit(&changes, cip->channel, chanservnick);
1745
1746 for (rbh=&(rcp->bans); *rbh; ) {
1747 rbp=*rbh;
1748 banstr=bantostring(rbp->cbp);
1749 chanservstdmessage(sender, QM_REMOVEDPERMBAN, banstr, cip->name->content);
1750 if (cip->channel)
1751 localdosetmode_ban(&changes, banstr, MCB_DEL);
1752 /* Remove from database */
1753 csdb_deleteban(rbp);
1754 /* Remove from list */
1755 (*rbh)=rbp->next;
1756 /* Free ban/string and update setby refcount, and free actual regban */
1757 freesstring(rbp->reason);
1758 freechanban(rbp->cbp);
1759 freeregban(rbp);
1760 }
1761
1762 if (cip->channel) {
1763 for (cbh=&(cip->channel->bans); *cbh; ) {
1764 cbp=*cbh;
1765 banstr=bantostring(cbp);
1766 chanservstdmessage(sender, QM_REMOVEDCHANBAN, banstr, cip->name->content);
1767 localdosetmode_ban(&changes, banstr, MCB_DEL);
1768 }
1769 localsetmodeflush(&changes,1);
1770 }
1771
1772 chanservstdmessage(sender, QM_DONE);
1773 return CMD_OK;
1774 }
1775
1776 int csc_dounbanmask(void *source, int cargc, char **cargv) {
1777 nick *sender=source;
1778 chanindex *cip;
1779 regban **rbh, *rbp;
1780 chanban **cbh, *cbp;
1781 regchan *rcp;
1782 chanban *theban;
1783 modechanges changes;
1784 char *banstr;
1785
1786 if (cargc<2) {
1787 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "unbanmask");
1788 return CMD_ERROR;
1789 }
1790
1791 if (!(cip=cs_checkaccess(sender, cargv[0], CA_OPPRIV, NULL, "unbanmask", 0, 0)))
1792 return CMD_ERROR;
1793
1794 rcp=cip->exts[chanservext];
1795 theban=makeban(cargv[1]);
1796
1797 if (cip->channel)
1798 localsetmodeinit(&changes, cip->channel, chanservnick);
1799
1800 for (rbh=&(rcp->bans); *rbh; ) {
1801 rbp=*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);
1807 rbh=&(rbp->next);
1808 } else {
1809 chanservstdmessage(sender, QM_REMOVEDPERMBAN, banstr, cip->name->content);
1810 if (cip->channel)
1811 localdosetmode_ban(&changes, banstr, MCB_DEL);
1812 /* Remove from database */
1813 csdb_deleteban(rbp);
1814 /* Remove from list */
1815 (*rbh)=rbp->next;
1816 /* Free ban/string and update setby refcount, and free actual regban */
1817 freesstring(rbp->reason);
1818 freechanban(rbp->cbp);
1819 freeregban(rbp);
1820 }
1821 } else {
1822 rbh=&(rbp->next);
1823 }
1824 }
1825
1826 if (cip->channel) {
1827 for (cbh=&(cip->channel->bans); *cbh; ) {
1828 cbp=*cbh;
1829 if (banoverlap(theban, cbp)) {
1830 /* Remove */
1831 banstr=bantostring(cbp);
1832 chanservstdmessage(sender, QM_REMOVEDCHANBAN, banstr, cip->name->content);
1833 localdosetmode_ban(&changes, banstr, MCB_DEL);
1834 } else {
1835 cbh=&(cbp->next);
1836 }
1837 }
1838 localsetmodeflush(&changes,1);
1839 }
1840
1841
1842 chanservstdmessage(sender, QM_DONE);
1843 return CMD_OK;
1844 }
1845
1846 int csc_dorenchan(void *source, int cargc, char **cargv) {
1847 nick *sender=source;
1848 reguser *rup=getreguserfromnick(sender);
1849 chanindex *cip1,*cip2;
1850 regchan *rcp;
1851
1852 if (!rup)
1853 return CMD_ERROR;
1854
1855 if (cargc<2) {
1856 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "renchan");
1857 return CMD_ERROR;
1858 }
1859
1860 if (!(cip1=findchanindex(cargv[0])) || !(rcp=cip1->exts[chanservext])) {
1861 chanservstdmessage(sender, QM_UNKNOWNCHAN, cargv[0]);
1862 return CMD_ERROR;
1863 }
1864
1865 if (*cargv[1] != '#') {
1866 chanservstdmessage(sender, QM_INVALIDCHANNAME, cargv[0]);
1867 return CMD_ERROR;
1868 }
1869
1870 if (!(cip2=findorcreatechanindex(cargv[1])) || cip2->exts[chanservext]) {
1871 chanservstdmessage(sender, QM_ALREADYREGISTERED, cip2->name->content);
1872 return CMD_ERROR;
1873 }
1874
1875 cs_log(sender,"RENCHAN %s -> %s",cip1->name->content,cip2->name->content);
1876
1877 /* Remove from the channel. Don't bother if the channel doesn't exist. */
1878 if (!CIsSuspended(rcp) && cip1->channel) {
1879 CSetSuspended(rcp);
1880 chanservjoinchan(cip1->channel);
1881 CClearSuspended(rcp);
1882 }
1883
1884 cip1->exts[chanservext]=NULL;
1885 releasechanindex(cip1);
1886
1887 cip2->exts[chanservext]=rcp;
1888 rcp->index=cip2;
1889 if (cip2->channel) {
1890 chanservjoinchan(cip2->channel);
1891 }
1892
1893 csdb_updatechannel(rcp);
1894 chanservstdmessage(sender, QM_DONE);
1895
1896 return CMD_OK;
1897 }
1898
1899 int csc_dochannelcomment(void *source, int cargc, char **cargv) {
1900 nick *sender=source;
1901 reguser *rup=getreguserfromnick(sender);
1902 regchan *rcp;
1903 chanindex *cip;
1904 char buf[300];
1905 int bufpos;
1906
1907 if (!rup)
1908 return CMD_ERROR;
1909
1910 if (cargc<1) {
1911 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "channelcomment");
1912 return CMD_ERROR;
1913 }
1914
1915 if (!(cip=findchanindex(cargv[0])) || !(rcp=cip->exts[chanservext])) {
1916 chanservstdmessage(sender, QM_UNKNOWNCHAN, cargv[0]);
1917 return CMD_ERROR;
1918 }
1919
1920 if (cargc>1) {
1921 if (!ircd_strcmp(cargv[1],"none")) {
1922 freesstring(rcp->comment);
1923 rcp->comment=NULL;
1924 } else {
1925 if (*cargv[1]=='+') {
1926 if (rcp->comment) {
1927 strcpy(buf,rcp->comment->content);
1928 bufpos=rcp->comment->length;
1929 buf[bufpos++]=' ';
1930 } else {
1931 bufpos=0;
1932 }
1933 strncpy(buf+bufpos, cargv[1]+1, 250-bufpos);
1934 } else {
1935 strncpy(buf, cargv[1], 250);
1936 }
1937
1938 freesstring(rcp->comment);
1939 rcp->comment=getsstring(buf,250);
1940 }
1941 csdb_updatechannel(rcp);
1942 }
1943
1944 if (rcp->comment)
1945 chanservstdmessage(sender, QM_COMMENT, cip->name->content, rcp->comment->content);
1946 else
1947 chanservstdmessage(sender, QM_NOCOMMENT, cip->name->content);
1948
1949 return CMD_OK;
1950 }
1951
1952 int csc_dorejoin(void *source, int cargc, char **cargv) {
1953 nick *sender=source;
1954 chanindex *cip;
1955 regchan *rcp;
1956
1957 if (cargc<1) {
1958 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "rejoin");
1959 return CMD_ERROR;
1960 }
1961
1962 if (!(cip=findchanindex(cargv[0])) || !(rcp=cip->exts[chanservext])) {
1963 chanservstdmessage(sender, QM_UNKNOWNCHAN, cargv[0]);
1964 return CMD_ERROR;
1965 }
1966
1967 if (CIsJoined(rcp) && !CIsSuspended(rcp)) {
1968 CSetSuspended(rcp);
1969 chanservjoinchan(cip->channel);
1970 CClearSuspended(rcp);
1971 chanservjoinchan(cip->channel);
1972 }
1973
1974 chanservstdmessage(sender, QM_DONE);
1975
1976 return CMD_OK;
1977 }
1978
1979 int csc_dochantype(void *source, int cargc, char **cargv) {
1980 nick *sender=source;
1981 chanindex *cip;
1982 regchan *rcp;
1983 int type;
1984
1985 if (cargc<1) {
1986 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "chantype");
1987 return CMD_ERROR;
1988 }
1989
1990 if (!(cip=findchanindex(cargv[0])) || !(rcp=cip->exts[chanservext])) {
1991 chanservstdmessage(sender, QM_UNKNOWNCHAN, cargv[0]);
1992 return CMD_ERROR;
1993 }
1994
1995 if (cargc>1) {
1996 /* Set type */
1997 for (type=CHANTYPES-1;type;type--) {
1998 if (!ircd_strcmp(chantypes[type]->content, cargv[1]))
1999 break;
2000 }
2001 if (!type) {
2002 chanservstdmessage(sender, QM_UNKNOWNCHANTYPE, cargv[1]);
2003 return CMD_ERROR;
2004 }
2005 rcp->chantype=type;
2006
2007 csdb_updatechannel(rcp);
2008 chanservstdmessage(sender, QM_DONE);
2009 }
2010
2011 chanservstdmessage(sender, QM_CHANTYPEIS, cip->name->content, chantypes[rcp->chantype]->content);
2012
2013 return CMD_OK;
2014 }
2015
2016 int csc_doadduser(void *source, int cargc, char **cargv) {
2017 nick *sender=source;
2018 chanindex *cip;
2019 regchanuser *rcup;
2020 regchan *rcp;
2021 reguser *rup;
2022 int i;
2023
2024 if (cargc<2) {
2025 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "adduser");
2026 return CMD_ERROR;
2027 }
2028
2029 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "adduser", QPRIV_CHANGECHANLEV, 0)))
2030 return CMD_ERROR;
2031
2032 rcp=cip->exts[chanservext];
2033
2034 for (i=1;i<cargc;i++) {
2035 if (!(rup=findreguser(sender, cargv[i])))
2036 continue;
2037
2038 if ((rcup=findreguseronchannel(rcp, rup))) {
2039 chanservstdmessage(sender, QM_ALREADYKNOWNONCHAN, cargv[i], cip->name->content);
2040 continue;
2041 }
2042
2043 rcup=getregchanuser();
2044 rcup->chan=rcp;
2045 rcup->user=rup;
2046 rcup->flags = QCUFLAG_OP | QCUFLAG_AUTOOP | QCUFLAG_TOPIC;
2047 rcup->changetime=time(NULL);
2048 rcup->usetime=0;
2049 rcup->info=NULL;
2050
2051 cs_log(sender,"CHANLEV %s #%s +aot (+ -> +aot)",cip->name->content,rup->username);
2052 addregusertochannel(rcup);
2053 csdb_createchanuser(rcup);
2054 }
2055
2056 rcp->status |= QCSTAT_OPCHECK;
2057 cs_timerfunc(cip);
2058
2059 chanservstdmessage(sender, QM_DONE);
2060
2061 return CMD_OK;
2062 }
2063
2064 int csc_doremoveuser(void *source, int cargc, char **cargv) {
2065 nick *sender=source;
2066 chanindex *cip;
2067 regchanuser *rcup;
2068 regchan *rcp;
2069 reguser *rup;
2070 int isowner=0;
2071 int i;
2072
2073 if (cargc<2) {
2074 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "removeuser");
2075 return CMD_ERROR;
2076 }
2077
2078 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV, NULL, "adduser", QPRIV_CHANGECHANLEV, 0)))
2079 return CMD_ERROR;
2080
2081 if (cs_checkaccess(sender, NULL, CA_OWNERPRIV, cip, "adduser", QPRIV_CHANGECHANLEV, 1))
2082 isowner=1;
2083
2084 rcp=cip->exts[chanservext];
2085
2086 for (i=1;i<cargc;i++) {
2087 if (!(rup=findreguser(sender, cargv[i])))
2088 continue;
2089
2090 if (!(rcup=findreguseronchannel(rcp, rup))) {
2091 chanservstdmessage(sender, QM_CHANUSERUNKNOWN, cargv[i], cip->name->content);
2092 continue;
2093 }
2094
2095 if (CUIsOwner(rcup)) {
2096 chanservstdmessage(sender, QM_CANNOTREMOVEOWNER, cargv[i], cip->name->content);
2097 continue;
2098 }
2099
2100 if (CUIsMaster(rcup) && !isowner && (rup != getreguserfromnick(sender))) {
2101 chanservstdmessage(sender, QM_CANNOTREMOVEMASTER, cargv[i], cip->name->content);
2102 continue;
2103 }
2104
2105 cs_log(sender,"CHANLEV %s #%s -%s (%s -> +)",cip->name->content,rup->username,
2106 printflags_noprefix(rcup->flags, rcuflags), printflags(rcup->flags, rcuflags));
2107
2108 csdb_deletechanuser(rcup);
2109 delreguserfromchannel(rcp, rup);
2110 }
2111
2112 rcp->status |= QCSTAT_OPCHECK;
2113 cs_timerfunc(cip);
2114
2115 chanservstdmessage(sender, QM_DONE);
2116
2117 return CMD_OK;
2118 }
2119
2120 int csc_dochanstat(void *source, int cargc, char **cargv) {
2121 nick *sender=source;
2122 chanindex *cip;
2123 regchan *rcp;
2124 char timebuf[30];
2125
2126 if (cargc<1) {
2127 chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "chanstat");
2128 return CMD_ERROR;
2129 }
2130
2131 if (!(cip=cs_checkaccess(sender, cargv[0], CA_MASTERPRIV,
2132 NULL, "chanstat", QPRIV_VIEWFULLCHANLEV, 0)))
2133 return CMD_ERROR;
2134
2135 rcp=cip->exts[chanservext];
2136
2137 chanservstdmessage(sender, QM_STATSHEADER, cip->name->content);
2138
2139 strftime(timebuf, 30, "%d/%m/%y %H:%M", localtime(&(rcp->created)));
2140 chanservstdmessage(sender, QM_STATSADDED, timebuf);
2141
2142 /* Show opers founder/addedby/type info */
2143 if (cs_privcheck(QPRIV_VIEWFULLCHANLEV, sender)) {
2144 reguser *founder=NULL, *addedby=NULL;
2145
2146 strftime(timebuf, 30, "%d/%m/%y %H:%M", localtime(&(rcp->lastactive)));
2147 chanservstdmessage(sender, QM_STATSLASTACTIVE, timebuf);
2148
2149
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);
2155 }
2156
2157 strftime(timebuf, 30, "%d/%m/%y %H:%M", localtime(&(rcp->created)));
2158
2159 chanservstdmessage(sender, QM_STATSJOINS, timebuf, rcp->maxusers, rcp->totaljoins,
2160 (float)rcp->totaljoins/ ((time(NULL)-rcp->created)/(3600*24)));
2161
2162 strftime(timebuf, 30, "%d/%m/%y %H:%M", localtime(&(rcp->statsreset)));
2163
2164 chanservstdmessage(sender, QM_STATSJOINS, timebuf, rcp->tripusers, rcp->tripjoins,
2165 (float)rcp->tripjoins / ((time(NULL)-rcp->statsreset)/(3600*24)));
2166
2167 return CMD_OK;
2168 }