changeset 133:2eda98f3db1b

Irccd: preparation for modules
author David Demelier <markand@malikania.fr>
date Fri, 13 May 2016 12:06:06 +0200
parents 105287c768ba
children dc7d6ba08122
files lib/irccd/CMakeSources.cmake lib/irccd/cmd-plugin-load.cpp lib/irccd/cmd-plugin-reload.cpp lib/irccd/config.cpp lib/irccd/js-plugin.cpp lib/irccd/js-timer.cpp lib/irccd/module.hpp lib/irccd/plugin-js.cpp lib/irccd/plugin-js.hpp lib/irccd/plugin.cpp lib/irccd/plugin.hpp lib/irccd/server-event.cpp lib/irccd/service-plugin.cpp lib/irccd/service-plugin.hpp lib/irccd/service-server.cpp lib/irccd/util.hpp
diffstat 16 files changed, 313 insertions(+), 378 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/CMakeSources.cmake	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/CMakeSources.cmake	Fri May 13 12:06:06 2016 +0200
@@ -126,7 +126,6 @@
 	${CMAKE_CURRENT_LIST_DIR}/logger.cpp
 	${CMAKE_CURRENT_LIST_DIR}/options.cpp
 	${CMAKE_CURRENT_LIST_DIR}/path.cpp
-	${CMAKE_CURRENT_LIST_DIR}/plugin.cpp
 	${CMAKE_CURRENT_LIST_DIR}/plugin-js.cpp
 	${CMAKE_CURRENT_LIST_DIR}/rule.cpp
 	${CMAKE_CURRENT_LIST_DIR}/server.cpp
--- a/lib/irccd/cmd-plugin-load.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/cmd-plugin-load.cpp	Fri May 13 12:06:06 2016 +0200
@@ -45,7 +45,7 @@
 #if defined(WITH_JS)
 	auto name = request.at("plugin").toString();
 
-	irccd.pluginService().load(name, name, true);
+	irccd.pluginService().load(name);
 
 	return RemoteCommand::exec(irccd, request);
 #else
--- a/lib/irccd/cmd-plugin-reload.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/cmd-plugin-reload.cpp	Fri May 13 12:06:06 2016 +0200
@@ -44,7 +44,7 @@
 json::Value PluginReload::exec(Irccd &irccd, const json::Value &request) const
 {
 #if defined(WITH_JS)
-	irccd.pluginService().require(request.at("plugin").toString())->onReload();
+	irccd.pluginService().require(request.at("plugin").toString())->onReload(irccd);
 
 	return RemoteCommand::exec(irccd, request);
 #else
--- a/lib/irccd/config.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/config.cpp	Fri May 13 12:06:06 2016 +0200
@@ -629,7 +629,7 @@
 			log::info("plugin {}: loading"_format(name));
 
 			if (path.empty()) {
-				plugins.push_back(Plugin::find(name, findPluginConfig(name)));
+				// plugins.push_back(Plugin::find(name, findPluginConfig(name)));
 			} else {
 				log::info("plugin {}: trying {}"_format(name, path));
 				plugins.push_back(std::make_shared<JsPlugin>(name, path, findPluginConfig(name)));
--- a/lib/irccd/js-plugin.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/js-plugin.cpp	Fri May 13 12:06:06 2016 +0200
@@ -127,7 +127,7 @@
 duk::Ret load(duk::ContextPtr ctx)
 {
 	return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) {
-		irccd.pluginService().load(name, name, true);
+		irccd.pluginService().load(name);
 	});
 }
 
--- a/lib/irccd/js-timer.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/js-timer.cpp	Fri May 13 12:06:06 2016 +0200
@@ -21,6 +21,7 @@
 
 #include "js.hpp"
 #include "plugin-js.hpp"
