anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

channels.cpp (23936B)

      1 /* Channel-handling routines.
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "services.h"
     13 #include "channels.h"
     14 #include "regchannel.h"
     15 #include "logger.h"
     16 #include "modules.h"
     17 #include "users.h"
     18 #include "bots.h"
     19 #include "servers.h"
     20 #include "protocol.h"
     21 #include "users.h"
     22 #include "config.h"
     23 #include "access.h"
     24 #include "sockets.h"
     25 #include "language.h"
     26 #include "uplink.h"
     27 
     28 channel_map ChannelList;
     29 std::vector<Channel *> Channel::deleting;
     30 
     31 Channel::Channel(const Anope::string &nname, time_t ts)
     32 {
     33 	if (nname.empty())
     34 		throw CoreException("A channel without a name ?");
     35 
     36 	this->name = nname;
     37 
     38 	this->creation_time = ts;
     39 	this->syncing = this->botchannel = false;
     40 	this->server_modetime = this->chanserv_modetime = 0;
     41 	this->server_modecount = this->chanserv_modecount = this->bouncy_modes = this->topic_ts = this->topic_time = 0;
     42 
     43 	this->ci = ChannelInfo::Find(this->name);
     44 	if (this->ci)
     45 		this->ci->c = this;
     46 
     47 	if (Me && Me->IsSynced())
     48 		Log(NULL, this, "create");
     49 
     50 	FOREACH_MOD(OnChannelCreate, (this));
     51 }
     52 
     53 Channel::~Channel()
     54 {
     55 	UnsetExtensibles();
     56 
     57 	FOREACH_MOD(OnChannelDelete, (this));
     58 
     59 	ModeManager::StackerDel(this);
     60 
     61 	if (Me && Me->IsSynced())
     62 		Log(NULL, this, "destroy");
     63 
     64 	if (this->ci)
     65 		this->ci->c = NULL;
     66 
     67 	ChannelList.erase(this->name);
     68 }
     69 
     70 void Channel::Reset()
     71 {
     72 	this->modes.clear();
     73 
     74 	for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it)
     75 	{
     76 		ChanUserContainer *uc = it->second;
     77 
     78 		ChannelStatus f = uc->status;
     79 		uc->status.Clear();
     80 
     81 		/* reset modes for my clients */
     82 		if (uc->user->server == Me)
     83 		{
     84 			for (size_t i = 0; i < f.Modes().length(); ++i)
     85 				this->SetMode(NULL, ModeManager::FindChannelModeByChar(f.Modes()[i]), uc->user->GetUID(), false);
     86 			/* Modes might not exist yet, so be sure the status is really reset */
     87 			uc->status = f;
     88 		}
     89 	}
     90 
     91 	for (ChanUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it)
     92 		this->SetCorrectModes(it->second->user, true);
     93 
     94 	// If the channel is syncing now, do not force a sync due to Reset(), as we are probably iterating over users in Message::SJoin
     95 	// A sync will come soon
     96 	if (!syncing)
     97 		this->Sync();
     98 }
     99 
    100 void Channel::Sync()
    101 {
    102 	syncing = false;
    103 	FOREACH_MOD(OnChannelSync, (this));
    104 	CheckModes();
    105 }
    106 
    107 void Channel::CheckModes()
    108 {
    109 	if (this->bouncy_modes || this->syncing)
    110 		return;
    111 
    112 	/* Check for mode bouncing */
    113 	if (this->chanserv_modetime == Anope::CurTime && this->server_modetime == Anope::CurTime && this->server_modecount >= 3 && this->chanserv_modecount >= 3)
    114 	{
    115 		Log() << "Warning: unable to set modes on channel " << this->name << ". Are your servers' U:lines configured correctly?";
    116 		this->bouncy_modes = 1;
    117 		return;
    118 	}
    119 
    120 	Reference<Channel> ref = this;
    121 	FOREACH_MOD(OnCheckModes, (ref));
    122 }
    123 
    124 bool Channel::CheckDelete()
    125 {
    126 	/* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediately
    127 	 * We also don't part the bot here either, if necessary we will part it after the sync
    128 	 */
    129 	if (this->syncing)
    130 		return false;
    131 
    132 	/* Permanent channels never get deleted */
    133 	if (this->HasMode("PERM"))
    134 		return false;
    135 
    136 	EventReturn MOD_RESULT;
    137 	FOREACH_RESULT(OnCheckDelete, MOD_RESULT, (this));
    138 
    139 	return MOD_RESULT != EVENT_STOP && this->users.empty();
    140 }
    141 
    142 ChanUserContainer* Channel::JoinUser(User *user, const ChannelStatus *status)
    143 {
    144 	if (user->server && user->server->IsSynced())
    145 		Log(user, this, "join");
    146 
    147 	ChanUserContainer *cuc = new ChanUserContainer(user, this);
    148 	user->chans[this] = cuc;
    149 	this->users[user] = cuc;
    150 	if (status)
    151 		cuc->status = *status;
    152 
    153 	return cuc;
    154 }
    155 
    156 void Channel::DeleteUser(User *user)
    157 {
    158 	if (user->server && user->server->IsSynced() && !user->Quitting())
    159 		Log(user, this, "leave");
    160 
    161 	FOREACH_MOD(OnLeaveChannel, (user, this));
    162 
    163 	ChanUserContainer *cu = user->FindChannel(this);
    164 	if (!this->users.erase(user))
    165 		Log(LOG_DEBUG) << "Channel::DeleteUser() tried to delete nonexistent user " << user->nick << " from channel " << this->name;
    166 
    167 	if (!user->chans.erase(this))
    168 		Log(LOG_DEBUG) << "Channel::DeleteUser() tried to delete nonexistent channel " << this->name << " from " << user->nick << "'s channel list";
    169 	delete cu;
    170 
    171 	QueueForDeletion();
    172 }
    173 
    174 ChanUserContainer *Channel::FindUser(User *u) const
    175 {
    176 	ChanUserList::const_iterator it = this->users.find(u);
    177 	if (it != this->users.end())
    178 		return it->second;
    179 	return NULL;
    180 }
    181 
    182 bool Channel::HasUserStatus(User *u, ChannelModeStatus *cms)
    183 {
    184 	/* Usually its more efficient to search the users channels than the channels users */
    185 	ChanUserContainer *cc = u->FindChannel(this);
    186 	if (cc)
    187 	{
    188 		if (cms)
    189 			return cc->status.HasMode(cms->mchar);
    190 		else
    191 			return cc->status.Empty();
    192 	}
    193 
    194 	return false;
    195 }
    196 
    197 bool Channel::HasUserStatus(User *u, const Anope::string &mname)
    198 {
    199 	return HasUserStatus(u, anope_dynamic_static_cast<ChannelModeStatus *>(ModeManager::FindChannelModeByName(mname)));
    200 }
    201 
    202 size_t Channel::HasMode(const Anope::string &mname, const Anope::string &param)
    203 {
    204 	if (param.empty())
    205 		return modes.count(mname);
    206 	std::vector<Anope::string> v = this->GetModeList(mname);
    207 	for (unsigned int i = 0; i < v.size(); ++i)
    208 		if (v[i].equals_ci(param))
    209 			return 1;
    210 	return 0;
    211 }
    212 
    213 Anope::string Channel::GetModes(bool complete, bool plus)
    214 {
    215 	Anope::string res, params;
    216 
    217 	for (std::multimap<Anope::string, Anope::string>::const_iterator it = this->modes.begin(), it_end = this->modes.end(); it != it_end; ++it)
    218 	{
    219 		ChannelMode *cm = ModeManager::FindChannelModeByName(it->first);
    220 		if (!cm || cm->type == MODE_LIST)
    221 			continue;
    222 
    223 		res += cm->mchar;
    224 
    225 		if (complete && !it->second.empty())
    226 		{
    227 			ChannelModeParam *cmp = NULL;
    228 			if (cm->type == MODE_PARAM)
    229 				cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
    230 
    231 			if (plus || !cmp || !cmp->minus_no_arg)
    232 				params += " " + it->second;
    233 		}
    234 	}
    235 
    236 	return res + params;
    237 }
    238 
    239 const Channel::ModeList &Channel::GetModes() const
    240 {
    241 	return this->modes;
    242 }
    243 
    244 template<typename F, typename S>
    245 struct second
    246 {
    247 	S operator()(const std::pair<F, S> &p)
    248 	{
    249 		return p.second;
    250 	}
    251 };
    252 
    253 std::vector<Anope::string> Channel::GetModeList(const Anope::string &mname)
    254 {
    255 	std::vector<Anope::string> r;
    256 	std::transform(modes.lower_bound(mname), modes.upper_bound(mname), std::back_inserter(r), second<Anope::string, Anope::string>());
    257 	return r;
    258 }
    259 
    260 void Channel::SetModeInternal(MessageSource &setter, ChannelMode *ocm, const Anope::string &oparam, bool enforce_mlock)
    261 {
    262 	if (!ocm)
    263 		return;
    264 
    265 	Anope::string param = oparam;
    266 	ChannelMode *cm = ocm->Unwrap(param);
    267 
    268 	EventReturn MOD_RESULT;
    269 
    270 	/* Setting v/h/o/a/q etc */
    271 	if (cm->type == MODE_STATUS)
    272 	{
    273 		if (param.empty())
    274 		{
    275 			Log() << "Channel::SetModeInternal() mode " << cm->mchar << " with no parameter for channel " << this->name;
    276 			return;
    277 		}
    278 
    279 		User *u = User::Find(param);
    280 
    281 		if (!u)
    282 		{
    283 			Log(LOG_DEBUG) << "MODE " << this->name << " +" << cm->mchar << " for nonexistent user " << param;
    284 			return;
    285 		}
    286 
    287 		Log(LOG_DEBUG) << "Setting +" << cm->mchar << " on " << this->name << " for " << u->nick;
    288 
    289 		/* Set the status on the user */
    290 		ChanUserContainer *cc = u->FindChannel(this);
    291 		if (cc)
    292 			cc->status.AddMode(cm->mchar);
    293 
    294 		FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, param));
    295 
    296 		/* Enforce secureops, etc */
    297 		if (enforce_mlock && MOD_RESULT != EVENT_STOP)
    298 			this->SetCorrectModes(u, false);
    299 		return;
    300 	}
    301 
    302 	if (cm->type != MODE_LIST)
    303 		this->modes.erase(cm->name);
    304 	else if (this->HasMode(cm->name, param))
    305 		return;
    306 
    307 	this->modes.insert(std::make_pair(cm->name, param));
    308 
    309 	if (param.empty() && cm->type != MODE_REGULAR)
    310 	{
    311 		Log() << "Channel::SetModeInternal() mode " << cm->mchar << " for " << this->name << " with no paramater, but is a param mode";
    312 		return;
    313 	}
    314 
    315 	if (cm->type == MODE_LIST)
    316 	{
    317 		ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
    318 		cml->OnAdd(this, param);
    319 	}
    320 
    321 	FOREACH_RESULT(OnChannelModeSet, MOD_RESULT, (this, setter, cm, param));
    322 
    323 	/* Check if we should enforce mlock */
    324 	if (!enforce_mlock || MOD_RESULT == EVENT_STOP)
    325 		return;
    326 
    327 	this->CheckModes();
    328 }
    329 
    330 void Channel::RemoveModeInternal(MessageSource &setter, ChannelMode *ocm, const Anope::string &oparam, bool enforce_mlock)
    331 {
    332 	if (!ocm)
    333 		return;
    334 
    335 	Anope::string param = oparam;
    336 	ChannelMode *cm = ocm->Unwrap(param);
    337 
    338 	EventReturn MOD_RESULT;
    339 
    340 	/* Setting v/h/o/a/q etc */
    341 	if (cm->type == MODE_STATUS)
    342 	{
    343 		if (param.empty())
    344 		{
    345 			Log() << "Channel::RemoveModeInternal() mode " << cm->mchar << " with no parameter for channel " << this->name;
    346 			return;
    347 		}
    348 
    349 		BotInfo *bi = BotInfo::Find(param);
    350 		User *u = bi ? bi : User::Find(param);
    351 
    352 		if (!u)
    353 		{
    354 			Log(LOG_DEBUG) << "Channel::RemoveModeInternal() MODE " << this->name << "-" << cm->mchar << " for nonexistent user " << param;
    355 			return;
    356 		}
    357 
    358 		Log(LOG_DEBUG) << "Setting -" << cm->mchar << " on " << this->name << " for " << u->nick;
    359 
    360 		/* Remove the status on the user */
    361 		ChanUserContainer *cc = u->FindChannel(this);
    362 		if (cc)
    363 			cc->status.DelMode(cm->mchar);
    364 
    365 		FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm, param));
    366 
    367 		if (enforce_mlock && MOD_RESULT != EVENT_STOP)
    368 			this->SetCorrectModes(u, false);
    369 
    370 		return;
    371 	}
    372 
    373 	if (cm->type == MODE_LIST)
    374 	{
    375 		for (Channel::ModeList::iterator it = modes.lower_bound(cm->name), it_end = modes.upper_bound(cm->name); it != it_end; ++it)
    376 			if (param.equals_ci(it->second))
    377 			{
    378 				this->modes.erase(it);
    379 				break;
    380 			}
    381 	}
    382 	else
    383 		this->modes.erase(cm->name);
    384 
    385 	if (cm->type == MODE_LIST)
    386 	{
    387 		ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
    388 		cml->OnDel(this, param);
    389 	}
    390 
    391 	FOREACH_RESULT(OnChannelModeUnset, MOD_RESULT, (this, setter, cm, param));
    392 
    393 	if (cm->name == "PERM")
    394 	{
    395 		if (this->CheckDelete())
    396 		{
    397 			delete this;
    398 			return;
    399 		}
    400 	}
    401 
    402 	/* Check for mlock */
    403 	if (!enforce_mlock || MOD_RESULT == EVENT_STOP)
    404 		return;
    405 
    406 	this->CheckModes();
    407 }
    408 
    409 void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string &param, bool enforce_mlock)
    410 {
    411 	Anope::string wparam = param;
    412 	if (!cm)
    413 		return;
    414 	/* Don't set modes already set */
    415 	if (cm->type == MODE_REGULAR && HasMode(cm->name))
    416 		return;
    417 	else if (cm->type == MODE_PARAM)
    418 	{
    419 		ChannelModeParam *cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
    420 		if (!cmp->IsValid(wparam))
    421 			return;
    422 
    423 		Anope::string cparam;
    424 		if (GetParam(cm->name, cparam) && cparam.equals_cs(wparam))
    425 			return;
    426 	}
    427 	else if (cm->type == MODE_STATUS)
    428 	{
    429 		User *u = User::Find(param);
    430 		if (!u || HasUserStatus(u, anope_dynamic_static_cast<ChannelModeStatus *>(cm)))
    431 			return;
    432 	}
    433 	else if (cm->type == MODE_LIST)
    434 	{
    435 		ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
    436 
    437 		if (!cml->IsValid(wparam))
    438 			return;
    439 
    440 		if (this->HasMode(cm->name, wparam))
    441 			return;
    442 	}
    443 
    444 	if (Me->IsSynced())
    445 	{
    446 		if (this->chanserv_modetime != Anope::CurTime)
    447 		{
    448 			this->chanserv_modecount = 0;
    449 			this->chanserv_modetime = Anope::CurTime;
    450 		}
    451 
    452 		this->chanserv_modecount++;
    453 	}
    454 
    455 	ChannelMode *wcm = cm->Wrap(wparam);
    456 
    457 	ModeManager::StackerAdd(bi, this, wcm, true, wparam);
    458 	MessageSource ms(bi);
    459 	SetModeInternal(ms, wcm, wparam, enforce_mlock);
    460 }
    461 
    462 void Channel::SetMode(BotInfo *bi, const Anope::string &mname, const Anope::string &param, bool enforce_mlock)
    463 {
    464 	SetMode(bi, ModeManager::FindChannelModeByName(mname), param, enforce_mlock);
    465 }
    466 
    467 void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string &wparam, bool enforce_mlock)
    468 {
    469 	if (!cm)
    470 		return;
    471 
    472 	/* Don't unset modes that arent set */
    473 	if ((cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && !HasMode(cm->name))
    474 		return;
    475 
    476 	/* Unwrap to be sure we have the internal representation */
    477 	Anope::string param = wparam;
    478 	cm = cm->Unwrap(param);
    479 
    480 	/* Don't unset status that aren't set */
    481 	if (cm->type == MODE_STATUS)
    482 	{
    483 		User *u = User::Find(param);
    484 		if (!u || !HasUserStatus(u, anope_dynamic_static_cast<ChannelModeStatus *>(cm)))
    485 			return;
    486 	}
    487 	else if (cm->type == MODE_LIST)
    488 	{
    489 		if (!this->HasMode(cm->name, param))
    490 			return;
    491 	}
    492 
    493 	/* Get the param to send, if we need it */
    494 	if (cm->type == MODE_PARAM)
    495 	{
    496 		param.clear();
    497 		ChannelModeParam *cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
    498 		if (!cmp->minus_no_arg)
    499 			this->GetParam(cmp->name, param);
    500 	}
    501 
    502 	if (Me->IsSynced())
    503 	{
    504 		if (this->chanserv_modetime != Anope::CurTime)
    505 		{
    506 			this->chanserv_modecount = 0;
    507 			this->chanserv_modetime = Anope::CurTime;
    508 		}
    509 
    510 		this->chanserv_modecount++;
    511 	}
    512 
    513 	/* Wrap to get ircd representation */
    514 	ChannelMode *wcm = cm->Wrap(param);
    515 
    516 	ModeManager::StackerAdd(bi, this, wcm, false, param);
    517 	MessageSource ms(bi);
    518 	RemoveModeInternal(ms, wcm, param, enforce_mlock);
    519 }
    520 
    521 void Channel::RemoveMode(BotInfo *bi, const Anope::string &mname, const Anope::string &param, bool enforce_mlock)
    522 {
    523 	RemoveMode(bi, ModeManager::FindChannelModeByName(mname), param, enforce_mlock);
    524 }
    525 
    526 bool Channel::GetParam(const Anope::string &mname, Anope::string &target) const
    527 {
    528 	std::multimap<Anope::string, Anope::string>::const_iterator it = this->modes.find(mname);
    529 
    530 	target.clear();
    531 
    532 	if (it != this->modes.end())
    533 	{
    534 		target = it->second;
    535 		return true;
    536 	}
    537 
    538 	return false;
    539 }
    540 
    541 void Channel::SetModes(BotInfo *bi, bool enforce_mlock, const char *cmodes, ...)
    542 {
    543 	char buf[BUFSIZE] = "";
    544 	va_list args;
    545 	Anope::string modebuf, sbuf;
    546 	int add = -1;
    547 	va_start(args, cmodes);
    548 	vsnprintf(buf, BUFSIZE - 1, cmodes, args);
    549 	va_end(args);
    550 
    551 	Reference<Channel> this_reference(this);
    552 
    553 	spacesepstream sep(buf);
    554 	sep.GetToken(modebuf);
    555 	for (unsigned i = 0, end = modebuf.length(); this_reference && i < end; ++i)
    556 	{
    557 		ChannelMode *cm;
    558 
    559 		switch (modebuf[i])
    560 		{
    561 			case '+':
    562 				add = 1;
    563 				continue;
    564 			case '-':
    565 				add = 0;
    566 				continue;
    567 			default:
    568 				if (add == -1)
    569 					continue;
    570 				cm = ModeManager::FindChannelModeByChar(modebuf[i]);
    571 				if (!cm)
    572 					continue;
    573 		}
    574 
    575 		if (add)
    576 		{
    577 			if (cm->type != MODE_REGULAR && sep.GetToken(sbuf))
    578 			{
    579 				if (cm->type == MODE_STATUS)
    580 				{
    581 					User *targ = User::Find(sbuf);
    582 					if (targ != NULL)
    583 						sbuf = targ->GetUID();
    584 				}
    585 				this->SetMode(bi, cm, sbuf, enforce_mlock);
    586 			}
    587 			else
    588 				this->SetMode(bi, cm, "", enforce_mlock);
    589 		}
    590 		else if (!add)
    591 		{
    592 			if (cm->type != MODE_REGULAR && sep.GetToken(sbuf))
    593 			{
    594 				if (cm->type == MODE_STATUS)
    595 				{
    596 					User *targ = User::Find(sbuf);
    597 					if (targ != NULL)
    598 						sbuf = targ->GetUID();
    599 				}
    600 				this->RemoveMode(bi, cm, sbuf, enforce_mlock);
    601 			}
    602 			else
    603 				this->RemoveMode(bi, cm, "", enforce_mlock);
    604 		}
    605 	}
    606 }
    607 
    608 void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode, time_t ts, bool enforce_mlock)
    609 {
    610 	if (!ts)
    611 		;
    612 	else if (ts > this->creation_time)
    613 	{
    614 		Log(LOG_DEBUG) << "Dropping mode " << mode << " on " << this->name << ", " << ts << " > " << this->creation_time;
    615 		return;
    616 	}
    617 	else if (ts < this->creation_time)
    618 	{
    619 		Log(LOG_DEBUG) << "Changing TS of " << this->name << " from " << this->creation_time << " to " << ts;
    620 		this->creation_time = ts;
    621 		this->Reset();
    622 	}
    623 
    624 	User *setter = source.GetUser();
    625 	/* Removing channel modes *may* delete this channel */
    626 	Reference<Channel> this_reference(this);
    627 
    628 	spacesepstream sep_modes(mode);
    629 	Anope::string m;
    630 
    631 	sep_modes.GetToken(m);
    632 
    633 	Anope::string modestring;
    634 	Anope::string paramstring;
    635 	int add = -1;
    636 	bool changed = false;
    637 	for (unsigned int i = 0, end = m.length(); i < end && this_reference; ++i)
    638 	{
    639 		ChannelMode *cm;
    640 
    641 		switch (m[i])
    642 		{
    643 			case '+':
    644 				modestring += '+';
    645 				add = 1;
    646 				continue;
    647 			case '-':
    648 				modestring += '-';
    649 				add = 0;
    650 				continue;
    651 			default:
    652 				if (add == -1)
    653 					continue;
    654 				cm = ModeManager::FindChannelModeByChar(m[i]);
    655 				if (!cm)
    656 				{
    657 					Log(LOG_DEBUG) << "Channel::SetModeInternal: Unknown mode char " << m[i];
    658 					continue;
    659 				}
    660 				modestring += cm->mchar;
    661 		}
    662 
    663 		if (cm->type == MODE_REGULAR)
    664 		{
    665 			/* something changed if we are adding a mode we don't have, or removing one we have */
    666 			changed |= !!add != this->HasMode(cm->name);
    667 			if (add)
    668 				this->SetModeInternal(source, cm, "", false);
    669 			else
    670 				this->RemoveModeInternal(source, cm, "", false);
    671 			continue;
    672 		}
    673 		else if (cm->type == MODE_PARAM)
    674 		{
    675 			ChannelModeParam *cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
    676 
    677 			if (!add && cmp->minus_no_arg)
    678 			{
    679 				this->RemoveModeInternal(source, cm, "", false);
    680 				continue;
    681 			}
    682 		}
    683 		Anope::string token;
    684 		if (sep_modes.GetToken(token))
    685 		{
    686 			User *u = NULL;
    687 			if (cm->type == MODE_STATUS && (u = User::Find(token)))
    688 				paramstring += " " + u->nick;
    689 			else
    690 				paramstring += " " + token;
    691 
    692 			changed |= !!add != this->HasMode(cm->name, token);
    693 			/* CheckModes below doesn't check secureops (+ the module event) */
    694 			if (add)
    695 				this->SetModeInternal(source, cm, token, enforce_mlock);
    696 			else
    697 				this->RemoveModeInternal(source, cm, token, enforce_mlock);
    698 		}
    699 		else
    700 			Log() << "warning: Channel::SetModesInternal() received more modes requiring params than params, modes: " << mode;
    701 	}
    702 
    703 	if (!this_reference)
    704 		return;
    705 
    706 	if (changed && source.GetServer() && source.GetServer()->IsSynced())
    707 	{
    708 		if (Anope::CurTime != this->server_modetime)
    709 		{
    710 			this->server_modecount = 0;
    711 			this->server_modetime = Anope::CurTime;
    712 		}
    713 
    714 		++this->server_modecount;
    715 	}
    716 
    717 	if (setter)
    718 		Log(setter, this, "mode") << modestring << paramstring;
    719 	else
    720 		Log(LOG_DEBUG) << source.GetName() << " is setting " << this->name << " to " << modestring << paramstring;
    721 
    722 	if (enforce_mlock)
    723 		this->CheckModes();
    724 }
    725 
    726 bool Channel::MatchesList(User *u, const Anope::string &mode)
    727 {
    728 	if (!this->HasMode(mode))
    729 		return false;
    730 
    731 	std::vector<Anope::string> v = this->GetModeList(mode);
    732 	for (unsigned i = 0; i < v.size(); ++i)
    733 	{
    734 		Entry e(mode, v[i]);
    735 		if (e.Matches(u))
    736 			return true;
    737 	}
    738 
    739 	return false;
    740 }
    741 
    742 void Channel::KickInternal(const MessageSource &source, const Anope::string &nick, const Anope::string &reason)
    743 {
    744 	User *sender = source.GetUser();
    745 	User *target = User::Find(nick);
    746 	if (!target)
    747 	{
    748 		Log(LOG_DEBUG) << "Channel::KickInternal got a nonexistent user " << nick << " on " << this->name << ": " << reason;
    749 		return;
    750 	}
    751 
    752 	if (sender)
    753 		Log(sender, this, "kick") << "kicked " << target->nick << " (" << reason << ")";
    754 	else
    755 		Log(target, this, "kick") << "was kicked by " << source.GetName() << " (" << reason << ")";
    756 
    757 	Anope::string chname = this->name;
    758 
    759 	ChanUserContainer *cu = target->FindChannel(this);
    760 	if (cu == NULL)
    761 	{
    762 		Log(LOG_DEBUG) << "Channel::KickInternal got kick for user " << target->nick << " from " << source.GetSource() << " who isn't on channel " << this->name;
    763 		return;
    764 	}
    765 
    766 	ChannelStatus status = cu->status;
    767 
    768 	FOREACH_MOD(OnPreUserKicked, (source, cu, reason));
    769 	this->DeleteUser(target);
    770 	FOREACH_MOD(OnUserKicked, (source, target, this->name, status, reason));
    771 }
    772 
    773 bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...)
    774 {
    775 	va_list args;
    776 	char buf[BUFSIZE] = "";
    777 	va_start(args, reason);
    778 	vsnprintf(buf, BUFSIZE - 1, reason, args);
    779 	va_end(args);
    780 
    781 	/* Do not kick protected clients or Ulines */
    782 	if (u->IsProtected())
    783 		return false;
    784 
    785 	if (bi == NULL)
    786 		bi = this->ci->WhoSends();
    787 
    788 	EventReturn MOD_RESULT;
    789 	FOREACH_RESULT(OnBotKick, MOD_RESULT, (bi, this, u, buf));
    790 	if (MOD_RESULT == EVENT_STOP)
    791 		return false;
    792 	IRCD->SendKick(bi, this, u, "%s", buf);
    793 	this->KickInternal(bi, u->nick, buf);
    794 	return true;
    795 }
    796 
    797 void Channel::ChangeTopicInternal(User *u, const Anope::string &user, const Anope::string &newtopic, time_t ts)
    798 {
    799 	this->topic = newtopic;
    800 	this->topic_setter = u ? u->nick : user;
    801 	this->topic_ts = ts;
    802 	this->topic_time = Anope::CurTime;
    803 
    804 	Log(LOG_DEBUG) << "Topic of " << this->name << " changed by " << this->topic_setter << " to " << newtopic;
    805 
    806 	FOREACH_MOD(OnTopicUpdated, (u, this, user, this->topic));
    807 }
    808 
    809 void Channel::ChangeTopic(const Anope::string &user, const Anope::string &newtopic, time_t ts)
    810 {
    811 	this->topic = newtopic;
    812 	this->topic_setter = user;
    813 	this->topic_ts = ts;
    814 
    815 	IRCD->SendTopic(this->ci->WhoSends(), this);
    816 
    817 	/* Now that the topic is set update the time set. This is *after* we set it so the protocol modules are able to tell the old last set time */
    818 	this->topic_time = Anope::CurTime;
    819 
    820 	FOREACH_MOD(OnTopicUpdated, (NULL, this, user, this->topic));
    821 }
    822 
    823 void Channel::SetCorrectModes(User *user, bool give_modes)
    824 {
    825 	if (user == NULL)
    826 		return;
    827 
    828 	if (!this->ci)
    829 		return;
    830 
    831 	Log(LOG_DEBUG) << "Setting correct user modes for " << user->nick << " on " << this->name << " (" << (give_modes ? "" : "not ") << "giving modes)";
    832 
    833 	AccessGroup u_access = ci->AccessFor(user);
    834 
    835 	/* Initially only take modes if the channel is being created by a non netmerge */
    836 	bool take_modes = this->syncing && user->server->IsSynced();
    837 
    838 	FOREACH_MOD(OnSetCorrectModes, (user, this, u_access, give_modes, take_modes));
    839 
    840 	/* Never take modes from ulines */
    841 	if (user->server->IsULined())
    842 		take_modes = false;
    843 
    844 	/* whether or not we are giving modes */
    845 	bool giving = give_modes;
    846 	/* whether or not we have given a mode */
    847 	bool given = false;
    848 	for (unsigned i = 0; i < ModeManager::GetStatusChannelModesByRank().size(); ++i)
    849 	{
    850 		ChannelModeStatus *cm = ModeManager::GetStatusChannelModesByRank()[i];
    851 		bool has_priv = u_access.HasPriv("AUTO" + cm->name);
    852 
    853 		if (give_modes && has_priv)
    854 		{
    855 			/* Always give op. If we have already given one mode, don't give more until it has a symbol */
    856 			if (cm->name == "OP" || !given || (giving && cm->symbol))
    857 			{
    858 				this->SetMode(NULL, cm, user->GetUID(), false);
    859 				/* Now if this contains a symbol don't give any more modes, to prevent setting +qaohv etc on users */
    860 				giving = !cm->symbol;
    861 				given = true;
    862 			}
    863 		}
    864 		/* modes that have no privileges assigned shouldn't be removed (like operprefix, ojoin) */
    865 		else if (take_modes && !has_priv && ci->GetLevel(cm->name + "ME") != ACCESS_INVALID && !u_access.HasPriv(cm->name + "ME"))
    866 		{
    867 			/* Only remove modes if they are > voice */
    868 			if (cm->name == "VOICE")
    869 				take_modes = false;
    870 			else
    871 				this->RemoveMode(NULL, cm, user->GetUID(), false);
    872 		}
    873 	}
    874 }
    875 
    876 bool Channel::Unban(User *u, const Anope::string &mode, bool full)
    877 {
    878 	if (!this->HasMode(mode))
    879 		return false;
    880 
    881 	bool ret = false;
    882 
    883 	std::vector<Anope::string> v = this->GetModeList(mode);
    884 	for (unsigned int i = 0; i < v.size(); ++i)
    885 	{
    886 		Entry ban(mode, v[i]);
    887 		if (ban.Matches(u, full))
    888 		{
    889 			this->RemoveMode(NULL, mode, ban.GetMask());
    890 			ret = true;
    891 		}
    892 	}
    893 
    894 	return ret;
    895 }
    896 
    897 bool Channel::CheckKick(User *user)
    898 {
    899 	if (user->super_admin)
    900 		return false;
    901 
    902 	/* We don't enforce services restrictions on clients on ulined services
    903 	 * as this will likely lead to kick/rejoin floods. ~ Viper */
    904 	if (user->IsProtected())
    905 		return false;
    906 
    907 	Anope::string mask, reason;
    908 
    909 	EventReturn MOD_RESULT;
    910 	FOREACH_RESULT(OnCheckKick, MOD_RESULT, (user, this, mask, reason));
    911 	if (MOD_RESULT != EVENT_STOP)
    912 		return false;
    913 
    914 	if (mask.empty())
    915 		mask = this->ci->GetIdealBan(user);
    916 	if (reason.empty())
    917 		reason = Language::Translate(user->Account(), CHAN_NOT_ALLOWED_TO_JOIN);
    918 
    919 	Log(LOG_DEBUG) << "Autokicking " << user->nick << " (" << mask << ") from " << this->name;
    920 
    921 	this->SetMode(NULL, "BAN", mask);
    922 	this->Kick(NULL, user, "%s", reason.c_str());
    923 
    924 	return true;
    925 }
    926 
    927 Channel* Channel::Find(const Anope::string &name)
    928 {
    929 	channel_map::const_iterator it = ChannelList.find(name);
    930 
    931 	if (it != ChannelList.end())
    932 		return it->second;
    933 	return NULL;
    934 }
    935 
    936 Channel *Channel::FindOrCreate(const Anope::string &name, bool &created, time_t ts)
    937 {
    938 	Channel* &chan = ChannelList[name];
    939 	created = chan == NULL;
    940 	if (!chan)
    941 		chan = new Channel(name, ts);
    942 	return chan;
    943 }
    944 
    945 void Channel::QueueForDeletion()
    946 {
    947 	if (std::find(deleting.begin(), deleting.end(), this) == deleting.end())
    948 		deleting.push_back(this);
    949 }
    950 
    951 void Channel::DeleteChannels()
    952 {
    953 	for (unsigned int i = 0; i < deleting.size(); ++i)
    954 	{
    955 		Channel *c = deleting[i];
    956 
    957 		if (c->CheckDelete())
    958 			delete c;
    959 	}
    960 	deleting.clear();
    961 }