changeset 210:2d10d7e661a0

Irccd: make object based IRC events, #522
author David Demelier <markand@malikania.fr>
date Wed, 22 Jun 2016 13:02:29 +0200
parents f8612b08aa81
children c8c831d9f4bf
files lib/irccd/plugin-dynlib.cpp lib/irccd/plugin-dynlib.hpp lib/irccd/plugin-js.cpp lib/irccd/plugin-js.hpp lib/irccd/plugin.hpp lib/irccd/server.cpp lib/irccd/server.hpp lib/irccd/service-server.cpp lib/irccd/service-server.hpp tests/plugin-ask/main.cpp tests/plugin-auth/main.cpp tests/plugin-hangman/main.cpp tests/plugin-history/main.cpp tests/plugin-logger/main.cpp tests/plugin-plugin/main.cpp
diffstat 15 files changed, 718 insertions(+), 935 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/plugin-dynlib.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/plugin-dynlib.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -68,57 +68,39 @@
 {
 }
 
-void DynlibPlugin::onCommand(Irccd &irccd,
-                             const std::shared_ptr<Server> &server,
-                             const std::string &origin,
-                             const std::string &channel,
-                             const std::string &message)
+void DynlibPlugin::onCommand(Irccd &irccd, const MessageEvent &ev)
 {
-    call(m_onCommand, irccd, server, origin, channel, message);
+    call(m_onCommand, irccd, ev);
 }
 
-void DynlibPlugin::onConnect(Irccd &irccd, const std::shared_ptr<Server> &server)
+void DynlibPlugin::onConnect(Irccd &irccd, const ConnectEvent &ev)
 {
-    call(m_onConnect, irccd, server);
+    call(m_onConnect, irccd, ev);
 }
 
-void DynlibPlugin::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 DynlibPlugin::onChannelMode(Irccd &irccd, const ChannelModeEvent &ev)
 {
-    call(m_onChannelMode, irccd, server, origin, channel, mode, arg);
+    call(m_onChannelMode, irccd, ev);
 }
 
-void DynlibPlugin::onChannelNotice(Irccd &irccd,
-                                   const std::shared_ptr<Server> &server,
-                                   const std::string &origin,
-                                   const std::string &channel,
-                                   const std::string &notice)
+void DynlibPlugin::onChannelNotice(Irccd &irccd, const ChannelNoticeEvent &ev)
 {
-    call(m_onChannelNotice, irccd, server, origin, channel, notice);
-}
-
-void DynlibPlugin::onInvite(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
-{
-    call(m_onInvite, irccd, server, origin, channel);
+    call(m_onChannelNotice, irccd, ev);
 }
 
-void DynlibPlugin::onJoin(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+void DynlibPlugin::onInvite(Irccd &irccd, const InviteEvent &ev)
 {
-    call(m_onJoin, irccd, server, origin, channel);
+    call(m_onInvite, irccd, ev);
 }
 
-void DynlibPlugin::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 DynlibPlugin::onJoin(Irccd &irccd, const JoinEvent &ev)
 {
-    call(m_onKick, irccd, server, origin, channel, target, reason);
+    call(m_onJoin, irccd, ev);
+}
+
+void DynlibPlugin::onKick(Irccd &irccd, const KickEvent &ev)
+{
+    call(m_onKick, irccd, ev);
 }
 
 void DynlibPlugin::onLoad(Irccd &irccd)
@@ -126,67 +108,49 @@
     call(m_onLoad, irccd, *this);
 }
 
-void DynlibPlugin::onMessage(Irccd &irccd,
-                             const std::shared_ptr<Server> &server,
-                             const std::string &origin,
-                             const std::string &channel,
-                             const std::string &message)
+void DynlibPlugin::onMessage(Irccd &irccd, const MessageEvent &ev)
 {
-    call(m_onMessage, irccd, server, origin, channel, message);
+    call(m_onMessage, irccd, ev);
 }
 
-void DynlibPlugin::onMe(Irccd &irccd,
-                        const std::shared_ptr<Server> &server,
-                        const std::string &origin,
-                        const std::string &channel,
-                        const std::string &message)
+void DynlibPlugin::onMe(Irccd &irccd, const MeEvent &ev)
 {
-    call(m_onMe, irccd, server, origin, channel, message);
+    call(m_onMe, irccd, ev);
 }
 
-void DynlibPlugin::onMode(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode)
+void DynlibPlugin::onMode(Irccd &irccd, const ModeEvent &ev)
 {
-    call(m_onMode, irccd, server, origin, mode);
+    call(m_onMode, irccd, ev);
 }
 
-void DynlibPlugin::onNames(Irccd &irccd,
-                           const std::shared_ptr<Server> &server,
-                           const std::string &channel,
-                           const std::vector<std::string> &list)
+void DynlibPlugin::onNames(Irccd &irccd, const NamesEvent &ev)
 {
-    call(m_onNames, irccd, server, channel, list);
+    call(m_onNames, irccd, ev);
 }
 
-void DynlibPlugin::onNick(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick)
+void DynlibPlugin::onNick(Irccd &irccd, const NickEvent &ev)
 {
-    call(m_onNick, irccd, server, origin, nick);
+    call(m_onNick, irccd, ev);
 }
 
-void DynlibPlugin::onNotice(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice)
+void DynlibPlugin::onNotice(Irccd &irccd, const NoticeEvent &ev)
 {
-    call(m_onNotice, irccd, server, origin, notice);
+    call(m_onNotice, irccd, ev);
 }
 
-void DynlibPlugin::onPart(Irccd &irccd,
-                          const std::shared_ptr<Server> &server,
-                          const std::string &origin,
-                          const std::string &channel,
-                          const std::string &reason)
+void DynlibPlugin::onPart(Irccd &irccd, const PartEvent &ev)
 {
-    call(m_onPart, irccd, server, origin, channel, reason);
+    call(m_onPart, irccd, ev);
 }
 
-void DynlibPlugin::onQuery(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message)
+void DynlibPlugin::onQuery(Irccd &irccd, const QueryEvent &ev)
 {
-    call(m_onQuery, irccd, server, origin, message);
+    call(m_onQuery, irccd, ev);
 }
 
-void DynlibPlugin::onQueryCommand(Irccd &irccd,
-                                  const std::shared_ptr<Server> &server,
-                                  const std::string &origin,
-                                  const std::string &message)
+void DynlibPlugin::onQueryCommand(Irccd &irccd, const QueryEvent &ev)
 {
-    call(m_onQueryCommand, irccd, server, origin, message);
+    call(m_onQueryCommand, irccd, ev);
 }
 
 void DynlibPlugin::onReload(Irccd &irccd)
@@ -194,13 +158,9 @@
     call(m_onReload, irccd, *this);
 }
 
-void DynlibPlugin::onTopic(Irccd &irccd,
-                           const std::shared_ptr<Server> &server,
-                           const std::string &origin,
-                           const std::string &channel,
-                           const std::string &topic)
+void DynlibPlugin::onTopic(Irccd &irccd, const TopicEvent &ev)
 {
-    call(m_onTopic, irccd, server, origin, channel, topic);
+    call(m_onTopic, irccd, ev);
 }
 
 void DynlibPlugin::onUnload(Irccd &irccd)
@@ -208,9 +168,9 @@
     call(m_onUnload, irccd, *this);
 }
 
-void DynlibPlugin::onWhois(Irccd &irccd, const std::shared_ptr<Server> &server, const ServerWhois &info)
+void DynlibPlugin::onWhois(Irccd &irccd, const WhoisEvent &ev)
 {
-    call(m_onWhois, irccd, server, info);
+    call(m_onWhois, irccd, ev);
 }
 
 } // !irccd
--- a/lib/irccd/plugin-dynlib.hpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/plugin-dynlib.hpp	Wed Jun 22 13:02:29 2016 +0200
@@ -35,27 +35,27 @@
  */
 class DynlibPlugin : public Plugin {
 private:
-    using OnCommand = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &, const std::string &);
-    using OnConnect = void (*)(Irccd &, const std::shared_ptr<Server> &);
-    using OnChannelMode = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &, const std::string &, const std::string &);
-    using OnChannelNotice = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &, const std::string &);
-    using OnInvite = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &);
-    using OnJoin = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &);
-    using OnKick = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &, const std::string &, const std::string &);
+    using OnCommand = void (*)(Irccd &, const MessageEvent &);
+    using OnConnect = void (*)(Irccd &, const ConnectEvent &);
+    using OnChannelMode = void (*)(Irccd &, const ChannelModeEvent &);
+    using OnChannelNotice = void (*)(Irccd &, const ChannelNoticeEvent &);
+    using OnInvite = void (*)(Irccd &, const InviteEvent &);
+    using OnJoin = void (*)(Irccd &, const JoinEvent &);
+    using OnKick = void (*)(Irccd &, const KickEvent &);
     using OnLoad = void (*)(Irccd &, DynlibPlugin &);
-    using OnMessage = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &, const std::string &);
-    using OnMe = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &, const std::string &);
-    using OnMode = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &);
-    using OnNames = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::vector<std::string> &);
-    using OnNick = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &);
-    using OnNotice = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &);
-    using OnPart = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &, const std::string &);
-    using OnQuery = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &);
-    using OnQueryCommand = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &);
+    using OnMessage = void (*)(Irccd &, const MessageEvent &);
+    using OnMe = void (*)(Irccd &, const MeEvent &);
+    using OnMode = void (*)(Irccd &, const ModeEvent &);
+    using OnNames = void (*)(Irccd &, const NamesEvent &);
+    using OnNick = void (*)(Irccd &, const NickEvent &);
+    using OnNotice = void (*)(Irccd &, const NoticeEvent &);
+    using OnPart = void (*)(Irccd &, const PartEvent &);
+    using OnQuery = void (*)(Irccd &, const QueryEvent &);
+    using OnQueryCommand = void (*)(Irccd &, const QueryEvent &);
     using OnReload = void (*)(Irccd &, DynlibPlugin &);
-    using OnTopic = void (*)(Irccd &, const std::shared_ptr<Server> &, const std::string &, const std::string &, const std::string &);
+    using OnTopic = void (*)(Irccd &, const TopicEvent &);
     using OnUnload = void (*)(Irccd &, DynlibPlugin &);
-    using OnWhois = void (*)(Irccd &, const std::shared_ptr<Server> &, const ServerWhois &);
+    using OnWhois = void (*)(Irccd &, const WhoisEvent &);
 
     Dynlib m_dso;
     OnCommand m_onCommand;
