changeset 986:583d9f83e9f5

irccd: bring back Javascript plugins While here, fix various small issues.
author David Demelier <markand@malikania.fr>
date Wed, 10 Feb 2021 13:20:39 +0100
parents 6da542806ed3
children 685b85367c8e
files CMakeLists.txt cmake/IrccdDefinePlugin.cmake irccd/jsapi-util.c lib/irccd/irccd.c lib/irccd/server.c lib/irccd/subst.c plugins/CMakeLists.txt plugins/ask/CMakeLists.txt plugins/auth/CMakeLists.txt plugins/hangman/CMakeLists.txt plugins/history/CMakeLists.txt plugins/joke/CMakeLists.txt plugins/logger/CMakeLists.txt plugins/logger/logger.js plugins/plugin/CMakeLists.txt plugins/roulette/CMakeLists.txt plugins/tictactoe/CMakeLists.txt
diffstat 17 files changed, 378 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Tue Feb 09 22:42:05 2021 +0100
+++ b/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -37,6 +37,8 @@
 
 include(GNUInstallDirs)
 
+include(cmake/IrccdDefinePlugin.cmake)
+
 find_package(FLEX REQUIRED)
 find_package(BISON REQUIRED)
 
@@ -54,6 +56,7 @@
 add_subdirectory(lib)
 add_subdirectory(irccd)
 add_subdirectory(irccdctl)
+add_subdirectory(plugins)
 
 if (IRCCD_WITH_TESTS)
 	enable_testing()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/IrccdDefinePlugin.cmake	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,52 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+function(irccd_define_js_plugin)
