diff options
-rw-r--r-- | data/example.conf | 7 | ||||
-rw-r--r-- | docs/Changes.conf | 1 | ||||
-rw-r--r-- | include/config.h | 2 | ||||
-rw-r--r-- | include/extensible.h | 8 | ||||
-rw-r--r-- | include/extern.h | 2 | ||||
-rw-r--r-- | include/language.h | 9 | ||||
-rw-r--r-- | modules/core/cs_ban.cpp | 2 | ||||
-rw-r--r-- | modules/core/ns_ajoin.cpp | 240 | ||||
-rw-r--r-- | modules/extra/cs_tban.cpp | 2 | ||||
-rw-r--r-- | src/botserv.cpp | 3 | ||||
-rw-r--r-- | src/config.cpp | 1 | ||||
-rw-r--r-- | src/language.cpp | 22 | ||||
-rw-r--r-- | src/regchannel.cpp | 2 | ||||
-rw-r--r-- | src/users.cpp | 7 |
14 files changed, 293 insertions, 15 deletions
diff --git a/data/example.conf b/data/example.conf index 66b65c413..c89e9ac25 100644 --- a/data/example.conf +++ b/data/example.conf @@ -877,7 +877,7 @@ nickserv * The core modules to load for NickServ. This is a space separated list that corresponds * to the base names of the modules for NickServ. This directive is optional, but highly recommended. */ - modules = "ns_help ns_register ns_group ns_identify ns_access ns_set ns_saset ns_set_autoop ns_set_email ns_set_greet ns_set_hide ns_set_kill ns_set_language ns_set_message ns_set_private ns_set_secure ns_saset_noexpire ns_drop ns_recover ns_release ns_sendpass ns_ghost ns_alist ns_info ns_list ns_logout ns_status ns_update ns_getpass ns_getemail ns_forbid ns_suspend ns_resetpass" + modules = "ns_help ns_register ns_group ns_identify ns_access ns_set ns_saset ns_set_autoop ns_set_email ns_set_greet ns_set_hide ns_set_kill ns_set_language ns_set_message ns_set_private ns_set_secure ns_saset_noexpire ns_drop ns_recover ns_release ns_sendpass ns_ghost ns_alist ns_info ns_list ns_logout ns_status ns_update ns_getpass ns_getemail ns_forbid ns_suspend ns_resetpass ns_ajoin" /* * Force users to give an e-mail address when they register a nick. This directive @@ -1046,6 +1046,11 @@ nickserv * This directive is optional. */ addaccessonreg = yes + + /* + * The maximum number of channels a user can have on NickServ's AJOIN command. + */ + ajoinmax = 10 } /* diff --git a/docs/Changes.conf b/docs/Changes.conf index fab3b6b26..ac58669d8 100644 --- a/docs/Changes.conf +++ b/docs/Changes.conf @@ -5,6 +5,7 @@ chanserv:modules added cs_clone and cs_mode nickserv:suspendexpire and nickserv:forbidexpire added chanserv:suspendexpire and chanserv:forbidexpire added added cs_entrymsg +nickserv:modules added ns_ajoin Anope Version 1.9.3 ------------------ diff --git a/include/config.h b/include/config.h index aef620b3c..4a5fc0d97 100644 --- a/include/config.h +++ b/include/config.h @@ -627,6 +627,8 @@ class CoreExport ServerConfig bool NSModeOnID; /* Add the users hostnask their access list when they register */ bool NSAddAccessOnReg; + /* Maximum number of channels on AJoin */ + unsigned AJoinMax; /* Default flags for newly registered channels */ Flags<ChannelInfoFlag, CI_END> CSDefFlags; diff --git a/include/extensible.h b/include/extensible.h index 62413f131..2d7fb5509 100644 --- a/include/extensible.h +++ b/include/extensible.h @@ -28,7 +28,7 @@ template<typename T> class ExtensibleItemRegular : public ExtensibleItemBase public: ExtensibleItemRegular(T item) : Item(item) { } virtual ~ExtensibleItemRegular() { } - T GetItem() const { return Item; } + T &GetItem() { return Item; } }; /** Class used to represent an extensible item that holds a pointer @@ -41,7 +41,7 @@ template<typename T> class ExtensibleItemPointer : public ExtensibleItemBase public: ExtensibleItemPointer(T *item) : Item(item) { } virtual ~ExtensibleItemPointer() { delete Item; } - T *GetItem() const { return Item; } + T *GetItem() { return Item; } }; /** Class used to represent an extensible item that holds a pointer to an arrray @@ -54,7 +54,7 @@ template<typename T> class ExtensibleItemPointerArray : public ExtensibleItemBas public: ExtensibleItemPointerArray(T *item) : Item(item) { } virtual ~ExtensibleItemPointerArray() { delete [] Item; } - T *GetItem() const { return Item; } + T *GetItem() { return Item; } }; class CoreExport Extensible : public Base @@ -108,7 +108,7 @@ class CoreExport Extensible : public Base */ void Extend(const Anope::string &key) { - this->Extend(key, new ExtensibleItemRegular<char *>(NULL)); + this->Extend(key, new ExtensibleItemPointer<char *>(NULL)); } /** Shrink an Extensible class. diff --git a/include/extern.h b/include/extern.h index b2e33dd83..025525186 100644 --- a/include/extern.h +++ b/include/extern.h @@ -343,7 +343,7 @@ E User *do_nick(const Anope::string &source, const Anope::string &nick, const An E void do_umode(const Anope::string &, const Anope::string &user, const Anope::string &modes); E void do_kill(User *user, const Anope::string &reason); -E bool is_excepted(ChannelInfo *ci, User *user); +E bool matches_list(Channel *c, User *user, ChannelModeName mode); E bool is_excepted_mask(ChannelInfo *ci, const Anope::string &mask); E Anope::string create_mask(User *u); diff --git a/include/language.h b/include/language.h index c61a870d9..a0d728772 100644 --- a/include/language.h +++ b/include/language.h @@ -179,6 +179,13 @@ enum LanguageString NICK_ACCESS_LIST_X, NICK_ACCESS_LIST_EMPTY, NICK_ACCESS_LIST_X_EMPTY, + NICK_AJOIN_SYNTAX, + NICK_AJOIN_LIST_EMPTY, + NICK_AJOIN_LIST_HEAD, + NICK_AJOIN_LIST_FULL, + NICK_AJOIN_ADDED, + NICK_AJOIN_NOTFOUND, + NICK_AJOIN_DELETED, NICK_STATUS_REPLY, NICK_INFO_SYNTAX, NICK_INFO_REALNAME, @@ -1176,6 +1183,7 @@ enum LanguageString NICK_HELP_CMD_FORBID, NICK_HELP_CMD_SUSPEND, NICK_HELP_CMD_UNSUSPEND, + NICK_HELP_CMD_AJOIN, NICK_HELP, NICK_HELP_FOOTER, NICK_HELP_EXPIRES, @@ -1246,6 +1254,7 @@ enum LanguageString NICK_HELP_CONFIRM, NICK_HELP_CONFIRM_OPER, NICK_HELP_RESEND, + NICK_HELP_AJOIN, NICK_SERVADMIN_HELP, NICK_SERVADMIN_HELP_LOGOUT, NICK_SERVADMIN_HELP_DROP, diff --git a/modules/core/cs_ban.cpp b/modules/core/cs_ban.cpp index dc56bb995..8ff5319fb 100644 --- a/modules/core/cs_ban.cpp +++ b/modules/core/cs_ban.cpp @@ -47,7 +47,7 @@ class CommandCSBan : public Command * Dont ban/kick the user on channels where he is excepted * to prevent services <-> server wars. */ - else if (ModeManager::FindChannelModeByName(CMODE_EXCEPT) && is_excepted(ci, u2)) + else if (matches_list(ci->c, u2, CMODE_EXCEPT)) source.Reply(CHAN_EXCEPTED, u2->nick.c_str(), ci->name.c_str()); else if (u2->IsProtected()) source.Reply(ACCESS_DENIED); diff --git a/modules/core/ns_ajoin.cpp b/modules/core/ns_ajoin.cpp new file mode 100644 index 000000000..9b1de33d3 --- /dev/null +++ b/modules/core/ns_ajoin.cpp @@ -0,0 +1,240 @@ +/* NickServ core functions + * + * (C) 2003-2011 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 CommandNSAJoin : public Command +{ + void DoList(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + std::vector<std::pair<Anope::string, Anope::string> > channels; + source.u->Account()->GetExtRegular("ns_ajoin_channels", channels); + + if (channels.empty()) + source.Reply(NICK_AJOIN_LIST_EMPTY); + else + { + source.Reply(NICK_AJOIN_LIST_HEAD); + for (unsigned i = 0; i < channels.size(); ++i) + source.Reply(" %3d %-23s %s", i + 1, channels[i].first.c_str(), channels[i].second.c_str()); + } + } + + void DoAdd(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + std::vector<std::pair<Anope::string, Anope::string> > channels; + source.u->Account()->GetExtRegular("ns_ajoin_channels", channels); + + if (channels.size() >= Config->AJoinMax) + source.Reply(NICK_AJOIN_LIST_FULL); + else if (ircdproto->IsChannelValid(params[1]) == false) + source.Reply(CHAN_X_INVALID, params[1].c_str()); + else + { + channels.push_back(std::make_pair(params[1], params.size() > 2 ? params[2] : "")); + source.Reply(NICK_AJOIN_ADDED, params[1].c_str()); + source.u->Account()->Extend("ns_ajoin_channels", new ExtensibleItemRegular<std::vector< + std::pair<Anope::string, Anope::string> > >(channels)); + } + } + + void DoDel(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + std::vector<std::pair<Anope::string, Anope::string> > channels; + source.u->Account()->GetExtRegular("ns_ajoin_channels", channels); + + unsigned i; + for (i = 0; i < channels.size(); ++i) + if (channels[i].first.equals_ci(params[1])) + break; + + if (i == channels.size()) + source.Reply(NICK_AJOIN_NOTFOUND, params[1].c_str()); + else + { + channels.erase(channels.begin() + i); + source.Reply(NICK_AJOIN_DELETED, params[1].c_str()); + } + } + + public: + CommandNSAJoin() : Command("AJOIN", 1, 3) + { + } + + CommandReturn Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) + { + if (params[0].equals_ci("LIST")) + this->DoList(source, params); + else if (params.size() < 2) + this->OnSyntaxError(source, ""); + else if (params[0].equals_ci("ADD")) + this->DoAdd(source, params); + else if (params[0].equals_ci("DEL")) + this->DoDel(source, params); + else + this->OnSyntaxError(source, ""); + + return MOD_CONT; + } + + bool OnHelp(CommandSource &source, const Anope::string &subcommand) + { + source.Reply(NICK_HELP_AJOIN); + return true; + } + + void OnSyntaxError(CommandSource &source, const Anope::string &subcommand) + { + SyntaxError(source, "AJOIN", NICK_AJOIN_SYNTAX); + } + + void OnServHelp(CommandSource &source) + { + source.Reply(NICK_HELP_CMD_AJOIN); + } +}; + +class NSAJoin : public Module +{ + CommandNSAJoin commandnsajoin; + + public: + NSAJoin(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator) + { + this->SetAuthor("Anope"); + this->SetType(CORE); + + this->AddCommand(NickServ, &commandnsajoin); + + Implementation i[] = { I_OnNickIdentify, I_OnDatabaseWriteMetadata, I_OnDatabaseReadMetadata }; + ModuleManager::Attach(i, this, 3); + } + + void OnNickIdentify(User *u) + { + std::vector<std::pair<Anope::string, Anope::string> > channels; + u->Account()->GetExtRegular("ns_ajoin_channels", channels); + + for (unsigned i = 0; i < channels.size(); ++i) + { + Channel *c = findchan(channels[i].first); + ChannelInfo *ci = c != NULL? c->ci : cs_findchan(channels[i].first); + if (c == NULL && ci != NULL) + c = ci->c; + + bool need_invite = false; + Anope::string key = channels[i].second; + + if (ci != NULL) + { + if (ci->HasFlag(CI_SUSPENDED) || ci->HasFlag(CI_FORBIDDEN)) + continue; + } + if (c != NULL) + { + if (c->FindUser(u) != NULL) + continue; + else if (c->HasMode(CMODE_OPERONLY) && !u->HasMode(UMODE_OPER)) + continue; + else if (c->HasMode(CMODE_ADMINONLY) && !u->HasMode(UMODE_ADMIN)) + continue; + else if (c->HasMode(CMODE_SSL) && !u->HasMode(UMODE_SSL)) + continue; + else if (matches_list(c, u, CMODE_BAN) == true && matches_list(c, u, CMODE_EXCEPT) == false) + need_invite = true; + else if (c->HasMode(CMODE_INVITE) && matches_list(c, u, CMODE_INVITEOVERRIDE) == false) + need_invite = true; + + if (c->HasMode(CMODE_KEY)) + { + Anope::string k; + if (c->GetParam(CMODE_KEY, k)) + { + if (check_access(u, ci, CA_GETKEY)) + key = k; + else if (key != k) + need_invite = true; + } + } + if (c->HasMode(CMODE_LIMIT)) + { + Anope::string l; + if (c->GetParam(CMODE_LIMIT, l)) + { + try + { + unsigned limit = convertTo<unsigned>(l); + if (c->users.size() >= limit) + need_invite = true; + } + catch (const ConvertException &) { } + } + } + } + + if (need_invite) + { + if (!check_access(u, ci, CA_INVITE)) + continue; + ircdproto->SendInvite(NickServ, channels[i].first, u->nick); + } + + ircdproto->SendSVSJoin(NickServ->nick, u->nick, channels[i].first, key); + } + } + + void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), NickCore *nc) + { + std::vector<std::pair<Anope::string, Anope::string> > channels; + nc->GetExtRegular("ns_ajoin_channels", channels); + + Anope::string chans; + for (unsigned i = 0; i < channels.size(); ++i) + chans += " " + channels[i].first + "," + channels[i].second; + + if (!chans.empty()) + { + chans.erase(chans.begin()); + WriteMetadata("NS_AJOIN", chans); + } + } + + EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> ¶ms) + { + if (key == "NS_AJOIN") + { + std::vector<std::pair<Anope::string, Anope::string> > channels; + bool valid = nc->GetExtRegular("ns_ajoin_channels", channels); + + for (unsigned i = 0; i < params.size(); ++i) + { + Anope::string chan, chankey; + commasepstream sep(params[0]); + sep.GetToken(chan); + sep.GetToken(chankey); + + channels.push_back(std::make_pair(chan, chankey)); + } + + nc->Extend("ns_ajoin_channels", new ExtensibleItemRegular<std::vector< + std::pair<Anope::string, Anope::string> > >(channels)); + + return EVENT_STOP; + } + + return EVENT_CONTINUE; + } +}; + +MODULE_INIT(NSAJoin) diff --git a/modules/extra/cs_tban.cpp b/modules/extra/cs_tban.cpp index e40e16bc7..35757ff1e 100644 --- a/modules/extra/cs_tban.cpp +++ b/modules/extra/cs_tban.cpp @@ -41,7 +41,7 @@ static bool CanBanUser(Channel *c, User *u, User *u2) bool ok = false; if (!check_access(u, ci, CA_BAN)) u->SendMessage(ChanServ, ACCESS_DENIED); - else if (is_excepted(ci, u2)) + else if (matches_list(c, u2, CMODE_EXCEPT)) u->SendMessage(ChanServ, CHAN_EXCEPTED, u2->nick.c_str(), ci->name.c_str()); else if (u2->IsProtected()) u->SendMessage(ChanServ, ACCESS_DENIED); diff --git a/src/botserv.cpp b/src/botserv.cpp index 78e29451a..fac49761d 100644 --- a/src/botserv.cpp +++ b/src/botserv.cpp @@ -329,7 +329,6 @@ void botchanmsgs(User *u, ChannelInfo *ci, const Anope::string &buf) { Anope::string message = sep.GetRemaining(); - EventReturn MOD_RESULT; FOREACH_RESULT(I_OnPreCommandRun, OnPreCommandRun(u, ci->bi, command, message, ci)); if (MOD_RESULT == EVENT_STOP) return; @@ -529,7 +528,7 @@ void bot_raw_ban(User *requester, ChannelInfo *ci, User *u, const Anope::string if (ci->HasFlag(CI_PEACE) && !requester->nick.equals_ci(u->nick) && u_level >= req_level) return; - if (ModeManager::FindChannelModeByName(CMODE_EXCEPT) && is_excepted(ci, u) == 1) + if (matches_list(ci->c, u, CMODE_EXCEPT)) { ircdproto->SendPrivmsg(ci->bi, ci->name, "%s", GetString(requester, BOT_EXCEPT).c_str()); return; diff --git a/src/config.cpp b/src/config.cpp index 330594c13..9804161b1 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1115,6 +1115,7 @@ void ServerConfig::Read() {"nickserv", "strictprivileges", "no", new ValueContainerBool(&this->NSStrictPrivileges), DT_BOOLEAN, NoValidation}, {"nickserv", "modeonid", "no", new ValueContainerBool(&this->NSModeOnID), DT_BOOLEAN, NoValidation}, {"nickserv", "addaccessonreg", "no", new ValueContainerBool(&this->NSAddAccessOnReg), DT_BOOLEAN, NoValidation}, + {"nickserv", "ajoinmax", "10", new ValueContainerUInt(&this->AJoinMax), DT_UINTEGER, NoValidation}, {"mail", "usemail", "no", new ValueContainerBool(&this->UseMail), DT_BOOLEAN, ValidateEmailReg}, {"mail", "sendmailpath", "", new ValueContainerString(&this->SendMailPath), DT_STRING, ValidateMail}, {"mail", "sendfrom", "", new ValueContainerString(&this->SendFrom), DT_STRING, ValidateMail}, diff --git a/src/language.cpp b/src/language.cpp index f6a2d432e..e91f45638 100644 --- a/src/language.cpp +++ b/src/language.cpp @@ -505,6 +505,21 @@ const char *const language_strings[LANG_STRING_COUNT] = { _("Your access list is empty."), /* NICK_ACCESS_LIST_X_EMPTY */ _("Access list for %s is empty."), + /* NICK_AJOIN_SYNTAX */ + _("AJOIN {ADD | DEL | LIST} [\037channel\037] [\037key\037]"), + /* NICK_AJOIN_LIST_EMPTY */ + _("Your auto join list is empty."), + /* NICK_AJOIN_LIST_HEAD */ + _("Your auto join list:\n" + " Num Channel Key"), + /* NICK_AJOIN_LIST_FULL */ + _("Your auto join list is full."), + /* NICK_AJOIN_ADDED */ + _("Added %s to your auto join list."), + /* NICK_AJOIN_NOTFOUND */ + _("%s was not found on your auto join list."), + /* NICK_AJOIN_DELETED */ + _("%s was removed from your auto join list."), /* NICK_STATUS_REPLY */ _("STATUS %s %d %s"), /* NICK_INFO_SYNTAX */ @@ -2671,6 +2686,8 @@ const char *const language_strings[LANG_STRING_COUNT] = { _(" SUSPEND Suspend a given nick"), /* NICK_HELP_CMD_UNSUSPEND */ _(" UNSUSPEND Unsuspend a given nick"), + /* NICK_HELP_CMD_AJOIN */ + _(" AJOIN Manage your auto join list"), /* NICK_HELP */ _("%S allows you to \"register\" a nickname and\n" "prevent others from using it. The following\n" @@ -3203,6 +3220,11 @@ const char *const language_strings[LANG_STRING_COUNT] = { " \n" "This command will re-send the auth code (also called passcode)\n" "to the e-mail address of the user whom is performing it."), + /* NICK_HELP_AJOIN */ + _("Syntax: \002AJOIN {ADD | DEL | LIST} [\037channel\037] [\037key\037]\002\n" + " \n" + "This command manages your auto join list. When you identify\n" + "you will automatically join the channels on your auto join list"), /* NICK_SERVADMIN_HELP */ _(" \n" "Services Operators can also drop any nickname without needing\n" diff --git a/src/regchannel.cpp b/src/regchannel.cpp index 0d0f5dc54..16e90bebb 100644 --- a/src/regchannel.cpp +++ b/src/regchannel.cpp @@ -749,7 +749,7 @@ bool ChannelInfo::CheckKick(User *user) do_kick = true; } - if (!do_kick && ModeManager::FindChannelModeByName(CMODE_EXCEPT) && is_excepted(this, user) == 1) + if (!do_kick && matches_list(this->c, user, CMODE_EXCEPT)) return false; const NickCore *nc = user->Account() || user->IsRecognized() ? user->Account() : NULL; diff --git a/src/users.cpp b/src/users.cpp index 5e406ced2..488f143c8 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -876,14 +876,13 @@ void do_kill(User *user, const Anope::string &msg) /*************************************************************************/ /*************************************************************************/ -/* Is the given user ban-excepted? */ -bool is_excepted(ChannelInfo *ci, User *user) +bool matches_list(Channel *c, User *user, ChannelModeName mode) { - if (!ci->c || !ModeManager::FindChannelModeByName(CMODE_EXCEPT)) + if (!c || !c->HasMode(mode)) return false; - std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> modes = ci->c->GetModeList(CMODE_EXCEPT); + std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> modes = c->GetModeList(mode); for (; modes.first != modes.second; ++modes.first) { Entry e(modes.first->second); |