@@ -97,55 +97,37 @@
     /**
      * \copydoc Plugin::onCommand
      */
-    IRCCD_EXPORT void onCommand(Irccd &irccd,
-                                const std::shared_ptr<Server> &server,
-                                const std::string &origin,
-                                const std::string &channel,
-                                const std::string &message) override;
+    IRCCD_EXPORT void onCommand(Irccd &irccd, const MessageEvent &event) override;
 
     /**
      * \copydoc Plugin::onConnect
      */
-    IRCCD_EXPORT void onConnect(Irccd &irccd, const std::shared_ptr<Server> &server) override;
+    IRCCD_EXPORT void onConnect(Irccd &irccd, const ConnectEvent &event) override;
 
     /**
      * \copydoc Plugin::onChannelMode
      */
-    IRCCD_EXPORT 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;
+    IRCCD_EXPORT void onChannelMode(Irccd &irccd, const ChannelModeEvent &event) override;
 
     /**
      * \copydoc Plugin::onChannelNotice
      */
-    IRCCD_EXPORT void onChannelNotice(Irccd &irccd,
-                                      const std::shared_ptr<Server> &server,
-                                      const std::string &origin,
-                                      const std::string &channel,
-                                      const std::string &notice) override;
+    IRCCD_EXPORT void onChannelNotice(Irccd &irccd, const ChannelNoticeEvent &event) override;
 
     /**
      * \copydoc Plugin::onInvite
      */
-    IRCCD_EXPORT void onInvite(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override;
+    IRCCD_EXPORT void onInvite(Irccd &irccd, const InviteEvent &event) override;
 
     /**
      * \copydoc Plugin::onJoin
      */
-    IRCCD_EXPORT void onJoin(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override;
+    IRCCD_EXPORT void onJoin(Irccd &irccd, const JoinEvent &event) override;
 
     /**
      * \copydoc Plugin::onKick
      */
-    IRCCD_EXPORT 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;
+    IRCCD_EXPORT void onKick(Irccd &irccd, const KickEvent &event) override;
 
     /**
      * \copydoc Plugin::onLoad
@@ -155,65 +137,47 @@
     /**
      * \copydoc Plugin::onMessage
      */
-    IRCCD_EXPORT void onMessage(Irccd &irccd,
-                                const std::shared_ptr<Server> &server,
-                                const std::string &origin,
-                                const std::string &channel,
-                                const std::string &message) override;
+    IRCCD_EXPORT void onMessage(Irccd &irccd, const MessageEvent &event) override;
 
     /**
      * \copydoc Plugin::onMe
      */
-    IRCCD_EXPORT void onMe(Irccd &irccd,
-                           const std::shared_ptr<Server> &server,
-                           const std::string &origin,
-                           const std::string &channel,
-                           const std::string &message) override;
+    IRCCD_EXPORT void onMe(Irccd &irccd, const MeEvent &event) override;
 
     /**
      * \copydoc Plugin::onMode
      */
-    IRCCD_EXPORT void onMode(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode) override;
+    IRCCD_EXPORT void onMode(Irccd &irccd, const ModeEvent &event) override;
 
     /**
      * \copydoc Plugin::onNames
      */
-    IRCCD_EXPORT void onNames(Irccd &irccd,
-                              const std::shared_ptr<Server> &server,
-                              const std::string &channel,
-                              const std::vector<std::string> &list) override;
+    IRCCD_EXPORT void onNames(Irccd &irccd, const NamesEvent &event) override;
 
     /**
      * \copydoc Plugin::onNick
      */
-    IRCCD_EXPORT void onNick(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick) override;
+    IRCCD_EXPORT void onNick(Irccd &irccd, const NickEvent &event) override;
 
     /**
      * \copydoc Plugin::onNotice
      */
-    IRCCD_EXPORT void onNotice(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice) override;
+    IRCCD_EXPORT void onNotice(Irccd &irccd, const NoticeEvent &event) override;
 
     /**
      * \copydoc Plugin::onPart
      */
-    IRCCD_EXPORT void onPart(Irccd &irccd,
-                             const std::shared_ptr<Server> &server,
-                             const std::string &origin,
-                             const std::string &channel,
-                             const std::string &reason) override;
+    IRCCD_EXPORT void onPart(Irccd &irccd, const PartEvent &event) override;
 
     /**
      * \copydoc Plugin::onQuery
      */
-    IRCCD_EXPORT void onQuery(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) override;
+    IRCCD_EXPORT void onQuery(Irccd &irccd, const QueryEvent &event) override;
 
     /**
      * \copydoc Plugin::onQueryCommand
      */
-    IRCCD_EXPORT void onQueryCommand(Irccd &irccd,
-                                     const std::shared_ptr<Server> &server,
-                                     const std::string &origin,
-                                     const std::string &message) override;
+    IRCCD_EXPORT void onQueryCommand(Irccd &irccd, const QueryEvent &event) override;
 
     /**
      * \copydoc Plugin::onReload
@@ -223,11 +187,7 @@
     /**
      * \copydoc Plugin::onTopic
      */
-    IRCCD_EXPORT void onTopic(Irccd &irccd,
-                              const std::shared_ptr<Server> &server,
-                              const std::string &origin,
-                              const std::string &channel,
-                              const std::string &topic) override;
+    IRCCD_EXPORT void onTopic(Irccd &irccd, const TopicEvent &event) override;
 
     /**
      * \copydoc Plugin::onUnload
@@ -237,7 +197,7 @@
     /**
      * \copydoc Plugin::onWhois
      */
-    IRCCD_EXPORT void onWhois(Irccd &irccd, const std::shared_ptr<Server> &server, const ServerWhois &info) override;
+    IRCCD_EXPORT void onWhois(Irccd &irccd, const WhoisEvent &event) override;
 };
 
 } // !irccd
--- a/lib/irccd/plugin-js.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/plugin-js.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -174,95 +174,77 @@
     putTable(FormatGlobal, formats);
 }
 
-void JsPlugin::onChannelMode(Irccd &,
-                             const std::shared_ptr<Server> &server,
-                             const std::string &origin,
-                             const std::string &channel,
-                             const std::string &mode,
-                             const std::string &arg)
+void JsPlugin::onChannelMode(Irccd &, const ChannelModeEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_std_string(m_context, mode);
-    dukx_push_std_string(m_context, arg);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_std_string(m_context, event.mode);
+    dukx_push_std_string(m_context, event.argument);
     call("onChannelMode", 5);
 }
 
-void JsPlugin::onChannelNotice(Irccd &,
-                               const std::shared_ptr<Server> &server,
-                               const std::string &origin,
-                               const std::string &channel,
-                               const std::string &notice)
+void JsPlugin::onChannelNotice(Irccd &, const ChannelNoticeEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_std_string(m_context, notice);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_std_string(m_context, event.message);
     call("onChannelNotice", 4);
 }
 
-void JsPlugin::onCommand(Irccd &,
-                         const std::shared_ptr<Server> &server,
-                         const std::string &origin,
-                         const std::string &channel,
-                         const std::string &message)
+void JsPlugin::onCommand(Irccd &, const MessageEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_std_string(m_context, message);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_std_string(m_context, event.message);
     call("onCommand", 4);
 }
 
-void JsPlugin::onConnect(Irccd &, const std::shared_ptr<Server> &server)
+void JsPlugin::onConnect(Irccd &, const ConnectEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
+    duk_push_server(m_context, std::move(event.server));
     call("onConnect", 1);
 }
 
-void JsPlugin::onInvite(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+void JsPlugin::onInvite(Irccd &, const InviteEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
     call("onInvite", 3);
 }
 
-void JsPlugin::onJoin(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+void JsPlugin::onJoin(Irccd &, const JoinEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
     call("onJoin", 3);
 }
 
-void JsPlugin::onKick(Irccd &,
-                      const std::shared_ptr<Server> &server,
-                      const std::string &origin,
-                      const std::string &channel,
-                      const std::string &target,
-                      const std::string &reason)
+void JsPlugin::onKick(Irccd &, const KickEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_std_string(m_context, target);
-    dukx_push_std_string(m_context, reason);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_std_string(m_context, event.target);
+    dukx_push_std_string(m_context, event.reason);
     call("onKick", 5);
 }
 
@@ -333,114 +315,96 @@
     call("onLoad", 0);
 }
 
-void JsPlugin::onMessage(Irccd &,
-                         const std::shared_ptr<Server> &server,
-                         const std::string &origin,
-                         const std::string &channel,
-                         const std::string &message)
+void JsPlugin::onMessage(Irccd &, const MessageEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_std_string(m_context, message);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_std_string(m_context, event.message);
     call("onMessage", 4);
 }
 
-void JsPlugin::onMe(Irccd &,
-                    const std::shared_ptr<Server> &server,
-                    const std::string &origin,
-                    const std::string &channel,
-                    const std::string &message)
+void JsPlugin::onMe(Irccd &, const MeEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_std_string(m_context, message);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_std_string(m_context, event.message);
     call("onMe", 4);
 }
 
-void JsPlugin::onMode(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode)
+void JsPlugin::onMode(Irccd &, const ModeEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, mode);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.mode);
     call("onMode", 3);
 }
 
-void JsPlugin::onNames(Irccd &, const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &names)
-{
-    StackAssert sa(m_context);
-
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_array(m_context, names, dukx_push_std_string);
-    call("onNames", 3);
-}
-
-void JsPlugin::onNick(Irccd &, const std::shared_ptr<Server> &server, const std::string &oldnick, const std::string &newnick)
+void JsPlugin::onNames(Irccd &, const NamesEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, oldnick);
-    dukx_push_std_string(m_context, newnick);
-    call("onNick", 3);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_array(m_context, event.names, dukx_push_std_string);
+    call("onNames", 3);
 }
 
-void JsPlugin::onNotice(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice)
+void JsPlugin::onNick(Irccd &, const NickEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, notice);
-    call("onNotice", 3);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.nickname);
+    call("onNick", 3);
 }
 
-void JsPlugin::onPart(Irccd &,
-                      const std::shared_ptr<Server> &server,
-                      const std::string &origin,
-                      const std::string &channel,
-                      const std::string &reason)
+void JsPlugin::onNotice(Irccd &, const NoticeEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_std_string(m_context, reason);
-    call("onPart", 4);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.message);
+    call("onNotice", 3);
 }
 
