summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/example.conf7
-rw-r--r--docs/Changes.conf1
-rw-r--r--include/config.h2
-rw-r--r--include/extensible.h8
-rw-r--r--include/extern.h2
-rw-r--r--include/language.h9
-rw-r--r--modules/core/cs_ban.cpp2
-rw-r--r--modules/core/ns_ajoin.cpp240
-rw-r--r--modules/extra/cs_tban.cpp2
-rw-r--r--src/botserv.cpp3
-rw-r--r--src/config.cpp1
-rw-r--r--src/language.cpp22
-rw-r--r--src/regchannel.cpp2
-rw-r--r--src/users.cpp7
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> &params)
+ {
+ 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> &params)
+ {
+ 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> &params)
+ {
+ 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> &params)
+ {
+ 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> &params)
+ {
+ 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);