diff options
author | Adam <Adam@anope.org> | 2010-11-15 18:03:50 -0500 |
---|---|---|
committer | Adam <Adam@anope.org> | 2010-12-12 19:33:58 -0500 |
commit | 1625a5af0ce1368e46705a2f72578eda463f3650 (patch) | |
tree | 37b2783e32684aebc879d17f05dcf276f799beaa | |
parent | 2e9a632e1410fbeadc1b7a0418cf66247e0e458c (diff) |
Added /chanserv clone command
-rw-r--r-- | data/example.conf | 2 | ||||
-rw-r--r-- | docs/Changes.conf | 1 | ||||
-rw-r--r-- | include/language.h | 7 | ||||
-rw-r--r-- | include/regchannel.h | 5 | ||||
-rw-r--r-- | modules/core/cs_clone.cpp | 181 | ||||
-rw-r--r-- | modules/core/cs_register.cpp | 14 | ||||
-rw-r--r-- | src/channels.cpp | 4 | ||||
-rw-r--r-- | src/language.cpp | 19 | ||||
-rw-r--r-- | src/regchannel.cpp | 47 |
9 files changed, 271 insertions, 9 deletions
diff --git a/data/example.conf b/data/example.conf index 4655875ca..aa6964e16 100644 --- a/data/example.conf +++ b/data/example.conf @@ -1044,7 +1044,7 @@ chanserv * The core modules to load for ChanServ. This is a space separated list that corresponds * to the base names of the modules for ChanServ. This directive is optional, but highly recommended. */ - modules = "cs_help cs_register cs_set cs_saset cs_saset_noexpire cs_set_bantype cs_set_description cs_set_entrymsg cs_set_founder cs_set_keeptopic cs_set_mlock cs_set_opnotice cs_set_peace cs_set_persist cs_set_private cs_set_restricted cs_set_secure cs_set_securefounder cs_set_secureops cs_set_signkick cs_set_successor cs_set_topiclock cs_set_xop cs_xop cs_access cs_akick cs_drop cs_ban cs_clear cs_modes cs_getkey cs_invite cs_kick cs_list cs_topic cs_info cs_forbid cs_suspend cs_status cs_unban" + modules = "cs_help cs_register cs_set cs_saset cs_saset_noexpire cs_set_bantype cs_set_description cs_set_entrymsg cs_set_founder cs_set_keeptopic cs_set_mlock cs_set_opnotice cs_set_peace cs_set_persist cs_set_private cs_set_restricted cs_set_secure cs_set_securefounder cs_set_secureops cs_set_signkick cs_set_successor cs_set_topiclock cs_set_xop cs_xop cs_access cs_akick cs_drop cs_ban cs_clear cs_modes cs_getkey cs_invite cs_kick cs_list cs_topic cs_info cs_forbid cs_suspend cs_status cs_unban cs_clone" /* * The default options for newly registered channels. Note that changing these options diff --git a/docs/Changes.conf b/docs/Changes.conf index b453fec76..792477f12 100644 --- a/docs/Changes.conf +++ b/docs/Changes.conf @@ -1,6 +1,7 @@ Anope Version 1.9.4 ------------------- memoserv:modules added ms_ignore +chanserv:modules added cs_clone Anope Version 1.9.3 ------------------ diff --git a/include/language.h b/include/language.h index 51f3e1cfc..5406e3480 100644 --- a/include/language.h +++ b/include/language.h @@ -568,6 +568,11 @@ enum LanguageString CHAN_CLEARED_OPS, CHAN_CLEARED_USERS, CHAN_CLEARED_INVITES, + CHAN_CLONED, + CHAN_CLONED_ACCESS, + CHAN_CLONED_AKICK, + CHAN_CLONED_BADWORDS, + CHAN_CLONE_SYNTAX, CHAN_GETKEY_SYNTAX, CHAN_GETKEY_NOKEY, CHAN_GETKEY_KEY, @@ -1287,6 +1292,7 @@ enum LanguageString CHAN_HELP_CMD_OWNER, CHAN_HELP_CMD_PROTECT, CHAN_HELP_CMD_DEOP, + CHAN_HELP_CMD_CLONE, CHAN_HELP, CHAN_HELP_EXPIRES, CHAN_HELP_REGISTER, @@ -1362,6 +1368,7 @@ enum LanguageString CHAN_HELP_TOPIC, CHAN_HELP_CLEAR, CHAN_HELP_GETKEY, + CHAN_HELP_CLONE, CHAN_SERVADMIN_HELP, CHAN_SERVADMIN_HELP_DROP, CHAN_SERVADMIN_HELP_SET_NOEXPIRE, diff --git a/include/regchannel.h b/include/regchannel.h index 689857c2d..1300b9cf4 100644 --- a/include/regchannel.h +++ b/include/regchannel.h @@ -78,6 +78,11 @@ class CoreExport ChannelInfo : public Extensible, public Flags<ChannelInfoFlag, */ ChannelInfo(const Anope::string &chname); + /** Copy constructor + * @param ci The ChannelInfo to copy settings to + */ + ChannelInfo(ChannelInfo *ci); + /** Default destructor */ ~ChannelInfo(); diff --git a/modules/core/cs_clone.cpp b/modules/core/cs_clone.cpp new file mode 100644 index 000000000..a6568290c --- /dev/null +++ b/modules/core/cs_clone.cpp @@ -0,0 +1,181 @@ +/* ChanServ core functions + * + * (C) 2003-2010 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + +/*************************************************************************/ + +#include "module.h" + +class CommandCSClone : public Command +{ +public: + CommandCSClone() : Command("CLONE", 2, 3) + { + } + + CommandReturn Execute(User *u, const std::vector<Anope::string> ¶ms) + { + const Anope::string &channel = params[0]; + const Anope::string &target = params[1]; + Anope::string what = params.size() > 2 ? params[2] : ""; + + ChannelInfo *ci = cs_findchan(channel); + if (!check_access(u, ci, CA_SET)) + { + u->SendMessage(ChanServ, ACCESS_DENIED); + return MOD_CONT; + } + ChannelInfo *target_ci = cs_findchan(target); + if (!target_ci) + { + u->SendMessage(ChanServ, CHAN_X_NOT_REGISTERED, target.c_str()); + return MOD_CONT; + } + if (!IsFounder(u, ci) || !IsFounder(u, target_ci)) + { + u->SendMessage(ChanServ, ACCESS_DENIED); + return MOD_CONT; + } + + if (Config->CSMaxReg && u->Account()->channelcount >= Config->CSMaxReg && !u->Account()->HasPriv("chanserv/no-register-limit")) + { + u->SendMessage(ChanServ, u->Account()->channelcount > Config->CSMaxReg ? CHAN_EXCEEDED_CHANNEL_LIMIT : CHAN_REACHED_CHANNEL_LIMIT, Config->CSMaxReg); + return MOD_CONT; + } + + if (what.equals_ci("ALL")) + what.clear(); + + if (what.empty()) + { + delete target_ci; + target_ci = new ChannelInfo(ci); + target_ci->name = target; + RegisteredChannelList[target_ci->name] = target_ci; + target_ci->c = findchan(target_ci->name); + if (target_ci->c) + { + target_ci->c->ci = target_ci; + + check_modes(target_ci->c); + + ChannelMode *cm; + if (u->FindChannel(target_ci->c) != NULL) + { + /* On most ircds you do not receive the admin/owner mode till its registered */ + if ((cm = ModeManager::FindChannelModeByName(CMODE_OWNER))) + target_ci->c->SetMode(NULL, cm, u->nick); + else if ((cm = ModeManager::FindChannelModeByName(CMODE_PROTECT))) + target_ci->c->RemoveMode(NULL, cm, u->nick); + } + + /* Mark the channel as persistant */ + if (target_ci->c->HasMode(CMODE_PERM)) + target_ci->SetFlag(CI_PERSIST); + /* Persist may be in def cflags, set it here */ + else if (target_ci->HasFlag(CI_PERSIST) && (cm = ModeManager::FindChannelModeByName(CMODE_PERM))) + target_ci->c->SetMode(NULL, CMODE_PERM); + + if (target_ci->bi && target_ci->c->FindUser(target_ci->bi) == NULL) + target_ci->bi->Join(target_ci->c); + } + + if (target_ci->c && !target_ci->c->topic.empty()) + { + target_ci->last_topic = target_ci->c->topic; + target_ci->last_topic_setter = target_ci->c->topic_setter; + target_ci->last_topic_time = target_ci->c->topic_time; + } + else + target_ci->last_topic_setter = Config->s_ChanServ; + + FOREACH_MOD(I_OnChanRegistered, OnChanRegistered(target_ci)); + + u->SendMessage(ChanServ, CHAN_CLONED, channel.c_str(), target.c_str()); + } + else if (what.equals_ci("ACCESS")) + { + target_ci->ClearAccess(); + for (unsigned i = 0; i < ci->GetAccessCount(); ++i) + { + ChanAccess *access = ci->GetAccess(i); + target_ci->AddAccess(access->nc, access->level, access->creator, access->last_seen); + } + + u->SendMessage(ChanServ, CHAN_CLONED_ACCESS, channel.c_str(), target.c_str()); + } + else if (what.equals_ci("AKICK")) + { + target_ci->ClearAkick(); + for (unsigned i = 0; i < ci->GetAkickCount(); ++i) + { + AutoKick *akick = ci->GetAkick(i); + if (akick->HasFlag(AK_ISNICK)) + target_ci->AddAkick(akick->creator, akick->nc, akick->reason, akick->addtime, akick->last_used); + else + target_ci->AddAkick(akick->creator, akick->mask, akick->reason, akick->addtime, akick->last_used); + } + + u->SendMessage(ChanServ, CHAN_CLONED_AKICK, channel.c_str(), target.c_str()); + } + else if (what.equals_ci("BADWORDS")) + { + target_ci->ClearBadWords(); + for (unsigned i = 0; i < ci->GetBadWordCount(); ++i) + { + BadWord *bw = ci->GetBadWord(i); + target_ci->AddBadWord(bw->word, bw->type); + } + + u->SendMessage(ChanServ, CHAN_CLONED_BADWORDS, channel.c_str(), target.c_str()); + } + else + { + this->OnSyntaxError(u, ""); + return MOD_CONT; + } + + Log(LOG_COMMAND, u, this, ci) << "to clone it to " << target_ci->name; + + return MOD_CONT; + } + + bool OnHelp(User *u, const Anope::string &subcommand) + { + u->SendMessage(ChanServ, CHAN_HELP_CLONE); + return true; + } + + void OnSyntaxError(User *u, const Anope::string &subcommand) + { + SyntaxError(ChanServ, u, "CLONE", CHAN_CLONE_SYNTAX); + } + + void OnServHelp(User *u) + { + u->SendMessage(ChanServ, CHAN_HELP_CMD_CLONE); + } +}; + +class CSClone : public Module +{ + CommandCSClone commandcsclone; + + public: + CSClone(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator) + { + this->SetAuthor("Anope"); + this->SetType(CORE); + + this->AddCommand(ChanServ, &commandcsclone); + } +}; + +MODULE_INIT(CSClone) diff --git a/modules/core/cs_register.cpp b/modules/core/cs_register.cpp index c488bfc4a..bef71a726 100644 --- a/modules/core/cs_register.cpp +++ b/modules/core/cs_register.cpp @@ -71,11 +71,15 @@ class CommandCSRegister : public Command if (c) { check_modes(c); - /* On most ircds you do not receive the admin/owner mode till its registered */ - if ((cm = ModeManager::FindChannelModeByName(CMODE_OWNER))) - c->SetMode(NULL, cm, u->nick); - else if ((cm = ModeManager::FindChannelModeByName(CMODE_PROTECT))) - c->RemoveMode(NULL, cm, u->nick); + + if (u->FindChannel(c) != NULL) + { + /* On most ircds you do not receive the admin/owner mode till its registered */ + if ((cm = ModeManager::FindChannelModeByName(CMODE_OWNER))) + c->SetMode(NULL, cm, u->nick); + else if ((cm = ModeManager::FindChannelModeByName(CMODE_PROTECT))) + c->RemoveMode(NULL, cm, u->nick); + } /* Mark the channel as persistant */ if (c->HasMode(CMODE_PERM)) diff --git a/src/channels.cpp b/src/channels.cpp index 6e1e25f23..72e573029 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -566,7 +566,7 @@ void Channel::SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶m, else if (cm->Type == MODE_STATUS) { User *u = finduser(param); - if (u && HasUserStatus(u, debug_cast<ChannelModeStatus *>(cm))) + if (!u || HasUserStatus(u, debug_cast<ChannelModeStatus *>(cm))) return; } else if (cm->Type == MODE_LIST) @@ -607,7 +607,7 @@ void Channel::RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string ¶ else if (cm->Type == MODE_STATUS) { User *u = finduser(param); - if (u && !HasUserStatus(u, debug_cast<ChannelModeStatus *>(cm))) + if (!u || !HasUserStatus(u, debug_cast<ChannelModeStatus *>(cm))) return; } else if (cm->Type == MODE_LIST) diff --git a/src/language.cpp b/src/language.cpp index a49508d0c..4a89ac626 100644 --- a/src/language.cpp +++ b/src/language.cpp @@ -1322,6 +1322,16 @@ const char *const language_strings[LANG_STRING_COUNT] = { _("All users have been kicked from channel %s."), /* CHAN_CLEARED_INVITES */ _("All invites on channel %s have been removed."), + /* CHAN_CLONED */ + _("All settings from \002%s\002 have been transferred to \002%s\002"), + /* CHAN_CLONED_ACCESS */ + _("All access entries from \002%s\002 have been transferred to \002%s\002"), + /* CHAN_CLONED_AKICK */ + _("All akick entries from \002%s\002 have been transferred to \002%s\002"), + /* CHAN_CLONED_BADWORDS */ + _("All badword entries from \002%s\002 have been transferred to \002%s\002"), + /* CHAN_CLONE_SYNTAX */ + _("CLONE \037channel\037 \037target\037"), /* CHAN_GETKEY_SYNTAX */ _("GETKEY channel"), /* CHAN_GETKEY_NOKEY */ @@ -3354,6 +3364,8 @@ const char *const language_strings[LANG_STRING_COUNT] = { _(" PROTECT Protects a selected nick on a channel"), /* CHAN_HELP_CMD_DEOP */ _(" DEOP Deops a selected nick on a channel"), + /* CHAN_HELP_CMD_CLONE */ + _(" CLONE Copy all settings from one channel to another"), /* CHAN_HELP */ _("%S allows you to register and control various\n" "aspects of channels. %S can often prevent\n" @@ -4131,6 +4143,13 @@ const char *const language_strings[LANG_STRING_COUNT] = { _("Syntax: GETKEY channel\n" " \n" "Returns the key of the given channel."), + /* CHAN_HELP_CLONE */ + _("Syntax: \002CLONE \037channel\037 \037target\037 [all | access | akick | badwords]\002\n" + " \n" + "Copies all settings, access, akicks, etc from channel to the\n" + "target channel. If access, akick, or badwords is specified then only\n" + "the respective settings are transferred. You must have founder level\n" + "access to \037channel\037 and \037target\037."), /* CHAN_SERVADMIN_HELP */ _(" \n" "Services Operators can also drop any channel without needing\n" diff --git a/src/regchannel.cpp b/src/regchannel.cpp index b4cded05b..b4c42cb82 100644 --- a/src/regchannel.cpp +++ b/src/regchannel.cpp @@ -52,7 +52,7 @@ ChannelInfo::ChannelInfo(const Anope::string &chname) this->memos.memomax = Config->MSMaxMemos; this->last_used = this->time_registered = Anope::CurTime; - this->ttb = new int16[2 * TTB_SIZE]; + this->ttb = new int16[TTB_SIZE]; for (int i = 0; i < TTB_SIZE; ++i) this->ttb[i] = 0; @@ -61,6 +61,51 @@ ChannelInfo::ChannelInfo(const Anope::string &chname) RegisteredChannelList[this->name] = this; } +/** Copy constructor + * @param ci The ChannelInfo to copy settings to + */ +ChannelInfo::ChannelInfo(ChannelInfo *ci) +{ + *this = *ci; + + if (this->founder) + ++this->founder->channelcount; + + this->access.clear(); + this->akick.clear(); + this->badwords.clear(); + + if (this->bi) + ++this->bi->chancount; + + this->ttb = new int16[TTB_SIZE]; + for (int i = 0; i < TTB_SIZE; ++i) + this->ttb[i] = ci->ttb[i]; + + this->levels = new int16[CA_SIZE]; + for (int i = 0; i < CA_SIZE; ++i) + this->levels[i] = ci->levels[i]; + + for (unsigned i = 0; i < ci->GetAccessCount(); ++i) + { + ChanAccess *access = ci->GetAccess(i); + this->AddAccess(access->nc, access->level, access->creator, access->last_seen); + } + for (unsigned i = 0; i < ci->GetAkickCount(); ++i) + { + AutoKick *akick = ci->GetAkick(i); + if (akick->HasFlag(AK_ISNICK)) + this->AddAkick(akick->creator, akick->nc, akick->reason, akick->addtime, akick->last_used); + else + this->AddAkick(akick->creator, akick->mask, akick->reason, akick->addtime, akick->last_used); + } + for (unsigned i = 0; i < ci->GetBadWordCount(); ++i) + { + BadWord *bw = ci->GetBadWord(i); + this->AddBadWord(bw->word, bw->type); + } +} + /** Default destructor, cleans up the channel complete and removes it from the internal list */ ChannelInfo::~ChannelInfo() |