-void JsPlugin::onQuery(Irccd &,
-                       const std::shared_ptr<Server> &server,
-                       const std::string &origin,
-                       const std::string &message)
+void JsPlugin::onPart(Irccd &, const PartEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, message);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_std_string(m_context, event.reason);
+    call("onPart", 4);
+}
+
+void JsPlugin::onQuery(Irccd &, const QueryEvent &event)
+{
+    StackAssert sa(m_context);
+
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.message);
     call("onQuery", 3);
 }
 
-void JsPlugin::onQueryCommand(Irccd &,
-                              const std::shared_ptr<Server> &server,
-                              const std::string &origin,
-                              const std::string &message)
+void JsPlugin::onQueryCommand(Irccd &, const QueryEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, message);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.message);
     call("onQueryCommand", 3);
 }
 
@@ -451,18 +415,14 @@
     call("onReload");
 }
 
-void JsPlugin::onTopic(Irccd &,
-                       const std::shared_ptr<Server> &server,
-                       const std::string &origin,
-                       const std::string &channel,
-                       const std::string &topic)
+void JsPlugin::onTopic(Irccd &, const TopicEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
-    dukx_push_std_string(m_context, origin);
-    dukx_push_std_string(m_context, channel);
-    dukx_push_std_string(m_context, topic);
+    duk_push_server(m_context, std::move(event.server));
+    dukx_push_std_string(m_context, event.origin);
+    dukx_push_std_string(m_context, event.channel);
+    dukx_push_std_string(m_context, event.topic);
     call("onTopic", 4);
 }
 
@@ -476,21 +436,21 @@
         module->unload(irccd, std::static_pointer_cast<JsPlugin>(shared_from_this()));
 }
 
-void JsPlugin::onWhois(Irccd &, const std::shared_ptr<Server> &server, const ServerWhois &whois)
+void JsPlugin::onWhois(Irccd &, const WhoisEvent &event)
 {
     StackAssert sa(m_context);
 
-    duk_push_server(m_context, server);
+    duk_push_server(m_context, std::move(event.server));
     duk_push_object(m_context);
-    dukx_push_std_string(m_context, whois.nick);
+    dukx_push_std_string(m_context, event.whois.nick);
     duk_put_prop_string(m_context, -2, "nickname");
-    dukx_push_std_string(m_context, whois.user);
+    dukx_push_std_string(m_context, event.whois.user);
     duk_put_prop_string(m_context, -2, "username");
-    dukx_push_std_string(m_context, whois.realname);
+    dukx_push_std_string(m_context, event.whois.realname);
     duk_put_prop_string(m_context, -2, "realname");
-    dukx_push_std_string(m_context, whois.host);
+    dukx_push_std_string(m_context, event.whois.host);
     duk_put_prop_string(m_context, -2, "host");
-    dukx_push_array(m_context, whois.channels, dukx_push_std_string);
+    dukx_push_array(m_context, event.whois.channels, dukx_push_std_string);
     duk_put_prop_string(m_context, -2, "channels");
     call("onWhois", 2);
 }
--- a/lib/irccd/plugin-js.hpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/plugin-js.hpp	Wed Jun 22 13:02:29 2016 +0200
@@ -83,55 +83,37 @@
     /**
      * \copydoc Plugin::onCommand
      */
-    IRCCD_EXPORT void onCommand(Irccd &irccd,
-                                const std::shared_ptr<Server> &server,
-                                const std::string &origin,
-                                const std::string &channel,
-                                const std::string &message) override;
+    IRCCD_EXPORT void onCommand(Irccd &irccd, const MessageEvent &event) override;
 
     /**
      * \copydoc Plugin::onConnect
      */
-    IRCCD_EXPORT void onConnect(Irccd &irccd, const std::shared_ptr<Server> &server) override;
+    IRCCD_EXPORT void onConnect(Irccd &irccd, const ConnectEvent &event) override;
 
     /**
      * \copydoc Plugin::onChannelMode
      */
-    IRCCD_EXPORT 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;
+    IRCCD_EXPORT void onChannelMode(Irccd &irccd, const ChannelModeEvent &event) override;
 
     /**
      * \copydoc Plugin::onChannelNotice
      */
-    IRCCD_EXPORT void onChannelNotice(Irccd &irccd,
-                                      const std::shared_ptr<Server> &server,
-                                      const std::string &origin,
-                                      const std::string &channel,
-                                      const std::string &notice) override;
+    IRCCD_EXPORT void onChannelNotice(Irccd &irccd, const ChannelNoticeEvent &event) override;
 
     /**
      * \copydoc Plugin::onInvite
      */
-    IRCCD_EXPORT void onInvite(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override;
+    IRCCD_EXPORT void onInvite(Irccd &irccd, const InviteEvent &event) override;
 
     /**
      * \copydoc Plugin::onJoin
      */
-    IRCCD_EXPORT void onJoin(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) override;
+    IRCCD_EXPORT void onJoin(Irccd &irccd, const JoinEvent &event) override;
 
     /**
      * \copydoc Plugin::onKick
      */
-    IRCCD_EXPORT 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;
+    IRCCD_EXPORT void onKick(Irccd &irccd, const KickEvent &event) override;
 
     /**
      * \copydoc Plugin::onLoad
@@ -141,65 +123,47 @@
     /**
      * \copydoc Plugin::onMessage
      */
-    IRCCD_EXPORT void onMessage(Irccd &irccd,
-                                const std::shared_ptr<Server> &server,
-                                const std::string &origin,
-                                const std::string &channel,
-                                const std::string &message) override;
+    IRCCD_EXPORT void onMessage(Irccd &irccd, const MessageEvent &event) override;
 
     /**
      * \copydoc Plugin::onMe
      */
-    IRCCD_EXPORT void onMe(Irccd &irccd,
-                           const std::shared_ptr<Server> &server,
-                           const std::string &origin,
-                           const std::string &channel,
-                           const std::string &message) override;
+    IRCCD_EXPORT void onMe(Irccd &irccd, const MeEvent &event) override;
 
     /**
      * \copydoc Plugin::onMode
      */
-    IRCCD_EXPORT void onMode(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode) override;
+    IRCCD_EXPORT void onMode(Irccd &irccd, const ModeEvent &event) override;
 
     /**
      * \copydoc Plugin::onNames
      */
-    IRCCD_EXPORT void onNames(Irccd &irccd,
-                              const std::shared_ptr<Server> &server,
-                              const std::string &channel,
-                              const std::vector<std::string> &list) override;
+    IRCCD_EXPORT void onNames(Irccd &irccd, const NamesEvent &event) override;
 
     /**
      * \copydoc Plugin::onNick
      */
-    IRCCD_EXPORT void onNick(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick) override;
+    IRCCD_EXPORT void onNick(Irccd &irccd, const NickEvent &event) override;
 
     /**
      * \copydoc Plugin::onNotice
      */
-    IRCCD_EXPORT void onNotice(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice) override;
+    IRCCD_EXPORT void onNotice(Irccd &irccd, const NoticeEvent &event) override;
 
     /**
      * \copydoc Plugin::onPart
      */
-    IRCCD_EXPORT void onPart(Irccd &irccd,
-                             const std::shared_ptr<Server> &server,
-                             const std::string &origin,
-                             const std::string &channel,
-                             const std::string &reason) override;
+    IRCCD_EXPORT void onPart(Irccd &irccd, const PartEvent &event) override;
 
     /**
      * \copydoc Plugin::onQuery
      */
-    IRCCD_EXPORT void onQuery(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message) override;
+    IRCCD_EXPORT void onQuery(Irccd &irccd, const QueryEvent &event) override;
 
     /**
      * \copydoc Plugin::onQueryCommand
      */
-    IRCCD_EXPORT void onQueryCommand(Irccd &irccd,
-                                     const std::shared_ptr<Server> &server,
-                                     const std::string &origin,
-                                     const std::string &message) override;
+    IRCCD_EXPORT void onQueryCommand(Irccd &irccd, const QueryEvent &event) override;
 
     /**
      * \copydoc Plugin::onReload
@@ -209,11 +173,7 @@
     /**
      * \copydoc Plugin::onTopic
      */
-    IRCCD_EXPORT void onTopic(Irccd &irccd,
-                              const std::shared_ptr<Server> &server,
-                              const std::string &origin,
-                              const std::string &channel,
-                              const std::string &topic) override;
+    IRCCD_EXPORT void onTopic(Irccd &irccd, const TopicEvent &event) override;
 
     /**
      * \copydoc Plugin::onUnload
@@ -223,7 +183,7 @@
     /**
      * \copydoc Plugin::onWhois
      */
-    IRCCD_EXPORT void onWhois(Irccd &irccd, const std::shared_ptr<Server> &server, const ServerWhois &info) override;
+    IRCCD_EXPORT void onWhois(Irccd &irccd, const WhoisEvent &event) override;
 };
 
 } // !irccd
--- a/lib/irccd/plugin.hpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/plugin.hpp	Wed Jun 22 13:02:29 2016 +0200
@@ -34,14 +34,13 @@
 #include <unordered_map>
 #include <vector>
 
+#include "server.hpp"
 #include "sysconfig.hpp"
 #include "util.hpp"
 
 namespace irccd {
 
 class Irccd;
-class Server;
-class ServerWhois;
 
 /**
  * \brief Configuration map extract from config file.
@@ -208,7 +207,7 @@
      */
     virtual void setConfig(PluginConfig config)
     {
-        (void)config;
+        util::unused(config);
     }
 
     /**
@@ -228,7 +227,7 @@
      */
     virtual void setFormats(PluginFormats formats)
     {
-        (void)formats;
+        util::unused(formats);
     }
 
     /**
@@ -237,113 +236,77 @@
      * 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
+     * \param event the event
      */
-    virtual void onCommand(Irccd &irccd,
-                           const std::shared_ptr<Server> &server,
-                           const std::string &origin,
-                           const std::string &channel,
-                           const std::string &message)
+    virtual void onCommand(Irccd &irccd, const MessageEvent &event)
     {
-        util::unused(irccd, server, origin, channel, message);
+        util::unused(irccd, event);
     }
 
     /**
      * On successful connection.
      *
      * \param irccd the irccd instance
-     * \param server the server
+     * \param event the event
      */
-    virtual void onConnect(Irccd &irccd, const std::shared_ptr<Server> &server)
+    virtual void onConnect(Irccd &irccd, const ConnectEvent &event)
     {
-        util::unused(irccd, server);
+        util::unused(irccd, event);
     }
 
     /**
      * 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
+     * \param event the event
      */
-    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)
+    virtual void onChannelMode(Irccd &irccd, const ChannelModeEvent &event)
     {
-        util::unused(irccd, server, origin, channel, mode, arg);
+        util::unused(irccd, event);
     }
 
     /**
      * 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
+     * \param event the event
      */
