anope

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

cs_clone.cpp (7421B)

      1 /* ChanServ core 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 "module.h"
     13 #include "modules/bs_badwords.h"
     14 
     15 class CommandCSClone : public Command
     16 {
     17 	void CopySetting(ChannelInfo *ci, ChannelInfo *target_ci, const Anope::string &setting)
     18 	{
     19 		if (ci->HasExt(setting))
     20 			target_ci->Extend<bool>(setting);
     21 	}
     22 
     23 	void CopyAccess(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
     24 	{
     25 		std::set<Anope::string> masks;
     26 		unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1024");
     27 		unsigned count = 0;
     28 
     29 		for (unsigned i = 0; i < target_ci->GetAccessCount(); ++i)
     30 			masks.insert(target_ci->GetAccess(i)->Mask());
     31 
     32 		for (unsigned i = 0; i < ci->GetAccessCount(); ++i)
     33 		{
     34 			const ChanAccess *taccess = ci->GetAccess(i);
     35 			AccessProvider *provider = taccess->provider;
     36 
     37 			if (access_max && target_ci->GetDeepAccessCount() >= access_max)
     38 				break;
     39 
     40 			if (masks.count(taccess->Mask()))
     41 				continue;
     42 			masks.insert(taccess->Mask());
     43 
     44 			ChanAccess *newaccess = provider->Create();
     45 			newaccess->SetMask(taccess->Mask(), target_ci);
     46 			newaccess->creator = taccess->creator;
     47 			newaccess->last_seen = taccess->last_seen;
     48 			newaccess->created = taccess->created;
     49 			newaccess->AccessUnserialize(taccess->AccessSerialize());
     50 
     51 			target_ci->AddAccess(newaccess);
     52 
     53 			++count;
     54 		}
     55 
     56 		source.Reply(_("%d access entries from \002%s\002 have been cloned to \002%s\002."), count, ci->name.c_str(), target_ci->name.c_str());
     57 	}
     58 
     59 	void CopyAkick(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
     60 	{
     61 		target_ci->ClearAkick();
     62 		for (unsigned i = 0; i < ci->GetAkickCount(); ++i)
     63 		{
     64 			const AutoKick *akick = ci->GetAkick(i);
     65 			if (akick->nc)
     66 				target_ci->AddAkick(akick->creator, akick->nc, akick->reason, akick->addtime, akick->last_used);
     67 			else
     68 				target_ci->AddAkick(akick->creator, akick->mask, akick->reason, akick->addtime, akick->last_used);
     69 		}
     70 
     71 		source.Reply(_("All akick entries from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str());
     72 	}
     73 
     74 	void CopyBadwords(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
     75 	{
     76 		BadWords *target_badwords = target_ci->Require<BadWords>("badwords"),
     77 			*badwords = ci->Require<BadWords>("badwords");
     78 
     79 		if (!target_badwords || !badwords)
     80 		{
     81 			source.Reply(ACCESS_DENIED); // BotServ doesn't exist/badwords isn't loaded
     82 			return;
     83 		}
     84 
     85 		target_badwords->ClearBadWords();
     86 
     87 		for (unsigned i = 0; i < badwords->GetBadWordCount(); ++i)
     88 		{
     89 			const BadWord *bw = badwords->GetBadWord(i);
     90 			target_badwords->AddBadWord(bw->word, bw->type);
     91 		}
     92 
     93 		badwords->Check();
     94 		target_badwords->Check();
     95 
     96 		source.Reply(_("All badword entries from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str());
     97 	}
     98 
     99 	void CopyLevels(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
    100 	{
    101 		const Anope::map<int16_t> &cilevels = ci->GetLevelEntries();
    102 
    103 		for (Anope::map<int16_t>::const_iterator it = cilevels.begin(); it != cilevels.end(); ++it)
    104 		{
    105 			target_ci->SetLevel(it->first, it->second);
    106 		}
    107 
    108 		source.Reply(_("All level entries from \002%s\002 have been cloned into \002%s\002."), ci->name.c_str(), target_ci->name.c_str());
    109 	}
    110 
    111 public:
    112 	CommandCSClone(Module *creator) : Command(creator, "chanserv/clone", 2, 3)
    113 	{
    114 		this->SetDesc(_("Copy all settings from one channel to another"));
    115 		this->SetSyntax(_("\037channel\037 \037target\037 [\037what\037]"));
    116 	}
    117 
    118 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    119 	{
    120 		const Anope::string &channel = params[0];
    121 		const Anope::string &target = params[1];
    122 		Anope::string what = params.size() > 2 ? params[2] : "";
    123 
    124 		if (Anope::ReadOnly)
    125 		{
    126 			source.Reply(READ_ONLY_MODE);
    127 			return;
    128 		}
    129 
    130 		User *u = source.GetUser();
    131 		ChannelInfo *ci = ChannelInfo::Find(channel);
    132 		bool override = false;
    133 
    134 		if (ci == NULL)
    135 		{
    136 			source.Reply(CHAN_X_NOT_REGISTERED, channel.c_str());
    137 			return;
    138 		}
    139 
    140 		ChannelInfo *target_ci = ChannelInfo::Find(target);
    141 		if (!target_ci)
    142 		{
    143 			source.Reply(CHAN_X_NOT_REGISTERED, target.c_str());
    144 			return;
    145 		}
    146 
    147 		if (ci == target_ci)
    148 		{
    149 			source.Reply(_("Cannot clone channel \002%s\002 to itself!"), target.c_str());
    150 			return;
    151 		}
    152 
    153 		if (!source.IsFounder(ci) || !source.IsFounder(target_ci))
    154 		{
    155 			if (!source.HasPriv("chanserv/administration"))
    156 			{
    157 				source.Reply(ACCESS_DENIED);
    158 				return;
    159 			}
    160 			else
    161 				override = true;
    162 		}
    163 
    164 		if (what.equals_ci("ALL"))
    165 			what.clear();
    166 
    167 		if (what.empty())
    168 		{
    169 			delete target_ci;
    170 			target_ci = new ChannelInfo(*ci);
    171 			target_ci->name = target;
    172 			target_ci->time_registered = Anope::CurTime;
    173 			(*RegisteredChannelList)[target_ci->name] = target_ci;
    174 			target_ci->c = Channel::Find(target_ci->name);
    175 
    176 			target_ci->bi = NULL;
    177 			if (ci->bi)
    178 				ci->bi->Assign(u, target_ci);
    179 
    180 			if (target_ci->c)
    181 			{
    182 				target_ci->c->ci = target_ci;
    183 
    184 				target_ci->c->CheckModes();
    185 
    186 				target_ci->c->SetCorrectModes(u, true);
    187 			}
    188 
    189 			if (target_ci->c && !target_ci->c->topic.empty())
    190 			{
    191 				target_ci->last_topic = target_ci->c->topic;
    192 				target_ci->last_topic_setter = target_ci->c->topic_setter;
    193 				target_ci->last_topic_time = target_ci->c->topic_time;
    194 			}
    195 			else
    196 				target_ci->last_topic_setter = source.service->nick;
    197 
    198 			const Anope::string settings[] = { "NOAUTOOP", "CS_KEEP_MODES", "PEACE", "PERSIST", "RESTRICTED",
    199 				"CS_SECURE", "SECUREFOUNDER", "SECUREOPS", "SIGNKICK", "SIGNKICK_LEVEL", "CS_NO_EXPIRE" };
    200 
    201 			for (unsigned int i = 0; i < sizeof(settings) / sizeof(Anope::string); ++i)
    202 				CopySetting(ci, target_ci, settings[i]);
    203 
    204 			CopyAccess(source, ci, target_ci);
    205 			CopyAkick(source, ci, target_ci);
    206 			CopyBadwords(source, ci, target_ci);
    207 			CopyLevels(source, ci, target_ci);
    208 
    209 			FOREACH_MOD(OnChanRegistered, (target_ci));
    210 
    211 			source.Reply(_("All settings from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str());
    212 		}
    213 		else if (what.equals_ci("ACCESS"))
    214 		{
    215 			CopyAccess(source, ci, target_ci);
    216 		}
    217 		else if (what.equals_ci("AKICK"))
    218 		{
    219 			CopyAkick(source, ci, target_ci);
    220 		}
    221 		else if (what.equals_ci("BADWORDS"))
    222 		{
    223 			CopyBadwords(source, ci, target_ci);
    224 		}
    225 		else if (what.equals_ci("LEVELS"))
    226 		{
    227 			CopyLevels(source, ci, target_ci);
    228 		}
    229 		else
    230 		{
    231 			this->OnSyntaxError(source, "");
    232 			return;
    233 		}
    234 
    235 		Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to clone " << (what.empty() ? "everything from it" : what) << " to " << target_ci->name;
    236 	}
    237 
    238 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    239 	{
    240 		this->SendSyntax(source);
    241 		source.Reply(" ");
    242 		source.Reply(_("Copies all settings, access, akicks, etc from \002channel\002 to the\n"
    243 				"\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, \002BADWORDS\002,\n"
    244 				"or \002LEVELS\002 then only the respective settings are cloned.\n"
    245 				"You must be the founder of \037channel\037 and \037target\037."));
    246 		return true;
    247 	}
    248 };
    249 
    250 class CSClone : public Module
    251 {
    252 	CommandCSClone commandcsclone;
    253 
    254  public:
    255 	CSClone(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandcsclone(this)
    256 	{
    257 
    258 	}
    259 };
    260 
    261 MODULE_INIT(CSClone)