+	set(options "")
+	set(oneValueArgs NAME MAN)
+	set(multiValueArgs SCRIPT)
+
+	cmake_parse_arguments(PLG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+	if (NOT PLG_NAME)
+		message(FATAL_ERROR "Missing NAME argument")
+	elseif (NOT PLG_SCRIPT)
+		message(FATAL_ERROR "Missing SCRIPT argument")
+	endif ()
+
+	# Install script.
+	get_filename_component(basename ${PLG_SCRIPT} NAME)
+	configure_file(${PLG_SCRIPT} ${CMAKE_CURRENT_BINARY_DIR}/${basename})
+
+	install(
+		FILES ${CMAKE_CURRENT_BINARY_DIR}/${basename}
+		DESTINATION ${CMAKE_INSTALL_LIBDIR}/irccd
+	)
+
+	# Install manual page.
+	if (PLG_MAN)
+		get_filename_component(basename ${PLG_MAN} NAME)
+		configure_file(${PLG_MAN} ${CMAKE_CURRENT_BINARY_DIR}/${basename})
+
+		install(
+			FILES ${CMAKE_CURRENT_BINARY_DIR}/${basename}
+			DESTINATION ${CMAKE_INSTALL_MANDIR}/man7
+			RENAME irccd-plugin-${basename}
+		)
+	endif ()
+endfunction()
--- a/irccd/jsapi-util.c	Tue Feb 09 22:42:05 2021 +0100
+++ b/irccd/jsapi-util.c	Wed Feb 10 13:20:39 2021 +0100
@@ -38,6 +38,17 @@
 
 TAILQ_HEAD(stringlist, string);
 
+static inline void
+subspack_finish(struct subspack *subst)
+{
+	for (size_t i = 0; i < subst->subst.keywordsz; ++i) {
+		free((char *)subst->kw[i].key);
+		free((char *)subst->kw[i].value);
+	}
+
+	free(subst->kw);
+}
+
 /*
  * Read parameters for Irccd.Util.format function, the object is defined as
  * following:
@@ -61,6 +72,11 @@
 	duk_enum(ctx, index, 0);
 
 	while (duk_next(ctx, -1, 1)) {
+		if (!duk_is_string(ctx, -2)) {
+			subspack_finish(pkg);
+			(void)duk_error(ctx, DUK_ERR_TYPE_ERROR, "keyword name must be a string");
+		}
+
 		if (strcmp(duk_get_string(ctx, -2), "date") == 0) {
 			pkg->subst.time = duk_get_number(ctx, -1);
 			continue;
@@ -69,9 +85,9 @@
 		pkg->kw = irc_util_reallocarray(pkg->kw, ++pkg->subst.keywordsz,
 		    sizeof (*pkg->kw));
 		pkg->kw[pkg->subst.keywordsz - 1].key =
-		    irc_util_strdup(duk_opt_string(ctx, -2, ""));
+		    irc_util_strdup(duk_get_string_default(ctx, -2, ""));
 		pkg->kw[pkg->subst.keywordsz - 1].value =
-		    irc_util_strdup(duk_opt_string(ctx, -1, ""));
+		    irc_util_strdup(duk_get_string_default(ctx, -1, ""));
 
 		duk_pop_n(ctx, 2);
 	}
@@ -83,17 +99,6 @@
 	pkg->subst.keywords = pkg->kw;
 }
 
-static inline void
-subspack_finish(struct subspack *subst)
-{
-	for (size_t i = 0; i < subst->subst.keywordsz; ++i) {
-		free((char *)subst->kw[i].key);
-		free((char *)subst->kw[i].value);
-	}
-
-	free(subst->kw);
-}
-
 static struct string *
 string_new(const char *v)
 {
--- a/lib/irccd/irccd.c	Tue Feb 09 22:42:05 2021 +0100
+++ b/lib/irccd/irccd.c	Wed Feb 10 13:20:39 2021 +0100
@@ -355,11 +355,14 @@
 		irc_log_info("irccd: opening plugin %s", name);
 
 	SLIST_FOREACH(ldr, &irc.plugin_loaders, link) {
+		if (p)
+			break;
+
 		if (path) {
 			if (!is_extension_valid(ldr, path))
 				continue;
-			if ((p = open_plugin(ldr, name, path)))
-				break;
+	
+			p = open_plugin(ldr, name, path);
 		} else {
 			/* Copy the paths to tokenize it. */
 			strlcpy(buf, ldr->paths, sizeof (buf));
@@ -409,10 +412,9 @@
 	if (!(p = irc_bot_plugin_get(name)))
 		return;
 
+	LIST_REMOVE(p, link);
 	irc_plugin_unload(p);
 	irc_plugin_finish(p);
-
-	LIST_REMOVE(p, link);
 }
 
 void