-    virtual void onChannelNotice(Irccd &irccd,
-                                 const std::shared_ptr<Server> &server,
-                                 const std::string &origin,
-                                 const std::string &channel,
-                                 const std::string &notice)
+    virtual void onChannelNotice(Irccd &irccd, const ChannelNoticeEvent &event)
     {
-        util::unused(irccd, server, origin, channel, notice);
+        util::unused(irccd, event);
     }
 
     /**
      * On invitation.
      *
      * \param irccd the irccd instance
-     * \param server the server
-     * \param origin the user who invited you
-     * \param channel the channel
+     * \param event the event
      */
-    virtual void onInvite(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+    virtual void onInvite(Irccd &irccd, const InviteEvent &event)
     {
-        util::unused(irccd, server, origin, channel);
+        util::unused(irccd, event);
     }
 
     /**
      * On join.
      *
      * \param irccd the irccd instance
-     * \param server the server
-     * \param origin the user who joined
-     * \param channel the channel
+     * \param event the event
      */
-    virtual void onJoin(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel)
+    virtual void onJoin(Irccd &irccd, const JoinEvent &event)
     {
-        util::unused(irccd, server, origin, channel);
+        util::unused(irccd, event);
     }
 
     /**
      * 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
+     * \param event the event
      */
-    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)
+    virtual void onKick(Irccd &irccd, const KickEvent &event)
     {
-        util::unused(irccd, server, origin, channel, target, reason);
+        util::unused(irccd, event);
     }
 
     /**
@@ -360,138 +323,99 @@
      * 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
+     * \param event the event
      */
-    virtual void onMessage(Irccd &irccd, 
-                           const std::shared_ptr<Server> &server,
-                           const std::string &origin,
-                           const std::string &channel,
-                           const std::string &message)
+    virtual void onMessage(Irccd &irccd, const MessageEvent &event)
     {
-        util::unused(irccd, server, origin, channel, message);
+        util::unused(irccd, event);
     }
 
     /**
      * 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
+     * \param event the event
      */
-    virtual void onMe(Irccd &irccd, 
-                      const std::shared_ptr<Server> &server,
-                      const std::string &origin,
-                      const std::string &channel,
-                      const std::string &message)
+    virtual void onMe(Irccd &irccd, const MeEvent &event)
     {
-        util::unused(irccd, server, origin, channel, message);
+        util::unused(irccd, event);
     }
 
     /**
      * 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
+     * \param event the event
      */
-    virtual void onMode(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode)
+    virtual void onMode(Irccd &irccd, const ModeEvent &event)
     {
-        util::unused(irccd, server, origin, mode);
+        util::unused(irccd, event);
     }
 
     /**
      * On names listing.
      *
      * \param irccd the irccd instance
-     * \param server the server
-     * \param channel the channel
-     * \param list the list of nicknames
+     * \param event the event
      */
-    virtual void onNames(Irccd &irccd,
-                         const std::shared_ptr<Server> &server,
-                         const std::string &channel,
-                         const std::vector<std::string> &list)
+    virtual void onNames(Irccd &irccd, const NamesEvent &event)
     {
-        util::unused(irccd, server, channel, list);
+        util::unused(irccd, event);
     }
 
     /**
      * 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
+     * \param event the event
      */
-    virtual void onNick(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &nick)
+    virtual void onNick(Irccd &irccd, const NickEvent &event)
     {
-        util::unused(irccd, server, origin, nick);
+        util::unused(irccd, event);
     }
 
     /**
      * On user notice.
      *
      * \param irccd the irccd instance
-     * \param server the server
-     * \param origin the user who sent the notice
-     * \param notice the notice
+     * \param event the event
      */
-    virtual void onNotice(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &notice)
+    virtual void onNotice(Irccd &irccd, const NoticeEvent &event)
     {
-        util::unused(irccd, server, origin, notice);
+        util::unused(irccd, event);
     }
 
     /**
      * 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
+     * \param event the event
      */
-    virtual void onPart(Irccd &irccd, 
-                        const std::shared_ptr<Server> &server,
-                        const std::string &origin,
-                        const std::string &channel,
-                        const std::string &reason)
+    virtual void onPart(Irccd &irccd, const PartEvent &event)
     {
-        util::unused(irccd, server, origin, channel, reason);
+        util::unused(irccd, event);
     }
 
     /**
      * On user query.
      *
      * \param irccd the irccd instance
-     * \param server the server
-     * \param origin the user who sent the query
-     * \param message the message
+     * \param event the event
      */
-    virtual void onQuery(Irccd &irccd, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &message)
+    virtual void onQuery(Irccd &irccd, const QueryEvent &event)
     {
-        util::unused(irccd, server, origin, message);
+        util::unused(irccd, event);
     }
 
     /**
      * 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
+     * \param event the event
      */
-    virtual void onQueryCommand(Irccd &irccd,
-                                const std::shared_ptr<Server> &server,
-                                const std::string &origin,
-                                const std::string &message)
+    virtual void onQueryCommand(Irccd &irccd, const QueryEvent &event)
     {
-        util::unused(irccd, server, origin, message);
+        util::unused(irccd, event);
     }
 
     /**
@@ -508,18 +432,11 @@
      * 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
+     * \param event the event
      */
-    virtual void onTopic(Irccd &irccd, 
-                         const std::shared_ptr<Server> &server,
-                         const std::string &origin,
-                         const std::string &channel,
-                         const std::string &topic)
+    virtual void onTopic(Irccd &irccd, const TopicEvent &event)
     {
-        util::unused(irccd, server, origin, channel, topic);
+        util::unused(irccd, event);
     }
 
     /**
@@ -536,12 +453,11 @@
      * On whois information.
      *
      * \param irccd the irccd instance
-     * \param server the server
-     * \param info the info
+     * \param event the event
      */
-    virtual void onWhois(Irccd &irccd, const std::shared_ptr<Server> &server, const ServerWhois &info)
+    virtual void onWhois(Irccd &irccd, const WhoisEvent &event)
     {
-        util::unused(irccd, server, info);
+        util::unused(irccd, event);
     }
 };
 
--- a/lib/irccd/server.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/server.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -122,7 +122,7 @@
 
     // Don't forget to change state and notify.
     next(std::make_unique<state::Connected>());
-    onConnect();
+    onConnect(ConnectEvent{shared_from_this()});
 
     // Auto join listed channels.
     for (const ServerChannel &channel : m_settings.channels) {
@@ -133,22 +133,22 @@
 
 void Server::handleChannel(const char *orig, const char **params) noexcept
 {
-    onMessage(strify(orig), strify(params[0]), strify(params[1]));
+    onMessage(MessageEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
 void Server::handleChannelMode(const char *orig, const char **params) noexcept
 {
-    onChannelMode(strify(orig), strify(params[0]), strify(params[1]), strify(params[2]));
+    onChannelMode(ChannelModeEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1]), strify(params[2])});
 }
 
 void Server::handleChannelNotice(const char *orig, const char **params) noexcept
 {
-    onChannelNotice(strify(orig), strify(params[0]), strify(params[1]));
+    onChannelNotice(ChannelNoticeEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
 void Server::handleCtcpAction(const char *orig, const char **params) noexcept
 {
-    onMe(strify(orig), strify(params[0]), strify(params[1]));
+    onMe(MeEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
 void Server::handleInvite(const char *orig, const char **params) noexcept
@@ -162,12 +162,12 @@
      * uncommon to need it so it is passed as the last argument to be
      * optional in the plugin.
      */
-    onInvite(strify(orig), strify(params[1]), strify(params[0]));
+    onInvite(InviteEvent{shared_from_this(), strify(orig), strify(params[1]), strify(params[0])});
 }
 
 void Server::handleJoin(const char *orig, const char **params) noexcept
 {
-    onJoin(strify(orig), strify(params[0]));
+    onJoin(JoinEvent{shared_from_this(), strify(orig), strify(params[0])});
 }
 
 void Server::handleKick(const char *orig, const char **params) noexcept
@@ -176,12 +176,12 @@
     if ((m_settings.flags & ServerSettings::AutoRejoin) && isSelf(strify(params[1])))
         join(strify(params[0]));
 
-    onKick(strify(orig), strify(params[0]), strify(params[1]), strify(params[2]));
+    onKick(KickEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1]), strify(params[2])});
 }
 
 void Server::handleMode(const char *orig, const char **params) noexcept
 {
-    onMode(strify(orig), strify(params[1]));
+    onMode(ModeEvent{shared_from_this(), strify(orig), strify(params[1])});
 }
 
 void Server::handleNick(const char *orig, const char **params) noexcept
@@ -190,13 +190,13 @@
     if (isSelf(strify(orig)))
         m_identity.nickname = strify(params[0]);
 
-    onNick(strify(orig), strify(params[0]));
+    onNick(NickEvent{shared_from_this(), strify(orig), strify(params[0])});
 }
 
 void Server::handleNotice(const char *orig, const char **params) noexcept
 {
     // Like handleInvite, the notice provides the target nickname, we discard it.
-    onNotice(strify(orig), strify(params[1]));
+    onNotice(NoticeEvent{shared_from_this(), strify(orig), strify(params[1])});
 }
 
 void Server::handleNumeric(unsigned int event, const char **params, unsigned int c) noexcept
