summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2012-02-22 18:12:02 -0500
committerAdam <Adam@anope.org>2012-02-22 18:12:02 -0500
commit3850b073ddf610415de54dced9ff134397779676 (patch)
treec1a464fba432a7a79535fac4c05cc46f8f19901e
parent81e50dd1f404c9bad008fe1b569dad134df91125 (diff)
Added regex support for many commands, such as akill, sqline, snline,
all of the */list commands, etc. Also extended the ability of akill to match a full nick!user@host and real name of users.
-rw-r--r--data/example.conf7
-rw-r--r--data/modules.example.conf22
-rw-r--r--docs/Changes2
-rw-r--r--docs/Changes.conf1
-rw-r--r--include/anope.h3
-rw-r--r--include/config.h2
-rw-r--r--include/defs.h1
-rw-r--r--include/module.h1
-rw-r--r--include/oper.h38
-rw-r--r--include/protocol.h2
-rw-r--r--include/regexpr.h47
-rw-r--r--modules/commands/cs_list.cpp6
-rw-r--r--modules/commands/ns_list.cpp6
-rw-r--r--modules/commands/os_akill.cpp201
-rw-r--r--modules/commands/os_chankill.cpp2
-rw-r--r--modules/commands/os_forbid.cpp15
-rw-r--r--modules/commands/os_ignore.cpp6
-rw-r--r--modules/commands/os_list.cpp10
-rw-r--r--modules/commands/os_sxline.cpp334
-rw-r--r--modules/extra/m_regex_pcre.cpp55
-rw-r--r--modules/extra/m_regex_posix.cpp57
-rw-r--r--modules/extra/m_regex_tre.cpp58
-rw-r--r--modules/protocol/bahamut.cpp62
-rw-r--r--modules/protocol/inspircd-ts6.h65
-rw-r--r--modules/protocol/inspircd11.cpp58
-rw-r--r--modules/protocol/inspircd12.cpp3
-rw-r--r--modules/protocol/inspircd20.cpp9
-rw-r--r--modules/protocol/plexus.cpp37
-rw-r--r--modules/protocol/ratbox.cpp37
-rw-r--r--modules/protocol/unreal.cpp60
-rw-r--r--modules/pseudoclients/operserv.cpp99
-rw-r--r--src/config.cpp2
-rw-r--r--src/misc.cpp39
-rw-r--r--src/modulemanager.cpp2
-rw-r--r--src/operserv.cpp220
35 files changed, 1174 insertions, 395 deletions
diff --git a/data/example.conf b/data/example.conf
index 73c6627a3..a746051c0 100644
--- a/data/example.conf
+++ b/data/example.conf
@@ -498,6 +498,13 @@ options
* If set, Services do not allow ownership of nick names, only ownership of accounts.
*/
nonicknameownership = no
+
+ /* The regex engine to use, as provided by the regex modules.
+ * Leave commented to disable regex matching.
+ *
+ * Note for this to work the regex module providing the regex engine must be loaded.
+ */
+ regexengine = "regex/pcre"
}
/*
diff --git a/data/modules.example.conf b/data/modules.example.conf
index 715be1898..101437d04 100644
--- a/data/modules.example.conf
+++ b/data/modules.example.conf
@@ -311,6 +311,28 @@ sqlite
}
/*
+ * m_regex_pcre
+ *
+ * Provides the regex engine regex/pcre, which uses the Perl Compatible Regular Expressions library.
+ */
+module { name = "m_regex_pcre" }
+
+/*
+ * m_regex_posix
+ *
+ * Provides the regex engine regex/posix, which uses the POSIX compliant regular expressions.
+ * This is likely the only regex module you will not need extra libraries for.
+ */
+#module { name = "m_regex_posix" }
+
+/*
+ * m_regex_tre
+ *
+ * Provides the regex engine regex/tre, which uses the TRE regex library.
+ */
+#module { name = "m_regex_tre" }
+
+/*
* m_rewrite
*
* Allows rewriting commands sent to clients.
diff --git a/docs/Changes b/docs/Changes
index 25b5dc142..7ad5a07da 100644
--- a/docs/Changes
+++ b/docs/Changes
@@ -1,5 +1,7 @@
Anope Version 1.9.7
--------------------
+A Added ability for using regex as patterns for various commands
+A Extended ability of operserv/akill to also match against nick and realname
Anope Version 1.9.6
--------------------
diff --git a/docs/Changes.conf b/docs/Changes.conf
index cdfbfa094..a9dd31cbf 100644
--- a/docs/Changes.conf
+++ b/docs/Changes.conf
@@ -1,6 +1,7 @@
Anope Version 1.9.7
-------------------
operserv:notifications removed in favor of log{} blocks
+options:regexengine added
Anope Version 1.9.6
-------------------
diff --git a/include/anope.h b/include/anope.h
index 421d735a3..b286d0fb6 100644
--- a/include/anope.h
+++ b/include/anope.h
@@ -346,8 +346,9 @@ namespace Anope
* @param str The string to check against the pattern (e.g. foobar)
* @param mask The pattern to check (e.g. foo*bar)
* @param case_sensitive Whether or not the match is case sensitive, default false.
+ * @param use_regex Whether or not to try regex. case_sensitive is not used in regex.
*/
- extern CoreExport bool Match(const string &str, const string &mask, bool case_sensitive = false);
+ extern CoreExport bool Match(const string &str, const string &mask, bool case_sensitive = false, bool use_regex = false);
/** Find a message in the message table
* @param name The name of the message were looking for
diff --git a/include/config.h b/include/config.h
index d53b7f41c..1ec67984a 100644
--- a/include/config.h
+++ b/include/config.h
@@ -456,6 +456,8 @@ class CoreExport ServerConfig
bool HidePrivilegedCommands;
/* If set, nicks cant be owned/everything is entirely account based */
bool NoNicknameOwnership;
+ /* Regex engine to use */
+ Anope::string RegexEngine;
/* A vector of our logfile options */
std::vector<LogInfo *> LogInfos;
diff --git a/include/defs.h b/include/defs.h
index 0a248daf7..098f48edd 100644
--- a/include/defs.h
+++ b/include/defs.h
@@ -35,6 +35,7 @@ class Module;
class NickAlias;
class NickCore;
class OperType;
+class Regex;
class Server;
class ServerConfig;
class Socket;
diff --git a/include/module.h b/include/module.h
index 94f565a3a..6865a2c17 100644
--- a/include/module.h
+++ b/include/module.h
@@ -36,6 +36,7 @@
#include "oper.h"
#include "opertype.h"
#include "protocol.h"
+#include "regexpr.h"
#include "regchannel.h"
#include "serialize.h"
#include "servers.h"
diff --git a/include/oper.h b/include/oper.h
index ced1d38dc..b3034b7c5 100644
--- a/include/oper.h
+++ b/include/oper.h
@@ -14,8 +14,10 @@
class CoreExport XLine : public Serializable
{
+ void InitRegex();
public:
Anope::string Mask;
+ Regex *regex;
Anope::string By;
time_t Created;
time_t Expires;
@@ -25,11 +27,18 @@ class CoreExport XLine : public Serializable
XLine(const Anope::string &mask, const Anope::string &reason = "", const Anope::string &uid = "");
- XLine(const Anope::string &mask, const Anope::string &by, const time_t expires, const Anope::string &reason, const Anope::string &uid);
+ XLine(const Anope::string &mask, const Anope::string &by, const time_t expires, const Anope::string &reason, const Anope::string &uid = "");
+ ~XLine();
Anope::string GetNick() const;
Anope::string GetUser() const;
Anope::string GetHost() const;
+ Anope::string GetReal() const;
+
+ Anope::string GetReason() const;
+
+ bool HasNickOrReal() const;
+ bool IsRegex() const;
Anope::string serialize_name() const;
serialized_data serialize();
@@ -41,7 +50,8 @@ class CoreExport XLineManager : public Service
char type;
/* List of XLines in this XLineManager */
std::vector<XLine *> XLines;
- static std::map<Anope::string, XLine *, ci::less> XLinesByUID;
+ /* Akills can have the same IDs, sometimes */
+ static std::multimap<Anope::string, XLine *, ci::less> XLinesByUID;
public:
/* List of XLine managers we check users against in XLineManager::CheckAll */
static std::list<XLineManager *> XLineManagers;
@@ -63,7 +73,7 @@ class CoreExport XLineManager : public Service
* Wparam u The user
* @return A pair of the XLineManager the user was found in and the XLine they matched, both may be NULL for no match
*/
- static std::pair<XLineManager *, XLine *> CheckAll(User *u);
+ static void CheckAll(User *u);
/** Generate a unique ID for this XLine
* @return A unique ID
@@ -116,15 +126,13 @@ class CoreExport XLineManager : public Service
void Clear();
/** Checks if a mask can/should be added to the XLineManager
+ * @param source The source adding the mask.
* @param mask The mask
* @param expires When the mask would expire
- * @return A pair of int and XLine*.
- * 1 - Mask already exists
- * 2 - Mask already exists, but the expiry time was changed
- * 3 - Mask is already covered by another mask
- * In each case the XLine it matches/is covered by is returned in XLine*
+ * @param reason the reason
+ * @return true if the mask can be added
*/
- std::pair<int, XLine *> CanAdd(const Anope::string &mask, time_t expires);
+ bool CanAdd(CommandSource &source, const Anope::string &mask, time_t expires, const Anope::string &reason);
/** Checks if this list has an entry
* @param mask The mask
@@ -134,15 +142,21 @@ class CoreExport XLineManager : public Service
/** Check a user against all of the xlines in this XLineManager
* @param u The user
- * @return The xline the user marches, if any. Also calls OnMatch()
+ * @return The xline the user marches, if any.
+ */
+ XLine *CheckAllXLines(User *u);
+
+ /** Check a user against an xline
+ * @param u The user
+ * @param x The xline
*/
- virtual XLine *Check(User *u);
+ virtual bool Check(User *u, XLine *x) = 0;
/** Called when a user matches a xline in this XLineManager
* @param u The user
* @param x The XLine they match
*/
- virtual void OnMatch(User *u, XLine *x);
+ virtual void OnMatch(User *u, XLine *x) = 0;
/** Called when an XLine expires
* @param x The xline
diff --git a/include/protocol.h b/include/protocol.h
index 40ddb75b3..edfc5bd53 100644
--- a/include/protocol.h
+++ b/include/protocol.h
@@ -67,7 +67,7 @@ class CoreExport IRCDProto
virtual void SendSVSNOOP(const Server *, bool) { }
virtual void SendTopic(BotInfo *, Channel *);
virtual void SendVhostDel(User *) { }
- virtual void SendAkill(User *, const XLine *) = 0;
+ virtual void SendAkill(User *, XLine *) = 0;
virtual void SendAkillDel(const XLine *) = 0;
virtual void SendSVSKill(const BotInfo *source, const User *user, const char *fmt, ...);
virtual void SendMode(const BotInfo *bi, const Channel *dest, const char *fmt, ...);
diff --git a/include/regexpr.h b/include/regexpr.h
new file mode 100644
index 000000000..a333c7e1b
--- /dev/null
+++ b/include/regexpr.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * (C) 2003-2012 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.
+ *
+ */
+
+#ifndef REGEXPR_H
+#define REGEXPR_H
+
+#include "services.h"
+#include "anope.h"
+#include "service.h"
+
+class RegexException : public CoreException
+{
+ public:
+ RegexException(const Anope::string &reason = "") : CoreException(reason) { }
+
+ virtual ~RegexException() throw() { }
+};
+
+class CoreExport Regex
+{
+ Anope::string expression;
+ protected:
+ Regex(const Anope::string &expr) : expression(expr) { }
+ public:
+ virtual ~Regex() { }
+ const Anope::string &GetExpression() { return expression; }
+ virtual bool Matches(const Anope::string &str) = 0;
+};
+
+class CoreExport RegexProvider : public Service
+{
+ public:
+ RegexProvider(Module *o, const Anope::string &n) : Service(o, "Regex", n) { }
+ virtual Regex *Compile(const Anope::string &) = 0;
+};
+
+#endif // REGEXPR_H
+
diff --git a/modules/commands/cs_list.cpp b/modules/commands/cs_list.cpp
index 57c14d157..77d7613fe 100644
--- a/modules/commands/cs_list.cpp
+++ b/modules/commands/cs_list.cpp
@@ -87,7 +87,7 @@ class CommandCSList : public Command
else if (channoexpire && !ci->HasFlag(CI_NO_EXPIRE))
continue;
- if (pattern.equals_ci(ci->name) || ci->name.equals_ci(spattern) || Anope::Match(ci->name, pattern) || Anope::Match(ci->name, spattern))
+ if (pattern.equals_ci(ci->name) || ci->name.equals_ci(spattern) || Anope::Match(ci->name, pattern, false, true) || Anope::Match(ci->name, spattern, false, true))
{
if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nchans <= Config->CSListMax)
{
@@ -125,6 +125,10 @@ class CommandCSList : public Command
"(Channels with the \002PRIVATE\002 option set are not listed.)\n"
"Note that a preceding '#' specifies a range, channel names\n"
"are to be written without '#'."));
+ if (!Config->RegexEngine.empty())
+ source.Reply(" \n"
+ "Regex matches are also supported using the %s engine.\n"
+ "Enclose your pattern in // if this desired.", Config->RegexEngine.c_str());
return true;
}
};
diff --git a/modules/commands/ns_list.cpp b/modules/commands/ns_list.cpp
index 491ed8733..de2852302 100644
--- a/modules/commands/ns_list.cpp
+++ b/modules/commands/ns_list.cpp
@@ -93,7 +93,7 @@ class CommandNSList : public Command
* Instead we build a nice nick!user@host buffer to compare.
* The output is then generated separately. -TheShadow */
Anope::string buf = Anope::printf("%s!%s", na->nick.c_str(), !na->last_usermask.empty() ? na->last_usermask.c_str() : "*@*");
- if (na->nick.equals_ci(pattern) || Anope::Match(buf, pattern))
+ if (na->nick.equals_ci(pattern) || Anope::Match(buf, pattern, false, true))
{
if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nnicks <= Config->NSListMax)
{
@@ -156,6 +156,10 @@ class CommandNSList : public Command
" \n"
" \002LIST * NOEXPIRE\002\n"
" Lists all registered nicks which have been set to not expire.\n"));
+ if (!Config->RegexEngine.empty())
+ source.Reply(" \n"
+ "Regex matches are also supported using the %s engine.\n"
+ "Enclose your pattern in // if this desired.", Config->RegexEngine.c_str());
return true;
}
diff --git a/modules/commands/os_akill.cpp b/modules/commands/os_akill.cpp
index d886ce2b3..f59c26e1f 100644
--- a/modules/commands/os_akill.cpp
+++ b/modules/commands/os_akill.cpp
@@ -60,19 +60,24 @@ class CommandOSAKill : public Command
void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
{
User *u = source.u;
- unsigned last_param = 2;
Anope::string expiry, mask;
- time_t expires;
- mask = params.size() > 1 ? params[1] : "";
- if (!mask.empty() && mask[0] == '+')
+ if (params.size() < 2)
+ {
+ this->OnSyntaxError(source, "ADD");
+ return;
+ }
+
+ spacesepstream sep(params[1]);
+ sep.GetToken(mask);
+
+ if (mask[0] == '+')
{
expiry = mask;
- mask = params.size() > 2 ? params[2] : "";
- last_param = 3;
+ sep.GetToken(mask);
}
- expires = !expiry.empty() ? dotime(expiry) : Config->AutokillExpiry;
+ time_t expires = !expiry.empty() ? dotime(expiry) : Config->AutokillExpiry;
/* If the expiry given does not contain a final letter, it's in days,
* said the doc. Ah well.
*/
@@ -87,84 +92,108 @@ class CommandOSAKill : public Command
else if (expires > 0)
expires += Anope::CurTime;
- if (params.size() <= last_param)
+ if (sep.StreamEnd())
{
this->OnSyntaxError(source, "ADD");
return;
}
- Anope::string reason = params[last_param];
- if (last_param == 2 && params.size() > 3)
- reason += " " + params[3];
- if (!mask.empty() && !reason.empty())
+ Anope::string reason;
+ if (mask.find('#') != Anope::string::npos)
{
- User *targ = NULL;
- std::pair<int, XLine *> canAdd = akills->CanAdd(mask, expires);
- if (mask.find('!') != Anope::string::npos)
- source.Reply(_("\002Reminder\002: AKILL masks cannot contain nicknames; make sure you have \002not\002 included a nick portion in your mask."));
- else if (mask.find('@') == Anope::string::npos && !(targ = finduser(mask)))
- source.Reply(BAD_USERHOST_MASK);
- else if (mask.find_first_not_of("~@.*?") == Anope::string::npos)
- source.Reply(USERHOST_MASK_TOO_WIDE, mask.c_str());
- else if (canAdd.first == 1)
- source.Reply(_("\002%s\002 already exists on the AKILL list."), canAdd.second->Mask.c_str());
- else if (canAdd.first == 2)
- source.Reply(_("Expiry time of \002%s\002 changed."), canAdd.second->Mask.c_str());
- else if (canAdd.first == 3)
- source.Reply(_("\002%s\002 is already covered by %s."), mask.c_str(), canAdd.second->Mask.c_str());
- else
+ Anope::string remaining = sep.GetRemaining();
+
+ size_t co = remaining[0] == ':' ? 0 : remaining.rfind(" :");
+ if (co == Anope::string::npos)
{
- if (targ)
- mask = "*@" + targ->host;
- unsigned int affected = 0;
- for (Anope::insensitive_map<User *>::iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
- if (Anope::Match(it->second->GetIdent() + "@" + it->second->host, mask))
- ++affected;
- float percent = static_cast<float>(affected) / static_cast<float>(UserListByNick.size()) * 100.0;
-
- if (percent > 95)
- {
- source.Reply(USERHOST_MASK_TOO_WIDE, mask.c_str());
- Log(LOG_ADMIN, u, this) << "tried to akill " << percent << "% of the network (" << affected << " users)";
- return;
- }
+ this->OnSyntaxError(source, "ADD");
+ return;
+ }
- if (Config->AddAkiller)
- reason = "[" + u->nick + "] " + reason;
+ if (co != 0)
+ ++co;
- Anope::string id;
- if (Config->AkillIds)
- {
- id = XLineManager::GenerateUID();
- reason = reason + " (ID: " + id + ")";
- }
+ reason = remaining.substr(co + 1);
+ mask += " " + remaining.substr(0, co);
+ mask.trim();
+ }
+ else
+ reason = sep.GetRemaining();
- XLine *x = new XLine(mask, u->nick, expires, reason, id);
+ if (mask[0] == '/' && mask[mask.length() - 1] == '/')
+ {
+ if (Config->RegexEngine.empty())
+ {
+ source.Reply(_("Regex is enabled."));
+ return;
+ }
- EventReturn MOD_RESULT;
- FOREACH_RESULT(I_OnAddXLine, OnAddXLine(u, x, akills));
- if (MOD_RESULT == EVENT_STOP)
- {
- delete x;
- return;
- }
+ service_reference<RegexProvider> provider("Regex", Config->RegexEngine);
+ if (!provider)
+ {
+ source.Reply(_("Unable to find regex engine %s"), Config->RegexEngine.c_str());
+ return;
+ }
- akills->AddXLine(x);
- if (Config->AkillOnAdd)
- akills->Send(NULL, x);
+ try
+ {
+ Anope::string stripped_mask = mask.substr(1, mask.length() - 2);
+ delete provider->Compile(stripped_mask);
+ }
+ catch (const RegexException &ex)
+ {
+ source.Reply("%s", ex.GetReason().c_str());
+ return;
+ }
+ }
- source.Reply(_("\002%s\002 added to the AKILL list."), mask.c_str());
+ User *targ = finduser(mask);
+ if (targ)
+ mask = "*@" + targ->host;
- Log(LOG_ADMIN, u, this) << "on " << mask << " (" << x->Reason << ") expires in " << (expires ? duration(expires - Anope::CurTime) : "never") << " [affects " << affected << " user(s) (" << percent << "%)]";
+ if (!akills->CanAdd(source, mask, expires, reason))
+ return;
+ else if (mask.find_first_not_of("/~@.*?") == Anope::string::npos)
+ {
+ source.Reply(USERHOST_MASK_TOO_WIDE, mask.c_str());
+ return;
+ }
- if (readonly)
- source.Reply(READ_ONLY_MODE);
- }
+ XLine *x = new XLine(mask, u->nick, expires, reason);
+ if (Config->AkillIds)
+ x->UID = XLineManager::GenerateUID();
+
+ unsigned int affected = 0;
+ for (Anope::insensitive_map<User *>::iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
+ if (akills->Check(it->second, x))
+ ++affected;
+ float percent = static_cast<float>(affected) / static_cast<float>(UserListByNick.size()) * 100.0;
+
+ if (percent > 95)
+ {
+ source.Reply(USERHOST_MASK_TOO_WIDE, mask.c_str());
+ Log(LOG_ADMIN, u, this) << "tried to akill " << percent << "% of the network (" << affected << " users)";
+ delete x;
+ return;
}
- else
- this->OnSyntaxError(source, "ADD");
- return;
+ EventReturn MOD_RESULT;
+ FOREACH_RESULT(I_OnAddXLine, OnAddXLine(u, x, akills));
+ if (MOD_RESULT == EVENT_STOP)
+ {
+ delete x;
+ return;
+ }
+
+ akills->AddXLine(x);
+ if (Config->AkillOnAdd)
+ akills->Send(NULL, x);
+
+ source.Reply(_("\002%s\002 added to the AKILL list."), mask.c_str());
+
+ Log(LOG_ADMIN, u, this) << "on " << mask << " (" << x->Reason << ") expires in " << (expires ? duration(expires - Anope::CurTime) : "never") << " [affects " << affected << " user(s) (" << percent << "%)]";
+ if (readonly)
+ source.Reply(READ_ONLY_MODE);
}
void DoDel(CommandSource &source, const std::vector<Anope::string> &params)
@@ -199,10 +228,14 @@ class CommandOSAKill : public Command
return;
}
- FOREACH_MOD(I_OnDelXLine, OnDelXLine(u, x, akills));
+ do
+ {
+ FOREACH_MOD(I_OnDelXLine, OnDelXLine(u, x, akills));
- source.Reply(_("\002%s\002 deleted from the AKILL list."), x->Mask.c_str());
- AkillDelCallback::DoDel(source, x);
+ source.Reply(_("\002%s\002 deleted from the AKILL list."), x->Mask.c_str());
+ AkillDelCallback::DoDel(source, x);
+ }
+ while ((x = akills->HasEntry(mask)));
}
@@ -240,7 +273,7 @@ class CommandOSAKill : public Command
entry["Number"] = stringify(number);
entry["Mask"] = x->Mask;
entry["Creator"] = x->By;
- entry["Created"] = do_strftime(x->Created);
+ entry["Created"] = do_strftime(x->Created, NULL, true);
entry["Expires"] = expire_left(NULL, x->Expires);
entry["Reason"] = x->Reason;
this->list.addEntry(entry);
@@ -255,13 +288,13 @@ class CommandOSAKill : public Command
{
XLine *x = akills->GetEntry(i);
- if (mask.empty() || mask.equals_ci(x->Mask) || mask == x->UID || Anope::Match(x->Mask, mask))
+ if (mask.empty() || mask.equals_ci(x->Mask) || mask == x->UID || Anope::Match(x->Mask, mask, false, true))
{
ListFormatter::ListEntry entry;
entry["Number"] = stringify(i + 1);
entry["Mask"] = x->Mask;
entry["Creator"] = x->By;
- entry["Created"] = do_strftime(x->Created);
+ entry["Created"] = do_strftime(x->Created, NULL, true);
entry["Expires"] = expire_left(source.u->Account(), x->Expires);
entry["Reason"] = x->Reason;
list.addEntry(entry);
@@ -327,7 +360,7 @@ class CommandOSAKill : public Command
source.Reply(_("The AKILL list has been cleared."));
}
public:
- CommandOSAKill(Module *creator) : Command(creator, "operserv/akill", 1, 4)
+ CommandOSAKill(Module *creator) : Command(creator, "operserv/akill", 1, 2)
{
this->SetDesc(_("Manipulate the AKILL list"));
this->SetSyntax(_("ADD [+\037expiry\037] \037mask\037 \037reason\037"));
@@ -367,11 +400,14 @@ class CommandOSAKill : public Command
source.Reply(_("Allows Services operators to manipulate the AKILL list. If\n"
"a user matching an AKILL mask attempts to connect, Services\n"
"will issue a KILL for that user and, on supported server\n"
- "types, will instruct all servers to add a ban (K-line) for\n"
- "the mask which the user matched.\n"
+ "types, will instruct all servers to add a ban for the mask\n"
+ "which the user matched.\n"
" \n"
- "\002AKILL ADD\002 adds the given nick or user@host/ip mask to the AKILL\n"
- "list for the given reason (which \002must\002 be given).\n"
+ "\002AKILL ADD\002 adds the given mask to the AKILL\n"
+ "list for the given reason, which \002must\002 be given.\n"
+ "Mask should be in the format of nick!user@host#real name,\n"
+ "though all that is required is user@host. If a real name is specified,\n"
+ "the reason must be prepended with a :.\n"
"\037expiry\037 is specified as an integer followed by one of \037d\037 \n"
"(days), \037h\037 (hours), or \037m\037 (minutes). Combinations (such as \n"
"\0371h30m\037) are not permitted. If a unit specifier is not \n"
@@ -380,7 +416,12 @@ class CommandOSAKill : public Command
"usermask to be added starts with a \037+\037, an expiry time must\n"
"be given, even if it is the same as the default. The\n"
"current AKILL default expiry time can be found with the\n"
- "\002STATS AKILL\002 command.\n"
+ "\002STATS AKILL\002 command.\n"));
+ if (!Config->RegexEngine.empty())
+ source.Reply(" \n"
+ "Regex matches are also supported using the %s engine.\n"
+ "Enclose your mask in // if this desired.", Config->RegexEngine.c_str());
+ source.Reply(_(
" \n"
"The \002AKILL DEL\002 command removes the given mask from the\n"
"AKILL list if it is present. If a list of entry numbers is \n"
diff --git a/modules/commands/os_chankill.cpp b/modules/commands/os_chankill.cpp
index 8b56eb3c2..bbfb5121b 100644
--- a/modules/commands/os_chankill.cpp
+++ b/modules/commands/os_chankill.cpp
@@ -82,7 +82,7 @@ class CommandOSChanKill : public Command
XLine *x = new XLine("*@" + uc->user->host, u->nick, expires, realreason, XLineManager::GenerateUID());
akills->AddXLine(x);
- akills->Check(uc->user);
+ akills->OnMatch(uc->user, x);
}
Log(LOG_ADMIN, u, this) << "on " << c->name << " (" << realreason << ")";
diff --git a/modules/commands/os_forbid.cpp b/modules/commands/os_forbid.cpp
index 908e2f2ca..d305de3c6 100644
--- a/modules/commands/os_forbid.cpp
+++ b/modules/commands/os_forbid.cpp
@@ -41,7 +41,7 @@ class MyForbidService : public ForbidService
{
ForbidData *d = this->forbidData[i - 1];
- if ((ftype == FT_NONE || ftype == d->type) && Anope::Match(mask, d->mask))
+ if ((ftype == FT_NONE || ftype == d->type) && Anope::Match(mask, d->mask, false, true))
return d;
}
return NULL;
@@ -217,6 +217,10 @@ class CommandOSForbid : public Command
source.Reply(" ");
source.Reply(_("Forbid allows you to forbid usage of certain nicknames, channels,\n"
"and email addresses. Wildcards are accepted for all entries."));
+ if (!Config->RegexEngine.empty())
+ source.Reply(" \n"
+ "Regex matches are also supported using the %s engine.\n"
+ "Enclose your pattern in // if this desired.", Config->RegexEngine.c_str());
return true;
}
};
@@ -273,8 +277,13 @@ class OSForbid : public Module
BotInfo *bi = findbot(Config->OperServ);
ForbidData *d = this->forbidService.FindForbid(c->name, FT_CHAN);
if (bi != NULL && d != NULL)
- {
- if (!c->HasFlag(CH_INHABIT))
+ {
+ if (ircd->chansqline)
+ {
+ XLine x(c->name, bi->nick, Anope::CurTime + Config->CSInhabit, d->reason);
+ ircdproto->SendSQLine(NULL, &x);
+ }
+ else if (!c->HasFlag(CH_INHABIT))
{
/* Join ChanServ and set a timer for this channel to part ChanServ later */
c->Hold();
diff --git a/modules/commands/os_ignore.cpp b/modules/commands/os_ignore.cpp
index f2012f212..3d84a4635 100644
--- a/modules/commands/os_ignore.cpp
+++ b/modules/commands/os_ignore.cpp
@@ -119,7 +119,7 @@ class OSIgnoreService : public IgnoreService
tmp = mask + "!*@*";
for (; ign != ign_end; ++ign)
- if (Anope::Match(tmp, ign->mask))
+ if (Anope::Match(tmp, ign->mask, false, true))
break;
}
@@ -297,6 +297,10 @@ class CommandOSIgnore : public Command
"Wildcards are permitted.\n"
" \n"
"Ignores will not be enforced on IRC Operators."));
+ if (!Config->RegexEngine.empty())
+ source.Reply(" \n"
+ "Regex matches are also supported using the %s engine.\n"
+ "Enclose your pattern in // if this desired.", Config->RegexEngine.c_str());
return true;
}
};
diff --git a/modules/commands/os_list.cpp b/modules/commands/os_list.cpp
index e9d67b52e..2850e0203 100644
--- a/modules/commands/os_list.cpp
+++ b/modules/commands/os_list.cpp
@@ -67,7 +67,7 @@ class CommandOSChanList : public Command
{
Channel *c = cit->second;
- if (!pattern.empty() && !Anope::Match(c->name, pattern))
+ if (!pattern.empty() && !Anope::Match(c->name, pattern, false, true))
c