--- a/lib/irccd/server.c	Tue Feb 09 22:42:05 2021 +0100
+++ b/lib/irccd/server.c	Wed Feb 10 13:20:39 2021 +0100
@@ -300,7 +300,7 @@
 handle_invite(struct irc_server *s, struct irc_event *ev, struct irc_conn_msg *msg)
 {
 	ev->type = IRC_EVENT_INVITE;
-	ev->invite.origin = strdup(msg->args[0]);
+	ev->invite.origin = strdup(msg->prefix);
 	ev->invite.channel = strdup(msg->args[1]);
 
 	if (s->flags & IRC_SERVER_FLAGS_JOIN_INVITE) {
@@ -795,6 +795,11 @@
 	char buf[IRC_BUF_LEN];
 	va_list ap;
 
+	if (s->state != IRC_SERVER_STATE_CONNECTED) {
+		errno = ENOTCONN;
+		return -1;
+	}
+
 	va_start(ap, fmt);
 	vsnprintf(buf, sizeof (buf), fmt, ap);
 	va_end(ap);
@@ -972,8 +977,10 @@
 
 	for (size_t i = 0; i < IRC_UTIL_SIZE(s->params.prefixes); ++i) {
 		if (**nick == s->params.prefixes[i].token) {
-			*mode = s->params.prefixes[i].mode;
-			*prefix = s->params.prefixes[i].token;
+			if (mode)
+				*mode = s->params.prefixes[i].mode;
+			if (prefix)
+				*prefix = s->params.prefixes[i].token;
 			*nick += 1;
 			break;
 		}
--- a/lib/irccd/subst.c	Tue Feb 09 22:42:05 2021 +0100
+++ b/lib/irccd/subst.c	Wed Feb 10 13:20:39 2021 +0100
@@ -24,6 +24,7 @@
 #include <string.h>
 
 #include "subst.h"
+#include "util.h"
 
 struct pair {
 	const char *key;
@@ -171,12 +172,7 @@
 static int
 subst_date(char *out, size_t outsz, const char *input, const struct irc_subst *subst)
 {
-	struct tm *tm;
-
-	if (!(subst->flags & IRC_SUBST_DATE))
-		return 0;
-
-	tm = localtime(&subst->time);
+	struct tm *tm = tm = localtime(&subst->time);
 
 	if (strftime(out, outsz, input, tm) == 0) {
 		errno = ENOMEM;
@@ -403,21 +399,33 @@
 }
 
 ssize_t
-irc_subst(char *out, size_t outsz, const char *input, const struct irc_subst *subst)
+irc_subst(char *out, size_t outsz, const char *in, const struct irc_subst *subst)
 {
+	assert(in);
 	assert(out);
 	assert(subst);
 
-	char *o = out;
+	char *o = out, *inalloc = NULL;
 
 	if (!outsz)
 		return 0;
 
-	/* Always start with the date first. */
-	if (subst_date(out, outsz, input, subst) < 0)
-		goto err;
+	/*
+	 * Always start with the date. To do that, we need to update the input
+	 * to transform the strftime tokens. Then we use that new string as
+	 * input. Since the final size must not exceed outsz, we use this as
+	 * temporary buffer.
+	 */
+	if (subst->flags & IRC_SUBST_DATE) {
+		inalloc = irc_util_calloc(1, outsz + 1);
 
-	for (const char *i = input; *i && outsz; ) {
+		if (subst_date(inalloc, outsz, in, subst) < 0)
+			goto err;
+
+		in = inalloc;
+	}
+
+	for (const char *i = in; *i && outsz; ) {
 		/*
 		 * Check if this is a reserved character, if it isn't go to the next character to
 		 * see if it's valid otherwise we print it as last token.
@@ -465,11 +473,13 @@
 		goto err;
 	}
 
+	free(inalloc);
 	*o = '\0';
 
 	return o - out;
 
 err:
+	free(inalloc);
 	out[0] = '\0';
 
 	return -1;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,29 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+if (IRCCD_WITH_JS)
+	add_subdirectory(ask)
+	add_subdirectory(auth)
+	add_subdirectory(hangman)
+	add_subdirectory(history)
+	add_subdirectory(joke)
+	add_subdirectory(logger)
+	add_subdirectory(plugin)
+	add_subdirectory(roulette)
+	add_subdirectory(tictactoe)
+endif ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/ask/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(ask)
+
+irccd_define_js_plugin(
+	NAME ask
+	SCRIPT ${ask_SOURCE_DIR}/ask.js
+	MAN ${ask_SOURCE_DIR}/ask.7
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/auth/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(auth)
+
+irccd_define_js_plugin(
+	NAME auth
+	SCRIPT ${auth_SOURCE_DIR}/auth.js
+	MAN ${auth_SOURCE_DIR}/auth.7
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/hangman/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(hangman)
+
+irccd_define_js_plugin(
+	NAME hangman
+	SCRIPT ${hangman_SOURCE_DIR}/hangman.js
+	MAN ${hangman_SOURCE_DIR}/hangman.7
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/history/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(history)
+
+irccd_define_js_plugin(
+	NAME history
+	SCRIPT ${history_SOURCE_DIR}/history.js
+	MAN ${history_SOURCE_DIR}/history.7
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/joke/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(joke)
+
+irccd_define_js_plugin(
+	NAME joke
+	SCRIPT ${joke_SOURCE_DIR}/joke.js
+	MAN ${joke_SOURCE_DIR}/joke.7
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/logger/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(logger)
+
+irccd_define_js_plugin(
+	NAME logger
+	SCRIPT ${logger_SOURCE_DIR}/logger.js
+	MAN ${logger_SOURCE_DIR}/logger.7
+)
--- a/plugins/logger/logger.js	Tue Feb 09 22:42:05 2021 +0100
+++ b/plugins/logger/logger.js	Wed Feb 10 13:20:39 2021 +0100
@@ -40,7 +40,8 @@
 	"kick":         "%H:%M:%S :: #{target} has been kicked by #{nickname} [reason: #{reason}]",
 	"me":           "%H:%M:%S * #{nickname} #{message}",
 	"message":      "%H:%M:%S #{nickname}: #{message}",
-	"mode":         "%H:%M:%S :: #{nickname} set mode #{mode} to #{arg}",
+	"invite":       "%H:%M:%S #{nickname} invited you on #{channel}",
+	"mode":         "%H:%M:%S :: #{nickname} set mode #{channel} #{mode} #{limit} #{user} #{mask}",
 	"notice":       "%H:%M:%S [notice] #{channel} (#{nickname}) #{message}",
 	"part":         "%H:%M:%S << #{nickname} left #{channel} [#{reason}]",
 	"query":        "%H:%M:%S #{nickname}: #{message}",
@@ -109,8 +110,8 @@
 	channel = channel.toLowerCase();
 
 	write("kick", keywords(server, channel, origin, {
-		"target":   target,
-		"reason":   reason
+		"target":       target,
+		"reason":       reason
 	}));
 }
 
@@ -120,7 +121,7 @@
 	channel = channel.toLowerCase();
 
 	write("me", keywords(server, channel, origin, {
-		"message":  message,
+		"message": message,
 	}));
 }
 
@@ -130,7 +131,7 @@
 	channel = channel.toLowerCase();
 
 	write("message", keywords(server, channel, origin, {
-		"message":  message,
+		"message": message,
 	}));
 }
 
@@ -139,10 +140,10 @@
 	origin = origin.toLowerCase();
 
 	write("mode", keywords(server, channel, origin, {
-		"mode":	 mode,
-		"limit":	limit,
-		"user":	 user,
-		"mask":	 mask
+		"mode":         mode,
+		"limit":        limit,
+		"user":         user,
+		"mask":         mask
 	}));
 }
 
@@ -156,7 +157,7 @@
 	origin = origin.toLowerCase();
 
 	write("notice", keywords(server, channel, origin, {
-		"message":  notice,
+		"message": notice,
 	}));
 }
 
@@ -166,7 +167,7 @@
 	channel = channel.toLowerCase();
 
 	write("part", keywords(server, channel, origin, {
-		"reason":   reason,
+		"reason": reason,
 	}));
 }
 
@@ -176,6 +177,6 @@
 	channel = channel.toLowerCase();
 
 	write("topic", keywords(server, channel, origin, {
-		"topic":	topic
+		"topic": topic
 	}));
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/plugin/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(plugin)
+
+irccd_define_js_plugin(
+	NAME plugin
+	SCRIPT ${plugin_SOURCE_DIR}/plugin.js
+	MAN ${plugin_SOURCE_DIR}/plugin.7
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/roulette/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(roulette)
+
+irccd_define_js_plugin(
+	NAME roulette
+	SCRIPT ${roulette_SOURCE_DIR}/roulette.js
+	MAN ${roulette_SOURCE_DIR}/roulette.7
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/tictactoe/CMakeLists.txt	Wed Feb 10 13:20:39 2021 +0100
@@ -0,0 +1,25 @@
+#
+# CMakeLists.txt -- CMake build for irccd
+#
+# Copyright (c) 2013-2021 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+project(tictactoe)
+
+irccd_define_js_plugin(
+	NAME tictactoe
+	SCRIPT ${tictactoe_SOURCE_DIR}/tictactoe.js
+	MAN ${tictactoe_SOURCE_DIR}/tictactoe.7
+)