@@ -233,7 +233,7 @@
 
         auto it = m_cache.namesMap.find(params[1]);
         if (it != m_cache.namesMap.end()) {
-            onNames(params[1], it->second);
+            onNames(NamesEvent{shared_from_this(), params[1], std::vector<std::string>(it->second.begin(), it->second.end())});
 
             // Don't forget to remove the list.
             m_cache.namesMap.erase(it);
@@ -291,7 +291,7 @@
          */
         auto it = m_cache.whoisMap.find(params[1]);
         if (it != m_cache.whoisMap.end()) {
-            onWhois(it->second);
+            onWhois(WhoisEvent{shared_from_this(), it->second});
 
             // Don't forget to remove.
             m_cache.whoisMap.erase(it);
@@ -311,7 +311,7 @@
 
 void Server::handlePart(const char *orig, const char **params) noexcept
 {
-    onPart(strify(orig), strify(params[0]), strify(params[1]));
+    onPart(PartEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
 void Server::handlePing(const char *, const char **params) noexcept
@@ -325,12 +325,12 @@
 
 void Server::handleQuery(const char *orig, const char **params) noexcept
 {
-    onQuery(strify(orig), strify(params[1]));
+    onQuery(QueryEvent{shared_from_this(), strify(orig), strify(params[1])});
 }
 
 void Server::handleTopic(const char *orig, const char **params) noexcept
 {
-    onTopic(strify(orig), strify(params[0]), strify(params[1]));
+    onTopic(TopicEvent{shared_from_this(), strify(orig), strify(params[0]), strify(params[1])});
 }
 
 ServerChannel Server::splitChannel(const std::string &value)
--- a/lib/irccd/server.hpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/server.hpp	Wed Jun 22 13:02:29 2016 +0200
@@ -146,6 +146,173 @@
 };
 
 /**
+ * \brief Channel event.
+ */
+class ChannelModeEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+    std::string mode;                       //!< The mode.
+    std::string argument;                   //!< The mode argument (Optional).
+};
+
+/**
+ * \brief Channel notice event.
+ */
+class ChannelNoticeEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+    std::string message;                    //!< The notice message.
+};
+
+/**
+ * \brief Connection success event.
+ */
+class ConnectEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+};
+
+/**
+ * \brief Invite event.
+ */
+class InviteEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+    std::string nickname;                   //!< The nickname (you).
+};
+
+/**
+ * \brief Join event.
+ */
+class JoinEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+};
+
+/**
+ * \brief Kick event.
+ */
+class KickEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+    std::string target;                     //!< The target.
+    std::string reason;                     //!< The reason (Optional).
+};
+
+/**
+ * \brief Message event.
+ */
+class MessageEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+    std::string message;                    //!< The message.
+};
+
+/**
+ * \brief CTCP action event.
+ */
+class MeEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+    std::string message;                    //!< The message.
+};
+
+/**
+ * \brief Mode event.
+ */
+class ModeEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string mode;                       //!< The mode.
+};
+
+/**
+ * \brief Names listing event.
+ */
+class NamesEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string channel;                    //!< The channel.
+    std::vector<std::string> names;         //!< The names.
+};
+
+/**
+ * \brief Nick change event.
+ */
+class NickEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string nickname;                   //!< The new nickname.
+};
+
+/**
+ * \brief Notice event.
+ */
+class NoticeEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string message;                    //!< The message.
+};
+
+/**
+ * \brief Part event.
+ */
+class PartEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+    std::string reason;                     //!< The reason.
+};
+
+/**
+ * \brief Query event.
+ */
+class QueryEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string message;                    //!< The message.
+};
+
+/**
+ * \brief Topic event.
+ */
+class TopicEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    std::string origin;                     //!< The originator.
+    std::string channel;                    //!< The channel.
+    std::string topic;                      //!< The topic message.
+};
+
+/**
+ * \brief Whois event.
+ */
+class WhoisEvent {
+public:
+    std::shared_ptr<Server> server;         //!< The server.
+    ServerWhois whois;                      //!< The whois information.
+};
+
+/**
  * \brief The class that connect to a IRC server
  *
  * The server is a class that stores callbacks which will be called on IRC events. It is the lowest part of the connection to a server, it
@@ -158,7 +325,7 @@
  *
  * Note: the server is set in non blocking mode, commands are placed in a queue and sent when only when they are ready.
  */
-class Server {
+class Server : public std::enable_shared_from_this<Server> {
 public:
     /**
      * Bridge for libircclient.
@@ -170,27 +337,16 @@
      * ----------------------------------------------------------
      *
      * Triggered when someone changed the channel mode.
-     *
-     * Arguments:
-     * - the origin,
-     * - the channel,
-     * - the mode,
-     * - the optional mode argument.
      */
-    Signal<std::string, std::string, std::string, std::string> onChannelMode;
+    Signal<ChannelModeEvent> onChannelMode;
 
     /**
      * Signal: onChannelNotice
      * ----------------------------------------------------------
      *
      * Triggered when a notice has been sent on a channel.
-     *
-     * Arguments:
-     *   - the origin (the nickname who has sent the notice),
-     *   - the channel name,
-     *   - the notice message.
      */
-    Signal<std::string, std::string, std::string> onChannelNotice;
+    Signal<ChannelNoticeEvent> onChannelNotice;
 
     /**
      * Signal: onConnect
@@ -198,7 +354,7 @@
      *
      * Triggered when the server is successfully connected.
      */
-    Signal<> onConnect;
+    Signal<ConnectEvent> onConnect;
 
     /**
      * Signal: onDie
@@ -213,52 +369,32 @@
      * ----------------------------------------------------------
      *
      * Triggered when an invite has been sent to you (the bot).
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the channel,
-     *   - your nickname.
      */
-    Signal<std::string, std::string, std::string> onInvite;
+    Signal<InviteEvent> onInvite;
 
     /**
      * Signal: onJoin
      * ----------------------------------------------------------
      *
      * Triggered when a user has joined the channel, it also includes you.
-     *
-     * Arguments:
-     *   - the origin (may be you),
-     *   - the channel.
      */
-    Signal<std::string, std::string> onJoin;
+    Signal<JoinEvent> onJoin;
 
     /**
      * Signal: onKick
      * ----------------------------------------------------------
      *
      * Triggered when someone has been kicked from a channel.
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the channel,
-     *   - the target who has been kicked,
-     *   - the optional reason.
      */
-    Signal<std::string, std::string, std::string, std::string> onKick;
+    Signal<KickEvent> onKick;
 
     /**
      * ServerEvent: onMessage
      * ----------------------------------------------------------
      *
      * Triggered when a message on a channel has been sent.
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the channel,
-     *   - the message.
      */
-    Signal<std::string, std::string, std::string> onMessage;
+    Signal<MessageEvent> onMessage;
 
     /**
      * Signal: onMe
@@ -267,110 +403,72 @@
      * Triggered on a CTCP Action.
      *
      * This is both used in a channel and in a private message so the target may be a channel or your nickname.
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the target,
-     *   - the message.
      */
-    Signal<std::string, std::string, std::string> onMe;
+    Signal<MeEvent> onMe;
 
     /**
      * Signal: onMode
      * ----------------------------------------------------------
      *
      * Triggered when the server changed your user mode.
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the mode (e.g +i).
      */
-    Signal<std::string, std::string> onMode;
+    Signal<ModeEvent> onMode;
 
     /**
      * Signal: onNames
      * ----------------------------------------------------------
      *
      * Triggered when names listing has finished on a channel.
-     *
-     * Arguments:
-     *   - the channel,
-     *   - the ordered list of names.
      */
-    Signal<std::string, std::set<std::string>> onNames;
+    Signal<NamesEvent> onNames;
 
     /**
      * Signal: onNick
      * ----------------------------------------------------------
      *
      * Triggered when someone changed its nickname, it also includes you.
-     *
-     * Arguments:
-     *   - the old nickname (may be you),
-     *   - the new nickname.
      */
-    Signal<std::string, std::string> onNick;
+    Signal<NickEvent> onNick;
 
     /**
      * Signal: onNotice
      * ----------------------------------------------------------
      *
      * Triggered when someone has sent a notice to you.
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the notice message.
      */
-    Signal<std::string, std::string> onNotice;
+    Signal<NoticeEvent> onNotice;
 
     /**
      * Signal: onPart
      * ----------------------------------------------------------
      *
      * Triggered when someone has left the channel.
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the channel that the nickname has left,
-     *   - the optional reason.
      */
-    Signal<std::string, std::string, std::string> onPart;
+    Signal<PartEvent> onPart;
 
     /**
      * Signal: onQuery
      * ----------------------------------------------------------
      *
      * Triggered when someone has sent you a private message.
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the message.
      */
-    Signal<std::string, std::string> onQuery;
+    Signal<QueryEvent> onQuery;
 
     /**
      * Signal: onTopic
      * ----------------------------------------------------------
      *
      * Triggered when someone changed the channel topic.
-     *
-     * Arguments:
-     *   - the origin,
-     *   - the channel,
-     *   - the new topic.
      */
-    Signal<std::string, std::string, std::string> onTopic;
+    Signal<TopicEvent> onTopic;
 
     /**
      * Signal: onWhois
      * ----------------------------------------------------------
      *
      * Triggered when whois information has been received.
-     *
-     * Arguments:
-     *   - the whois object.
      */
-    Signal<ServerWhois> onWhois;
+    Signal<WhoisEvent> onWhois;
 
 private:
     // Identifier.
--- a/lib/irccd/service-server.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/service-server.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -73,481 +73,411 @@
     }
 };
 