+#include "timer.hpp"
 
 namespace irccd {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/irccd/module.hpp	Fri May 13 12:06:06 2016 +0200
@@ -0,0 +1,42 @@
+#ifndef IRCCD_MODULE_HPP
+#define IRCCD_MODULE_HPP
+
+#include <memory>
+
+namespace irccd {
+
+class Irccd;
+class JsPlugin;
+
+class Module {
+public:
+	/**
+	 * Default constructor.
+	 */
+	Module() = default;
+
+	/**
+	 * Virtual destructor defaulted.
+	 */
+	virtual ~Module() = default
+
+	/**
+	 * Load the module into the JavaScript plugin.
+	 *
+	 * \param irccd the irccd instance
+	 * \param plugin the plugin
+	 */
+	void load(Irccd &irccd, const std::shared_ptr<JsPlugin> &plugin);
+
+	/**
+	 * Unload the module from the JavaScript plugin.
+	 *
+	 * \param irccd the irccd instance
+	 * \param plugin the plugin
+	 */
+	void unload(Irccd &irccd, const std::shared_ptr<Plugin> &plugin);
+};
+
+} // !irccd
+
+#endif // !IRCCD_MODULE_HPP
\ No newline at end of file
--- a/lib/irccd/plugin-js.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/plugin-js.cpp	Fri May 13 12:06:06 2016 +0200
@@ -38,6 +38,7 @@
 #include "js-util.hpp"
 #include "logger.hpp"
 #include "plugin-js.hpp"
+#include "timer.hpp"
 
 namespace irccd {
 
@@ -168,8 +169,8 @@
 	loadJsPlugin(m_context);
 	loadJsServer(m_context);
 	loadJsSystem(m_context);
+	loadJsUnicode(m_context);
 	loadJsTimer(m_context);
-	loadJsUnicode(m_context);
 	loadJsUtil(m_context);
 
 	putVars();
@@ -249,7 +250,8 @@
 	m_timers.erase(timer);
 }
 
-void JsPlugin::onChannelMode(const std::shared_ptr<Server> &server,
+void JsPlugin::onChannelMode(Irccd &,
+			     const std::shared_ptr<Server> &server,
 			     const std::string &origin,
 			     const std::string &channel,
 			     const std::string &mode,
@@ -265,7 +267,8 @@
 	call("onChannelMode", 5);
 }
 
-void JsPlugin::onChannelNotice(const std::shared_ptr<Server> &server,
+void JsPlugin::onChannelNotice(Irccd &,
+			       const std::shared_ptr<Server> &server,
 			       const std::string &origin,
 			       const std::string &channel,
 			       const std::string &notice)
@@ -279,7 +282,8 @@
 	call("onChannelNotice", 4);
 }
 
-void JsPlugin::onCommand(const std::shared_ptr<Server> &server,
+void JsPlugin::onCommand(Irccd &,
+			 const std::shared_ptr<Server> &server,
 			 const std::string &origin,
 			 const std::string &channel,
 			 const std::string &message)
@@ -293,7 +297,7 @@
 	call("onCommand", 4);
 }
 
-void JsPlugin::onConnect(const std::shared_ptr<Server> &server)
+void JsPlugin::onConnect(Irccd &, const std::shared_ptr<Server> &server)
 {
 	duk::StackAssert sa(m_context);
 
@@ -301,7 +305,7 @@
 	call("onConnect", 1);
 }
 
-void JsPlugin::onInvite(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+void JsPlugin::onInvite(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
 {
 	duk::StackAssert sa(m_context);
 
@@ -311,7 +315,7 @@
 	call("onInvite", 3);
 }
 
-void JsPlugin::onJoin(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+void JsPlugin::onJoin(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
 {
 	duk::StackAssert sa(m_context);
 
@@ -321,7 +325,8 @@
 	call("onJoin", 3);
 }
 
-void JsPlugin::onKick(const std::shared_ptr<Server> &server,
+void JsPlugin::onKick(Irccd &,
+		      const std::shared_ptr<Server> &server,
 		      const std::string &origin,
 		      const std::string &channel,
 		      const std::string &target,
@@ -337,14 +342,15 @@
 	call("onKick", 5);
 }
 
-void JsPlugin::onLoad()
+void JsPlugin::onLoad(Irccd &)
 {
 	duk::StackAssert sa(m_context);
 
 	call("onLoad", 0);
 }
 
-void JsPlugin::onMessage(const std::shared_ptr<Server> &server,
+void JsPlugin::onMessage(Irccd &,
+			 const std::shared_ptr<Server> &server,
 			 const std::string &origin,
 			 const std::string &channel,
 			 const std::string &message)
@@ -358,7 +364,8 @@
 	call("onMessage", 4);
 }
 
-void JsPlugin::onMe(const std::shared_ptr<Server> &server,
+void JsPlugin::onMe(Irccd &,
+		    const std::shared_ptr<Server> &server,
 		    const std::string &origin,
 		    const std::string &channel,
 		    const std::string &message)
@@ -372,7 +379,7 @@
 	call("onMe", 4);
 }
 
-void JsPlugin::onMode(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode)
+void JsPlugin::onMode(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode)
 {
 	duk::StackAssert sa(m_context);
 
@@ -382,7 +389,7 @@
 	call("onMode", 3);
 }
 
-void JsPlugin::onNames(const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &names)
+void JsPlugin::onNames(Irccd &, const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &names)
 {
 	duk::StackAssert sa(m_context);
 
@@ -392,7 +399,7 @@
 	call("onNames", 3);
 }
 
-void JsPlugin::onNick(const std::shared_ptr<Server> &server, const std::string &oldnick, const std::string &newnick)
+void JsPlugin::onNick(Irccd &, const std::shared_ptr<Server> &server, const std::string &oldnick, const std::string &newnick)
 {
 	duk::StackAssert sa(m_context);
 
@@ -402,7 +409,7 @@
 	call("onNick", 3);
 }
 
-void JsPlugin::onNotice(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice)
+void JsPlugin::onNotice(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice)
 {
 	duk::StackAssert sa(m_context);
 
@@ -412,7 +419,8 @@
 	call("onNotice", 3);
 }
 
-void JsPlugin::onPart(const std::shared_ptr<Server> &server,
+void JsPlugin::onPart(Irccd &,
+		      const std::shared_ptr<Server> &server,
 		      const std::string &origin,
 		      const std::string &channel,
 		      const std::string &reason)
@@ -426,7 +434,8 @@
 	call("onPart", 4);
 }
 
-void JsPlugin::onQuery(const std::shared_ptr<Server> &server,
+void JsPlugin::onQuery(Irccd &,
+		       const std::shared_ptr<Server> &server,
 		       const std::string &origin,
 		       const std::string &message)
 {
@@ -438,7 +447,8 @@
 	call("onQuery", 3);
 }
 
-void JsPlugin::onQueryCommand(const std::shared_ptr<Server> &server,
+void JsPlugin::onQueryCommand(Irccd &,
+			      const std::shared_ptr<Server> &server,
 			      const std::string &origin,
 			      const std::string &message)
 {
@@ -450,14 +460,15 @@
 	call("onQueryCommand", 3);
 }
 
-void JsPlugin::onReload()
+void JsPlugin::onReload(Irccd &)
 {
 	duk::StackAssert sa(m_context);
 
 	call("onReload");
 }
 
-void JsPlugin::onTopic(const std::shared_ptr<Server> &server,
+void JsPlugin::onTopic(Irccd &,
+		       const std::shared_ptr<Server> &server,
 		       const std::string &origin,
 		       const std::string &channel,
 		       const std::string &topic)
@@ -471,14 +482,14 @@
 	call("onTopic", 4);
 }
 
-void JsPlugin::onUnload()
+void JsPlugin::onUnload(Irccd &)
 {
 	duk::StackAssert sa(m_context);
 
 	call("onUnload");
 }
 
-void JsPlugin::onWhois(const std::shared_ptr<Server> &server, const ServerWhois &whois)
+void JsPlugin::onWhois(Irccd &, const std::shared_ptr<Server> &server, const ServerWhois &whois)
 {
 	duk::StackAssert sa(m_context);
 
--- a/lib/irccd/plugin-js.hpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/plugin-js.hpp	Fri May 13 12:06:06 2016 +0200
@@ -24,10 +24,18 @@
  * \brief JavaScript plugins for irccd.
  */
 
+#include <unordered_set>
+
+#include "js.hpp"
+#include "path.hpp"
 #include "plugin.hpp"
+#include "signals.hpp"
 
 namespace irccd {
 
+class Module;
+class Timer;
+
 /**
  * \brief Timers that a plugin owns.
  */
@@ -116,216 +124,149 @@
 	}
 
 	/**
-	 * On channel message. This event will call onMessage or
-	 * onCommand if the messages starts with the command character
-	 * plus the plugin name.
-	 *
-	 * \param server the server
-	 * \param origin the user who sent the message
-	 * \param channel the channel
-	 * \param message the message or command
+	 * \copydoc Plugin::onCommand
 	 */
-	void onCommand(const std::shared_ptr<Server> &server,
+	void onCommand(Irccd &irccd,
+		       const std::shared_ptr<Server> &server,
 		       const std::string &origin,
 		       const std::string &channel,
 		       const std::string &message) override;
 
 	/**
-	 * On successful connection.
-	 *
-	 * \param server the server
+	 * \copydoc Plugin::onConnect
 	 */
-	void onConnect(const std::shared_ptr<Server> &server) override;
+	void onConnect(Irccd &irccd, const std::shared_ptr<Server> &server) override;
 
 	/**
-	 * On channel mode.
-	 *
-	 * \param server the server
-	 * \param origin the ouser who has changed the mode
-	 * \param channel the channel
-	 * \param mode the mode
-	 * \param arg the optional mode argument
+	 * \copydoc Plugin::onChannelMode
 	 */
-	void onChannelMode(const std::shared_ptr<Server> &server,
+	void onChannelMode(Irccd &irccd,
+			   const std::shared_ptr<Server> &server,
 			   const std::string &origin,
 			   const std::string &channel,
 			   const std::string &mode,
 			   const std::string &arg) override;
 
 	/**
-	 * On a channel notice.
-	 *
-	 * \param server the server
-	 * \param origin the user who sent the notice
-	 * \param channel on which channel
-	 * \param notice the message
+	 * \copydoc Plugin::onChannelNotice
 	 */
-	void onChannelNotice(const std::shared_ptr<Server> &server,
+	void onChannelNotice(Irccd &irccd,
+			     const std::shared_ptr<Server> &server,
 			     const std::string &origin,
 			     const std::string &channel,
 			     const std::string &notice) override;
 
 	/**
-	 * On invitation.
-	 *
-	 * \param server the server
-	 * \param origin the user who invited you
-	 * \param channel the channel
+	 * \copydoc Plugin::onInvite
 	 */
-	void onInvite(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override;
+	void onInvite(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override;
 
 	/**
-	 * On join.
-	 *
-	 * \param server the server
-	 * \param origin the user who joined
-	 * \param channel the channel
+	 * \copydoc Plugin::onJoin
 	 */
-	void onJoin(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override;
+	void onJoin(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override;
 
 	/**
-	 * On kick.
-	 *
-	 * \param server the server
-	 * \param origin the user who kicked the target
-	 * \param channel the channel
-	 * \param target the kicked target
-	 * \param reason the optional reason
+	 * \copydoc Plugin::onKick
 	 */
-	void onKick(const std::shared_ptr<Server> &server,
+	void onKick(Irccd &irccd,
+		    const std::shared_ptr<Server> &server,
 		    const std::string &origin,
 		    const std::string &channel,
 		    const std::string &target,
 		    const std::string &reason) override;
 
 	/**
-	 * On load.
+	 * \copydoc Plugin::onLoad
 	 */
-	void onLoad() override;
+	void onLoad(Irccd &irccd) override;
 
 	/**
-	 * On channel message.
-	 *
-	 * \param server the server
-	 * \param origin the user who sent the message
-	 * \param channel the channel
-	 * \param message the message or command
+	 * \copydoc Plugin::onMessage
 	 */
-	void onMessage(const std::shared_ptr<Server> &server,
-			       const std::string &origin,
-			       const std::string &channel,
-			       const std::string &message) override;
+	void onMessage(Irccd &irccd,
+		       const std::shared_ptr<Server> &server,
+		       const std::string &origin,
+		       const std::string &channel,
+		       const std::string &message) override;
 
 	/**
-	 * On CTCP Action.
-	 *
-	 * \param server the server
-	 * \param origin the user who sent the message
-	 * \param channel the channel (may also be your nickname)
-	 * \param message the message
+	 * \copydoc Plugin::onMe
 	 */
-	void onMe(const std::shared_ptr<Server> &server,
+	void onMe(Irccd &irccd,
+		  const std::shared_ptr<Server> &server,
 		  const std::string &origin,
 		  const std::string &channel,
 		  const std::string &message) override;
 
 	/**
-	 * On user mode change.
-	 *
-	 * \param server the server
-	 * \param origin the person who changed the mode
-	 * \param mode the new mode
+	 * \copydoc Plugin::onMode
 	 */
-	void onMode(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode) override;
+	void onMode(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode) override;
 
 	/**
-	 * On names listing.
-	 *
-	 * \param server the server
-	 * \param channel the channel
-	 * \param list the list of nicknames
+	 * \copydoc Plugin::onNames
 	 */
-	void onNames(const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &list) override;
+	void onNames(Irccd &irccd,
+		     const std::shared_ptr<Server> &server,
+		     const std::string &channel,
+		     const std::vector<std::string> &list) override;
 
 	/**
-	 * On nick change.
-	 *
-	 * \param server the server
-	 * \param origin the user that changed its nickname
-	 * \param nick the new nickname
+	 * \copydoc Plugin::onNick
 	 */
-	void onNick(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick) override;
+	void onNick(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick) override;
 
 	/**
-	 * On user notice.
-	 *
-	 * \param server the server
-	 * \param origin the user who sent the notice
-	 * \param notice the notice
+	 * \copydoc Plugin::onNotice
 	 */
-	void onNotice(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice) override;
+	void onNotice(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice) override;
 
 	/**
-	 * On part.
-	 *
-	 * \param server the server
-	 * \param origin the user who left
-	 * \param channel the channel
-	 * \param reason the optional reason
+	 * \copydoc Plugin::onPart
 	 */
-	void onPart(const std::shared_ptr<Server> &server,
+	void onPart(Irccd &irccd,
+		    const std::shared_ptr<Server> &server,
 		    const std::string &origin,
 		    const std::string &channel,
 		    const std::string &reason) override;
 
 	/**
-	 * On user query.
-	 *
-	 * \param server the server
-	 * \param origin the user who sent the query
-	 * \param message the message
+	 * \copydoc Plugin::onQuery
 	 */
-	void onQuery(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) override;
+	void onQuery(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) override;
 
 	/**
-	 * On user query command.
-	 *
-	 * \param server the server
-	 * \param origin the user who sent the query
-	 * \param message the message
+	 * \copydoc Plugin::onQueryCommand
 	 */
-	void onQueryCommand(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) override;
+	void onQueryCommand(Irccd &irccd,
+			    const std::shared_ptr<Server> &server,
+			    const std::string &origin,
+			    const std::string &message) override;
 
 	/**
-	 * On reload.
+	 * \copydoc Plugin::onReload
 	 */
-	void onReload() override;
+	void onReload(Irccd &irccd) override;
 
 	/**
-	 * On topic change.
-	 *
-	 * \param server the server
-	 * \param origin the user who sent the topic
-	 * \param channel the channel
-	 * \param topic the new topic
+	 * \copydoc Plugin::onTopic
 	 */
-	void onTopic(const std::shared_ptr<Server> &server,
+	void onTopic(Irccd &irccd,
+		     const std::shared_ptr<Server> &server,
 		     const std::string &origin,
 		     const std::string &channel,
 		     const std::string &topic) override;
 
 	/**
-	 * On unload.
+	 * \copydoc Plugin::onUnload
 	 */
-	void onUnload() override;
+	void onUnload(Irccd &irccd) override;
 
 	/**
-	 * On whois information.
-	 *
-	 * \param server the server
-	 * \param info the info
+	 * \copydoc Plugin::onWhois
 	 */
-	void onWhois(const std::shared_ptr<Server> &server, const ServerWhois &info) override;
+	void onWhois(Irccd &irccd, const std::shared_ptr<Server> &server, const ServerWhois &info) override;
 };
 
 } // !irccd
--- a/lib/irccd/plugin.cpp	Thu May 12 15:06:23 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * plugin.cpp -- irccd JavaScript plugin interface
- *
- * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <stdexcept>
-
-#include <format.h>
-
-#include "fs.hpp"
-#include "logger.hpp"
-#include "path.hpp"
-#include "plugin-js.hpp"
-#include "server.hpp"
-#include "util.hpp"
-
-using namespace std;
-
-using namespace fmt::literals;
-
-namespace irccd {
-
-std::shared_ptr<Plugin> Plugin::find(const std::string &name, const PluginConfig &config)
-{
-	log::info("plugin {}: searching {}.js"_format(name, name));
-
-	for (const auto &path : path::list(path::PathPlugins)) {
-		std::string fullpath = path + name + ".js";
-
-		if (!fs::isReadable(fullpath)) {
-			continue;
-		}
-
-		log::info("plugin {}: trying {}"_format(name, fullpath));
-
-		try {
-			return std::make_shared<JsPlugin>(name, fullpath, config);
-		} catch (const std::exception &ex) {
-			throw std::runtime_error("{}: {}"_format(fullpath, ex.what()));
-		}
-	}
-
-	throw std::runtime_error("no suitable plugin found");
-}
-
-} // !irccd
--- a/lib/irccd/plugin.hpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/plugin.hpp	Fri May 13 12:06:06 2016 +0200
@@ -27,16 +27,13 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
-#include <unordered_set>
 #include <vector>
 
-#include "js.hpp"
-#include "path.hpp"
-#include "signals.hpp"
-#include "timer.hpp"
+#include "util.hpp"
 
 namespace irccd {
 
+class Irccd;
 class Server;
 class ServerWhois;
 
@@ -68,14 +65,6 @@
 
 public:
 	/**
-	 * Find plugin in standard paths.
-	 *
-	 * \param name the plugin name
-	 * \param config the optional configuration
-	 */
-	static std::shared_ptr<Plugin> find(const std::string &name, const PluginConfig &config = PluginConfig());
-
-	/**
 	 * Constructor.
 	 *
 	 * \param name the plugin id
@@ -201,20 +190,19 @@
 	 * onCommand if the messages starts with the command character
 	 * plus the plugin name.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who sent the message
 	 * \param channel the channel
 	 * \param message the message or command
 	 */
-	virtual void onCommand(const std::shared_ptr<Server> &server,
+	virtual void onCommand(Irccd &irccd,
+			       const std::shared_ptr<Server> &server,
 			       const std::string &origin,
 			       const std::string &channel,
 			       const std::string &message)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
-		(void)message;
+		util::unused(irccd, server, origin, channel, message);
 	}
 
 	/**
@@ -222,293 +210,291 @@
 	 *
 	 * \param server the server
 	 */
-	virtual void onConnect(const std::shared_ptr<Server> &server)
+	virtual void onConnect(Irccd &irccd, const std::shared_ptr<Server> &server)
 	{
-		(void)server;
+		util::unused(irccd, server);
 	}
 
 	/**
 	 * On channel mode.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the ouser who has changed the mode
 	 * \param channel the channel
 	 * \param mode the mode
 	 * \param arg the optional mode argument
 	 */
-	virtual void onChannelMode(const std::shared_ptr<Server> &server,
+	virtual void onChannelMode(Irccd &irccd,
+				   const std::shared_ptr<Server> &server,
 				   const std::string &origin,
 				   const std::string &channel,
 				   const std::string &mode,
 				   const std::string &arg)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
-		(void)mode;
-		(void)arg;
+		util::unused(irccd, server, origin, channel, mode, arg);
 	}
 
 	/**
 	 * On a channel notice.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who sent the notice
 	 * \param channel on which channel
 	 * \param notice the message
 	 */
-	virtual void onChannelNotice(const std::shared_ptr<Server> &server,
+	virtual void onChannelNotice(Irccd &irccd,
+				     const std::shared_ptr<Server> &server,
 				     const std::string &origin,
 				     const std::string &channel,
 				     const std::string &notice)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
-		(void)notice;
+		util::unused(irccd, server, origin, channel, notice);
 	}
 
 	/**
 	 * On invitation.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who invited you
 	 * \param channel the channel
 	 */
-	virtual void onInvite(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+	virtual void onInvite(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
+		util::unused(irccd, server, origin, channel);
 	}
 
 	/**
 	 * On join.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who joined
 	 * \param channel the channel
 	 */
-	virtual void onJoin(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+	virtual void onJoin(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
+		util::unused(irccd, server, origin, channel);
 	}
 
 	/**
 	 * On kick.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who kicked the target
 	 * \param channel the channel
 	 * \param target the kicked target
 	 * \param reason the optional reason
 	 */
-	virtual void onKick(const std::shared_ptr<Server> &server,
+	virtual void onKick(Irccd &irccd, 
+			    const std::shared_ptr<Server> &server,
 			    const std::string &origin,
 			    const std::string &channel,
 			    const std::string &target,
 			    const std::string &reason)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
-		(void)target;
-		(void)reason;
+		util::unused(irccd, server, origin, channel, target, reason);
 	}
 
 	/**
 	 * On load.
+	 *
+	 * \param irccd the irccd instance
 	 */
-	virtual void onLoad()
+	virtual void onLoad(Irccd &irccd)
 	{
+		util::unused(irccd);
 	}
 
 	/**
 	 * On channel message.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who sent the message
 	 * \param channel the channel
 	 * \param message the message or command
 	 */
-	virtual void onMessage(const std::shared_ptr<Server> &server,
+	virtual void onMessage(Irccd &irccd, 
+			       const std::shared_ptr<Server> &server,
 			       const std::string &origin,
 			       const std::string &channel,
 			       const std::string &message)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
-		(void)message;
+		util::unused(irccd, server, origin, channel, message);
 	}
 
 	/**
 	 * On CTCP Action.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who sent the message
 	 * \param channel the channel (may also be your nickname)
 	 * \param message the message
 	 */
-	virtual void onMe(const std::shared_ptr<Server> &server,
+	virtual void onMe(Irccd &irccd, 
+			  const std::shared_ptr<Server> &server,
 			  const std::string &origin,
 			  const std::string &channel,
 			  const std::string &message)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
-		(void)message;
+		util::unused(irccd, server, origin, channel, message);
 	}
 
 	/**
 	 * On user mode change.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the person who changed the mode
 	 * \param mode the new mode
 	 */
-	virtual void onMode(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode)
+	virtual void onMode(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode)
 	{
-		(void)server;
-		(void)origin;
-		(void)mode;
+		util::unused(irccd, server, origin, mode);
 	}
 
 	/**
 	 * On names listing.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param channel the channel
 	 * \param list the list of nicknames
 	 */
-	virtual void onNames(const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &list)
+	virtual void onNames(Irccd &irccd,
+			     const std::shared_ptr<Server> &server,
+			     const std::string &channel,
+			     const std::vector<std::string> &list)
 	{
-		(void)server;
-		(void)channel;
-		(void)list;
+		util::unused(irccd, server, channel, list);
 	}
 
 	/**
 	 * On nick change.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user that changed its nickname
 	 * \param nick the new nickname
 	 */
-	virtual void onNick(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick)
+	virtual void onNick(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick)
 	{
-		(void)server;
-		(void)origin;
-		(void)nick;
+		util::unused(irccd, server, origin, nick);
 	}
 
 	/**
 	 * On user notice.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who sent the notice
 	 * \param notice the notice
 	 */
-	virtual void onNotice(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice)
+	virtual void onNotice(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice)
 	{
-		(void)server;
-		(void)origin;
-		(void)notice;
+		util::unused(irccd, server, origin, notice);
 	}
 
 	/**
 	 * On part.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who left
 	 * \param channel the channel
 	 * \param reason the optional reason
 	 */
-	virtual void onPart(const std::shared_ptr<Server> &server,
+	virtual void onPart(Irccd &irccd, 
+			    const std::shared_ptr<Server> &server,
 			    const std::string &origin,
 			    const std::string &channel,
 			    const std::string &reason)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
-		(void)reason;
+		util::unused(irccd, server, origin, channel, reason);
 	}
 
 	/**
 	 * On user query.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who sent the query
 	 * \param message the message
 	 */
-	virtual void onQuery(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message)
+	virtual void onQuery(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message)
 	{
-		(void)server;
-		(void)origin;
-		(void)message;
+		util::unused(irccd, server, origin, message);
 	}
 
 	/**
 	 * On user query command.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who sent the query
 	 * \param message the message
 	 */
-	virtual void onQueryCommand(const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message)
+	virtual void onQueryCommand(Irccd &irccd,
+				    const std::shared_ptr<Server> &server,
+				    const std::string &origin,
+				    const std::string &message)
 	{
-		(void)server;
-		(void)origin;
-		(void)message;
+		util::unused(irccd, server, origin, message);
 	}
 
 	/**
 	 * On reload.
+	 *
+	 * \param irccd the irccd instance
 	 */
-	virtual void onReload()
+	virtual void onReload(Irccd &irccd)
 	{
+		util::unused(irccd);
 	}
 
 	/**
 	 * On topic change.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param origin the user who sent the topic
 	 * \param channel the channel
 	 * \param topic the new topic
 	 */
-	virtual void onTopic(const std::shared_ptr<Server> &server,
+	virtual void onTopic(Irccd &irccd, 
+			     const std::shared_ptr<Server> &server,
 			     const std::string &origin,
 			     const std::string &channel,
 			     const std::string &topic)
 	{
-		(void)server;
-		(void)origin;
-		(void)channel;
-		(void)topic;
+		util::unused(irccd, server, origin, channel, topic);
 	}
 
 	/**
 	 * On unload.
+	 *
+	 * \param irccd the irccd instance
 	 */
-	virtual void onUnload()
+	virtual void onUnload(Irccd &irccd)
 	{
+		util::unused(irccd);
 	}
 
 	/**
 	 * On whois information.
 	 *
+	 * \param irccd the irccd instance
 	 * \param server the server
 	 * \param info the info
 	 */
-	virtual void onWhois(const std::shared_ptr<Server> &server, const ServerWhois &info)
+	virtual void onWhois(Irccd &irccd, const std::shared_ptr<Server> &server, const ServerWhois &info)
 	{
-		(void)server;
-		(void)info;
+		util::unused(irccd, server, info);
 	}
 };
 
--- a/lib/irccd/server-event.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/server-event.cpp	Fri May 13 12:06:06 2016 +0200
@@ -18,7 +18,7 @@
 
 #include "irccd.hpp"
 #include "logger.hpp"
-#include "plugin.hpp"
+#include "plugin-js.hpp"
 #include "server-event.hpp"
 #include "service-plugin.hpp"
 #include "service-rule.hpp"
@@ -51,6 +51,7 @@
 			log::debug() << "rule: event allowed" << std::endl;
 		}
 
+		// TODO: server-event must not know which type of plugin
 		try {
 			m_plugin_exec(*plugin);
 		} catch (const duk::ErrorInfo &info) {
--- a/lib/irccd/service-plugin.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/service-plugin.cpp	Fri May 13 12:06:06 2016 +0200
@@ -22,6 +22,8 @@
 
 #include <format.h>
 
+#include "config.hpp"
+#include "fs.hpp"
 #include "irccd.hpp"
 #include "logger.hpp"
 #include "plugin.hpp"
@@ -37,6 +39,13 @@
 {
 }
 
+void PluginService::addModule(std::shared_ptr<Module> module)
+{
+	assert(module);
+
+	m_modules.push_back(std::move(module));
+}
+
 bool PluginService::has(const std::string &name) const noexcept
 {
 	return std::count_if(m_plugins.cbegin(), m_plugins.cend(), [&] (const auto &plugin) {
@@ -86,17 +95,34 @@
 	}
 
 	// Initial load now.
+	// TODO: not responsible of this.
 	try {
-		plugin->onLoad();
+		plugin->onLoad(m_irccd);
 		m_plugins.push_back(std::move(plugin));
 	} catch (const std::exception &ex) {
 		log::warning("plugin {}: {}"_format(plugin->name(), ex.what()));
 	}
 }
 
-void PluginService::load(std::string name, const std::string &source, bool find)
+std::shared_ptr<Plugin> PluginService::find(std::string name, PluginConfig config)
 {
-	// TODO: change with Plugin::find
+	for (const auto &path : path::list(path::PathPlugins)) {
+		std::string fullpath = path + name + ".js";
+
+		if (!fs::isReadable(fullpath)) {
+			continue;
+		}
+
+		log::info("plugin {}: trying {}"_format(name, fullpath));
+
+		return std::make_shared<JsPlugin>(std::move(name), std::move(fullpath), std::move(config));
+	}
+
+	throw std::runtime_error("no suitable plugin found");
+}
+
+void PluginService::load(std::string name, std::string path)
+{
 	auto it = std::find_if(m_plugins.begin(), m_plugins.end(), [&] (const auto &plugin) {
 		return plugin->name() == name;
 	});
@@ -105,35 +131,18 @@
 		throw std::invalid_argument("plugin already loaded");
 	}
 
-	std::vector<std::string> paths;
+	// TODO: LOAD CONFIG
 	std::shared_ptr<Plugin> plugin;
 
-	if (find) {
-		for (const std::string &dir : path::list(path::PathPlugins)) {
-			paths.push_back(dir + source + ".js");
+	try {
+		if (path.empty()) {
+			plugin = find(std::move(name), PluginConfig());
+		} else {
+			// TODO: DYNLIB BASED PLUGINS
+			plugin = std::make_shared<JsPlugin>(std::move(name), std::move(path));
 		}
-	} else {
-		paths.push_back(source);
-	}
-
-	// Iterate over all paths.
-	log::info("plugin {}: trying to load:"_format(name));
-
-	for (const auto &path : paths) {
-		log::info() << "  from " << path << std::endl;
-
-		try {
-			plugin = std::make_shared<Plugin>(name, path /*, m_pluginConf[name] */);
-			break;
-		} catch (const std::exception &ex) {
-			log::info(fmt::format("    error: {}", ex.what()));
-		}
-	}
-
-	if (plugin) {
-		add(std::move(plugin));
-	} else {
-		throw std::runtime_error("no suitable plugin found");
+	} catch (const std::exception &ex) {
+		log::warning("plugin {}: {}"_format(ex.what()));
 	}
 }
 
@@ -142,7 +151,7 @@
 	auto plugin = get(name);
 
 	if (plugin) {
-		plugin->onReload();
+		plugin->onReload(m_irccd);
 	}
 }
 
@@ -153,7 +162,7 @@
 	});
 
 	if (it != m_plugins.end()) {
-		(*it)->onUnload();
+		(*it)->onUnload(m_irccd);
 		m_plugins.erase(it);
 	}
 }
--- a/lib/irccd/service-plugin.hpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/service-plugin.hpp	Fri May 13 12:06:06 2016 +0200
@@ -27,12 +27,11 @@
 #include <memory>
 #include <vector>
 
+#include "plugin-js.hpp"
+
 namespace irccd {
 
 class Irccd;
-class Plugin;
-class JsPlugin;
-class Timer;
 
 /**
  * \brief Manage plugins.
@@ -40,6 +39,7 @@
 class PluginService {
 private:
 	Irccd &m_irccd;
+	std::vector<std::shared_ptr<Module>> m_modules;
 	std::vector<std::shared_ptr<Plugin>> m_plugins;
 
 	// TODO: get rid of this with future JavaScript modules.
@@ -65,6 +65,14 @@
 	}
 
 	/**
+	 * Add an API module for JavaScript plugins.
+	 *
+	 * \pre module is not null
+	 * \param module the module
+	 */
+	void addModule(std::shared_ptr<Module> module);
+
+	/**
 	 * Check if a plugin is loaded.
 	 *
 	 * \param name the plugin id
@@ -73,7 +81,7 @@
 	bool has(const std::string &name) const noexcept;
 
 	/**
-	 * Get a plugin or empty one if not found.
+	 * Get a loaded plugin or null if not found.
 	 *
 	 * \param name the plugin id
 	 * \return the plugin or empty one if not found
@@ -81,7 +89,7 @@
 	std::shared_ptr<Plugin> get(const std::string &name) const noexcept;
 
 	/**
-	 * Find a plugin.
+	 * Find a loaded plugin.
 	 *
 	 * \param name the plugin id
 	 * \return the plugin
@@ -89,24 +97,11 @@
 	 */
 	std::shared_ptr<Plugin> require(const std::string &name) const;
 
-	/**
-	 * Add a loaded plugin.
-	 *
-	 * Plugins signals will be connected to the irccd main loop. The onLoad function will also be called and the
-	 * plugin is not added on errors.
-	 *
-	 * \pre plugin must not be empty
-	 * \param plugin the plugin
-	 */
 	void add(std::shared_ptr<Plugin> plugin);
 
-	/**
-	 * Load a plugin by path or by searching through directories.
-	 *
-	 * \param source the path or the plugin id to search
-	 * \param find set to true for searching by id
-	 */
-	void load(std::string name, const std::string &source, bool find);
+	std::shared_ptr<Plugin> find(std::string name, PluginConfig config = PluginConfig());
+
+	void load(std::string name, std::string path = "");
 
 	/**
 	 * Unload a plugin and remove it.
--- a/lib/irccd/service-server.cpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/service-server.cpp	Fri May 13 12:06:06 2016 +0200
@@ -63,7 +63,8 @@
 			return "onChannelMode";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onChannelMode(std::move(server), std::move(origin), std::move(channel), std::move(mode), std::move(arg));
+			plugin.onChannelMode(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(mode),
+					     std::move(arg));
 		}
 	));
 #endif
@@ -96,7 +97,7 @@
 			return "onChannelNotice";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onChannelNotice(std::move(server), std::move(origin), std::move(channel), std::move(message));
+			plugin.onChannelNotice(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(message));
 		}
 	));
 #endif
@@ -123,7 +124,7 @@
 			return "onConnect";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onConnect(std::move(server));
+			plugin.onConnect(m_irccd, std::move(server));
 		}
 	));
 #endif
@@ -155,7 +156,7 @@
 			return "onInvite";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onInvite(std::move(server), std::move(origin), std::move(channel));
+			plugin.onInvite(m_irccd, std::move(server), std::move(origin), std::move(channel));
 		}
 	));
 #endif
@@ -186,7 +187,7 @@
 			return "onJoin";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onJoin(std::move(server), std::move(origin), std::move(channel));
+			plugin.onJoin(m_irccd, std::move(server), std::move(origin), std::move(channel));
 		}
 	));
 #endif
@@ -221,7 +222,7 @@
 			return "onKick";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onKick(std::move(server), std::move(origin), std::move(channel), std::move(target), std::move(reason));
+			plugin.onKick(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(target), std::move(reason));
 		}
 	));
 #endif
@@ -257,9 +258,9 @@
 			util::MessagePair pack = util::parseMessage(message, server->settings().command, plugin.name());
 
 			if (pack.second == util::MessageType::Command)
-				plugin.onCommand(std::move(server), std::move(origin), std::move(channel), std::move(pack.first));
+				plugin.onCommand(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(pack.first));
 			else
-				plugin.onMessage(std::move(server), std::move(origin), std::move(channel), std::move(pack.first));
+				plugin.onMessage(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(pack.first));
 		}
 	));
 #endif
@@ -292,7 +293,7 @@
 			return "onMe";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onMe(std::move(server), std::move(origin), std::move(target), std::move(message));
+			plugin.onMe(m_irccd, std::move(server), std::move(origin), std::move(target), std::move(message));
 		}
 	));
 #endif
@@ -323,7 +324,7 @@
 			return "onMode";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onMode(std::move(server), std::move(origin), std::move(mode));
+			plugin.onMode(m_irccd, std::move(server), std::move(origin), std::move(mode));
 		}
 	));
 #endif
@@ -356,7 +357,7 @@
 			return "onNames";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onNames(std::move(server), std::move(channel), std::vector<std::string>(nicknames.begin(), nicknames.end()));
+			plugin.onNames(m_irccd, std::move(server), std::move(channel), std::vector<std::string>(nicknames.begin(), nicknames.end()));
 		}
 	));
 #endif
@@ -387,7 +388,7 @@
 			return "onNick";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onNick(std::move(server), std::move(origin), std::move(nickname));
+			plugin.onNick(m_irccd, std::move(server), std::move(origin), std::move(nickname));
 		}
 	));
 #endif
@@ -418,7 +419,7 @@
 			return "onNotice";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onNotice(std::move(server), std::move(origin), std::move(message));
+			plugin.onNotice(m_irccd, std::move(server), std::move(origin), std::move(message));
 		}
 	));
 #endif
@@ -451,7 +452,7 @@
 			return "onPart";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onPart(std::move(server), std::move(origin), std::move(channel), std::move(reason));
+			plugin.onPart(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(reason));
 		}
 	));
 #endif
@@ -485,9 +486,9 @@
 			util::MessagePair pack = util::parseMessage(message, server->settings().command, plugin.name());
 
 			if (pack.second == util::MessageType::Command)
-				plugin.onQueryCommand(std::move(server), std::move(origin), std::move(pack.first));
+				plugin.onQueryCommand(m_irccd, std::move(server), std::move(origin), std::move(pack.first));
 			else
-				plugin.onQuery(std::move(server), std::move(origin), std::move(pack.first));
+				plugin.onQuery(m_irccd, std::move(server), std::move(origin), std::move(pack.first));
 		}
 	));
 #endif
@@ -520,7 +521,7 @@
 			return "onTopic";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onTopic(std::move(server), std::move(origin), std::move(channel), std::move(topic));
+			plugin.onTopic(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(topic));
 		}
 	));
 #endif
@@ -555,7 +556,7 @@
 			return "onWhois";
 		},
 		[=] (Plugin &plugin) {
-			plugin.onWhois(std::move(server), std::move(whois));
+			plugin.onWhois(m_irccd, std::move(server), std::move(whois));
 		}
 	));
 #endif
--- a/lib/irccd/util.hpp	Thu May 12 15:06:23 2016 +0200
+++ b/lib/irccd/util.hpp	Fri May 13 12:06:06 2016 +0200
@@ -292,6 +292,14 @@
  */
 std::string nextNetwork(std::string &input);
 
+/**
+ * Use arguments to avoid compiler warnings about unused parameters.
+ */
+template <typename... Args>
+inline void unused(Args&&...) noexcept
+{
+}
+
 } // !util
 
 } // !irccd