anope

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

regchannel.cpp (15817B)

      1 /* Registered channel functions
      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 "modules.h"
     14 #include "regchannel.h"
     15 #include "account.h"
     16 #include "access.h"
     17 #include "channels.h"
     18 #include "config.h"
     19 #include "bots.h"
     20 #include "servers.h"
     21 
     22 Serialize::Checker<registered_channel_map> RegisteredChannelList("ChannelInfo");
     23 
     24 AutoKick::AutoKick() : Serializable("AutoKick")
     25 {
     26 }
     27 
     28 AutoKick::~AutoKick()
     29 {
     30 	if (this->ci)
     31 	{
     32 		std::vector<AutoKick *>::iterator it = std::find(this->ci->akick->begin(), this->ci->akick->end(), this);
     33 		if (it != this->ci->akick->end())
     34 			this->ci->akick->erase(it);
     35 
     36 		if (nc)
     37 			nc->RemoveChannelReference(this->ci);
     38 	}
     39 }
     40 
     41 void AutoKick::Serialize(Serialize::Data &data) const
     42 {
     43 	data["ci"] << this->ci->name;
     44 	if (this->nc)
     45 		data["nc"] << this->nc->display;
     46 	else
     47 		data["mask"] << this->mask;
     48 	data["reason"] << this->reason;
     49 	data["creator"] << this->creator;
     50 	data.SetType("addtime", Serialize::Data::DT_INT); data["addtime"] << this->addtime;
     51 	data.SetType("last_used", Serialize::Data::DT_INT); data["last_used"] << this->last_used;
     52 }
     53 
     54 Serializable* AutoKick::Unserialize(Serializable *obj, Serialize::Data &data)
     55 {
     56 	Anope::string sci, snc;
     57 
     58 	data["ci"] >> sci;
     59 	data["nc"] >> snc;
     60 
     61 	ChannelInfo *ci = ChannelInfo::Find(sci);
     62 	if (!ci)
     63 		return NULL;
     64 
     65 	AutoKick *ak;
     66 	NickCore *nc = NickCore::Find(snc);
     67 	if (obj)
     68 	{
     69 		ak = anope_dynamic_static_cast<AutoKick *>(obj);
     70 		data["creator"] >> ak->creator;
     71 		data["reason"] >> ak->reason;
     72 		ak->nc = NickCore::Find(snc);
     73 		data["mask"] >> ak->mask;
     74 		data["addtime"] >> ak->addtime;
     75 		data["last_used"] >> ak->last_used;
     76 	}
     77 	else
     78 	{
     79 		time_t addtime, lastused;
     80 		data["addtime"] >> addtime;
     81 		data["last_used"] >> lastused;
     82 
     83 		Anope::string screator, sreason, smask;
     84 
     85 		data["creator"] >> screator;
     86 		data["reason"] >> sreason;
     87 		data["mask"] >> smask;
     88 
     89 		if (nc)
     90 			ak = ci->AddAkick(screator, nc, sreason, addtime, lastused);
     91 		else
     92 			ak = ci->AddAkick(screator, smask, sreason, addtime, lastused);
     93 	}
     94 
     95 	return ak;
     96 }
     97 
     98 ChannelInfo::ChannelInfo(const Anope::string &chname) : Serializable("ChannelInfo"),
     99 	access("ChanAccess"), akick("AutoKick")
    100 {
    101 	if (chname.empty())
    102 		throw CoreException("Empty channel passed to ChannelInfo constructor");
    103 
    104 	this->founder = NULL;
    105 	this->successor = NULL;
    106 	this->c = Channel::Find(chname);
    107 	if (this->c)
    108 		this->c->ci = this;
    109 	this->banexpire = 0;
    110 	this->bi = NULL;
    111 	this->last_topic_time = 0;
    112 
    113 	this->name = chname;
    114 
    115 	this->bantype = 2;
    116 	this->memos.memomax = 0;
    117 	this->last_used = this->time_registered = Anope::CurTime;
    118 
    119 	size_t old = RegisteredChannelList->size();
    120 	(*RegisteredChannelList)[this->name] = this;
    121 	if (old == RegisteredChannelList->size())
    122 		Log(LOG_DEBUG) << "Duplicate channel " << this->name << " in registered channel table?";
    123 
    124 	FOREACH_MOD(OnCreateChan, (this));
    125 }
    126 
    127 ChannelInfo::ChannelInfo(const ChannelInfo &ci) : Serializable("ChannelInfo"),
    128 	access("ChanAccess"), akick("AutoKick")
    129 {
    130 	*this = ci;
    131 
    132 	if (this->founder)
    133 		++this->founder->channelcount;
    134 
    135 	this->access->clear();
    136 	this->akick->clear();
    137 
    138 	FOREACH_MOD(OnCreateChan, (this));
    139 }
    140 
    141 ChannelInfo::~ChannelInfo()
    142 {
    143 	FOREACH_MOD(OnDelChan, (this));
    144 
    145 	UnsetExtensibles();
    146 
    147 	Log(LOG_DEBUG) << "Deleting channel " << this->name;
    148 
    149 	if (this->c)
    150 	{
    151 		if (this->bi && this->c->FindUser(this->bi))
    152 			this->bi->Part(this->c);
    153 
    154 		/* Parting the service bot can cause the channel to go away */
    155 
    156 		if (this->c)
    157 		{
    158 			if (this->c && this->c->CheckDelete())
    159 				this->c->QueueForDeletion();
    160 
    161 			this->c = NULL;
    162 		}
    163 	}
    164 
    165 	RegisteredChannelList->erase(this->name);
    166 
    167 	this->SetFounder(NULL);
    168 	this->SetSuccessor(NULL);
    169 
    170 	this->ClearAccess();
    171 	this->ClearAkick();
    172 
    173 	if (!this->memos.memos->empty())
    174 	{
    175 		for (unsigned i = 0, end = this->memos.memos->size(); i < end; ++i)
    176 			delete this->memos.GetMemo(i);
    177 		this->memos.memos->clear();
    178 	}
    179 }
    180 
    181 void ChannelInfo::Serialize(Serialize::Data &data) const
    182 {
    183 	data["name"] << this->name;
    184 	if (this->founder)
    185 		data["founder"] << this->founder->display;
    186 	if (this->successor)
    187 		data["successor"] << this->successor->display;
    188 	data["description"] << this->desc;
    189 	data.SetType("time_registered", Serialize::Data::DT_INT); data["time_registered"] << this->time_registered;
    190 	data.SetType("last_used", Serialize::Data::DT_INT); data["last_used"] << this->last_used;
    191 	data["last_topic"] << this->last_topic;
    192 	data["last_topic_setter"] << this->last_topic_setter;
    193 	data.SetType("last_topic_time", Serialize::Data::DT_INT); data["last_topic_time"] << this->last_topic_time;
    194 	data.SetType("bantype", Serialize::Data::DT_INT); data["bantype"] << this->bantype;
    195 	{
    196 		Anope::string levels_buffer;
    197 		for (Anope::map<int16_t>::const_iterator it = this->levels.begin(), it_end = this->levels.end(); it != it_end; ++it)
    198 			levels_buffer += it->first + " " + stringify(it->second) + " ";
    199 		data["levels"] << levels_buffer;
    200 	}
    201 	if (this->bi)
    202 		data["bi"] << this->bi->nick;
    203 	data.SetType("banexpire", Serialize::Data::DT_INT); data["banexpire"] << this->banexpire;
    204 	data["memomax"] << this->memos.memomax;
    205 	for (unsigned i = 0; i < this->memos.ignores.size(); ++i)
    206 		data["memoignores"] << this->memos.ignores[i] << " ";
    207 
    208 	Extensible::ExtensibleSerialize(this, this, data);
    209 }
    210 
    211 Serializable* ChannelInfo::Unserialize(Serializable *obj, Serialize::Data &data)
    212 {
    213 	Anope::string sname, sfounder, ssuccessor, slevels, sbi;
    214 
    215 	data["name"] >> sname;
    216 	data["founder"] >> sfounder;
    217 	data["successor"] >> ssuccessor;
    218 	data["levels"] >> slevels;
    219 	data["bi"] >> sbi;
    220 
    221 	ChannelInfo *ci;
    222 	if (obj)
    223 		ci = anope_dynamic_static_cast<ChannelInfo *>(obj);
    224 	else
    225 		ci = new ChannelInfo(sname);
    226 
    227 	ci->SetFounder(NickCore::Find(sfounder));
    228 	ci->SetSuccessor(NickCore::Find(ssuccessor));
    229 
    230 	data["description"] >> ci->desc;
    231 	data["time_registered"] >> ci->time_registered;
    232 	data["last_used"] >> ci->last_used;
    233 	data["last_topic"] >> ci->last_topic;
    234 	data["last_topic_setter"] >> ci->last_topic_setter;
    235 	data["last_topic_time"] >> ci->last_topic_time;
    236 	data["bantype"] >> ci->bantype;
    237 	{
    238 		std::vector<Anope::string> v;
    239 		spacesepstream(slevels).GetTokens(v);
    240 		for (unsigned i = 0; i + 1 < v.size(); i += 2)
    241 			try
    242 			{
    243 				ci->levels[v[i]] = convertTo<int16_t>(v[i + 1]);
    244 			}
    245 			catch (const ConvertException &) { }
    246 	}
    247 	BotInfo *bi = BotInfo::Find(sbi, true);
    248 	if (*ci->bi != bi)
    249 	{
    250 		if (bi)
    251 			bi->Assign(NULL, ci);
    252 		else if (ci->bi)
    253 			ci->bi->UnAssign(NULL, ci);
    254 	}
    255 	data["banexpire"] >> ci->banexpire;
    256 	data["memomax"] >> ci->memos.memomax;
    257 	{
    258 		Anope::string buf;
    259 		data["memoignores"] >> buf;
    260 		spacesepstream sep(buf);
    261 		ci->memos.ignores.clear();
    262 		while (sep.GetToken(buf))
    263 			ci->memos.ignores.push_back(buf);
    264 	}
    265 
    266 	Extensible::ExtensibleUnserialize(ci, ci, data);
    267 
    268 	/* compat */
    269 	bool b;
    270 	b = false;
    271 	data["extensible:SECURE"] >> b;
    272 	if (b)
    273 		ci->Extend<bool>("CS_SECURE");
    274 	b = false;
    275 	data["extensible:PRIVATE"] >> b;
    276 	if (b)
    277 		ci->Extend<bool>("CS_PRIVATE");
    278 	b = false;
    279 	data["extensible:NO_EXPIRE"] >> b;
    280 	if (b)
    281 		ci->Extend<bool>("CS_NO_EXPIRE");
    282 	b = false;
    283 	data["extensible:FANTASY"] >> b;
    284 	if (b)
    285 		ci->Extend<bool>("BS_FANTASY");
    286 	b = false;
    287 	data["extensible:GREET"] >> b;
    288 	if (b)
    289 		ci->Extend<bool>("BS_GREET");
    290 	b = false;
    291 	data["extensible:PEACE"] >> b;
    292 	if (b)
    293 		ci->Extend<bool>("PEACE");
    294 	b = false;
    295 	data["extensible:SECUREFOUNDER"] >> b;
    296 	if (b)
    297 		ci->Extend<bool>("SECUREFOUNDER");
    298 	b = false;
    299 	data["extensible:RESTRICTED"] >> b;
    300 	if (b)
    301 		ci->Extend<bool>("RESTRICTED");
    302 	b = false;
    303 	data["extensible:KEEPTOPIC"] >> b;
    304 	if (b)
    305 		ci->Extend<bool>("KEEPTOPIC");
    306 	b = false;
    307 	data["extensible:SIGNKICK"] >> b;
    308 	if (b)
    309 		ci->Extend<bool>("SIGNKICK");
    310 	b = false;
    311 	data["extensible:SIGNKICK_LEVEL"] >> b;
    312 	if (b)
    313 		ci->Extend<bool>("SIGNKICK_LEVEL");
    314 	/* end compat */
    315 
    316 	return ci;
    317 }
    318 
    319 
    320 void ChannelInfo::SetFounder(NickCore *nc)
    321 {
    322 	if (this->founder)
    323 	{
    324 		--this->founder->channelcount;
    325 		this->founder->RemoveChannelReference(this);
    326 	}
    327 
    328 	this->founder = nc;
    329 
    330 	if (this->founder)
    331 	{
    332 		++this->founder->channelcount;
    333 		this->founder->AddChannelReference(this);
    334 	}
    335 }
    336 
    337 NickCore *ChannelInfo::GetFounder() const
    338 {
    339 	return this->founder;
    340 }
    341 
    342 void ChannelInfo::SetSuccessor(NickCore *nc)
    343 {
    344 	if (this->successor)
    345 		this->successor->RemoveChannelReference(this);
    346 	this->successor = nc;
    347 	if (this->successor)
    348 		this->successor->AddChannelReference(this);
    349 }
    350 
    351 NickCore *ChannelInfo::GetSuccessor() const
    352 {
    353 	return this->successor;
    354 }
    355 
    356 BotInfo *ChannelInfo::WhoSends() const
    357 {
    358 	if (this && this->bi)
    359 		return this->bi;
    360 
    361 	BotInfo *ChanServ = Config->GetClient("ChanServ");
    362 	if (ChanServ)
    363 		return ChanServ;
    364 
    365 	if (!BotListByNick->empty())
    366 		return BotListByNick->begin()->second;
    367 
    368 	return NULL;
    369 }
    370 
    371 void ChannelInfo::AddAccess(ChanAccess *taccess)
    372 {
    373 	this->access->push_back(taccess);
    374 }
    375 
    376 ChanAccess *ChannelInfo::GetAccess(unsigned index) const
    377 {
    378 	if (this->access->empty() || index >= this->access->size())
    379 		return NULL;
    380 
    381 	ChanAccess *acc = (*this->access)[index];
    382 	acc->QueueUpdate();
    383 	return acc;
    384 }
    385 
    386 static void FindMatchesRecurse(ChannelInfo *ci, const User *u, const NickCore *account, unsigned int depth, std::vector<ChanAccess::Path> &paths, ChanAccess::Path &path)
    387 {
    388 	if (depth > ChanAccess::MAX_DEPTH)
    389 		return;
    390 
    391 	for (unsigned int i = 0; i < ci->GetAccessCount(); ++i)
    392 	{
    393 		ChanAccess *a = ci->GetAccess(i);
    394 		ChannelInfo *next = NULL;
    395 
    396 		if (a->Matches(u, account, next))
    397 		{
    398 			ChanAccess::Path next_path = path;
    399 			next_path.push_back(a);
    400 
    401 			paths.push_back(next_path);
    402 		}
    403 		else if (next)
    404 		{
    405 			ChanAccess::Path next_path = path;
    406 			next_path.push_back(a);
    407 
    408 			FindMatchesRecurse(next, u, account, depth + 1, paths, next_path);
    409 		}
    410 	}
    411 }
    412 
    413 static void FindMatches(AccessGroup &group, ChannelInfo *ci, const User *u, const NickCore *account)
    414 {
    415 	ChanAccess::Path path;
    416 	FindMatchesRecurse(ci, u, account, 0, group.paths, path);
    417 }
    418 
    419 AccessGroup ChannelInfo::AccessFor(const User *u, bool updateLastUsed)
    420 {
    421 	AccessGroup group;
    422 
    423 	if (u == NULL)
    424 		return group;
    425 
    426 	const NickCore *nc = u->Account();
    427 	if (nc == NULL && !this->HasExt("NS_SECURE") && u->IsRecognized())
    428 	{
    429 		const NickAlias *na = NickAlias::Find(u->nick);
    430 		if (na != NULL)
    431 			nc = na->nc;
    432 	}
    433 
    434 	group.super_admin = u->super_admin;
    435 	group.founder = IsFounder(u, this);
    436 	group.ci = this;
    437 	group.nc = nc;
    438 
    439 	FindMatches(group, this, u, u->Account());
    440 
    441 	if (group.founder || !group.paths.empty())
    442 	{
    443 		if (updateLastUsed)
    444 			this->last_used = Anope::CurTime;
    445 
    446 		for (unsigned i = 0; i < group.paths.size(); ++i)
    447 		{
    448 			ChanAccess::Path &p = group.paths[i];
    449 
    450 			for (unsigned int j = 0; j < p.size(); ++j)
    451 				p[j]->last_seen = Anope::CurTime;
    452 		}
    453 	}
    454 
    455 	return group;
    456 }
    457 
    458 AccessGroup ChannelInfo::AccessFor(const NickCore *nc, bool updateLastUsed)
    459 {
    460 	AccessGroup group;
    461 
    462 	group.founder = (this->founder && this->founder == nc);
    463 	group.ci = this;
    464 	group.nc = nc;
    465 
    466 	FindMatches(group, this, NULL, nc);
    467 
    468 	if (group.founder || !group.paths.empty())
    469 		if (updateLastUsed)
    470 			this->last_used = Anope::CurTime;
    471 
    472 	/* don't update access last seen here, this isn't the user requesting access */
    473 
    474 	return group;
    475 }
    476 
    477 unsigned ChannelInfo::GetAccessCount() const
    478 {
    479 	return this->access->size();
    480 }
    481 
    482 static unsigned int GetDeepAccessCount(const ChannelInfo *ci, std::set<const ChannelInfo *> &seen, unsigned int depth)
    483 {
    484 	if (depth > ChanAccess::MAX_DEPTH || seen.count(ci))
    485 		return 0;
    486 	seen.insert(ci);
    487 
    488 	unsigned int total = 0;
    489 
    490 	for (unsigned int i = 0; i < ci->GetAccessCount(); ++i)
    491 	{
    492 		ChanAccess::Path path;
    493 		ChanAccess *a = ci->GetAccess(i);
    494 		ChannelInfo *next = NULL;
    495 
    496 		a->Matches(NULL, NULL, next);
    497 		++total;
    498 
    499 		if (next)
    500 			total += GetDeepAccessCount(ci, seen, depth + 1);
    501 	}
    502 
    503 	return total;
    504 }
    505 
    506 unsigned ChannelInfo::GetDeepAccessCount() const
    507 {
    508 	std::set<const ChannelInfo *> seen;
    509 	return ::GetDeepAccessCount(this, seen, 0);
    510 }
    511 
    512 ChanAccess *ChannelInfo::EraseAccess(unsigned index)
    513 {
    514 	if (this->access->empty() || index >= this->access->size())
    515 		return NULL;
    516 
    517 	ChanAccess *ca = this->access->at(index);
    518 	this->access->erase(this->access->begin() + index);
    519 	return ca;
    520 }
    521 
    522 void ChannelInfo::ClearAccess()
    523 {
    524 	for (unsigned i = this->access->size(); i > 0; --i)
    525 		delete this->GetAccess(i - 1);
    526 }
    527 
    528 AutoKick *ChannelInfo::AddAkick(const Anope::string &user, NickCore *akicknc, const Anope::string &reason, time_t t, time_t lu)
    529 {
    530 	AutoKick *autokick = new AutoKick();
    531 	autokick->ci = this;
    532 	autokick->nc = akicknc;
    533 	autokick->reason = reason;
    534 	autokick->creator = user;
    535 	autokick->addtime = t;
    536 	autokick->last_used = lu;
    537 
    538 	this->akick->push_back(autokick);
    539 
    540 	akicknc->AddChannelReference(this);
    541 
    542 	return autokick;
    543 }
    544 
    545 AutoKick *ChannelInfo::AddAkick(const Anope::string &user, const Anope::string &mask, const Anope::string &reason, time_t t, time_t lu)
    546 {
    547 	AutoKick *autokick = new AutoKick();
    548 	autokick->ci = this;
    549 	autokick->mask = mask;
    550 	autokick->nc = NULL;
    551 	autokick->reason = reason;
    552 	autokick->creator = user;
    553 	autokick->addtime = t;
    554 	autokick->last_used = lu;
    555 
    556 	this->akick->push_back(autokick);
    557 
    558 	return autokick;
    559 }
    560 
    561 AutoKick *ChannelInfo::GetAkick(unsigned index) const
    562 {
    563 	if (this->akick->empty() || index >= this->akick->size())
    564 		return NULL;
    565 
    566 	AutoKick *ak = (*this->akick)[index];
    567 	ak->QueueUpdate();
    568 	return ak;
    569 }
    570 
    571 unsigned ChannelInfo::GetAkickCount() const
    572 {
    573 	return this->akick->size();
    574 }
    575 
    576 void ChannelInfo::EraseAkick(unsigned index)
    577 {
    578 	if (this->akick->empty() || index >= this->akick->size())
    579 		return;
    580 
    581 	delete this->GetAkick(index);
    582 }
    583 
    584 void ChannelInfo::ClearAkick()
    585 {
    586 	while (!this->akick->empty())
    587 		delete this->akick->back();
    588 }
    589 
    590 const Anope::map<int16_t> &ChannelInfo::GetLevelEntries()
    591 {
    592 	return this->levels;
    593 }
    594 
    595 int16_t ChannelInfo::GetLevel(const Anope::string &priv) const
    596 {
    597 	if (PrivilegeManager::FindPrivilege(priv) == NULL)
    598 	{
    599 		Log(LOG_DEBUG) << "Unknown privilege " + priv;
    600 		return ACCESS_INVALID;
    601 	}
    602 
    603 	Anope::map<int16_t>::const_iterator it = this->levels.find(priv);
    604 	if (it == this->levels.end())
    605 		return 0;
    606 	return it->second;
    607 }
    608 
    609 void ChannelInfo::SetLevel(const Anope::string &priv, int16_t level)
    610 {
    611 	if (PrivilegeManager::FindPrivilege(priv) == NULL)
    612 	{
    613 		Log(LOG_DEBUG) << "Unknown privilege " + priv;
    614 		return;
    615 	}
    616 
    617 	this->levels[priv] = level;
    618 }
    619 
    620 void ChannelInfo::RemoveLevel(const Anope::string &priv)
    621 {
    622 	this->levels.erase(priv);
    623 }
    624 
    625 void ChannelInfo::ClearLevels()
    626 {
    627 	this->levels.clear();
    628 }
    629 
    630 Anope::string ChannelInfo::GetIdealBan(User *u) const
    631 {
    632 	int bt = this ? this->bantype : -1;
    633 	switch (bt)
    634 	{
    635 		case 0:
    636 			return "*!" + u->GetVIdent() + "@" + u->GetDisplayedHost();
    637 		case 1:
    638 			if (u->GetVIdent()[0] == '~')
    639 				return "*!*" + u->GetVIdent() + "@" + u->GetDisplayedHost();
    640 			else
    641 				return "*!" + u->GetVIdent() + "@" + u->GetDisplayedHost();
    642 		case 3:
    643 			return "*!" + u->Mask();
    644 		case 2:
    645 		default:
    646 			return "*!*@" + u->GetDisplayedHost();
    647 	}
    648 }
    649 
    650 ChannelInfo* ChannelInfo::Find(const Anope::string &name)
    651 {
    652 	registered_channel_map::const_iterator it = RegisteredChannelList->find(name);
    653 	if (it != RegisteredChannelList->end())
    654 	{
    655 		it->second->QueueUpdate();
    656 		return it->second;
    657 	}
    658 
    659 	return NULL;
    660 }
    661 
    662 bool IsFounder(const User *user, const ChannelInfo *ci)
    663 {
    664 	if (!user || !ci)
    665 		return false;
    666 
    667 	if (user->super_admin)
    668 		return true;
    669 
    670 	if (user->Account() && user->Account() == ci->GetFounder())
    671 		return true;
    672 
    673 	return false;
    674 }
    675 
    676 
    677 void ChannelInfo::AddChannelReference(const Anope::string &what)
    678 {
    679 	++references[what];
    680 }
    681 
    682 void ChannelInfo::RemoveChannelReference(const Anope::string &what)
    683 {
    684 	int &i = references[what];
    685 	if (--i <= 0)
    686 		references.erase(what);
    687 }
    688 
    689 void ChannelInfo::GetChannelReferences(std::deque<Anope::string> &chans)
    690 {
    691 	chans.clear();
    692 	for (Anope::map<int>::iterator it = references.begin(); it != references.end(); ++it)
    693 		chans.push_back(it->first);
    694 }