-void ServerService::handleChannelMode(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string mode, std::string arg)
+void ServerService::handleChannelMode(const ChannelModeEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onChannelMode:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  channel: " << channel << "\n";
-    log::debug() << "  mode: " << mode << "\n";
-    log::debug() << "  argument: " << arg << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onChannelMode:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  channel: " << ev.channel << "\n";
+    log::debug() << "  mode: " << ev.mode << "\n";
+    log::debug() << "  argument: " << ev.argument << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onChannelMode"     },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "channel",    channel             },
-        { "mode",       mode                },
-        { "argument",   arg                 }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "mode",       ev.mode             },
+        { "argument",   ev.argument         }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, channel,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &) -> std::string {
             return "onChannelMode";
         },
         [=] (Plugin &plugin) {
-            plugin.onChannelMode(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(mode), std::move(arg));
+            plugin.onChannelMode(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleChannelNotice(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string message)
+void ServerService::handleChannelNotice(const ChannelNoticeEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onChannelNotice:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  channel: " << channel << "\n";
-    log::debug() << "  message: " << message << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onChannelNotice:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  channel: " << ev.channel << "\n";
+    log::debug() << "  message: " << ev.message << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onChannelNotice"   },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "channel",    channel             },
-        { "message",    message             }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "message",    ev.message          }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, channel,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &) -> std::string {
             return "onChannelNotice";
         },
         [=] (Plugin &plugin) {
-            plugin.onChannelNotice(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(message));
+            plugin.onChannelNotice(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleConnect(std::weak_ptr<Server> ptr)
+void ServerService::handleConnect(const ConnectEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onConnect" << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onConnect" << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onConnect"         },
-        { "server",     server->name()      }
+        { "server",     ev.server->name()   }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), /* origin */ "", /* channel */ "",
+    m_irccd.post(EventHandler{ev.server->name(), /* origin */ "", /* channel */ "",
         [=] (Plugin &) -> std::string {
             return "onConnect";
         },
         [=] (Plugin &plugin) {
-            plugin.onConnect(m_irccd, std::move(server));
+            plugin.onConnect(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleInvite(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string target)
+void ServerService::handleInvite(const InviteEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onInvite:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  channel: " << channel << "\n";
-    log::debug() << "  target: " << target << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onInvite:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  channel: " << ev.channel << "\n";
+    log::debug() << "  target: " << ev.nickname << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onInvite"          },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "channel",    channel             }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, channel,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &) -> std::string {
             return "onInvite";
         },
         [=] (Plugin &plugin) {
-            plugin.onInvite(m_irccd, std::move(server), std::move(origin), std::move(channel));
+            plugin.onInvite(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleJoin(std::weak_ptr<Server> ptr, std::string origin, std::string channel)
+void ServerService::handleJoin(const JoinEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onJoin:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  channel: " << channel << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onJoin:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  channel: " << ev.channel << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onJoin"            },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "channel",    channel             }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, channel,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &) -> std::string {
             return "onJoin";
         },
         [=] (Plugin &plugin) {
-            plugin.onJoin(m_irccd, std::move(server), std::move(origin), std::move(channel));
+            plugin.onJoin(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleKick(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string target, std::string reason)
+void ServerService::handleKick(const KickEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onKick:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  channel: " << channel << "\n";
-    log::debug() << "  target: " << target << "\n";
-    log::debug() << "  reason: " << reason << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onKick:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  channel: " << ev.channel << "\n";
+    log::debug() << "  target: " << ev.target << "\n";
+    log::debug() << "  reason: " << ev.reason << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onKick"            },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "channel",    channel             },
-        { "target",     target              },
-        { "reason",     reason              }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "target",     ev.target           },
+        { "reason",     ev.reason           }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, channel,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &) -> std::string {
             return "onKick";
         },
         [=] (Plugin &plugin) {
-            plugin.onKick(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(target), std::move(reason));
+            plugin.onKick(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleMessage(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string message)
+void ServerService::handleMessage(const MessageEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onMessage:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  channel: " << channel << "\n";
-    log::debug() << "  message: " << message << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onMessage:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  channel: " << ev.channel << "\n";
+    log::debug() << "  message: " << ev.message << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onMessage"         },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "channel",    channel             },
-        { "message",    message             }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "message",    ev.message          }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, channel,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &plugin) -> std::string {
-            return util::parseMessage(message, server->settings().command, plugin.name()).second == util::MessageType::Command ? "onCommand" : "onMessage";
+            return util::parseMessage(ev.message, ev.server->settings().command, plugin.name()).second == util::MessageType::Command ? "onCommand" : "onMessage";
         },
-        [=] (Plugin &plugin) {
-            util::MessagePair pack = util::parseMessage(message, server->settings().command, plugin.name());
+        [=] (Plugin &plugin) mutable {
+            auto copy = ev;
+            auto pack = util::parseMessage(copy.message, copy.server->settings().command, plugin.name());
+
+            copy.message = pack.first;
 
             if (pack.second == util::MessageType::Command)
-                plugin.onCommand(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(pack.first));
+                plugin.onCommand(m_irccd, copy);
             else
-                plugin.onMessage(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(pack.first));
+                plugin.onMessage(m_irccd, copy);
         }
     });
 }
 
-void ServerService::handleMe(std::weak_ptr<Server> ptr, std::string origin, std::string target, std::string message)
+void ServerService::handleMe(const MeEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onMe:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  target: " << target << "\n";
-    log::debug() << "  message: " << message << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onMe:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  target: " << ev.channel << "\n";
+    log::debug() << "  message: " << ev.message << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onMe"              },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "target",     target              },
-        { "message",    message             }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "target",     ev.channel          },
+        { "message",    ev.message          }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, target,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &) -> std::string {
             return "onMe";
         },
         [=] (Plugin &plugin) {
-            plugin.onMe(m_irccd, std::move(server), std::move(origin), std::move(target), std::move(message));
+            plugin.onMe(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleMode(std::weak_ptr<Server> ptr, std::string origin, std::string mode)
+void ServerService::handleMode(const ModeEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onMode\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  mode: " << mode << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onMode\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  mode: " << ev.mode << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onMode"            },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "mode",       mode                }
+        { "server",     ev.server->name()      },
+        { "origin",     ev.origin              },
+        { "mode",       ev.mode                }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, /* channel */ "",
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, /* channel */ "",
         [=] (Plugin &) -> std::string {
             return "onMode";
         },
         [=] (Plugin &plugin) {
-            plugin.onMode(m_irccd, std::move(server), std::move(origin), std::move(mode));
+            plugin.onMode(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleNames(std::weak_ptr<Server> ptr, std::string channel, std::set<std::string> nicknames)
+void ServerService::handleNames(const NamesEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
+    log::debug() << "server " << ev.server->name() << ": event onNames:\n";
+    log::debug() << "  channel: " << ev.channel << "\n";
+    log::debug() << "  names: " << util::join(ev.names.begin(), ev.names.end(), ", ") << std::endl;
 
-    if (!server)
-        return;
+    json::Value names = json::array();
 
-    log::debug() << "server " << server->name() << ": event onNames:\n";
-    log::debug() << "  channel: " << channel << "\n";
-    log::debug() << "  names: " << util::join(nicknames.begin(), nicknames.end(), ", ") << std::endl;
-
-    json::Value names(std::vector<json::Value>(nicknames.begin(), nicknames.end()));
+    for (const auto &v : ev.names)
+        names.append(v);
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onNames"           },
-        { "server",     server->name()      },
-        { "channel",    channel             },
+        { "server",     ev.server->name()   },
+        { "channel",    ev.channel          },
         { "names",      std::move(names)    }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), /* origin */ "", channel,
+    m_irccd.post(EventHandler{ev.server->name(), /* origin */ "", ev.channel,
         [=] (Plugin &) -> std::string {
             return "onNames";
         },
         [=] (Plugin &plugin) {
-            plugin.onNames(m_irccd, std::move(server), std::move(channel), std::vector<std::string>(nicknames.begin(), nicknames.end()));
+            plugin.onNames(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleNick(std::weak_ptr<Server> ptr, std::string origin, std::string nickname)
+void ServerService::handleNick(const NickEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onNick:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  nickname: " << nickname << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onNick:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  nickname: " << ev.nickname << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onNick"            },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "nickname",   nickname            }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "nickname",   ev.nickname         }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, /* channel */ "",
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, /* channel */ "",
         [=] (Plugin &) -> std::string {
             return "onNick";
         },
         [=] (Plugin &plugin) {
-            plugin.onNick(m_irccd, std::move(server), std::move(origin), std::move(nickname));
+            plugin.onNick(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleNotice(std::weak_ptr<Server> ptr, std::string origin, std::string message)
+void ServerService::handleNotice(const NoticeEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onNotice:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  message: " << message << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onNotice:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  message: " << ev.message << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onNotice"          },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "message",    message             }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "message",    ev.message          }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, /* channel */ "",
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, /* channel */ "",
         [=] (Plugin &) -> std::string {
             return "onNotice";
         },
         [=] (Plugin &plugin) {
-            plugin.onNotice(m_irccd, std::move(server), std::move(origin), std::move(message));
+            plugin.onNotice(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handlePart(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string reason)
+void ServerService::handlePart(const PartEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onPart:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  channel: " << channel << "\n";
-    log::debug() << "  reason: " << reason << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onPart:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  channel: " << ev.channel << "\n";
+    log::debug() << "  reason: " << ev.reason << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onPart"            },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "channel",    channel             },
-        { "reason",     reason              }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "reason",     ev.reason           }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, channel,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &) -> std::string {
             return "onPart";
         },
         [=] (Plugin &plugin) {
-            plugin.onPart(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(reason));
+            plugin.onPart(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleQuery(std::weak_ptr<Server> ptr, std::string origin, std::string message)
+void ServerService::handleQuery(const QueryEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onQuery:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  message: " << message << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onQuery:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  message: " << ev.message << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onQuery"           },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "message",    message             }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "message",    ev.message          }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, /* channel */ "",
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, /* channel */ "",
         [=] (Plugin &plugin) -> std::string {
-            return util::parseMessage(message, server->settings().command, plugin.name()).second == util::MessageType::Command ? "onQueryCommand" : "onQuery";
+            return util::parseMessage(ev.message, ev.server->settings().command, plugin.name()).second == util::MessageType::Command ? "onQueryCommand" : "onQuery";
         },
-        [=] (Plugin &plugin) {
-            util::MessagePair pack = util::parseMessage(message, server->settings().command, plugin.name());
+        [=] (Plugin &plugin) mutable {
+            auto copy = ev;
+            auto pack = util::parseMessage(copy.message, copy.server->settings().command, plugin.name());
+
+            copy.message = pack.first;
 
             if (pack.second == util::MessageType::Command)
-                plugin.onQueryCommand(m_irccd, std::move(server), std::move(origin), std::move(pack.first));
+                plugin.onQueryCommand(m_irccd, copy);
             else
-                plugin.onQuery(m_irccd, std::move(server), std::move(origin), std::move(pack.first));
+                plugin.onQuery(m_irccd, copy);
         }
     });
 }
 
-void ServerService::handleTopic(std::weak_ptr<Server> ptr, std::string origin, std::string channel, std::string topic)
+void ServerService::handleTopic(const TopicEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onTopic:\n";
-    log::debug() << "  origin: " << origin << "\n";
-    log::debug() << "  channel: " << channel << "\n";
-    log::debug() << "  topic: " << topic << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onTopic:\n";
+    log::debug() << "  origin: " << ev.origin << "\n";
+    log::debug() << "  channel: " << ev.channel << "\n";
+    log::debug() << "  topic: " << ev.topic << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
         { "event",      "onTopic"           },
-        { "server",     server->name()      },
-        { "origin",     origin              },
-        { "channel",    channel             },
-        { "topic",      topic               }
+        { "server",     ev.server->name()   },
+        { "origin",     ev.origin           },
+        { "channel",    ev.channel          },
+        { "topic",      ev.topic            }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), origin, channel,
+    m_irccd.post(EventHandler{ev.server->name(), ev.origin, ev.channel,
         [=] (Plugin &) -> std::string {
             return "onTopic";
         },
         [=] (Plugin &plugin) {
-            plugin.onTopic(m_irccd, std::move(server), std::move(origin), std::move(channel), std::move(topic));
+            plugin.onTopic(m_irccd, ev);
         }
     });
 }
 
-void ServerService::handleWhois(std::weak_ptr<Server> ptr, ServerWhois whois)
+void ServerService::handleWhois(const WhoisEvent &ev)
 {
-    std::shared_ptr<Server> server = ptr.lock();
-
-    if (!server)
-        return;
-
-    log::debug() << "server " << server->name() << ": event onWhois\n";
-    log::debug() << "  nickname: " << whois.nick << "\n";
-    log::debug() << "  username: " << whois.user << "\n";
-    log::debug() << "  host: " << whois.host << "\n";
-    log::debug() << "  realname: " << whois.realname << "\n";
-    log::debug() << "  channels: " << util::join(whois.channels.begin(), whois.channels.end()) << std::endl;
+    log::debug() << "server " << ev.server->name() << ": event onWhois\n";
+    log::debug() << "  nickname: " << ev.whois.nick << "\n";
+    log::debug() << "  username: " << ev.whois.user << "\n";
+    log::debug() << "  host: " << ev.whois.host << "\n";
+    log::debug() << "  realname: " << ev.whois.realname << "\n";
+    log::debug() << "  channels: " << util::join(ev.whois.channels.begin(), ev.whois.channels.end()) << std::endl;
 
     m_irccd.transportService().broadcast(json::object({
-        { "server",     server->name()      },
-        { "nickname",   whois.nick          },
-        { "username",   whois.user          },
-        { "host",       whois.host          },
-        { "realname",   whois.realname      }
+        { "event",      "onWhois"           },
+        { "server",     ev.server->name()   },
+        { "nickname",   ev.whois.nick       },
+        { "username",   ev.whois.user       },
+        { "host",       ev.whois.host       },
+        { "realname",   ev.whois.realname   }
     }).toJson(0));
 
-    m_irccd.post(EventHandler{server->name(), /* origin */ "", /* channel */ "",
+    m_irccd.post(EventHandler{ev.server->name(), /* origin */ "", /* channel */ "",
         [=] (Plugin &) -> std::string {
             return "onWhois";
         },
         [=] (Plugin &plugin) {
-            plugin.onWhois(m_irccd, std::move(server), std::move(whois));
+            plugin.onWhois(m_irccd, ev);
         }
     });
 }
@@ -586,22 +516,22 @@
 
     std::weak_ptr<Server> ptr(server);
 
-    server->onChannelMode.connect(std::bind(&ServerService::handleChannelMode, this, ptr, _1, _2, _3, _4));
-    server->onChannelNotice.connect(std::bind(&ServerService::handleChannelNotice, this, ptr, _1, _2, _3));
-    server->onConnect.connect(std::bind(&ServerService::handleConnect, this, ptr));
-    server->onInvite.connect(std::bind(&ServerService::handleInvite, this, ptr, _1, _2, _3));
-    server->onJoin.connect(std::bind(&ServerService::handleJoin, this, ptr, _1, _2));
-    server->onKick.connect(std::bind(&ServerService::handleKick, this, ptr, _1, _2, _3, _4));
-    server->onMessage.connect(std::bind(&ServerService::handleMessage, this, ptr, _1, _2, _3));
-    server->onMe.connect(std::bind(&ServerService::handleMe, this, ptr, _1, _2, _3));
-    server->onMode.connect(std::bind(&ServerService::handleMode, this, ptr, _1, _2));
-    server->onNames.connect(std::bind(&ServerService::handleNames, this, ptr, _1, _2));
-    server->onNick.connect(std::bind(&ServerService::handleNick, this, ptr, _1, _2));
-    server->onNotice.connect(std::bind(&ServerService::handleNotice, this, ptr, _1, _2));
-    server->onPart.connect(std::bind(&ServerService::handlePart, this, ptr, _1, _2, _3));
-    server->onQuery.connect(std::bind(&ServerService::handleQuery, this, ptr, _1, _2));
-    server->onTopic.connect(std::bind(&ServerService::handleTopic, this, ptr, _1, _2, _3));
-    server->onWhois.connect(std::bind(&ServerService::handleWhois, this, ptr, _1));
+    server->onChannelMode.connect(std::bind(&ServerService::handleChannelMode, this, _1));
+    server->onChannelNotice.connect(std::bind(&ServerService::handleChannelNotice, this, _1));
+    server->onConnect.connect(std::bind(&ServerService::handleConnect, this, _1));
+    server->onInvite.connect(std::bind(&ServerService::handleInvite, this, _1));
+    server->onJoin.connect(std::bind(&ServerService::handleJoin, this, _1));
+    server->onKick.connect(std::bind(&ServerService::handleKick, this, _1));
+    server->onMessage.connect(std::bind(&ServerService::handleMessage, this, _1));
+    server->onMe.connect(std::bind(&ServerService::handleMe, this, _1));
+    server->onMode.connect(std::bind(&ServerService::handleMode, this, _1));
+    server->onNames.connect(std::bind(&ServerService::handleNames, this, _1));
+    server->onNick.connect(std::bind(&ServerService::handleNick, this, _1));
+    server->onNotice.connect(std::bind(&ServerService::handleNotice, this, _1));
+    server->onPart.connect(std::bind(&ServerService::handlePart, this, _1));
+    server->onQuery.connect(std::bind(&ServerService::handleQuery, this, _1));
+    server->onTopic.connect(std::bind(&ServerService::handleTopic, this, _1));
+    server->onWhois.connect(std::bind(&ServerService::handleWhois, this, _1));
     server->onDie.connect([this, ptr] () {
         m_irccd.post([=] (Irccd &) {
             auto server = ptr.lock();
--- a/lib/irccd/service-server.hpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/lib/irccd/service-server.hpp	Wed Jun 22 13:02:29 2016 +0200
@@ -28,13 +28,12 @@
 #include <set>
 #include <string>
 
+#include "server.hpp"
 #include "service.hpp"
 
 namespace irccd {
 
 class Irccd;
-class Server;
-class ServerWhois;
 
 /**
  * \brief Manage IRC servers.
@@ -45,22 +44,22 @@
     Irccd &m_irccd;
     std::vector<std::shared_ptr<Server>> m_servers;
 
-    void handleChannelMode(std::weak_ptr<Server>, std::string, std::string, std::string, std::string);
-    void handleChannelNotice(std::weak_ptr<Server>, std::string, std::string, std::string);
-    void handleConnect(std::weak_ptr<Server>);
-    void handleInvite(std::weak_ptr<Server>, std::string, std::string, std::string);
-    void handleJoin(std::weak_ptr<Server>, std::string, std::string);
-    void handleKick(std::weak_ptr<Server>, std::string, std::string, std::string, std::string);
-    void handleMessage(std::weak_ptr<Server>, std::string, std::string, std::string);
-    void handleMe(std::weak_ptr<Server>, std::string, std::string, std::string);
-    void handleMode(std::weak_ptr<Server>, std::string, std::string);
-    void handleNames(std::weak_ptr<Server>, std::string, std::set<std::string>);
-    void handleNick(std::weak_ptr<Server>, std::string, std::string);
-    void handleNotice(std::weak_ptr<Server>, std::string, std::string);
-    void handlePart(std::weak_ptr<Server>, std::string, std::string, std::string);
-    void handleQuery(std::weak_ptr<Server>, std::string, std::string);
-    void handleTopic(std::weak_ptr<Server>, std::string, std::string, std::string);
-    void handleWhois(std::weak_ptr<Server>, ServerWhois);
+    void handleChannelMode(const ChannelModeEvent &);
+    void handleChannelNotice(const ChannelNoticeEvent &);
+    void handleConnect(const ConnectEvent &);
+    void handleInvite(const InviteEvent &);
+    void handleJoin(const JoinEvent &);
+    void handleKick(const KickEvent &);
+    void handleMessage(const MessageEvent &);
+    void handleMe(const MeEvent &);
+    void handleMode(const ModeEvent &);
+    void handleNames(const NamesEvent &);
+    void handleNick(const NickEvent &);
+    void handleNotice(const NoticeEvent &);
+    void handlePart(const PartEvent &);
+    void handleQuery(const QueryEvent &);
+    void handleTopic(const TopicEvent &);
+    void handleWhois(const WhoisEvent &);
 
 public:
     /**
--- a/tests/plugin-ask/main.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/tests/plugin-ask/main.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -71,7 +71,7 @@
 
     // Invoke the plugin 1000 times, it will be very unlucky to not have both answers in that amount of tries.
     for (int i = 0; i < 1000; ++i) {
-        m_plugin->onCommand(m_irccd, m_server, "tester", "#dummy", "");
+        m_plugin->onCommand(m_irccd, MessageEvent{m_server, "tester", "#dummy", ""});
 
         if (m_server->last() == "#dummy:tester, YES")
             yes = true;
--- a/tests/plugin-auth/main.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/tests/plugin-auth/main.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -79,21 +79,21 @@
 
 TEST_F(AuthTest, nickserv1)
 {
-    m_plugin->onConnect(m_irccd, m_nickserv1);
+    m_plugin->onConnect(m_irccd, ConnectEvent{m_nickserv1});
 
     ASSERT_EQ("NickServ:identify plopation", m_nickserv1->last());
 }
 
 TEST_F(AuthTest, nickserv2)
 {
-    m_plugin->onConnect(m_irccd, m_nickserv2);
+    m_plugin->onConnect(m_irccd, ConnectEvent{m_nickserv2});
 
     ASSERT_EQ("NickServ:identify jean something", m_nickserv2->last());
 }
 
 TEST_F(AuthTest, quakenet)
 {
-    m_plugin->onConnect(m_irccd, m_quakenet);
+    m_plugin->onConnect(m_irccd, ConnectEvent{m_quakenet});
 
     ASSERT_EQ("Q@CServe.quakenet.org:AUTH mario hello", m_quakenet->last());
 }
--- a/tests/plugin-hangman/main.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/tests/plugin-hangman/main.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -86,9 +86,9 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "s");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "s");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
 
     ASSERT_EQ("#hangman:asked=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s", m_server->last());
 }
@@ -97,17 +97,17 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "a");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "b");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "c");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "d");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "e");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "f");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "g");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "h");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "i");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "j");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "a"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "b"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "c"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "d"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "e"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "f"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "g"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "h"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "i"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "j"});
 
     ASSERT_EQ("#hangman:dead=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:sky", m_server->last());
 }
@@ -116,8 +116,8 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "s");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
 
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s _ _", m_server->last());
 }
@@ -126,7 +126,7 @@
 {
     load();
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
 
     ASSERT_EQ("#hangman:start=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:_ _ _", m_server->last());
 }
@@ -135,10 +135,10 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "s");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "k");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "y");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "k"});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "y"});
 
     ASSERT_EQ("#hangman:win=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:sky", m_server->last());
 }
@@ -147,8 +147,8 @@
 {
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "sky");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "sky"});
 
     ASSERT_EQ("#hangman:win=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:sky", m_server->last());
 }
@@ -157,8 +157,8 @@
 {
     load();
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "x");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "x"});
 
     ASSERT_EQ("#hangman:wrong-letter=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:x", m_server->last());
 }
@@ -167,8 +167,8 @@
 {
     load();
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "cheese");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "cheese"});
 
     ASSERT_EQ("#hangman:wrong-word=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:cheese", m_server->last());
 }
@@ -178,10 +178,10 @@
     // Disable collaborative mode.
     load({{ "collaborative", "false" }});
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "s");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s _ _", m_server->last());
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "k");
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "k"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s k _", m_server->last());
 }
 
@@ -190,12 +190,12 @@
     // Enable collaborative mode.
     load({{ "collaborative", "true" }});
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#hangman", "");
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "s");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "s"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:s _ _", m_server->last());
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#hangman", "k");
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", "k"});
     ASSERT_EQ("#hangman:wrong-player=hangman:!hangman:test:#hangman:jean!jean@localhost:jean:k", m_server->last());
-    m_plugin->onMessage(m_irccd, m_server, "francis!francis@localhost", "#hangman", "k");
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "francis!francis@localhost", "#hangman", "k"});
     ASSERT_EQ("#hangman:found=hangman:!hangman:test:#hangman:francis!francis@localhost:francis:s k _", m_server->last());
 }
 
--- a/tests/plugin-history/main.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/tests/plugin-history/main.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -84,7 +84,7 @@
 {
     load({{ "file", SOURCEDIR "/broken-conf.json" }});
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#history", "seen francis");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#history", "seen francis"});
     ASSERT_EQ("#history:error=history:!history:test:#history:jean!jean@localhost:jean", m_server->last());
 }
 
@@ -95,8 +95,8 @@
     remove(BINARYDIR "/seen.json");
     load({{ "file", BINARYDIR "/seen.json" }});
 
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#history", "hello");
-    m_plugin->onCommand(m_irccd, m_server, "destructor!dst@localhost", "#history", "seen jean");
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#history", "hello"});
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "destructor!dst@localhost", "#history", "seen jean"});
 
     ASSERT_TRUE(std::regex_match(m_server->last(), rule));
 }
@@ -108,8 +108,8 @@
     remove(BINARYDIR "/said.json");
     load({{ "file", BINARYDIR "/said.json" }});
 
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#history", "hello");
-    m_plugin->onCommand(m_irccd, m_server, "destructor!dst@localhost", "#history", "said jean");
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#history", "hello"});
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "destructor!dst@localhost", "#history", "said jean"});
 
     ASSERT_TRUE(std::regex_match(m_server->last(), rule));
 }
@@ -119,8 +119,8 @@
     remove(BINARYDIR "/unknown.json");
     load({{ "file", BINARYDIR "/unknown.json" }});
 
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#history", "hello");
-    m_plugin->onCommand(m_irccd, m_server, "destructor!dst@localhost", "#history", "seen nobody");
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#history", "hello"});
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "destructor!dst@localhost", "#history", "seen nobody"});
 
     ASSERT_EQ("#history:unknown=history:!history:test:#history:destructor!dst@localhost:destructor:nobody", m_server->last());
 }
--- a/tests/plugin-logger/main.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/tests/plugin-logger/main.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -88,7 +88,7 @@
 {
     load();
 
-    m_plugin->onChannelMode(m_irccd, m_server, "jean!jean@localhost", "#staff", "+o", "jean");
+    m_plugin->onChannelMode(m_irccd, ChannelModeEvent{m_server, "jean!jean@localhost", "#staff", "+o", "jean"});
 
     ASSERT_EQ("cmode=test:#staff:jean!jean@localhost:jean:+o:jean\n", last());
 }
@@ -97,7 +97,7 @@
 {
     load();
 
-    m_plugin->onChannelNotice(m_irccd, m_server, "jean!jean@localhost", "#staff", "bonjour!");
+    m_plugin->onChannelNotice(m_irccd, ChannelNoticeEvent{m_server, "jean!jean@localhost", "#staff", "bonjour!"});
 
     ASSERT_EQ("cnotice=test:#staff:jean!jean@localhost:jean:bonjour!\n", last());
 }
@@ -106,7 +106,7 @@
 {
     load();
 
-    m_plugin->onJoin(m_irccd, m_server, "jean!jean@localhost", "#staff");
+    m_plugin->onJoin(m_irccd, JoinEvent{m_server, "jean!jean@localhost", "#staff"});
 
     ASSERT_EQ("join=test:#staff:jean!jean@localhost:jean\n", last());
 }
@@ -115,7 +115,7 @@
 {
     load();
 
-    m_plugin->onKick(m_irccd, m_server, "jean!jean@localhost", "#staff", "badboy", "please do not flood");
+    m_plugin->onKick(m_irccd, KickEvent{m_server, "jean!jean@localhost", "#staff", "badboy", "please do not flood"});
 
     ASSERT_EQ("kick=test:#staff:jean!jean@localhost:jean:badboy:please do not flood\n", last());
 }
@@ -124,7 +124,7 @@
 {
     load();
 
-    m_plugin->onMe(m_irccd, m_server, "jean!jean@localhost", "#staff", "is drinking water");
+    m_plugin->onMe(m_irccd, MeEvent{m_server, "jean!jean@localhost", "#staff", "is drinking water"});
 
     ASSERT_EQ("me=test:#staff:jean!jean@localhost:jean:is drinking water\n", last());
 }
@@ -133,7 +133,7 @@
 {
     load();
 
-    m_plugin->onMessage(m_irccd, m_server, "jean!jean@localhost", "#staff", "hello guys");
+    m_plugin->onMessage(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "hello guys"});
 
     ASSERT_EQ("message=test:#staff:jean!jean@localhost:jean:hello guys\n", last());
 }
@@ -142,7 +142,7 @@
 {
     load();
 
-    m_plugin->onMode(m_irccd, m_server, "jean!jean@localhost", "+i");
+    m_plugin->onMode(m_irccd, ModeEvent{m_server, "jean!jean@localhost", "+i"});
 
     ASSERT_EQ("mode=test:jean!jean@localhost:jean:+i:\n", last());
 }
@@ -151,7 +151,7 @@
 {
     load();
 
-    m_plugin->onNotice(m_irccd, m_server, "jean!jean@localhost", "tu veux voir mon chat ?");
+    m_plugin->onNotice(m_irccd, NoticeEvent{m_server, "jean!jean@localhost", "tu veux voir mon chat ?"});
 
     ASSERT_EQ("notice=test:jean!jean@localhost:jean:tu veux voir mon chat ?\n", last());
 }
@@ -160,7 +160,7 @@
 {
     load();
 
-    m_plugin->onPart(m_irccd, m_server, "jean!jean@localhost", "#staff", "too noisy here");
+    m_plugin->onPart(m_irccd, PartEvent{m_server, "jean!jean@localhost", "#staff", "too noisy here"});
 
     ASSERT_EQ("part=test:#staff:jean!jean@localhost:jean:too noisy here\n", last());
 }
@@ -169,7 +169,7 @@
 {
     load();
 
-    m_plugin->onQuery(m_irccd, m_server, "jean!jean@localhost", "much irccd, wow");
+    m_plugin->onQuery(m_irccd, QueryEvent{m_server, "jean!jean@localhost", "much irccd, wow"});
 
     ASSERT_EQ("query=test:jean!jean@localhost:jean:much irccd, wow\n", last());
 }
@@ -178,7 +178,7 @@
 {
     load();
 
-    m_plugin->onTopic(m_irccd, m_server, "jean!jean@localhost", "#staff", "oh yeah yeaaaaaaaah");
+    m_plugin->onTopic(m_irccd, TopicEvent{m_server, "jean!jean@localhost", "#staff", "oh yeah yeaaaaaaaah"});
 
     ASSERT_EQ("topic=test:#staff:jean!jean@localhost:jean:oh yeah yeaaaaaaaah\n", last());
 }
--- a/tests/plugin-plugin/main.cpp	Tue Jun 21 21:56:04 2016 +0200
+++ b/tests/plugin-plugin/main.cpp	Wed Jun 22 13:02:29 2016 +0200
@@ -89,26 +89,26 @@
 
 TEST_F(PluginTest, formatUsage)
 {
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#staff", "");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", ""});
     ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", m_server->last());
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#staff", "fail");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "fail"});
     ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", m_server->last());
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#staff", "info");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "info"});
     ASSERT_EQ("#staff:usage=plugin:!plugin:test:#staff:jean!jean@localhost:jean", m_server->last());
 }
 
 TEST_F(PluginTest, formatInfo)
 {
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#staff", "info fake");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "info fake"});
 
     ASSERT_EQ("#staff:info=plugin:!plugin:test:#staff:jean!jean@localhost:jean:jean:BEER:fake:Fake White Beer 2000:0.0.0.0.0.1", m_server->last());
 }
 
 TEST_F(PluginTest, formatNotFound)
 {
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#staff", "info doesnotexistsihope");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "info doesnotexistsihope"});
 
     ASSERT_EQ("#staff:not-found=plugin:!plugin:test:#staff:jean!jean@localhost:jean:doesnotexistsihope", m_server->last());
 }
@@ -118,7 +118,7 @@
     for (int i = 0; i < 100; ++i)
         m_ps.add(std::make_shared<Plugin>("plugin-n-{}"_format(i), ""));
 
-    m_plugin->onCommand(m_irccd, m_server, "jean!jean@localhost", "#staff", "list");
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#staff", "list"});
 
     ASSERT_EQ("#staff:too-long=plugin:!plugin:test:#staff:jean!jean@localhost:jean", m_server->last());
 }