summaryrefslogtreecommitdiff
path: root/include/modules
diff options
context:
space:
mode:
Diffstat (limited to 'include/modules')
-rw-r--r--include/modules/account.h48
-rw-r--r--include/modules/away.h83
-rw-r--r--include/modules/cap.h335
-rw-r--r--include/modules/dns.h204
-rw-r--r--include/modules/exemption.h75
-rw-r--r--include/modules/hash.h72
-rw-r--r--include/modules/httpd.h262
-rw-r--r--include/modules/invite.h128
-rw-r--r--include/modules/ircv3.h101
-rw-r--r--include/modules/ircv3_batch.h185
-rw-r--r--include/modules/ircv3_servertime.h88
-rw-r--r--include/modules/ldap.h192
-rw-r--r--include/modules/regex.h62
-rw-r--r--include/modules/reload.h80
-rw-r--r--include/modules/sasl.h33
-rw-r--r--include/modules/server.h61
-rw-r--r--include/modules/shun.h70
-rw-r--r--include/modules/sql.h267
-rw-r--r--include/modules/ssl.h305
-rw-r--r--include/modules/stats.h191
-rw-r--r--include/modules/whois.h146
21 files changed, 2988 insertions, 0 deletions
diff --git a/include/modules/account.h b/include/modules/account.h
new file mode 100644
index 000000000..0368127a6
--- /dev/null
+++ b/include/modules/account.h
@@ -0,0 +1,48 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include <map>
+#include <string>
+
+#include "event.h"
+
+typedef StringExtItem AccountExtItem;
+
+inline AccountExtItem* GetAccountExtItem()
+{
+ return static_cast<AccountExtItem*>(ServerInstance->Extensions.GetItem("accountname"));
+}
+
+class AccountEventListener : public Events::ModuleEventListener
+{
+ public:
+ AccountEventListener(Module* mod)
+ : ModuleEventListener(mod, "event/account")
+ {
+ }
+
+ /** Called when a user logs in or logs out
+ * @param user User logging in or out
+ * @param newaccount New account name of the user or empty string if the user
+ * logged out
+ */
+ virtual void OnAccountChange(User* user, const std::string& newaccount) = 0;
+};
diff --git a/include/modules/away.h b/include/modules/away.h
new file mode 100644
index 000000000..f231f0a06
--- /dev/null
+++ b/include/modules/away.h
@@ -0,0 +1,83 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2016-2017 Peter Powell <petpow@saberuk.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/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+namespace Away
+{
+ class EventListener;
+ class EventProvider;
+}
+
+class Away::EventListener
+ : public Events::ModuleEventListener
+{
+ protected:
+ EventListener(Module* mod)
+ : ModuleEventListener(mod, "event/away")
+ {
+ }
+
+ public:
+ /** Called when a user wishes to mark themselves as away.
+ * @param user The user who is going away.
+ * @param message The away message that the user set.
+ * @return Either MOD_RES_ALLOW to allow the user to mark themself as away, MOD_RES_DENY to
+ * disallow the user to mark themself as away, or MOD_RES_PASSTHRU to let another module
+ * handle the event.
+ */
+ virtual ModResult OnUserPreAway(LocalUser* user, std::string& message)
+ {
+ return MOD_RES_PASSTHRU;
+ }
+
+ /** Called when a user wishes to mark themselves as back.
+ * @param user The user who is going away.
+ * @param message The away message that the user set.
+ * @return Either MOD_RES_ALLOW to allow the user to mark themself as back, MOD_RES_DENY to
+ * disallow the user to mark themself as back, or MOD_RES_PASSTHRU to let another module
+ * handle the event.
+ */
+ virtual ModResult OnUserPreBack(LocalUser* user)
+ {
+ return MOD_RES_PASSTHRU;
+ }
+
+ /** Called when a user has marked themself as away.
+ * @param user The user who has gone away.
+ */
+ virtual void OnUserAway(User* user) = 0;
+
+ /** Called when a user has returned from being away.
+ * @param user The user who has returned from being away.
+ */
+ virtual void OnUserBack(User* user) = 0;
+};
+
+class Away::EventProvider
+ : public Events::ModuleEventProvider
+{
+ public:
+ EventProvider(Module* mod)
+ : ModuleEventProvider(mod, "event/away")
+ {
+ }
+};
diff --git a/include/modules/cap.h b/include/modules/cap.h
new file mode 100644
index 000000000..6dcb9f3bc
--- /dev/null
+++ b/include/modules/cap.h
@@ -0,0 +1,335 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+namespace Cap
+{
+ static const unsigned int MAX_CAPS = (sizeof(intptr_t) * 8) - 1;
+ static const intptr_t CAP_302_BIT = (intptr_t)1 << MAX_CAPS;
+ static const unsigned int MAX_VALUE_LENGTH = 100;
+
+ typedef intptr_t Ext;
+ class ExtItem : public LocalIntExt
+ {
+ public:
+ ExtItem(Module* mod);
+ std::string serialize(SerializeFormat format, const Extensible* container, void* item) const CXX11_OVERRIDE;
+ void unserialize(SerializeFormat format, Extensible* container, const std::string& value) CXX11_OVERRIDE;
+ };
+
+ class Capability;
+
+ enum Protocol
+ {
+ /** Supports capability negotiation protocol v3.1, or none
+ */
+ CAP_LEGACY,
+
+ /** Supports capability negotiation v3.2
+ */
+ CAP_302
+ };
+
+ class EventListener : public Events::ModuleEventListener
+ {
+ public:
+ EventListener(Module* mod)
+ : ModuleEventListener(mod, "event/cap")
+ {
+ }
+
+ /** Called whenever a new client capability becomes available or unavailable
+ * @param cap Capability being added or removed
+ * @param add If true, the capability is being added, otherwise its being removed
+ */
+ virtual void OnCapAddDel(Capability* cap, bool add) = 0;
+
+ /** Called whenever the value of a cap changes.
+ * @param cap Capability whose value changed
+ */
+ virtual void OnCapValueChange(Capability* cap) { }
+ };
+
+ class Manager : public DataProvider
+ {
+ public:
+ Manager(Module* mod)
+ : DataProvider(mod, "capmanager")
+ {
+ }
+
+ /** Register a client capability.
+ * Modules should call Capability::SetActive(true) instead of this method.
+ * @param cap Capability to register
+ */
+ virtual void AddCap(Capability* cap) = 0;
+
+ /** Unregister a client capability.
+ * Modules should call Capability::SetActive(false) instead of this method.
+ * @param cap Capability to unregister
+ */
+ virtual void DelCap(Capability* cap) = 0;
+
+ /** Find a capability by name
+ * @param name Capability to find
+ * @return Capability object pointer if found, NULL otherwise
+ */
+ virtual Capability* Find(const std::string& name) const = 0;
+
+ /** Notify manager when a value of a cap changed
+ * @param cap Cap whose value changed
+ */
+ virtual void NotifyValueChange(Capability* cap) = 0;
+ };
+
+ /** Represents a client capability.
+ *
+ * Capabilities offer extensions to the client to server protocol. They must be negotiated with clients before they have any effect on the protocol.
+ * Each cap must have a unique name that is used during capability negotiation.
+ *
+ * After construction the cap is ready to be used by clients without any further setup, like other InspIRCd services.
+ * The get() method accepts a user as parameter and can be used to check whether that user has negotiated usage of the cap. This is only known for local users.
+ *
+ * The cap module must be loaded for the capability to work. The IsRegistered() method can be used to query whether the cap is actually online or not.
+ * The capability can be deactivated and reactivated with the SetActive() method. Deactivated caps behave as if they don't exist.
+ *
+ * It is possible to implement special behavior by inheriting from this class and overriding some of its methods.
+ */
+ class Capability : public ServiceProvider, private dynamic_reference_base::CaptureHook
+ {
+ typedef size_t Bit;
+
+ /** Bit allocated to this cap, undefined if the cap is unregistered
+ */
+ Bit bit;
+
+ /** Extension containing all caps set by a user. NULL if the cap is unregistered.
+ */
+ ExtItem* extitem;
+
+ /** True if the cap is active. Only active caps are registered in the manager.
+ */
+ bool active;
+
+ /** Reference to the cap manager object
+ */
+ dynamic_reference<Manager> manager;
+
+ void OnCapture() CXX11_OVERRIDE
+ {
+ if (active)
+ SetActive(true);
+ }
+
+ void Unregister()
+ {
+ bit = 0;
+ extitem = NULL;
+ }
+
+ Ext AddToMask(Ext mask) const { return (mask | GetMask()); }
+ Ext DelFromMask(Ext mask) const { return (mask & (~GetMask())); }
+ Bit GetMask() const { return bit; }
+
+ friend class ManagerImpl;
+
+ protected:
+ /** Notify the manager that the value of the capability changed.
+ * Must be called if the value of the cap changes for any reason.
+ */
+ void NotifyValueChange()
+ {
+ if (IsRegistered())
+ manager->NotifyValueChange(this);
+ }
+
+ public:
+ /** Constructor, initializes the capability.
+ * Caps are active by default.
+ * @param mod Module providing the cap
+ * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.)
+ */
+ Capability(Module* mod, const std::string& Name)
+ : ServiceProvider(mod, Name, SERVICE_CUSTOM)
+ , active(true)
+ , manager(mod, "capmanager")
+ {
+ Unregister();
+ }
+
+ ~Capability()
+ {
+ SetActive(false);
+ }
+
+ void RegisterService() CXX11_OVERRIDE
+ {
+ manager.SetCaptureHook(this);
+ SetActive(true);
+ }
+
+ /** Check whether a user has the capability turned on.
+ * This method is safe to call if the cap is unregistered and will return false.
+ * @param user User to check
+ * @return True if the user is using this capability, false otherwise
+ */
+ bool get(User* user) const
+ {
+ if (!IsRegistered())
+ return false;
+ Ext caps = extitem->get(user);
+ return ((caps & GetMask()) != 0);
+ }
+
+ /** Turn the capability on/off for a user. If the cap is not registered this method has no effect.
+ * @param user User to turn the cap on/off for
+ * @param val True to turn the cap on, false to turn it off
+ */
+ void set(User* user, bool val)
+ {
+ if (!IsRegistered())
+ return;
+ Ext curr = extitem->get(user);
+ extitem->set(user, (val ? AddToMask(curr) : DelFromMask(curr)));
+ }
+
+ /** Activate or deactivate the capability.
+ * If activating, the cap is marked as active and if the manager is available the cap is registered in the manager.
+ * If deactivating, the cap is marked as inactive and if it is registered, it will be unregistered.
+ * Users who had the cap turned on will have it turned off automatically.
+ * @param activate True to activate the cap, false to deactivate it
+ */
+ void SetActive(bool activate)
+ {
+ active = activate;
+ if (manager)
+ {
+ if (activate)
+ manager->AddCap(this);
+ else
+ manager->DelCap(this);
+ }
+ }
+
+ /** Get the name of the capability that's used in the protocol
+ * @return Name of the capability as used in the protocol
+ */
+ const std::string& GetName() const { return name; }
+
+ /** Check whether the capability is active. The cap must be active and registered to be used by users.
+ * @return True if the cap is active, false if it has been deactivated
+ */
+ bool IsActive() const { return active; }
+
+ /** Check whether the capability is registered
+ * The cap must be active and the manager must be available for a cap to be registered.
+ * @return True if the cap is registered in the manager, false otherwise
+ */
+ bool IsRegistered() const { return (extitem != NULL); }
+
+ /** Get the CAP negotiation protocol version of a user.
+ * The cap must be registered for this to return anything other than CAP_LEGACY.
+ * @param user User whose negotiation protocol version to query
+ * @return One of the Capability::Protocol enum indicating the highest supported capability negotiation protocol version
+ */
+ Protocol GetProtocol(LocalUser* user) const
+ {
+ return ((IsRegistered() && (extitem->get(user) & CAP_302_BIT)) ? CAP_302 : CAP_LEGACY);
+ }
+
+ /** Called when a user requests to turn this capability on or off.
+ * @param user User requesting to change the state of the cap
+ * @param add True if requesting to turn the cap on, false if requesting to turn it off
+ * @return True to allow the request, false to reject it
+ */
+ virtual bool OnRequest(LocalUser* user, bool add)
+ {
+ return true;
+ }
+
+ /** Called when a user requests a list of all capabilities and this capability is about to be included in the list.
+ * The default behavior always includes the cap in the list.
+ * @param user User querying a list capabilities
+ * @return True to add this cap to the list sent to the user, false to not list it
+ */
+ virtual bool OnList(LocalUser* user)
+ {
+ return true;
+ }
+
+ /** Query the value of this capability for a user
+ * @param user User who will get the value of the capability
+ * @return Value to show to the user. If NULL, the capability has no value (default).
+ */
+ virtual const std::string* GetValue(LocalUser* user) const
+ {
+ return NULL;
+ }
+ };
+
+ /** Reference to a cap. The cap may be provided by another module.
+ */
+ class Reference
+ {
+ dynamic_reference_nocheck<Capability> ref;
+
+ public:
+ /** Constructor, initializes the capability reference
+ * @param mod Module creating this object
+ * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.)
+ */
+ Reference(Module* mod, const std::string& Name)
+ : ref(mod, "cap/" + Name)
+ {
+ }
+
+ /** Check whether a user has the referenced capability turned on.
+ * @param user User to check
+ * @return True if the user is using the referenced capability, false otherwise
+ */
+ bool get(LocalUser* user)
+ {
+ if (ref)
+ return ref->get(user);
+ return false;
+ }
+ };
+
+ class MessageBase : public ClientProtocol::Message
+ {
+ public:
+ MessageBase(const std::string& subcmd)
+ : ClientProtocol::Message("CAP", ServerInstance->Config->ServerName)
+ {
+ PushParamPlaceholder();
+ PushParam(subcmd);
+ }
+
+ void SetUser(LocalUser* user)
+ {
+ if (user->registered & REG_NICK)
+ ReplaceParamRef(0, user->nick);
+ else
+ ReplaceParam(0, "*");
+ }
+ };
+}
diff --git a/include/modules/dns.h b/include/modules/dns.h
new file mode 100644
index 000000000..3db651798
--- /dev/null
+++ b/include/modules/dns.h
@@ -0,0 +1,204 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2013 Adam <Adam@anope.org>
+ * Copyright (C) 2003-2013 Anope Team <team@anope.org>
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+namespace DNS
+{
+ /** Valid query types
+ */
+ enum QueryType
+ {
+ /* Nothing */
+ QUERY_NONE,
+ /* A simple A lookup */
+ QUERY_A = 1,
+ /* A CNAME lookup */
+ QUERY_CNAME = 5,
+ /* Reverse DNS lookup */
+ QUERY_PTR = 12,
+ /* TXT */
+ QUERY_TXT = 16,
+ /* IPv6 AAAA lookup */
+ QUERY_AAAA = 28
+ };
+
+ /** Flags that can be AND'd into DNSPacket::flags to receive certain values
+ */
+ enum
+ {
+ QUERYFLAGS_QR = 0x8000,
+ QUERYFLAGS_OPCODE = 0x7800,
+ QUERYFLAGS_AA = 0x400,
+ QUERYFLAGS_TC = 0x200,
+ QUERYFLAGS_RD = 0x100,
+ QUERYFLAGS_RA = 0x80,
+ QUERYFLAGS_Z = 0x70,
+ QUERYFLAGS_RCODE = 0xF
+ };
+
+ enum Error
+ {
+ ERROR_NONE,
+ ERROR_UNKNOWN,
+ ERROR_UNLOADED,
+ ERROR_TIMEDOUT,
+ ERROR_MALFORMED,
+ ERROR_NOT_AN_ANSWER,
+ ERROR_NONSTANDARD_QUERY,
+ ERROR_FORMAT_ERROR,
+ ERROR_SERVER_FAILURE,
+ ERROR_DOMAIN_NOT_FOUND,
+ ERROR_NOT_IMPLEMENTED,
+ ERROR_REFUSED,
+ ERROR_NO_RECORDS,
+ ERROR_INVALIDTYPE
+ };
+
+ typedef uint16_t RequestId;
+
+ const int PORT = 53;
+
+ class Exception : public ModuleException
+ {
+ public:
+ Exception(const std::string& message) : ModuleException(message) { }
+ };
+
+ struct Question
+ {
+ std::string name;
+ QueryType type;
+
+ Question() : type(QUERY_NONE) { }
+ Question(const std::string& n, QueryType t) : name(n), type(t) { }
+ bool operator==(const Question& other) const { return ((name == other.name) && (type == other.type)); }
+ bool operator!=(const Question& other) const { return (!(*this == other)); }
+
+ struct hash
+ {
+ size_t operator()(const Question& question) const
+ {
+ return irc::insensitive()(question.name);
+ }
+ };
+ };
+
+ struct ResourceRecord : Question
+ {
+ unsigned int ttl;
+ std::string rdata;
+ time_t created;
+
+ ResourceRecord(const std::string& n, QueryType t) : Question(n, t), ttl(0), created(ServerInstance->Time()) { }
+ ResourceRecord(const Question& question) : Question(question), ttl(0), created(ServerInstance->Time()) { }
+ };
+
+ struct Query
+ {
+ Question question;
+ std::vector<ResourceRecord> answers;
+ Error error;
+ bool cached;
+
+ Query() : error(ERROR_NONE), cached(false) { }
+ Query(const Question& q) : question(q), error(ERROR_NONE), cached(false) { }
+
+ const ResourceRecord* FindAnswerOfType(QueryType qtype) const
+ {
+ for (std::vector<DNS::ResourceRecord>::const_iterator i = answers.begin(); i != answers.end(); ++i)
+ {
+ const DNS::ResourceRecord& rr = *i;
+ if (rr.type == qtype)
+ return &rr;
+ }
+
+ return NULL;
+ }
+ };
+
+ class ReplySocket;
+ class Request;
+
+ /** DNS manager
+ */
+ class Manager : public DataProvider
+ {
+ public:
+ Manager(Module* mod) : DataProvider(mod, "DNS") { }
+
+ virtual void Process(Request* req) = 0;
+ virtual void RemoveRequest(Request* req) = 0;
+ virtual std::string GetErrorStr(Error) = 0;
+ };
+
+ /** A DNS query.
+ */
+ class Request : public Timer
+ {
+ protected:
+ Manager* const manager;
+ public:
+ Question question;
+ /* Use result cache if available */
+ bool use_cache;
+ /* Request id */
+ RequestId id;
+ /* Creator of this request */
+ Module* const creator;
+
+ Request(Manager* mgr, Module* mod, const std::string& addr, QueryType qt, bool usecache = true)
+ : Timer(ServerInstance->Config->ConfValue("dns")->getDuration("timeout", 5, 1))
+ , manager(mgr)
+ , question(addr, qt)
+ , use_cache(usecache)
+ , id(0)
+ , creator(mod)
+ {
+ }
+
+ virtual ~Request()
+ {
+ manager->RemoveRequest(this);
+ }
+
+ /** Called when this request succeeds
+ * @param r The query sent back from the nameserver
+ */
+ virtual void OnLookupComplete(const Query* req) = 0;
+
+ /** Called when this request fails or times out.
+ * @param r The query sent back from the nameserver, check the error code.
+ */
+ virtual void OnError(const Query* req) { }
+
+ /** Used to time out the query, calls OnError and asks the TimerManager
+ * to delete this request
+ */
+ bool Tick(time_t now) CXX11_OVERRIDE
+ {
+ Query rr(this->question);
+ rr.error = ERROR_TIMEDOUT;
+ this->OnError(&rr);
+ delete this;
+ return false;
+ }
+ };
+
+} // namespace DNS
diff --git a/include/modules/exemption.h b/include/modules/exemption.h
new file mode 100644
index 000000000..b590a5797
--- /dev/null
+++ b/include/modules/exemption.h
@@ -0,0 +1,75 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2016-2017 Peter Powell <petpow@saberuk.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/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+namespace CheckExemption
+{
+ class EventListener;
+ class EventProvider;
+
+ /** Helper function for calling the CheckExemption::EventListener::OnCheckExemption event.
+ * @param prov The CheckExemption::EventProvider which is calling the event.
+ * @param user The user to check exemption for.
+ * @param chan The channel to check exemption on.
+ * @param restriction The restriction to check for.
+ * @return Either MOD_RES_ALLOW if the exemption was confirmed, MOD_RES_DENY if the exemption was
+ * denied or MOD_RES_PASSTHRU if no module handled the event.
+ */
+ inline ModResult Call(const CheckExemption::EventProvider& prov, User* user, Channel* chan, const std::string& restriction);
+}
+
+class CheckExemption::EventListener
+ : public Events::ModuleEventListener
+{
+ protected:
+ EventListener(Module* mod)
+ : ModuleEventListener(mod, "event/exemption")
+ {
+ }
+
+ public:
+ /** Called when checking if a user is exempt from something.
+ * @param user The user to check exemption for.
+ * @param chan The channel to check exemption on.
+ * @param restriction The restriction to check for.
+ * @return Either MOD_RES_ALLOW to confirm an exemption, MOD_RES_DENY to deny an exemption,
+ * or MOD_RES_PASSTHRU to let another module handle the event.
+ */
+ virtual ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) = 0;
+};
+
+class CheckExemption::EventProvider
+ : public Events::ModuleEventProvider
+{
+ public:
+ EventProvider(Module* mod)
+ : ModuleEventProvider(mod, "event/exemption")
+ {
+ }
+};
+
+inline ModResult CheckExemption::Call(const CheckExemption::EventProvider& prov, User* user, Channel* chan, const std::string& restriction)
+{
+ ModResult result;
+ FIRST_MOD_RESULT_CUSTOM(prov, CheckExemption::EventListener, OnCheckExemption, result, (user, chan, restriction));
+ return result;
+}
diff --git a/include/modules/hash.h b/include/modules/hash.h
new file mode 100644
index 000000000..7d46ee74a
--- /dev/null
+++ b/include/modules/hash.h
@@ -0,0 +1,72 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include "modules.h"
+
+class HashProvider : public DataProvider
+{
+ public:
+ const unsigned int out_size;
+ const unsigned int block_size;
+ HashProvider(Module* mod, const std::string& Name, unsigned int osiz = 0, unsigned int bsiz = 0)
+ : DataProvider(mod, "hash/" + Name), out_size(osiz), block_size(bsiz)
+ {
+ }
+
+ virtual std::string GenerateRaw(const std::string& data) = 0;
+
+ virtual std::string ToPrintable(const std::string& raw)
+ {
+ return BinToHex(raw);
+ }
+
+ virtual bool Compare(const std::string& input, const std::string& hash)
+ {
+ return InspIRCd::TimingSafeCompare(Generate(input), hash);
+ }
+
+ std::string Generate(const std::string& data)
+ {
+ return ToPrintable(GenerateRaw(data));
+ }
+
+ /** HMAC algorithm, RFC 2104 */
+ std::string hmac(const std::string& key, const std::string& msg)
+ {
+ std::string hmac1, hmac2;
+ std::string kbuf = key.length() > block_size ? GenerateRaw(key) : key;
+ kbuf.resize(block_size);
+
+ for (size_t n = 0; n < block_size; n++)
+ {
+ hmac1.push_back(static_cast<char>(kbuf[n] ^ 0x5C));
+ hmac2.push_back(static_cast<char>(kbuf[n] ^ 0x36));
+ }
+ hmac2.append(msg);
+ hmac1.append(GenerateRaw(hmac2));
+ return GenerateRaw(hmac1);
+ }
+
+ bool IsKDF() const
+ {
+ return (!block_size);
+ }
+};
diff --git a/include/modules/httpd.h b/include/modules/httpd.h
new file mode 100644
index 000000000..b4b88bed5
--- /dev/null
+++ b/include/modules/httpd.h
@@ -0,0 +1,262 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
+ * Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net>
+ * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include "base.h"
+#include "event.h"
+
+#include <string>
+#include <sstream>
+#include <map>
+
+/** A modifyable list of HTTP header fields
+ */
+class HTTPHeaders
+{
+ protected:
+ std::map<std::string,std::string> headers;
+ public:
+
+ /** Set the value of a header
+ * Sets the value of the named header. If the header is already present, it will be replaced
+ */
+ void SetHeader(const std::string &name, const std::string &data)
+ {
+ headers[name] = data;
+ }
+
+ /** Set the value of a header, only if it doesn't exist already
+ * Sets the value of the named header. If the header is already present, it will NOT be updated
+ */
+ void CreateHeader(const std::string &name, const std::string &data)
+ {
+ if (!IsSet(name))
+ SetHeader(name, data);
+ }
+
+ /** Remove the named header
+ */
+ void RemoveHeader(const std::string &name)
+ {
+ headers.erase(name);
+ }
+
+ /** Remove all headers
+ */
+ void Clear()
+ {
+ headers.clear();
+ }
+
+ /** Get the value of a header
+ * @return The value of the header, or an empty string
+ */
+ std::string GetHeader(const std::string &name)
+ {
+ std::map<std::string,std::string>::iterator it = headers.find(name);
+ if (it == headers.end())
+ return std::string();
+
+ return it->second;
+ }
+
+ /** Check if the given header is specified
+ * @return true if the header is specified
+ */
+ bool IsSet(const std::string &name)
+ {
+ std::map<std::string,std::string>::iterator it = headers.find(name);
+ return (it != headers.end());
+ }
+
+ /** Get all headers, formatted by the HTTP protocol
+ * @return Returns all headers, formatted according to the HTTP protocol. There is no request terminator at the end
+ */
+ std::string GetFormattedHeaders()
+ {
+ std::string re;
+
+ for (std::map<std::string,std::string>::iterator i = headers.begin(); i != headers.end(); i++)
+ re += i->first + ": " + i->second + "\r\n";
+
+ return re;
+ }
+};
+
+class HttpServerSocket;
+
+/** This class represents a HTTP request.
+ */
+class HTTPRequest
+{
+ protected:
+ std::string type;
+ std::string document;
+ std::string ipaddr;
+ std::string postdata;
+
+ public:
+
+ HTTPHeaders *headers;
+ int errorcode;
+
+ /** A socket pointer, which you must return in your HTTPDocument class
+ * if you reply to this request.
+ */
+ HttpServerSocket* sock;
+
+ /** Initialize HTTPRequest.
+ * This constructor is called by m_httpd.so to initialize the class.
+ * @param request_type The request type, e.g. GET, POST, HEAD
+ * @param uri The URI, e.g. /page
+ * @param hdr The headers sent with the request
+ * @param opaque An opaque pointer used internally by m_httpd, which you must pass back to the module in your reply.
+ * @param ip The IP address making the web request.
+ * @param pdata The post data (content after headers) received with the request, up to Content-Length in size
+ */
+ HTTPRequest(const std::string& request_type, const std::string& uri,
+ HTTPHeaders* hdr, HttpServerSocket* socket, const std::string &ip, const std::string &pdata)
+ : type(request_type), document(uri), ipaddr(ip), postdata(pdata), headers(hdr), sock(socket)
+ {
+ }
+
+ /** Get the post data (request content).
+ * All post data will be returned, including carriage returns and linefeeds.
+ * @return The postdata
+ */
+ std::string& GetPostData()
+ {
+ return postdata;
+ }
+
+ /** Get the request type.
+ * Any request type can be intercepted, even ones which are invalid in the HTTP/1.1 spec.
+ * @return The request type, e.g. GET, POST, HEAD
+ */
+ std::string& GetType()
+ {
+ return type;
+ }
+
+ /** Get URI.
+ * The URI string (URL minus hostname and scheme) will be provided by this function.
+ * @return The URI being requested
+ */
+ std::string& GetURI()
+ {
+ return document;
+ }
+
+ /** Get IP address of requester.
+ * The requesting system's ip address will be returned.
+ * @return The IP address as a string
+ */
+ std::string& GetIP()
+ {
+ return ipaddr;
+ }
+};
+
+/** If you want to reply to HTTP requests, you must return a HTTPDocumentResponse to
+ * the httpd module via the HTTPdAPI.
+ * When you initialize this class you initialize it with all components required to
+ * form a valid HTTP response: the document data and a response code.
+ * You can add additional HTTP headers, if you want.
+ */
+class HTTPDocumentResponse
+{
+ public:
+ /** Module that generated this reply
+ */
+ Module* const module;
+
+ std::stringstream* document;
+ unsigned int responsecode;
+
+ /** Any extra headers to include with the defaults
+ */
+ HTTPHeaders headers;
+
+ HTTPRequest& src;
+
+ /** Initialize a HTTPDocumentResponse ready for sending to the httpd module.
+ * @param mod A pointer to the module who responded to the request
+ * @param req The request you obtained from the HTTPRequest at an earlier time
+ * @param doc A stringstream containing the document body
+ * @param response A valid HTTP/1.0 or HTTP/1.1 response code. The response text will be determined for you
+ * based upon the response code.
+ */
+ HTTPDocumentResponse(Module* mod, HTTPRequest& req, std::stringstream* doc, unsigned int response)
+ : module(mod), document(doc), responsecode(response), src(req)
+ {
+ }
+};
+
+class HTTPdAPIBase : public DataProvider
+{
+ public:
+ HTTPdAPIBase(Module* parent)
+ : DataProvider(parent, "m_httpd_api")
+ {
+ }
+
+ /** Answer an incoming HTTP request with the provided document
+ * @param response The response created by your module that will be sent to the client
+ */
+ virtual void SendResponse(HTTPDocumentResponse& response) = 0;
+};
+
+/** The API provided by the httpd module that allows other modules to respond to incoming
+ * HTTP requests
+ */
+class HTTPdAPI : public dynamic_reference<HTTPdAPIBase>
+{
+ public:
+ HTTPdAPI(Module* parent)
+ : dynamic_reference<HTTPdAPIBase>(parent, "m_httpd_api")
+ {
+ }
+};
+
+class HTTPACLEventListener : public Events::ModuleEventListener
+{
+ public:
+ HTTPACLEventListener(Module* mod)
+ : ModuleEventListener(mod, "event/http-acl")
+ {
+ }
+
+ virtual ModResult OnHTTPACLCheck(HTTPRequest& req) = 0;
+};
+
+class HTTPRequestEventListener : public Events::ModuleEventListener
+{
+ public:
+ HTTPRequestEventListener(Module* mod)
+ : ModuleEventListener(mod, "event/http-request")
+ {
+ }
+
+ virtual ModResult OnHTTPRequest(HTTPRequest& req) = 0;
+};
diff --git a/include/modules/invite.h b/include/modules/invite.h
new file mode 100644
index 000000000..e53d5202f
--- /dev/null
+++ b/include/modules/invite.h
@@ -0,0 +1,128 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2012, 2015 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/>.
+ */
+
+
+#pragma once
+
+namespace Invite
+{
+ class APIBase;
+ class API;
+ class Invite;
+
+ typedef insp::intrusive_list<Invite, LocalUser> List;
+}
+
+class Invite::APIBase : public DataProvider
+{
+ public:
+ APIBase(Module* parent);
+
+ /** Create or extend an Invite.
+ * When a user is invited to join a channel either a new Invite object is created or
+ * or the expiration timestamp is updated if there is already a pending Invite for
+ * the given (user, channel) pair and the new expiration time is further than the current.
+ * @param user Target user
+ * @param chan Target channel
+ * @param timeout Timestamp when the invite should expire, 0 for no expiration
+ */
+ virtual void Create(LocalUser* user, Channel* chan, time_t timeout) = 0;
+
+ /** Retrieves the Invite object for the given (user, channel) pair
+ * @param user Target user
+ * @param chan Target channel
+ * @return Invite object for the given (channel, user) pair if it exists, NULL otherwise
+ */
+ virtual Invite* Find(LocalUser* user, Channel* chan) = 0;
+
+ /** Returns the list of channels a user has been invited to but has not yet joined.
+ * @param user User whose invite list to retrieve
+ * @return List of channels the user is invited to or NULL if the list is empty
+ */
+ virtual const List* GetList(LocalUser* user) = 0;
+
+ /** Check if a user is invited to a channel
+ * @param user User to check
+ * @param chan Channel to check
+ * @return True if the user is invited to the channel, false otherwise
+ */
+ bool IsInvited(LocalUser* user, Channel* chan) { return (Find(user, chan) != NULL); }
+
+ /** Removes an Invite if it exists
+ * @param user User whose invite to remove
+ * @param chan Channel to remove the invite to
+ * @return True if the user was invited to the channel and the invite was removed, false if the user wasn't invited
+ */
+ virtual bool Remove(LocalUser* user, Channel* chan) = 0;
+};
+
+class Invite::API : public dynamic_reference<APIBase>
+{
+ public:
+ API(Module* parent)
+ : dynamic_reference<APIBase>(parent, "core_channel_invite")
+ {
+ }
+};
+
+/**
+ * The Invite class contains all data about a pending invite.
+ * Invite objects are referenced from the user and the channel they belong to.
+ */
+class Invite::Invite : public insp::intrusive_list_node<Invite, LocalUser>, public insp::intrusive_list_node<Invite, Channel>
+{
+ public:
+ /** User the invite is for
+ */
+ LocalUser* const user;
+
+ /** Channel where the user is invited to
+ */
+ Channel* const chan;
+
+ /** Check whether the invite will expire or not
+ * @return True if the invite is timed, false if it doesn't expire
+ */
+ bool IsTimed() const { return (expiretimer != NULL); }
+
+ /** Serialize this object
+ * @param format Serialization format
+ * @param show_chans True to include channel in the output, false to include the nick/uuid
+ * @param out Output will be appended to this string
+ */
+ void Serialize(SerializeFormat format, bool show_chans, std::string& out);
+
+ friend class APIImpl;
+
+ private:
+ /** Timer handling expiration. If NULL this invite doesn't expire.
+ */
+ Timer* expiretimer;
+
+ /** Constructor, only available to the module providing the invite API (core_channel).
+ * To create Invites use InviteAPI::Create().
+ * @param user User being invited
+ * @param chan Channel the user is invited to
+ */
+ Invite(LocalUser* user, Channel* chan);
+
+ /** Destructor, only available to the module providing the invite API (core_channel).
+ * To remove Invites use InviteAPI::Remove().
+ */
+ ~Invite();
+};
diff --git a/include/modules/ircv3.h b/include/modules/ircv3.h
new file mode 100644
index 000000000..338abdeba
--- /dev/null
+++ b/include/modules/ircv3.h
@@ -0,0 +1,101 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+
+#pragma once
+
+#include "modules/cap.h"
+
+namespace IRCv3
+{
+ class WriteNeighborsWithCap;
+ template <typename T>
+ class CapTag;
+}
+
+class IRCv3::WriteNeighborsWithCap : public User::ForEachNeighborHandler
+{
+ const Cap::Capability& cap;
+ ClientProtocol::Event& protoev;
+
+ void Execute(LocalUser* user) CXX11_OVERRIDE
+ {
+ if (cap.get(user))
+ user->Send(protoev);
+ }
+
+ public:
+ WriteNeighborsWithCap(User* user, ClientProtocol::Event& ev, const Cap::Capability& capability)
+ : cap(capability)
+ , protoev(ev)
+ {
+ user->ForEachNeighbor(*this, false);
+ }
+};
+
+/** Base class for simple message tags.
+ * Message tags provided by classes derived from this class will be sent to clients that have negotiated
+ * a client capability, also managed by this class.
+ *
+ * Derived classes specify the name of the capability and the message tag and provide a public GetValue()
+ * method with the following signature: const std::string* GetValue(ClientProtocol::Message& msg).
+ * The returned value determines whether to attach the tag to the message. If it is NULL, the tag won't
+ * be attached. If it is non-NULL the tag will be attached with the value in the string. If the string is
+ * empty the tag is attached without a value.
+ *
+ * Providers inheriting from this class don't accept incoming tags by default.
+ *
+ * For more control, inherit from ClientProtocol::MessageTagProvider directly.
+ *
+ * Template parameter T is the derived class.
+ */
+template <typename T>
+class IRCv3::CapTag : public ClientProtocol::MessageTagProvider
+{
+ Cap::Capability cap;
+ const std::string tagname;
+
+ bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) CXX11_OVERRIDE
+ {
+ return cap.get(user);
+ }
+
+ void OnClientProtocolPopulateTags(ClientProtocol::Message& msg) CXX11_OVERRIDE
+ {
+ T& tag = static_cast<T&>(*this);
+ const std::string* const val = tag.GetValue(msg);
+ if (val)
+ msg.AddTag(tagname, this, *val);
+ }
+
+ public:
+ /** Constructor.
+ * @param mod Module that owns the tag.
+ * @param capname Name of the client capability.
+ * A client capability with this name will be created. It will be available to all clients and it won't
+ * have a value.
+ * See Cap::Capability for more info on client capabilities.
+ * @param Tagname Name of the message tag, to use in the protocol.
+ */
+ CapTag(Module* mod, const std::string& capname, const std::string& Tagname)
+ : ClientProtocol::MessageTagProvider(mod)
+ , cap(mod, capname)
+ , tagname(Tagname)
+ {
+ }
+};
diff --git a/include/modules/ircv3_batch.h b/include/modules/ircv3_batch.h
new file mode 100644
index 000000000..841554bdb
--- /dev/null
+++ b/include/modules/ircv3_batch.h
@@ -0,0 +1,185 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+// For CapReference
+#include "modules/cap.h"
+
+namespace IRCv3
+{
+ namespace Batch
+ {
+ typedef uint64_t RefTag;
+ class Manager;
+ class ManagerImpl;
+ class Batch;
+ struct BatchInfo;
+ class API;
+ class CapReference;
+
+ static const unsigned int MAX_BATCHES = (sizeof(intptr_t) * 8) - 1;
+ }
+}
+
+/** Batch Manager.
+ * Implements batch starting and stopping. When it becomes unavailable (due to e.g. module unload)
+ * all running batches are stopped.
+ */
+class IRCv3::Batch::Manager : public DataProvider, public ClientProtocol::MessageTagProvider
+{
+ public:
+ /** Constructor.
+ * @param mod Module that owns the Manager.
+ */
+ Manager(Module* mod)
+ : DataProvider(mod, "batchapi")
+ , ClientProtocol::MessageTagProvider(mod)
+ {
+ }
+
+ /** Start a batch.
+ * Check Batch::IsRunning() to learn if the batch has been started.
+ * @param batch Batch to start.
+ */
+ virtual void Start(Batch& batch) = 0;
+
+ /** End a batch.
+ * @param batch Batch to end.
+ */
+ virtual void End(Batch& batch) = 0;
+};
+
+/** Represents a batch.
+ * Batches are used to group together physically separate client protocol messages that logically belong
+ * together for one reason or another. The type of a batch, if provided, indicates what kind of grouping
+ * it does.
+ *
+ * Batch objects have two states: running and stopped. If a batch is running, messages can be added to it.
+ * If a message has been added to a batch and that message is sent to a client that negotiated the batch
+ * capability then the client will receive a message tag attached to the message indicating the batch that
+ * the message is a part of. If a message M is part of a batch B and M is sent to a client that hasn't yet
+ * received any message from batch B it will get a batch start message for B before M. When a batch B is
+ * stopped, every client that received at least one message which was in batch B will receive an end of
+ * batch message for B.
+ * A message may only be part of a single batch at any given time.
+ */
+class IRCv3::Batch::Batch
+{
+ Manager* manager;
+ const std::string type;
+ RefTag reftag;
+ std::string reftagstr;
+ unsigned int bit;
+ BatchInfo* batchinfo;
+ ClientProtocol::Message* batchstartmsg;
+
+ void Setup(unsigned int b)
+ {
+ bit = b;
+ reftag = (1 << bit);
+ reftagstr = ConvToStr(reftag);
+ }
+
+ unsigned int GetId() const { return bit; }
+ intptr_t GetBit() const { return reftag; }
+
+ public:
+ /** Constructor.
+ * The batch is initially stopped. To start it, pass it to Manager::Start().
+ * @param Type Batch type string, used to indicate what kind of grouping the batch does. May be empty.
+ */
+ Batch(const std::string& Type)
+ : manager(NULL)
+ , type(Type)
+ , batchinfo(NULL)
+ , batchstartmsg(NULL)
+ {
+ }
+
+ /** Destructor.
+ * If the batch is running, it is ended.
+ */
+ ~Batch()
+ {
+ if (manager)
+ manager->End(*this);
+ }
+
+ /** Add a message to the batch.
+ * If the batch isn't running then this method does nothing.
+ * @param msg Message to add to the batch. If it is already part of any batch, this method is a no-op.
+ */
+ void AddToBatch(ClientProtocol::Message& msg)
+ {
+ if (manager)
+ msg.AddTag("batch", manager, reftagstr, this);
+ }
+
+ /** Get batch reference tag which is an opaque id for the batch and is used in the client protocol.
+ * Only running batches have a reference tag assigned.
+ * @return Reference tag as a string, only valid if the batch is running.
+ */
+ const std::string& GetRefTagStr() const { return reftagstr; }
+
+ /** Get batch type.
+ * @return Batch type string.
+ */
+ const std::string& GetType() const { return type; }
+
+ /** Check whether the batch is running.
+ * Batches can be started with Manager::Start() and stopped with Manager::End().
+ * @return True if the batch is running, false otherwise.
+ */
+ bool IsRunning() const { return (manager != NULL); }
+
+ /** Get the batch start client protocol message.
+ * The returned message object can be manipulated to add extra parameters or labels to the message. The first
+ * parameter of the message is the batch reference tag generated by the module providing batch support.
+ * If the batch type string was specified, it will be the second parameter of the message.
+ * May only be called if IsRunning() == true.
+ * @return Mutable batch start client protocol message.
+ */
+ ClientProtocol::Message& GetBatchStartMessage() { return *batchstartmsg; }
+
+ friend class ManagerImpl;
+};
+
+/** Batch API. Use this to access the Manager.
+ */
+class IRCv3::Batch::API : public dynamic_reference_nocheck<Manager>
+{
+ public:
+ API(Module* mod)
+ : dynamic_reference_nocheck<Manager>(mod, "batchapi")
+ {
+ }
+};
+
+/** Reference to the batch cap.
+ * Can be used to check whether a user has the batch client cap enabled.
+ */
+class IRCv3::Batch::CapReference : public Cap::Reference
+{
+ public:
+ CapReference(Module* mod)
+ : Cap::Reference(mod, "batch")
+ {
+ }
+};
diff --git a/include/modules/ircv3_servertime.h b/include/modules/ircv3_servertime.h
new file mode 100644
index 000000000..b917531a0
--- /dev/null
+++ b/include/modules/ircv3_servertime.h
@@ -0,0 +1,88 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+namespace IRCv3
+{
+ namespace ServerTime
+ {
+ class Manager;
+ class API;
+
+ /** Format a unix timestamp into the format used by server-time.
+ * @param t Time to format.
+ * @return Time in server-time format, as a string.
+ */
+ inline std::string FormatTime(time_t t)
+ {
+ return InspIRCd::TimeString(t, "%Y-%m-%dT%H:%M:%S.000Z", true);
+ }
+ }
+}
+
+/** Implements manipulating the server time on messages.
+ * A timestamp can be attached to outgoing client protocol messages to indicate the time when the message
+ * was generated by us. If a message has server time attached then recipient clients who have negotiated
+ * the appropriate protocol extension will receive it.
+ */
+class IRCv3::ServerTime::Manager : public DataProvider
+{
+ protected:
+ ClientProtocol::MessageTagProvider* tagprov;
+
+ public:
+ /** Constructor.
+ * @param mod Module that owns the Manager.
+ */
+ Manager(Module* mod)
+ : DataProvider(mod, "servertimeapi")
+ {
+ }
+
+ /** Set the server time on a message.
+ * @param msg Message to set the time on. No-op if the message already has server time set.
+ * @param t Unix timestamp to set.
+ */
+ void Set(ClientProtocol::Message& msg, time_t t)
+ {
+ Set(msg, FormatTime(t));
+ }
+
+ /** Set the server time on a message.
+ * @param msg Message to set the time on. No-op if the message already has server time set.
+ * @param timestr Timestamp to set. Must be in server time format.
+ * The FormatTime() function can be used to convert unix timestamps into the required format.
+ */
+ void Set(ClientProtocol::Message& msg, const std::string& timestr)
+ {
+ msg.AddTag("time", tagprov, timestr);
+ }
+};
+
+/** Server time API. Use this to access the Manager.
+ */
+class IRCv3::ServerTime::API : public dynamic_reference_nocheck<Manager>
+{
+ public:
+ API(Module* mod)
+ : dynamic_reference_nocheck<Manager>(mod, "servertimeapi")
+ {
+ }
+};
diff --git a/include/modules/ldap.h b/include/modules/ldap.h
new file mode 100644
index 000000000..aeb3aa335
--- /dev/null
+++ b/include/modules/ldap.h
@@ -0,0 +1,192 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2015 Adam <Adam@anope.org>
+ * Copyright (C) 2003-2015 Anope Team <team@anope.org>
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+typedef int LDAPQuery;
+
+class LDAPException : public ModuleException
+{
+ public:
+ LDAPException(const std::string& reason) : ModuleException(reason) { }
+
+ virtual ~LDAPException() throw() { }
+};
+
+struct LDAPModification
+{
+ enum LDAPOperation
+ {
+ LDAP_ADD,
+ LDAP_DEL,
+ LDAP_REPLACE
+ };
+
+ LDAPOperation op;
+ std::string name;
+ std::vector<std::string> values;
+};
+
+typedef std::vector<LDAPModification> LDAPMods;
+
+struct LDAPAttributes : public std::map<std::string, std::vector<std::string> >
+{
+ size_t size(const std::string& attr) const
+ {
+ const std::vector<std::string>& array = this->getArray(attr);
+ return array.size();
+ }
+
+ const std::vector<std::string> keys() const
+ {
+ std::vector<std::string> k;
+ for (const_iterator it = this->begin(), it_end = this->end(); it != it_end; ++it)
+ k.push_back(it->first);
+ return k;
+ }
+
+ const std::string& get(const std::string& attr) const
+ {
+ const std::vector<std::string>& array = this->getArray(attr);
+ if (array.empty())
+ throw LDAPException("Empty attribute " + attr + " in LDAPResult::get");
+ return array[0];
+ }
+
+ const std::vector<std::string>& getArray(const std::string& attr) const
+ {
+ const_iterator it = this->find(attr);
+ if (it == this->end())
+ throw LDAPException("Unknown attribute " + attr + " in LDAPResult::getArray");
+ return it->second;
+ }
+};
+
+enum QueryType
+{
+ QUERY_UNKNOWN,
+ QUERY_BIND,
+ QUERY_SEARCH,
+ QUERY_ADD,
+ QUERY_DELETE,
+ QUERY_MODIFY,
+ QUERY_COMPARE
+};
+
+struct LDAPResult
+{
+ std::vector<LDAPAttributes> messages;
+ std::string error;
+
+ QueryType type;
+ LDAPQuery id;
+
+ LDAPResult()
+ : type(QUERY_UNKNOWN), id(-1)
+ {
+ }
+
+ size_t size() const
+ {
+ return this->messages.size();
+ }
+
+ bool empty() const
+ {
+ return this->messages.empty();
+ }
+
+ const LDAPAttributes& get(size_t sz) const
+ {
+ if (sz >= this->messages.size())
+ throw LDAPException("Index out of range");
+ return this->messages[sz];
+ }
+
+ const std::string& getError() const
+ {
+ return this->error;
+ }
+};
+
+class LDAPInterface
+{
+ public:
+ ModuleRef creator;
+
+ LDAPInterface(Module* m) : creator(m) { }
+ virtual ~LDAPInterface() { }
+
+ virtual void OnResult(const LDAPResult& r) = 0;
+ virtual void OnError(const LDAPResult& err) = 0;
+};
+
+class LDAPProvider : public DataProvider
+{
+ public:
+ LDAPProvider(Module* Creator, const std::string& Name)
+ : DataProvider(Creator, Name) { }
+
+ /** Attempt to bind to the LDAP server as a manager
+ * @param i The LDAPInterface the result is sent to
+ */
+ virtual void BindAsManager(LDAPInterface* i) = 0;
+
+ /** Bind to LDAP
+ * @param i The LDAPInterface the result is sent to
+ * @param who The binddn
+ * @param pass The password
+ */
+ virtual void Bind(LDAPInterface* i, const std::string& who, const std::string& pass) = 0;
+
+ /** Search ldap for the specified filter
+ * @param i The LDAPInterface the result is sent to
+ * @param base The base DN to search
+ * @param filter The filter to apply
+ */
+ virtual void Search(LDAPInterface* i, const std::string& base, const std::string& filter) = 0;
+
+ /** Add an entry to LDAP
+ * @param i The LDAPInterface the result is sent to
+ * @param dn The dn of the entry to add
+ * @param attributes The attributes
+ */
+ virtual void Add(LDAPInterface* i, const std::string& dn, LDAPMods& attributes) = 0;
+
+ /** Delete an entry from LDAP
+ * @param i The LDAPInterface the result is sent to
+ * @param dn The dn of the entry to delete
+ */
+ virtual void Del(LDAPInterface* i, const std::string& dn) = 0;
+
+ /** Modify an existing entry in LDAP
+ * @param i The LDAPInterface the result is sent to
+ * @param base The base DN to modify
+ * @param attributes The attributes to modify
+ */
+ virtual void Modify(LDAPInterface* i, const std::string& base, LDAPMods& attributes) = 0;
+
+ /** Compare an attribute in LDAP with our value
+ * @param i The LDAPInterface the result is sent to
+ * @param dn DN to use for comparing
+ * @param attr Attr of DN to compare with
+ * @param val value to compare attr of dn
+ */
+ virtual void Compare(LDAPInterface* i, const std::string& dn, const std::string& attr, const std::string& val) = 0;
+};
diff --git a/include/modules/regex.h b/include/modules/regex.h
new file mode 100644
index 000000000..5ef00cdd0
--- /dev/null
+++ b/include/modules/regex.h
@@ -0,0 +1,62 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include "inspircd.h"
+
+class Regex : public classbase
+{
+protected:
+ /** The uncompiled regex string. */
+ std::string regex_string;
+
+ // Constructor may as well be protected, as this class is abstract.
+ Regex(const std::string& rx) : regex_string(rx) { }
+
+public:
+
+ virtual ~Regex() { }
+
+ virtual bool Matches(const std::string& text) = 0;
+
+ const std::string& GetRegexString() const
+ {
+ return regex_string;
+ }
+};
+
+class RegexFactory : public DataProvider
+{
+ public:
+ RegexFactory(Module* Creator, const std::string& Name) : DataProvider(Creator, Name) { }
+
+ virtual Regex* Create(const std::string& expr) = 0;
+};
+
+class RegexException : public ModuleException
+{
+ public:
+ RegexException(const std::string& regex, const std::string& error)
+ : ModuleException("Error in regex '" + regex + "': " + error) { }
+
+ RegexException(const std::string& regex, const std::string& error, int offset)
+ : ModuleException("Error in regex '" + regex + "' at offset " + ConvToStr(offset) + ": " + error) { }
+};
diff --git a/include/modules/reload.h b/include/modules/reload.h
new file mode 100644
index 000000000..dcdbc95e9
--- /dev/null
+++ b/include/modules/reload.h
@@ -0,0 +1,80 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+namespace ReloadModule
+{
+ class EventListener;
+ class DataKeeper;
+
+ /** Container for data saved by modules before another module is reloaded.
+ */
+ class CustomData
+ {
+ struct Data
+ {
+ EventListener* handler;
+ void* data;
+ Data(EventListener* Handler, void* moddata) : handler(Handler), data(moddata) { }
+ };
+ typedef std::vector<Data> List;
+ List list;
+
+ public:
+ /** Add data to the saved state of a module.
+ * The provided handler's OnReloadModuleRestore() method will be called when the reload is done with the pointer
+ * provided.
+ * @param handler Handler for restoring the data
+ * @param data Pointer to the data, will be passed back to the provided handler's OnReloadModuleRestore() after the
+ * reload finishes
+ */
+ void add(EventListener* handler, void* data)
+ {
+ list.push_back(Data(handler, data));
+ }
+
+ friend class DataKeeper;
+ };
+
+ class EventListener : public Events::ModuleEventListener
+ {
+ public:
+ EventListener(Module* mod)
+ : ModuleEventListener(mod, "event/reloadmodule")
+ {
+ }
+
+ /** Called whenever a module is about to be reloaded. Use this event to save data related to the module that you want
+ * to be restored after the reload.
+ * @param mod Module to be reloaded
+ * @param cd CustomData instance that can store your data once.
+ */
+ virtual void OnReloadModuleSave(Module* mod, CustomData& cd) = 0;
+
+ /** Restore data after a reload. Only called if data was added in OnReloadModuleSave().
+ * @param mod Reloaded module, if NULL the reload failed and the module no longer exists
+ * @param data Pointer that was passed to CustomData::add() in OnReloadModuleSave() at the time when the module's state
+ * was saved
+ */
+ virtual void OnReloadModuleRestore(Module* mod, void* data) = 0;
+ };
+}
diff --git a/include/modules/sasl.h b/include/modules/sasl.h
new file mode 100644
index 000000000..8a54cfdb3
--- /dev/null
+++ b/include/modules/sasl.h
@@ -0,0 +1,33 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+class SASLEventListener : public Events::ModuleEventListener
+{
+ public:
+ SASLEventListener(Module* mod)
+ : ModuleEventListener(mod, "event/sasl")
+ {
+ }
+
+ virtual void OnSASLAuth(const CommandBase::Params& params) = 0;
+};
diff --git a/include/modules/server.h b/include/modules/server.h
new file mode 100644
index 000000000..99bd2ee1d
--- /dev/null
+++ b/include/modules/server.h
@@ -0,0 +1,61 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+class ServerEventListener : public Events::ModuleEventListener
+{
+ public:
+ ServerEventListener(Module* mod)
+ : ModuleEventListener(mod, "event/server")
+ {
+ }
+
+ /** Fired when a server finishes burst
+ * @param server Server that recently linked and finished burst
+ */
+ virtual void OnServerLink(const Server* server) { }
+
+ /** Fired when a server splits
+ * @param server Server that split
+ */
+ virtual void OnServerSplit(const Server* server) { }
+
+ /** Allows modules to synchronize user metadata during a netburst. This will
+ * be called for every user visible on your side of the burst.
+ * @param user The user being synchronized.
+ * @param server The target of the burst.
+ */
+ virtual void OnSyncUser(User* user, ProtocolServer& server) { }
+
+ /** Allows modules to synchronize channel metadata during a netburst. This will
+ * be called for every channel visible on your side of the burst.
+ * @param chan The channel being synchronized.
+ * @param server The target of the burst.
+ */
+ virtual void OnSyncChannel(Channel* chan, ProtocolServer& server) { }
+
+ /** Allows modules to synchronize network metadata during a netburst.
+ * @param server The target of the burst.
+ */
+ virtual void OnSyncNetwork(ProtocolServer& server) { }
+
+};
diff --git a/include/modules/shun.h b/include/modules/shun.h
new file mode 100644
index 000000000..9ce547e2d
--- /dev/null
+++ b/include/modules/shun.h
@@ -0,0 +1,70 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2017 Dylan Frank <b00mx0r@aureus.pw>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include "xline.h"
+
+/** Shun class
+ */
+class Shun : public XLine
+{
+ public:
+ /** Create a Shun.
+ * @param s_time The set time
+ * @param d The duration of the xline
+ * @param src The sender of the xline
+ * @param re The reason of the xline
+ * @param shunmask Mask to match
+ */
+ Shun(time_t s_time, long d, const std::string& src, const std::string& re, const std::string& shunmask)
+ : XLine(s_time, d, src, re, "SHUN")
+ , matchtext(shunmask)
+ {
+ }
+
+ bool Matches(User* u) CXX11_OVERRIDE
+ {
+ LocalUser* lu = IS_LOCAL(u);
+ if (lu && lu->exempt)
+ return false;
+
+ if (InspIRCd::Match(u->GetFullHost(), matchtext) || InspIRCd::Match(u->GetFullRealHost(), matchtext) || InspIRCd::Match(u->nick+"!"+u->ident+"@"+u->GetIPString(), matchtext))
+ return true;
+
+ if (InspIRCd::MatchCIDR(u->GetIPString(), matchtext, ascii_case_insensitive_map))
+ return true;
+
+ return false;
+ }
+
+ bool Matches(const std::string& str) CXX11_OVERRIDE
+ {
+ return (matchtext == str);
+ }
+
+ const std::string& Displayable() CXX11_OVERRIDE
+ {
+ return matchtext;
+ }
+
+ private:
+ /** Matching mask **/
+ std::string matchtext;
+};
diff --git a/include/modules/sql.h b/include/modules/sql.h
new file mode 100644
index 000000000..15e8260b6
--- /dev/null
+++ b/include/modules/sql.h
@@ -0,0 +1,267 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2017 Peter Powell <petpow@saberuk.com>
+ * Copyright (C) 2010 Daniel De Graaf <danieldg@inspircd.org>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+
+namespace SQL
+{
+ class Error;
+ class Field;
+ class Provider;
+ class Query;
+ class Result;
+
+ /** A list of parameter replacement values. */
+ typedef std::vector<std::string> ParamList;
+
+ /** A map of parameter replacement values. */
+ typedef std::map<std::string, std::string> ParamMap;
+
+ /** A list of SQL fields from a specific row. */
+ typedef std::vector<Field> Row;
+
+ /** An enumeration of possible error codes. */
+ enum ErrorCode
+ {
+ /** No error has occurred. */
+ SUCCESS,
+
+ /** The database identifier is invalid. */
+ BAD_DBID,
+
+ /** The database connection has failed. */
+ BAD_CONN,
+
+ /** Executing the query failed. */
+ QSEND_FAIL,
+
+ /** Reading the response failed. */
+ QREPLY_FAIL
+ };
+
+ /** Populates a parameter map with information about a user.
+ * @param user The user to collect information from.
+ * @param userinfo The map to populate.
+ */
+ void PopulateUserInfo(User* user, ParamMap& userinfo);
+}
+
+/** Represents a single SQL field. */
+class SQL::Field
+{
+ private:
+ /** Whether this SQL field is NULL. */
+ bool null;
+
+ /** The underlying SQL value. */
+ std::string value;
+
+ public:
+ /** Creates a new NULL SQL field. */
+ Field()
+ : null(true)
+ {
+ }
+
+ /** Creates a new non-NULL SQL field.
+ * @param v The value of the field.
+ */
+ Field(const std::string& v)
+ : null(false)
+ , value(v)
+ {
+ }
+
+ /** Determines whether this SQL entry is NULL. */
+ inline bool IsNull() const { return null; }
+
+ /** Retrieves the underlying value. */
+ inline operator const std::string&() const { return value; }
+};
+
+/** Represents the result of an SQL query. */
+class SQL::Result : public classbase
+{
+ public:
+ /**
+ * Return the number of rows in the result.
+ *
+ * Note that if you have perfomed an INSERT or UPDATE query or other
+ * query which will not return rows, this will return the number of
+ * affected rows. In this case you SHOULD NEVER access any of the result
+ * set rows, as there aren't any!
+ * @returns Number of rows in the result set.
+ */
+ virtual int Rows() = 0;
+
+ /** Retrieves the next available row from the database.
+ * @param result A list to store the fields from this row in.
+ * @return True if a row could be retrieved; otherwise, false.
+ */
+ virtual bool GetRow(Row& result) = 0;
+
+ /** Retrieves a list of SQL columns in the result.
+ * @param result A reference to the vector to store column names in.
+ */
+ virtual void GetCols(std::vector<std::string>& result) = 0;
+
+ /**
+ * Check if there's a column with the specified name in the result
+ *
+ * @param the column name
+ * @param on success, this is the column index
+ * @returns true, or false if the column is not found
+ */
+ virtual bool HasColumn(const std::string& column, size_t& index) = 0;
+};
+
+/** SQL::Error holds the error state of a request.
+ * The error string varies from database software to database software
+ * and should be used to display informational error messages to users.
+ */
+class SQL::Error
+{
+ private:
+ /** The custom error message if one has been specified. */
+ const std::string message;
+
+ public:
+ /** The code which represents this error. */
+ const ErrorCode code;
+
+ /** Initialize an SQL::Error from an error code.
+ * @param c A code which represents this error.
+ */
+ Error(ErrorCode c)
+ : code(c)
+ {
+ }
+
+ /** Initialize an SQL::Error from an error code and a custom error message.
+ * @param c A code which represents this error.
+ * @param m A custom error message.
+ */
+ Error(ErrorCode c, const std::string m)
+ : message(m)
+ , code(c)
+ {
+ }
+
+ /** Retrieves the error message. */
+ const char* ToString() const
+ {
+ if (!message.empty())
+ return message.c_str();
+
+ switch (code)
+ {
+ case BAD_DBID:
+ return "Invalid database identifier";
+ case BAD_CONN:
+ return "Invalid connection";
+ case QSEND_FAIL:
+ return "Sending query failed";
+ case QREPLY_FAIL:
+ return "Getting query result failed";
+ default:
+ return "Unknown error";
+ }
+ }
+};
+
+/**
+ * Object representing an SQL query. This should be allocated on the heap and
+ * passed to an SQL::Provider, which will free it when the query is complete or
+ * when the querying module is unloaded.
+ *
+ * You should store whatever information is needed to have the callbacks work in
+ * this object (UID of user, channel name, etc).
+ */
+class SQL::Query : public classbase
+{
+ protected:
+ /** Creates a new SQL query. */
+ Query(Module* Creator)
+ : creator(Creator)
+ {
+ }
+
+ public:
+ const ModuleRef creator;
+
+ /* Destroys this Query instance. */
+ virtual ~Query()
+ {
+ }
+
+ /** Called when an SQL error happens.
+ * @param error The error that occurred.
+ */
+ virtual void OnError(Error& error) = 0;
+
+ /** Called when a SQL result is received.
+ * @param result The result of the SQL query.
+ */
+ virtual void OnResult(Result& result) = 0;
+};
+
+/**
+ * Provider object for SQL servers
+ */
+class SQL::Provider : public DataProvider
+{
+ public:
+ Provider(Module* Creator, const std::string& Name)
+ : DataProvider(Creator, Name)
+ {
+ }
+
+ /** Submit an asynchronous SQL query.
+ * @param callback The result reporting point
+ * @param query The hardcoded query string. If you have parameters to substitute, see below.
+ */
+ virtual void Submit(Query* callback, const std::string& query) = 0;
+
+ /** Submit an asynchronous SQL query.
+ * @param callback The result reporting point
+ * @param format The simple parameterized query string ('?' parameters)
+ * @param p Parameters to fill in for the '?' entries
+ */
+ virtual void Submit(Query* callback, const std::string& format, const SQL::ParamList& p) = 0;
+
+ /** Submit an asynchronous SQL query.
+ * @param callback The result reporting point
+ * @param format The parameterized query string ('$name' parameters)
+ * @param p Parameters to fill in for the '$name' entries
+ */
+ virtual void Submit(Query* callback, const std::string& format, const ParamMap& p) = 0;
+};
+
+inline void SQL::PopulateUserInfo(User* user, ParamMap& userinfo)
+{
+ userinfo["nick"] = user->nick;
+ userinfo["host"] = user->GetRealHost();
+ userinfo["ip"] = user->GetIPString();
+ userinfo["real"] = user->GetRealName();
+ userinfo["ident"] = user->ident;
+ userinfo["server"] = user->server->GetName();
+ userinfo["uuid"] = user->uuid;
+}
diff --git a/include/modules/ssl.h b/include/modules/ssl.h
new file mode 100644
index 000000000..930cb6dc6
--- /dev/null
+++ b/include/modules/ssl.h
@@ -0,0 +1,305 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc>
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include <string>
+#include "iohook.h"
+
+/** ssl_cert is a class which abstracts SSL certificate
+ * and key information.
+ *
+ * Because gnutls and openssl represent key information in
+ * wildly different ways, this class allows it to be accessed
+ * in a unified manner. These classes are attached to ssl-
+ * connected local users using SSLCertExt
+ */
+class ssl_cert : public refcountbase
+{
+ public:
+ std::string dn;
+ std::string issuer;
+ std::string error;
+ std::string fingerprint;
+ bool trusted, invalid, unknownsigner, revoked;
+
+ ssl_cert() : trusted(false), invalid(true), unknownsigner(true), revoked(false) {}
+
+ /** Get certificate distinguished name
+ * @return Certificate DN
+ */
+ const std::string& GetDN()
+ {
+ return dn;
+ }
+
+ /** Get Certificate issuer
+ * @return Certificate issuer
+ */
+ const std::string& GetIssuer()
+ {
+ return issuer;
+ }
+
+ /** Get error string if an error has occured
+ * @return The error associated with this users certificate,
+ * or an empty string if there is no error.
+ */
+ const std::string& GetError()
+ {
+ return error;
+ }
+
+ /** Get key fingerprint.
+ * @return The key fingerprint as a hex string.
+ */
+ const std::string& GetFingerprint()
+ {
+ return fingerprint;
+ }
+
+ /** Get trust status
+ * @return True if this is a trusted certificate
+ * (the certificate chain validates)
+ */
+ bool IsTrusted()
+ {
+ return trusted;
+ }
+
+ /** Get validity status
+ * @return True if the certificate itself is
+ * correctly formed.
+ */
+ bool IsInvalid()
+ {
+ return invalid;
+ }
+
+ /** Get signer status
+ * @return True if the certificate appears to be
+ * self-signed.
+ */
+ bool IsUnknownSigner()
+ {
+ return unknownsigner;
+ }
+
+ /** Get revokation status.
+ * @return True if the certificate is revoked.
+ * Note that this only works properly for GnuTLS
+ * right now.
+ */
+ bool IsRevoked()
+ {
+ return revoked;
+ }
+
+ /** Get certificate usability
+ * @return True if the certificate is not expired nor revoked
+ */
+ bool IsUsable()
+ {
+ return !invalid && !revoked && error.empty();
+ }
+
+ /** Get CA trust status
+ * @return True if the certificate is issued by a CA
+ * and valid.
+ */
+ bool IsCAVerified()
+ {
+ return IsUsable() && trusted && !unknownsigner;
+ }
+
+ std::string GetMetaLine()
+ {
+ std::stringstream value;
+ bool hasError = !error.empty();
+ value << (IsInvalid() ? "v" : "V") << (IsTrusted() ? "T" : "t") << (IsRevoked() ? "R" : "r")
+ << (IsUnknownSigner() ? "s" : "S") << (hasError ? "E" : "e") << " ";
+ if (hasError)
+ value << GetError();
+ else
+ value << GetFingerprint() << " " << GetDN() << " " << GetIssuer();
+ return value.str();
+ }
+};
+
+class SSLIOHook : public IOHook
+{
+ protected:
+ /** Peer SSL certificate, set by the SSL module
+ */
+ reference<ssl_cert> certificate;
+
+ /** Reduce elements in a send queue by appending later elements to the first element until there are no more
+ * elements to append or a desired length is reached
+ * @param sendq SendQ to work on
+ * @param targetsize Target size of the front element
+ */
+ static void FlattenSendQueue(StreamSocket::SendQueue& sendq, size_t targetsize)
+ {
+ if ((sendq.size() <= 1) || (sendq.front().length() >= targetsize))
+ return;
+
+ // Avoid multiple repeated SSL encryption invocations
+ // This adds a single copy of the queue, but avoids
+ // much more overhead in terms of system calls invoked
+ // by an IOHook.
+ std::string tmp;
+ tmp.reserve(std::min(targetsize, sendq.bytes())+1);
+ do
+ {
+ tmp.append(sendq.front());
+ sendq.pop_front();
+ }
+ while (!sendq.empty() && tmp.length() < targetsize);
+ sendq.push_front(tmp);
+ }
+
+ public:
+ static SSLIOHook* IsSSL(StreamSocket* sock)
+ {
+ IOHook* const iohook = sock->GetIOHook();
+ if ((iohook) && ((iohook->prov->type == IOHookProvider::IOH_SSL)))
+ return static_cast<SSLIOHook*>(iohook);
+ return NULL;
+ }
+
+ SSLIOHook(IOHookProvider* hookprov)
+ : IOHook(hookprov)
+ {
+ }
+
+ /**
+ * Get the certificate sent by this peer
+ * @return The SSL certificate sent by the peer, NULL if no cert was sent
+ */
+ ssl_cert* GetCertificate() const
+ {
+ if (certificate && certificate->IsUsable())
+ return certificate;
+ return NULL;
+ }
+
+ /**
+ * Get the fingerprint of the peer's certificate
+ * @return The fingerprint of the SSL client certificate sent by the peer,
+ * empty if no cert was sent
+ */
+ std::string GetFingerprint() const
+ {
+ ssl_cert* cert = GetCertificate();
+ if (cert)
+ return cert->GetFingerprint();
+ return "";
+ }
+
+ /**
+ * Get the ciphersuite negotiated with the peer
+ * @param out String where the ciphersuite string will be appended to
+ */
+ virtual void GetCiphersuite(std::string& out) const = 0;
+
+
+ /** Retrieves the name of the SSL connection which is sent via SNI.
+ * @param out String that the server name will be appended to.
+ * returns True if the server name was retrieved; otherwise, false.
+ */
+ virtual bool GetServerName(std::string& out) const = 0;
+};
+
+/** Helper functions for obtaining SSL client certificates and key fingerprints
+ * from StreamSockets
+ */
+class SSLClientCert
+{
+ public:
+ /**
+ * Get the client certificate from a socket
+ * @param sock The socket to get the certificate from, the socket does not have to use SSL
+ * @return The SSL client certificate information, NULL if the peer is not using SSL
+ */
+ static ssl_cert* GetCertificate(StreamSocket* sock)
+ {
+ SSLIOHook* ssliohook = SSLIOHook::IsSSL(sock);
+ if (!ssliohook)
+ return NULL;
+
+ return ssliohook->GetCertificate();
+ }
+
+ /**
+ * Get the fingerprint of a client certificate from a socket
+ * @param sock The socket to get the certificate fingerprint from, the
+ * socket does not have to use SSL
+ * @return The key fingerprint from the SSL certificate sent by the peer,
+ * empty if no cert was sent or the peer is not using SSL
+ */
+ static std::string GetFingerprint(StreamSocket* sock)
+ {
+ ssl_cert* cert = SSLClientCert::GetCertificate(sock);
+ if (cert)
+ return cert->GetFingerprint();
+ return "";
+ }
+};
+
+class UserCertificateAPIBase : public DataProvider
+{
+ public:
+ UserCertificateAPIBase(Module* parent)
+ : DataProvider(parent, "m_sslinfo_api")
+ {
+ }
+
+ /** Get the SSL certificate of a user
+ * @param user The user whose certificate to get, user may be remote
+ * @return The SSL certificate of the user or NULL if the user is not using SSL
+ */
+ virtual ssl_cert* GetCertificate(User* user) = 0;
+
+ /** Get the key fingerprint from a user's certificate
+ * @param user The user whose key fingerprint to get, user may be remote
+ * @return The key fingerprint from the user's SSL certificate or an empty string
+ * if the user is not using SSL or did not provide a client certificate
+ */
+ std::string GetFingerprint(User* user)
+ {
+ ssl_cert* cert = GetCertificate(user);
+ if (cert)
+ return cert->GetFingerprint();
+ return "";
+ }
+};
+
+/** API implemented by m_sslinfo that allows modules to retrive the SSL certificate
+ * information of local and remote users. It can also be used to find out whether a
+ * user is using SSL or not.
+ */
+class UserCertificateAPI : public dynamic_reference<UserCertificateAPIBase>
+{
+ public:
+ UserCertificateAPI(Module* parent)
+ : dynamic_reference<UserCertificateAPIBase>(parent, "m_sslinfo_api")
+ {
+ }
+};
diff --git a/include/modules/stats.h b/include/modules/stats.h
new file mode 100644
index 000000000..e69070c9f
--- /dev/null
+++ b/include/modules/stats.h
@@ -0,0 +1,191 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * 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/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+namespace Stats
+{
+ class Context;
+ class EventListener;
+ class Row;
+}
+
+class Stats::EventListener : public Events::ModuleEventListener
+{
+ public:
+ EventListener(Module* mod)
+ : ModuleEventListener(mod, "event/stats")
+ {
+ }
+
+ /** Called when the STATS command is executed.
+ * @param stats Context of the /STATS request, contains requesting user, list of answer rows etc.
+ * @return MOD_RES_DENY if the stats request has been fulfilled. Otherwise, MOD_RES_PASSTHRU.
+ */
+ virtual ModResult OnStats(Stats::Context& stats) = 0;
+};
+
+class Stats::Row : public Numeric::Numeric
+{
+ public:
+ Row(unsigned int num)
+ : Numeric(num)
+ {
+ }
+};
+
+class Stats::Context
+{
+ /** Source user of the STATS request
+ */
+ User* const source;
+
+ /** List of reply rows
+ */
+ std::vector<Row> rows;
+
+ /** Symbol indicating the type of this STATS request (usually a letter)
+ */
+ const char symbol;
+
+ public:
+ /** Constructor
+ * @param src Source user of the STATS request, can be a local or remote user
+ * @param sym Symbol (letter) indicating the type of the request
+ */
+ Context(User* src, char sym)
+ : source(src)
+ , symbol(sym)
+ {
+ }
+
+ /** Get the source user of the STATS request
+ * @return Source user of the STATS request
+ */
+ User* GetSource() const { return source; }
+
+ /** Get the list of reply rows
+ * @return List of rows generated as reply for the request
+ */
+ const std::vector<Row>& GetRows() const { return rows; }
+
+ /** Get the symbol (letter) indicating what type of STATS was requested
+ * @return Symbol specified by the requesting user
+ */
+ char GetSymbol() const { return symbol; }
+
+ /** Add a row to the reply list
+ * @param row Reply to add
+ */
+ void AddRow(const Row& row) { rows.push_back(row); }
+
+ template <typename T1>
+ void AddRow(unsigned int numeric, T1 p1)
+ {
+ Row n(numeric);
+ n.push(p1);
+ AddRow(n);
+ }
+
+ template <typename T1, typename T2>
+ void AddRow(unsigned int numeric, T1 p1, T2 p2)
+ {
+ Row n(numeric);
+ n.push(p1);
+ n.push(p2);
+ AddRow(n);
+ }
+
+ template <typename T1, typename T2, typename T3>
+ void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3)
+ {
+ Row n(numeric);
+ n.push(p1);
+ n.push(p2);
+ n.push(p3);
+ AddRow(n);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4>
+ void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4)
+ {
+ Row n(numeric);
+ n.push(p1);
+ n.push(p2);
+ n.push(p3);
+ n.push(p4);
+ AddRow(n);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5)
+ {
+ Row n(numeric);
+ n.push(p1);
+ n.push(p2);
+ n.push(p3);
+ n.push(p4);
+ n.push(p5);
+ AddRow(n);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+ void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6)
+ {
+ Row n(numeric);
+ n.push(p1);
+ n.push(p2);
+ n.push(p3);
+ n.push(p4);
+ n.push(p5);
+ n.push(p6);
+ AddRow(n);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+ void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7)
+ {
+ Row n(numeric);
+ n.push(p1);
+ n.push(p2);
+ n.push(p3);
+ n.push(p4);
+ n.push(p5);
+ n.push(p6);
+ n.push(p7);
+ AddRow(n);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+ void AddRow(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8)
+ {
+ Row n(numeric);
+ n.push(p1);
+ n.push(p2);
+ n.push(p3);
+ n.push(p4);
+ n.push(p5);
+ n.push(p6);
+ n.push(p7);
+ n.push(p8);
+ AddRow(n);
+ }
+};
diff --git a/include/modules/whois.h b/include/modules/whois.h
new file mode 100644
index 000000000..4f09d268b
--- /dev/null
+++ b/include/modules/whois.h
@@ -0,0 +1,146 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+namespace Whois
+{
+ class EventListener;
+ class LineEventListener;
+ class Context;
+}
+
+class Whois::EventListener : public Events::ModuleEventListener
+{
+ public:
+ EventListener(Module* mod)
+ : ModuleEventListener(mod, "event/whois")
+ {
+ }
+
+ /** Called whenever a /WHOIS is performed by a local user.
+ * @param whois Whois context, can be used to send numerics
+ */
+ virtual void OnWhois(Context& whois) = 0;
+};
+
+class Whois::LineEventListener : public Events::ModuleEventListener
+{
+ public:
+ LineEventListener(Module* mod)
+ : ModuleEventListener(mod, "event/whoisline")
+ {
+ }
+
+ /** Called whenever a line of WHOIS output is sent to a user.
+ * You may change the numeric and the text of the output by changing
+ * the values numeric and text, but you cannot change the user the
+ * numeric is sent to.
+ * @param whois Whois context, can be used to send numerics
+ * @param numeric Numeric being sent
+ * @return MOD_RES_DENY to drop the line completely so that the user does not
+ * receive it, or MOD_RES_PASSTHRU to allow the line to be sent.
+ */
+ virtual ModResult OnWhoisLine(Context& whois, Numeric::Numeric& numeric) = 0;
+};
+
+class Whois::Context
+{
+ protected:
+ /** User doing the WHOIS
+ */
+ LocalUser* const source;
+
+ /** User being WHOISed
+ */
+ User* const target;
+
+ public:
+ Context(LocalUser* src, User* targ)
+ : source(src)
+ , target(targ)
+ {
+ }
+
+ /** Returns true if the user is /WHOISing himself
+ * @return True if whois source is the same user as the whois target, false if they are different users
+ */
+ bool IsSelfWhois() const { return (source == target); }
+
+ /** Returns the LocalUser who has done the /WHOIS
+ * @return LocalUser doing the /WHOIS
+ */
+ LocalUser* GetSource() const { return source; }
+
+ /** Returns the target of the /WHOIS
+ * @return User who was /WHOIS'd
+ */
+ User* GetTarget() const { return target; }
+
+ /** Send a line of WHOIS data to the source of the WHOIS
+ */
+ template <typename T1>
+ void SendLine(unsigned int numeric, T1 p1)
+ {
+ Numeric::Numeric n(numeric);
+ n.push(target->nick);
+ n.push(p1);
+ SendLine(n);
+ }
+
+ template <typename T1, typename T2>
+ void SendLine(unsigned int numeric, T1 p1, T2 p2)
+ {
+ Numeric::Numeric n(numeric);
+ n.push(target->nick);
+ n.push(p1);
+ n.push(p2);
+ SendLine(n);
+ }
+
+ template <typename T1, typename T2, typename T3>
+ void SendLine(unsigned int numeric, T1 p1, T2 p2, T3 p3)
+ {
+ Numeric::Numeric n(numeric);
+ n.push(target->nick);
+ n.push(p1);
+ n.push(p2);
+ n.push(p3);
+ SendLine(n);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4>
+ void SendLine(unsigned int numeric, T1 p1, T2 p2, T3 p3, T4 p4)
+ {
+ Numeric::Numeric n(numeric);
+ n.push(target->nick);
+ n.push(p1);
+ n.push(p2);
+ n.push(p3);
+ n.push(p4);
+ SendLine(n);
+ }
+
+ /** Send a line of WHOIS data to the source of the WHOIS
+ * @param numeric Numeric to send
+ */
+ virtual void SendLine(Numeric::Numeric& numeric) = 0;
+};