aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules
diff options
context:
space:
mode:
authorGravatar Sadie Powell2019-03-30 22:06:19 +0000
committerGravatar Sadie Powell2019-03-30 22:06:19 +0000
commit1fff2f7f87fa0e69494fe45902cfa315204d1e43 (patch)
treeb4f3eac01dc458cc7f3ab5b43a57c44d06044bed /src/modules
parentRemove the flashpolicyd module. (diff)
parentRename OnClientProtocolPopulateTags to OnPopulateTags. (diff)
Merge branch 'insp3' into master.
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/extra/README2
-rw-r--r--src/modules/m_botmode.cpp32
-rw-r--r--src/modules/m_callerid.cpp4
-rw-r--r--src/modules/m_cban.cpp8
-rw-r--r--src/modules/m_cgiirc.cpp2
-rw-r--r--src/modules/m_check.cpp2
-rw-r--r--src/modules/m_chghost.cpp2
-rw-r--r--src/modules/m_chgident.cpp2
-rw-r--r--src/modules/m_chgname.cpp2
-rw-r--r--src/modules/m_clearchan.cpp2
-rw-r--r--src/modules/m_customtitle.cpp2
-rw-r--r--src/modules/m_cycle.cpp2
-rw-r--r--src/modules/m_dccallow.cpp8
-rw-r--r--src/modules/m_delayjoin.cpp18
-rw-r--r--src/modules/m_dnsbl.cpp18
-rw-r--r--src/modules/m_filter.cpp104
-rw-r--r--src/modules/m_globalload.cpp6
-rw-r--r--src/modules/m_globops.cpp2
-rw-r--r--src/modules/m_hideoper.cpp19
-rw-r--r--src/modules/m_httpd.cpp20
-rw-r--r--src/modules/m_ircv3_chghost.cpp2
-rw-r--r--src/modules/m_ircv3_ctctags.cpp347
-rw-r--r--src/modules/m_ircv3_echomessage.cpp47
-rw-r--r--src/modules/m_knock.cpp2
-rw-r--r--src/modules/m_modenotice.cpp2
-rw-r--r--src/modules/m_monitor.cpp2
-rw-r--r--src/modules/m_namedmodes.cpp2
-rw-r--r--src/modules/m_namesx.cpp19
-rw-r--r--src/modules/m_nationalchars.cpp4
-rw-r--r--src/modules/m_nicklock.cpp4
-rw-r--r--src/modules/m_noctcp.cpp8
-rw-r--r--src/modules/m_password_hash.cpp2
-rw-r--r--src/modules/m_permchannels.cpp4
-rw-r--r--src/modules/m_remove.cpp4
-rw-r--r--src/modules/m_repeat.cpp6
-rw-r--r--src/modules/m_rline.cpp14
-rw-r--r--src/modules/m_rmode.cpp2
-rw-r--r--src/modules/m_sajoin.cpp5
-rw-r--r--src/modules/m_sakick.cpp4
-rw-r--r--src/modules/m_samode.cpp2
-rw-r--r--src/modules/m_sanick.cpp5
-rw-r--r--src/modules/m_sapart.cpp5
-rw-r--r--src/modules/m_saquit.cpp5
-rw-r--r--src/modules/m_satopic.cpp2
-rw-r--r--src/modules/m_sethost.cpp2
-rw-r--r--src/modules/m_setident.cpp2
-rw-r--r--src/modules/m_setname.cpp2
-rw-r--r--src/modules/m_shun.cpp11
-rw-r--r--src/modules/m_silence.cpp6
-rw-r--r--src/modules/m_spanningtree/addline.cpp12
-rw-r--r--src/modules/m_spanningtree/compat.cpp7
-rw-r--r--src/modules/m_spanningtree/main.cpp5
-rw-r--r--src/modules/m_spanningtree/main.h4
-rw-r--r--src/modules/m_spanningtree/rsquit.cpp2
-rw-r--r--src/modules/m_spanningtree/server.cpp2
-rw-r--r--src/modules/m_sslinfo.cpp16
-rw-r--r--src/modules/m_svshold.cpp6
-rw-r--r--src/modules/m_timedbans.cpp2
-rw-r--r--src/modules/m_userip.cpp2
-rw-r--r--src/modules/m_watch.cpp2
-rw-r--r--src/modules/m_xline_db.cpp9
61 files changed, 661 insertions, 187 deletions
diff --git a/src/modules/extra/README b/src/modules/extra/README
index b59494df9..630ab3e85 100644
--- a/src/modules/extra/README
+++ b/src/modules/extra/README
@@ -2,7 +2,7 @@ This directory stores modules which require external libraries to compile.
For example, m_filter_pcre requires the PCRE libraries.
To compile any of these modules first ensure you have the required dependencies
-(read the online documentation at https://wiki.inspircd.org/) and then symlink
+(read the online documentation at https://wiki.inspircd.org) and then symlink
the .cpp file from this directory into the parent directory (src/modules/).
Alternatively, use the command: ./configure --enable-extras=m_extra.cpp, which will
diff --git a/src/modules/m_botmode.cpp b/src/modules/m_botmode.cpp
index 1bb06e687..a86e9116f 100644
--- a/src/modules/m_botmode.cpp
+++ b/src/modules/m_botmode.cpp
@@ -20,6 +20,7 @@
#include "inspircd.h"
+#include "modules/cap.h"
#include "modules/whois.h"
enum
@@ -28,13 +29,44 @@ enum
RPL_WHOISBOT = 335
};
+class BotTag : public ClientProtocol::MessageTagProvider
+{
+ private:
+ SimpleUserModeHandler& botmode;
+ Cap::Reference ctctagcap;
+
+ public:
+ BotTag(Module* mod, SimpleUserModeHandler& bm)
+ : ClientProtocol::MessageTagProvider(mod)
+ , botmode(bm)
+ , ctctagcap(mod, "message-tags")
+ {
+ }
+
+ void OnPopulateTags(ClientProtocol::Message& msg) override
+ {
+ User* const user = msg.GetSourceUser();
+ if (user && user->IsModeSet(botmode))
+ msg.AddTag("inspircd.org/bot", this, "");
+ }
+
+ bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) override
+ {
+ return ctctagcap.get(user);
+ }
+};
+
class ModuleBotMode : public Module, public Whois::EventListener
{
+ private:
SimpleUserModeHandler bm;
+ BotTag tag;
+
public:
ModuleBotMode()
: Whois::EventListener(this)
, bm(this, "bot", 'B')
+ , tag(this, bm)
{
}
diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp
index b8ffd6f62..470db5543 100644
--- a/src/modules/m_callerid.cpp
+++ b/src/modules/m_callerid.cpp
@@ -179,7 +179,7 @@ public:
extInfo(Creator)
{
allow_empty_last_param = false;
- syntax = "*|(+|-)<nick>[,(+|-)<nick> ...]";
+ syntax = "*|(+|-)<nick>[,(+|-)<nick>]+";
translation = { TR_CUSTOM };
}
@@ -189,7 +189,7 @@ public:
if (parameter.find(',') != std::string::npos)
return;
- // Convert a [+|-]<nick> into a [-]<uuid>
+ // Convert a (+|-)<nick> into a [-]<uuid>
ACCEPTAction action = GetTargetAndAction(parameter);
if (!action.first)
return;
diff --git a/src/modules/m_cban.cpp b/src/modules/m_cban.cpp
index a9f0e50eb..316b6dc2c 100644
--- a/src/modules/m_cban.cpp
+++ b/src/modules/m_cban.cpp
@@ -88,7 +88,7 @@ class CommandCBan : public Command
public:
CommandCBan(Module* Creator) : Command(Creator, "CBAN", 1, 3)
{
- flags_needed = 'o'; this->syntax = "<channel> [<duration> :<reason>]";
+ flags_needed = 'o'; this->syntax = "<channel> [<duration> [:<reason>]]";
}
CmdResult Handle(User* user, const Params& parameters) override
@@ -130,9 +130,9 @@ class CommandCBan : public Command
}
else
{
- time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = InspIRCd::TimeString(c_requires_crap);
- ServerInstance->SNO.WriteGlobalSno('x', "%s added timed CBan for %s, expires on %s: %s", user->nick.c_str(), parameters[0].c_str(), timestr.c_str(), reason);
+ ServerInstance->SNO.WriteGlobalSno('x', "%s added timed CBan for %s, expires in %s (on %s): %s",
+ user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), reason);
}
}
else
diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp
index 890a8f302..8a028f546 100644
--- a/src/modules/m_cgiirc.cpp
+++ b/src/modules/m_cgiirc.cpp
@@ -132,7 +132,7 @@ class CommandWebIRC : public SplitCommand
{
allow_empty_last_param = false;
works_before_reg = true;
- this->syntax = "<password> <gateway> <hostname> <ip> [flags]";
+ this->syntax = "<password> <gateway> <hostname> <ip> [<flags>]";
}
CmdResult HandleLocal(LocalUser* user, const Params& parameters) override
diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp
index ae459c6df..24afa4882 100644
--- a/src/modules/m_check.cpp
+++ b/src/modules/m_check.cpp
@@ -146,7 +146,7 @@ class CommandCheck : public Command
: Command(parent,"CHECK", 1)
, snomaskmode(parent, "snomask")
{
- flags_needed = 'o'; syntax = "<nickname>|<ip>|<hostmask>|<channel> <server>";
+ flags_needed = 'o'; syntax = "<nick>|<ipmask>|<hostmask>|<channel> [<servername>]";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_chghost.cpp b/src/modules/m_chghost.cpp
index 46e644551..0bcc5ab91 100644
--- a/src/modules/m_chghost.cpp
+++ b/src/modules/m_chghost.cpp
@@ -33,7 +33,7 @@ class CommandChghost : public Command
{
allow_empty_last_param = false;
flags_needed = 'o';
- syntax = "<nick> <newhost>";
+ syntax = "<nick> <host>";
translation = { TR_NICK, TR_TEXT };
}
diff --git a/src/modules/m_chgident.cpp b/src/modules/m_chgident.cpp
index 28a144336..8ff609b29 100644
--- a/src/modules/m_chgident.cpp
+++ b/src/modules/m_chgident.cpp
@@ -31,7 +31,7 @@ class CommandChgident : public Command
{
allow_empty_last_param = false;
flags_needed = 'o';
- syntax = "<nick> <newident>";
+ syntax = "<nick> <ident>";
translation = { TR_NICK, TR_TEXT };
}
diff --git a/src/modules/m_chgname.cpp b/src/modules/m_chgname.cpp
index 65999b142..cf0c2d8ee 100644
--- a/src/modules/m_chgname.cpp
+++ b/src/modules/m_chgname.cpp
@@ -29,7 +29,7 @@ class CommandChgname : public Command
{
allow_empty_last_param = false;
flags_needed = 'o';
- syntax = "<nick> <new real name>";
+ syntax = "<nick> :<realname>";
translation = { TR_NICK, TR_TEXT };
}
diff --git a/src/modules/m_clearchan.cpp b/src/modules/m_clearchan.cpp
index dd2ab6390..f5f8a6dde 100644
--- a/src/modules/m_clearchan.cpp
+++ b/src/modules/m_clearchan.cpp
@@ -28,7 +28,7 @@ class CommandClearChan : public Command
CommandClearChan(Module* Creator)
: Command(Creator, "CLEARCHAN", 1, 3)
{
- syntax = "<channel> [<KILL|KICK|G|Z>] [<reason>]";
+ syntax = "<channel> [KILL|KICK|G|Z] [:<reason>]";
flags_needed = 'o';
// Stop the linking mod from forwarding ENCAP'd CLEARCHAN commands, see below why
diff --git a/src/modules/m_customtitle.cpp b/src/modules/m_customtitle.cpp
index 6b81a7932..5ddde6c68 100644
--- a/src/modules/m_customtitle.cpp
+++ b/src/modules/m_customtitle.cpp
@@ -74,7 +74,7 @@ class CommandTitle : public Command
CommandTitle(Module* Creator) : Command(Creator,"TITLE", 2),
ctitle("ctitle", ExtensionItem::EXT_USER, Creator)
{
- syntax = "<user> <password>";
+ syntax = "<username> <password>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_cycle.cpp b/src/modules/m_cycle.cpp
index e9c9580e5..5d71384c5 100644
--- a/src/modules/m_cycle.cpp
+++ b/src/modules/m_cycle.cpp
@@ -28,7 +28,7 @@ class CommandCycle : public SplitCommand
CommandCycle(Module* Creator)
: SplitCommand(Creator, "CYCLE", 1)
{
- Penalty = 3; syntax = "<channel> :[reason]";
+ Penalty = 3; syntax = "<channel> [:<reason>]";
}
CmdResult HandleLocal(LocalUser* user, const Params& parameters) override
diff --git a/src/modules/m_dccallow.cpp b/src/modules/m_dccallow.cpp
index 94ddcce02..5fefd75e5 100644
--- a/src/modules/m_dccallow.cpp
+++ b/src/modules/m_dccallow.cpp
@@ -54,7 +54,7 @@ static const char* const helptext[] =
"Brain would then be able to send you files. They would have to",
"resend the file again if the server gave them an error message",
"before you added them to your DCCALLOW list.",
- "DCCALLOW entries will be temporary by default, if you want to add",
+ "DCCALLOW entries will be temporary. If you want to add",
"them to your DCCALLOW list until you leave IRC, type:",
"/DCCALLOW +Brain 0",
"To remove the user from your DCCALLOW list, type:",
@@ -63,7 +63,7 @@ static const char* const helptext[] =
"/DCCALLOW LIST",
"NOTE: If the user leaves IRC or changes their nickname",
" they will be removed from your DCCALLOW list.",
- " your DCCALLOW list will be deleted when you leave IRC."
+ " Your DCCALLOW list will be deleted when you leave IRC."
};
class BannedFileList
@@ -117,7 +117,7 @@ class CommandDccallow : public Command
CmdResult Handle(User* user, const Params& parameters) override
{
- /* syntax: DCCALLOW [+|-]<nick> (<time>) */
+ /* syntax: DCCALLOW [(+|-)<nick> [<time>]]|[LIST|HELP] */
if (!parameters.size())
{
// display current DCCALLOW list
@@ -235,7 +235,7 @@ class CommandDccallow : public Command
if (length > 0)
{
- user->WriteNumeric(RPL_DCCALLOWTIMED, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for %ld seconds", target->nick.c_str(), length));
+ user->WriteNumeric(RPL_DCCALLOWTIMED, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for %s", target->nick.c_str(), InspIRCd::DurationString(length).c_str()));
}
else
{
diff --git a/src/modules/m_delayjoin.cpp b/src/modules/m_delayjoin.cpp
index 8afb27c92..17036a398 100644
--- a/src/modules/m_delayjoin.cpp
+++ b/src/modules/m_delayjoin.cpp
@@ -21,6 +21,7 @@
#include "inspircd.h"
+#include "modules/ctctags.h"
class DelayJoinMode : public ModeHandler
{
@@ -72,7 +73,9 @@ class JoinHook : public ClientProtocol::EventHook
}
-class ModuleDelayJoin : public Module
+class ModuleDelayJoin
+ : public Module
+ , public CTCTags::EventListener
{
public:
LocalIntExt unjoined;
@@ -80,7 +83,8 @@ class ModuleDelayJoin : public Module
DelayJoinMode djm;
ModuleDelayJoin()
- : unjoined("delayjoin", ExtensionItem::EXT_MEMBERSHIP, this)
+ : CTCTags::EventListener(this)
+ , unjoined("delayjoin", ExtensionItem::EXT_MEMBERSHIP, this)
, joinhook(this, unjoined)
, djm(this, unjoined)
{
@@ -94,6 +98,7 @@ class ModuleDelayJoin : public Module
void OnUserKick(User* source, Membership*, const std::string &reason, CUList&) override;
void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) override;
void OnUserMessage(User* user, const MessageTarget& target, const MessageDetails& details) override;
+ void OnUserTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) override;
ModResult OnRawMode(User* user, Channel* channel, ModeHandler* mh, const std::string& param, bool adding) override;
};
@@ -176,6 +181,15 @@ void ModuleDelayJoin::OnBuildNeighborList(User* source, IncludeChanList& include
}
}
+void ModuleDelayJoin::OnUserTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details)
+{
+ if (target.type != MessageTarget::TYPE_CHANNEL)
+ return;
+
+ Channel* channel = target.Get<Channel>();
+ djm.RevealUser(user, channel);
+}
+
void ModuleDelayJoin::OnUserMessage(User* user, const MessageTarget& target, const MessageDetails& details)
{
if (target.type != MessageTarget::TYPE_CHANNEL)
diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp
index 02bd90aea..8fcf5c12f 100644
--- a/src/modules/m_dnsbl.cpp
+++ b/src/modules/m_dnsbl.cpp
@@ -147,9 +147,9 @@ class DNSBLResolver : public DNS::Request
"*", them->GetIPString());
if (ServerInstance->XLines->AddLine(kl,NULL))
{
- std::string timestr = InspIRCd::TimeString(kl->expiry);
- ServerInstance->SNO.WriteGlobalSno('x', "K-line added due to DNSBL match on *@%s to expire on %s: %s",
- them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
+ ServerInstance->SNO.WriteGlobalSno('x', "K-line added due to DNSBL match on *@%s to expire in %s (on %s): %s",
+ them->GetIPString().c_str(), InspIRCd::DurationString(kl->duration).c_str(),
+ InspIRCd::TimeString(kl->expiry).c_str(), reason.c_str());
ServerInstance->XLines->ApplyLines();
}
else
@@ -165,9 +165,9 @@ class DNSBLResolver : public DNS::Request
"*", them->GetIPString());
if (ServerInstance->XLines->AddLine(gl,NULL))
{
- std::string timestr = InspIRCd::TimeString(gl->expiry);
- ServerInstance->SNO.WriteGlobalSno('x', "G-line added due to DNSBL match on *@%s to expire on %s: %s",
- them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
+ ServerInstance->SNO.WriteGlobalSno('x', "G-line added due to DNSBL match on *@%s to expire in %s (on %s): %s",
+ them->GetIPString().c_str(), InspIRCd::DurationString(gl->duration).c_str(),
+ InspIRCd::TimeString(gl->expiry).c_str(), reason.c_str());
ServerInstance->XLines->ApplyLines();
}
else
@@ -183,9 +183,9 @@ class DNSBLResolver : public DNS::Request
them->GetIPString());
if (ServerInstance->XLines->AddLine(zl,NULL))
{
- std::string timestr = InspIRCd::TimeString(zl->expiry);
- ServerInstance->SNO.WriteGlobalSno('x', "Z-line added due to DNSBL match on %s to expire on %s: %s",
- them->GetIPString().c_str(), timestr.c_str(), reason.c_str());
+ ServerInstance->SNO.WriteGlobalSno('x', "Z-line added due to DNSBL match on %s to expire in %s (on %s): %s",
+ them->GetIPString().c_str(), InspIRCd::DurationString(zl->duration).c_str(),
+ InspIRCd::TimeString(zl->expiry).c_str(), reason.c_str());
ServerInstance->XLines->ApplyLines();
}
else
diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp
index 313038276..ebc1ae1f7 100644
--- a/src/modules/m_filter.cpp
+++ b/src/modules/m_filter.cpp
@@ -155,7 +155,7 @@ class CommandFilter : public Command
: Command(f, "FILTER", 1, 5)
{
flags_needed = 'o';
- this->syntax = "<filter-definition> <action> <flags> [<duration>] :<reason>";
+ this->syntax = "<pattern> [<action> <flags> [<duration>] :<reason>]";
}
CmdResult Handle(User* user, const Params& parameters) override;
@@ -192,8 +192,8 @@ class ModuleFilter : public Module, public ServerEventListener, public Stats::Ev
CullResult cull() override;
ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) override;
FilterResult* FilterMatch(User* user, const std::string &text, int flags);
- bool DeleteFilter(const std::string &freeform);
- std::pair<bool, std::string> AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flags);
+ bool DeleteFilter(const std::string& freeform, std::string& reason);
+ std::pair<bool, std::string> AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flags, bool config = false);
void ReadConfig(ConfigStatus& status) override;
Version GetVersion() override;
std::string EncodeFilter(FilterResult* filter);
@@ -214,11 +214,14 @@ CmdResult CommandFilter::Handle(User* user, const Params& parameters)
if (parameters.size() == 1)
{
/* Deleting a filter */
- Module *me = creator;
- if (static_cast<ModuleFilter *>(me)->DeleteFilter(parameters[0]))
+ Module* me = creator;
+ std::string reason;
+
+ if (static_cast<ModuleFilter*>(me)->DeleteFilter(parameters[0], reason))
{
- user->WriteNotice("*** Removed filter '" + parameters[0] + "'");
- ServerInstance->SNO.WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', "FILTER: "+user->nick+" removed filter '"+parameters[0]+"'");
+ user->WriteNotice("*** Removed filter '" + parameters[0] + "': " + reason);
+ ServerInstance->SNO.WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', "%s removed filter '%s': %s",
+ user->nick.c_str(), parameters[0].c_str(), reason.c_str());
return CMD_SUCCESS;
}
else
@@ -269,15 +272,19 @@ CmdResult CommandFilter::Handle(User* user, const Params& parameters)
reasonindex = 3;
}
- Module *me = creator;
- std::pair<bool, std::string> result = static_cast<ModuleFilter *>(me)->AddFilter(freeform, type, parameters[reasonindex], duration, flags);
+ Module* me = creator;
+ std::pair<bool, std::string> result = static_cast<ModuleFilter*>(me)->AddFilter(freeform, type, parameters[reasonindex], duration, flags);
if (result.first)
{
- user->WriteNotice("*** Added filter '" + freeform + "', type '" + parameters[1] + "'" +
- (duration ? ", duration " + parameters[3] : "") + ", flags '" + flags + "', reason: '" +
- parameters[reasonindex] + "'");
+ const std::string message = InspIRCd::Format("'%s', type '%s'%s, flags '%s', reason: %s",
+ freeform.c_str(), parameters[1].c_str(),
+ (duration ? InspIRCd::Format(", duration '%s'",
+ InspIRCd::DurationString(duration).c_str()).c_str()
+ : ""), flags.c_str(), parameters[reasonindex].c_str());
- ServerInstance->SNO.WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', "FILTER: "+user->nick+" added filter '"+freeform+"', type '"+parameters[1]+"', "+(duration ? "duration "+parameters[3]+", " : "")+"flags '"+flags+"', reason: "+parameters[reasonindex]);
+ user->WriteNotice("*** Added filter " + message);
+ ServerInstance->SNO.WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F',
+ "%s added filter %s", user->nick.c_str(), message.c_str());
return CMD_SUCCESS;
}
@@ -409,8 +416,10 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar
else if (f->action == FA_SHUN && (ServerInstance->XLines->GetFactory("SHUN")))
{
Shun* sh = new Shun(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString());
- ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was shunned because their message to %s matched %s (%s)",
- user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str()));
+ ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was shunned for %s (expires on %s) because their message to %s matched %s (%s)",
+ user->nick.c_str(), sh->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(),
+ target.c_str(), f->freeform.c_str(), f->reason.c_str()));
if (ServerInstance->XLines->AddLine(sh, NULL))
{
ServerInstance->XLines->ApplyLines();
@@ -421,8 +430,10 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar
else if (f->action == FA_GLINE)
{
GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString());
- ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was G-lined because their message to %s matched %s (%s)",
- user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str()));
+ ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was G-lined for %s (expires on %s) because their message to %s matched %s (%s)",
+ user->nick.c_str(), gl->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(),
+ target.c_str(), f->freeform.c_str(), f->reason.c_str()));
if (ServerInstance->XLines->AddLine(gl,NULL))
{
ServerInstance->XLines->ApplyLines();
@@ -433,8 +444,10 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar
else if (f->action == FA_ZLINE)
{
ZLine* zl = new ZLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString());
- ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was Z-lined because their message to %s matched %s (%s)",
- user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str()));
+ ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was Z-lined for %s (expires on %s) because their message to %s matched %s (%s)",
+ user->nick.c_str(), zl->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(),
+ target.c_str(), f->freeform.c_str(), f->reason.c_str()));
if (ServerInstance->XLines->AddLine(zl,NULL))
{
ServerInstance->XLines->ApplyLines();
@@ -508,8 +521,11 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
{
/* Note: We G-line *@IP so that if their host doesn't resolve the G-line still applies. */
GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString());
- ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was G-lined because their %s message matched %s (%s)",
- user->nick.c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str()));
+ ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was G-lined for %s (expires on %s) because their %s message matched %s (%s)",
+ user->nick.c_str(), gl->Displayable().c_str(),
+ InspIRCd::DurationString(f->duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(),
+ command.c_str(), f->freeform.c_str(), f->reason.c_str()));
if (ServerInstance->XLines->AddLine(gl,NULL))
{
@@ -521,8 +537,11 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
if (f->action == FA_ZLINE)
{
ZLine* zl = new ZLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString());
- ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was Z-lined because their %s message matched %s (%s)",
- user->nick.c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str()));
+ ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was Z-lined for %s (expires on %s) because their %s message matched %s (%s)",
+ user->nick.c_str(), zl->Displayable().c_str(),
+ InspIRCd::DurationString(f->duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(),
+ command.c_str(), f->freeform.c_str(), f->reason.c_str()));
if (ServerInstance->XLines->AddLine(zl,NULL))
{
@@ -535,8 +554,12 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params&
{
/* Note: We shun *!*@IP so that if their host doesnt resolve the shun still applies. */
Shun* sh = new Shun(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString());
- ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was shunned because their %s message matched %s (%s)",
- user->nick.c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str()));
+ ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was shunned for %s (expires on %s) because their %s message matched %s (%s)",
+ user->nick.c_str(), sh->Displayable().c_str(),
+ InspIRCd::DurationString(f->duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(),
+ command.c_str(), f->freeform.c_str(), f->reason.c_str()));
+
if (ServerInstance->XLines->AddLine(sh, NULL))
{
ServerInstance->XLines->ApplyLines();
@@ -705,12 +728,13 @@ FilterResult* ModuleFilter::FilterMatch(User* user, const std::string &text, int
return NULL;
}
-bool ModuleFilter::DeleteFilter(const std::string &freeform)
+bool ModuleFilter::DeleteFilter(const std::string& freeform, std::string& reason)
{
for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++)
{
if (i->freeform == freeform)
{
+ reason.assign(i->reason);
delete i->regex;
filters.erase(i);
return true;
@@ -719,7 +743,7 @@ bool ModuleFilter::DeleteFilter(const std::string &freeform)
return false;
}
-std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flgs)
+std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flgs, bool config)
{
for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++)
{
@@ -731,7 +755,7 @@ std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform
try
{
- filters.push_back(FilterResult(RegexEngine, freeform, reason, type, duration, flgs, false));
+ filters.push_back(FilterResult(RegexEngine, freeform, reason, type, duration, flgs, config));
}
catch (ModuleException &e)
{
@@ -782,11 +806,13 @@ std::string ModuleFilter::FilterActionToString(FilterAction fa)
void ModuleFilter::ReadFilters()
{
+ insp::flat_set<std::string> removedfilters;
+
for (std::vector<FilterResult>::iterator filter = filters.begin(); filter != filters.end(); )
{
if (filter->from_config)
{
- ServerInstance->SNO.WriteGlobalSno('f', "FILTER: removing filter '" + filter->freeform + "' due to config rehash.");
+ removedfilters.insert(filter->freeform);
delete filter->regex;
filter = filters.erase(filter);
continue;
@@ -811,15 +837,17 @@ void ModuleFilter::ReadFilters()
if (!StringToFilterAction(action, fa))
fa = FA_NONE;
- try
- {
- filters.push_back(FilterResult(RegexEngine, pattern, reason, fa, duration, flgs, true));
- ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Regular expression %s loaded.", pattern.c_str());
- }
- catch (ModuleException &e)
- {
- ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Error in regular expression '%s': %s", pattern.c_str(), e.GetReason().c_str());
- }
+ std::pair<bool, std::string> result = static_cast<ModuleFilter*>(this)->AddFilter(pattern, fa, reason, duration, flgs, true);
+ if (result.first)
+ removedfilters.erase(pattern);
+ else
+ ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Filter '%s' could not be added: %s", pattern.c_str(), result.second.c_str());
+ }
+
+ if (!removedfilters.empty())
+ {
+ for (insp::flat_set<std::string>::const_iterator it = removedfilters.begin(); it != removedfilters.end(); ++it)
+ ServerInstance->SNO.WriteGlobalSno('f', "Removing filter '" + *(it) + "' due to config rehash.");
}
}
diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp
index fa0b58a3b..344ac1e66 100644
--- a/src/modules/m_globalload.cpp
+++ b/src/modules/m_globalload.cpp
@@ -32,7 +32,7 @@ class CommandGloadmodule : public Command
CommandGloadmodule(Module* Creator) : Command(Creator,"GLOADMODULE", 1)
{
flags_needed = 'o';
- syntax = "<modulename> [servermask]";
+ syntax = "<modulename> [<servermask>]";
}
CmdResult Handle(User* user, const Params& parameters) override
@@ -71,7 +71,7 @@ class CommandGunloadmodule : public Command
CommandGunloadmodule(Module* Creator) : Command(Creator,"GUNLOADMODULE", 1)
{
flags_needed = 'o';
- syntax = "<modulename> [servermask]";
+ syntax = "<modulename> [<servermask>]";
}
CmdResult Handle(User* user, const Params& parameters) override
@@ -121,7 +121,7 @@ class CommandGreloadmodule : public Command
public:
CommandGreloadmodule(Module* Creator) : Command(Creator, "GRELOADMODULE", 1)
{
- flags_needed = 'o'; syntax = "<modulename> [servermask]";
+ flags_needed = 'o'; syntax = "<modulename> [<servermask>]";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_globops.cpp b/src/modules/m_globops.cpp
index 56272a11e..4a57a14f6 100644
--- a/src/modules/m_globops.cpp
+++ b/src/modules/m_globops.cpp
@@ -30,7 +30,7 @@ class CommandGlobops : public Command
public:
CommandGlobops(Module* Creator) : Command(Creator,"GLOBOPS", 1,1)
{
- flags_needed = 'o'; syntax = "<any-text>";
+ flags_needed = 'o'; syntax = ":<message>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp
index 792389843..5ac2e6f1e 100644
--- a/src/modules/m_hideoper.cpp
+++ b/src/modules/m_hideoper.cpp
@@ -123,22 +123,9 @@ class ModuleHideOper
if (request.flags['o'])
return MOD_RES_DENY;
- size_t flag_index = 5;
- if (request.whox)
- {
- // We only need to fiddle with the flags if they are present.
- if (!request.whox_fields['f'])
- return MOD_RES_PASSTHRU;
-
- // WHOX makes this a bit tricky as we need to work out the parameter which the flags are in.
- flag_index = 0;
- static const char* flags = "tcuihsn";
- for (size_t i = 0; i < strlen(flags); ++i)
- {
- if (request.whox_fields[flags[i]])
- flag_index += 1;
- }
- }
+ size_t flag_index;
+ if (!request.GetFieldIndex('f', flag_index))
+ return MOD_RES_PASSTHRU;
// hide the "*" that marks the user as an oper from the /WHO line
// #chan ident localhost insp22.test nick H@ :0 Attila
diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp
index 459fb6f5e..7164da8a7 100644
--- a/src/modules/m_httpd.cpp
+++ b/src/modules/m_httpd.cpp
@@ -29,7 +29,9 @@
#include "modules/httpd.h"
// Fix warnings about shadowing in http_parser.
-#pragma GCC diagnostic ignored "-Wshadow"
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wshadow"
+#endif
#include <http_parser.c>
@@ -211,24 +213,12 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru
AddToCull();
}
- const char* Response(unsigned int response)
- {
- switch (response)
- {
-#define HTTP_STATUS_CASE(n, m, s) case n: return #s;
- HTTP_STATUS_MAP(HTTP_STATUS_CASE)
- default:
- return "WTF";
- break;
- }
- }
-
void SendHTTPError(unsigned int response)
{
HTTPHeaders empty;
std::string data = InspIRCd::Format(
"<html><head></head><body>Server error %u: %s<br>"
- "<small>Powered by <a href='http://www.inspircd.org'>InspIRCd</a></small></body></html>", response, Response(response));
+ "<small>Powered by <a href='https://www.inspircd.org'>InspIRCd</a></small></body></html>", response, http_status_str((http_status)response));
SendHeaders(data.length(), response, empty);
WriteData(data);
@@ -237,7 +227,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru
void SendHeaders(unsigned long size, unsigned int response, HTTPHeaders &rheaders)
{
- WriteData(InspIRCd::Format("HTTP/%u.%u %u %s\r\n", parser.http_major ? parser.http_major : 1, parser.http_major ? parser.http_minor : 1, response, Response(response)));
+ WriteData(InspIRCd::Format("HTTP/%u.%u %u %s\r\n", parser.http_major ? parser.http_major : 1, parser.http_major ? parser.http_minor : 1, response, http_status_str((http_status)response)));
rheaders.CreateHeader("Date", InspIRCd::TimeString(ServerInstance->Time(), "%a, %d %b %Y %H:%M:%S GMT", true));
rheaders.CreateHeader("Server", INSPIRCD_BRANCH);
diff --git a/src/modules/m_ircv3_chghost.cpp b/src/modules/m_ircv3_chghost.cpp
index 31e2c1519..dba1b5466 100644
--- a/src/modules/m_ircv3_chghost.cpp
+++ b/src/modules/m_ircv3_chghost.cpp
@@ -32,7 +32,7 @@ class ModuleIRCv3ChgHost : public Module
msg.PushParamRef(ident);
msg.PushParamRef(host);
ClientProtocol::Event protoev(protoevprov, msg);
- IRCv3::WriteNeighborsWithCap(user, protoev, cap);
+ IRCv3::WriteNeighborsWithCap(user, protoev, cap, true);
}
public:
diff --git a/src/modules/m_ircv3_ctctags.cpp b/src/modules/m_ircv3_ctctags.cpp
new file mode 100644
index 000000000..bdf60cf7c
--- /dev/null
+++ b/src/modules/m_ircv3_ctctags.cpp
@@ -0,0 +1,347 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2019 Peter Powell <petpow@saberuk.com>
+ * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com>
+ *
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "modules/cap.h"
+#include "modules/ctctags.h"
+
+class CommandTagMsg : public Command
+{
+ private:
+ Cap::Capability& cap;
+ ChanModeReference moderatedmode;
+ ChanModeReference noextmsgmode;
+ Events::ModuleEventProvider tagevprov;
+ ClientProtocol::EventProvider msgevprov;
+
+ bool FirePreEvents(User* source, MessageTarget& msgtarget, CTCTags::TagMessageDetails& msgdetails)
+ {
+ // Inform modules that a TAGMSG wants to be sent.
+ ModResult modres;
+ FIRST_MOD_RESULT_CUSTOM(tagevprov, CTCTags::EventListener, OnUserPreTagMessage, modres, (source, msgtarget, msgdetails));
+ if (modres == MOD_RES_DENY)
+ {
+ // Inform modules that a module blocked the TAGMSG.
+ FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserTagMessageBlocked, (source, msgtarget, msgdetails));
+ return false;
+ }
+
+ // Inform modules that a TAGMSG is about to be sent.
+ FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserTagMessage, (source, msgtarget, msgdetails));
+ return true;
+ }
+
+ CmdResult FirePostEvent(User* source, const MessageTarget& msgtarget, const CTCTags::TagMessageDetails& msgdetails)
+ {
+ // If the source is local then update its idle time.
+ LocalUser* lsource = IS_LOCAL(source);
+ if (lsource)
+ lsource->idle_lastmsg = ServerInstance->Time();
+
+ // Inform modules that a TAGMSG was sent.
+ FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserPostTagMessage, (source, msgtarget, msgdetails));
+ return CMD_SUCCESS;
+ }
+
+ CmdResult HandleChannelTarget(User* source, const Params& parameters, const char* target, PrefixMode* pm)
+ {
+ Channel* chan = ServerInstance->FindChan(target);
+ if (!chan)
+ {
+ // The target channel does not exist.
+ source->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
+ return CMD_FAILURE;
+ }
+
+ if (IS_LOCAL(source))
+ {
+ if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(source))
+ {
+ // The noextmsg mode is set and the source is not in the channel.
+ source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (no external messages)");
+ return CMD_FAILURE;
+ }
+
+ bool no_chan_priv = chan->GetPrefixValue(source) < VOICE_VALUE;
+ if (no_chan_priv && chan->IsModeSet(moderatedmode))
+ {
+ // The moderated mode is set and the source has no status rank.
+ source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (+m)");
+ return CMD_FAILURE;
+ }
+
+ if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(source))
+ {
+ // The source is banned in the channel and restrictbannedusers is enabled.
+ if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY)
+ source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're banned)");
+ return CMD_FAILURE;
+ }
+ }
+
+ // Fire the pre-message events.
+ MessageTarget msgtarget(chan, pm ? pm->GetPrefix() : 0);
+ CTCTags::TagMessageDetails msgdetails(parameters.GetTags());
+ if (!FirePreEvents(source, msgtarget, msgdetails))
+ return CMD_FAILURE;
+
+ unsigned int minrank = pm ? pm->GetPrefixRank() : 0;
+ CTCTags::TagMessage message(source, chan, parameters.GetTags());
+ const Channel::MemberMap& userlist = chan->GetUsers();
+ for (Channel::MemberMap::const_iterator iter = userlist.begin(); iter != userlist.end(); ++iter)
+ {
+ LocalUser* luser = IS_LOCAL(iter->first);
+
+ // Don't send to remote users or the user who is the source.
+ if (!luser || luser == source)
+ continue;
+
+ // Don't send to unprivileged or exempt users.
+ if (iter->second->getRank() < minrank || msgdetails.exemptions.count(luser))
+ continue;
+
+ // Send to users if they have the capability.
+ if (cap.get(luser))
+ luser->Send(msgevprov, message);
+ }
+ return FirePostEvent(source, msgtarget, msgdetails);
+ }
+
+ CmdResult HandleServerTarget(User* source, const Params& parameters)
+ {
+ // If the source isn't allowed to mass message users then reject
+ // the attempt to mass-message users.
+ if (!source->HasPrivPermission("users/mass-message"))
+ return CMD_FAILURE;
+
+ // Extract the server glob match from the target parameter.
+ std::string servername(parameters[0], 1);
+
+ // Fire the pre-message events.
+ MessageTarget msgtarget(&servername);
+ CTCTags::TagMessageDetails msgdetails(parameters.GetTags());
+ if (!FirePreEvents(source, msgtarget, msgdetails))
+ return CMD_FAILURE;
+
+ // If the current server name matches the server name glob then send
+ // the message out to the local users.
+ if (InspIRCd::Match(ServerInstance->Config->ServerName, servername))
+ {
+ CTCTags::TagMessage message(source, "$*", parameters.GetTags());
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter)
+ {
+ LocalUser* luser = IS_LOCAL(*iter);
+
+ // Don't send to unregistered users or the user who is the source.
+ if (luser->registered != REG_ALL || luser == source)
+ continue;
+
+ // Don't send to exempt users.
+ if (msgdetails.exemptions.count(luser))
+ continue;
+
+ // Send to users if they have the capability.
+ if (cap.get(luser))
+ luser->Send(msgevprov, message);
+ }
+ }
+
+ // Fire the post-message event.
+ return FirePostEvent(source, msgtarget, msgdetails);
+ }
+
+ CmdResult HandleUserTarget(User* source, const Params& parameters)
+ {
+ User* target;
+ if (IS_LOCAL(source))
+ {
+ // Local sources can specify either a nick or a nick@server mask as the target.
+ const char* targetserver = strchr(parameters[0].c_str(), '@');
+ if (targetserver)
+ {
+ // The target is a user on a specific server (e.g. jto@tolsun.oulu.fi).
+ target = ServerInstance->FindNickOnly(parameters[0].substr(0, targetserver - parameters[0].c_str()));
+ if (target && strcasecmp(target->server->GetName().c_str(), targetserver + 1))
+ target = NULL;
+ }
+ else
+ {
+ // If the source is a local user then we only look up the target by nick.
+ target = ServerInstance->FindNickOnly(parameters[0]);
+ }
+ }
+ else
+ {
+ // Remote users can only specify a nick or UUID as the target.
+ target = ServerInstance->FindNick(parameters[0]);
+ }
+
+ if (!target || target->registered != REG_ALL)
+ {
+ // The target user does not exist or is not fully registered.
+ source->WriteNumeric(Numerics::NoSuchNick(parameters[0]));
+ return CMD_FAILURE;
+ }
+
+ // Fire the pre-message events.
+ MessageTarget msgtarget(target);
+ CTCTags::TagMessageDetails msgdetails(parameters.GetTags());
+ if (!FirePreEvents(source, msgtarget, msgdetails))
+ return CMD_FAILURE;
+
+ LocalUser* const localtarget = IS_LOCAL(target);
+ if (localtarget && cap.get(localtarget))
+ {
+ // Send to the target if they have the capability and are a local user.
+ CTCTags::TagMessage message(source, localtarget, parameters.GetTags());
+ localtarget->Send(msgevprov, message);
+ }
+
+ // Fire the post-message event.
+ return FirePostEvent(source, msgtarget, msgdetails);
+ }
+
+ public:
+ CommandTagMsg(Module* Creator, Cap::Capability& Cap)
+ : Command(Creator, "TAGMSG", 1)
+ , cap(Cap)
+ , moderatedmode(Creator, "moderated")
+ , noextmsgmode(Creator, "noextmsg")
+ , tagevprov(Creator, "event/tagmsg")
+ , msgevprov(Creator, "TAGMSG")
+ {
+ allow_empty_last_param = false;
+ }
+
+ CmdResult Handle(User* user, const Params& parameters) override
+ {
+ if (CommandParser::LoopCall(user, this, parameters, 0))
+ return CMD_SUCCESS;
+
+ // Check that the source has the message tags capability.
+ if (IS_LOCAL(user) && !cap.get(user))
+ return CMD_FAILURE;
+
+ // The target is a server glob.
+ if (parameters[0][0] == '$')
+ return HandleServerTarget(user, parameters);
+
+ // If the message begins with a status character then look it up.
+ const char* target = parameters[0].c_str();
+ PrefixMode* pmh = ServerInstance->Modes.FindPrefix(target[0]);
+ if (pmh)
+ target++;
+
+ // The target is a channel name.
+ if (*target == '#')
+ return HandleChannelTarget(user, parameters, target, pmh);
+
+ // The target is a nickname.
+ return HandleUserTarget(user, parameters);
+ }
+
+ RouteDescriptor GetRouting(User* user, const Params& parameters) override
+ {
+ return ROUTE_MESSAGE(parameters[0]);
+ }
+};
+
+class C2CTags : public ClientProtocol::MessageTagProvider
+{
+ private:
+ Cap::Capability& cap;
+
+ public:
+ C2CTags(Module* Creator, Cap::Capability& Cap)
+ : ClientProtocol::MessageTagProvider(Creator)
+ , cap(Cap)
+ {
+ }
+
+ ModResult OnProcessTag(User* user, const std::string& tagname, std::string& tagvalue) override
+ {
+ // A client-only tag is prefixed with a plus sign (+) and otherwise conforms
+ // to the format specified in IRCv3.2 tags.
+ if (tagname[0] != '+' || tagname.length() < 2)
+ return MOD_RES_PASSTHRU;
+
+ // If the user is local then we check whether they have the message-tags cap
+ // enabled. If not then we reject all client-only tags originating from them.
+ LocalUser* lu = IS_LOCAL(user);
+ if (lu && !cap.get(lu))
+ return MOD_RES_DENY;
+
+ // Remote users have their client-only tags checked by their local server.
+ return MOD_RES_ALLOW;
+ }
+
+ bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) override
+ {
+ return cap.get(user);
+ }
+};
+
+class ModuleIRCv3CTCTags
+ : public Module
+ , public CTCTags::EventListener
+{
+ private:
+ Cap::Capability cap;
+ CommandTagMsg cmd;
+ C2CTags c2ctags;
+
+ ModResult CopyClientTags(const ClientProtocol::TagMap& tags_in, ClientProtocol::TagMap& tags_out)
+ {
+ for (ClientProtocol::TagMap::const_iterator i = tags_in.begin(); i != tags_in.end(); ++i)
+ {
+ const ClientProtocol::MessageTagData& tagdata = i->second;
+ if (tagdata.tagprov == &c2ctags)
+ tags_out.insert(*i);
+ }
+ return MOD_RES_PASSTHRU;
+ }
+
+ public:
+ ModuleIRCv3CTCTags()
+ : CTCTags::EventListener(this)
+ , cap(this, "message-tags")
+ , cmd(this, cap)
+ , c2ctags(this, cap)
+ {
+ }
+
+ ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) override
+ {
+ return CopyClientTags(details.tags_in, details.tags_out);
+ }
+
+ ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) override
+ {
+ return CopyClientTags(details.tags_in, details.tags_out);
+ }
+
+ Version GetVersion() override
+ {
+ return Version("Provides the DRAFT message-tags IRCv3 extension", VF_VENDOR | VF_COMMON);
+ }
+};
+
+MODULE_INIT(ModuleIRCv3CTCTags)
diff --git a/src/modules/m_ircv3_echomessage.cpp b/src/modules/m_ircv3_echomessage.cpp
index 16d6751d9..1a08ef3d9 100644
--- a/src/modules/m_ircv3_echomessage.cpp
+++ b/src/modules/m_ircv3_echomessage.cpp
@@ -20,14 +20,21 @@
#include "inspircd.h"
#include "modules/cap.h"
+#include "modules/ctctags.h"
-class ModuleIRCv3EchoMessage : public Module
+class ModuleIRCv3EchoMessage
+ : public Module
+ , public CTCTags::EventListener
{
+ private:
Cap::Capability cap;
+ ClientProtocol::EventProvider tagmsgprov;
public:
ModuleIRCv3EchoMessage()
- : cap(this, "echo-message")
+ : CTCTags::EventListener(this)
+ , cap(this, "echo-message")
+ , tagmsgprov(this, "TAGMSG")
{
}
@@ -64,6 +71,35 @@ class ModuleIRCv3EchoMessage : public Module
}
}
+ void OnUserPostTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) override
+ {
+ if (!cap.get(user) || !details.echo)
+ return;
+
+ // Caps are only set on local users
+ LocalUser* const localuser = static_cast<LocalUser*>(user);
+
+ const ClientProtocol::TagMap& tags = details.echo_original ? details.tags_in : details.tags_out;
+ if (target.type == MessageTarget::TYPE_USER)
+ {
+ User* destuser = target.Get<User>();
+ CTCTags::TagMessage message(user, destuser, tags);
+ localuser->Send(tagmsgprov, message);
+ }
+ else if (target.type == MessageTarget::TYPE_CHANNEL)
+ {
+ Channel* chan = target.Get<Channel>();
+ CTCTags::TagMessage message(user, chan, tags);
+ localuser->Send(tagmsgprov, message);
+ }
+ else
+ {
+ const std::string* servername = target.Get<std::string>();
+ CTCTags::TagMessage message(user, servername->c_str(), tags);
+ localuser->Send(tagmsgprov, message);
+ }
+ }
+
void OnUserMessageBlocked(User* user, const MessageTarget& target, const MessageDetails& details) override
{
// Prevent spammers from knowing that their spam was blocked.
@@ -71,6 +107,13 @@ class ModuleIRCv3EchoMessage : public Module
OnUserPostMessage(user, target, details);
}
+ void OnUserTagMessageBlocked(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) override
+ {
+ // Prevent spammers from knowing that their spam was blocked.
+ if (details.echo_original)
+ OnUserPostTagMessage(user, target, details);
+ }
+
Version GetVersion() override
{
return Version("Provides the echo-message IRCv3 extension", VF_VENDOR);
diff --git a/src/modules/m_knock.cpp b/src/modules/m_knock.cpp
index 5d76a9d66..b2824c78e 100644
--- a/src/modules/m_knock.cpp
+++ b/src/modules/m_knock.cpp
@@ -46,7 +46,7 @@ class CommandKnock : public Command
, noknockmode(Noknockmode)
, inviteonlymode(Creator, "inviteonly")
{
- syntax = "<channel> <reason>";
+ syntax = "<channel> :<reason>";
Penalty = 5;
}
diff --git a/src/modules/m_modenotice.cpp b/src/modules/m_modenotice.cpp
index 4a94c89ee..5376d4cc4 100644
--- a/src/modules/m_modenotice.cpp
+++ b/src/modules/m_modenotice.cpp
@@ -24,7 +24,7 @@ class CommandModeNotice : public Command
public:
CommandModeNotice(Module* parent) : Command(parent,"MODENOTICE",2,2)
{
- syntax = "<modes> <message>";
+ syntax = "<modeletters> :<message>";
flags_needed = 'o';
}
diff --git a/src/modules/m_monitor.cpp b/src/modules/m_monitor.cpp
index 4225d5fb2..809a7fb24 100644
--- a/src/modules/m_monitor.cpp
+++ b/src/modules/m_monitor.cpp
@@ -316,7 +316,7 @@ class CommandMonitor : public SplitCommand
{
Penalty = 2;
allow_empty_last_param = false;
- syntax = "[C|L|S|+ <nick1>[,<nick2>]|- <nick1>[,<nick2>]";
+ syntax = "C|L|S|(+|-) <nick>[,<nick>]+";
}
CmdResult HandleLocal(LocalUser* user, const Params& parameters) override
diff --git a/src/modules/m_namedmodes.cpp b/src/modules/m_namedmodes.cpp
index c99ff9133..81afb6cac 100644
--- a/src/modules/m_namedmodes.cpp
+++ b/src/modules/m_namedmodes.cpp
@@ -56,7 +56,7 @@ class CommandProp : public SplitCommand
CommandProp(Module* parent)
: SplitCommand(parent, "PROP", 1)
{
- syntax = "<user|channel> {[+-]<mode> [<value>]}*";
+ syntax = "<channel> [[(+|-)]<mode> [<value>]]";
}
CmdResult HandleLocal(LocalUser* src, const Params& parameters) override
diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp
index 5d265fc56..549b0755e 100644
--- a/src/modules/m_namesx.cpp
+++ b/src/modules/m_namesx.cpp
@@ -84,22 +84,9 @@ class ModuleNamesX
if (prefixes.length() <= 1)
return MOD_RES_PASSTHRU;
- size_t flag_index = 5;
- if (request.whox)
- {
- // We only need to fiddle with the flags if they are present.
- if (!request.whox_fields['f'])
- return MOD_RES_PASSTHRU;
-
- // WHOX makes this a bit tricky as we need to work out the parameter which the flags are in.
- flag_index = 0;
- static const char* flags = "tcuihsn";
- for (size_t i = 0; i < strlen(flags); ++i)
- {
- if (request.whox_fields[flags[i]])
- flag_index += 1;
- }
- }
+ size_t flag_index;
+ if (!request.GetFieldIndex('f', flag_index))
+ return MOD_RES_PASSTHRU;
// #chan ident localhost insp22.test nick H@ :0 Attila
if (numeric.GetParams().size() <= flag_index)
diff --git a/src/modules/m_nationalchars.cpp b/src/modules/m_nationalchars.cpp
index 0302cb7f5..884efed23 100644
--- a/src/modules/m_nationalchars.cpp
+++ b/src/modules/m_nationalchars.cpp
@@ -20,8 +20,8 @@
*/
-/* Contains a code of Unreal IRCd + Bynets patch ( http://www.unrealircd.com/ and http://www.bynets.org/ )
- Original patch is made by Dmitry "Killer{R}" Kononko. ( http://killprog.com/ )
+/* Contains a code of Unreal IRCd + Bynets patch (https://www.unrealircd.org and https://bynets.org)
+ Original patch is made by Dmitry "Killer{R}" Kononko. (http://killprog.com)
Changed at 2008-06-15 - 2009-02-11
by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru */
diff --git a/src/modules/m_nicklock.cpp b/src/modules/m_nicklock.cpp
index 987dea86d..77cc53359 100644
--- a/src/modules/m_nicklock.cpp
+++ b/src/modules/m_nicklock.cpp
@@ -40,7 +40,7 @@ class CommandNicklock : public Command
locked(ext)
{
flags_needed = 'o';
- syntax = "<oldnick> <newnick>";
+ syntax = "<nick> <newnick>";
translation = { TR_NICK, TR_TEXT };
}
@@ -100,7 +100,7 @@ class CommandNickunlock : public Command
locked(ext)
{
flags_needed = 'o';
- syntax = "<locked-nick>";
+ syntax = "<nick>";
translation = { TR_NICK };
}
diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp
index b7e981450..9c27b20ea 100644
--- a/src/modules/m_noctcp.cpp
+++ b/src/modules/m_noctcp.cpp
@@ -52,6 +52,9 @@ class ModuleNoCTCP : public Module
if (target.type == MessageTarget::TYPE_CHANNEL)
{
+ if (user->HasPrivPermission("channels/ignore-noctcp"))
+ return MOD_RES_PASSTHRU;
+
Channel* c = target.Get<Channel>();
ModResult res = CheckExemption::Call(exemptionprov, user, c, "noctcp");
if (res == MOD_RES_ALLOW)
@@ -65,11 +68,14 @@ class ModuleNoCTCP : public Module
}
else if (target.type == MessageTarget::TYPE_USER)
{
+ if (user->HasPrivPermission("users/ignore-noctcp"))
+ return MOD_RES_PASSTHRU;
+
User* u = target.Get<User>();
if (u->IsModeSet(ncu))
{
user->WriteNumeric(ERR_CANTSENDTOUSER, u->nick, "Can't send CTCP to user (+T set)");
- return MOD_RES_PASSTHRU;
+ return MOD_RES_DENY;
}
}
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_password_hash.cpp b/src/modules/m_password_hash.cpp
index f0a12019b..ce0e1e156 100644
--- a/src/modules/m_password_hash.cpp
+++ b/src/modules/m_password_hash.cpp
@@ -28,7 +28,7 @@ class CommandMkpasswd : public Command
public:
CommandMkpasswd(Module* Creator) : Command(Creator, "MKPASSWD", 2)
{
- syntax = "<hashtype> <any-text>";
+ syntax = "<hashtype> <plaintext>";
Penalty = 5;
}
diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp
index 59695a43a..90215fdf2 100644
--- a/src/modules/m_permchannels.cpp
+++ b/src/modules/m_permchannels.cpp
@@ -193,9 +193,9 @@ public:
std::string channel = tag->getString("channel");
std::string modes = tag->getString("modes");
- if ((channel.empty()) || (channel.length() > ServerInstance->Config->Limits.ChanMax))
+ if (!ServerInstance->IsChannel(channel))
{
- ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Ignoring permchannels tag with empty or too long channel name (\"" + channel + "\")");
+ ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Ignoring permchannels tag with invalid channel name (\"" + channel + "\")");
continue;
}
diff --git a/src/modules/m_remove.cpp b/src/modules/m_remove.cpp
index eca43ff1c..6459b898d 100644
--- a/src/modules/m_remove.cpp
+++ b/src/modules/m_remove.cpp
@@ -165,7 +165,7 @@ class CommandRemove : public RemoveBase
CommandRemove(Module* Creator, bool& snk, ChanModeReference& nkm)
: RemoveBase(Creator, snk, nkm, "REMOVE")
{
- syntax = "<channel> <nick> [<reason>]";
+ syntax = "<channel> <nick> [:<reason>]";
translation = { TR_NICK, TR_TEXT, TR_TEXT };
}
@@ -183,7 +183,7 @@ class CommandFpart : public RemoveBase
CommandFpart(Module* Creator, bool& snk, ChanModeReference& nkm)
: RemoveBase(Creator, snk, nkm, "FPART")
{
- syntax = "<channel> <nick> [<reason>]";
+ syntax = "<channel> <nick> [:<reason>]";
translation = { TR_TEXT, TR_NICK, TR_TEXT };
}
diff --git a/src/modules/m_repeat.cpp b/src/modules/m_repeat.cpp
index 0c93075f5..7f7fa56c6 100644
--- a/src/modules/m_repeat.cpp
+++ b/src/modules/m_repeat.cpp
@@ -141,14 +141,14 @@ class RepeatMode : public ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> >
if (!ParseSettings(source, parameter, settings))
{
source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter,
- "Invalid repeat syntax. Syntax is {[~*]}[lines]:[time]{:[difference]}{:[backlog]}."));
+ "Invalid repeat syntax. Syntax is: [~|*]<lines>:<sec>[:<difference>][:<backlog>]"));
return MODEACTION_DENY;
}
if ((settings.Backlog > 0) && (settings.Lines > settings.Backlog))
{
source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter,
- "Invalid repeat syntax. You can't set needed lines higher than backlog."));
+ "Invalid repeat syntax. You can't set lines higher than backlog."));
return MODEACTION_DENY;
}
@@ -319,7 +319,7 @@ class RepeatMode : public ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> >
if (ms.MaxSecs && settings.Seconds > ms.MaxSecs)
{
source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format(
- "Invalid repeat parameter. The seconds you specified is too great. Maximum allowed is %u.", ms.MaxSecs)));
+ "Invalid repeat parameter. The seconds you specified are too great. Maximum allowed is %u.", ms.MaxSecs)));
return false;
}
diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp
index a8bf98e3b..6c4db08a9 100644
--- a/src/modules/m_rline.cpp
+++ b/src/modules/m_rline.cpp
@@ -80,9 +80,9 @@ class RLine : public XLine
ZLine* zl = new ZLine(ServerInstance->Time(), duration ? expiry - ServerInstance->Time() : 0, ServerInstance->Config->ServerName.c_str(), reason.c_str(), u->GetIPString());
if (ServerInstance->XLines->AddLine(zl, NULL))
{
- std::string timestr = InspIRCd::TimeString(zl->expiry);
- ServerInstance->SNO.WriteToSnoMask('x', "Z-line added due to R-line match on %s%s%s: %s",
- zl->ipaddr.c_str(), zl->duration ? " to expire on " : "", zl->duration ? timestr.c_str() : "", zl->reason.c_str());
+ std::string expirystr = zl->duration ? InspIRCd::Format(" to expire in %s (on %s)", InspIRCd::DurationString(zl->duration).c_str(), InspIRCd::TimeString(zl->expiry).c_str()) : "";
+ ServerInstance->SNO.WriteToSnoMask('x', "Z-line added due to R-line match on %s%s: %s",
+ zl->ipaddr.c_str(), expirystr.c_str(), zl->reason.c_str());
added_zline = true;
}
else
@@ -137,7 +137,7 @@ class CommandRLine : public Command
public:
CommandRLine(Module* Creator, RLineFactory& rlf) : Command(Creator,"RLINE", 1, 3), factory(rlf)
{
- flags_needed = 'o'; this->syntax = "<regex> [<rline-duration>] :<reason>";
+ flags_needed = 'o'; this->syntax = "<regex> [<duration> :<reason>]";
}
CmdResult Handle(User* user, const Params& parameters) override
@@ -174,9 +174,9 @@ class CommandRLine : public Command
}
else
{
- time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = InspIRCd::TimeString(c_requires_crap);
- ServerInstance->SNO.WriteToSnoMask('x', "%s added timed R-line for %s to expire on %s: %s", user->nick.c_str(), parameters[0].c_str(), timestr.c_str(), parameters[2].c_str());
+ ServerInstance->SNO.WriteToSnoMask('x', "%s added timed R-line for %s to expire in %s (on %s): %s",
+ user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str());
}
ServerInstance->XLines->ApplyLines();
diff --git a/src/modules/m_rmode.cpp b/src/modules/m_rmode.cpp
index 76b89d6db..fdeb8565d 100644
--- a/src/modules/m_rmode.cpp
+++ b/src/modules/m_rmode.cpp
@@ -28,7 +28,7 @@ class CommandRMode : public Command
CommandRMode(Module* Creator) : Command(Creator,"RMODE", 2, 3)
{
allow_empty_last_param = false;
- syntax = "<channel> <mode> [pattern]";
+ syntax = "<channel> <mode> [<pattern>]";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_sajoin.cpp b/src/modules/m_sajoin.cpp
index 2ed66f9fd..8d7403b0e 100644
--- a/src/modules/m_sajoin.cpp
+++ b/src/modules/m_sajoin.cpp
@@ -29,7 +29,8 @@ class CommandSajoin : public Command
CommandSajoin(Module* Creator) : Command(Creator,"SAJOIN", 1)
{
allow_empty_last_param = false;
- flags_needed = 'o'; syntax = "[<nick>] <channel>[,<channel>]";
+ flags_needed = 'o';
+ syntax = "[<nick>] <channel>[,<channel>]+";
translation = { TR_NICK, TR_TEXT };
}
@@ -53,7 +54,7 @@ class CommandSajoin : public Command
if (dest->server->IsULine())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client");
+ user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client");
return CMD_FAILURE;
}
if (IS_LOCAL(user) && !ServerInstance->IsChannel(channel))
diff --git a/src/modules/m_sakick.cpp b/src/modules/m_sakick.cpp
index af336ed8d..7f1144504 100644
--- a/src/modules/m_sakick.cpp
+++ b/src/modules/m_sakick.cpp
@@ -27,7 +27,7 @@ class CommandSakick : public Command
public:
CommandSakick(Module* Creator) : Command(Creator,"SAKICK", 2, 3)
{
- flags_needed = 'o'; syntax = "<channel> <nick> [reason]";
+ flags_needed = 'o'; syntax = "<channel> <nick> [:<reason>]";
translation = { TR_TEXT, TR_NICK, TR_TEXT };
}
@@ -42,7 +42,7 @@ class CommandSakick : public Command
if (dest->server->IsULine())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client");
+ user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client");
return CMD_FAILURE;
}
diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp
index 3e823b09f..6df95c10e 100644
--- a/src/modules/m_samode.cpp
+++ b/src/modules/m_samode.cpp
@@ -33,7 +33,7 @@ class CommandSamode : public Command
CommandSamode(Module* Creator) : Command(Creator,"SAMODE", 2)
{
allow_empty_last_param = false;
- flags_needed = 'o'; syntax = "<target> <modes> {<mode-parameters>}";
+ flags_needed = 'o'; syntax = "<target> (+|-)<modes> [<mode-parameters>]";
active = false;
}
diff --git a/src/modules/m_sanick.cpp b/src/modules/m_sanick.cpp
index 3d809f5d4..0e785359e 100644
--- a/src/modules/m_sanick.cpp
+++ b/src/modules/m_sanick.cpp
@@ -29,7 +29,8 @@ class CommandSanick : public Command
CommandSanick(Module* Creator) : Command(Creator,"SANICK", 2)
{
allow_empty_last_param = false;
- flags_needed = 'o'; syntax = "<nick> <new-nick>";
+ flags_needed = 'o';
+ syntax = "<nick> <newnick>";
translation = { TR_NICK, TR_TEXT };
}
@@ -42,7 +43,7 @@ class CommandSanick : public Command
{
if (target && target->server->IsULine())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client");
+ user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client");
return CMD_FAILURE;
}
diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp
index 484bb44e3..57cc70628 100644
--- a/src/modules/m_sapart.cpp
+++ b/src/modules/m_sapart.cpp
@@ -28,7 +28,8 @@ class CommandSapart : public Command
public:
CommandSapart(Module* Creator) : Command(Creator,"SAPART", 2, 3)
{
- flags_needed = 'o'; syntax = "<nick> <channel>[,<channel>] [reason]";
+ flags_needed = 'o';
+ syntax = "<nick> <channel>[,<channel>]+ [:<reason>]";
translation = { TR_NICK, TR_TEXT, TR_TEXT };
}
@@ -48,7 +49,7 @@ class CommandSapart : public Command
if (dest->server->IsULine())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client");
+ user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client");
return CMD_FAILURE;
}
diff --git a/src/modules/m_saquit.cpp b/src/modules/m_saquit.cpp
index 6b9af2baf..1d03d1fc7 100644
--- a/src/modules/m_saquit.cpp
+++ b/src/modules/m_saquit.cpp
@@ -28,7 +28,8 @@ class CommandSaquit : public Command
public:
CommandSaquit(Module* Creator) : Command(Creator, "SAQUIT", 2, 2)
{
- flags_needed = 'o'; syntax = "<nick> <reason>";
+ flags_needed = 'o';
+ syntax = "<nick> :<reason>";
translation = { TR_NICK, TR_TEXT };
}
@@ -39,7 +40,7 @@ class CommandSaquit : public Command
{
if (dest->server->IsULine())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client");
+ user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client");
return CMD_FAILURE;
}
diff --git a/src/modules/m_satopic.cpp b/src/modules/m_satopic.cpp
index f2c75942e..4f5efde3b 100644
--- a/src/modules/m_satopic.cpp
+++ b/src/modules/m_satopic.cpp
@@ -26,7 +26,7 @@ class CommandSATopic : public Command
public:
CommandSATopic(Module* Creator) : Command(Creator,"SATOPIC", 2, 2)
{
- flags_needed = 'o'; syntax = "<target> <topic>";
+ flags_needed = 'o'; syntax = "<channel> :<topic>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_sethost.cpp b/src/modules/m_sethost.cpp
index 4b22cae66..58d712c70 100644
--- a/src/modules/m_sethost.cpp
+++ b/src/modules/m_sethost.cpp
@@ -32,7 +32,7 @@ class CommandSethost : public Command
: Command(Creator,"SETHOST", 1)
{
allow_empty_last_param = false;
- flags_needed = 'o'; syntax = "<new-hostname>";
+ flags_needed = 'o'; syntax = "<host>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_setident.cpp b/src/modules/m_setident.cpp
index d83d5a75e..ecfa62bea 100644
--- a/src/modules/m_setident.cpp
+++ b/src/modules/m_setident.cpp
@@ -30,7 +30,7 @@ class CommandSetident : public Command
CommandSetident(Module* Creator) : Command(Creator,"SETIDENT", 1)
{
allow_empty_last_param = false;
- flags_needed = 'o'; syntax = "<new-ident>";
+ flags_needed = 'o'; syntax = "<ident>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp
index 135525512..3fedc9830 100644
--- a/src/modules/m_setname.cpp
+++ b/src/modules/m_setname.cpp
@@ -30,7 +30,7 @@ class CommandSetname : public Command
CommandSetname(Module* Creator) : Command(Creator,"SETNAME", 1, 1)
{
allow_empty_last_param = false;
- syntax = "<new real name>";
+ syntax = ":<realname>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_shun.cpp b/src/modules/m_shun.cpp
index f8b7f82bb..9e7529571 100644
--- a/src/modules/m_shun.cpp
+++ b/src/modules/m_shun.cpp
@@ -53,7 +53,7 @@ class CommandShun : public Command
public:
CommandShun(Module* Creator) : Command(Creator, "SHUN", 1, 3)
{
- flags_needed = 'o'; this->syntax = "<nick!user@hostmask> [<shun-duration>] :<reason>";
+ flags_needed = 'o'; this->syntax = "<nick!user@host> [<duration> :<reason>]";
}
CmdResult Handle(User* user, const Params& parameters) override
@@ -110,15 +110,14 @@ class CommandShun : public Command
{
if (!duration)
{
- ServerInstance->SNO.WriteToSnoMask('x',"%s added permanent SHUN for %s: %s",
+ ServerInstance->SNO.WriteToSnoMask('x', "%s added permanent SHUN for %s: %s",
user->nick.c_str(), target.c_str(), expr.c_str());
}
else
{
- time_t c_requires_crap = duration + ServerInstance->Time();
- std::string timestr = InspIRCd::TimeString(c_requires_crap);
- ServerInstance->SNO.WriteToSnoMask('x', "%s added timed SHUN for %s to expire on %s: %s",
- user->nick.c_str(), target.c_str(), timestr.c_str(), expr.c_str());
+ ServerInstance->SNO.WriteToSnoMask('x', "%s added timed SHUN for %s to expire in %s (on %s): %s",
+ user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(),
+ InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), expr.c_str());
}
}
else
diff --git a/src/modules/m_silence.cpp b/src/modules/m_silence.cpp
index 5c4a8c630..40b2bb81f 100644
--- a/src/modules/m_silence.cpp
+++ b/src/modules/m_silence.cpp
@@ -24,7 +24,7 @@
#include "inspircd.h"
/* Improved drop-in replacement for the /SILENCE command
- * syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude>
+ * syntax: /SILENCE [(+|-)<mask> [p|c|i|n|t|a|x]] as in [privatemessages|channelmessages|invites|privatenotices|channelnotices|all|exclude]
*
* example that blocks all except private messages
* /SILENCE +*!*@* a
@@ -74,7 +74,7 @@ class CommandSVSSilence : public Command
public:
CommandSVSSilence(Module* Creator) : Command(Creator,"SVSSILENCE", 2)
{
- syntax = "<target> {[+|-]<mask> <p|c|i|n|t|a|x>}";
+ syntax = "<target> (+|-)<mask> [p|c|i|n|t|a|x]";
translation = { TR_NICK, TR_TEXT, TR_TEXT };
}
@@ -119,7 +119,7 @@ class CommandSilence : public Command
, ext("silence_list", ExtensionItem::EXT_USER, Creator)
{
allow_empty_last_param = false;
- syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}";
+ syntax = "[(+|-)<mask> [p|c|i|n|t|a|x]]";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_spanningtree/addline.cpp b/src/modules/m_spanningtree/addline.cpp
index 85b550508..81e9d1467 100644
--- a/src/modules/m_spanningtree/addline.cpp
+++ b/src/modules/m_spanningtree/addline.cpp
@@ -50,14 +50,16 @@ CmdResult CommandAddLine::Handle(User* usr, Params& params)
{
if (xl->duration)
{
- std::string timestr = InspIRCd::TimeString(xl->expiry);
- ServerInstance->SNO.WriteToSnoMask('X',"%s added %s%s on %s to expire on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "",
- params[1].c_str(), timestr.c_str(), params[5].c_str());
+ ServerInstance->SNO.WriteToSnoMask('X', "%s added %s%s on %s to expire in %s (on %s): %s",
+ setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "",
+ params[1].c_str(), InspIRCd::DurationString(xl->duration).c_str(),
+ InspIRCd::TimeString(xl->expiry).c_str(), params[5].c_str());
}
else
{
- ServerInstance->SNO.WriteToSnoMask('X',"%s added permanent %s%s on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "",
- params[1].c_str(),params[5].c_str());
+ ServerInstance->SNO.WriteToSnoMask('X', "%s added permanent %s%s on %s: %s",
+ setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "",
+ params[1].c_str(), params[5].c_str());
}
TreeServer* remoteserver = TreeServer::Get(usr);
diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp
index d95465f40..9ba6cfc1c 100644
--- a/src/modules/m_spanningtree/compat.cpp
+++ b/src/modules/m_spanningtree/compat.cpp
@@ -42,7 +42,7 @@ void TreeSocket::WriteLine(const std::string& original_line)
if (line[0] == '@')
{
// The line contains tags which the 1202 protocol can't handle.
- line.erase(0, a);
+ line.erase(0, a + 1);
a = line.find(' ');
}
std::string::size_type b = line.find(' ', a + 1);
@@ -309,6 +309,11 @@ void TreeSocket::WriteLine(const std::string& original_line)
push.append(line, 26, std::string::npos);
push.swap(line);
}
+ else if (command == "TAGMSG")
+ {
+ // Drop IRCv3 tag messages as v2 has no message tag support.
+ return;
+ }
}
WriteLineNoCompat(line);
return;
diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp
index 321943e2e..ee73e6d9f 100644
--- a/src/modules/m_spanningtree/main.cpp
+++ b/src/modules/m_spanningtree/main.cpp
@@ -45,6 +45,7 @@ ModuleSpanningTree::ModuleSpanningTree()
, commands(this)
, currmembid(0)
, eventprov(this, "event/server")
+ , sslapi(this)
, DNS(this, "DNS")
, tagevprov(this, "event/messagetag")
, loopCall(false)
@@ -447,6 +448,10 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user)
if (user->quitting)
return;
+ // Create the lazy ssl_cert metadata for this user if not already created.
+ if (sslapi)
+ sslapi->GetCertificate(user);
+
CommandUID::Builder(user).Broadcast();
if (user->IsOper())
diff --git a/src/modules/m_spanningtree/main.h b/src/modules/m_spanningtree/main.h
index 7ffa4a748..1afd5e7ef 100644
--- a/src/modules/m_spanningtree/main.h
+++ b/src/modules/m_spanningtree/main.h
@@ -26,6 +26,7 @@
#include "inspircd.h"
#include "event.h"
#include "modules/dns.h"
+#include "modules/ssl.h"
#include "modules/stats.h"
#include "servercommand.h"
#include "commands.h"
@@ -80,6 +81,9 @@ class ModuleSpanningTree
*/
Events::ModuleEventProvider eventprov;
+ /** API for accessing user SSL certificates. */
+ UserCertificateAPI sslapi;
+
public:
dynamic_reference<DNS::Manager> DNS;
diff --git a/src/modules/m_spanningtree/rsquit.cpp b/src/modules/m_spanningtree/rsquit.cpp
index f4ffe3bfa..22f181f82 100644
--- a/src/modules/m_spanningtree/rsquit.cpp
+++ b/src/modules/m_spanningtree/rsquit.cpp
@@ -29,7 +29,7 @@ CommandRSQuit::CommandRSQuit(Module* Creator)
: Command(Creator, "RSQUIT", 1)
{
flags_needed = 'o';
- syntax = "<target-server-mask> [reason]";
+ syntax = "<target-server-mask> [:<reason>]";
}
CmdResult CommandRSQuit::Handle(User* user, const Params& parameters)
diff --git a/src/modules/m_spanningtree/server.cpp b/src/modules/m_spanningtree/server.cpp
index e2ba99682..9e1b164be 100644
--- a/src/modules/m_spanningtree/server.cpp
+++ b/src/modules/m_spanningtree/server.cpp
@@ -114,7 +114,7 @@ Link* TreeSocket::AuthRemote(const CommandBase::Params& params)
for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i < Utils->LinkBlocks.end(); i++)
{
Link* x = *i;
- if ((!stdalgo::string::equalsci(x->Name, sname)) && (x->Name != "*")) // open link allowance
+ if (!InspIRCd::Match(sname, x->Name))
continue;
if (!ComparePass(*x, password))
diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp
index b6a208d39..1c5c4d8c9 100644
--- a/src/modules/m_sslinfo.cpp
+++ b/src/modules/m_sslinfo.cpp
@@ -21,6 +21,7 @@
#include "modules/ssl.h"
#include "modules/webirc.h"
#include "modules/whois.h"
+#include "modules/who.h"
enum
{
@@ -184,6 +185,7 @@ class ModuleSSLInfo
: public Module
, public WebIRC::EventListener
, public Whois::EventListener
+ , public Who::EventListener
{
private:
CommandSSLInfo cmd;
@@ -197,6 +199,7 @@ class ModuleSSLInfo
ModuleSSLInfo()
: WebIRC::EventListener(this)
, Whois::EventListener(this)
+ , Who::EventListener(this)
, cmd(this)
{
}
@@ -218,6 +221,19 @@ class ModuleSSLInfo
}
}
+ ModResult OnWhoLine(const Who::Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) override
+ {
+ size_t flag_index;
+ if (!request.GetFieldIndex('f', flag_index))
+ return MOD_RES_PASSTHRU;
+
+ ssl_cert* cert = cmd.sslapi.GetCertificate(user);
+ if (cert)
+ numeric.GetParams()[flag_index].push_back('s');
+
+ return MOD_RES_PASSTHRU;
+ }
+
ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) override
{
if ((command == "OPER") && (validated))
diff --git a/src/modules/m_svshold.cpp b/src/modules/m_svshold.cpp
index f226ba780..3da73224f 100644
--- a/src/modules/m_svshold.cpp
+++ b/src/modules/m_svshold.cpp
@@ -58,8 +58,8 @@ public:
{
if (!silent)
{
- ServerInstance->SNO.WriteToSnoMask('x', "Removing expired SVSHOLD %s (set by %s %ld seconds ago): %s",
- nickname.c_str(), source.c_str(), (long)(ServerInstance->Time() - set_time), reason.c_str());
+ ServerInstance->SNO.WriteToSnoMask('x', "Removing expired SVSHOLD %s (set by %s %s ago): %s",
+ nickname.c_str(), source.c_str(), InspIRCd::DurationString(ServerInstance->Time() - set_time).c_str(), reason.c_str());
}
}
@@ -96,7 +96,7 @@ class CommandSvshold : public Command
public:
CommandSvshold(Module* Creator) : Command(Creator, "SVSHOLD", 1)
{
- flags_needed = 'o'; this->syntax = "<nickname> [<duration> :<reason>]";
+ flags_needed = 'o'; this->syntax = "<nick> [<duration> :<reason>]";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_timedbans.cpp b/src/modules/m_timedbans.cpp
index 08158ece8..931c4e707 100644
--- a/src/modules/m_timedbans.cpp
+++ b/src/modules/m_timedbans.cpp
@@ -118,7 +118,7 @@ class CommandTban : public Command
T.chan = channel;
TimedBanList.push_back(T);
- const std::string addban = user->nick + " added a timed ban on " + mask + " lasting for " + ConvToStr(duration) + " seconds.";
+ const std::string addban = user->nick + " added a timed ban on " + mask + " lasting for " + InspIRCd::DurationString(duration) + ".";
// If halfop is loaded, send notice to halfops and above, otherwise send to ops and above
PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h');
char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@';
diff --git a/src/modules/m_userip.cpp b/src/modules/m_userip.cpp
index 444ff6fe7..6e540a206 100644
--- a/src/modules/m_userip.cpp
+++ b/src/modules/m_userip.cpp
@@ -28,7 +28,7 @@ class CommandUserip : public Command
public:
CommandUserip(Module* Creator) : Command(Creator,"USERIP", 1)
{
- syntax = "<nick> [<nick> ...]";
+ syntax = "<nick> [<nick>]+";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_watch.cpp b/src/modules/m_watch.cpp
index 46870eceb..f03f1b5a3 100644
--- a/src/modules/m_watch.cpp
+++ b/src/modules/m_watch.cpp
@@ -133,7 +133,7 @@ class CommandWatch : public SplitCommand
, manager(managerref)
{
allow_empty_last_param = false;
- syntax = "[<C|L|S|l|+<nick1>|-<nick>>]";
+ syntax = "C|L|l|S|(+|-)<nick> [(+|-)<nick>]+";
}
CmdResult HandleLocal(LocalUser* user, const Params& parameters) override
diff --git a/src/modules/m_xline_db.cpp b/src/modules/m_xline_db.cpp
index d42423a24..5b3840202 100644
--- a/src/modules/m_xline_db.cpp
+++ b/src/modules/m_xline_db.cpp
@@ -51,7 +51,8 @@ class ModuleXLineDB : public Module
*/
void OnAddLine(User* source, XLine* line) override
{
- dirty = true;
+ if (!line->from_config)
+ dirty = true;
}
/** Called whenever an xline is deleted.
@@ -61,7 +62,8 @@ class ModuleXLineDB : public Module
*/
void OnDelLine(User* source, XLine* line) override
{
- dirty = true;
+ if (!line->from_config)
+ dirty = true;
}
void OnBackgroundTimer(time_t now) override
@@ -113,6 +115,9 @@ class ModuleXLineDB : public Module
for (LookupIter i = lookup->begin(); i != lookup->end(); ++i)
{
XLine* line = i->second;
+ if (line->from_config)
+ continue;
+
stream << "LINE " << line->type << " " << line->Displayable() << " "
<< line->source << " " << line->set_time << " "
<< line->duration << " :" << line->reason << std::endl;