Mercurial > irccd
changeset 95:1125d90b3b44
Misc: switch to .hpp, #477
line wrap: on
line diff
--- a/cmake/IrccdSystem.cmake Tue Apr 19 10:17:52 2016 +0200 +++ b/cmake/IrccdSystem.cmake Wed Apr 20 19:45:00 2016 +0200 @@ -253,19 +253,19 @@ file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/irccd) configure_file( - ${CMAKE_CURRENT_LIST_DIR}/internal/sysconfig.h.in - ${CMAKE_BINARY_DIR}/irccd/sysconfig.h + ${CMAKE_CURRENT_LIST_DIR}/internal/sysconfig.hpp.in + ${CMAKE_BINARY_DIR}/irccd/sysconfig.hpp ) install( - FILES ${CMAKE_BINARY_DIR}/irccd/sysconfig.h + FILES ${CMAKE_BINARY_DIR}/irccd/sysconfig.hpp DESTINATION include/irccd ) # Also copy to fakedir if possible if (IRCCD_RELOCATABLE) file( - COPY ${CMAKE_BINARY_DIR}/irccd/sysconfig.h + COPY ${CMAKE_BINARY_DIR}/irccd/sysconfig.hpp DESTINATION ${IRCCD_FAKEDIR}/include/irccd ) endif ()
--- a/cmake/internal/sysconfig.h.in Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * sysconfig.h -- configuration for irccd - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_SYSCONFIG_H -#define IRCCD_SYSCONFIG_H - -/* - * Fix annoying "Please include winsock2.h before windows.h" - */ -#if defined(_WIN32) -# include <winsock2.h> -# include <windows.h> -#endif - -/* - * Auto generated from CMake. - * ------------------------------------------------------------------ - */ - -#define PREFIX "@CMAKE_INSTALL_PREFIX@" - -#define IRCCD_VERSION_MAJOR @IRCCD_VERSION_MAJOR@ -#define IRCCD_VERSION_MINOR @IRCCD_VERSION_MINOR@ -#define IRCCD_VERSION_PATCH @IRCCD_VERSION_PATCH@ - -#cmakedefine IRCCD_RELOCATABLE - -/* - * System identification. - * ------------------------------------------------------------------ - */ - -#cmakedefine IRCCD_SYSTEM_WINDOWS -#cmakedefine IRCCD_SYSTEM_MAC -#cmakedefine IRCCD_SYSTEM_FREEBSD -#cmakedefine IRCCD_SYSTEM_NETBSD -#cmakedefine IRCCD_SYSTEM_OPENBSD -#cmakedefine IRCCD_SYSTEM_LINUX -#cmakedefine IRCCD_SYSTEM_UNKNOWN - -/* - * User definable options. - * ------------------------------------------------------------------ - */ - -#define WITH_BINDIR "@WITH_BINDIR@" -#define WITH_DATADIR "@WITH_DATADIR@" -#define WITH_CONFDIR "@WITH_CONFDIR@" -#define WITH_PLUGINDIR "@WITH_PLUGINDIR@" -#define WITH_CACHEDIR "@WITH_CACHEDIR@" - -#cmakedefine WITH_JS -#cmakedefine WITH_SSL - -/* - * Platform checks. - * ------------------------------------------------------------------ - */ - -#cmakedefine HAVE_ACCESS -#cmakedefine HAVE_DAEMON -#cmakedefine HAVE_GETPID -#cmakedefine HAVE_POPEN -#cmakedefine HAVE_SETGID -#cmakedefine HAVE_SETPROGNAME -#cmakedefine HAVE_SETUID -#cmakedefine HAVE_STD_PUT_TIME -#cmakedefine HAVE_STAT -#cmakedefine HAVE_STAT_ST_ATIME -#cmakedefine HAVE_STAT_ST_BLKSIZE -#cmakedefine HAVE_STAT_ST_BLOCKS -#cmakedefine HAVE_STAT_ST_CTIME -#cmakedefine HAVE_STAT_ST_DEV -#cmakedefine HAVE_STAT_ST_GID -#cmakedefine HAVE_STAT_ST_INO -#cmakedefine HAVE_STAT_ST_MODE -#cmakedefine HAVE_STAT_ST_MTIME -#cmakedefine HAVE_STAT_ST_NLINK -#cmakedefine HAVE_STAT_ST_RDEV -#cmakedefine HAVE_STAT_ST_SIZE -#cmakedefine HAVE_STAT_ST_UID -#cmakedefine HAVE_SYSLOG - -#endif // !IRCCD_SYSCONFIG_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/internal/sysconfig.hpp.in Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,99 @@ +/* + * sysconfig.h -- configuration for irccd + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SYSCONFIG_H +#define IRCCD_SYSCONFIG_H + +/* + * Fix annoying "Please include winsock2.h before windows.h" + */ +#if defined(_WIN32) +# include <winsock2.h> +# include <windows.h> +#endif + +/* + * Auto generated from CMake. + * ------------------------------------------------------------------ + */ + +#define PREFIX "@CMAKE_INSTALL_PREFIX@" + +#define IRCCD_VERSION_MAJOR @IRCCD_VERSION_MAJOR@ +#define IRCCD_VERSION_MINOR @IRCCD_VERSION_MINOR@ +#define IRCCD_VERSION_PATCH @IRCCD_VERSION_PATCH@ + +#cmakedefine IRCCD_RELOCATABLE + +/* + * System identification. + * ------------------------------------------------------------------ + */ + +#cmakedefine IRCCD_SYSTEM_WINDOWS +#cmakedefine IRCCD_SYSTEM_MAC +#cmakedefine IRCCD_SYSTEM_FREEBSD +#cmakedefine IRCCD_SYSTEM_NETBSD +#cmakedefine IRCCD_SYSTEM_OPENBSD +#cmakedefine IRCCD_SYSTEM_LINUX +#cmakedefine IRCCD_SYSTEM_UNKNOWN + +/* + * User definable options. + * ------------------------------------------------------------------ + */ + +#define WITH_BINDIR "@WITH_BINDIR@" +#define WITH_DATADIR "@WITH_DATADIR@" +#define WITH_CONFDIR "@WITH_CONFDIR@" +#define WITH_PLUGINDIR "@WITH_PLUGINDIR@" +#define WITH_CACHEDIR "@WITH_CACHEDIR@" + +#cmakedefine WITH_JS +#cmakedefine WITH_SSL + +/* + * Platform checks. + * ------------------------------------------------------------------ + */ + +#cmakedefine HAVE_ACCESS +#cmakedefine HAVE_DAEMON +#cmakedefine HAVE_GETPID +#cmakedefine HAVE_POPEN +#cmakedefine HAVE_SETGID +#cmakedefine HAVE_SETPROGNAME +#cmakedefine HAVE_SETUID +#cmakedefine HAVE_STD_PUT_TIME +#cmakedefine HAVE_STAT +#cmakedefine HAVE_STAT_ST_ATIME +#cmakedefine HAVE_STAT_ST_BLKSIZE +#cmakedefine HAVE_STAT_ST_BLOCKS +#cmakedefine HAVE_STAT_ST_CTIME +#cmakedefine HAVE_STAT_ST_DEV +#cmakedefine HAVE_STAT_ST_GID +#cmakedefine HAVE_STAT_ST_INO +#cmakedefine HAVE_STAT_ST_MODE +#cmakedefine HAVE_STAT_ST_MTIME +#cmakedefine HAVE_STAT_ST_NLINK +#cmakedefine HAVE_STAT_ST_RDEV +#cmakedefine HAVE_STAT_ST_SIZE +#cmakedefine HAVE_STAT_ST_UID +#cmakedefine HAVE_SYSLOG + +#endif // !IRCCD_SYSCONFIG_H
--- a/doc/procs/60.new-command.md Tue Apr 19 10:17:52 2016 +0200 +++ b/doc/procs/60.new-command.md Wed Apr 20 19:45:00 2016 +0200 @@ -30,7 +30,7 @@ Inherit from `TransportCommand` and override the `exec` function. - #include "transport-command.h" + #include "transport-command.hpp" namespace irccd { @@ -57,7 +57,7 @@ Inherit from `Command` and override both `usage` and `exec` functions. - #include "command.h" + #include "command.hpp" namespace irccd {
--- a/irccd/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/irccd/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,15 +18,15 @@ #include <csignal> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include <irccd/logger.h> -#include <irccd/options.h> -#include <irccd/path.h> -#include <irccd/system.h> +#include <irccd/logger.hpp> +#include <irccd/options.hpp> +#include <irccd/path.hpp> +#include <irccd/system.hpp> -#include <irccd/config.h> -#include <irccd/irccd.h> +#include <irccd/config.hpp> +#include <irccd/irccd.hpp> using namespace irccd;
--- a/irccdctl/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/irccdctl/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,9 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/irccdctl.h> -#include <irccd/logger.h> -#include <irccd/path.h> +#include <irccd/irccdctl.hpp> +#include <irccd/logger.hpp> +#include <irccd/path.hpp> using namespace irccd;
--- a/lib/irccd/CMakeSources.cmake Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/CMakeSources.cmake Wed Apr 20 19:45:00 2016 +0200 @@ -3,68 +3,68 @@ ${COMMAND_HEADERS} ${JS_HEADERS} ${PRIVATE_HEADERS} - ${CMAKE_CURRENT_LIST_DIR}/alias.h - ${CMAKE_CURRENT_LIST_DIR}/application.h - ${CMAKE_CURRENT_LIST_DIR}/connection.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-help.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-info.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-list.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-load.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-reload.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-unload.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-cmode.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-cnotice.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-connect.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-disconnect.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-info.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-invite.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-join.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-kick.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-list.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-me.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-message.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-mode.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-nick.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-notice.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-part.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-reconnect.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-server-topic.h - ${CMAKE_CURRENT_LIST_DIR}/cmd-watch.h - ${CMAKE_CURRENT_LIST_DIR}/command.h - ${CMAKE_CURRENT_LIST_DIR}/config.h - ${CMAKE_CURRENT_LIST_DIR}/elapsed-timer.h - ${CMAKE_CURRENT_LIST_DIR}/fs.h - ${CMAKE_CURRENT_LIST_DIR}/ini.h - ${CMAKE_CURRENT_LIST_DIR}/irccd.h - ${CMAKE_CURRENT_LIST_DIR}/irccdctl.h - ${CMAKE_CURRENT_LIST_DIR}/js.h - ${CMAKE_CURRENT_LIST_DIR}/json.h - ${CMAKE_CURRENT_LIST_DIR}/js-directory.h - ${CMAKE_CURRENT_LIST_DIR}/js-elapsed-timer.h - ${CMAKE_CURRENT_LIST_DIR}/js-file.h - ${CMAKE_CURRENT_LIST_DIR}/js-irccd.h - ${CMAKE_CURRENT_LIST_DIR}/js-logger.h - ${CMAKE_CURRENT_LIST_DIR}/js-plugin.h - ${CMAKE_CURRENT_LIST_DIR}/js-server.h - ${CMAKE_CURRENT_LIST_DIR}/js-system.h - ${CMAKE_CURRENT_LIST_DIR}/js-timer.h - ${CMAKE_CURRENT_LIST_DIR}/js-unicode.h - ${CMAKE_CURRENT_LIST_DIR}/js-util.h - ${CMAKE_CURRENT_LIST_DIR}/logger.h - ${CMAKE_CURRENT_LIST_DIR}/options.h - ${CMAKE_CURRENT_LIST_DIR}/path.h - ${CMAKE_CURRENT_LIST_DIR}/plugin.h - ${CMAKE_CURRENT_LIST_DIR}/rule.h - ${CMAKE_CURRENT_LIST_DIR}/server.h - ${CMAKE_CURRENT_LIST_DIR}/server-private.h - ${CMAKE_CURRENT_LIST_DIR}/server-state.h - ${CMAKE_CURRENT_LIST_DIR}/sockets.h - ${CMAKE_CURRENT_LIST_DIR}/system.h - ${CMAKE_CURRENT_LIST_DIR}/timer.h - ${CMAKE_CURRENT_LIST_DIR}/transport-client.h - ${CMAKE_CURRENT_LIST_DIR}/transport-server.h - ${CMAKE_CURRENT_LIST_DIR}/unicode.h - ${CMAKE_CURRENT_LIST_DIR}/util.h + ${CMAKE_CURRENT_LIST_DIR}/alias.hpp + ${CMAKE_CURRENT_LIST_DIR}/application.hpp + ${CMAKE_CURRENT_LIST_DIR}/connection.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-help.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-info.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-list.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-load.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-reload.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-plugin-unload.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-cmode.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-cnotice.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-connect.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-disconnect.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-info.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-invite.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-join.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-kick.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-list.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-me.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-message.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-mode.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-nick.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-notice.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-part.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-reconnect.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-server-topic.hpp + ${CMAKE_CURRENT_LIST_DIR}/cmd-watch.hpp + ${CMAKE_CURRENT_LIST_DIR}/command.hpp + ${CMAKE_CURRENT_LIST_DIR}/config.hpp + ${CMAKE_CURRENT_LIST_DIR}/elapsed-timer.hpp + ${CMAKE_CURRENT_LIST_DIR}/fs.hpp + ${CMAKE_CURRENT_LIST_DIR}/ini.hpp + ${CMAKE_CURRENT_LIST_DIR}/irccd.hpp + ${CMAKE_CURRENT_LIST_DIR}/irccdctl.hpp + ${CMAKE_CURRENT_LIST_DIR}/js.hpp + ${CMAKE_CURRENT_LIST_DIR}/json.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-directory.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-elapsed-timer.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-file.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-irccd.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-logger.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-plugin.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-server.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-system.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-timer.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-unicode.hpp + ${CMAKE_CURRENT_LIST_DIR}/js-util.hpp + ${CMAKE_CURRENT_LIST_DIR}/logger.hpp + ${CMAKE_CURRENT_LIST_DIR}/options.hpp + ${CMAKE_CURRENT_LIST_DIR}/path.hpp + ${CMAKE_CURRENT_LIST_DIR}/plugin.hpp + ${CMAKE_CURRENT_LIST_DIR}/rule.hpp + ${CMAKE_CURRENT_LIST_DIR}/server.hpp + ${CMAKE_CURRENT_LIST_DIR}/server-private.hpp + ${CMAKE_CURRENT_LIST_DIR}/server-state.hpp + ${CMAKE_CURRENT_LIST_DIR}/sockets.hpp + ${CMAKE_CURRENT_LIST_DIR}/system.hpp + ${CMAKE_CURRENT_LIST_DIR}/timer.hpp + ${CMAKE_CURRENT_LIST_DIR}/transport-client.hpp + ${CMAKE_CURRENT_LIST_DIR}/transport-server.hpp + ${CMAKE_CURRENT_LIST_DIR}/unicode.hpp + ${CMAKE_CURRENT_LIST_DIR}/util.hpp ) set( @@ -132,6 +132,6 @@ ) if (NOT IRCCD_SYSTEM_WINDOWS) - list(APPEND HEADERS ${CMAKE_CURRENT_LIST_DIR}/xdg.h) + list(APPEND HEADERS ${CMAKE_CURRENT_LIST_DIR}/xdg.hpp) list(APPEND SOURCES ${CMAKE_CURRENT_LIST_DIR}/xdg.cpp) endif ()
--- a/lib/irccd/alias.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/alias.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -19,7 +19,7 @@ #include <cassert> #include <regex> -#include "alias.h" +#include "alias.hpp" namespace irccd {
--- a/lib/irccd/alias.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,171 +0,0 @@ -/* - * alias.h -- create irccdctl aliases - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_ALIAS_H -#define IRCCD_ALIAS_H - -/** - * @file alias.h - * @brief Create irccdctl aliases. - */ - -#include <ostream> -#include <string> -#include <vector> - -namespace irccd { - -/** - * @class AliasArg - * @brief Describe an alias argument. - * - * When the user specify arguments, it can precise an applied argument or a placeholder that will be substituted - * during command line invocation. - * - * Placeholders are placed using %n where n is an integer starting from 0. - */ -class AliasArg { -private: - std::string m_value; - bool m_isPlaceholder; - -public: - /** - * Construct an argument. - * - * @pre value must not be empty - * @param value the value - */ - AliasArg(std::string value); - - /** - * Check if the argument is a placeholder. - * - * @return true if the argument is a placeholder - */ - inline bool isPlaceholder() const noexcept - { - return m_isPlaceholder; - } - - /** - * Get the placeholder index (e.g %0 returns 0) - * - * @pre isPlaceholder() must return true - * @return the position - */ - unsigned index() const noexcept; - - /** - * Get the real value. - * - * @pre isPlaceholder() must return false - * @return the value - */ - const std::string &value() const noexcept; - - /** - * Output the alias to the stream. - * - * @param out the output stream - * @return out - */ - friend std::ostream &operator<<(std::ostream &out, const AliasArg &); -}; - -/** - * @class AliasCommand - * @brief Describe a user-provided alias command. - * - * An alias command is just a command with a set of applied or placeholders arguments. - */ -class AliasCommand { -private: - std::string m_command; - std::vector<AliasArg> m_args; - -public: - /** - * Create an alias command. - * - * @param command the command - * @param args the arguments - */ - inline AliasCommand(std::string command, std::vector<AliasArg> args = {}) noexcept - : m_command(std::move(command)) - , m_args(std::move(args)) - { - } - - /** - * Get the command to execute. - * - * @return the command name - */ - inline const std::string &command() const noexcept - { - return m_command; - } - - /** - * Get the arguments. - * - * @return the arguments - */ - inline const std::vector<AliasArg> &args() const noexcept - { - return m_args; - } -}; - -/** - * @class Alias - * @brief A set of commands to execute with their arguments. - * - * An alias is a composition of AliasCommand, typically, the user is able to set an alias that execute a list of - * specified commands in order they are defined. - */ -class Alias : public std::vector<AliasCommand> { -private: - std::string m_name; - -public: - /** - * Create an alias. - * - * @param name the alias name - */ - inline Alias(std::string name) noexcept - : m_name(std::move(name)) - { - } - - /** - * Get the alias name. - * - * @return the name - */ - inline const std::string &name() const noexcept - { - return m_name; - } -}; - -} // !irccd - -#endif // !IRCCD_ALIAS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/alias.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,171 @@ +/* + * alias.hpp -- create irccdctl aliases + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_ALIAS_HPP +#define IRCCD_ALIAS_HPP + +/** + * @file alias.hpp + * @brief Create irccdctl aliases. + */ + +#include <ostream> +#include <string> +#include <vector> + +namespace irccd { + +/** + * @class AliasArg + * @brief Describe an alias argument. + * + * When the user specify arguments, it can precise an applied argument or a placeholder that will be substituted + * during command line invocation. + * + * Placeholders are placed using %n where n is an integer starting from 0. + */ +class AliasArg { +private: + std::string m_value; + bool m_isPlaceholder; + +public: + /** + * Construct an argument. + * + * @pre value must not be empty + * @param value the value + */ + AliasArg(std::string value); + + /** + * Check if the argument is a placeholder. + * + * @return true if the argument is a placeholder + */ + inline bool isPlaceholder() const noexcept + { + return m_isPlaceholder; + } + + /** + * Get the placeholder index (e.g %0 returns 0) + * + * @pre isPlaceholder() must return true + * @return the position + */ + unsigned index() const noexcept; + + /** + * Get the real value. + * + * @pre isPlaceholder() must return false + * @return the value + */ + const std::string &value() const noexcept; + + /** + * Output the alias to the stream. + * + * @param out the output stream + * @return out + */ + friend std::ostream &operator<<(std::ostream &out, const AliasArg &); +}; + +/** + * @class AliasCommand + * @brief Describe a user-provided alias command. + * + * An alias command is just a command with a set of applied or placeholders arguments. + */ +class AliasCommand { +private: + std::string m_command; + std::vector<AliasArg> m_args; + +public: + /** + * Create an alias command. + * + * @param command the command + * @param args the arguments + */ + inline AliasCommand(std::string command, std::vector<AliasArg> args = {}) noexcept + : m_command(std::move(command)) + , m_args(std::move(args)) + { + } + + /** + * Get the command to execute. + * + * @return the command name + */ + inline const std::string &command() const noexcept + { + return m_command; + } + + /** + * Get the arguments. + * + * @return the arguments + */ + inline const std::vector<AliasArg> &args() const noexcept + { + return m_args; + } +}; + +/** + * @class Alias + * @brief A set of commands to execute with their arguments. + * + * An alias is a composition of AliasCommand, typically, the user is able to set an alias that execute a list of + * specified commands in order they are defined. + */ +class Alias : public std::vector<AliasCommand> { +private: + std::string m_name; + +public: + /** + * Create an alias. + * + * @param name the alias name + */ + inline Alias(std::string name) noexcept + : m_name(std::move(name)) + { + } + + /** + * Get the alias name. + * + * @return the name + */ + inline const std::string &name() const noexcept + { + return m_name; + } +}; + +} // !irccd + +#endif // !IRCCD_ALIAS_HPP
--- a/lib/irccd/application.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/application.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,31 +16,31 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "application.h" -#include "cmd-help.h" -#include "cmd-plugin-info.h" -#include "cmd-plugin-list.h" -#include "cmd-plugin-load.h" -#include "cmd-plugin-reload.h" -#include "cmd-plugin-unload.h" -#include "cmd-server-cmode.h" -#include "cmd-server-cnotice.h" -#include "cmd-server-connect.h" -#include "cmd-server-disconnect.h" -#include "cmd-server-info.h" -#include "cmd-server-invite.h" -#include "cmd-server-join.h" -#include "cmd-server-kick.h" -#include "cmd-server-list.h" -#include "cmd-server-me.h" -#include "cmd-server-message.h" -#include "cmd-server-mode.h" -#include "cmd-server-nick.h" -#include "cmd-server-notice.h" -#include "cmd-server-part.h" -#include "cmd-server-reconnect.h" -#include "cmd-server-topic.h" -#include "cmd-watch.h" +#include "application.hpp" +#include "cmd-help.hpp" +#include "cmd-plugin-info.hpp" +#include "cmd-plugin-list.hpp" +#include "cmd-plugin-load.hpp" +#include "cmd-plugin-reload.hpp" +#include "cmd-plugin-unload.hpp" +#include "cmd-server-cmode.hpp" +#include "cmd-server-cnotice.hpp" +#include "cmd-server-connect.hpp" +#include "cmd-server-disconnect.hpp" +#include "cmd-server-info.hpp" +#include "cmd-server-invite.hpp" +#include "cmd-server-join.hpp" +#include "cmd-server-kick.hpp" +#include "cmd-server-list.hpp" +#include "cmd-server-me.hpp" +#include "cmd-server-message.hpp" +#include "cmd-server-mode.hpp" +#include "cmd-server-nick.hpp" +#include "cmd-server-notice.hpp" +#include "cmd-server-part.hpp" +#include "cmd-server-reconnect.hpp" +#include "cmd-server-topic.hpp" +#include "cmd-watch.hpp" namespace irccd {
--- a/lib/irccd/application.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * application.h -- super base class to create irccd front ends - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_APPLICATION_H -#define IRCCD_APPLICATION_H - -/** - * @file application.h - * @brief Base class for irccd and irccdctl. - */ - -#include <cassert> -#include <memory> -#include <unordered_map> - -#include "command.h" - -namespace irccd { - -/** - * Map of commands. - */ -using RemoteCommands = std::unordered_map<std::string, std::unique_ptr<RemoteCommand>>; - -/** - * @brief Base class for creating irccd front ends. - */ -class Application { -protected: - /** - * Map of commands. - */ - RemoteCommands m_commands; - -public: - /** - * Create the application and fill the commands with predefined commands. - */ - Application(); - - /** - * Access the remote commands. - * - * @return the commands - */ - inline const RemoteCommands &commands() const noexcept - { - return m_commands; - } - - /** - * Add a new command. - * - * @pre command must not be null - * @pre the command must not exist - * @param command the command - */ - inline void addCommand(std::unique_ptr<RemoteCommand> command) - { - assert(command); - assert(m_commands.count(command->name()) == 0); - - m_commands.emplace(command->name(), std::move(command)); - } -}; - -} // !irccd - -#endif // !_IRCCD_APPLICATION_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/application.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,84 @@ +/* + * application.hpp -- super base class to create irccd front ends + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_APPLICATION_HPP +#define IRCCD_APPLICATION_HPP + +/** + * @file application.hpp + * @brief Base class for irccd and irccdctl. + */ + +#include <cassert> +#include <memory> +#include <unordered_map> + +#include "command.hpp" + +namespace irccd { + +/** + * Map of commands. + */ +using RemoteCommands = std::unordered_map<std::string, std::unique_ptr<RemoteCommand>>; + +/** + * @brief Base class for creating irccd front ends. + */ +class Application { +protected: + /** + * Map of commands. + */ + RemoteCommands m_commands; + +public: + /** + * Create the application and fill the commands with predefined commands. + */ + Application(); + + /** + * Access the remote commands. + * + * @return the commands + */ + inline const RemoteCommands &commands() const noexcept + { + return m_commands; + } + + /** + * Add a new command. + * + * @pre command must not be null + * @pre the command must not exist + * @param command the command + */ + inline void addCommand(std::unique_ptr<RemoteCommand> command) + { + assert(command); + assert(m_commands.count(command->name()) == 0); + + m_commands.emplace(command->name(), std::move(command)); + } +}; + +} // !irccd + +#endif // !_IRCCD_APPLICATION_HPP_
--- a/lib/irccd/cmd-help.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-help.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,10 +16,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/irccdctl.h> -#include <irccd/logger.h> +#include <irccd/irccdctl.hpp> +#include <irccd/logger.hpp> -#include "cmd-help.h" +#include "cmd-help.hpp" namespace irccd {
--- a/lib/irccd/cmd-help.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * cmd-help.h -- implementation of irccdctl help - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_HELP_H -#define IRCCD_CMD_HELP_H - -/** - * @file cmd-help.h - * @brief Implementation of irccdctl help. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class Help - * @brief Implementation of irccdctl help. - */ -class Help : public RemoteCommand { -public: - Help(); - - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_HELP_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-help.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,58 @@ +/* + * cmd-help.hpp -- implementation of irccdctl help + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_HPPELP_HPP +#define IRCCD_CMD_HPPELP_HPP + +/** + * @file cmd-help.hpp + * @brief Implementation of irccdctl help. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class Help + * @brief Implementation of irccdctl help. + */ +class Help : public RemoteCommand { +public: + Help(); + + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_HPPELP_HPP
--- a/lib/irccd/cmd-plugin-info.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-plugin-info.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,10 +18,10 @@ #include <iostream> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "cmd-plugin-info.h" -#include "irccd.h" +#include "cmd-plugin-info.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-plugin-info.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * cmd-plugin-info.h -- implementation of plugin-info command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_PLUGIN_INFO_H -#define IRCCD_CMD_PLUGIN_INFO_H - -/** - * @file cmd-plugin-info.h - * @brief Implementation of plugin-info transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class PluginInfo - * @brief Implementation of plugin-info transport command. - */ -class PluginInfo : public RemoteCommand { -public: - /** - * Constructor. - */ - PluginInfo(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; - - /** - * @copydoc RemoteCommand::result - */ - void result(Irccdctl &irccdctl, const json::Value &response) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_PLUGIN_INFO_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-plugin-info.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,74 @@ +/* + * cmd-plugin-info.hpp -- implementation of plugin-info command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_PLUGIN_INFO_HPP +#define IRCCD_CMD_PLUGIN_INFO_HPP + +/** + * @file cmd-plugin-info.hpp + * @brief Implementation of plugin-info transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class PluginInfo + * @brief Implementation of plugin-info transport command. + */ +class PluginInfo : public RemoteCommand { +public: + /** + * Constructor. + */ + PluginInfo(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; + + /** + * @copydoc RemoteCommand::result + */ + void result(Irccdctl &irccdctl, const json::Value &response) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_PLUGIN_INFO_HPP
--- a/lib/irccd/cmd-plugin-list.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-plugin-list.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,10 +18,10 @@ #include <iostream> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "cmd-plugin-list.h" -#include "irccd.h" +#include "cmd-plugin-list.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-plugin-list.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * cmd-plugin-list.h -- implementation of plugin-list transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_PLUGIN_LIST_H -#define IRCCD_CMD_PLUGIN_LIST_H - -/** - * @file cmd-plugin-list.h - * @brief Implementation of plugin-list transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class PluginList - * @brief Implementation of plugin-list transport command. - */ -class PluginList : public RemoteCommand { -public: - /** - * Constructor. - */ - PluginList(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; - - /** - * @copydoc RemoteCommand::result - */ - void result(Irccdctl &irccdctl, const json::Value &response) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_PLUGIN_LIST_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-plugin-list.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,64 @@ +/* + * cmd-plugin-list.hpp -- implementation of plugin-list transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_PLUGIN_LIST_HPP +#define IRCCD_CMD_PLUGIN_LIST_HPP + +/** + * @file cmd-plugin-list.hpp + * @brief Implementation of plugin-list transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class PluginList + * @brief Implementation of plugin-list transport command. + */ +class PluginList : public RemoteCommand { +public: + /** + * Constructor. + */ + PluginList(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; + + /** + * @copydoc RemoteCommand::result + */ + void result(Irccdctl &irccdctl, const json::Value &response) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_PLUGIN_LIST_HPP
--- a/lib/irccd/cmd-plugin-load.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-plugin-load.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,10 +16,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "cmd-plugin-load.h" -#include "irccd.h" +#include "cmd-plugin-load.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-plugin-load.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * cmd-plugin-load.h -- implementation of plugin-load transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_PLUGIN_LOAD_H -#define IRCCD_CMD_PLUGIN_LOAD_H - -/** - * @file cmd-plugin-load.h - * @brief Implementation of plugin-load transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class PluginLoad - * @brief Implementation of plugin-load transport command. - */ -class PluginLoad : public RemoteCommand { -public: - /** - * Constructor. - */ - PluginLoad(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_PLUGIN_LOAD_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-plugin-load.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,64 @@ +/* + * cmd-plugin-load.hpp -- implementation of plugin-load transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_PLUGIN_LOAD_HPP +#define IRCCD_CMD_PLUGIN_LOAD_HPP + +/** + * @file cmd-plugin-load.hpp + * @brief Implementation of plugin-load transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class PluginLoad + * @brief Implementation of plugin-load transport command. + */ +class PluginLoad : public RemoteCommand { +public: + /** + * Constructor. + */ + PluginLoad(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_PLUGIN_LOAD_HPP
--- a/lib/irccd/cmd-plugin-reload.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-plugin-reload.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,10 +16,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "cmd-plugin-reload.h" -#include "irccd.h" +#include "cmd-plugin-reload.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-plugin-reload.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * cmd-plugin-reload.h -- implementation of plugin-reload transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_PLUGIN_RELOAD_H -#define IRCCD_CMD_PLUGIN_RELOAD_H - -/** - * @file cmd-plugin-reload.h - * @brief Implementation of plugin-reload transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class PluginReload - * @brief Implementation of plugin-reload transport command. - */ -class PluginReload : public RemoteCommand { -public: - /** - * Constructor. - */ - PluginReload(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_PLUGIN_RELOAD_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-plugin-reload.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,64 @@ +/* + * cmd-plugin-reload.hpp -- implementation of plugin-reload transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_PLUGIN_RELOAD_HPP +#define IRCCD_CMD_PLUGIN_RELOAD_HPP + +/** + * @file cmd-plugin-reload.hpp + * @brief Implementation of plugin-reload transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class PluginReload + * @brief Implementation of plugin-reload transport command. + */ +class PluginReload : public RemoteCommand { +public: + /** + * Constructor. + */ + PluginReload(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_PLUGIN_RELOAD_HPP
--- a/lib/irccd/cmd-plugin-unload.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-plugin-unload.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,10 +16,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "cmd-plugin-unload.h" -#include "irccd.h" +#include "cmd-plugin-unload.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-plugin-unload.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * cmd-plugin-unload.h -- implementation of plugin-unload transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_PLUGIN_UNLOAD_H -#define IRCCD_CMD_PLUGIN_UNLOAD_H - -/** - * @file cmd-plugin-unload.h - * @brief Implementation of plugin-unload transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class PluginUnload - * @brief Implementation of plugin-unload transport command. - */ -class PluginUnload : public RemoteCommand { -public: - /** - * Constructor. - */ - PluginUnload(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_PLUGIN_UNLOAD_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-plugin-unload.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,64 @@ +/* + * cmd-plugin-unload.hpp -- implementation of plugin-unload transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_PLUGIN_UNLOAD_HPP +#define IRCCD_CMD_PLUGIN_UNLOAD_HPP + +/** + * @file cmd-plugin-unload.hpp + * @brief Implementation of plugin-unload transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class PluginUnload + * @brief Implementation of plugin-unload transport command. + */ +class PluginUnload : public RemoteCommand { +public: + /** + * Constructor. + */ + PluginUnload(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_PLUGIN_UNLOAD_HPP
--- a/lib/irccd/cmd-server-cmode.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-cmode.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-cmode.h" -#include "irccd.h" +#include "cmd-server-cmode.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-cmode.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * cmd-server-cmode.h -- implementation of server-cmode transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_CMODE_H -#define IRCCD_CMD_SERVER_CMODE_H - -/** - * @file cmd-server-cmode.h - * @brief Implementation of server-cmode transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerChannelMode - * @brief Implementation of server-cmode transport command. - */ -class ServerChannelMode : public RemoteCommand { -public: - /** - * Constructor. - */ - ServerChannelMode(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_CMODE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-cmode.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,64 @@ +/* + * cmd-server-cmode.hpp -- implementation of server-cmode transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_CMODE_HPP +#define IRCCD_CMD_SERVER_CMODE_HPP + +/** + * @file cmd-server-cmode.hpp + * @brief Implementation of server-cmode transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerChannelMode + * @brief Implementation of server-cmode transport command. + */ +class ServerChannelMode : public RemoteCommand { +public: + /** + * Constructor. + */ + ServerChannelMode(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_CMODE_HPP
--- a/lib/irccd/cmd-server-cnotice.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-cnotice.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-cnotice.h" -#include "irccd.h" +#include "cmd-server-cnotice.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-cnotice.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * cmd-server-cnotice.h -- implementation of server-cnotice transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_CNOTICE_H -#define IRCCD_CMD_SERVER_CNOTICE_H - -/** - * @file cmd-server-cnotice.h - * @brief Implementation of server-cnotice transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerChannelNotice - * @brief Implementation of server-cnotice transport command. - * - * Send a channel notice to the specified channel. - * - * { - * "command": "server-cnotice", - * "server": "the server name", - * "channel": "name", - * "message": "the message" - * } - */ -class ServerChannelNotice : public RemoteCommand { -public: - /** - * Constructor. - */ - ServerChannelNotice(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_CNOTICE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-cnotice.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,73 @@ +/* + * cmd-server-cnotice.hpp -- implementation of server-cnotice transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_CNOTICE_HPP +#define IRCCD_CMD_SERVER_CNOTICE_HPP + +/** + * @file cmd-server-cnotice.hpp + * @brief Implementation of server-cnotice transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerChannelNotice + * @brief Implementation of server-cnotice transport command. + * + * Send a channel notice to the specified channel. + * + * { + * "command": "server-cnotice", + * "server": "the server name", + * "channel": "name", + * "message": "the message" + * } + */ +class ServerChannelNotice : public RemoteCommand { +public: + /** + * Constructor. + */ + ServerChannelNotice(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_CNOTICE_HPP
--- a/lib/irccd/cmd-server-connect.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-connect.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,10 +18,10 @@ #include <limits> -#include "cmd-server-connect.h" -#include "irccd.h" -#include "server.h" -#include "util.h" +#include "cmd-server-connect.hpp" +#include "irccd.hpp" +#include "server.hpp" +#include "util.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-connect.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * cmd-server-connect.h -- implementation of server-connect transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_CONNECT_H -#define IRCCD_CMD_SERVER_CONNECT_H - -/** - * @file cmd-server-connect.h - * @brief Implementation of server-connect transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerConnect - * @brief Implementation of server-connect transport command. - */ -class ServerConnect : public RemoteCommand { -public: - /** - * Constructor. - */ - ServerConnect(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::options - */ - std::vector<Option> options() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_CONNECT_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-connect.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,69 @@ +/* + * cmd-server-connect.hpp -- implementation of server-connect transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_CONNECT_HPP +#define IRCCD_CMD_SERVER_CONNECT_HPP + +/** + * @file cmd-server-connect.hpp + * @brief Implementation of server-connect transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerConnect + * @brief Implementation of server-connect transport command. + */ +class ServerConnect : public RemoteCommand { +public: + /** + * Constructor. + */ + ServerConnect(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::options + */ + std::vector<Option> options() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_CONNECT_HPP
--- a/lib/irccd/cmd-server-disconnect.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-disconnect.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-disconnect.h" -#include "irccd.h" +#include "cmd-server-disconnect.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-disconnect.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-disconnect.h -- implementation of server-disconnect transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_DISCONNECT_H -#define IRCCD_CMD_SERVER_DISCONNECT_H - -/** - * @file cmd-server-disconnect.h - * @brief Implementation of server-disconnect transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerDisconnect - * @brief Implementation of server-disconnect transport command. - */ -class ServerDisconnect : public RemoteCommand { -public: - /** - * Constructor. - */ - ServerDisconnect(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * Get list of arguments required. - * - * @return the arguments required - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_DISCONNECT_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-disconnect.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-disconnect.hpp -- implementation of server-disconnect transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_DISCONNECT_HPP +#define IRCCD_CMD_SERVER_DISCONNECT_HPP + +/** + * @file cmd-server-disconnect.hpp + * @brief Implementation of server-disconnect transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerDisconnect + * @brief Implementation of server-disconnect transport command. + */ +class ServerDisconnect : public RemoteCommand { +public: + /** + * Constructor. + */ + ServerDisconnect(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * Get list of arguments required. + * + * @return the arguments required + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_DISCONNECT_HPP
--- a/lib/irccd/cmd-server-info.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-info.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,8 +18,8 @@ #include <iostream> -#include "cmd-server-info.h" -#include "irccd.h" +#include "cmd-server-info.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-info.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * cmd-server-info.h -- implementation of server-info transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_INFO_H -#define IRCCD_CMD_SERVER_INFO_H - -/** - * @file cmd-server-info.h - * @brief Implementation of server-info transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerInfo - * @brief Implementation of server-info transport command. - */ -class ServerInfo : public RemoteCommand { -public: - ServerInfo(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; - - /** - * @copydoc RemoteCommand::result - */ - void result(Irccdctl &irccdctl, const json::Value &response) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_INFO_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-info.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,71 @@ +/* + * cmd-server-info.hpp -- implementation of server-info transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_INFO_HPP +#define IRCCD_CMD_SERVER_INFO_HPP + +/** + * @file cmd-server-info.hpp + * @brief Implementation of server-info transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerInfo + * @brief Implementation of server-info transport command. + */ +class ServerInfo : public RemoteCommand { +public: + ServerInfo(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; + + /** + * @copydoc RemoteCommand::result + */ + void result(Irccdctl &irccdctl, const json::Value &response) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_INFO_HPP
--- a/lib/irccd/cmd-server-invite.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-invite.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-invite.h" -#include "irccd.h" +#include "cmd-server-invite.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-invite.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * cmd-server-invite.h -- implementation of server-invite transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_INVITE_H -#define IRCCD_CMD_SERVER_INVITE_H - -/** - * @file cmd-server-invite.h - * @brief Implementation of server-invite transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerInvite - * @brief Implementation of server-invite transport command. - */ -class ServerInvite : public RemoteCommand { -public: - ServerInvite(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; - - -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_INVITE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-invite.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,68 @@ +/* + * cmd-server-invite.hpp -- implementation of server-invite transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_INVITE_HPP +#define IRCCD_CMD_SERVER_INVITE_HPP + +/** + * @file cmd-server-invite.hpp + * @brief Implementation of server-invite transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerInvite + * @brief Implementation of server-invite transport command. + */ +class ServerInvite : public RemoteCommand { +public: + ServerInvite(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; + + +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_INVITE_HPP
--- a/lib/irccd/cmd-server-join.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-join.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-join.h" -#include "irccd.h" +#include "cmd-server-join.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-join.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-join.h -- implementation of server-join transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_JOIN_H -#define IRCCD_CMD_SERVER_JOIN_H - -/** - * @file cmd-server-join.h - * @brief Implementation of server-join transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerJoin - * @brief Implementation of server-join transport command. - */ -class ServerJoin : public RemoteCommand { -public: - ServerJoin(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_JOIN_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-join.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-join.hpp -- implementation of server-join transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_JOIN_HPP +#define IRCCD_CMD_SERVER_JOIN_HPP + +/** + * @file cmd-server-join.hpp + * @brief Implementation of server-join transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerJoin + * @brief Implementation of server-join transport command. + */ +class ServerJoin : public RemoteCommand { +public: + ServerJoin(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_JOIN_HPP
--- a/lib/irccd/cmd-server-kick.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-kick.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-kick.h" -#include "irccd.h" +#include "cmd-server-kick.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-kick.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-kick.h -- implementation of server-kick transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_KICK_H -#define IRCCD_CMD_SERVER_KICK_H - -/** - * @file cmd-server-kick.h - * @brief Implementation of server-kick transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerKick - * @brief Implementation of server-kick transport command. - */ -class ServerKick : public RemoteCommand { -public: - ServerKick(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_KICK_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-kick.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-kick.hpp -- implementation of server-kick transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_KICK_HPP +#define IRCCD_CMD_SERVER_KICK_HPP + +/** + * @file cmd-server-kick.hpp + * @brief Implementation of server-kick transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerKick + * @brief Implementation of server-kick transport command. + */ +class ServerKick : public RemoteCommand { +public: + ServerKick(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_KICK_HPP
--- a/lib/irccd/cmd-server-list.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-list.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,8 +18,8 @@ #include <iostream> -#include "cmd-server-list.h" -#include "irccd.h" +#include "cmd-server-list.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-list.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * cmd-server-list.h -- implementation of server-list transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_LIST_H -#define IRCCD_CMD_SERVER_LIST_H - -/** - * @file cmd-server-list.h - * @brief Implementation of server-list transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerList - * @brief Implementation of server-list transport command. - */ -class ServerList : public RemoteCommand { -public: - ServerList(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - json::Value exec(Irccd &irccd, const json::Value &request) const override; - - void result(Irccdctl &irccdctl, const json::Value &response) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_LIST_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-list.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,55 @@ +/* + * cmd-server-list.hpp -- implementation of server-list transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_LIST_HPP +#define IRCCD_CMD_SERVER_LIST_HPP + +/** + * @file cmd-server-list.hpp + * @brief Implementation of server-list transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerList + * @brief Implementation of server-list transport command. + */ +class ServerList : public RemoteCommand { +public: + ServerList(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + json::Value exec(Irccd &irccd, const json::Value &request) const override; + + void result(Irccdctl &irccdctl, const json::Value &response) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_LIST_HPP
--- a/lib/irccd/cmd-server-me.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-me.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-me.h" -#include "irccd.h" +#include "cmd-server-me.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-me.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-me.h -- implementation of server-me transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_ME_H -#define IRCCD_CMD_SERVER_ME_H - -/** - * @file cmd-server-me.h - * @brief Implementation of server-me transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerMe - * @brief Implementation of server-me transport command. - */ -class ServerMe : public RemoteCommand { -public: - ServerMe(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_ME_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-me.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-me.hpp -- implementation of server-me transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_ME_HPP +#define IRCCD_CMD_SERVER_ME_HPP + +/** + * @file cmd-server-me.hpp + * @brief Implementation of server-me transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerMe + * @brief Implementation of server-me transport command. + */ +class ServerMe : public RemoteCommand { +public: + ServerMe(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_ME_HPP
--- a/lib/irccd/cmd-server-message.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-message.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-message.h" -#include "irccd.h" +#include "cmd-server-message.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-message.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-message.h -- implementation of server-message transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_MESSAGE_H -#define IRCCD_CMD_SERVER_MESSAGE_H - -/** - * @file cmd-server-message.h - * @brief Implementation of server-message transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerMessage - * @brief Implementation of server-message transport command. - */ -class ServerMessage : public RemoteCommand { -public: - ServerMessage(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_MESSAGE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-message.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-message.hpp -- implementation of server-message transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_MESSAGE_HPP +#define IRCCD_CMD_SERVER_MESSAGE_HPP + +/** + * @file cmd-server-message.hpp + * @brief Implementation of server-message transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerMessage + * @brief Implementation of server-message transport command. + */ +class ServerMessage : public RemoteCommand { +public: + ServerMessage(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_MESSAGE_HPP
--- a/lib/irccd/cmd-server-mode.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-mode.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-mode.h" -#include "irccd.h" +#include "cmd-server-mode.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-mode.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-mode.h -- implementation of server-mode transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_MODE_H -#define IRCCD_CMD_SERVER_MODE_H - -/** - * @file cmd-server-mode.h - * @brief Implementation of server-mode transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerMode - * @brief Implementation of server-mode transport command. - */ -class ServerMode : public RemoteCommand { -public: - ServerMode(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_MODE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-mode.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-mode.hpp -- implementation of server-mode transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_MODE_HPP +#define IRCCD_CMD_SERVER_MODE_HPP + +/** + * @file cmd-server-mode.hpp + * @brief Implementation of server-mode transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerMode + * @brief Implementation of server-mode transport command. + */ +class ServerMode : public RemoteCommand { +public: + ServerMode(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_MODE_HPP
--- a/lib/irccd/cmd-server-nick.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-nick.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-nick.h" -#include "irccd.h" +#include "cmd-server-nick.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-nick.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-nick.h -- implementation of server-nick transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_NICK_H -#define IRCCD_CMD_SERVER_NICK_H - -/** - * @file cmd-server-nick.h - * @brief Implementation of server-nick transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerNick - * @brief Implementation of server-nick transport command. - */ -class ServerNick : public RemoteCommand { -public: - ServerNick(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_NICK_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-nick.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-nick.hpp -- implementation of server-nick transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_NICK_HPP +#define IRCCD_CMD_SERVER_NICK_HPP + +/** + * @file cmd-server-nick.hpp + * @brief Implementation of server-nick transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerNick + * @brief Implementation of server-nick transport command. + */ +class ServerNick : public RemoteCommand { +public: + ServerNick(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_NICK_HPP
--- a/lib/irccd/cmd-server-notice.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-notice.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-notice.h" -#include "irccd.h" +#include "cmd-server-notice.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-notice.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-notice.h -- implementation of server-notice transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_NOTICE_H -#define IRCCD_CMD_SERVER_NOTICE_H - -/** - * @file cmd-server-notice.h - * @brief Implementation of server-notice transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerNotice - * @brief Implementation of server-notice transport command. - */ -class ServerNotice : public RemoteCommand { -public: - ServerNotice(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_NOTICE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-notice.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-notice.hpp -- implementation of server-notice transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_NOTICE_HPP +#define IRCCD_CMD_SERVER_NOTICE_HPP + +/** + * @file cmd-server-notice.hpp + * @brief Implementation of server-notice transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerNotice + * @brief Implementation of server-notice transport command. + */ +class ServerNotice : public RemoteCommand { +public: + ServerNotice(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_NOTICE_HPP
--- a/lib/irccd/cmd-server-part.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-part.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-part.h" -#include "irccd.h" +#include "cmd-server-part.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-part.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-part.h -- implementation of server-part transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_PART_H -#define IRCCD_CMD_SERVER_PART_H - -/** - * @file cmd-server-part.h - * @brief Implementation of server-part transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerPart - * @brief Implementation of server-part transport command. - */ -class ServerPart : public RemoteCommand { -public: - ServerPart(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_PART_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-part.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-part.hpp -- implementation of server-part transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_PART_HPP +#define IRCCD_CMD_SERVER_PART_HPP + +/** + * @file cmd-server-part.hpp + * @brief Implementation of server-part transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerPart + * @brief Implementation of server-part transport command. + */ +class ServerPart : public RemoteCommand { +public: + ServerPart(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_PART_HPP
--- a/lib/irccd/cmd-server-reconnect.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-reconnect.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-reconnect.h" -#include "irccd.h" +#include "cmd-server-reconnect.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-reconnect.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-reconnect.h -- implementation of server-reconnect transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_RECONNECT_H -#define IRCCD_CMD_SERVER_RECONNECT_H - -/** - * @file cmd-server-reconnect.h - * @brief Implementation of server-reconnect transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerReconnect - * @brief Implementation of server-reconnect transport command. - */ -class ServerReconnect : public RemoteCommand { -public: - ServerReconnect(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_RECONNECT_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-reconnect.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-reconnect.hpp -- implementation of server-reconnect transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_RECONNECT_HPP +#define IRCCD_CMD_SERVER_RECONNECT_HPP + +/** + * @file cmd-server-reconnect.hpp + * @brief Implementation of server-reconnect transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerReconnect + * @brief Implementation of server-reconnect transport command. + */ +class ServerReconnect : public RemoteCommand { +public: + ServerReconnect(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_RECONNECT_HPP
--- a/lib/irccd/cmd-server-topic.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-server-topic.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "cmd-server-topic.h" -#include "irccd.h" +#include "cmd-server-topic.hpp" +#include "irccd.hpp" namespace irccd {
--- a/lib/irccd/cmd-server-topic.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * cmd-server-topic.h -- implementation of server-topic transport command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_SERVER_TOPIC_H -#define IRCCD_CMD_SERVER_TOPIC_H - -/** - * @file cmd-server-topic.h - * @brief Implementation of server-topic transport command. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class ServerTopic - * @brief Implementation of server-topic transport command. - */ -class ServerTopic : public RemoteCommand { -public: - ServerTopic(); - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::args - */ - std::vector<Arg> args() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; - - /** - * @copydoc RemoteCommand::exec - */ - json::Value exec(Irccd &irccd, const json::Value &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_SERVER_TOPIC_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-server-topic.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,66 @@ +/* + * cmd-server-topic.hpp -- implementation of server-topic transport command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_SERVER_TOPIC_HPP +#define IRCCD_CMD_SERVER_TOPIC_HPP + +/** + * @file cmd-server-topic.hpp + * @brief Implementation of server-topic transport command. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class ServerTopic + * @brief Implementation of server-topic transport command. + */ +class ServerTopic : public RemoteCommand { +public: + ServerTopic(); + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::args + */ + std::vector<Arg> args() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const override; + + /** + * @copydoc RemoteCommand::exec + */ + json::Value exec(Irccd &irccd, const json::Value &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_SERVER_TOPIC_HPP
--- a/lib/irccd/cmd-watch.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/cmd-watch.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -21,8 +21,8 @@ #include <sstream> #include <unordered_map> -#include "cmd-watch.h" -#include "irccdctl.h" +#include "cmd-watch.hpp" +#include "irccdctl.hpp" namespace irccd {
--- a/lib/irccd/cmd-watch.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * cmd-watch.h -- implementation of irccdctl watch - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CMD_WATCH_H -#define IRCCD_CMD_WATCH_H - -/** - * @file cmd-watch.h - * @brief Implementation of irccdctl watch. - */ - -#include "command.h" - -namespace irccd { - -namespace command { - -/** - * @class Watch - * @brief Implementation of irccdctl watch. - */ -class Watch : public RemoteCommand { -public: - Watch(); - - std::vector<Option> options() const override; - - /** - * @copydoc RemoteCommand::help - */ - std::string help() const override; - - /** - * @copydoc RemoteCommand::request - */ - json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &request) const override; -}; - -} // !command - -} // !irccd - -#endif // !IRCCD_CMD_WATCH_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/cmd-watch.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,58 @@ +/* + * cmd-watch.hpp -- implementation of irccdctl watch + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CMD_WATCH_HPP +#define IRCCD_CMD_WATCH_HPP + +/** + * @file cmd-watch.hpp + * @brief Implementation of irccdctl watch. + */ + +#include "command.hpp" + +namespace irccd { + +namespace command { + +/** + * @class Watch + * @brief Implementation of irccdctl watch. + */ +class Watch : public RemoteCommand { +public: + Watch(); + + std::vector<Option> options() const override; + + /** + * @copydoc RemoteCommand::help + */ + std::string help() const override; + + /** + * @copydoc RemoteCommand::request + */ + json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &request) const override; +}; + +} // !command + +} // !irccd + +#endif // !IRCCD_CMD_WATCH_HPP
--- a/lib/irccd/command.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/command.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -20,10 +20,10 @@ #include <iomanip> #include <sstream> -#include <irccd/logger.h> -#include <irccd/system.h> +#include <irccd/logger.hpp> +#include <irccd/system.hpp> -#include "command.h" +#include "command.hpp" using namespace std::string_literals;
--- a/lib/irccd/command.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,493 +0,0 @@ -/* - * command.h -- remote command - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_COMMAND_H -#define IRCCD_COMMAND_H - -/** - * @file command.h - * @brief Remote commands. - */ - -#include <cassert> -#include <map> -#include <vector> - -#include <irccd/json.h> - -namespace irccd { - -class Irccd; -class Irccdctl; - -/** - * @brief Command line arguments to irccdctl. - * - * This class contains the resolved arguments from command line that can apply to the command. - */ -class RemoteCommandRequest { -public: - /** - * The options given by command line. - */ - using Options = std::multimap<std::string, std::string>; - - /** - * Command line arguments in the same order. - */ - using Args = std::vector<std::string>; - -private: - Options m_options; - Args m_args; - -public: - /** - * Construct the request. - * - * @param options the options - * @param args the arguments - */ - inline RemoteCommandRequest(Options options, Args args) noexcept - : m_options(std::move(options)) - , m_args(std::move(args)) - { - } - - /** - * Get the arguments. - * - * @return the arguments - */ - inline const Args &args() const noexcept - { - return m_args; - } - - /** - * Get the options. - * - * @return the options - */ - inline const Options &options() const noexcept - { - return m_options; - } - - /** - * Get the number of arguments. - * - * @return the number of arguments - */ - inline unsigned length() const noexcept - { - return (unsigned)m_args.size(); - } - - /** - * Check if the request has the given option id. - * - * @param option the option id - * @return true if the option is available - */ - inline bool has(const std::string &option) const noexcept - { - return m_options.count(option) != 0; - } - - /** - * Get the argument at the specified index. - * - * @pre index < length() - * @param index the argument index - * @return the argument - */ - inline const std::string &arg(unsigned index) const noexcept - { - assert(index < m_args.size()); - - return m_args[index]; - } - - /** - * Get the argument or default value if not available. - * - * @param index the index - * @param defaultValue the value if index is out of range - * @return the argument - */ - inline std::string argOr(unsigned index, std::string defaultValue) const noexcept - { - return index < m_args.size() ? m_args[index] : defaultValue; - } - - /** - * Get the given option by its id. - * - * @pre has(key) - * @param key the option id - * @return the option - */ - inline const std::string &option(const std::string &key) const noexcept - { - assert(m_options.count(key) != 0); - - return m_options.find(key)->second; - } - - /** - * Get the given option by its id or defaultValue if not found. - * - * @param key the option id - * @param defaultValue the value replacement - * @return the option - */ - inline std::string optionOr(const std::string &key, std::string defaultValue) const noexcept - { - auto it = m_options.find(key); - - if (it == m_options.end()) - return defaultValue; - - return it->second; - } -}; - -/** - * @brief Invokable command. - * - * A remote command is a invokable command in the irccd daemon. You can register dynamically any remote command you - * like using Application::addCommand. - * - * The remote command will be usable directly from irccdctl without any other code. - * - * A remote command can have options and arguments. Options always come first, before arguments. - * - * The command workflow is defined as follow: - * - * 1. User wants to invoke a command, request() is called and return a JSON object containaing the request, it it send - * to the daemon. - * - * 2. The daemon receive the request and execute it using exec(). It returns a JSON object containint the request result - * or error if any. - * - * 3. Finally, the command receives the result in result() function and user can manipulate it. For convenience, the - * default implementation shows the error if any. - */ -class RemoteCommand { -public: - /** - * @brief Defines available options for this command. - */ - class Option; - - /** - * @brief Defines available arguments for this command. - */ - class Arg; - -private: - std::string m_name; - std::string m_category; - bool m_visible; - -public: - /** - * Create the remote command. - * - * @pre name must not be empty - * @pre category must not be empty - * @param name the command name (e.g. server-list) - * @param category the category (e.g. Server) - * @param visible true if the command should be visible without verbosity - */ - inline RemoteCommand(std::string name, std::string category, bool visible = true) noexcept - : m_name(std::move(name)) - , m_category(std::move(category)) - , m_visible(visible) - { - assert(!m_name.empty()); - assert(!m_category.empty()); - } - - /** - * Default destructor virtual. - */ - virtual ~RemoteCommand() = default; - - /** - * Return the command name, must not have spaces. - * - * @return the command name - */ - inline const std::string &name() const noexcept - { - return m_name; - } - - /** - * Get the command category. - * - * Irccdctl will sort commands by categories. - * - * @return the category - */ - inline const std::string &category() const noexcept - { - return m_category; - } - - /** - * Hide the command in non-verbose mode. - * - * @return true if the command should be visible in non-verbose mode - */ - inline bool visible() const noexcept - { - return m_visible; - } - - /** - * Return the command documentation usage. - * - * @return the usage - */ - std::string usage() const; - - /** - * Return the help message. - * - * @return the help message - */ - virtual std::string help() const = 0; - - /** - * Get the supported irccdctl options. - * - * @return the options - */ - virtual std::vector<Option> options() const - { - return {}; - } - - /** - * Get the supported arguments. - * - * @return the arguments - */ - virtual std::vector<Arg> args() const - { - return {}; - } - - /** - * Get the minimum number of arguments required. - * - * @return the minimum - */ - unsigned min() const noexcept; - - /** - * Get the maximum number of arguments required. - * - * @return the maximum - */ - unsigned max() const noexcept; - - /** - * Prepare a JSON request to the daemon. - * - * If the command is local and does not need to send anything to irccd's instance, return a null JSON value. - * - * The default implementation just send the command name with no arguments. - * - * @param irccdctl the irccdctl instance - * @param args the command line arguments and options - * @return the JSON object to send to the daemon - * @post the returned JSON value must be an object - */ - virtual json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const; - - /** - * Execute the command in the daemon. - * - * The user can return an object with any properties to forward to the client. Irccd will automatically - * add the command name and the appropriate status code. - * - * The default return an empty object which indicates success. - * - * If any exception is thrown from this function, it is forwarded to the client as error status. - * - * @param irccd the instance - * @param request the JSON request - * @return the response - */ - virtual json::Value exec(Irccd &irccd, const json::Value &request) const; - - /** - * What to do when receiving the response from irccd. - * - * This default implementation just check for an error string and shows it if any. - * - * @param irccdctl the irccdctl instan e - * @param response the JSON response - */ - virtual void result(Irccdctl &irccdctl, const json::Value &response) const; -}; - -/** - * @brief Option description for a command. - */ -class RemoteCommand::Option { -private: - std::string m_id; - std::string m_simple; - std::string m_long; - std::string m_arg; - std::string m_description; - -public: - /** - * Constructor an option description. - * - * Simple and long keys must not start with '-' or '--', they will be added automatically. - * - * If arg is not empty, the option takes an argument. - * - * @pre id must not be empty - * @pre at least simpleKey or longKey must not be empty - * @pre description must not be empty - * @param id the option id - * @param simpleKey the key the option key - * @param longKey the long option name - * @param arg the argument name if needed - * @param description the description - */ - inline Option(std::string id, - std::string simpleKey, - std::string longKey, - std::string arg, - std::string description) noexcept - : m_id(std::move(id)) - , m_simple(std::move(simpleKey)) - , m_long(std::move(longKey)) - , m_arg(std::move(arg)) - , m_description(std::move(description)) - { - assert(!m_id.empty()); - assert(!m_simple.empty() || !m_long.empty()); - assert(!m_description.empty()); - } - - /** - * Get the id. - * - * @return the id - */ - inline const std::string &id() const noexcept - { - return m_id; - } - - /** - * Get the option key. - * - * @return the key - */ - inline const std::string &simpleKey() const noexcept - { - return m_simple; - } - - /** - * Get the long option. - * - * @return the long option - */ - inline const std::string &longKey() const noexcept - { - return m_long; - } - - /** - * Get the option description. - * - * @return the description - */ - inline const std::string &description() const noexcept - { - return m_description; - } - - /** - * Get the option argument name. - * - * @return the argument name if any - */ - inline const std::string &arg() const noexcept - { - return m_arg; - } -}; - -/** - * @brief Argument description for command. - */ -class RemoteCommand::Arg { -private: - std::string m_name; - bool m_required; - -public: - /** - * Construct an argument. - * - * @param name the name - * @param required true if the argument is required - */ - inline Arg(std::string name, bool required) noexcept - : m_name(std::move(name)) - , m_required(required) - { - } - - /** - * Get the argument name. - * - * @return the name - */ - inline const std::string &name() const noexcept - { - return m_name; - } - - /** - * Tells if the argument is required. - * - * @return true if required - */ - inline bool required() const noexcept - { - return m_required; - } -}; - -} // !irccd - -#endif // !IRCCD_COMMAND_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/command.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,493 @@ +/* + * command.hpp -- remote command + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_COMMAND_HPP +#define IRCCD_COMMAND_HPP + +/** + * @file command.hpp + * @brief Remote commands. + */ + +#include <cassert> +#include <map> +#include <vector> + +#include <irccd/json.hpp> + +namespace irccd { + +class Irccd; +class Irccdctl; + +/** + * @brief Command line arguments to irccdctl. + * + * This class contains the resolved arguments from command line that can apply to the command. + */ +class RemoteCommandRequest { +public: + /** + * The options given by command line. + */ + using Options = std::multimap<std::string, std::string>; + + /** + * Command line arguments in the same order. + */ + using Args = std::vector<std::string>; + +private: + Options m_options; + Args m_args; + +public: + /** + * Construct the request. + * + * @param options the options + * @param args the arguments + */ + inline RemoteCommandRequest(Options options, Args args) noexcept + : m_options(std::move(options)) + , m_args(std::move(args)) + { + } + + /** + * Get the arguments. + * + * @return the arguments + */ + inline const Args &args() const noexcept + { + return m_args; + } + + /** + * Get the options. + * + * @return the options + */ + inline const Options &options() const noexcept + { + return m_options; + } + + /** + * Get the number of arguments. + * + * @return the number of arguments + */ + inline unsigned length() const noexcept + { + return (unsigned)m_args.size(); + } + + /** + * Check if the request has the given option id. + * + * @param option the option id + * @return true if the option is available + */ + inline bool has(const std::string &option) const noexcept + { + return m_options.count(option) != 0; + } + + /** + * Get the argument at the specified index. + * + * @pre index < length() + * @param index the argument index + * @return the argument + */ + inline const std::string &arg(unsigned index) const noexcept + { + assert(index < m_args.size()); + + return m_args[index]; + } + + /** + * Get the argument or default value if not available. + * + * @param index the index + * @param defaultValue the value if index is out of range + * @return the argument + */ + inline std::string argOr(unsigned index, std::string defaultValue) const noexcept + { + return index < m_args.size() ? m_args[index] : defaultValue; + } + + /** + * Get the given option by its id. + * + * @pre has(key) + * @param key the option id + * @return the option + */ + inline const std::string &option(const std::string &key) const noexcept + { + assert(m_options.count(key) != 0); + + return m_options.find(key)->second; + } + + /** + * Get the given option by its id or defaultValue if not found. + * + * @param key the option id + * @param defaultValue the value replacement + * @return the option + */ + inline std::string optionOr(const std::string &key, std::string defaultValue) const noexcept + { + auto it = m_options.find(key); + + if (it == m_options.end()) + return defaultValue; + + return it->second; + } +}; + +/** + * @brief Invokable command. + * + * A remote command is a invokable command in the irccd daemon. You can register dynamically any remote command you + * like using Application::addCommand. + * + * The remote command will be usable directly from irccdctl without any other code. + * + * A remote command can have options and arguments. Options always come first, before arguments. + * + * The command workflow is defined as follow: + * + * 1. User wants to invoke a command, request() is called and return a JSON object containaing the request, it it send + * to the daemon. + * + * 2. The daemon receive the request and execute it using exec(). It returns a JSON object containint the request result + * or error if any. + * + * 3. Finally, the command receives the result in result() function and user can manipulate it. For convenience, the + * default implementation shows the error if any. + */ +class RemoteCommand { +public: + /** + * @brief Defines available options for this command. + */ + class Option; + + /** + * @brief Defines available arguments for this command. + */ + class Arg; + +private: + std::string m_name; + std::string m_category; + bool m_visible; + +public: + /** + * Create the remote command. + * + * @pre name must not be empty + * @pre category must not be empty + * @param name the command name (e.g. server-list) + * @param category the category (e.g. Server) + * @param visible true if the command should be visible without verbosity + */ + inline RemoteCommand(std::string name, std::string category, bool visible = true) noexcept + : m_name(std::move(name)) + , m_category(std::move(category)) + , m_visible(visible) + { + assert(!m_name.empty()); + assert(!m_category.empty()); + } + + /** + * Default destructor virtual. + */ + virtual ~RemoteCommand() = default; + + /** + * Return the command name, must not have spaces. + * + * @return the command name + */ + inline const std::string &name() const noexcept + { + return m_name; + } + + /** + * Get the command category. + * + * Irccdctl will sort commands by categories. + * + * @return the category + */ + inline const std::string &category() const noexcept + { + return m_category; + } + + /** + * Hide the command in non-verbose mode. + * + * @return true if the command should be visible in non-verbose mode + */ + inline bool visible() const noexcept + { + return m_visible; + } + + /** + * Return the command documentation usage. + * + * @return the usage + */ + std::string usage() const; + + /** + * Return the help message. + * + * @return the help message + */ + virtual std::string help() const = 0; + + /** + * Get the supported irccdctl options. + * + * @return the options + */ + virtual std::vector<Option> options() const + { + return {}; + } + + /** + * Get the supported arguments. + * + * @return the arguments + */ + virtual std::vector<Arg> args() const + { + return {}; + } + + /** + * Get the minimum number of arguments required. + * + * @return the minimum + */ + unsigned min() const noexcept; + + /** + * Get the maximum number of arguments required. + * + * @return the maximum + */ + unsigned max() const noexcept; + + /** + * Prepare a JSON request to the daemon. + * + * If the command is local and does not need to send anything to irccd's instance, return a null JSON value. + * + * The default implementation just send the command name with no arguments. + * + * @param irccdctl the irccdctl instance + * @param args the command line arguments and options + * @return the JSON object to send to the daemon + * @post the returned JSON value must be an object + */ + virtual json::Value request(Irccdctl &irccdctl, const RemoteCommandRequest &args) const; + + /** + * Execute the command in the daemon. + * + * The user can return an object with any properties to forward to the client. Irccd will automatically + * add the command name and the appropriate status code. + * + * The default return an empty object which indicates success. + * + * If any exception is thrown from this function, it is forwarded to the client as error status. + * + * @param irccd the instance + * @param request the JSON request + * @return the response + */ + virtual json::Value exec(Irccd &irccd, const json::Value &request) const; + + /** + * What to do when receiving the response from irccd. + * + * This default implementation just check for an error string and shows it if any. + * + * @param irccdctl the irccdctl instan e + * @param response the JSON response + */ + virtual void result(Irccdctl &irccdctl, const json::Value &response) const; +}; + +/** + * @brief Option description for a command. + */ +class RemoteCommand::Option { +private: + std::string m_id; + std::string m_simple; + std::string m_long; + std::string m_arg; + std::string m_description; + +public: + /** + * Constructor an option description. + * + * Simple and long keys must not start with '-' or '--', they will be added automatically. + * + * If arg is not empty, the option takes an argument. + * + * @pre id must not be empty + * @pre at least simpleKey or longKey must not be empty + * @pre description must not be empty + * @param id the option id + * @param simpleKey the key the option key + * @param longKey the long option name + * @param arg the argument name if needed + * @param description the description + */ + inline Option(std::string id, + std::string simpleKey, + std::string longKey, + std::string arg, + std::string description) noexcept + : m_id(std::move(id)) + , m_simple(std::move(simpleKey)) + , m_long(std::move(longKey)) + , m_arg(std::move(arg)) + , m_description(std::move(description)) + { + assert(!m_id.empty()); + assert(!m_simple.empty() || !m_long.empty()); + assert(!m_description.empty()); + } + + /** + * Get the id. + * + * @return the id + */ + inline const std::string &id() const noexcept + { + return m_id; + } + + /** + * Get the option key. + * + * @return the key + */ + inline const std::string &simpleKey() const noexcept + { + return m_simple; + } + + /** + * Get the long option. + * + * @return the long option + */ + inline const std::string &longKey() const noexcept + { + return m_long; + } + + /** + * Get the option description. + * + * @return the description + */ + inline const std::string &description() const noexcept + { + return m_description; + } + + /** + * Get the option argument name. + * + * @return the argument name if any + */ + inline const std::string &arg() const noexcept + { + return m_arg; + } +}; + +/** + * @brief Argument description for command. + */ +class RemoteCommand::Arg { +private: + std::string m_name; + bool m_required; + +public: + /** + * Construct an argument. + * + * @param name the name + * @param required true if the argument is required + */ + inline Arg(std::string name, bool required) noexcept + : m_name(std::move(name)) + , m_required(required) + { + } + + /** + * Get the argument name. + * + * @return the name + */ + inline const std::string &name() const noexcept + { + return m_name; + } + + /** + * Tells if the argument is required. + * + * @return true if required + */ + inline bool required() const noexcept + { + return m_required; + } +}; + +} // !irccd + +#endif // !IRCCD_COMMAND_HPP
--- a/lib/irccd/config.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/config.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> #if defined(HAVE_GETPID) # include <sys/types.h> @@ -30,14 +30,14 @@ # include <cstdlib> #endif -#include "config.h" -#include "ini.h" -#include "logger.h" -#include "path.h" -#include "sockets.h" -#include "system.h" -#include "util.h" -#include "irccd.h" +#include "config.hpp" +#include "ini.hpp" +#include "logger.hpp" +#include "path.hpp" +#include "sockets.hpp" +#include "system.hpp" +#include "util.hpp" +#include "irccd.hpp" using namespace std; using namespace std::string_literals;
--- a/lib/irccd/config.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * config.h -- irccd configuration loader - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CONFIG_H -#define IRCCD_CONFIG_H - -/** - * @file config.h - * @brief Read .ini configuration file for irccd - */ - -#include <irccd/options.h> - -namespace irccd { - -namespace ini { - -class Document; -class Section; - -} // !ini - -class Irccd; - -/** - * @class Config - * @brief Read .ini configuration file for irccd - */ -class Config { -private: - parser::Result m_options; - - void loadGeneral(const ini::Document &config) const; - void loadLogFile(const ini::Section &sc) const; - void loadLogSyslog() const; - void loadLogs(const ini::Document &config) const; - void loadPlugins(Irccd &irccd, const ini::Section &sc) const; - void loadPluginConfig(Irccd &irccd, const ini::Section &sc, std::string name) const; - void loadPlugins(Irccd &irccd, const ini::Document &config) const; - void loadServer(Irccd &irccd, const ini::Section &sc) const; - void loadServers(Irccd &irccd, const ini::Document &config) const; - void loadIdentity(Irccd &irccd, const ini::Section &sc) const; - void loadIdentities(Irccd &irccd, const ini::Document &config) const; - void loadRule(Irccd &irccd, const ini::Section &sc) const; - void loadRules(Irccd &irccd, const ini::Document &config) const; - void loadTransportIp(Irccd &irccd, const ini::Section &sc) const; - void loadTransportUnix(Irccd &irccd, const ini::Section &sc) const; - void loadTransports(Irccd &irccd, const ini::Document &config) const; - bool openConfig(Irccd &irccd, const std::string &path) const; - -public: - /** - * Construct the configuration file loader. If path is empty, then the configuration file is searched through - * the standard directories. - * - * @param options the option parsed at command line - */ - Config(parser::Result options) noexcept; - - /** - * Load the config into irccd. - * - * @param irccd the irccd instance - */ - void load(Irccd &irccd); -}; - -} // !irccd - -#endif // !IRCCD_CONFIG_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/config.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,85 @@ +/* + * config.hpp -- irccd configuration loader + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CONFIG_HPP +#define IRCCD_CONFIG_HPP + +/** + * @file config.hpp + * @brief Read .ini configuration file for irccd + */ + +#include <irccd/options.hpp> + +namespace irccd { + +namespace ini { + +class Document; +class Section; + +} // !ini + +class Irccd; + +/** + * @class Config + * @brief Read .ini configuration file for irccd + */ +class Config { +private: + parser::Result m_options; + + void loadGeneral(const ini::Document &config) const; + void loadLogFile(const ini::Section &sc) const; + void loadLogSyslog() const; + void loadLogs(const ini::Document &config) const; + void loadPlugins(Irccd &irccd, const ini::Section &sc) const; + void loadPluginConfig(Irccd &irccd, const ini::Section &sc, std::string name) const; + void loadPlugins(Irccd &irccd, const ini::Document &config) const; + void loadServer(Irccd &irccd, const ini::Section &sc) const; + void loadServers(Irccd &irccd, const ini::Document &config) const; + void loadIdentity(Irccd &irccd, const ini::Section &sc) const; + void loadIdentities(Irccd &irccd, const ini::Document &config) const; + void loadRule(Irccd &irccd, const ini::Section &sc) const; + void loadRules(Irccd &irccd, const ini::Document &config) const; + void loadTransportIp(Irccd &irccd, const ini::Section &sc) const; + void loadTransportUnix(Irccd &irccd, const ini::Section &sc) const; + void loadTransports(Irccd &irccd, const ini::Document &config) const; + bool openConfig(Irccd &irccd, const std::string &path) const; + +public: + /** + * Construct the configuration file loader. If path is empty, then the configuration file is searched through + * the standard directories. + * + * @param options the option parsed at command line + */ + Config(parser::Result options) noexcept; + + /** + * Load the config into irccd. + * + * @param irccd the irccd instance + */ + void load(Irccd &irccd); +}; + +} // !irccd + +#endif // !IRCCD_CONFIG_HPP
--- a/lib/irccd/connection.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/connection.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,9 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/logger.h> +#include <irccd/logger.hpp> -#include "connection.h" +#include "connection.hpp" namespace irccd {
--- a/lib/irccd/connection.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,246 +0,0 @@ -/* - * connection.h -- value wrapper for connecting to irccd - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_CONNECTION_H -#define IRCCD_CONNECTION_H - -/** - * @file connection.h - * @brief Connection to irccd instance. - */ - -#include <cassert> -#include <stdexcept> - -#include <irccd/json.h> -#include <irccd/system.h> -#include <irccd/util.h> - -#include "elapsed-timer.h" -#include "sockets.h" - -namespace irccd { - -/** - * @class Connection - * @brief Abstract class for connecting to irccd from Ip or Local addresses. - */ -class Connection { -protected: - /** - * Timer to track elapsed time. - */ - ElapsedTimer m_timer; - - /** - * Clamp the time to wait to be sure that it will be never less than 0. - */ - inline int clamp(int timeout) noexcept - { - return timeout < 0 ? -1 : (timeout - (int)m_timer.elapsed() < 0) ? 0 : (timeout - m_timer.elapsed()); - } - -public: - /** - * Default constructor. - */ - Connection() = default; - - /** - * Default destructor. - */ - virtual ~Connection() = default; - - /** - * Wait for the next requested response. - * - * @param name the response name - * @param timeout the optional timeout - * @return the object - * @throw net::Error on errors or on timeout - */ - json::Value next(const std::string &name, int timeout = 30000); - - /** - * Just wait if the operation succeeded. - * - * @param name the response name - * @param timeout the timeout - */ - void verify(const std::string &name, int timeout = 30000); - - /** - * Check if the socket is still connected. - * - * @return true if connected - */ - virtual bool isConnected() const noexcept = 0; - - /** - * Try to connect to the host. - * - * @param timeout the maximum time in milliseconds - * @throw net::Error on errors or timeout - */ - virtual void connect(int timeout = 30000) = 0; - - /** - * Try to send the message in 30 seconds. The message must not end with \\r\\n\\r\\n, it is added automatically. - * - * @pre msg must not be empty - * @param msg the message to send - * @param timeout the maximum time in milliseconds - * @throw net::Error on errors - */ - virtual void send(std::string msg, int timeout = 30000) = 0; - - /** - * Get the next event from irccd. - * - * This functions throws if the connection is lost. - * - * @param timeout the maximum time in milliseconds - * @return the next event - * @throw net::Error on errors or disconnection - */ - virtual json::Value next(int timeout = 30000) = 0; -}; - -/** - * @class ConnectionBase - * @brief Implementation for Ip or Local. - */ -template <typename Address> -class ConnectionBase : public Connection { -private: - net::SocketTcp<Address> m_socket; - net::Listener<> m_listener; - Address m_address; - - /* Input buffer */ - std::string m_input; - -public: - /** - * Construct the socket but do not connect immediately. - * - * @param address the address - */ - ConnectionBase(Address address) - : m_address(std::move(address)) - { - m_socket.set(net::option::SockBlockMode{false}); - m_listener.set(m_socket.handle(), net::Condition::Readable); - } - - /** - * @copydoc Connection::isConnected - */ - bool isConnected() const noexcept override - { - return m_socket.state() == net::State::Connected; - } - - /** - * @copydoc Connection::connect - */ - void connect(int timeout) override; - - /** - * @copydoc Connection::send - */ - void send(std::string msg, int timeout) override; - - /** - * @copydoc Connection::next - */ - json::Value next(int timeout) override; -}; - -template <typename Address> -void ConnectionBase<Address>::connect(int timeout) -{ - m_socket.connect(m_address); - - if (m_socket.state() == net::State::Connecting) { - m_listener.set(m_socket.handle(), net::Condition::Writable); - m_listener.wait(timeout); - m_socket.connect(); - m_listener.unset(m_socket.handle(), net::Condition::Writable); - } -} - -template <typename Address> -void ConnectionBase<Address>::send(std::string msg, int timeout) -{ - assert(!msg.empty()); - - /* Add termination */ - msg += "\r\n\r\n"; - - m_listener.remove(m_socket.handle()); - m_listener.set(m_socket.handle(), net::Condition::Writable); - m_timer.reset(); - - while (!msg.empty()) { - /* Do not wait the time that is already passed */ - m_listener.wait(clamp(timeout)); - - /* Try to send at most as possible */ - msg.erase(0, m_socket.send(msg)); - } - - /* Timeout? */ - if (!msg.empty()) - throw std::runtime_error("operation timed out while sending to irccd"); -} - -template <typename Address> -json::Value ConnectionBase<Address>::next(int timeout) -{ - /* Maybe there is already something */ - std::string buffer = util::nextNetwork(m_input); - - m_listener.remove(m_socket.handle()); - m_listener.set(m_socket.handle(), net::Condition::Readable); - m_timer.reset(); - - /* Read if there is nothing */ - while (buffer.empty() && isConnected()) { - /* Wait and read */ - m_listener.wait(clamp(timeout)); - m_input += m_socket.recv(512); - - /* Finally try */ - buffer = util::nextNetwork(m_input); - } - - if (!isConnected()) - throw std::runtime_error("connection lost"); - - json::Value value(json::Buffer{buffer}); - - if (!value.isObject()) - throw std::invalid_argument("invalid message received"); - - return value; -} - -} // !irccd - -#endif // !IRCCD_CONNECTION_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/connection.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,246 @@ +/* + * connection.hpp -- value wrapper for connecting to irccd + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_CONNECTION_HPP +#define IRCCD_CONNECTION_HPP + +/** + * @file connection.hpp + * @brief Connection to irccd instance. + */ + +#include <cassert> +#include <stdexcept> + +#include <irccd/json.hpp> +#include <irccd/system.hpp> +#include <irccd/util.hpp> + +#include "elapsed-timer.hpp" +#include "sockets.hpp" + +namespace irccd { + +/** + * @class Connection + * @brief Abstract class for connecting to irccd from Ip or Local addresses. + */ +class Connection { +protected: + /** + * Timer to track elapsed time. + */ + ElapsedTimer m_timer; + + /** + * Clamp the time to wait to be sure that it will be never less than 0. + */ + inline int clamp(int timeout) noexcept + { + return timeout < 0 ? -1 : (timeout - (int)m_timer.elapsed() < 0) ? 0 : (timeout - m_timer.elapsed()); + } + +public: + /** + * Default constructor. + */ + Connection() = default; + + /** + * Default destructor. + */ + virtual ~Connection() = default; + + /** + * Wait for the next requested response. + * + * @param name the response name + * @param timeout the optional timeout + * @return the object + * @throw net::Error on errors or on timeout + */ + json::Value next(const std::string &name, int timeout = 30000); + + /** + * Just wait if the operation succeeded. + * + * @param name the response name + * @param timeout the timeout + */ + void verify(const std::string &name, int timeout = 30000); + + /** + * Check if the socket is still connected. + * + * @return true if connected + */ + virtual bool isConnected() const noexcept = 0; + + /** + * Try to connect to the host. + * + * @param timeout the maximum time in milliseconds + * @throw net::Error on errors or timeout + */ + virtual void connect(int timeout = 30000) = 0; + + /** + * Try to send the message in 30 seconds. The message must not end with \\r\\n\\r\\n, it is added automatically. + * + * @pre msg must not be empty + * @param msg the message to send + * @param timeout the maximum time in milliseconds + * @throw net::Error on errors + */ + virtual void send(std::string msg, int timeout = 30000) = 0; + + /** + * Get the next event from irccd. + * + * This functions throws if the connection is lost. + * + * @param timeout the maximum time in milliseconds + * @return the next event + * @throw net::Error on errors or disconnection + */ + virtual json::Value next(int timeout = 30000) = 0; +}; + +/** + * @class ConnectionBase + * @brief Implementation for Ip or Local. + */ +template <typename Address> +class ConnectionBase : public Connection { +private: + net::SocketTcp<Address> m_socket; + net::Listener<> m_listener; + Address m_address; + + /* Input buffer */ + std::string m_input; + +public: + /** + * Construct the socket but do not connect immediately. + * + * @param address the address + */ + ConnectionBase(Address address) + : m_address(std::move(address)) + { + m_socket.set(net::option::SockBlockMode{false}); + m_listener.set(m_socket.handle(), net::Condition::Readable); + } + + /** + * @copydoc Connection::isConnected + */ + bool isConnected() const noexcept override + { + return m_socket.state() == net::State::Connected; + } + + /** + * @copydoc Connection::connect + */ + void connect(int timeout) override; + + /** + * @copydoc Connection::send + */ + void send(std::string msg, int timeout) override; + + /** + * @copydoc Connection::next + */ + json::Value next(int timeout) override; +}; + +template <typename Address> +void ConnectionBase<Address>::connect(int timeout) +{ + m_socket.connect(m_address); + + if (m_socket.state() == net::State::Connecting) { + m_listener.set(m_socket.handle(), net::Condition::Writable); + m_listener.wait(timeout); + m_socket.connect(); + m_listener.unset(m_socket.handle(), net::Condition::Writable); + } +} + +template <typename Address> +void ConnectionBase<Address>::send(std::string msg, int timeout) +{ + assert(!msg.empty()); + + /* Add termination */ + msg += "\r\n\r\n"; + + m_listener.remove(m_socket.handle()); + m_listener.set(m_socket.handle(), net::Condition::Writable); + m_timer.reset(); + + while (!msg.empty()) { + /* Do not wait the time that is already passed */ + m_listener.wait(clamp(timeout)); + + /* Try to send at most as possible */ + msg.erase(0, m_socket.send(msg)); + } + + /* Timeout? */ + if (!msg.empty()) + throw std::runtime_error("operation timed out while sending to irccd"); +} + +template <typename Address> +json::Value ConnectionBase<Address>::next(int timeout) +{ + /* Maybe there is already something */ + std::string buffer = util::nextNetwork(m_input); + + m_listener.remove(m_socket.handle()); + m_listener.set(m_socket.handle(), net::Condition::Readable); + m_timer.reset(); + + /* Read if there is nothing */ + while (buffer.empty() && isConnected()) { + /* Wait and read */ + m_listener.wait(clamp(timeout)); + m_input += m_socket.recv(512); + + /* Finally try */ + buffer = util::nextNetwork(m_input); + } + + if (!isConnected()) + throw std::runtime_error("connection lost"); + + json::Value value(json::Buffer{buffer}); + + if (!value.isObject()) + throw std::invalid_argument("invalid message received"); + + return value; +} + +} // !irccd + +#endif // !IRCCD_CONNECTION_HPP
--- a/lib/irccd/elapsed-timer.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/elapsed-timer.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "elapsed-timer.h" +#include "elapsed-timer.hpp" using std::chrono::duration_cast; using std::chrono::high_resolution_clock;
--- a/lib/irccd/elapsed-timer.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * elapsed-timer.h -- measure elapsed time - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_ELAPSED_TIMER_H -#define IRCCD_ELAPSED_TIMER_H - -/** - * @file elapsed-timer.h - * @brief Measure elapsed time - */ - -#include <chrono> - -namespace irccd { - -/** - * @class ElapsedTimer - * @brief Measure elapsed time - * - * This class provides an abstraction to measure elapsed time since the - * construction of the object. - * - * It uses std::chrono::high_resolution_clock for more precision and uses - * milliseconds only. - */ -class ElapsedTimer { -private: - using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>; - - TimePoint m_last; - bool m_paused{false}; - unsigned m_elapsed{0}; - -public: - /** - * Construct the elapsed timer, start counting. - */ - ElapsedTimer() noexcept; - - /** - * Virtual destructor defaulted. - */ - virtual ~ElapsedTimer() = default; - - /** - * Put the timer on pause, the already elapsed time is stored. - */ - void pause() noexcept; - - /** - * Restart the timer, does not reset it. - */ - void restart() noexcept; - - /** - * Reset the timer to 0. - */ - void reset() noexcept; - - /** - * Get the number of elapsed milliseconds. - * - * @return the milliseconds - */ - unsigned elapsed() noexcept; -}; - -} // !irccd - -#endif // !IRCCD_ELAPSED_TIMER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/elapsed-timer.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,85 @@ +/* + * elapsed-timer.hpp -- measure elapsed time + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_ELAPSED_TIMER_HPP +#define IRCCD_ELAPSED_TIMER_HPP + +/** + * @file elapsed-timer.hpp + * @brief Measure elapsed time + */ + +#include <chrono> + +namespace irccd { + +/** + * @class ElapsedTimer + * @brief Measure elapsed time + * + * This class provides an abstraction to measure elapsed time since the + * construction of the object. + * + * It uses std::chrono::high_resolution_clock for more precision and uses + * milliseconds only. + */ +class ElapsedTimer { +private: + using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>; + + TimePoint m_last; + bool m_paused{false}; + unsigned m_elapsed{0}; + +public: + /** + * Construct the elapsed timer, start counting. + */ + ElapsedTimer() noexcept; + + /** + * Virtual destructor defaulted. + */ + virtual ~ElapsedTimer() = default; + + /** + * Put the timer on pause, the already elapsed time is stored. + */ + void pause() noexcept; + + /** + * Restart the timer, does not reset it. + */ + void restart() noexcept; + + /** + * Reset the timer to 0. + */ + void reset() noexcept; + + /** + * Get the number of elapsed milliseconds. + * + * @return the milliseconds + */ + unsigned elapsed() noexcept; +}; + +} // !irccd + +#endif // !IRCCD_ELAPSED_TIMER_HPP
--- a/lib/irccd/fs.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/fs.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -32,7 +32,7 @@ # include <unistd.h> #endif -#include "fs.h" +#include "fs.hpp" namespace irccd {
--- a/lib/irccd/fs.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,320 +0,0 @@ -/* - * fs.h -- filesystem operations - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_FS_H -#define IRCCD_FS_H - -/** - * @file fs.h - * @brief Filesystem operations made easy. - * - * The following options can be set by the user: - * - * - **HAVE_ACCESS**: (bool) Set to true if unistd.h file and access(2) function are available. - * - * On Windows, you must link to shlwapi library. - */ - -#include <sys/stat.h> - -#include <regex> -#include <string> -#include <vector> - -namespace irccd { - -namespace fs { - -/** - * @enum Flags - * @brief Flags for readdir. - */ -enum Flags { - Dot = (1 << 0), //!< if set, also lists "." - DotDot = (1 << 1) //!< if set, also lists ".." -}; - -/** - * @class Entry - * @brief Entry in the directory list. - */ -class Entry { -public: - /** - * @brief Describe the type of an entry - */ - enum Type : char { - Unknown, //!< File type is unknown, - File, //!< File is regular type, - Dir, //!< File is directory, - Link //!< File is link - }; - - std::string name; //! name of entry (base name) - Type type{Unknown}; //! type of file -}; - -/** - * Check if two entries are identical. - * - * @param e1 the first entry - * @param e2 the second entry - * @return true if they are identical - */ -bool operator==(const Entry &e1, const Entry &e2) noexcept; - -/** - * Check if two entries are different. - * - * @param e1 the first entry - * @param e2 the second entry - * @return true if they are different - */ -bool operator!=(const Entry &e1, const Entry &e2) noexcept; - -/** - * Get the separator for that system. - * - * @return \ on Windows and / otherwise - */ -inline char separator() noexcept -{ -#if defined(_WIN32) - return '\\'; -#else - return '/'; -#endif -} - -/** - * Clean a path by removing any extra / or \ and add a trailing one. - * - * @param path the path - * @return the updated path - */ -std::string clean(std::string path); - -/** - * Get the base name from a path. - * - * Example, baseName("/etc/foo.conf") // foo.conf - * - * @param path the path - * @return the base name - */ -std::string baseName(std::string path); - -/** - * Get the parent directory from a path. - * - * Example, dirName("/etc/foo.conf") // /etc - * - * @param path the path - * @return the parent directory - */ -std::string dirName(std::string path); - -/** - * Get stat information. - * - * @param path the path - * @return the stat information - * @throw std::runtime_error on failure - */ -struct stat stat(const std::string &path); - -/** - * Check if a file exists. - * - * If HAVE_ACCESS is defined, the function access is used, otherwise stat is used. - * - * @param path the path to check - * @return true if the path exists - */ -bool exists(const std::string &path) noexcept; - -/** - * Check if the path is absolute. - * - * @param path the path - * @return true if the path is absolute - */ -bool isAbsolute(const std::string &path) noexcept; - -/** - * Check if the path is relative. - * - * @param path the path - * @return true if the path is absolute - */ -bool isRelative(const std::string &path) noexcept; - -/** - * Check if the file is readable. - * - * @param path the path - * @return true if has read access - */ -bool isReadable(const std::string &path) noexcept; - -/** - * Check if the file is writable. - * - * @param path the path - * @return true if has write access - */ -bool isWritable(const std::string &path) noexcept; - -/** - * Check if the file is a regular file. - * - * @param path the path - * @return true if it is a file and false if not or not readable - */ -bool isFile(const std::string &path) noexcept; - -/** - * Check if the file is a directory. - * - * @param path the path - * @return true if it is a directory and false if not or not readable - */ -bool isDirectory(const std::string &path) noexcept; - -/** - * Check if the file is a symbolic link. - * - * @param path the path - * @return true if it is a symbolic link and false if not or not readable - */ -bool isSymlink(const std::string &path) noexcept; - -/** - * Read a directory and return a list of entries (not recursive). - * - * @param path the directory path - * @param flags the optional flags (see Flags) - * @return the list of entries - * @throw std::runtime_error on failure - */ -std::vector<Entry> readdir(const std::string &path, int flags = 0); - -/** - * Create a directory recursively. - * - * @param path the path - * @param mode the optional mode (not always supported) - * @throw std::runtime_error on failure - * @post all intermediate directories are created - */ -void mkdir(const std::string &path, int mode = 0700); - -/** - * Remove a directory recursively. - * - * If errors happens, they are silently discarded to remove as much as possible. - * - * @param path the path - */ -void rmdir(const std::string &path) noexcept; - -/** - * Search an item recursively. - * - * The predicate must have the following signature: - * void f(const std::string &base, const Entry &entry) - * - * Where: - * - base is the current parent directory in the tree - * - entry is the current entry - * - * @param base the base directory - * @param predicate the predicate - * @return the full path name to the file or empty string if never found - * @throw std::runtime_error on read errors - */ -template <typename Predicate> -std::string findIf(const std::string &base, Predicate &&predicate) -{ - /* - * Do not go deeply to the tree before testing all files in the current directory for performances reasons, we iterate - * this directory to search for the entry name and iterate again over all sub directories if not found. - */ - std::string path; - std::vector<Entry> entries = readdir(base); - - for (const auto &entry : entries) { - if (predicate(base, entry)) { - path = base + separator() + entry.name; - break; - } - } - - if (path.empty()) { - for (const auto &entry : entries) { - if (entry.type == Entry::Dir) { - path = findIf(base + separator() + entry.name, std::forward<Predicate>(predicate)); - - if (!path.empty()) - break; - } - } - } - - return path; -} - -/** - * Find a file by name recursively. - * - * @param base the base directory - * @param name the file name - * @return the full path name to the file or empty string if never found - * @throw std::runtime_error on read errors - */ -inline std::string find(const std::string &base, const std::string &name) -{ - return findIf(base, [&] (const auto &, const auto &entry) { return entry.name == name; }); -} - -/** - * Overload by regular expression. - * - * @param base the base directory - * @param regex the regular expression - * @return the full path name to the file or empty string if never found - * @throw std::runtime_error on read errors - */ -inline std::string find(const std::string &base, const std::regex ®ex) -{ - return findIf(base, [&] (const auto &, const auto &entry) { return std::regex_match(entry.name, regex); }); -} - -/** - * Get the current working directory. - * - * @return the current working directory - * @throw std::runtime_error on failure - */ -std::string cwd(); - -} // !fs - -} // !irccd - -#endif // !IRCCD_FS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/fs.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,320 @@ +/* + * fs.hpp -- filesystem operations + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_FS_HPP +#define IRCCD_FS_HPP + +/** + * @file fs.hpp + * @brief Filesystem operations made easy. + * + * The following options can be set by the user: + * + * - **HAVE_ACCESS**: (bool) Set to true if unistd.h file and access(2) function are available. + * + * On Windows, you must link to shlwapi library. + */ + +#include <sys/stat.h> + +#include <regex> +#include <string> +#include <vector> + +namespace irccd { + +namespace fs { + +/** + * @enum Flags + * @brief Flags for readdir. + */ +enum Flags { + Dot = (1 << 0), //!< if set, also lists "." + DotDot = (1 << 1) //!< if set, also lists ".." +}; + +/** + * @class Entry + * @brief Entry in the directory list. + */ +class Entry { +public: + /** + * @brief Describe the type of an entry + */ + enum Type : char { + Unknown, //!< File type is unknown, + File, //!< File is regular type, + Dir, //!< File is directory, + Link //!< File is link + }; + + std::string name; //! name of entry (base name) + Type type{Unknown}; //! type of file +}; + +/** + * Check if two entries are identical. + * + * @param e1 the first entry + * @param e2 the second entry + * @return true if they are identical + */ +bool operator==(const Entry &e1, const Entry &e2) noexcept; + +/** + * Check if two entries are different. + * + * @param e1 the first entry + * @param e2 the second entry + * @return true if they are different + */ +bool operator!=(const Entry &e1, const Entry &e2) noexcept; + +/** + * Get the separator for that system. + * + * @return \ on Windows and / otherwise + */ +inline char separator() noexcept +{ +#if defined(_WIN32) + return '\\'; +#else + return '/'; +#endif +} + +/** + * Clean a path by removing any extra / or \ and add a trailing one. + * + * @param path the path + * @return the updated path + */ +std::string clean(std::string path); + +/** + * Get the base name from a path. + * + * Example, baseName("/etc/foo.conf") // foo.conf + * + * @param path the path + * @return the base name + */ +std::string baseName(std::string path); + +/** + * Get the parent directory from a path. + * + * Example, dirName("/etc/foo.conf") // /etc + * + * @param path the path + * @return the parent directory + */ +std::string dirName(std::string path); + +/** + * Get stat information. + * + * @param path the path + * @return the stat information + * @throw std::runtime_error on failure + */ +struct stat stat(const std::string &path); + +/** + * Check if a file exists. + * + * If HAVE_ACCESS is defined, the function access is used, otherwise stat is used. + * + * @param path the path to check + * @return true if the path exists + */ +bool exists(const std::string &path) noexcept; + +/** + * Check if the path is absolute. + * + * @param path the path + * @return true if the path is absolute + */ +bool isAbsolute(const std::string &path) noexcept; + +/** + * Check if the path is relative. + * + * @param path the path + * @return true if the path is absolute + */ +bool isRelative(const std::string &path) noexcept; + +/** + * Check if the file is readable. + * + * @param path the path + * @return true if has read access + */ +bool isReadable(const std::string &path) noexcept; + +/** + * Check if the file is writable. + * + * @param path the path + * @return true if has write access + */ +bool isWritable(const std::string &path) noexcept; + +/** + * Check if the file is a regular file. + * + * @param path the path + * @return true if it is a file and false if not or not readable + */ +bool isFile(const std::string &path) noexcept; + +/** + * Check if the file is a directory. + * + * @param path the path + * @return true if it is a directory and false if not or not readable + */ +bool isDirectory(const std::string &path) noexcept; + +/** + * Check if the file is a symbolic link. + * + * @param path the path + * @return true if it is a symbolic link and false if not or not readable + */ +bool isSymlink(const std::string &path) noexcept; + +/** + * Read a directory and return a list of entries (not recursive). + * + * @param path the directory path + * @param flags the optional flags (see Flags) + * @return the list of entries + * @throw std::runtime_error on failure + */ +std::vector<Entry> readdir(const std::string &path, int flags = 0); + +/** + * Create a directory recursively. + * + * @param path the path + * @param mode the optional mode (not always supported) + * @throw std::runtime_error on failure + * @post all intermediate directories are created + */ +void mkdir(const std::string &path, int mode = 0700); + +/** + * Remove a directory recursively. + * + * If errors happens, they are silently discarded to remove as much as possible. + * + * @param path the path + */ +void rmdir(const std::string &path) noexcept; + +/** + * Search an item recursively. + * + * The predicate must have the following signature: + * void f(const std::string &base, const Entry &entry) + * + * Where: + * - base is the current parent directory in the tree + * - entry is the current entry + * + * @param base the base directory + * @param predicate the predicate + * @return the full path name to the file or empty string if never found + * @throw std::runtime_error on read errors + */ +template <typename Predicate> +std::string findIf(const std::string &base, Predicate &&predicate) +{ + /* + * Do not go deeply to the tree before testing all files in the current directory for performances reasons, we iterate + * this directory to search for the entry name and iterate again over all sub directories if not found. + */ + std::string path; + std::vector<Entry> entries = readdir(base); + + for (const auto &entry : entries) { + if (predicate(base, entry)) { + path = base + separator() + entry.name; + break; + } + } + + if (path.empty()) { + for (const auto &entry : entries) { + if (entry.type == Entry::Dir) { + path = findIf(base + separator() + entry.name, std::forward<Predicate>(predicate)); + + if (!path.empty()) + break; + } + } + } + + return path; +} + +/** + * Find a file by name recursively. + * + * @param base the base directory + * @param name the file name + * @return the full path name to the file or empty string if never found + * @throw std::runtime_error on read errors + */ +inline std::string find(const std::string &base, const std::string &name) +{ + return findIf(base, [&] (const auto &, const auto &entry) { return entry.name == name; }); +} + +/** + * Overload by regular expression. + * + * @param base the base directory + * @param regex the regular expression + * @return the full path name to the file or empty string if never found + * @throw std::runtime_error on read errors + */ +inline std::string find(const std::string &base, const std::regex ®ex) +{ + return findIf(base, [&] (const auto &, const auto &entry) { return std::regex_match(entry.name, regex); }); +} + +/** + * Get the current working directory. + * + * @return the current working directory + * @throw std::runtime_error on failure + */ +std::string cwd(); + +} // !fs + +} // !irccd + +#endif // !IRCCD_FS_HPP
--- a/lib/irccd/ini.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/ini.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -29,7 +29,7 @@ # include <Shlwapi.h> // for PathIsRelative #endif -#include "ini.h" +#include "ini.hpp" namespace {
--- a/lib/irccd/ini.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,538 +0,0 @@ -/* - * ini.h -- .ini file parsing - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_INI_H -#define IRCCD_INI_H - -/** - * @file ini.h - * @brief Configuration file parser. - */ - -#include <algorithm> -#include <exception> -#include <stdexcept> -#include <string> -#include <vector> - -namespace irccd { - -/** - * Namespace for ini related classes. - */ -namespace ini { - -class Document; - -/** - * @class Error - * @brief Error in a file - */ -class Error : public std::exception { -private: - int m_line; //!< line number - int m_column; //!< line column - std::string m_message; //!< error message - -public: - /** - * Constructor. - * - * @param l the line - * @param c the column - * @param m the message - */ - inline Error(int l, int c, std::string m) noexcept - : m_line(l) - , m_column(c) - , m_message(std::move(m)) - { - } - - /** - * Get the line number. - * - * @return the line - */ - inline int line() const noexcept - { - return m_line; - } - - /** - * Get the column number. - * - * @return the column - */ - inline int column() const noexcept - { - return m_column; - } - - /** - * Return the raw error message (no line and column shown). - * - * @return the error message - */ - const char *what() const noexcept override - { - return m_message.c_str(); - } -}; - -/** - * @class Token - * @brief Describe a token read in the .ini source - * - * This class can be used when you want to parse a .ini file yourself. - * - * @see Document::analyze - */ -class Token { -public: - /** - * @brief Token type - */ - enum Type { - Include, //!< include statement - Section, //!< [section] - Word, //!< word without quotes - QuotedWord, //!< word with quotes - Assign, //!< = assignment - ListBegin, //!< begin of list ( - ListEnd, //!< end of list ) - Comma //!< list separation - }; - -private: - Type m_type; - int m_line; - int m_column; - std::string m_value; - -public: - /** - * Construct a token. - * - * @param type the type - * @param line the line - * @param column the column - * @param value the value - */ - Token(Type type, int line, int column, std::string value = "") noexcept - : m_type(type) - , m_line(line) - , m_column(column) - { - switch (type) { - case Include: - m_value = "@include"; - break; - case Section: - case Word: - case QuotedWord: - m_value = value; - break; - case Assign: - m_value = "="; - break; - case ListBegin: - m_value = "("; - break; - case ListEnd: - m_value = ")"; - break; - case Comma: - m_value = ","; - break; - default: - break; - } - } - - /** - * Get the type. - * - * @return the type - */ - inline Type type() const noexcept - { - return m_type; - } - - /** - * Get the line. - * - * @return the line - */ - inline int line() const noexcept - { - return m_line; - } - - /** - * Get the column. - * - * @return the column - */ - inline int column() const noexcept - { - return m_column; - } - - /** - * Get the value. For words, quoted words and section, the value is the content. Otherwise it's the - * characters parsed. - * - * @return the value - */ - inline const std::string &value() const noexcept - { - return m_value; - } -}; - -/** - * List of tokens in order they are analyzed. - */ -using Tokens = std::vector<Token>; - -/** - * @class Option - * @brief Option definition. - */ -class Option : public std::vector<std::string> { -private: - std::string m_key; - -public: - /** - * Construct an empty option. - * - * @param key the key - * @param value the value - */ - inline Option(std::string key) noexcept - : std::vector<std::string>() - , m_key(std::move(key)) - { - } - - /** - * Construct a single option. - * - * @param key the key - * @param value the value - */ - inline Option(std::string key, std::string value) noexcept - : m_key(std::move(key)) - { - push_back(std::move(value)); - } - - /** - * Construct a list option. - * - * @param key the key - * @param values the values - */ - inline Option(std::string key, std::vector<std::string> values) noexcept - : std::vector<std::string>(std::move(values)) - , m_key(std::move(key)) - { - } - - /** - * Get the option key. - * - * @return the key - */ - inline const std::string &key() const noexcept - { - return m_key; - } - - /** - * Get the option value. - * - * @return the value - */ - inline const std::string &value() const noexcept - { - static std::string dummy; - - return empty() ? dummy : (*this)[0]; - } -}; - -/** - * @class Section - * @brief Section that contains one or more options. - */ -class Section : public std::vector<Option> { -private: - std::string m_key; - -public: - /** - * Construct a section with its name. - * - * @param key the key - */ - inline Section(std::string key) noexcept - : m_key(std::move(key)) - { - } - - /** - * Get the section key. - * - * @return the key - */ - inline const std::string &key() const noexcept - { - return m_key; - } - - /** - * Check if the section contains a specific option. - * - * @param key the option key - * @return true if the option exists - */ - inline bool contains(const std::string &key) const noexcept - { - return find(key) != end(); - } - - /** - * Access an option at the specified key. - * - * @param key the key - * @return the option - * @throw std::out_of_range if the key does not exist - */ - inline Option &operator[](const std::string &key) - { - return *find(key); - } - - /** - * Access an option at the specified key. - * - * @param key the key - * @return the option - * @throw std::out_of_range if the key does not exist - */ - inline const Option &operator[](const std::string &key) const - { - return *find(key); - } - - /** - * Find an option by key and return an iterator. - * - * @param key the key - * @return the iterator or end() if not found - */ - inline iterator find(const std::string &key) noexcept - { - return std::find_if(begin(), end(), [&] (const auto &o) { - return o.key() == key; - }); - } - - /** - * Find an option by key and return an iterator. - * - * @param key the key - * @return the iterator or end() if not found - */ - inline const_iterator find(const std::string &key) const noexcept - { - return std::find_if(cbegin(), cend(), [&] (const auto &o) { - return o.key() == key; - }); - } - - /** - * Inherited operators. - */ - using std::vector<Option>::operator[]; -}; - -/** - * @class File - * @brief Source for reading .ini files. - */ -class File { -public: - /** - * Path to the file. - */ - std::string path; -}; - -/** - * @class Buffer - * @brief Source for reading ini from text. - * @note the include statement is not supported with buffers. - */ -class Buffer { -public: - /** - * The ini content. - */ - std::string text; -}; - -/** - * @class Document - * @brief Ini config file loader - */ -class Document : public std::vector<Section> { -private: - std::string m_path; - -public: - /** - * Analyze a file and extract tokens. If the function succeeds, that does not mean the content is valid, - * it just means that there are no syntax error. - * - * For example, this class does not allow adding options under no sections and this function will not - * detect that issue. - * - * @param file the file to read - * @return the list of tokens - * @throws Error on errors - */ - static Tokens analyze(const File &file); - - /** - * Overloaded function for buffers. - * - * @param buffer the buffer to read - * @return the list of tokens - * @throws Error on errors - */ - static Tokens analyze(const Buffer &buffer); - - /** - * Show all tokens and their description. - * - * @param tokens the tokens - */ - static void dump(const Tokens &tokens); - - /** - * Construct a document from a file. - * - * @param file the file to read - * @throws Error on errors - */ - Document(const File &file); - - /** - * Overloaded constructor for buffers. - * - * @param buffer the buffer to read - * @throws Error on errors - */ - Document(const Buffer &buffer); - - /** - * Get the current document path, only useful when constructed from File source. - * - * @return the path - */ - inline const std::string &path() const noexcept - { - return m_path; - } - - /** - * Check if a document has a specific section. - * - * @param key the key - */ - inline bool contains(const std::string &key) const noexcept - { - return std::find_if(begin(), end(), [&] (const auto &sc) { return sc.key() == key; }) != end(); - } - - /** - * Access a section at the specified key. - * - * @param key the key - * @return the section - * @throw std::out_of_range if the key does not exist - */ - inline Section &operator[](const std::string &key) - { - return *find(key); - } - - /** - * Access a section at the specified key. - * - * @param key the key - * @return the section - * @throw std::out_of_range if the key does not exist - */ - inline const Section &operator[](const std::string &key) const - { - return *find(key); - } - - /** - * Find a section by key and return an iterator. - * - * @param key the key - * @return the iterator or end() if not found - */ - inline iterator find(const std::string &key) noexcept - { - return std::find_if(begin(), end(), [&] (const auto &o) { - return o.key() == key; - }); - } - - /** - * Find a section by key and return an iterator. - * - * @param key the key - * @return the iterator or end() if not found - */ - inline const_iterator find(const std::string &key) const noexcept - { - return std::find_if(cbegin(), cend(), [&] (const auto &o) { - return o.key() == key; - }); - } - - /** - * Inherited operators. - */ - using std::vector<Section>::operator[]; -}; - -} // !ini - -} // !irccd - -#endif // !IRCCD_INI_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/ini.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,538 @@ +/* + * ini.hpp -- .ini file parsing + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_INI_HPP +#define IRCCD_INI_HPP + +/** + * @file ini.hpp + * @brief Configuration file parser. + */ + +#include <algorithm> +#include <exception> +#include <stdexcept> +#include <string> +#include <vector> + +namespace irccd { + +/** + * Namespace for ini related classes. + */ +namespace ini { + +class Document; + +/** + * @class Error + * @brief Error in a file + */ +class Error : public std::exception { +private: + int m_line; //!< line number + int m_column; //!< line column + std::string m_message; //!< error message + +public: + /** + * Constructor. + * + * @param l the line + * @param c the column + * @param m the message + */ + inline Error(int l, int c, std::string m) noexcept + : m_line(l) + , m_column(c) + , m_message(std::move(m)) + { + } + + /** + * Get the line number. + * + * @return the line + */ + inline int line() const noexcept + { + return m_line; + } + + /** + * Get the column number. + * + * @return the column + */ + inline int column() const noexcept + { + return m_column; + } + + /** + * Return the raw error message (no line and column shown). + * + * @return the error message + */ + const char *what() const noexcept override + { + return m_message.c_str(); + } +}; + +/** + * @class Token + * @brief Describe a token read in the .ini source + * + * This class can be used when you want to parse a .ini file yourself. + * + * @see Document::analyze + */ +class Token { +public: + /** + * @brief Token type + */ + enum Type { + Include, //!< include statement + Section, //!< [section] + Word, //!< word without quotes + QuotedWord, //!< word with quotes + Assign, //!< = assignment + ListBegin, //!< begin of list ( + ListEnd, //!< end of list ) + Comma //!< list separation + }; + +private: + Type m_type; + int m_line; + int m_column; + std::string m_value; + +public: + /** + * Construct a token. + * + * @param type the type + * @param line the line + * @param column the column + * @param value the value + */ + Token(Type type, int line, int column, std::string value = "") noexcept + : m_type(type) + , m_line(line) + , m_column(column) + { + switch (type) { + case Include: + m_value = "@include"; + break; + case Section: + case Word: + case QuotedWord: + m_value = value; + break; + case Assign: + m_value = "="; + break; + case ListBegin: + m_value = "("; + break; + case ListEnd: + m_value = ")"; + break; + case Comma: + m_value = ","; + break; + default: + break; + } + } + + /** + * Get the type. + * + * @return the type + */ + inline Type type() const noexcept + { + return m_type; + } + + /** + * Get the line. + * + * @return the line + */ + inline int line() const noexcept + { + return m_line; + } + + /** + * Get the column. + * + * @return the column + */ + inline int column() const noexcept + { + return m_column; + } + + /** + * Get the value. For words, quoted words and section, the value is the content. Otherwise it's the + * characters parsed. + * + * @return the value + */ + inline const std::string &value() const noexcept + { + return m_value; + } +}; + +/** + * List of tokens in order they are analyzed. + */ +using Tokens = std::vector<Token>; + +/** + * @class Option + * @brief Option definition. + */ +class Option : public std::vector<std::string> { +private: + std::string m_key; + +public: + /** + * Construct an empty option. + * + * @param key the key + * @param value the value + */ + inline Option(std::string key) noexcept + : std::vector<std::string>() + , m_key(std::move(key)) + { + } + + /** + * Construct a single option. + * + * @param key the key + * @param value the value + */ + inline Option(std::string key, std::string value) noexcept + : m_key(std::move(key)) + { + push_back(std::move(value)); + } + + /** + * Construct a list option. + * + * @param key the key + * @param values the values + */ + inline Option(std::string key, std::vector<std::string> values) noexcept + : std::vector<std::string>(std::move(values)) + , m_key(std::move(key)) + { + } + + /** + * Get the option key. + * + * @return the key + */ + inline const std::string &key() const noexcept + { + return m_key; + } + + /** + * Get the option value. + * + * @return the value + */ + inline const std::string &value() const noexcept + { + static std::string dummy; + + return empty() ? dummy : (*this)[0]; + } +}; + +/** + * @class Section + * @brief Section that contains one or more options. + */ +class Section : public std::vector<Option> { +private: + std::string m_key; + +public: + /** + * Construct a section with its name. + * + * @param key the key + */ + inline Section(std::string key) noexcept + : m_key(std::move(key)) + { + } + + /** + * Get the section key. + * + * @return the key + */ + inline const std::string &key() const noexcept + { + return m_key; + } + + /** + * Check if the section contains a specific option. + * + * @param key the option key + * @return true if the option exists + */ + inline bool contains(const std::string &key) const noexcept + { + return find(key) != end(); + } + + /** + * Access an option at the specified key. + * + * @param key the key + * @return the option + * @throw std::out_of_range if the key does not exist + */ + inline Option &operator[](const std::string &key) + { + return *find(key); + } + + /** + * Access an option at the specified key. + * + * @param key the key + * @return the option + * @throw std::out_of_range if the key does not exist + */ + inline const Option &operator[](const std::string &key) const + { + return *find(key); + } + + /** + * Find an option by key and return an iterator. + * + * @param key the key + * @return the iterator or end() if not found + */ + inline iterator find(const std::string &key) noexcept + { + return std::find_if(begin(), end(), [&] (const auto &o) { + return o.key() == key; + }); + } + + /** + * Find an option by key and return an iterator. + * + * @param key the key + * @return the iterator or end() if not found + */ + inline const_iterator find(const std::string &key) const noexcept + { + return std::find_if(cbegin(), cend(), [&] (const auto &o) { + return o.key() == key; + }); + } + + /** + * Inherited operators. + */ + using std::vector<Option>::operator[]; +}; + +/** + * @class File + * @brief Source for reading .ini files. + */ +class File { +public: + /** + * Path to the file. + */ + std::string path; +}; + +/** + * @class Buffer + * @brief Source for reading ini from text. + * @note the include statement is not supported with buffers. + */ +class Buffer { +public: + /** + * The ini content. + */ + std::string text; +}; + +/** + * @class Document + * @brief Ini config file loader + */ +class Document : public std::vector<Section> { +private: + std::string m_path; + +public: + /** + * Analyze a file and extract tokens. If the function succeeds, that does not mean the content is valid, + * it just means that there are no syntax error. + * + * For example, this class does not allow adding options under no sections and this function will not + * detect that issue. + * + * @param file the file to read + * @return the list of tokens + * @throws Error on errors + */ + static Tokens analyze(const File &file); + + /** + * Overloaded function for buffers. + * + * @param buffer the buffer to read + * @return the list of tokens + * @throws Error on errors + */ + static Tokens analyze(const Buffer &buffer); + + /** + * Show all tokens and their description. + * + * @param tokens the tokens + */ + static void dump(const Tokens &tokens); + + /** + * Construct a document from a file. + * + * @param file the file to read + * @throws Error on errors + */ + Document(const File &file); + + /** + * Overloaded constructor for buffers. + * + * @param buffer the buffer to read + * @throws Error on errors + */ + Document(const Buffer &buffer); + + /** + * Get the current document path, only useful when constructed from File source. + * + * @return the path + */ + inline const std::string &path() const noexcept + { + return m_path; + } + + /** + * Check if a document has a specific section. + * + * @param key the key + */ + inline bool contains(const std::string &key) const noexcept + { + return std::find_if(begin(), end(), [&] (const auto &sc) { return sc.key() == key; }) != end(); + } + + /** + * Access a section at the specified key. + * + * @param key the key + * @return the section + * @throw std::out_of_range if the key does not exist + */ + inline Section &operator[](const std::string &key) + { + return *find(key); + } + + /** + * Access a section at the specified key. + * + * @param key the key + * @return the section + * @throw std::out_of_range if the key does not exist + */ + inline const Section &operator[](const std::string &key) const + { + return *find(key); + } + + /** + * Find a section by key and return an iterator. + * + * @param key the key + * @return the iterator or end() if not found + */ + inline iterator find(const std::string &key) noexcept + { + return std::find_if(begin(), end(), [&] (const auto &o) { + return o.key() == key; + }); + } + + /** + * Find a section by key and return an iterator. + * + * @param key the key + * @return the iterator or end() if not found + */ + inline const_iterator find(const std::string &key) const noexcept + { + return std::find_if(cbegin(), cend(), [&] (const auto &o) { + return o.key() == key; + }); + } + + /** + * Inherited operators. + */ + using std::vector<Section>::operator[]; +}; + +} // !ini + +} // !irccd + +#endif // !IRCCD_INI_HPP
--- a/lib/irccd/irccd.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/irccd.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -19,11 +19,11 @@ #include <algorithm> #include <stdexcept> -#include "irccd.h" -#include "fs.h" -#include "logger.h" -#include "path.h" -#include "util.h" +#include "irccd.hpp" +#include "fs.hpp" +#include "logger.hpp" +#include "path.hpp" +#include "util.hpp" using namespace std; using namespace std::placeholders;
--- a/lib/irccd/irccd.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,543 +0,0 @@ -/* - * irccd.h -- main irccd class - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_H -#define IRCCD_H - -/** - * @file irccd.h - * @brief Base class for irccd front end. - */ - -#include <atomic> -#include <cassert> -#include <condition_variable> -#include <functional> -#include <memory> -#include <mutex> -#include <vector> - -#include <irccd/sysconfig.h> - -#include "sockets.h" - -#if defined(WITH_JS) -# include "plugin.h" -#endif - -#include "application.h" -#include "logger.h" -#include "rule.h" -#include "server.h" -#include "transport-server.h" - -namespace irccd { - -class Plugin; -class TransportCommand; - -/** - * Event to execute after the poll. - */ -using Event = std::function<void ()>; - -/** - * List of events. - */ -using Events = std::vector<Event>; - -/** - * Map of identities. - */ -using Identities = std::unordered_map<std::string, ServerIdentity>; - -/** - * List of rules. - */ -using Rules = std::vector<Rule>; - -/** - * @class ServerEvent - * @brief Structure that owns several informations about an IRC event - * - * This structure is used to dispatch the IRC event to the plugins and the transports. - */ -class ServerEvent { -public: - std::string server; //!< the server - std::string origin; //!< the originator - std::string target; //!< the target - std::string json; //!< the JSON message -#if defined(WITH_JS) - std::function<std::string (Plugin &)> name; //!< the function to event name - std::function<void (Plugin &)> exec; //!< the plugin function to call -#endif -}; - -/** - * Map of servers. - */ -using Servers = std::unordered_map<std::string, std::shared_ptr<Server>>; - -/** - * Map of transport command handlers. - */ -using TransportCommands = std::unordered_map<std::string, std::unique_ptr<TransportCommand>>; - -#if defined(WITH_JS) - -/** - * Map of plugins. - */ -using Plugins = std::unordered_map<std::string, std::shared_ptr<Plugin>>; - -/** - * Map of plugin configurations. - */ -using PluginConfigs = std::unordered_map<std::string, PluginConfig>; - -#endif - -/** - * @class Irccd - * @brief Irccd main instance - * - * This class is used as the main application event loop, it stores servers, plugins and transports. - * - * In a general manner, no code in irccd is thread-safe because irccd is mono-threaded except the JavaScript timer - * API. - * - * If you plan to add more threads to irccd, then the simpliest and safest way to execute thread-safe code is to - * register an event using Irccd::post function which will be called during the event loop dispatching. - * - * Thus, except noticed as thread-safe, no function is assumed to be. - */ -class Irccd : public Application { -private: - template <typename T> - using LookupTable = std::unordered_map<net::Handle, std::shared_ptr<T>>; - - /* Main loop */ - std::atomic<bool> m_running{true}; - - /* Mutex for post() */ - std::mutex m_mutex; - - /* IPC */ - net::SocketTcp<net::address::Ip> m_socketServer; - net::SocketTcp<net::address::Ip> m_socketClient; - - /* Event loop */ - Events m_events; - - /* Servers */ - Servers m_servers; - - /* Optional JavaScript plugins */ -#if defined(WITH_JS) - Plugins m_plugins; - PluginConfigs m_pluginConf; -#endif - - /* Identities */ - Identities m_identities; - - /* Rules */ - Rules m_rules; - - /* Lookup tables */ - LookupTable<TransportClient> m_lookupTransportClients; - LookupTable<TransportServer> m_lookupTransportServers; - - /* - * Server slots - * ---------------------------------------------------------- - */ - - void handleServerChannelMode(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string mode, std::string arg); - void handleServerChannelNotice(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string notice); - void handleServerConnect(std::weak_ptr<Server> server); - void handleServerInvite(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string target); - void handleServerJoin(std::weak_ptr<Server> server, std::string origin, std::string channel); - void handleServerKick(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string target, std::string reason); - void handleServerMessage(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string message); - void handleServerMe(std::weak_ptr<Server> server, std::string origin, std::string target, std::string message); - void handleServerMode(std::weak_ptr<Server> server, std::string origin, std::string mode); - void handleServerNames(std::weak_ptr<Server> server, std::string channel, std::set<std::string> nicknames); - void handleServerNick(std::weak_ptr<Server> server, std::string origin, std::string nickname); - void handleServerNotice(std::weak_ptr<Server> server, std::string origin, std::string message); - void handleServerPart(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string reason); - void handleServerQuery(std::weak_ptr<Server> server, std::string origin, std::string message); - void handleServerTopic(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string topic); - void handleServerWhois(std::weak_ptr<Server> server, ServerWhois whois); - - /* - * Transport clients slots - * ---------------------------------------------------------- - */ - void handleTransportCommand(std::weak_ptr<TransportClient>, const json::Value &); - void handleTransportDie(std::weak_ptr<TransportClient>); - - /* - * Plugin timers slots - * ---------------------------------------------------------- - * - * These handlers catch the timer signals and call the plugin function or remove the timer from the plugin. - */ - -#if defined(WITH_JS) - void handleTimerSignal(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); - void handleTimerEnd(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); -#endif - - /* - * Process the socket sets. - * ---------------------------------------------------------- - * - * These functions are called after polling which sockets are ready for reading/writing. - */ - - void processIpc(fd_set &input); - void processTransportClients(fd_set &input, fd_set &output); - void processTransportServers(fd_set &input); - void processServers(fd_set &input, fd_set &output); - void process(fd_set &setinput, fd_set &setoutput); - -public: - /** - * Constructor that instanciate IPC. - */ - Irccd(); - - /** - * Load a configuration into irccd. Added as convenience to allow expressions like `irccd.load(Config{"foo"})`. - * - * @param config the configuration loader - */ - template <typename T> - inline void load(T &&config) - { - config.load(*this); - } - - /** - * Add an event to the queue. This will immediately signals the event loop to interrupt itself to dispatch - * the pending events. - * - * @param ev the event - * @note Thread-safe - */ - void post(Event ev) noexcept; - - /** - * This function wraps post() to iterate over all plugins to call the function and to send to all - * connected transport the event. - * - * @param ev the event - */ - void postServerEvent(ServerEvent ev) noexcept; - - /* - * Identity management - * ---------------------------------------------------------- - * - * Functions to get or add new identities. - */ - - /** - * Add an identity. - * - * @param identity the identity - * @note If the identity already exists, it is overriden - */ - inline void addIdentity(ServerIdentity identity) noexcept - { - m_identities.emplace(identity.name, std::move(identity)); - } - - /** - * Get an identity, if not found, the default one is used. - * - * @param name the identity name - * @return the identity or default one - */ - inline ServerIdentity findIdentity(const std::string &name) const noexcept - { - auto it = m_identities.find(name); - - return it == m_identities.end() ? ServerIdentity() : it->second; - } - - /* - * Server management - * ---------------------------------------------------------- - * - * Functions to get or create new servers. - * - * Servers that are added to this instance are automatically polled when run() is called. - */ - - /** - * Check if a server exists. - * - * @param name the name - * @return true if exists - */ - inline bool hasServer(const std::string &name) const noexcept - { - return m_servers.count(name) > 0; - } - - /** - * Add a new server to the application. - * - * @pre hasServer must return false - * @param sv the server - */ - void addServer(std::shared_ptr<Server> sv) noexcept; - - /** - * Get a server or empty one if not found - * - * @param name the server name - * @return the server or empty one if not found - */ - std::shared_ptr<Server> getServer(const std::string &name) const noexcept; - - /** - * Find a server by name. - * - * @param name the server name - * @return the server - * @throw std::out_of_range if the server does not exist - */ - std::shared_ptr<Server> requireServer(const std::string &name) const; - - /** - * Get the map of loaded servers. - * - * @return the servers - */ - inline const Servers &servers() const noexcept - { - return m_servers; - } - - /** - * Remove a server from the irccd instance. - * - * The server if any, will be disconnected. - * - * @param name the server name - */ - void removeServer(const std::string &name); - - /** - * Remove all servers. - * - * All servers will be disconnected. - */ - void clearServers() noexcept; - - /* - * Transport management - * ---------------------------------------------------------- - * - * Functions for adding new transport servers. - */ - - /** - * Add a transport server. - * - * @param ts the transport server - */ - void addTransport(std::shared_ptr<TransportServer> ts); - - /* - * Plugin management - * ---------------------------------------------------------- - * - * Functions for loading JavaScript plugins. - */ - -#if defined(WITH_JS) - /** - * Check if a plugin is loaded. - * - * @param name the plugin id - * @return true if has plugin - */ - inline bool hasPlugin(const std::string &name) const noexcept - { - return m_plugins.count(name) > 0; - } - - /** - * Get a plugin or empty one if not found. - * - * @param name the plugin id - * @return the plugin or empty one if not found - */ - std::shared_ptr<Plugin> getPlugin(const std::string &name) const noexcept; - - /** - * Find a plugin. - * - * @param name the plugin id - * @return the plugin - * @throws std::out_of_range if not found - */ - std::shared_ptr<Plugin> requirePlugin(const std::string &name) const; - - /** - * Add plugin configuration for the specified plugin. - * - * @param name - * @param config - */ - inline void addPluginConfig(std::string name, PluginConfig config) - { - m_pluginConf.emplace(std::move(name), std::move(config)); - } - - /** - * Add a loaded plugin. - * - * Plugins signals will be connected to the irccd main loop. The onLoad function will also be called and the - * plugin is not added on errors. - * - * @pre plugin must not be empty - * @param plugin the plugin - */ - void addPlugin(std::shared_ptr<Plugin> plugin); - - /** - * Load a plugin by path or by searching through directories. - * - * TODO: Move this somewhere else (e.g. Plugin::find). - * - * @param source the path or the plugin id to search - * @param find set to true for searching by id - */ - void loadPlugin(std::string name, const std::string &source, bool find); - - /** - * Unload a plugin and remove it. - * - * @param name the plugin id - */ - void unloadPlugin(const std::string &name); - - /** - * Reload a plugin by calling onReload. - * - * @param name the plugin name - * @throw std::exception on failures - */ - void reloadPlugin(const std::string &name); - - /** - * Get the map of plugins. - * - * @return the map of plugins - */ - inline const Plugins &plugins() const noexcept - { - return m_plugins; - } - -#endif // !WITH_JS - - /* - * Rule management - * ---------------------------------------------------------- - * - * Functions for adding, creating new rules that are used to filter IRC events before being processed - * by JavaScript plugins. - */ - - /** - * Append a rule. - * - * @param rule the rule to append - */ - inline void addRule(Rule rule) - { - m_rules.push_back(std::move(rule)); - } - - /** - * Insert a new rule at the specified position. - * - * @param rule the rule - * @param position the position - */ - inline void insertRule(Rule rule, unsigned position) - { - assert(position <= m_rules.size()); - - m_rules.insert(m_rules.begin() + position, std::move(rule)); - } - - /** - * Get the list of rules. - * - * @return the list of rules - */ - inline const std::vector<Rule> &rules() const noexcept - { - return m_rules; - } - - /** - * Remove a new rule from the specified position. - * - * @pre position must be valid - * @param position the position - */ - inline void removeRule(unsigned position) - { - assert(position < m_rules.size()); - - m_rules.erase(m_rules.begin() + position); - } - - /** - * Loop forever by calling poll() and dispatch() indefinitely. - */ - void run(); - - /** - * Poll the next events without blocking (250 ms max). - */ - void poll(); - - /** - * Dispatch the pending events, usually after calling poll(). - */ - void dispatch(); - - /** - * Request to stop, usually from a signal. - */ - void stop(); -}; - -} // !irccd - -#endif // !IRCCD_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/irccd.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,543 @@ +/* + * irccd.hpp -- main irccd class + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_HPP +#define IRCCD_HPP + +/** + * @file irccd.hpp + * @brief Base class for irccd front end. + */ + +#include <atomic> +#include <cassert> +#include <condition_variable> +#include <functional> +#include <memory> +#include <mutex> +#include <vector> + +#include <irccd/sysconfig.hpp> + +#include "sockets.hpp" + +#if defined(WITH_JS) +# include "plugin.hpp" +#endif + +#include "application.hpp" +#include "logger.hpp" +#include "rule.hpp" +#include "server.hpp" +#include "transport-server.hpp" + +namespace irccd { + +class Plugin; +class TransportCommand; + +/** + * Event to execute after the poll. + */ +using Event = std::function<void ()>; + +/** + * List of events. + */ +using Events = std::vector<Event>; + +/** + * Map of identities. + */ +using Identities = std::unordered_map<std::string, ServerIdentity>; + +/** + * List of rules. + */ +using Rules = std::vector<Rule>; + +/** + * @class ServerEvent + * @brief Structure that owns several informations about an IRC event + * + * This structure is used to dispatch the IRC event to the plugins and the transports. + */ +class ServerEvent { +public: + std::string server; //!< the server + std::string origin; //!< the originator + std::string target; //!< the target + std::string json; //!< the JSON message +#if defined(WITH_JS) + std::function<std::string (Plugin &)> name; //!< the function to event name + std::function<void (Plugin &)> exec; //!< the plugin function to call +#endif +}; + +/** + * Map of servers. + */ +using Servers = std::unordered_map<std::string, std::shared_ptr<Server>>; + +/** + * Map of transport command handlers. + */ +using TransportCommands = std::unordered_map<std::string, std::unique_ptr<TransportCommand>>; + +#if defined(WITH_JS) + +/** + * Map of plugins. + */ +using Plugins = std::unordered_map<std::string, std::shared_ptr<Plugin>>; + +/** + * Map of plugin configurations. + */ +using PluginConfigs = std::unordered_map<std::string, PluginConfig>; + +#endif + +/** + * @class Irccd + * @brief Irccd main instance + * + * This class is used as the main application event loop, it stores servers, plugins and transports. + * + * In a general manner, no code in irccd is thread-safe because irccd is mono-threaded except the JavaScript timer + * API. + * + * If you plan to add more threads to irccd, then the simpliest and safest way to execute thread-safe code is to + * register an event using Irccd::post function which will be called during the event loop dispatching. + * + * Thus, except noticed as thread-safe, no function is assumed to be. + */ +class Irccd : public Application { +private: + template <typename T> + using LookupTable = std::unordered_map<net::Handle, std::shared_ptr<T>>; + + /* Main loop */ + std::atomic<bool> m_running{true}; + + /* Mutex for post() */ + std::mutex m_mutex; + + /* IPC */ + net::SocketTcp<net::address::Ip> m_socketServer; + net::SocketTcp<net::address::Ip> m_socketClient; + + /* Event loop */ + Events m_events; + + /* Servers */ + Servers m_servers; + + /* Optional JavaScript plugins */ +#if defined(WITH_JS) + Plugins m_plugins; + PluginConfigs m_pluginConf; +#endif + + /* Identities */ + Identities m_identities; + + /* Rules */ + Rules m_rules; + + /* Lookup tables */ + LookupTable<TransportClient> m_lookupTransportClients; + LookupTable<TransportServer> m_lookupTransportServers; + + /* + * Server slots + * ---------------------------------------------------------- + */ + + void handleServerChannelMode(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string mode, std::string arg); + void handleServerChannelNotice(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string notice); + void handleServerConnect(std::weak_ptr<Server> server); + void handleServerInvite(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string target); + void handleServerJoin(std::weak_ptr<Server> server, std::string origin, std::string channel); + void handleServerKick(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string target, std::string reason); + void handleServerMessage(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string message); + void handleServerMe(std::weak_ptr<Server> server, std::string origin, std::string target, std::string message); + void handleServerMode(std::weak_ptr<Server> server, std::string origin, std::string mode); + void handleServerNames(std::weak_ptr<Server> server, std::string channel, std::set<std::string> nicknames); + void handleServerNick(std::weak_ptr<Server> server, std::string origin, std::string nickname); + void handleServerNotice(std::weak_ptr<Server> server, std::string origin, std::string message); + void handleServerPart(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string reason); + void handleServerQuery(std::weak_ptr<Server> server, std::string origin, std::string message); + void handleServerTopic(std::weak_ptr<Server> server, std::string origin, std::string channel, std::string topic); + void handleServerWhois(std::weak_ptr<Server> server, ServerWhois whois); + + /* + * Transport clients slots + * ---------------------------------------------------------- + */ + void handleTransportCommand(std::weak_ptr<TransportClient>, const json::Value &); + void handleTransportDie(std::weak_ptr<TransportClient>); + + /* + * Plugin timers slots + * ---------------------------------------------------------- + * + * These handlers catch the timer signals and call the plugin function or remove the timer from the plugin. + */ + +#if defined(WITH_JS) + void handleTimerSignal(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); + void handleTimerEnd(std::weak_ptr<Plugin>, std::shared_ptr<Timer>); +#endif + + /* + * Process the socket sets. + * ---------------------------------------------------------- + * + * These functions are called after polling which sockets are ready for reading/writing. + */ + + void processIpc(fd_set &input); + void processTransportClients(fd_set &input, fd_set &output); + void processTransportServers(fd_set &input); + void processServers(fd_set &input, fd_set &output); + void process(fd_set &setinput, fd_set &setoutput); + +public: + /** + * Constructor that instanciate IPC. + */ + Irccd(); + + /** + * Load a configuration into irccd. Added as convenience to allow expressions like `irccd.load(Config{"foo"})`. + * + * @param config the configuration loader + */ + template <typename T> + inline void load(T &&config) + { + config.load(*this); + } + + /** + * Add an event to the queue. This will immediately signals the event loop to interrupt itself to dispatch + * the pending events. + * + * @param ev the event + * @note Thread-safe + */ + void post(Event ev) noexcept; + + /** + * This function wraps post() to iterate over all plugins to call the function and to send to all + * connected transport the event. + * + * @param ev the event + */ + void postServerEvent(ServerEvent ev) noexcept; + + /* + * Identity management + * ---------------------------------------------------------- + * + * Functions to get or add new identities. + */ + + /** + * Add an identity. + * + * @param identity the identity + * @note If the identity already exists, it is overriden + */ + inline void addIdentity(ServerIdentity identity) noexcept + { + m_identities.emplace(identity.name, std::move(identity)); + } + + /** + * Get an identity, if not found, the default one is used. + * + * @param name the identity name + * @return the identity or default one + */ + inline ServerIdentity findIdentity(const std::string &name) const noexcept + { + auto it = m_identities.find(name); + + return it == m_identities.end() ? ServerIdentity() : it->second; + } + + /* + * Server management + * ---------------------------------------------------------- + * + * Functions to get or create new servers. + * + * Servers that are added to this instance are automatically polled when run() is called. + */ + + /** + * Check if a server exists. + * + * @param name the name + * @return true if exists + */ + inline bool hasServer(const std::string &name) const noexcept + { + return m_servers.count(name) > 0; + } + + /** + * Add a new server to the application. + * + * @pre hasServer must return false + * @param sv the server + */ + void addServer(std::shared_ptr<Server> sv) noexcept; + + /** + * Get a server or empty one if not found + * + * @param name the server name + * @return the server or empty one if not found + */ + std::shared_ptr<Server> getServer(const std::string &name) const noexcept; + + /** + * Find a server by name. + * + * @param name the server name + * @return the server + * @throw std::out_of_range if the server does not exist + */ + std::shared_ptr<Server> requireServer(const std::string &name) const; + + /** + * Get the map of loaded servers. + * + * @return the servers + */ + inline const Servers &servers() const noexcept + { + return m_servers; + } + + /** + * Remove a server from the irccd instance. + * + * The server if any, will be disconnected. + * + * @param name the server name + */ + void removeServer(const std::string &name); + + /** + * Remove all servers. + * + * All servers will be disconnected. + */ + void clearServers() noexcept; + + /* + * Transport management + * ---------------------------------------------------------- + * + * Functions for adding new transport servers. + */ + + /** + * Add a transport server. + * + * @param ts the transport server + */ + void addTransport(std::shared_ptr<TransportServer> ts); + + /* + * Plugin management + * ---------------------------------------------------------- + * + * Functions for loading JavaScript plugins. + */ + +#if defined(WITH_JS) + /** + * Check if a plugin is loaded. + * + * @param name the plugin id + * @return true if has plugin + */ + inline bool hasPlugin(const std::string &name) const noexcept + { + return m_plugins.count(name) > 0; + } + + /** + * Get a plugin or empty one if not found. + * + * @param name the plugin id + * @return the plugin or empty one if not found + */ + std::shared_ptr<Plugin> getPlugin(const std::string &name) const noexcept; + + /** + * Find a plugin. + * + * @param name the plugin id + * @return the plugin + * @throws std::out_of_range if not found + */ + std::shared_ptr<Plugin> requirePlugin(const std::string &name) const; + + /** + * Add plugin configuration for the specified plugin. + * + * @param name + * @param config + */ + inline void addPluginConfig(std::string name, PluginConfig config) + { + m_pluginConf.emplace(std::move(name), std::move(config)); + } + + /** + * Add a loaded plugin. + * + * Plugins signals will be connected to the irccd main loop. The onLoad function will also be called and the + * plugin is not added on errors. + * + * @pre plugin must not be empty + * @param plugin the plugin + */ + void addPlugin(std::shared_ptr<Plugin> plugin); + + /** + * Load a plugin by path or by searching through directories. + * + * TODO: Move this somewhere else (e.g. Plugin::find). + * + * @param source the path or the plugin id to search + * @param find set to true for searching by id + */ + void loadPlugin(std::string name, const std::string &source, bool find); + + /** + * Unload a plugin and remove it. + * + * @param name the plugin id + */ + void unloadPlugin(const std::string &name); + + /** + * Reload a plugin by calling onReload. + * + * @param name the plugin name + * @throw std::exception on failures + */ + void reloadPlugin(const std::string &name); + + /** + * Get the map of plugins. + * + * @return the map of plugins + */ + inline const Plugins &plugins() const noexcept + { + return m_plugins; + } + +#endif // !WITH_JS + + /* + * Rule management + * ---------------------------------------------------------- + * + * Functions for adding, creating new rules that are used to filter IRC events before being processed + * by JavaScript plugins. + */ + + /** + * Append a rule. + * + * @param rule the rule to append + */ + inline void addRule(Rule rule) + { + m_rules.push_back(std::move(rule)); + } + + /** + * Insert a new rule at the specified position. + * + * @param rule the rule + * @param position the position + */ + inline void insertRule(Rule rule, unsigned position) + { + assert(position <= m_rules.size()); + + m_rules.insert(m_rules.begin() + position, std::move(rule)); + } + + /** + * Get the list of rules. + * + * @return the list of rules + */ + inline const std::vector<Rule> &rules() const noexcept + { + return m_rules; + } + + /** + * Remove a new rule from the specified position. + * + * @pre position must be valid + * @param position the position + */ + inline void removeRule(unsigned position) + { + assert(position < m_rules.size()); + + m_rules.erase(m_rules.begin() + position); + } + + /** + * Loop forever by calling poll() and dispatch() indefinitely. + */ + void run(); + + /** + * Poll the next events without blocking (250 ms max). + */ + void poll(); + + /** + * Dispatch the pending events, usually after calling poll(). + */ + void dispatch(); + + /** + * Request to stop, usually from a signal. + */ + void stop(); +}; + +} // !irccd + +#endif // !IRCCD_HPP
--- a/lib/irccd/irccdctl.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/irccdctl.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -23,19 +23,19 @@ #include <string> #include <unordered_map> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "elapsed-timer.h" -#include "fs.h" -#include "ini.h" -#include "irccdctl.h" -#include "json.h" -#include "logger.h" -#include "options.h" -#include "path.h" -#include "sockets.h" -#include "system.h" -#include "util.h" +#include "elapsed-timer.hpp" +#include "fs.hpp" +#include "ini.hpp" +#include "irccdctl.hpp" +#include "json.hpp" +#include "logger.hpp" +#include "options.hpp" +#include "path.hpp" +#include "sockets.hpp" +#include "system.hpp" +#include "util.hpp" namespace irccd {
--- a/lib/irccd/irccdctl.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * irccdctl.h -- main irccdctl class - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_IRCCDCTL_H -#define IRCCD_IRCCDCTL_H - -/** - * @file irccdctl.h - * @brief Base class for irccdctl front end. - */ - -#include <cassert> -#include <map> -#include <memory> -#include <string> - -#include "alias.h" -#include "application.h" -#include "connection.h" -#include "options.h" - -namespace irccd { - -class Command; - -namespace ini { - -class Section; - -} // !ini - -/** - * @brief Main irccdctl class. - */ -class Irccdctl : public Application { -private: - /* Irccd's information */ - unsigned short m_major{0}; - unsigned short m_minor{0}; - unsigned short m_patch{0}; - - /* Irccd's compilation option */ - bool m_javascript{true}; - bool m_ssl{true}; - - std::unique_ptr<Connection> m_connection; - std::unordered_map<std::string, Alias> m_aliases; - - void usage() const; - - void readConnectIp(const ini::Section &sc); - void readConnectUnix(const ini::Section &sc); - void readConnect(const ini::Section &sc); - void readGeneral(const ini::Section &sc); - void readAliases(const ini::Section &sc); - void read(const std::string &path, const parser::Result &options); - - void parseConnectIp(const parser::Result &options, bool ipv6); - void parseConnectUnix(const parser::Result &options); - void parseConnect(const parser::Result &options); - parser::Result parse(int &argc, char **&argv) const; - - void connect(); - -public: - /** - * Execute the given command and wait for its result. - * - * @param cmd the command - * @param args the arguments - */ - void exec(const RemoteCommand &cmd, std::vector<std::string> args); - - /** - * Execute the given alias. - * - * @param alias the alias - * @param args the arguments - */ - void exec(const Alias &alias, std::vector<std::string> args); - - /** - * Resolve the command line arguments. - * - * @param args the main arguments - */ - void exec(std::vector<std::string> args); - - /** - * Get the connection. - * - * @return the connection - */ - inline Connection &connection() noexcept - { - return *m_connection; - } - - /** - * Run the irccdctl front end. - * - * @param argc the number of arguments - * @param argv the arguments - */ - void run(int argc, char **argv); -}; - -} // !irccd - -#endif // !IRCCD_IRCCDCTL_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/irccdctl.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,125 @@ +/* + * irccdctl.hpp -- main irccdctl class + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_IRCCDCTL_HPP +#define IRCCD_IRCCDCTL_HPP + +/** + * @file irccdctl.hpp + * @brief Base class for irccdctl front end. + */ + +#include <cassert> +#include <map> +#include <memory> +#include <string> + +#include "alias.hpp" +#include "application.hpp" +#include "connection.hpp" +#include "options.hpp" + +namespace irccd { + +class Command; + +namespace ini { + +class Section; + +} // !ini + +/** + * @brief Main irccdctl class. + */ +class Irccdctl : public Application { +private: + /* Irccd's information */ + unsigned short m_major{0}; + unsigned short m_minor{0}; + unsigned short m_patch{0}; + + /* Irccd's compilation option */ + bool m_javascript{true}; + bool m_ssl{true}; + + std::unique_ptr<Connection> m_connection; + std::unordered_map<std::string, Alias> m_aliases; + + void usage() const; + + void readConnectIp(const ini::Section &sc); + void readConnectUnix(const ini::Section &sc); + void readConnect(const ini::Section &sc); + void readGeneral(const ini::Section &sc); + void readAliases(const ini::Section &sc); + void read(const std::string &path, const parser::Result &options); + + void parseConnectIp(const parser::Result &options, bool ipv6); + void parseConnectUnix(const parser::Result &options); + void parseConnect(const parser::Result &options); + parser::Result parse(int &argc, char **&argv) const; + + void connect(); + +public: + /** + * Execute the given command and wait for its result. + * + * @param cmd the command + * @param args the arguments + */ + void exec(const RemoteCommand &cmd, std::vector<std::string> args); + + /** + * Execute the given alias. + * + * @param alias the alias + * @param args the arguments + */ + void exec(const Alias &alias, std::vector<std::string> args); + + /** + * Resolve the command line arguments. + * + * @param args the main arguments + */ + void exec(std::vector<std::string> args); + + /** + * Get the connection. + * + * @return the connection + */ + inline Connection &connection() noexcept + { + return *m_connection; + } + + /** + * Run the irccdctl front end. + * + * @param argc the number of arguments + * @param argv the arguments + */ + void run(int argc, char **argv); +}; + +} // !irccd + +#endif // !IRCCD_IRCCDCTL_HPP
--- a/lib/irccd/js-directory.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-directory.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -24,12 +24,12 @@ #include <stdexcept> #include <string> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "fs.h" -#include "js.h" -#include "js-irccd.h" -#include "path.h" +#include "fs.hpp" +#include "js.hpp" +#include "js-irccd.hpp" +#include "path.hpp" namespace irccd {
--- a/lib/irccd/js-directory.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * js-directory.h -- Irccd.Directory API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_DIRECTORY_H -#define IRCCD_JS_DIRECTORY_H - -/** - * @file js-directory.h - * @brief Irccd.Directory JavaScript API. - */ - -#include "js.h" - -namespace irccd { - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsDirectory(duk::ContextPtr ctx) noexcept; - -} // !irccd - -#endif // !IRCCD_JS_DIRECTORY_H -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-directory.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,41 @@ +/* + * js-directory.hpp -- Irccd.Directory API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_DIRECTORY_HPP +#define IRCCD_JS_DIRECTORY_HPP + +/** + * @file js-directory.hpp + * @brief Irccd.Directory JavaScript API. + */ + +#include "js.hpp" + +namespace irccd { + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsDirectory(duk::ContextPtr ctx) noexcept; + +} // !irccd + +#endif // !IRCCD_JS_DIRECTORY_HPP +
--- a/lib/irccd/js-elapsed-timer.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-elapsed-timer.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "elapsed-timer.h" -#include "js.h" +#include "elapsed-timer.hpp" +#include "js.hpp" namespace irccd {
--- a/lib/irccd/js-elapsed-timer.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * js-elapsed-timer.h -- Irccd.ElapsedTimer API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_ELAPSED_TIMER_H -#define IRCCD_JS_ELAPSED_TIMER_H - -/** - * @file js-elapsed-timer.h - * @brief Irccd.ElapsedTimer JavaScript API. - */ - -#include "js.h" - -namespace irccd { - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsElapsedTimer(duk::ContextPtr ctx) noexcept; - -} // !irccd - -#endif // !IRCCD_JS_ELAPSED_TIMER_H -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-elapsed-timer.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,41 @@ +/* + * js-elapsed-timer.hpp -- Irccd.ElapsedTimer API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_ELAPSED_TIMER_HPP +#define IRCCD_JS_ELAPSED_TIMER_HPP + +/** + * @file js-elapsed-timer.hpp + * @brief Irccd.ElapsedTimer JavaScript API. + */ + +#include "js.hpp" + +namespace irccd { + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsElapsedTimer(duk::ContextPtr ctx) noexcept; + +} // !irccd + +#endif // !IRCCD_JS_ELAPSED_TIMER_HPP +
--- a/lib/irccd/js-file.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-file.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -21,16 +21,16 @@ #include <iterator> #include <vector> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> #if defined(HAVE_STAT) # include <sys/types.h> # include <sys/stat.h> #endif -#include "fs.h" -#include "js-irccd.h" -#include "js-file.h" +#include "fs.hpp" +#include "js-irccd.hpp" +#include "js-file.hpp" namespace irccd {
--- a/lib/irccd/js-file.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -/* - * js-file.h -- Irccd.File API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_FILE_H -#define IRCCD_JS_FILE_H - -/** - * @file js-file.h - * @brief Irccd.File JavaScript API. - */ - -#include <cassert> -#include <cerrno> -#include <cstdio> -#include <cstring> -#include <functional> -#include <stdexcept> -#include <string> - -#include "js.h" - -namespace irccd { - -/** - * @class File - * @brief Object for Javascript to perform I/O. - * - * This class can be constructed to Javascript. - * - * It is used in: - * - * - Irccd.File [constructor] - * - Irccd.System.popen (optional) - */ -class File { -private: - File(const File &) = delete; - File &operator=(const File &) = delete; - - File(File &&) = delete; - File &operator=(File &&) = delete; - -private: - std::string m_path; - std::FILE *m_stream; - std::function<void (std::FILE *)> m_destructor; - -public: - /** - * Construct a file specified by path - * - * @param path the path - * @param mode the mode string (for std::fopen) - * @throw std::runtime_error on failures - */ - inline File(std::string path, const std::string &mode) - : m_path(std::move(path)) - , m_destructor([] (std::FILE *fp) { std::fclose(fp); }) - { - if ((m_stream = std::fopen(m_path.c_str(), mode.c_str())) == nullptr) - throw std::runtime_error(std::strerror(errno)); - } - - /** - * Construct a file from a already created FILE pointer (e.g. popen). - * - * The class takes ownership of fp and will close it. - * - * @pre destructor must not be null - * @param fp the file pointer - * @param destructor the function to close fp (e.g. std::fclose) - */ - inline File(std::FILE *fp, std::function<void (std::FILE *)> destructor) noexcept - : m_stream(fp) - , m_destructor(std::move(destructor)) - { - assert(m_destructor != nullptr); - } - - /** - * Closes the file. - */ - virtual ~File() noexcept - { - close(); - } - - /** - * Get the path. - * - * @return the path - * @warning empty when constructed from the FILE constructor - */ - inline const std::string &path() const noexcept - { - return m_path; - } - - /** - * Get the handle. - * - * @return the handle or nullptr if the stream was closed - */ - inline std::FILE *handle() noexcept - { - return m_stream; - } - - /** - * Force close, can be safely called multiple times. - */ - inline void close() noexcept - { - if (m_stream) { - m_destructor(m_stream); - m_stream = nullptr; - } - } -}; - -namespace duk { - -/** - * @brief JavaScript binding for File. - */ -template <> -class TypeTraits<File> { -public: - /** - * Push the File prototype. - * - * @param ctx the context - */ - static inline void prototype(ContextPtr ctx) - { - getGlobal<void>(ctx, "Irccd"); - getGlobal<void>(ctx, "File"); - getProperty<void>(ctx, -1, "prototype"); - remove(ctx, -2); - remove(ctx, -2); - } - - /** - * Get the File signature. - * - * @return File - */ - static inline std::string name() - { - return "\xff""\xff""File"; - } - - /** - * Get the inheritance list. - * - * @return empty - */ - static inline std::vector<std::string> inherits() - { - return {}; - } -}; - -} // !duk - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsFile(duk::ContextPtr ctx); - -} // !irccd - -#endif // !IRCCD_JS_FILE_H -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-file.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,191 @@ +/* + * js-file.hpp -- Irccd.File API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_FILE_HPP +#define IRCCD_JS_FILE_HPP + +/** + * @file js-file.hpp + * @brief Irccd.File JavaScript API. + */ + +#include <cassert> +#include <cerrno> +#include <cstdio> +#include <cstring> +#include <functional> +#include <stdexcept> +#include <string> + +#include "js.hpp" + +namespace irccd { + +/** + * @class File + * @brief Object for Javascript to perform I/O. + * + * This class can be constructed to Javascript. + * + * It is used in: + * + * - Irccd.File [constructor] + * - Irccd.System.popen (optional) + */ +class File { +private: + File(const File &) = delete; + File &operator=(const File &) = delete; + + File(File &&) = delete; + File &operator=(File &&) = delete; + +private: + std::string m_path; + std::FILE *m_stream; + std::function<void (std::FILE *)> m_destructor; + +public: + /** + * Construct a file specified by path + * + * @param path the path + * @param mode the mode string (for std::fopen) + * @throw std::runtime_error on failures + */ + inline File(std::string path, const std::string &mode) + : m_path(std::move(path)) + , m_destructor([] (std::FILE *fp) { std::fclose(fp); }) + { + if ((m_stream = std::fopen(m_path.c_str(), mode.c_str())) == nullptr) + throw std::runtime_error(std::strerror(errno)); + } + + /** + * Construct a file from a already created FILE pointer (e.g. popen). + * + * The class takes ownership of fp and will close it. + * + * @pre destructor must not be null + * @param fp the file pointer + * @param destructor the function to close fp (e.g. std::fclose) + */ + inline File(std::FILE *fp, std::function<void (std::FILE *)> destructor) noexcept + : m_stream(fp) + , m_destructor(std::move(destructor)) + { + assert(m_destructor != nullptr); + } + + /** + * Closes the file. + */ + virtual ~File() noexcept + { + close(); + } + + /** + * Get the path. + * + * @return the path + * @warning empty when constructed from the FILE constructor + */ + inline const std::string &path() const noexcept + { + return m_path; + } + + /** + * Get the handle. + * + * @return the handle or nullptr if the stream was closed + */ + inline std::FILE *handle() noexcept + { + return m_stream; + } + + /** + * Force close, can be safely called multiple times. + */ + inline void close() noexcept + { + if (m_stream) { + m_destructor(m_stream); + m_stream = nullptr; + } + } +}; + +namespace duk { + +/** + * @brief JavaScript binding for File. + */ +template <> +class TypeTraits<File> { +public: + /** + * Push the File prototype. + * + * @param ctx the context + */ + static inline void prototype(ContextPtr ctx) + { + getGlobal<void>(ctx, "Irccd"); + getGlobal<void>(ctx, "File"); + getProperty<void>(ctx, -1, "prototype"); + remove(ctx, -2); + remove(ctx, -2); + } + + /** + * Get the File signature. + * + * @return File + */ + static inline std::string name() + { + return "\xff""\xff""File"; + } + + /** + * Get the inheritance list. + * + * @return empty + */ + static inline std::vector<std::string> inherits() + { + return {}; + } +}; + +} // !duk + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsFile(duk::ContextPtr ctx); + +} // !irccd + +#endif // !IRCCD_JS_FILE_HPP +
--- a/lib/irccd/js-irccd.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-irccd.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,9 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "js-irccd.h" +#include "js-irccd.hpp" namespace irccd {
--- a/lib/irccd/js-irccd.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * js-irccd.h -- Irccd API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_IRCCD_H -#define IRCCD_JS_IRCCD_H - -/** - * @file js-irccd.h - * @brief Irccd.Irccd JavaScript API. - */ - -#include <cerrno> -#include <cstring> - -#include "js.h" - -namespace irccd { - -/** - * @brief Custom JavaScript exception for system error. - */ -class SystemError { -private: - int m_errno; - std::string m_message; - -public: - /** - * Create a system error from the current errno value. - */ - SystemError(); - - /** - * Create a system error with the given errno and message. - * - * @param e the errno number - * @param message the message - */ - SystemError(int e, std::string message); - - /** - * Raise the SystemError. - * - * @param ctx the context - */ - void raise(duk::ContextPtr ctx) const; -}; - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsIrccd(duk::Context &ctx); - -} // !irccd - -#endif // !IRCCD_JS_IRCCD_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-irccd.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,73 @@ +/* + * js-irccd.hpp -- Irccd API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_IRCCD_HPP +#define IRCCD_JS_IRCCD_HPP + +/** + * @file js-irccd.hpp + * @brief Irccd.Irccd JavaScript API. + */ + +#include <cerrno> +#include <cstring> + +#include "js.hpp" + +namespace irccd { + +/** + * @brief Custom JavaScript exception for system error. + */ +class SystemError { +private: + int m_errno; + std::string m_message; + +public: + /** + * Create a system error from the current errno value. + */ + SystemError(); + + /** + * Create a system error with the given errno and message. + * + * @param e the errno number + * @param message the message + */ + SystemError(int e, std::string message); + + /** + * Raise the SystemError. + * + * @param ctx the context + */ + void raise(duk::ContextPtr ctx) const; +}; + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsIrccd(duk::Context &ctx); + +} // !irccd + +#endif // !IRCCD_JS_IRCCD_HPP
--- a/lib/irccd/js-logger.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-logger.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "js-logger.h" -#include "logger.h" +#include "js-logger.hpp" +#include "logger.hpp" namespace irccd {
--- a/lib/irccd/js-logger.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * js-logger.h -- Irccd.Logger API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_LOGGER_H -#define IRCCD_JS_LOGGER_H - -/** - * @file js-logger.h - * @brief Irccd.Logger JavaScript API. - */ - -#include "js.h" - -namespace irccd { - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsLogger(duk::ContextPtr ctx); - -} // !irccd - -#endif // !IRCCD_JS_LOGGER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-logger.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,40 @@ +/* + * js-logger.hpp -- Irccd.Logger API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_LOGGER_HPP +#define IRCCD_JS_LOGGER_HPP + +/** + * @file js-logger.hpp + * @brief Irccd.Logger JavaScript API. + */ + +#include "js.hpp" + +namespace irccd { + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsLogger(duk::ContextPtr ctx); + +} // !irccd + +#endif // !IRCCD_JS_LOGGER_HPP
--- a/lib/irccd/js-plugin.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-plugin.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "irccd.h" -#include "js-plugin.h" +#include "irccd.hpp" +#include "js-plugin.hpp" namespace irccd {
--- a/lib/irccd/js-plugin.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * js-plugin.h -- Irccd.Plugin API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_PLUGIN_H -#define IRCCD_JS_PLUGIN_H - -/** - * @file js-plugin.h - * @brief Irccd.Plugin JavaScript API. - */ - -#include "js.h" - -namespace irccd { - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsPlugin(duk::Context &ctx) noexcept; - -} // !irccd - -#endif // !IRCCD_JS_PLUGIN_H -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-plugin.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,41 @@ +/* + * js-plugin.hpp -- Irccd.Plugin API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_PLUGIN_HPP +#define IRCCD_JS_PLUGIN_HPP + +/** + * @file js-plugin.hpp + * @brief Irccd.Plugin JavaScript API. + */ + +#include "js.hpp" + +namespace irccd { + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsPlugin(duk::Context &ctx) noexcept; + +} // !irccd + +#endif // !IRCCD_JS_PLUGIN_HPP +
--- a/lib/irccd/js-server.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-server.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -19,9 +19,9 @@ #include <sstream> #include <unordered_map> -#include "irccd.h" -#include "js-server.h" -#include "server.h" +#include "irccd.hpp" +#include "js-server.hpp" +#include "server.hpp" namespace irccd {
--- a/lib/irccd/js-server.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * js-server.h -- Irccd.Server API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_SERVER_H -#define IRCCD_JS_SERVER_H - -/** - * @file js-server.h - * @brief Irccd.Server JavaScript API. - */ - -#include <irccd/server.h> - -#include "js.h" - -namespace irccd { - -namespace duk { - -/** - * @brief JavaScript binding for Server. - */ -template <> -class TypeTraits<irccd::Server> { -public: - /** - * Push the Server prototype. - * - * @param ctx the context - */ - static inline void prototype(ContextPtr ctx) - { - getGlobal<void>(ctx, "Irccd"); - getProperty<void>(ctx, -1, "Server"); - getProperty<void>(ctx, -1, "prototype"); - remove(ctx, -2); - remove(ctx, -2); - } - - /** - * Get the Server signature. - * - * @return Server - */ - static inline std::string name() - { - return "\xff""\xff""Server"; - } - - /** - * Get the inheritance list. - * - * @return empty - */ - static inline std::vector<std::string> inherits() - { - return {}; - } -}; - -} // !duk - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsServer(duk::ContextPtr ctx); - -} // !irccd - -#endif // !IRCCD_JS_SERVER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-server.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,87 @@ +/* + * js-server.hpp -- Irccd.Server API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_SERVER_HPP +#define IRCCD_JS_SERVER_HPP + +/** + * @file js-server.hpp + * @brief Irccd.Server JavaScript API. + */ + +#include <irccd/server.hpp> + +#include "js.hpp" + +namespace irccd { + +namespace duk { + +/** + * @brief JavaScript binding for Server. + */ +template <> +class TypeTraits<irccd::Server> { +public: + /** + * Push the Server prototype. + * + * @param ctx the context + */ + static inline void prototype(ContextPtr ctx) + { + getGlobal<void>(ctx, "Irccd"); + getProperty<void>(ctx, -1, "Server"); + getProperty<void>(ctx, -1, "prototype"); + remove(ctx, -2); + remove(ctx, -2); + } + + /** + * Get the Server signature. + * + * @return Server + */ + static inline std::string name() + { + return "\xff""\xff""Server"; + } + + /** + * Get the inheritance list. + * + * @return empty + */ + static inline std::vector<std::string> inherits() + { + return {}; + } +}; + +} // !duk + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsServer(duk::ContextPtr ctx); + +} // !irccd + +#endif // !IRCCD_JS_SERVER_HPP
--- a/lib/irccd/js-system.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-system.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> #include <chrono> @@ -27,10 +27,10 @@ #include <cstdlib> #include <thread> -#include "js-file.h" -#include "js-irccd.h" -#include "js-system.h" -#include "system.h" +#include "js-file.hpp" +#include "js-irccd.hpp" +#include "js-system.hpp" +#include "system.hpp" namespace irccd {
--- a/lib/irccd/js-system.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * js-system.h -- Irccd.System API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_SYSTEM_H -#define IRCCD_JS_SYSTEM_H - -/** - * @file js-system.h - * @brief Irccd.System JavaScript API. - */ - -#include "js.h" - -namespace irccd { - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsSystem(duk::ContextPtr ctx); - -} // !irccd - -#endif // !IRCCD_JS_SYSTEM_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-system.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,40 @@ +/* + * js-system.hpp -- Irccd.System API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_SYSTEM_HPP +#define IRCCD_JS_SYSTEM_HPP + +/** + * @file js-system.hpp + * @brief Irccd.System JavaScript API. + */ + +#include "js.hpp" + +namespace irccd { + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsSystem(duk::ContextPtr ctx); + +} // !irccd + +#endif // !IRCCD_JS_SYSTEM_HPP
--- a/lib/irccd/js-timer.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-timer.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -19,8 +19,8 @@ #include <cassert> #include <cstdint> -#include "js.h" -#include "plugin.h" +#include "js.hpp" +#include "plugin.hpp" namespace irccd {
--- a/lib/irccd/js-timer.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * js-timer.h -- Irccd.Timer API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_TIMER_H -#define IRCCD_JS_TIMER_H - -/** - * @file js-timer.h - * @brief Irccd.Timer JavaScript API. - */ - -#include "js.h" - -namespace irccd { - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsTimer(duk::ContextPtr ctx) noexcept; - -} // !irccd - -#endif // !IRCCD_JS_TIMER_H -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-timer.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,41 @@ +/* + * js-timer.hpp -- Irccd.Timer API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_TIMER_HPP +#define IRCCD_JS_TIMER_HPP + +/** + * @file js-timer.hpp + * @brief Irccd.Timer JavaScript API. + */ + +#include "js.hpp" + +namespace irccd { + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsTimer(duk::ContextPtr ctx) noexcept; + +} // !irccd + +#endif // !IRCCD_JS_TIMER_HPP +
--- a/lib/irccd/js-unicode.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-unicode.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,8 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "js.h" -#include "unicode.h" +#include "js.hpp" +#include "unicode.hpp" namespace irccd {
--- a/lib/irccd/js-unicode.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * js-unicode.cpp -- Irccd.Unicode API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_UNICODE_H -#define IRCCD_JS_UNICODE_H - -/** - * @file js-unicode.h - * @brief Irccd.Unicode JavaScript API. - */ - -#include "js.h" - -namespace irccd { - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsUnicode(duk::ContextPtr ctx); - -} // !irccd - -#endif // !IRCCD_JS_UNICODE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-unicode.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,40 @@ +/* + * js-unicode.cpp -- Irccd.Unicode API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_UNICODE_HPP +#define IRCCD_JS_UNICODE_HPP + +/** + * @file js-unicode.hpp + * @brief Irccd.Unicode JavaScript API. + */ + +#include "js.hpp" + +namespace irccd { + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsUnicode(duk::ContextPtr ctx); + +} // !irccd + +#endif // !IRCCD_JS_UNICODE_HPP
--- a/lib/irccd/js-util.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/js-util.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,8 +18,8 @@ #include <libircclient.h> -#include "js-util.h" -#include "util.h" +#include "js-util.hpp" +#include "util.hpp" namespace irccd {
--- a/lib/irccd/js-util.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * js-util.h -- Irccd.Util API - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_UTIL_H -#define IRCCD_JS_UTIL_H - -/** - * @file js-util.h - * @brief Irccd.Util JavaScript API. - */ - -#include "js.h" - -namespace irccd { - -/** - * Load the module. - * - * @param ctx the context. - */ -void loadJsUtil(duk::ContextPtr ctx); - -} // !irccd - -#endif // !IRCCD_JS_UTIL_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js-util.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,40 @@ +/* + * js-util.hpp -- Irccd.Util API + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_UTIL_HPP +#define IRCCD_JS_UTIL_HPP + +/** + * @file js-util.hpp + * @brief Irccd.Util JavaScript API. + */ + +#include "js.hpp" + +namespace irccd { + +/** + * Load the module. + * + * @param ctx the context. + */ +void loadJsUtil(duk::ContextPtr ctx); + +} // !irccd + +#endif // !IRCCD_JS_UTIL_HPP
--- a/lib/irccd/js.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2381 +0,0 @@ -/* - * js.h -- JavaScript C++14 wrapper for Duktape - * - * Copyright (c) 2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JS_H -#define IRCCD_JS_H - -/** - * @file js.h - * @brief Bring JavaScript using Duktape. - * - * This file provides usual Duktape function renamed and placed into `duk` namespace. It also replaces error - * code with exceptions when possible. - * - * For convenience, this file also provides templated functions, overloads and much more. - */ - -#include <cassert> -#include <functional> -#include <memory> -#include <string> -#include <type_traits> -#include <unordered_map> -#include <utility> -#include <vector> - -#include <duktape.h> - -namespace irccd { - -/** - * Duktape C++ namespace wrapper. - */ -namespace duk { - -class Context; - -using CodePoint = duk_codepoint_t; -using ContextPtr = duk_context *; -using Index = duk_idx_t; -using Ret = duk_ret_t; -using Size = duk_size_t; - -/** - * @class StackAssert - * @brief Stack sanity checker. - * - * Instanciate this class where you need to manipulate the Duktape stack outside a Duktape/C function, its destructor - * will examinate if the stack size matches the user expected size. - * - * When compiled with NDEBUG, this class does nothing. - * - * To use it, just declare an lvalue at the beginning of your function. - */ -class StackAssert { -#if !defined(NDEBUG) -private: - ContextPtr m_context; - unsigned m_expected; - unsigned m_begin; -#endif - -public: - /** - * Create the stack checker. - * - * No-op if NDEBUG is set. - * - * @param ctx the context - * @param expected the size expected relative to the already existing values - */ - inline StackAssert(ContextPtr ctx, unsigned expected = 0) noexcept -#if !defined(NDEBUG) - : m_context(ctx) - , m_expected(expected) - , m_begin(static_cast<unsigned>(duk_get_top(ctx))) -#endif - { -#if defined(NDEBUG) - (void)ctx; - (void)expected; -#endif - } - - /** - * Verify the expected size. - * - * No-op if NDEBUG is set. - */ - inline ~StackAssert() noexcept - { -#if !defined(NDEBUG) - assert((unsigned)duk_get_top(m_context) - m_begin == m_expected); -#endif - } -}; - -/** - * @class Object - * @brief Empty class tag for push() function. - */ -class Object { -}; - -/** - * @class Array - * @brief Empty class tag for push() function. - */ -class Array { -}; - -/** - * @class Global - * @brief Empty class tag to push the global object. - */ -class Global { -}; - -/** - * @class Undefined - * @brief Empty class tag to push undefined to the stack. - */ -class Undefined { -}; - -/** - * @class Null - * @brief Empty class tag to push null to the stack. - */ -class Null { -}; - -/** - * @class This - * @brief Empty class tag to push this binding to the stack. - */ -class This { -}; - -/** - * @class RawPointer - * @brief Push a non-managed pointer to Duktape, the pointer will never be deleted. - * @note For a managed pointer with prototype, see Pointer - */ -template <typename T> -class RawPointer { -public: - /** - * The pointer to push. - */ - T *object; -}; - -/** - * @brief Manage shared_ptr from C++ and JavaScript - * - * This class allowed you to push and retrieve shared_ptr from C++ and JavaScript without taking care of ownership - * and deletion. - * - */ -template <typename T> -class Shared { -public: - /** - * The shared object. - */ - std::shared_ptr<T> object; -}; - -/** - * @brief Manage pointers from C++ and JavaScript - * - * This class allowed you to push and retrieve C++ pointers from C++ and JavaScript. The object will be deleted when - * the JavaScript garbage collectors collect them so never store a pointer created with this. - * - * The only requirement is to have the function `void prototype(Context &ctx)` in your class T. - */ -template <typename T> -class Pointer { -public: - /** - * The object. - */ - T *object{nullptr}; -}; - -/** - * @class Function - * @brief Duktape/C function definition. - * - * This class wraps the std::function as a Duktape/C function by storing a copied pointer. - */ -class Function { -public: - /** - * The function pointer, must not be null. - */ - duk_c_function function; - - /** - * Number of args that the function takes - */ - duk_idx_t nargs{0}; -}; - -/** - * Map of functions to set on an object. - */ -using FunctionMap = std::unordered_map<std::string, Function>; - -/** - * Map of string to type, ideal for setting constants like enums. - */ -template <typename Type> -using Map = std::unordered_map<std::string, Type>; - -/** - * @class ErrorInfo - * @brief Error description. - * - * This class fills the fields got in an Error object. - */ -class ErrorInfo : public std::exception { -public: - std::string name; //!< name of error - std::string message; //!< error message - std::string stack; //!< stack if available - std::string fileName; //!< filename if applicable - int lineNumber{0}; //!< line number if applicable - - /** - * Get the error message. This effectively returns message field. - * - * @return the message - */ - const char *what() const noexcept override - { - return message.c_str(); - } -}; - -/** - * @class TypeTraits - * @brief Type information to implement new types in JavaScript's context. - * - * This class depending on your needs may have the following functions: - * - * - `static void construct(Context &ctx, Type value)` - * - `static Type get(Context &ctx, int index)` - * - `static bool is(Context &ctx, int index)` - * - `static Type optional(Context &ctx, int index, Type defaultValue)` - * - `static void push(Context &ctx, Type value)` - * - `static Type require(Context &ctx, int index)` - * - * The `construct` function is used in Context::construct to build a new value as this (e.g. constructors). - * - * The `get` function is used in Context::get, Context::getProperty, Context::getGlobal to retrieve a value from the - * stack. - * - * The `is` function is used in Context::is to check if the value on the stack is of type `Type`. - * - * The `optional` function is used in Context::optional to get a value or a replacement if not applicable. - * - * The `push` function is used in Context::push to usually create a new value on the stack but some specializations - * may not (e.g. FunctionMap). - * - * The `require` function is used in Context::require to get a value from the stack or raise a JavaScript exception if - * not applicable. - * - * This class is fully specialized for: `bool`, `const char *`, `double`, `int`, `std::string`. - * - * It is also partially specialized for : `Global`, `Object`, `Array`, `Undefined`, `Null`, `std::vector<Type>`. - */ -template <typename Type> -class TypeTraits { -}; - -/** - * @class Context - * @brief RAII based Duktape handler. - * - * This class is implicitly convertible to duk_context for convenience. - */ -class Context { -private: - using Deleter = void (*)(duk_context *); - using Handle = std::unique_ptr<duk_context, Deleter>; - - Handle m_handle; - - Context(const Context &) = delete; - Context &operator=(const Context &) = delete; - Context(const Context &&) = delete; - Context &operator=(const Context &&) = delete; - -public: - /** - * Create default context. - */ - inline Context() - : m_handle(duk_create_heap_default(), duk_destroy_heap) - { - } - - /** - * Convert the context to the native Duktape/C type. - * - * @return the duk_context - */ - inline operator duk_context *() noexcept - { - return m_handle.get(); - } - - /** - * Convert the context to the native Duktape/C type. - * - * @return the duk_context - */ - inline operator duk_context *() const noexcept - { - return m_handle.get(); - } -}; - -/** - * Get the error object when a JavaScript error has been thrown (e.g. eval failure). - * - * @param ctx the context - * @param index the index - * @return the information - */ -inline ErrorInfo error(ContextPtr ctx, int index) -{ - ErrorInfo error; - - index = duk_normalize_index(ctx, index); - - duk_get_prop_string(ctx, index, "name"); - error.name = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "message"); - error.message = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "fileName"); - error.fileName = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "lineNumber"); - error.lineNumber = duk_to_int(ctx, -1); - duk_get_prop_string(ctx, index, "stack"); - error.stack = duk_to_string(ctx, -1); - duk_pop_n(ctx, 5); - - return error; -} - -/** - * Wrapper for [duk_base64_decode](http://duktape.org/api.html#duk_base64_decode). - * - * @param ctx the context - * @param index the index - */ -inline void base64Decode(ContextPtr ctx, Index index) -{ - duk_base64_decode(ctx, index); -} - -/** - * Wrapper for [duk_base64_encode](http://duktape.org/api.html#duk_base64_encode). - * - * @param ctx the context - * @param index the index - */ -inline void base64Encode(ContextPtr ctx, Index index) -{ - duk_base64_encode(ctx, index); -} - -/** - * Wrapper for [duk_call](http://duktape.org/api.html#duk_call). - * - * @param ctx the context - * @param nargs the number of arguments - */ -inline void call(ContextPtr ctx, Index nargs = 0) -{ - duk_call(ctx, nargs); -} - -/** - * Wrapper for [duk_call_method](http://duktape.org/api.html#duk_call_method). - * - * @param ctx the context - * @param nargs the number of arguments - */ -inline void callMethod(ContextPtr ctx, Index nargs = 0) -{ - duk_call_method(ctx, nargs); -} - -/** - * Wrapper for [duk_call_prop](http://duktape.org/api.html#duk_call_prop). - * - * @param ctx the context - * @param index the object index - * @param nargs the number of arguments - */ -inline void callProperty(ContextPtr ctx, Index index, Index nargs = 0) -{ - duk_call_prop(ctx, index, nargs); -} - -/** - * Wrapper for [duk_char_code_at](http://duktape.org/api.html#duk_char_code_at). - * - * @param ctx the context - * @param index the index - * @param charOffset the offset - */ -inline CodePoint charCodeAt(ContextPtr ctx, Index index, Size charOffset) -{ - return duk_char_code_at(ctx, index, charOffset); -} - -/** - * Wrapper for [duk_check_stack](http://duktape.org/api.html#duk_check_stack). - * - * @param ctx the context - * @param extra the extra space - * @return true if space is available - */ -inline bool checkStack(ContextPtr ctx, Index extra) -{ - return duk_check_stack(ctx, extra); -} - -/** - * Wrapper for [duk_check_stack_top](http://duktape.org/api.html#duk_check_stack_top). - * - * @param ctx the context - * @param top the extra space - * @return true if space is available - */ -inline bool checkStackTop(ContextPtr ctx, Index top) -{ - return duk_check_stack_top(ctx, top); -} - -/** - * Wrapper for [duk_check_type](http://duktape.org/api.html#duk_check_type). - * - * @param ctx the context - * @param index the value index - * @param type the desired type - * @return true if object is given type - */ -inline bool checkType(ContextPtr ctx, Index index, int type) -{ - return duk_check_type(ctx, index, type); -} - -/** - * Wrapper for [duk_check_type_mask](http://duktape.org/api.html#duk_check_type_mask). - * - * @param ctx the context - * @param index the value index - * @param mask the desired mask - * @return true if object is one of the type - */ -inline bool checkTypeMask(ContextPtr ctx, Index index, unsigned mask) -{ - return duk_check_type_mask(ctx, index, mask); -} - -/** - * Wrapper for [duk_compact](http://duktape.org/api.html#duk_compact). - * - * @param ctx the context - * @param objIndex the object index - */ -inline void compact(ContextPtr ctx, Index objIndex) -{ - duk_compact(ctx, objIndex); -} - -/** - * Wrapper for [duk_concat](http://duktape.org/api.html#duk_concat). - * - * @param ctx the context - * @param count the number of values - */ -inline void concat(ContextPtr ctx, Index count) -{ - duk_concat(ctx, count); -} - -/** - * Wrapper for [duk_copy](http://duktape.org/api.html#duk_copy). - * - * @param from the from index - * @param to the destination - */ -inline void copy(ContextPtr ctx, Index from, Index to) -{ - duk_copy(ctx, from, to); -} - -/** - * Wrapper for [duk_def_prop](http://duktape.org/api.html#duk_def_prop). - * - * @param index the object index - * @param flags the flags - */ -inline void defineProperty(ContextPtr ctx, Index index, unsigned flags) -{ - duk_def_prop(ctx, index, flags); -} - -/** - * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop). - * - * @param index the object index - * @return true if deleted - */ -inline bool deleteProperty(ContextPtr ctx, Index index) -{ - return duk_del_prop(ctx, index); -} - -/** - * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop). - * - * @param index the object index - * @param position the property index - * @return true if deleted - */ -inline bool deleteProperty(ContextPtr ctx, Index index, unsigned position) -{ - return duk_del_prop_index(ctx, index, position); -} - -/** - * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop). - * - * @param index the object index - * @param name the property name - * @return true if deleted - */ -inline bool deleteProperty(ContextPtr ctx, Index index, const std::string &name) -{ - return duk_del_prop_string(ctx, index, name.c_str()); -} - -/** - * Wrapper for [duk_dup](http://duktape.org/api.html#duk_dup). - * - * @param index the value to copy - */ -inline void dup(ContextPtr ctx, int index = -1) -{ - duk_dup(ctx, index); -} - -/** - * Wrapper for [duk_equals](http://duktape.org/api.html#duk_equals). - * - * @param ctx the context - * @param index1 the first value - * @param index2 the second value - * @return true if they equal - */ -inline bool equals(ContextPtr ctx, Index index1, Index index2) -{ - return duk_equals(ctx, index1, index2); -} - -/** - * Wrapper for [duk_eval](http://duktape.org/api.html#duk_eval). - * - * @param ctx the context - */ -inline void eval(ContextPtr ctx) -{ - duk_eval(ctx); -} - -/** - * Wrapper for [duk_eval_file](http://duktape.org/api.html#duk_eval_file). - * - * @param ctx the context - * @param path the path - * @param result true to get the result at the top of the stack - */ -inline void evalFile(ContextPtr ctx, const std::string &path, bool result = true) -{ - if (result) - duk_eval_file(ctx, path.c_str()); - else - duk_eval_file_noresult(ctx, path.c_str()); -} - -/** - * Wrapper for [duk_eval_string](http://duktape.org/api.html#duk_eval_string). - * - * @param ctx the context - * @param src the source script - * @param result true to get the result at the top of the stack - */ -inline void evalString(ContextPtr ctx, const std::string &src, bool result = true) -{ - if (result) - duk_eval_string(ctx, src.c_str()); - else - duk_eval_string_noresult(ctx, src.c_str()); -} -/** - * Wrapper for [duk_gc](http://duktape.org/api.html#duk_gc). - * - * @param ctx the context - * @param flags the flags - */ -inline void gc(ContextPtr ctx, unsigned flags = 0) -{ - duk_gc(ctx, flags); -} - -/** - * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop). - * - * @param ctx the context - * @param index the object index - * @return true if has - */ -inline bool hasProperty(ContextPtr ctx, Index index) -{ - return duk_has_prop(ctx, index); -} - -/** - * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop). - * - * @param ctx the context - * @param index the object index - * @param position the property index - * @return true if has - */ -inline bool hasProperty(ContextPtr ctx, Index index, unsigned position) -{ - return duk_has_prop_index(ctx, index, position); -} - -/** - * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop). - * - * @param ctx the context - * @param index the object index - * @param name the property name - * @return true if has - */ -inline bool hasProperty(ContextPtr ctx, int index, const std::string &name) -{ - return duk_has_prop_string(ctx, index, name.c_str()); -} - -/** - * Wrapper for [duk_insert](http://duktape.org/api.html#duk_insert). - * - * @param ctx the context - * @param to the destination - * @note Wrapper of duk_insert - */ -inline void insert(ContextPtr ctx, Index to) -{ - duk_insert(ctx, to); -} - -/** - * Wrapper for [duk_instanceof](http://duktape.org/api.html#duk_instanceof). - * - * @param ctx the context - * @param idx1 the value to test - * @param idx2 the instance requested - * @return true if idx1 is instance of idx2 - */ -inline bool instanceof(ContextPtr ctx, Index idx1, Index idx2) -{ - return duk_instanceof(ctx, idx1, idx2); -} - -/** - * Wrapper for [duk_join](http://duktape.org/api.html#duk_join). - * - * @param ctx the context - * @param count the number of values - */ -inline void join(ContextPtr ctx, Index count) -{ - duk_join(ctx, count); -} - -/** - * Wrapper for [duk_json_decode](http://duktape.org/api.html#duk_json_decode). - * - * @param ctx the context - * @param index the index - */ -inline void jsonDecode(ContextPtr ctx, Index index) -{ - duk_json_decode(ctx, index); -} - -/** - * Wrapper for [duk_json_encode](http://duktape.org/api.html#duk_json_encode). - * - * @param ctx the context - * @param index the index - */ -inline void jsonEncode(ContextPtr ctx, Index index) -{ - duk_json_encode(ctx, index); -} - -/** - * Wrapper for [duk_normalize_index](http://duktape.org/api.html#duk_normalize_index). - * - * @param ctx the context - * @param index the index - */ -inline Index normalizeIndex(ContextPtr ctx, Index index) -{ - return duk_normalize_index(ctx, index); -} - -/** - * Wrapper for [duk_pcall](http://duktape.org/api.html#duk_pcall). - * - * @param ctx the context - * @param nargs the number of arguments - */ -inline int pcall(ContextPtr ctx, Index nargs = 0) -{ - return duk_pcall(ctx, nargs); -} - -/** - * Wrapper for [duk_peval](http://duktape.org/api.html#duk_peval). - * - * @param ctx the context - */ -inline int peval(ContextPtr ctx) -{ - return duk_peval(ctx); -} - -/** - * Wrapper for [duk_peval_file](http://duktape.org/api.html#duk_peval_file). - * - * @param ctx the context - * @param path the path - * @param result true to get the result at the top of the stack - */ -inline int pevalFile(ContextPtr ctx, const std::string &path, bool result = true) -{ - return result ? duk_peval_file(ctx, path.c_str()) : duk_peval_file_noresult(ctx, path.c_str()); -} - -/** - * Wrapper for [duk_peval_string](http://duktape.org/api.html#duk_peval_string). - * - * @param ctx the context - * @param src the source script - * @param result true to get the result at the top of the stack - */ -inline int pevalString(ContextPtr ctx, const std::string &src, bool result = true) -{ - return result ? duk_peval_string(ctx, src.c_str()) : duk_peval_string_noresult(ctx, src.c_str()); -} - -/** - * Wrapper for [duk_pop_n](http://duktape.org/api.html#duk_pop_n). - * - * @param ctx the context - * @param count the number of values to pop - */ -inline void pop(ContextPtr ctx, Index count = 1) -{ - duk_pop_n(ctx, count); -} - -/** - * Wrapper for [duk_remove](http://duktape.org/api.html#duk_remove). - * - * @param ctx the context - * @param index the value to remove - */ -inline void remove(ContextPtr ctx, Index index) -{ - duk_remove(ctx, index); -} - -/** - * Wrapper for [duk_replace](http://duktape.org/api.html#duk_replace). - * - * @param ctx the context - * @param index the value to replace by the value at the top of the stack - */ -inline void replace(ContextPtr ctx, Index index) -{ - duk_replace(ctx, index); -} - -/** - * Wrapper for [duk_set_prototype](http://duktape.org/api.html#duk_set_prototype). - * - * @param ctx the context - * @param index the value index - */ -inline void setPrototype(ContextPtr ctx, Index index) -{ - duk_set_prototype(ctx, index); -} - -/** - * Wrapper for [duk_swap](http://duktape.org/api.html#duk_swap). - * - * @param ctx the context - * @param index1 the first index - * @param index2 the second index - */ -inline void swap(ContextPtr ctx, Index index1, Index index2) -{ - duk_swap(ctx, index1, index2); -} - -/** - * Wrapper for [duk_swap_top](http://duktape.org/api.html#duk_swap_top). - * - * @param ctx the context - * @param index the index - */ -inline void swapTop(ContextPtr ctx, Index index) -{ - duk_swap_top(ctx, index); -} - -/** - * Wrapper for [duk_get_top](http://duktape.org/api.html#duk_get_top). - * - * @param ctx the context - * @return the stack size - */ -inline int top(ContextPtr ctx) noexcept -{ - return duk_get_top(ctx); -} - -/** - * Wrapper for [duk_get_type](http://duktape.org/api.html#duk_get_type). - * - * @param ctx the context - * @param index the idnex - * @return the type - */ -inline int type(ContextPtr ctx, Index index) noexcept -{ - return duk_get_type(ctx, index); -} - -/* - * Push / Get / Require / Is / Optional - * ---------------------------------------------------------- - * - * The following functions are used to push, get or check values from the stack. They use specialization - * of TypeTraits class. - */ - -/** - * Push a value into the stack. Calls TypeTraits<T>::push(*this, value); - * - * @param value the value to forward - */ -template <typename Type> -inline void push(ContextPtr ctx, Type &&value) -{ - TypeTraits<std::decay_t<Type>>::push(ctx, std::forward<Type>(value)); -} - -/** - * Generic template function to get a value from the stack. - * - * @param index the index - * @return the value - */ -template <typename Type> -inline auto get(ContextPtr ctx, int index) -> decltype(TypeTraits<Type>::get(ctx, 0)) -{ - return TypeTraits<Type>::get(ctx, index); -} - -/** - * Require a type at the specified index. - * - * @param index the index - * @return the value - */ -template <typename Type> -inline auto require(ContextPtr ctx, int index) -> decltype(TypeTraits<Type>::require(ctx, 0)) -{ - return TypeTraits<Type>::require(ctx, index); -} - -/** - * Check if a value is a type of T. - * - * The TypeTraits<T> must have `static bool is(ContextPtr ptr, int index)`. - * - * @param index the value index - * @return true if is the type - */ -template <typename T> -inline bool is(ContextPtr ctx, int index) -{ - return TypeTraits<T>::is(ctx, index); -} - -/** - * Get an optional value from the stack, if the value is not available of not the correct type, - * return defaultValue instead. - * - * The TypeTraits<T> must have `static T optional(Context &, int index, T &&defaultValue)`. - * - * @param index the value index - * @param defaultValue the value replacement - * @return the value or defaultValue - */ -template <typename Type> -inline auto optional(ContextPtr ctx, int index, Type &&defaultValue) -{ - return TypeTraits<std::decay_t<Type>>::optional(ctx, index, std::forward<Type>(defaultValue)); -} - -/* - * Properties management - * ---------------------------------------------------------- - * - * The following functions are used to read or set properties on objects or globals also using TypeTraits. - */ - -/** - * Get the property `name' as value from the object at the specified index. - * - * @param index the object index - * @param name the property name - * @return the value - * @note The stack is unchanged - */ -template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> -inline auto getProperty(ContextPtr ctx, int index, const std::string &name) -> decltype(get<Type>(ctx, 0)) -{ - duk_get_prop_string(ctx, index, name.c_str()); - decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Get a property by index, for arrays. - * - * @param index the object index - * @param position the position int the object - * @return the value - * @note The stack is unchanged - */ -template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> -inline auto getProperty(ContextPtr ctx, int index, int position) -> decltype(get<Type>(ctx, 0)) -{ - duk_get_prop_index(ctx, index, position); - decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Get the property `name' and push it to the stack from the object at the specified index. - * - * @param index the object index - * @param name the property name - * @note The stack contains the property value - */ -template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> -inline void getProperty(ContextPtr ctx, int index, const std::string &name) -{ - duk_get_prop_string(ctx, index, name.c_str()); -} - -/** - * Get the property by index and push it to the stack from the object at the specified index. - * - * @param index the object index - * @param position the position in the object - * @note The stack contains the property value - */ -template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> -inline void getProperty(ContextPtr ctx, int index, int position) -{ - duk_get_prop_index(ctx, index, position); -} - -/** - * Get an optional property `name` from the object at the specified index. - * - * @param index the object index - * @param name the property name - * @param def the default value - * @return the value or def - * @note The stack is unchanged - */ -template <typename Type, typename DefaultValue> -inline auto optionalProperty(ContextPtr ctx, int index, const std::string &name, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) -{ - duk_get_prop_string(ctx, index, name.c_str()); - decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def)); - duk_pop(ctx); - - return value; -} - -/** - * Get an optional property by index, for arrays - * - * @param index the object index - * @param position the position int the object - * @param def the default value - * @return the value or def - * @note The stack is unchanged - */ -template <typename Type, typename DefaultValue> -inline auto optionalProperty(ContextPtr ctx, int index, int position, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) -{ - duk_get_prop_index(ctx, index, position); - decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def)); - duk_pop(ctx); - - return value; -} - -/** - * Set a property to the object at the specified index. - * - * @param index the object index - * @param name the property name - * @param value the value to forward - * @note The stack is unchanged - */ -template <typename Type> -void putProperty(ContextPtr ctx, int index, const std::string &name, Type &&value) -{ - index = duk_normalize_index(ctx, index); - - push(ctx, std::forward<Type>(value)); - duk_put_prop_string(ctx, index, name.c_str()); -} - -/** - * Set a property by index, for arrays. - * - * @param index the object index - * @param position the position in the object - * @param value the value to forward - * @note The stack is unchanged - */ -template <typename Type> -void putProperty(ContextPtr ctx, int index, int position, Type &&value) -{ - index = duk_normalize_index(ctx, index); - - push(ctx, std::forward<Type>(value)); - duk_put_prop_index(ctx, index, position); -} - -/** - * Put the value that is at the top of the stack as property to the object. - * - * @param index the object index - * @param name the property name - */ -inline void putProperty(ContextPtr ctx, int index, const std::string &name) -{ - duk_put_prop_string(ctx, index, name.c_str()); -} - -/** - * Put the value that is at the top of the stack to the object as index. - * - * @param index the object index - * @param position the position in the object - */ -inline void putProperty(ContextPtr ctx, int index, int position) -{ - duk_put_prop_index(ctx, index, position); -} - -/** - * Get a global value. - * - * @param name the name of the global variable - * @return the value - */ -template <typename Type> -inline auto getGlobal(ContextPtr ctx, const std::string &name, std::enable_if_t<!std::is_void<Type>::value> * = nullptr) -> decltype(get<Type>(ctx, 0)) -{ - duk_get_global_string(ctx, name.c_str()); - decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Overload that push the value at the top of the stack instead of returning it. - */ -template <typename Type> -inline void getGlobal(ContextPtr ctx, const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr) noexcept -{ - duk_get_global_string(ctx, name.c_str()); -} - -/** - * Set a global variable. - * - * @param name the name of the global variable - * @param type the value to set - */ -template <typename Type> -inline void putGlobal(ContextPtr ctx, const std::string &name, Type&& type) -{ - push(ctx, std::forward<Type>(type)); - duk_put_global_string(ctx, name.c_str()); -} - -/** - * Put the value at the top of the stack as global property. - * - * @param name the property name - */ -inline void putGlobal(ContextPtr ctx, const std::string &name) -{ - duk_put_global_string(ctx, name.c_str()); -} - -/* - * Extra functions - * ---------------------------------------------------------- - * - * The following functions are implemented for convenience and do not exists in the native Duktape API. - */ - -/** - * Enumerate an object or an array at the specified index. - * - * @param index the object or array index - * @param flags the optional flags to pass to duk_enum - * @param getvalue set to true if you want to extract the value - * @param func the function to call for each properties - */ -template <typename Func> -void enumerate(ContextPtr ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func) -{ - duk_enum(ctx, index, flags); - - while (duk_next(ctx, -1, getvalue)) { - func(ctx); - duk_pop_n(ctx, 1 + (getvalue ? 1 : 0)); - } - - duk_pop(ctx); -} - -/** - * Return the this binding of the current function. - * - * @return the this binding as the template given - */ -template <typename T> -inline auto self(ContextPtr ctx) -> decltype(TypeTraits<T>::get(ctx, 0)) -{ - duk_push_this(ctx); - decltype(TypeTraits<T>::get(ctx, 0)) value = TypeTraits<T>::get(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Throw an ECMAScript exception. - * - * @param ex the exception - */ -template <typename Exception> -void raise(ContextPtr ctx, const Exception &ex) -{ - ex.raise(ctx); -} - -/** - * Wrapper for duk_throw. - * - * @param ctx the context - */ -inline void raise(ContextPtr ctx) -{ - duk_throw(ctx); -} - -/** - * Wrapper for duk_error. - * - * @param ctx the context - * @param type the error type (e.g. DUK_ERR_REFERENCE_ERROR) - * @param fmt the format string - * @param args the arguments - */ -template <typename... Args> -inline void raise(ContextPtr ctx, int type, const char *fmt, Args&&... args) -{ - duk_error(ctx, type, fmt, std::forward<Args>(args)...); -} - -/** - * Wrapper for duk_new. - * - * @param ctx the context - * @param nargs the number of arguments - */ -inline void create(ContextPtr ctx, int nargs = 0) -{ - duk_new(ctx, nargs); -} - -/** - * Construct the object in place, setting value as this binding. - * - * The TypeTraits<T> must have the following requirements: - * - * - static void construct(Context &, T): must update this with the value and keep the stack unchanged - * - * @param value the value to forward - * @see self - */ -template <typename T> -inline void construct(ContextPtr ctx, T &&value) -{ - TypeTraits<std::decay_t<T>>::construct(ctx, std::forward<T>(value)); -} - -/** - * Sign the given object with the name from T. - * - * This is automatically done for when constructing/pushing object with Shared and Pointer helpers, however you need - * to manually add it when using inheritance. - */ -template <typename T> -inline void sign(ContextPtr ctx, Index index) -{ - StackAssert sa(ctx, 0); - - index = duk_normalize_index(ctx, index); - - duk_push_string(ctx, TypeTraits<T>::name().c_str()); - duk_push_boolean(ctx, true); - duk_def_prop(ctx, index < 0 ? index : index, DUK_DEFPROP_HAVE_VALUE); - - /* Do for inherited classes */ - for (const std::string &parent : TypeTraits<T>::inherits()) { - duk_push_string(ctx, parent.c_str()); - duk_push_boolean(ctx, true); - duk_def_prop(ctx, index < 0 ? index : index, DUK_DEFPROP_HAVE_VALUE); - } -} - -/** - * Check if the object at the given index is signed by T or raise TypeError if not. - * - * @param ctx the context - * @param index the index - * @see sign - */ -template <typename T> -inline void checkSignature(ContextPtr ctx, Index index) -{ - StackAssert sa(ctx, 0); - - if (!is<Object>(ctx, index) || !getProperty<bool>(ctx, index, TypeTraits<T>::name())) - raise(ctx, DUK_ERR_TYPE_ERROR, "invalid this binding"); -} - -/** - * Tells if the object at the specified index is of type T. - * - * @param ctx the context - * @param index the index - */ -template <typename T> -inline bool isSigned(ContextPtr ctx, Index index) -{ - StackAssert sa(ctx, 0); - - return is<Object>(ctx, index) && getProperty<bool>(ctx, index, TypeTraits<T>::name()); -} - -/* ------------------------------------------------------------------ - * Exception handling - * ------------------------------------------------------------------ */ - -/** - * @class Error - * @brief Base ECMAScript error class. - * @warning Override the function create for your own exceptions - */ -class Error { -private: - int m_type{DUK_ERR_ERROR}; - std::string m_message; - -protected: - /** - * Constructor with a type of error specified, specially designed for derived errors. - * - * @param type of error (e.g. DUK_ERR_ERROR) - * @param message the message - */ - inline Error(int type, std::string message) noexcept - : m_type(type) - , m_message(std::move(message)) - { - } - -public: - /** - * Constructor with a message. - * - * @param message the message - */ - inline Error(std::string message) noexcept - : m_message(std::move(message)) - { - } - - /** - * Create the exception on the stack. - * - * @note the default implementation search for the global variables - * @param ctx the context - */ - virtual void raise(ContextPtr ctx) const noexcept - { - duk_error(ctx, m_type, "%s", m_message.c_str()); - } -}; - -/** - * @class EvalError - * @brief Error in eval() function. - */ -class EvalError : public Error { -public: - /** - * Construct an EvalError. - * - * @param message the message - */ - inline EvalError(std::string message) noexcept - : Error(DUK_ERR_EVAL_ERROR, std::move(message)) - { - } -}; - -/** - * @class RangeError - * @brief Value is out of range. - */ -class RangeError : public Error { -public: - /** - * Construct an RangeError. - * - * @param message the message - */ - inline RangeError(std::string message) noexcept - : Error(DUK_ERR_RANGE_ERROR, std::move(message)) - { - } -}; - -/** - * @class ReferenceError - * @brief Trying to use a variable that does not exist. - */ -class ReferenceError : public Error { -public: - /** - * Construct an ReferenceError. - * - * @param message the message - */ - inline ReferenceError(std::string message) noexcept - : Error(DUK_ERR_REFERENCE_ERROR, std::move(message)) - { - } -}; - -/** - * @class SyntaxError - * @brief Syntax error in the script. - */ -class SyntaxError : public Error { -public: - /** - * Construct an SyntaxError. - * - * @param message the message - */ - inline SyntaxError(std::string message) noexcept - : Error(DUK_ERR_SYNTAX_ERROR, std::move(message)) - { - } -}; - -/** - * @class TypeError - * @brief Invalid type given. - */ -class TypeError : public Error { -public: - /** - * Construct an TypeError. - * - * @param message the message - */ - inline TypeError(std::string message) noexcept - : Error(DUK_ERR_TYPE_ERROR, std::move(message)) - { - } -}; - -/** - * @class URIError - * @brief URI manipulation failure. - */ -class URIError : public Error { -public: - /** - * Construct an URIError. - * - * @param message the message - */ - inline URIError(std::string message) noexcept - : Error(DUK_ERR_URI_ERROR, std::move(message)) - { - } -}; - -/* ------------------------------------------------------------------ - * Standard overloads for TypeTraits<T> - * ------------------------------------------------------------------ */ - -/** - * @class TypeTraits<int> - * @brief Default implementation for int. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<int> { -public: - /** - * Get an integer, return 0 if not an integer. - * - * @param ctx the context - * @param index the index - * @return the integer - */ - static inline int get(ContextPtr ctx, int index) - { - return duk_get_int(ctx, index); - } - - /** - * Check if value is an integer. - * - * @param ctx the context - * @param index the index - * @return true if integer - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_number(ctx, index); - } - - /** - * Get an integer, return defaultValue if the value is not an integer. - * - * @param ctx the context - * @param index the index - * @param defaultValue the defaultValue - * @return the integer or defaultValue - */ - static inline int optional(ContextPtr ctx, int index, int defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push an integer. - * - * @param ctx the context - * @param value the value - */ - static inline void push(ContextPtr ctx, int value) - { - duk_push_int(ctx, value); - } - - /** - * Require an integer, throws a JavaScript exception if not an integer. - * - * @param ctx the context - * @param index the index - * @return the integer - */ - static inline int require(ContextPtr ctx, int index) - { - return duk_require_int(ctx, index); - } -}; - -/** - * @class TypeTraits<bool> - * @brief Default implementation for bool. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<bool> { -public: - /** - * Get a boolean, return 0 if not a boolean. - * - * @param ctx the context - * @param index the index - * @return the boolean - */ - static inline bool get(ContextPtr ctx, int index) - { - return duk_get_boolean(ctx, index); - } - - /** - * Check if value is a boolean. - * - * @param ctx the context - * @param index the index - * @return true if boolean - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_boolean(ctx, index); - } - - /** - * Get a bool, return defaultValue if the value is not a boolean. - * - * @param ctx the context - * @param index the index - * @param defaultValue the defaultValue - * @return the boolean or defaultValue - */ - static inline bool optional(ContextPtr ctx, int index, bool defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a boolean. - * - * @param ctx the context - * @param value the value - */ - static inline void push(ContextPtr ctx, bool value) - { - duk_push_boolean(ctx, value); - } - - /** - * Require a boolean, throws a JavaScript exception if not a boolean. - * - * @param ctx the context - * @param index the index - * @return the boolean - */ - static inline bool require(ContextPtr ctx, int index) - { - return duk_require_boolean(ctx, index); - } -}; - -/** - * @class TypeTraits<double> - * @brief Default implementation for double. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<double> { -public: - /** - * Get a double, return 0 if not a double. - * - * @param ctx the context - * @param index the index - * @return the double - */ - static inline double get(ContextPtr ctx, int index) - { - return duk_get_number(ctx, index); - } - - /** - * Check if value is a double. - * - * @param ctx the context - * @param index the index - * @return true if double - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_number(ctx, index); - } - - /** - * Get a double, return defaultValue if the value is not a double. - * - * @param ctx the context - * @param index the index - * @param defaultValue the defaultValue - * @return the double or defaultValue - */ - static inline double optional(ContextPtr ctx, int index, double defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a double. - * - * @param ctx the context - * @param value the value - */ - static inline void push(ContextPtr ctx, double value) - { - duk_push_number(ctx, value); - } - - /** - * Require a double, throws a JavaScript exception if not a double. - * - * @param ctx the context - * @param index the index - * @return the double - */ - static inline double require(ContextPtr ctx, int index) - { - return duk_require_number(ctx, index); - } -}; - -/** - * @class TypeTraits<std::string> - * @brief Default implementation for std::string. - * - * Provides: get, is, optional, push, require. - * - * Note: the functions allows embedded '\0'. - */ -template <> -class TypeTraits<std::string> { -public: - /** - * Get a string, return 0 if not a string. - * - * @param ctx the context - * @param index the index - * @return the string - */ - static inline std::string get(ContextPtr ctx, int index) - { - duk_size_t size; - const char *text = duk_get_lstring(ctx, index, &size); - - return std::string{text, size}; - } - - /** - * Check if value is a string. - * - * @param ctx the context - * @param index the index - * @return true if string - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_string(ctx, index); - } - - /** - * Get a string, return defaultValue if the value is not an string. - * - * @param ctx the context - * @param index the index - * @param defaultValue the defaultValue - * @return the string or defaultValue - */ - static inline std::string optional(ContextPtr ctx, int index, std::string defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a string. - * - * @param ctx the context - * @param value the value - */ - static inline void push(ContextPtr ctx, const std::string &value) - { - duk_push_lstring(ctx, value.c_str(), value.length()); - } - - /** - * Require a string, throws a JavaScript exception if not a string. - * - * @param ctx the context - * @param index the index - * @return the string - */ - static inline std::string require(ContextPtr ctx, int index) - { - duk_size_t size; - const char *text = duk_require_lstring(ctx, index, &size); - - return std::string{text, size}; - } -}; - -/** - * @class TypeTraits<const char *> - * @brief Default implementation for const char literals. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<const char *> { -public: - /** - * Get a string, return 0 if not a string. - * - * @param ctx the context - * @param index the index - * @return the string - */ - static inline const char *get(ContextPtr ctx, int index) - { - return duk_get_string(ctx, index); - } - - /** - * Check if value is a string. - * - * @param ctx the context - * @param index the index - * @return true if string - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_string(ctx, index); - } - - /** - * Get an integer, return defaultValue if the value is not an integer. - * - * @param ctx the context - * @param index the index - * @param defaultValue the defaultValue - * @return the integer or defaultValue - */ - static inline const char *optional(ContextPtr ctx, int index, const char *defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a string. - * - * @param ctx the context - * @param value the value - */ - static inline void push(ContextPtr ctx, const char *value) - { - duk_push_string(ctx, value); - } - - /** - * Require a string, throws a JavaScript exception if not a string. - * - * @param ctx the context - * @param index the index - * @return the string - */ - static inline const char *require(ContextPtr ctx, int index) - { - return duk_require_string(ctx, index); - } -}; - -/** - * @brief Implementation for non-managed pointers. - * - * Provides: get, is, optional, push, require. - */ -template <typename T> -class TypeTraits<RawPointer<T>> { -public: - /** - * Get a pointer, return nullptr if not a pointer. - * - * @param ctx the context - * @param index the index - * @return the pointer - */ - static inline T *get(ContextPtr ctx, int index) - { - return static_cast<T *>(duk_to_pointer(ctx, index)); - } - - /** - * Check if value is a pointer. - * - * @param ctx the context - * @param index the index - * @return true if pointer - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_pointer(ctx, index); - } - - /** - * Get a pointer, return defaultValue if the value is not a pointer. - * - * @param ctx the context - * @param index the index - * @param defaultValue the defaultValue - * @return the pointer or defaultValue - */ - static inline T *optional(ContextPtr ctx, int index, RawPointer<T> defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue.object; - } - - /** - * Push a pointer. - * - * @param ctx the context - * @param value the value - */ - static inline void push(ContextPtr ctx, const RawPointer<T> &value) - { - duk_push_pointer(ctx, value.object); - } - - /** - * Require a pointer, throws a JavaScript exception if not a pointer. - * - * @param ctx the context - * @param index the index - * @return the pointer - */ - static inline T *require(ContextPtr ctx, int index) - { - return static_cast<T *>(duk_require_pointer(ctx, index)); - } -}; - -/** - * @class TypeTraits<Function> - * @brief Push C++ function to the stack. - * - * Provides: push. - * - * This implementation push a Duktape/C function that is wrapped as C++ for convenience. - */ -template <> -class TypeTraits<Function> { -public: - /** - * Check if the value at the given index is callable. - * - * @param ctx the context - * @param index the value index - * @return true if the value is callable - */ - static bool is(ContextPtr ctx, Index index) - { - return duk_is_callable(ctx, index); - } - - /** - * Push the C++ function, it is wrapped as Duktape/C function and allocated on the heap by moving the - * std::function. - * - * @param ctx the context - * @param fn the function - */ - static void push(ContextPtr ctx, Function fn) - { - duk_push_c_function(ctx, fn.function, fn.nargs); - } -}; - -/** - * @class TypeTraits<FunctionMap> - * @brief Put the functions to the object at the top of the stack. - * - * Provides: push. - */ -template <> -class TypeTraits<FunctionMap> { -public: - /** - * Push all functions to the object at the top of the stack. - * - * @param ctx the context - * @param map the map of function - */ - static inline void push(ContextPtr ctx, const FunctionMap &map) - { - StackAssert sa(ctx, 0); - - for (const auto &entry : map) { - duk_push_c_function(ctx, entry.second.function, entry.second.nargs); - duk_put_prop_string(ctx, -2, entry.first.c_str()); - } - } -}; - -/** - * @class TypeTraits<Object> - * @brief Push empty object to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits<Object> { -public: - /** - * Check if value is an object. - * - * @param ctx the context - * @param index the index - * @return true if object - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_object(ctx, index); - } - - /** - * Create an empty object on the stack. - * - * @param ctx the context - */ - static inline void push(ContextPtr ctx, const Object &) - { - duk_push_object(ctx); - } -}; - -/** - * @class TypeTraits<Array> - * @brief Push empty array to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits<Array> { -public: - /** - * Check if value is a array. - * - * @param ctx the context - * @param index the index - * @return true if array - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_array(ctx, index); - } - - /** - * Create an empty array on the stack. - * - * @param ctx the context - */ - static inline void push(ContextPtr ctx, const Array &) - { - duk_push_array(ctx); - } -}; - -/** - * @class TypeTraits<Undefined> - * @brief Push undefined value to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits<Undefined> { -public: - /** - * Check if value is undefined. - * - * @param ctx the context - * @param index the index - * @return true if undefined - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_undefined(ctx, index); - } - - /** - * Push undefined value on the stack. - * - * @param ctx the context - */ - static inline void push(ContextPtr ctx, const Undefined &) - { - duk_push_undefined(ctx); - } -}; - -/** - * @class TypeTraits<Null> - * @brief Push null value to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits<Null> { -public: - /** - * Check if value is null. - * - * @param ctx the context - * @param index the index - * @return true if null - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_null(ctx, index); - } - - /** - * Push null value on the stack. - * - * @param ctx the context - */ - static inline void push(ContextPtr ctx, const Null &) - { - duk_push_null(ctx); - } -}; - -/** - * @brief Push this binding into the stack. - * - * Provides: push. - */ -template <> -class TypeTraits<This> { -public: - /** - * Push this function into the stack. - * - * @param ctx the context - */ - static inline void push(ContextPtr ctx, const This &) - { - duk_push_this(ctx); - } -}; - -/** - * @class TypeTraits<Global> - * @brief Push the global object to the stack. - * - * Provides: push. - */ -template <> -class TypeTraits<Global> { -public: - /** - * Push the global object into the stack. - * - * @param ctx the context - */ - static inline void push(ContextPtr ctx, const Global &) - { - duk_push_global_object(ctx); - } -}; - -/** - * @brief Push a map of key-value pair as objects. - * - * Provides: push. - * - * This class is convenient for settings constants such as enums, string and such. - */ -template <typename T> -class TypeTraits<std::unordered_map<std::string, T>> { -public: - /** - * Put all values from the map as properties to the object at the top of the stack. - * - * @param ctx the context - * @param map the values - * @note You need an object at the top of the stack before calling this function - */ - static void push(ContextPtr ctx, const std::unordered_map<std::string, T> &map) - { - StackAssert sa(ctx, 0); - - for (const auto &pair : map) { - TypeTraits<T>::push(ctx, pair.second); - duk_put_prop_string(ctx, -2, pair.first.c_str()); - } - } -}; - -/** - * @brief Push or get vectors as JavaScript arrays. - * - * Provides: get, push. - */ -template <typename T> -class TypeTraits<std::vector<T>> { -public: - /** - * Get an array from the stack. - * - * @param ctx the context - * @param index the array index - * @return the array or empty array if the value is not an array - */ - static std::vector<T> get(ContextPtr ctx, int index) - { - StackAssert sa(ctx, 0); - - std::vector<T> result; - - if (!duk_is_array(ctx, -1)) - return result; - - int total = duk_get_length(ctx, index); - - for (int i = 0; i < total; ++i) - result.push_back(getProperty<T>(ctx, index, i)); - - return result; - } - - /** - * Create an array with the specified values. - * - * @param ctx the context - * @param array the values - */ - static void push(ContextPtr ctx, const std::vector<T> &array) - { - StackAssert sa(ctx, 1); - - duk_push_array(ctx); - - unsigned i = 0; - for (const auto &v : array) { - TypeTraits<T>::push(ctx, v); - duk_put_prop_index(ctx, -2, i++); - } - } -}; - -/** - * @brief Implementation of managed shared_ptr - * @see Shared - */ -template <typename T> -class TypeTraits<Shared<T>> { -private: - static void apply(ContextPtr ctx, std::shared_ptr<T> value) - { - StackAssert sa(ctx, 0); - - sign<T>(ctx, -1); - - duk_push_pointer(ctx, new std::shared_ptr<T>(std::move(value))); - duk_put_prop_string(ctx, -2, "\xff""\xff""js-shared-ptr"); - duk_push_c_function(ctx, [] (duk_context *ctx) -> Ret { - duk_get_prop_string(ctx, 0, "\xff""\xff""js-shared-ptr"); - delete static_cast<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_push_null(ctx); - duk_put_prop_string(ctx, 0, "\xff""\xff""js-ptr"); - - return 0; - }, 1); - duk_set_finalizer(ctx, -2); - } - -public: - /** - * Construct the shared_ptr as this. - * - * @param ctx the context - * @param value the value - */ - static void construct(ContextPtr ctx, Shared<T> value) - { - StackAssert sa(ctx, 0); - - duk_push_this(ctx); - apply(ctx, std::move(value.object)); - duk_pop(ctx); - } - - /** - * Push a managed shared_ptr as object. - * - * @param ctx the context - * @param value the value - */ - static void push(ContextPtr ctx, Shared<T> value) - { - StackAssert sa(ctx, 1); - - duk_push_object(ctx); - apply(ctx, value.object); - TypeTraits<T>::prototype(ctx); - duk_set_prototype(ctx, -2); - } - - /** - * Get a managed shared_ptr from the stack. - * - * @param ctx the context - * @param index the object index - * @return the shared_ptr - */ - static std::shared_ptr<T> get(ContextPtr ctx, int index) - { - StackAssert sa(ctx, 0); - - checkSignature<T>(ctx, index); - - duk_get_prop_string(ctx, index, "\xff""\xff""js-shared-ptr"); - std::shared_ptr<T> value = *static_cast<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return value; - } -}; - -/** - * @brief Implementation of managed pointers - * @see Pointer - */ -template <typename T> -class TypeTraits<Pointer<T>> { -private: - static void apply(ContextPtr ctx, T *value) - { - StackAssert sa(ctx, 0); - - sign<T>(ctx, -1); - - duk_push_pointer(ctx, value); - duk_put_prop_string(ctx, -2, "\xff""\xff""js-ptr"); - duk_push_c_function(ctx, [] (duk_context *ctx) -> Ret { - duk_get_prop_string(ctx, 0, "\xff""\xff""js-ptr"); - delete static_cast<T *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_push_null(ctx); - duk_put_prop_string(ctx, 0, "\xff""\xff""js-ptr"); - - return 0; - }, 1); - duk_set_finalizer(ctx, -2); - } - -public: - /** - * Construct the pointer as this. - * - * @param ctx the context - * @param value the value - */ - static void construct(ContextPtr ctx, Pointer<T> value) - { - StackAssert sa(ctx, 0); - - duk_push_this(ctx); - apply(ctx, value.object); - duk_pop(ctx); - } - - /** - * Push a managed pointer as object. - * - * @param ctx the context - * @param value the value - */ - static void push(ContextPtr ctx, Pointer<T> value) - { - StackAssert sa(ctx, 1); - - duk_push_object(ctx); - apply(ctx, value.object); - TypeTraits<T>::prototype(ctx); - duk_set_prototype(ctx, -2); - } - - /** - * Get a managed pointer from the stack. - * - * @param ctx the context - * @param index the object index - * @return the pointer - * @warning Do not store the pointer into the C++ side, the object can be deleted at any time - */ - static T *get(ContextPtr ctx, int index) - { - StackAssert sa(ctx, 0); - - checkSignature<T>(ctx, index); - - duk_get_prop_string(ctx, index, "\xff""\xff""js-ptr"); - T *value = static_cast<T *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return value; - } -}; - -} // !duk - -} // !irccd - -#endif // !IRCCD_JS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/js.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,2381 @@ +/* + * js.hpp -- JavaScript C++14 wrapper for Duktape + * + * Copyright (c) 2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JS_HPP +#define IRCCD_JS_HPP + +/** + * @file js.hpp + * @brief Bring JavaScript using Duktape. + * + * This file provides usual Duktape function renamed and placed into `duk` namespace. It also replaces error + * code with exceptions when possible. + * + * For convenience, this file also provides templated functions, overloads and much more. + */ + +#include <cassert> +#include <functional> +#include <memory> +#include <string> +#include <type_traits> +#include <unordered_map> +#include <utility> +#include <vector> + +#include <duktape.h> + +namespace irccd { + +/** + * Duktape C++ namespace wrapper. + */ +namespace duk { + +class Context; + +using CodePoint = duk_codepoint_t; +using ContextPtr = duk_context *; +using Index = duk_idx_t; +using Ret = duk_ret_t; +using Size = duk_size_t; + +/** + * @class StackAssert + * @brief Stack sanity checker. + * + * Instanciate this class where you need to manipulate the Duktape stack outside a Duktape/C function, its destructor + * will examinate if the stack size matches the user expected size. + * + * When compiled with NDEBUG, this class does nothing. + * + * To use it, just declare an lvalue at the beginning of your function. + */ +class StackAssert { +#if !defined(NDEBUG) +private: + ContextPtr m_context; + unsigned m_expected; + unsigned m_begin; +#endif + +public: + /** + * Create the stack checker. + * + * No-op if NDEBUG is set. + * + * @param ctx the context + * @param expected the size expected relative to the already existing values + */ + inline StackAssert(ContextPtr ctx, unsigned expected = 0) noexcept +#if !defined(NDEBUG) + : m_context(ctx) + , m_expected(expected) + , m_begin(static_cast<unsigned>(duk_get_top(ctx))) +#endif + { +#if defined(NDEBUG) + (void)ctx; + (void)expected; +#endif + } + + /** + * Verify the expected size. + * + * No-op if NDEBUG is set. + */ + inline ~StackAssert() noexcept + { +#if !defined(NDEBUG) + assert((unsigned)duk_get_top(m_context) - m_begin == m_expected); +#endif + } +}; + +/** + * @class Object + * @brief Empty class tag for push() function. + */ +class Object { +}; + +/** + * @class Array + * @brief Empty class tag for push() function. + */ +class Array { +}; + +/** + * @class Global + * @brief Empty class tag to push the global object. + */ +class Global { +}; + +/** + * @class Undefined + * @brief Empty class tag to push undefined to the stack. + */ +class Undefined { +}; + +/** + * @class Null + * @brief Empty class tag to push null to the stack. + */ +class Null { +}; + +/** + * @class This + * @brief Empty class tag to push this binding to the stack. + */ +class This { +}; + +/** + * @class RawPointer + * @brief Push a non-managed pointer to Duktape, the pointer will never be deleted. + * @note For a managed pointer with prototype, see Pointer + */ +template <typename T> +class RawPointer { +public: + /** + * The pointer to push. + */ + T *object; +}; + +/** + * @brief Manage shared_ptr from C++ and JavaScript + * + * This class allowed you to push and retrieve shared_ptr from C++ and JavaScript without taking care of ownership + * and deletion. + * + */ +template <typename T> +class Shared { +public: + /** + * The shared object. + */ + std::shared_ptr<T> object; +}; + +/** + * @brief Manage pointers from C++ and JavaScript + * + * This class allowed you to push and retrieve C++ pointers from C++ and JavaScript. The object will be deleted when + * the JavaScript garbage collectors collect them so never store a pointer created with this. + * + * The only requirement is to have the function `void prototype(Context &ctx)` in your class T. + */ +template <typename T> +class Pointer { +public: + /** + * The object. + */ + T *object{nullptr}; +}; + +/** + * @class Function + * @brief Duktape/C function definition. + * + * This class wraps the std::function as a Duktape/C function by storing a copied pointer. + */ +class Function { +public: + /** + * The function pointer, must not be null. + */ + duk_c_function function; + + /** + * Number of args that the function takes + */ + duk_idx_t nargs{0}; +}; + +/** + * Map of functions to set on an object. + */ +using FunctionMap = std::unordered_map<std::string, Function>; + +/** + * Map of string to type, ideal for setting constants like enums. + */ +template <typename Type> +using Map = std::unordered_map<std::string, Type>; + +/** + * @class ErrorInfo + * @brief Error description. + * + * This class fills the fields got in an Error object. + */ +class ErrorInfo : public std::exception { +public: + std::string name; //!< name of error + std::string message; //!< error message + std::string stack; //!< stack if available + std::string fileName; //!< filename if applicable + int lineNumber{0}; //!< line number if applicable + + /** + * Get the error message. This effectively returns message field. + * + * @return the message + */ + const char *what() const noexcept override + { + return message.c_str(); + } +}; + +/** + * @class TypeTraits + * @brief Type information to implement new types in JavaScript's context. + * + * This class depending on your needs may have the following functions: + * + * - `static void construct(Context &ctx, Type value)` + * - `static Type get(Context &ctx, int index)` + * - `static bool is(Context &ctx, int index)` + * - `static Type optional(Context &ctx, int index, Type defaultValue)` + * - `static void push(Context &ctx, Type value)` + * - `static Type require(Context &ctx, int index)` + * + * The `construct` function is used in Context::construct to build a new value as this (e.g. constructors). + * + * The `get` function is used in Context::get, Context::getProperty, Context::getGlobal to retrieve a value from the + * stack. + * + * The `is` function is used in Context::is to check if the value on the stack is of type `Type`. + * + * The `optional` function is used in Context::optional to get a value or a replacement if not applicable. + * + * The `push` function is used in Context::push to usually create a new value on the stack but some specializations + * may not (e.g. FunctionMap). + * + * The `require` function is used in Context::require to get a value from the stack or raise a JavaScript exception if + * not applicable. + * + * This class is fully specialized for: `bool`, `const char *`, `double`, `int`, `std::string`. + * + * It is also partially specialized for : `Global`, `Object`, `Array`, `Undefined`, `Null`, `std::vector<Type>`. + */ +template <typename Type> +class TypeTraits { +}; + +/** + * @class Context + * @brief RAII based Duktape handler. + * + * This class is implicitly convertible to duk_context for convenience. + */ +class Context { +private: + using Deleter = void (*)(duk_context *); + using Handle = std::unique_ptr<duk_context, Deleter>; + + Handle m_handle; + + Context(const Context &) = delete; + Context &operator=(const Context &) = delete; + Context(const Context &&) = delete; + Context &operator=(const Context &&) = delete; + +public: + /** + * Create default context. + */ + inline Context() + : m_handle(duk_create_heap_default(), duk_destroy_heap) + { + } + + /** + * Convert the context to the native Duktape/C type. + * + * @return the duk_context + */ + inline operator duk_context *() noexcept + { + return m_handle.get(); + } + + /** + * Convert the context to the native Duktape/C type. + * + * @return the duk_context + */ + inline operator duk_context *() const noexcept + { + return m_handle.get(); + } +}; + +/** + * Get the error object when a JavaScript error has been thrown (e.g. eval failure). + * + * @param ctx the context + * @param index the index + * @return the information + */ +inline ErrorInfo error(ContextPtr ctx, int index) +{ + ErrorInfo error; + + index = duk_normalize_index(ctx, index); + + duk_get_prop_string(ctx, index, "name"); + error.name = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "message"); + error.message = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "fileName"); + error.fileName = duk_to_string(ctx, -1); + duk_get_prop_string(ctx, index, "lineNumber"); + error.lineNumber = duk_to_int(ctx, -1); + duk_get_prop_string(ctx, index, "stack"); + error.stack = duk_to_string(ctx, -1); + duk_pop_n(ctx, 5); + + return error; +} + +/** + * Wrapper for [duk_base64_decode](http://duktape.org/api.html#duk_base64_decode). + * + * @param ctx the context + * @param index the index + */ +inline void base64Decode(ContextPtr ctx, Index index) +{ + duk_base64_decode(ctx, index); +} + +/** + * Wrapper for [duk_base64_encode](http://duktape.org/api.html#duk_base64_encode). + * + * @param ctx the context + * @param index the index + */ +inline void base64Encode(ContextPtr ctx, Index index) +{ + duk_base64_encode(ctx, index); +} + +/** + * Wrapper for [duk_call](http://duktape.org/api.html#duk_call). + * + * @param ctx the context + * @param nargs the number of arguments + */ +inline void call(ContextPtr ctx, Index nargs = 0) +{ + duk_call(ctx, nargs); +} + +/** + * Wrapper for [duk_call_method](http://duktape.org/api.html#duk_call_method). + * + * @param ctx the context + * @param nargs the number of arguments + */ +inline void callMethod(ContextPtr ctx, Index nargs = 0) +{ + duk_call_method(ctx, nargs); +} + +/** + * Wrapper for [duk_call_prop](http://duktape.org/api.html#duk_call_prop). + * + * @param ctx the context + * @param index the object index + * @param nargs the number of arguments + */ +inline void callProperty(ContextPtr ctx, Index index, Index nargs = 0) +{ + duk_call_prop(ctx, index, nargs); +} + +/** + * Wrapper for [duk_char_code_at](http://duktape.org/api.html#duk_char_code_at). + * + * @param ctx the context + * @param index the index + * @param charOffset the offset + */ +inline CodePoint charCodeAt(ContextPtr ctx, Index index, Size charOffset) +{ + return duk_char_code_at(ctx, index, charOffset); +} + +/** + * Wrapper for [duk_check_stack](http://duktape.org/api.html#duk_check_stack). + * + * @param ctx the context + * @param extra the extra space + * @return true if space is available + */ +inline bool checkStack(ContextPtr ctx, Index extra) +{ + return duk_check_stack(ctx, extra); +} + +/** + * Wrapper for [duk_check_stack_top](http://duktape.org/api.html#duk_check_stack_top). + * + * @param ctx the context + * @param top the extra space + * @return true if space is available + */ +inline bool checkStackTop(ContextPtr ctx, Index top) +{ + return duk_check_stack_top(ctx, top); +} + +/** + * Wrapper for [duk_check_type](http://duktape.org/api.html#duk_check_type). + * + * @param ctx the context + * @param index the value index + * @param type the desired type + * @return true if object is given type + */ +inline bool checkType(ContextPtr ctx, Index index, int type) +{ + return duk_check_type(ctx, index, type); +} + +/** + * Wrapper for [duk_check_type_mask](http://duktape.org/api.html#duk_check_type_mask). + * + * @param ctx the context + * @param index the value index + * @param mask the desired mask + * @return true if object is one of the type + */ +inline bool checkTypeMask(ContextPtr ctx, Index index, unsigned mask) +{ + return duk_check_type_mask(ctx, index, mask); +} + +/** + * Wrapper for [duk_compact](http://duktape.org/api.html#duk_compact). + * + * @param ctx the context + * @param objIndex the object index + */ +inline void compact(ContextPtr ctx, Index objIndex) +{ + duk_compact(ctx, objIndex); +} + +/** + * Wrapper for [duk_concat](http://duktape.org/api.html#duk_concat). + * + * @param ctx the context + * @param count the number of values + */ +inline void concat(ContextPtr ctx, Index count) +{ + duk_concat(ctx, count); +} + +/** + * Wrapper for [duk_copy](http://duktape.org/api.html#duk_copy). + * + * @param from the from index + * @param to the destination + */ +inline void copy(ContextPtr ctx, Index from, Index to) +{ + duk_copy(ctx, from, to); +} + +/** + * Wrapper for [duk_def_prop](http://duktape.org/api.html#duk_def_prop). + * + * @param index the object index + * @param flags the flags + */ +inline void defineProperty(ContextPtr ctx, Index index, unsigned flags) +{ + duk_def_prop(ctx, index, flags); +} + +/** + * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop). + * + * @param index the object index + * @return true if deleted + */ +inline bool deleteProperty(ContextPtr ctx, Index index) +{ + return duk_del_prop(ctx, index); +} + +/** + * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop). + * + * @param index the object index + * @param position the property index + * @return true if deleted + */ +inline bool deleteProperty(ContextPtr ctx, Index index, unsigned position) +{ + return duk_del_prop_index(ctx, index, position); +} + +/** + * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop). + * + * @param index the object index + * @param name the property name + * @return true if deleted + */ +inline bool deleteProperty(ContextPtr ctx, Index index, const std::string &name) +{ + return duk_del_prop_string(ctx, index, name.c_str()); +} + +/** + * Wrapper for [duk_dup](http://duktape.org/api.html#duk_dup). + * + * @param index the value to copy + */ +inline void dup(ContextPtr ctx, int index = -1) +{ + duk_dup(ctx, index); +} + +/** + * Wrapper for [duk_equals](http://duktape.org/api.html#duk_equals). + * + * @param ctx the context + * @param index1 the first value + * @param index2 the second value + * @return true if they equal + */ +inline bool equals(ContextPtr ctx, Index index1, Index index2) +{ + return duk_equals(ctx, index1, index2); +} + +/** + * Wrapper for [duk_eval](http://duktape.org/api.html#duk_eval). + * + * @param ctx the context + */ +inline void eval(ContextPtr ctx) +{ + duk_eval(ctx); +} + +/** + * Wrapper for [duk_eval_file](http://duktape.org/api.html#duk_eval_file). + * + * @param ctx the context + * @param path the path + * @param result true to get the result at the top of the stack + */ +inline void evalFile(ContextPtr ctx, const std::string &path, bool result = true) +{ + if (result) + duk_eval_file(ctx, path.c_str()); + else + duk_eval_file_noresult(ctx, path.c_str()); +} + +/** + * Wrapper for [duk_eval_string](http://duktape.org/api.html#duk_eval_string). + * + * @param ctx the context + * @param src the source script + * @param result true to get the result at the top of the stack + */ +inline void evalString(ContextPtr ctx, const std::string &src, bool result = true) +{ + if (result) + duk_eval_string(ctx, src.c_str()); + else + duk_eval_string_noresult(ctx, src.c_str()); +} +/** + * Wrapper for [duk_gc](http://duktape.org/api.html#duk_gc). + * + * @param ctx the context + * @param flags the flags + */ +inline void gc(ContextPtr ctx, unsigned flags = 0) +{ + duk_gc(ctx, flags); +} + +/** + * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop). + * + * @param ctx the context + * @param index the object index + * @return true if has + */ +inline bool hasProperty(ContextPtr ctx, Index index) +{ + return duk_has_prop(ctx, index); +} + +/** + * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop). + * + * @param ctx the context + * @param index the object index + * @param position the property index + * @return true if has + */ +inline bool hasProperty(ContextPtr ctx, Index index, unsigned position) +{ + return duk_has_prop_index(ctx, index, position); +} + +/** + * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop). + * + * @param ctx the context + * @param index the object index + * @param name the property name + * @return true if has + */ +inline bool hasProperty(ContextPtr ctx, int index, const std::string &name) +{ + return duk_has_prop_string(ctx, index, name.c_str()); +} + +/** + * Wrapper for [duk_insert](http://duktape.org/api.html#duk_insert). + * + * @param ctx the context + * @param to the destination + * @note Wrapper of duk_insert + */ +inline void insert(ContextPtr ctx, Index to) +{ + duk_insert(ctx, to); +} + +/** + * Wrapper for [duk_instanceof](http://duktape.org/api.html#duk_instanceof). + * + * @param ctx the context + * @param idx1 the value to test + * @param idx2 the instance requested + * @return true if idx1 is instance of idx2 + */ +inline bool instanceof(ContextPtr ctx, Index idx1, Index idx2) +{ + return duk_instanceof(ctx, idx1, idx2); +} + +/** + * Wrapper for [duk_join](http://duktape.org/api.html#duk_join). + * + * @param ctx the context + * @param count the number of values + */ +inline void join(ContextPtr ctx, Index count) +{ + duk_join(ctx, count); +} + +/** + * Wrapper for [duk_json_decode](http://duktape.org/api.html#duk_json_decode). + * + * @param ctx the context + * @param index the index + */ +inline void jsonDecode(ContextPtr ctx, Index index) +{ + duk_json_decode(ctx, index); +} + +/** + * Wrapper for [duk_json_encode](http://duktape.org/api.html#duk_json_encode). + * + * @param ctx the context + * @param index the index + */ +inline void jsonEncode(ContextPtr ctx, Index index) +{ + duk_json_encode(ctx, index); +} + +/** + * Wrapper for [duk_normalize_index](http://duktape.org/api.html#duk_normalize_index). + * + * @param ctx the context + * @param index the index + */ +inline Index normalizeIndex(ContextPtr ctx, Index index) +{ + return duk_normalize_index(ctx, index); +} + +/** + * Wrapper for [duk_pcall](http://duktape.org/api.html#duk_pcall). + * + * @param ctx the context + * @param nargs the number of arguments + */ +inline int pcall(ContextPtr ctx, Index nargs = 0) +{ + return duk_pcall(ctx, nargs); +} + +/** + * Wrapper for [duk_peval](http://duktape.org/api.html#duk_peval). + * + * @param ctx the context + */ +inline int peval(ContextPtr ctx) +{ + return duk_peval(ctx); +} + +/** + * Wrapper for [duk_peval_file](http://duktape.org/api.html#duk_peval_file). + * + * @param ctx the context + * @param path the path + * @param result true to get the result at the top of the stack + */ +inline int pevalFile(ContextPtr ctx, const std::string &path, bool result = true) +{ + return result ? duk_peval_file(ctx, path.c_str()) : duk_peval_file_noresult(ctx, path.c_str()); +} + +/** + * Wrapper for [duk_peval_string](http://duktape.org/api.html#duk_peval_string). + * + * @param ctx the context + * @param src the source script + * @param result true to get the result at the top of the stack + */ +inline int pevalString(ContextPtr ctx, const std::string &src, bool result = true) +{ + return result ? duk_peval_string(ctx, src.c_str()) : duk_peval_string_noresult(ctx, src.c_str()); +} + +/** + * Wrapper for [duk_pop_n](http://duktape.org/api.html#duk_pop_n). + * + * @param ctx the context + * @param count the number of values to pop + */ +inline void pop(ContextPtr ctx, Index count = 1) +{ + duk_pop_n(ctx, count); +} + +/** + * Wrapper for [duk_remove](http://duktape.org/api.html#duk_remove). + * + * @param ctx the context + * @param index the value to remove + */ +inline void remove(ContextPtr ctx, Index index) +{ + duk_remove(ctx, index); +} + +/** + * Wrapper for [duk_replace](http://duktape.org/api.html#duk_replace). + * + * @param ctx the context + * @param index the value to replace by the value at the top of the stack + */ +inline void replace(ContextPtr ctx, Index index) +{ + duk_replace(ctx, index); +} + +/** + * Wrapper for [duk_set_prototype](http://duktape.org/api.html#duk_set_prototype). + * + * @param ctx the context + * @param index the value index + */ +inline void setPrototype(ContextPtr ctx, Index index) +{ + duk_set_prototype(ctx, index); +} + +/** + * Wrapper for [duk_swap](http://duktape.org/api.html#duk_swap). + * + * @param ctx the context + * @param index1 the first index + * @param index2 the second index + */ +inline void swap(ContextPtr ctx, Index index1, Index index2) +{ + duk_swap(ctx, index1, index2); +} + +/** + * Wrapper for [duk_swap_top](http://duktape.org/api.html#duk_swap_top). + * + * @param ctx the context + * @param index the index + */ +inline void swapTop(ContextPtr ctx, Index index) +{ + duk_swap_top(ctx, index); +} + +/** + * Wrapper for [duk_get_top](http://duktape.org/api.html#duk_get_top). + * + * @param ctx the context + * @return the stack size + */ +inline int top(ContextPtr ctx) noexcept +{ + return duk_get_top(ctx); +} + +/** + * Wrapper for [duk_get_type](http://duktape.org/api.html#duk_get_type). + * + * @param ctx the context + * @param index the idnex + * @return the type + */ +inline int type(ContextPtr ctx, Index index) noexcept +{ + return duk_get_type(ctx, index); +} + +/* + * Push / Get / Require / Is / Optional + * ---------------------------------------------------------- + * + * The following functions are used to push, get or check values from the stack. They use specialization + * of TypeTraits class. + */ + +/** + * Push a value into the stack. Calls TypeTraits<T>::push(*this, value); + * + * @param value the value to forward + */ +template <typename Type> +inline void push(ContextPtr ctx, Type &&value) +{ + TypeTraits<std::decay_t<Type>>::push(ctx, std::forward<Type>(value)); +} + +/** + * Generic template function to get a value from the stack. + * + * @param index the index + * @return the value + */ +template <typename Type> +inline auto get(ContextPtr ctx, int index) -> decltype(TypeTraits<Type>::get(ctx, 0)) +{ + return TypeTraits<Type>::get(ctx, index); +} + +/** + * Require a type at the specified index. + * + * @param index the index + * @return the value + */ +template <typename Type> +inline auto require(ContextPtr ctx, int index) -> decltype(TypeTraits<Type>::require(ctx, 0)) +{ + return TypeTraits<Type>::require(ctx, index); +} + +/** + * Check if a value is a type of T. + * + * The TypeTraits<T> must have `static bool is(ContextPtr ptr, int index)`. + * + * @param index the value index + * @return true if is the type + */ +template <typename T> +inline bool is(ContextPtr ctx, int index) +{ + return TypeTraits<T>::is(ctx, index); +} + +/** + * Get an optional value from the stack, if the value is not available of not the correct type, + * return defaultValue instead. + * + * The TypeTraits<T> must have `static T optional(Context &, int index, T &&defaultValue)`. + * + * @param index the value index + * @param defaultValue the value replacement + * @return the value or defaultValue + */ +template <typename Type> +inline auto optional(ContextPtr ctx, int index, Type &&defaultValue) +{ + return TypeTraits<std::decay_t<Type>>::optional(ctx, index, std::forward<Type>(defaultValue)); +} + +/* + * Properties management + * ---------------------------------------------------------- + * + * The following functions are used to read or set properties on objects or globals also using TypeTraits. + */ + +/** + * Get the property `name' as value from the object at the specified index. + * + * @param index the object index + * @param name the property name + * @return the value + * @note The stack is unchanged + */ +template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> +inline auto getProperty(ContextPtr ctx, int index, const std::string &name) -> decltype(get<Type>(ctx, 0)) +{ + duk_get_prop_string(ctx, index, name.c_str()); + decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); + duk_pop(ctx); + + return value; +} + +/** + * Get a property by index, for arrays. + * + * @param index the object index + * @param position the position int the object + * @return the value + * @note The stack is unchanged + */ +template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> +inline auto getProperty(ContextPtr ctx, int index, int position) -> decltype(get<Type>(ctx, 0)) +{ + duk_get_prop_index(ctx, index, position); + decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); + duk_pop(ctx); + + return value; +} + +/** + * Get the property `name' and push it to the stack from the object at the specified index. + * + * @param index the object index + * @param name the property name + * @note The stack contains the property value + */ +template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> +inline void getProperty(ContextPtr ctx, int index, const std::string &name) +{ + duk_get_prop_string(ctx, index, name.c_str()); +} + +/** + * Get the property by index and push it to the stack from the object at the specified index. + * + * @param index the object index + * @param position the position in the object + * @note The stack contains the property value + */ +template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> +inline void getProperty(ContextPtr ctx, int index, int position) +{ + duk_get_prop_index(ctx, index, position); +} + +/** + * Get an optional property `name` from the object at the specified index. + * + * @param index the object index + * @param name the property name + * @param def the default value + * @return the value or def + * @note The stack is unchanged + */ +template <typename Type, typename DefaultValue> +inline auto optionalProperty(ContextPtr ctx, int index, const std::string &name, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) +{ + duk_get_prop_string(ctx, index, name.c_str()); + decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def)); + duk_pop(ctx); + + return value; +} + +/** + * Get an optional property by index, for arrays + * + * @param index the object index + * @param position the position int the object + * @param def the default value + * @return the value or def + * @note The stack is unchanged + */ +template <typename Type, typename DefaultValue> +inline auto optionalProperty(ContextPtr ctx, int index, int position, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) +{ + duk_get_prop_index(ctx, index, position); + decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def)); + duk_pop(ctx); + + return value; +} + +/** + * Set a property to the object at the specified index. + * + * @param index the object index + * @param name the property name + * @param value the value to forward + * @note The stack is unchanged + */ +template <typename Type> +void putProperty(ContextPtr ctx, int index, const std::string &name, Type &&value) +{ + index = duk_normalize_index(ctx, index); + + push(ctx, std::forward<Type>(value)); + duk_put_prop_string(ctx, index, name.c_str()); +} + +/** + * Set a property by index, for arrays. + * + * @param index the object index + * @param position the position in the object + * @param value the value to forward + * @note The stack is unchanged + */ +template <typename Type> +void putProperty(ContextPtr ctx, int index, int position, Type &&value) +{ + index = duk_normalize_index(ctx, index); + + push(ctx, std::forward<Type>(value)); + duk_put_prop_index(ctx, index, position); +} + +/** + * Put the value that is at the top of the stack as property to the object. + * + * @param index the object index + * @param name the property name + */ +inline void putProperty(ContextPtr ctx, int index, const std::string &name) +{ + duk_put_prop_string(ctx, index, name.c_str()); +} + +/** + * Put the value that is at the top of the stack to the object as index. + * + * @param index the object index + * @param position the position in the object + */ +inline void putProperty(ContextPtr ctx, int index, int position) +{ + duk_put_prop_index(ctx, index, position); +} + +/** + * Get a global value. + * + * @param name the name of the global variable + * @return the value + */ +template <typename Type> +inline auto getGlobal(ContextPtr ctx, const std::string &name, std::enable_if_t<!std::is_void<Type>::value> * = nullptr) -> decltype(get<Type>(ctx, 0)) +{ + duk_get_global_string(ctx, name.c_str()); + decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); + duk_pop(ctx); + + return value; +} + +/** + * Overload that push the value at the top of the stack instead of returning it. + */ +template <typename Type> +inline void getGlobal(ContextPtr ctx, const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr) noexcept +{ + duk_get_global_string(ctx, name.c_str()); +} + +/** + * Set a global variable. + * + * @param name the name of the global variable + * @param type the value to set + */ +template <typename Type> +inline void putGlobal(ContextPtr ctx, const std::string &name, Type&& type) +{ + push(ctx, std::forward<Type>(type)); + duk_put_global_string(ctx, name.c_str()); +} + +/** + * Put the value at the top of the stack as global property. + * + * @param name the property name + */ +inline void putGlobal(ContextPtr ctx, const std::string &name) +{ + duk_put_global_string(ctx, name.c_str()); +} + +/* + * Extra functions + * ---------------------------------------------------------- + * + * The following functions are implemented for convenience and do not exists in the native Duktape API. + */ + +/** + * Enumerate an object or an array at the specified index. + * + * @param index the object or array index + * @param flags the optional flags to pass to duk_enum + * @param getvalue set to true if you want to extract the value + * @param func the function to call for each properties + */ +template <typename Func> +void enumerate(ContextPtr ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func) +{ + duk_enum(ctx, index, flags); + + while (duk_next(ctx, -1, getvalue)) { + func(ctx); + duk_pop_n(ctx, 1 + (getvalue ? 1 : 0)); + } + + duk_pop(ctx); +} + +/** + * Return the this binding of the current function. + * + * @return the this binding as the template given + */ +template <typename T> +inline auto self(ContextPtr ctx) -> decltype(TypeTraits<T>::get(ctx, 0)) +{ + duk_push_this(ctx); + decltype(TypeTraits<T>::get(ctx, 0)) value = TypeTraits<T>::get(ctx, -1); + duk_pop(ctx); + + return value; +} + +/** + * Throw an ECMAScript exception. + * + * @param ex the exception + */ +template <typename Exception> +void raise(ContextPtr ctx, const Exception &ex) +{ + ex.raise(ctx); +} + +/** + * Wrapper for duk_throw. + * + * @param ctx the context + */ +inline void raise(ContextPtr ctx) +{ + duk_throw(ctx); +} + +/** + * Wrapper for duk_error. + * + * @param ctx the context + * @param type the error type (e.g. DUK_ERR_REFERENCE_ERROR) + * @param fmt the format string + * @param args the arguments + */ +template <typename... Args> +inline void raise(ContextPtr ctx, int type, const char *fmt, Args&&... args) +{ + duk_error(ctx, type, fmt, std::forward<Args>(args)...); +} + +/** + * Wrapper for duk_new. + * + * @param ctx the context + * @param nargs the number of arguments + */ +inline void create(ContextPtr ctx, int nargs = 0) +{ + duk_new(ctx, nargs); +} + +/** + * Construct the object in place, setting value as this binding. + * + * The TypeTraits<T> must have the following requirements: + * + * - static void construct(Context &, T): must update this with the value and keep the stack unchanged + * + * @param value the value to forward + * @see self + */ +template <typename T> +inline void construct(ContextPtr ctx, T &&value) +{ + TypeTraits<std::decay_t<T>>::construct(ctx, std::forward<T>(value)); +} + +/** + * Sign the given object with the name from T. + * + * This is automatically done for when constructing/pushing object with Shared and Pointer helpers, however you need + * to manually add it when using inheritance. + */ +template <typename T> +inline void sign(ContextPtr ctx, Index index) +{ + StackAssert sa(ctx, 0); + + index = duk_normalize_index(ctx, index); + + duk_push_string(ctx, TypeTraits<T>::name().c_str()); + duk_push_boolean(ctx, true); + duk_def_prop(ctx, index < 0 ? index : index, DUK_DEFPROP_HAVE_VALUE); + + /* Do for inherited classes */ + for (const std::string &parent : TypeTraits<T>::inherits()) { + duk_push_string(ctx, parent.c_str()); + duk_push_boolean(ctx, true); + duk_def_prop(ctx, index < 0 ? index : index, DUK_DEFPROP_HAVE_VALUE); + } +} + +/** + * Check if the object at the given index is signed by T or raise TypeError if not. + * + * @param ctx the context + * @param index the index + * @see sign + */ +template <typename T> +inline void checkSignature(ContextPtr ctx, Index index) +{ + StackAssert sa(ctx, 0); + + if (!is<Object>(ctx, index) || !getProperty<bool>(ctx, index, TypeTraits<T>::name())) + raise(ctx, DUK_ERR_TYPE_ERROR, "invalid this binding"); +} + +/** + * Tells if the object at the specified index is of type T. + * + * @param ctx the context + * @param index the index + */ +template <typename T> +inline bool isSigned(ContextPtr ctx, Index index) +{ + StackAssert sa(ctx, 0); + + return is<Object>(ctx, index) && getProperty<bool>(ctx, index, TypeTraits<T>::name()); +} + +/* ------------------------------------------------------------------ + * Exception handling + * ------------------------------------------------------------------ */ + +/** + * @class Error + * @brief Base ECMAScript error class. + * @warning Override the function create for your own exceptions + */ +class Error { +private: + int m_type{DUK_ERR_ERROR}; + std::string m_message; + +protected: + /** + * Constructor with a type of error specified, specially designed for derived errors. + * + * @param type of error (e.g. DUK_ERR_ERROR) + * @param message the message + */ + inline Error(int type, std::string message) noexcept + : m_type(type) + , m_message(std::move(message)) + { + } + +public: + /** + * Constructor with a message. + * + * @param message the message + */ + inline Error(std::string message) noexcept + : m_message(std::move(message)) + { + } + + /** + * Create the exception on the stack. + * + * @note the default implementation search for the global variables + * @param ctx the context + */ + virtual void raise(ContextPtr ctx) const noexcept + { + duk_error(ctx, m_type, "%s", m_message.c_str()); + } +}; + +/** + * @class EvalError + * @brief Error in eval() function. + */ +class EvalError : public Error { +public: + /** + * Construct an EvalError. + * + * @param message the message + */ + inline EvalError(std::string message) noexcept + : Error(DUK_ERR_EVAL_ERROR, std::move(message)) + { + } +}; + +/** + * @class RangeError + * @brief Value is out of range. + */ +class RangeError : public Error { +public: + /** + * Construct an RangeError. + * + * @param message the message + */ + inline RangeError(std::string message) noexcept + : Error(DUK_ERR_RANGE_ERROR, std::move(message)) + { + } +}; + +/** + * @class ReferenceError + * @brief Trying to use a variable that does not exist. + */ +class ReferenceError : public Error { +public: + /** + * Construct an ReferenceError. + * + * @param message the message + */ + inline ReferenceError(std::string message) noexcept + : Error(DUK_ERR_REFERENCE_ERROR, std::move(message)) + { + } +}; + +/** + * @class SyntaxError + * @brief Syntax error in the script. + */ +class SyntaxError : public Error { +public: + /** + * Construct an SyntaxError. + * + * @param message the message + */ + inline SyntaxError(std::string message) noexcept + : Error(DUK_ERR_SYNTAX_ERROR, std::move(message)) + { + } +}; + +/** + * @class TypeError + * @brief Invalid type given. + */ +class TypeError : public Error { +public: + /** + * Construct an TypeError. + * + * @param message the message + */ + inline TypeError(std::string message) noexcept + : Error(DUK_ERR_TYPE_ERROR, std::move(message)) + { + } +}; + +/** + * @class URIError + * @brief URI manipulation failure. + */ +class URIError : public Error { +public: + /** + * Construct an URIError. + * + * @param message the message + */ + inline URIError(std::string message) noexcept + : Error(DUK_ERR_URI_ERROR, std::move(message)) + { + } +}; + +/* ------------------------------------------------------------------ + * Standard overloads for TypeTraits<T> + * ------------------------------------------------------------------ */ + +/** + * @class TypeTraits<int> + * @brief Default implementation for int. + * + * Provides: get, is, optional, push, require. + */ +template <> +class TypeTraits<int> { +public: + /** + * Get an integer, return 0 if not an integer. + * + * @param ctx the context + * @param index the index + * @return the integer + */ + static inline int get(ContextPtr ctx, int index) + { + return duk_get_int(ctx, index); + } + + /** + * Check if value is an integer. + * + * @param ctx the context + * @param index the index + * @return true if integer + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_number(ctx, index); + } + + /** + * Get an integer, return defaultValue if the value is not an integer. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the integer or defaultValue + */ + static inline int optional(ContextPtr ctx, int index, int defaultValue) + { + return is(ctx, index) ? get(ctx, index) : defaultValue; + } + + /** + * Push an integer. + * + * @param ctx the context + * @param value the value + */ + static inline void push(ContextPtr ctx, int value) + { + duk_push_int(ctx, value); + } + + /** + * Require an integer, throws a JavaScript exception if not an integer. + * + * @param ctx the context + * @param index the index + * @return the integer + */ + static inline int require(ContextPtr ctx, int index) + { + return duk_require_int(ctx, index); + } +}; + +/** + * @class TypeTraits<bool> + * @brief Default implementation for bool. + * + * Provides: get, is, optional, push, require. + */ +template <> +class TypeTraits<bool> { +public: + /** + * Get a boolean, return 0 if not a boolean. + * + * @param ctx the context + * @param index the index + * @return the boolean + */ + static inline bool get(ContextPtr ctx, int index) + { + return duk_get_boolean(ctx, index); + } + + /** + * Check if value is a boolean. + * + * @param ctx the context + * @param index the index + * @return true if boolean + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_boolean(ctx, index); + } + + /** + * Get a bool, return defaultValue if the value is not a boolean. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the boolean or defaultValue + */ + static inline bool optional(ContextPtr ctx, int index, bool defaultValue) + { + return is(ctx, index) ? get(ctx, index) : defaultValue; + } + + /** + * Push a boolean. + * + * @param ctx the context + * @param value the value + */ + static inline void push(ContextPtr ctx, bool value) + { + duk_push_boolean(ctx, value); + } + + /** + * Require a boolean, throws a JavaScript exception if not a boolean. + * + * @param ctx the context + * @param index the index + * @return the boolean + */ + static inline bool require(ContextPtr ctx, int index) + { + return duk_require_boolean(ctx, index); + } +}; + +/** + * @class TypeTraits<double> + * @brief Default implementation for double. + * + * Provides: get, is, optional, push, require. + */ +template <> +class TypeTraits<double> { +public: + /** + * Get a double, return 0 if not a double. + * + * @param ctx the context + * @param index the index + * @return the double + */ + static inline double get(ContextPtr ctx, int index) + { + return duk_get_number(ctx, index); + } + + /** + * Check if value is a double. + * + * @param ctx the context + * @param index the index + * @return true if double + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_number(ctx, index); + } + + /** + * Get a double, return defaultValue if the value is not a double. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the double or defaultValue + */ + static inline double optional(ContextPtr ctx, int index, double defaultValue) + { + return is(ctx, index) ? get(ctx, index) : defaultValue; + } + + /** + * Push a double. + * + * @param ctx the context + * @param value the value + */ + static inline void push(ContextPtr ctx, double value) + { + duk_push_number(ctx, value); + } + + /** + * Require a double, throws a JavaScript exception if not a double. + * + * @param ctx the context + * @param index the index + * @return the double + */ + static inline double require(ContextPtr ctx, int index) + { + return duk_require_number(ctx, index); + } +}; + +/** + * @class TypeTraits<std::string> + * @brief Default implementation for std::string. + * + * Provides: get, is, optional, push, require. + * + * Note: the functions allows embedded '\0'. + */ +template <> +class TypeTraits<std::string> { +public: + /** + * Get a string, return 0 if not a string. + * + * @param ctx the context + * @param index the index + * @return the string + */ + static inline std::string get(ContextPtr ctx, int index) + { + duk_size_t size; + const char *text = duk_get_lstring(ctx, index, &size); + + return std::string{text, size}; + } + + /** + * Check if value is a string. + * + * @param ctx the context + * @param index the index + * @return true if string + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_string(ctx, index); + } + + /** + * Get a string, return defaultValue if the value is not an string. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the string or defaultValue + */ + static inline std::string optional(ContextPtr ctx, int index, std::string defaultValue) + { + return is(ctx, index) ? get(ctx, index) : defaultValue; + } + + /** + * Push a string. + * + * @param ctx the context + * @param value the value + */ + static inline void push(ContextPtr ctx, const std::string &value) + { + duk_push_lstring(ctx, value.c_str(), value.length()); + } + + /** + * Require a string, throws a JavaScript exception if not a string. + * + * @param ctx the context + * @param index the index + * @return the string + */ + static inline std::string require(ContextPtr ctx, int index) + { + duk_size_t size; + const char *text = duk_require_lstring(ctx, index, &size); + + return std::string{text, size}; + } +}; + +/** + * @class TypeTraits<const char *> + * @brief Default implementation for const char literals. + * + * Provides: get, is, optional, push, require. + */ +template <> +class TypeTraits<const char *> { +public: + /** + * Get a string, return 0 if not a string. + * + * @param ctx the context + * @param index the index + * @return the string + */ + static inline const char *get(ContextPtr ctx, int index) + { + return duk_get_string(ctx, index); + } + + /** + * Check if value is a string. + * + * @param ctx the context + * @param index the index + * @return true if string + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_string(ctx, index); + } + + /** + * Get an integer, return defaultValue if the value is not an integer. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the integer or defaultValue + */ + static inline const char *optional(ContextPtr ctx, int index, const char *defaultValue) + { + return is(ctx, index) ? get(ctx, index) : defaultValue; + } + + /** + * Push a string. + * + * @param ctx the context + * @param value the value + */ + static inline void push(ContextPtr ctx, const char *value) + { + duk_push_string(ctx, value); + } + + /** + * Require a string, throws a JavaScript exception if not a string. + * + * @param ctx the context + * @param index the index + * @return the string + */ + static inline const char *require(ContextPtr ctx, int index) + { + return duk_require_string(ctx, index); + } +}; + +/** + * @brief Implementation for non-managed pointers. + * + * Provides: get, is, optional, push, require. + */ +template <typename T> +class TypeTraits<RawPointer<T>> { +public: + /** + * Get a pointer, return nullptr if not a pointer. + * + * @param ctx the context + * @param index the index + * @return the pointer + */ + static inline T *get(ContextPtr ctx, int index) + { + return static_cast<T *>(duk_to_pointer(ctx, index)); + } + + /** + * Check if value is a pointer. + * + * @param ctx the context + * @param index the index + * @return true if pointer + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_pointer(ctx, index); + } + + /** + * Get a pointer, return defaultValue if the value is not a pointer. + * + * @param ctx the context + * @param index the index + * @param defaultValue the defaultValue + * @return the pointer or defaultValue + */ + static inline T *optional(ContextPtr ctx, int index, RawPointer<T> defaultValue) + { + return is(ctx, index) ? get(ctx, index) : defaultValue.object; + } + + /** + * Push a pointer. + * + * @param ctx the context + * @param value the value + */ + static inline void push(ContextPtr ctx, const RawPointer<T> &value) + { + duk_push_pointer(ctx, value.object); + } + + /** + * Require a pointer, throws a JavaScript exception if not a pointer. + * + * @param ctx the context + * @param index the index + * @return the pointer + */ + static inline T *require(ContextPtr ctx, int index) + { + return static_cast<T *>(duk_require_pointer(ctx, index)); + } +}; + +/** + * @class TypeTraits<Function> + * @brief Push C++ function to the stack. + * + * Provides: push. + * + * This implementation push a Duktape/C function that is wrapped as C++ for convenience. + */ +template <> +class TypeTraits<Function> { +public: + /** + * Check if the value at the given index is callable. + * + * @param ctx the context + * @param index the value index + * @return true if the value is callable + */ + static bool is(ContextPtr ctx, Index index) + { + return duk_is_callable(ctx, index); + } + + /** + * Push the C++ function, it is wrapped as Duktape/C function and allocated on the heap by moving the + * std::function. + * + * @param ctx the context + * @param fn the function + */ + static void push(ContextPtr ctx, Function fn) + { + duk_push_c_function(ctx, fn.function, fn.nargs); + } +}; + +/** + * @class TypeTraits<FunctionMap> + * @brief Put the functions to the object at the top of the stack. + * + * Provides: push. + */ +template <> +class TypeTraits<FunctionMap> { +public: + /** + * Push all functions to the object at the top of the stack. + * + * @param ctx the context + * @param map the map of function + */ + static inline void push(ContextPtr ctx, const FunctionMap &map) + { + StackAssert sa(ctx, 0); + + for (const auto &entry : map) { + duk_push_c_function(ctx, entry.second.function, entry.second.nargs); + duk_put_prop_string(ctx, -2, entry.first.c_str()); + } + } +}; + +/** + * @class TypeTraits<Object> + * @brief Push empty object to the stack. + * + * Provides: is, push. + */ +template <> +class TypeTraits<Object> { +public: + /** + * Check if value is an object. + * + * @param ctx the context + * @param index the index + * @return true if object + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_object(ctx, index); + } + + /** + * Create an empty object on the stack. + * + * @param ctx the context + */ + static inline void push(ContextPtr ctx, const Object &) + { + duk_push_object(ctx); + } +}; + +/** + * @class TypeTraits<Array> + * @brief Push empty array to the stack. + * + * Provides: is, push. + */ +template <> +class TypeTraits<Array> { +public: + /** + * Check if value is a array. + * + * @param ctx the context + * @param index the index + * @return true if array + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_array(ctx, index); + } + + /** + * Create an empty array on the stack. + * + * @param ctx the context + */ + static inline void push(ContextPtr ctx, const Array &) + { + duk_push_array(ctx); + } +}; + +/** + * @class TypeTraits<Undefined> + * @brief Push undefined value to the stack. + * + * Provides: is, push. + */ +template <> +class TypeTraits<Undefined> { +public: + /** + * Check if value is undefined. + * + * @param ctx the context + * @param index the index + * @return true if undefined + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_undefined(ctx, index); + } + + /** + * Push undefined value on the stack. + * + * @param ctx the context + */ + static inline void push(ContextPtr ctx, const Undefined &) + { + duk_push_undefined(ctx); + } +}; + +/** + * @class TypeTraits<Null> + * @brief Push null value to the stack. + * + * Provides: is, push. + */ +template <> +class TypeTraits<Null> { +public: + /** + * Check if value is null. + * + * @param ctx the context + * @param index the index + * @return true if null + */ + static inline bool is(ContextPtr ctx, int index) + { + return duk_is_null(ctx, index); + } + + /** + * Push null value on the stack. + * + * @param ctx the context + */ + static inline void push(ContextPtr ctx, const Null &) + { + duk_push_null(ctx); + } +}; + +/** + * @brief Push this binding into the stack. + * + * Provides: push. + */ +template <> +class TypeTraits<This> { +public: + /** + * Push this function into the stack. + * + * @param ctx the context + */ + static inline void push(ContextPtr ctx, const This &) + { + duk_push_this(ctx); + } +}; + +/** + * @class TypeTraits<Global> + * @brief Push the global object to the stack. + * + * Provides: push. + */ +template <> +class TypeTraits<Global> { +public: + /** + * Push the global object into the stack. + * + * @param ctx the context + */ + static inline void push(ContextPtr ctx, const Global &) + { + duk_push_global_object(ctx); + } +}; + +/** + * @brief Push a map of key-value pair as objects. + * + * Provides: push. + * + * This class is convenient for settings constants such as enums, string and such. + */ +template <typename T> +class TypeTraits<std::unordered_map<std::string, T>> { +public: + /** + * Put all values from the map as properties to the object at the top of the stack. + * + * @param ctx the context + * @param map the values + * @note You need an object at the top of the stack before calling this function + */ + static void push(ContextPtr ctx, const std::unordered_map<std::string, T> &map) + { + StackAssert sa(ctx, 0); + + for (const auto &pair : map) { + TypeTraits<T>::push(ctx, pair.second); + duk_put_prop_string(ctx, -2, pair.first.c_str()); + } + } +}; + +/** + * @brief Push or get vectors as JavaScript arrays. + * + * Provides: get, push. + */ +template <typename T> +class TypeTraits<std::vector<T>> { +public: + /** + * Get an array from the stack. + * + * @param ctx the context + * @param index the array index + * @return the array or empty array if the value is not an array + */ + static std::vector<T> get(ContextPtr ctx, int index) + { + StackAssert sa(ctx, 0); + + std::vector<T> result; + + if (!duk_is_array(ctx, -1)) + return result; + + int total = duk_get_length(ctx, index); + + for (int i = 0; i < total; ++i) + result.push_back(getProperty<T>(ctx, index, i)); + + return result; + } + + /** + * Create an array with the specified values. + * + * @param ctx the context + * @param array the values + */ + static void push(ContextPtr ctx, const std::vector<T> &array) + { + StackAssert sa(ctx, 1); + + duk_push_array(ctx); + + unsigned i = 0; + for (const auto &v : array) { + TypeTraits<T>::push(ctx, v); + duk_put_prop_index(ctx, -2, i++); + } + } +}; + +/** + * @brief Implementation of managed shared_ptr + * @see Shared + */ +template <typename T> +class TypeTraits<Shared<T>> { +private: + static void apply(ContextPtr ctx, std::shared_ptr<T> value) + { + StackAssert sa(ctx, 0); + + sign<T>(ctx, -1); + + duk_push_pointer(ctx, new std::shared_ptr<T>(std::move(value))); + duk_put_prop_string(ctx, -2, "\xff""\xff""js-shared-ptr"); + duk_push_c_function(ctx, [] (duk_context *ctx) -> Ret { + duk_get_prop_string(ctx, 0, "\xff""\xff""js-shared-ptr"); + delete static_cast<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_push_null(ctx); + duk_put_prop_string(ctx, 0, "\xff""\xff""js-ptr"); + + return 0; + }, 1); + duk_set_finalizer(ctx, -2); + } + +public: + /** + * Construct the shared_ptr as this. + * + * @param ctx the context + * @param value the value + */ + static void construct(ContextPtr ctx, Shared<T> value) + { + StackAssert sa(ctx, 0); + + duk_push_this(ctx); + apply(ctx, std::move(value.object)); + duk_pop(ctx); + } + + /** + * Push a managed shared_ptr as object. + * + * @param ctx the context + * @param value the value + */ + static void push(ContextPtr ctx, Shared<T> value) + { + StackAssert sa(ctx, 1); + + duk_push_object(ctx); + apply(ctx, value.object); + TypeTraits<T>::prototype(ctx); + duk_set_prototype(ctx, -2); + } + + /** + * Get a managed shared_ptr from the stack. + * + * @param ctx the context + * @param index the object index + * @return the shared_ptr + */ + static std::shared_ptr<T> get(ContextPtr ctx, int index) + { + StackAssert sa(ctx, 0); + + checkSignature<T>(ctx, index); + + duk_get_prop_string(ctx, index, "\xff""\xff""js-shared-ptr"); + std::shared_ptr<T> value = *static_cast<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return value; + } +}; + +/** + * @brief Implementation of managed pointers + * @see Pointer + */ +template <typename T> +class TypeTraits<Pointer<T>> { +private: + static void apply(ContextPtr ctx, T *value) + { + StackAssert sa(ctx, 0); + + sign<T>(ctx, -1); + + duk_push_pointer(ctx, value); + duk_put_prop_string(ctx, -2, "\xff""\xff""js-ptr"); + duk_push_c_function(ctx, [] (duk_context *ctx) -> Ret { + duk_get_prop_string(ctx, 0, "\xff""\xff""js-ptr"); + delete static_cast<T *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_push_null(ctx); + duk_put_prop_string(ctx, 0, "\xff""\xff""js-ptr"); + + return 0; + }, 1); + duk_set_finalizer(ctx, -2); + } + +public: + /** + * Construct the pointer as this. + * + * @param ctx the context + * @param value the value + */ + static void construct(ContextPtr ctx, Pointer<T> value) + { + StackAssert sa(ctx, 0); + + duk_push_this(ctx); + apply(ctx, value.object); + duk_pop(ctx); + } + + /** + * Push a managed pointer as object. + * + * @param ctx the context + * @param value the value + */ + static void push(ContextPtr ctx, Pointer<T> value) + { + StackAssert sa(ctx, 1); + + duk_push_object(ctx); + apply(ctx, value.object); + TypeTraits<T>::prototype(ctx); + duk_set_prototype(ctx, -2); + } + + /** + * Get a managed pointer from the stack. + * + * @param ctx the context + * @param index the object index + * @return the pointer + * @warning Do not store the pointer into the C++ side, the object can be deleted at any time + */ + static T *get(ContextPtr ctx, int index) + { + StackAssert sa(ctx, 0); + + checkSignature<T>(ctx, index); + + duk_get_prop_string(ctx, index, "\xff""\xff""js-ptr"); + T *value = static_cast<T *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return value; + } +}; + +} // !duk + +} // !irccd + +#endif // !IRCCD_JS_HPP
--- a/lib/irccd/json.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/json.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -20,7 +20,7 @@ #include <sstream> -#include "json.h" +#include "json.hpp" namespace irccd {
--- a/lib/irccd/json.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1183 +0,0 @@ -/* - * json.h -- C++14 JSON manipulation using jansson parser - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_JSON_H -#define IRCCD_JSON_H - -/** - * @file json.h - * @brief Jansson C++14 wrapper - * - * These classes can be used to build or parse JSON documents using jansson library. It is designed to be safe - * and explicit. It does not implement implicit sharing like jansson so when you access (e.g. Value::toObject) values - * you get real copies, thus when you read big documents it can has a performance cost. - */ - -#include <cassert> -#include <exception> -#include <initializer_list> -#include <map> -#include <string> -#include <utility> -#include <vector> - -namespace irccd { - -/** - * Json namespace. - */ -namespace json { - -/** - * @enum Type - * @brief Type of Value. - */ -enum class Type { - Array, //!< Value is an array [] - Boolean, //!< Value is boolean - Int, //!< Value is integer - Null, //!< Value is defined to null - Object, //!< Value is object {} - Real, //!< Value is float - String //!< Value is unicode string -}; - -/** - * @class Error - * @brief Error description. - */ -class Error : public std::exception { -private: - std::string m_text; - std::string m_source; - int m_line; - int m_column; - int m_position; - -public: - /** - * Create the error. - * - * @param text the text message - * @param source the source (e.g. file name) - * @param line the line number - * @param column the column number - * @param position the position - */ - inline Error(std::string text, std::string source, int line, int column, int position) noexcept - : m_text(std::move(text)) - , m_source(std::move(source)) - , m_line(line) - , m_column(column) - , m_position(position) - { - } - - /** - * Get the error message. - * - * @return the text - */ - inline const std::string &text() const noexcept - { - return m_text; - } - - /** - * Get the source (e.g. a file name). - * - * @return the source - */ - inline const std::string &source() const noexcept - { - return m_source; - } - - /** - * Get the line. - * - * @return the line - */ - inline int line() const noexcept - { - return m_line; - } - - /** - * Get the column. - * - * @return the column - */ - inline int column() const noexcept - { - return m_column; - } - - /** - * Get the position. - * - * @return the position - */ - inline int position() const noexcept - { - return m_position; - } - - /** - * Get the error message. - * - * @return the message - */ - const char *what() const noexcept override - { - return m_text.c_str(); - } -}; - -/** - * @class Buffer - * @brief Open JSON document from text. - */ -class Buffer { -public: - std::string text; //!< The JSON text -}; - -/** - * @class File - * @brief Open JSON document from a file. - */ -class File { -public: - std::string path; //!< The path to the file -}; - -/** - * @class Value - * @brief Generic JSON value wrapper. - */ -class Value { -private: - Type m_type{Type::Null}; - - union { - double m_number; - bool m_boolean; - int m_integer; - std::string m_string; - std::vector<Value> m_array; - std::map<std::string, Value> m_object; - }; - - void copy(const Value &); - void move(Value &&); - std::string toJson(int indent, int current) const; - - /** - * @class BaseIterator - * @brief This is the base class for iterator and const_iterator - * - * This iterator works for both arrays and objects. Because of that purpose, it is only available - * as forward iterator. - * - * When iterator comes from an object, you can use key() otherwise you can use index(). - */ - template <typename ValueType, typename ArrayIteratorType, typename ObjectIteratorType> - class BaseIterator : public std::iterator<std::forward_iterator_tag, ValueType> { - private: - friend class Value; - - ValueType &m_value; - ArrayIteratorType m_ita; - ObjectIteratorType m_itm; - - inline void increment() - { - if (m_value.isObject()) - m_itm++; - else - m_ita++; - } - - BaseIterator(ValueType &value, ObjectIteratorType it) - : m_value(value) - , m_itm(it) - { - } - - BaseIterator(ValueType &value, ArrayIteratorType it) - : m_value(value) - , m_ita(it) - { - } - - public: - /** - * Get the iterator key (for objects). - * - * @pre iterator must be dereferenceable - * @pre iterator must come from object - * @return the key - */ - inline const std::string &key() const noexcept - { - assert(m_value.isObject()); - assert(m_itm != m_value.m_object.end()); - - return m_itm->first; - } - - /** - * Get the iterator position (for arrays). - * - * @pre iterator must be dereferenceable - * @pre iterator must come from arrays - * @return the index - */ - inline unsigned index() const noexcept - { - assert(m_value.isArray()); - assert(m_ita != m_value.m_array.end()); - - return std::distance(m_value.m_array.begin(), m_ita); - } - - /** - * Dereference the iterator. - * - * @pre iterator be dereferenceable - * @return the value - */ - inline ValueType &operator*() noexcept - { - assert((m_value.isArray() && m_ita != m_value.m_array.end()) || - (m_value.isObject() && m_itm != m_value.m_object.end())); - - return (m_value.m_type == Type::Object) ? m_itm->second : *m_ita; - } - - /** - * Dereference the iterator as a pointer. - * - * @pre iterator must be dereferenceable - * @return the value - */ - inline ValueType *operator->() noexcept - { - assert((m_value.isArray() && m_ita != m_value.m_array.end()) || - (m_value.isObject() && m_itm != m_value.m_object.end())); - - return (m_value.m_type == Type::Object) ? &m_itm->second : &(*m_ita); - } - - /** - * Increment the iterator. (Prefix version). - * - * @pre iterator must be dereferenceable - * @return *this; - */ - inline BaseIterator &operator++() noexcept - { - assert((m_value.isArray() && m_ita != m_value.m_array.end()) || - (m_value.isObject() && m_itm != m_value.m_object.end())); - - increment(); - - return *this; - } - - /** - * Increment the iterator. (Postfix version). - * - * @pre iterator must be dereferenceable - * @return *this; - */ - inline BaseIterator &operator++(int) noexcept - { - assert((m_value.isArray() && m_ita != m_value.m_array.end()) || - (m_value.isObject() && m_itm != m_value.m_object.end())); - - increment(); - - return *this; - } - - /** - * Compare two iterators. - * - * @param it1 the first iterator - * @param it2 the second iterator - * @return true if they are same - */ - bool operator==(const BaseIterator &it) const noexcept - { - if (m_value.isObject() && it.m_value.isObject()) - return m_itm == it.m_itm; - if (m_value.isArray() && it.m_value.isArray()) - return m_ita == it.m_ita; - - return false; - } - - /** - * Test if the iterator is different. - * - * @param it the iterator - * @return true if they are different - */ - inline bool operator!=(const BaseIterator &it) const noexcept - { - return !(*this == it); - } - }; - -public: - /** - * Forward iterator. - */ - using iterator = BaseIterator<Value, typename std::vector<Value>::iterator, typename std::map<std::string, Value>::iterator>; - - /** - * Const forward iterator. - */ - using const_iterator = BaseIterator<const Value, typename std::vector<Value>::const_iterator, typename std::map<std::string, Value>::const_iterator>; - - /** - * Construct a null value. - */ - inline Value() - { - } - - /** - * Create a value with a specified type, this is usually only needed when you want to create an object or - * an array. - * - * For any other types, initialize with sane default value. - * - * @param type the type - */ - Value(Type type); - - /** - * Construct a null value. - */ - inline Value(std::nullptr_t) noexcept - : m_type(Type::Null) - { - } - - /** - * Construct a boolean value. - * - * @param value the boolean value - */ - inline Value(bool value) noexcept - : m_type(Type::Boolean) - , m_boolean(value) - { - } - - /** - * Create value from integer. - * - * @param value the value - */ - inline Value(int value) noexcept - : m_type(Type::Int) - , m_integer(value) - { - } - - /** - * Construct a value from a C-string. - * - * @param value the C-string - */ - inline Value(const char *value) - : m_type(Type::String) - { - new (&m_string) std::string(value ? value : ""); - } - - /** - * Construct a number value. - * - * @param value the real value - */ - inline Value(double value) noexcept - : m_type(Type::Real) - , m_number(value) - { - } - - /** - * Construct a string value. - * - * @param value the string - */ - inline Value(std::string value) noexcept - : m_type(Type::String) - { - new (&m_string) std::string(std::move(value)); - } - - /** - * Create an object from a map. - * - * @param values the values - * @see fromObject - */ - inline Value(std::map<std::string, Value> values) - : Value(Type::Object) - { - for (const auto &pair : values) - insert(pair.first, pair.second); - } - - /** - * Create an array from a vector. - * - * @param values the values - * @see fromArray - */ - inline Value(std::vector<Value> values) - : Value(Type::Array) - { - for (Value value : values) - append(std::move(value)); - } - - /** - * Construct a value from a buffer. - * - * @param buffer the text - * @throw Error on errors - */ - Value(const Buffer &buffer); - - /** - * Construct a value from a file. - * - * @param file the file - * @throw Error on errors - */ - Value(const File &file); - - /** - * Move constructor. - * - * @param other the value to move from - */ - inline Value(Value &&other) - { - move(std::move(other)); - } - - /** - * Copy constructor. - * - * @param other the value to copy from - */ - inline Value(const Value &other) - { - copy(other); - } - - /** - * Copy operator. - * - * @param other the value to copy from - * @return *this - */ - inline Value &operator=(const Value &other) - { - copy(other); - - return *this; - } - - /** - * Move operator. - * - * @param other the value to move from - */ - inline Value &operator=(Value &&other) - { - move(std::move(other)); - - return *this; - } - - /** - * Destructor. - */ - ~Value(); - - /** - * Get an iterator to the beginning. - * - * @pre must be an array or object - * @return the iterator - */ - inline iterator begin() noexcept - { - assert(isArray() || isObject()); - - return m_type == Type::Object ? iterator(*this, m_object.begin()) : iterator(*this, m_array.begin()); - } - - /** - * Overloaded function. - * - * @pre must be an array or object - * @return the iterator - */ - inline const_iterator begin() const noexcept - { - assert(isArray() || isObject()); - - return m_type == Type::Object ? const_iterator(*this, m_object.begin()) : const_iterator(*this, m_array.begin()); - } - - /** - * Overloaded function. - * - * @pre must be an array or object - * @return the iterator - */ - inline const_iterator cbegin() const noexcept - { - assert(isArray() || isObject()); - - return m_type == Type::Object ? const_iterator(*this, m_object.cbegin()) : const_iterator(*this, m_array.cbegin()); - } - - /** - * Get an iterator to the end. - * - * @pre must be an array or object - * @return the iterator - */ - inline iterator end() noexcept - { - assert(isArray() || isObject()); - - return m_type == Type::Object ? iterator(*this, m_object.end()) : iterator(*this, m_array.end()); - } - - /** - * Get an iterator to the end. - * - * @pre must be an array or object - * @return the iterator - */ - inline const_iterator end() const noexcept - { - assert(isArray() || isObject()); - - return m_type == Type::Object ? const_iterator(*this, m_object.end()) : const_iterator(*this, m_array.end()); - } - - /** - * Get an iterator to the end. - * - * @pre must be an array or object - * @return the iterator - */ - inline const_iterator cend() const noexcept - { - assert(isArray() || isObject()); - - return m_type == Type::Object ? const_iterator(*this, m_object.cend()) : const_iterator(*this, m_array.cend()); - } - - /** - * Get the value type. - * - * @return the type - */ - inline Type typeOf() const noexcept - { - return m_type; - } - - /** - * Get the value as boolean. - * - * @return the value or false if not a boolean - */ - bool toBool() const noexcept; - - /** - * Get the value as integer. - * - * @return the value or 0 if not a integer - */ - int toInt() const noexcept; - - /** - * Get the value as real. - * - * @return the value or 0 if not a real - */ - double toReal() const noexcept; - - /** - * Get the value as string. - * - * @param coerce set to true to coerce the value if not a string - * @return the value or empty string if not a string - */ - std::string toString(bool coerce = false) const noexcept; - - /** - * Check if the value is boolean type. - * - * @return true if boolean - */ - inline bool isBool() const noexcept - { - return m_type == Type::Boolean; - } - - /** - * Check if the value is integer type. - * - * @return true if integer - */ - inline bool isInt() const noexcept - { - return m_type == Type::Int; - } - - /** - * Check if the value is object type. - * - * @return true if object - */ - inline bool isObject() const noexcept - { - return m_type == Type::Object; - } - - /** - * Check if the value is array type. - * - * @return true if array - */ - inline bool isArray() const noexcept - { - return m_type == Type::Array; - } - - /** - * Check if the value is integer or real type. - * - * @return true if integer or real - * @see toInt - * @see toReal - */ - inline bool isNumber() const noexcept - { - return m_type == Type::Real || m_type == Type::Int; - } - - /** - * Check if the value is real type. - * - * @return true if real - */ - inline bool isReal() const noexcept - { - return m_type == Type::Real; - } - - /** - * Check if the value is null type. - * - * @return true if null - */ - inline bool isNull() const noexcept - { - return m_type == Type::Null; - } - - /** - * Check if the value is string type. - * - * @return true if string - */ - inline bool isString() const noexcept - { - return m_type == Type::String; - } - - /** - * Get the array or object size. - * - * @pre must be an array or object - * @return the size - */ - inline unsigned size() const noexcept - { - assert(isArray() || isObject()); - - if (m_type == Type::Object) - return m_object.size(); - - return m_array.size(); - } - - /** - * Remove all the values. - * - * @pre must be an array or an object - */ - inline void clear() noexcept - { - assert(isArray() || isObject()); - - if (m_type == Type::Array) - m_array.clear(); - else - m_object.clear(); - } - - /* - * Array functions - * ---------------------------------------------------------- - */ - - /** - * Get the value at the specified position or the defaultValue if position is out of bounds. - * - * @param position the position - * @param defaultValue the value replacement - * @return the value or defaultValue - */ - template <typename DefaultValue> - inline Value valueOr(unsigned position, DefaultValue &&defaultValue) const - { - if (m_type != Type::Array || position >= m_array.size()) - return defaultValue; - - return m_array[position]; - } - - /** - * Overloaded function with type check. - * - * @param position the position - * @param type the requested type - * @param defaultValue the value replacement - * @return the value or defaultValue - */ - template <typename DefaultValue> - inline Value valueOr(unsigned position, Type type, DefaultValue &&defaultValue) const - { - if (m_type != Type::Array || position >= m_array.size() || m_array[position].typeOf() != type) - return defaultValue; - - return m_array[position]; - } - - /** - * Get a value at the specified index. - * - * @pre must be an array - * @param position the position - * @return the value - * @throw std::out_of_range if out of bounds - */ - inline const Value &at(unsigned position) const - { - assert(isArray()); - - return m_array.at(position); - } - - /** - * Overloaded function. - * - * @pre must be an array - * @param position the position - * @return the value - * @throw std::out_of_range if out of bounds - */ - inline Value &at(unsigned position) - { - assert(isArray()); - - return m_array.at(position); - } - - /** - * Get a value at the specified index. - * - * @pre must be an array - * @pre position must be valid - * @param position the position - * @return the value - */ - inline const Value &operator[](unsigned position) const - { - assert(isArray()); - assert(position < m_array.size()); - - return m_array[position]; - } - - /** - * Overloaded function. - * - * @pre must be an array - * @pre position must be valid - * @param position the position - * @return the value - */ - inline Value &operator[](unsigned position) - { - assert(isArray()); - assert(position < m_array.size()); - - return m_array[position]; - } - - /** - * Push a value to the beginning of the array. - * - * @pre must be an array - * @param value the value to push - */ - inline void push(const Value &value) - { - assert(isArray()); - - m_array.insert(m_array.begin(), value); - } - - /** - * Overloaded function. - * - * @pre must be an array - * @param value the value to push - */ - inline void push(Value &&value) - { - assert(isArray()); - - m_array.insert(m_array.begin(), std::move(value)); - } - - /** - * Insert a value at the specified position. - * - * @pre must be an array - * @pre position must be valid - * @param position the position - * @param value the value to push - */ - inline void insert(unsigned position, const Value &value) - { - assert(isArray()); - assert(position <= m_array.size()); - - m_array.insert(m_array.begin() + position, value); - } - - /** - * Overloaded function. - * - * @pre must be an array - * @pre position must be valid - * @param position the position - * @param value the value to push - */ - inline void insert(unsigned position, Value &&value) - { - assert(isArray()); - assert(position <= m_array.size()); - - m_array.insert(m_array.begin() + position, std::move(value)); - } - - /** - * Add a new value to the end. - * - * @pre must be an array - * @param value the value to append - */ - inline void append(const Value &value) - { - assert(isArray()); - - m_array.push_back(value); - } - - /** - * Overloaded function. - * - * @pre must be an array - * @param value the value to append - */ - inline void append(Value &&value) - { - assert(isArray()); - - m_array.push_back(std::move(value)); - } - - /** - * Remove a value at the specified position. - * - * @pre must be an array - * @pre position must be valid - * @param position the position - */ - inline void erase(unsigned position) - { - assert(isArray()); - assert(position < m_array.size()); - - m_array.erase(m_array.begin() + position); - } - - /* - * Object functions - * ---------------------------------------------------------- - */ - - /** - * Get the value at the specified key or the defaultValue if key is absent. - * - * @param name the name - * @param defaultValue the value replacement - * @return the value or defaultValue - */ - template <typename DefaultValue> - Value valueOr(const std::string &name, DefaultValue &&defaultValue) const - { - if (m_type != Type::Object) - return defaultValue; - - auto it = m_object.find(name); - - if (it == m_object.end()) - return defaultValue; - - return it->second; - } - - /** - * Overloaded function with type check. - * - * @param name the name - * @param type the requested type - * @param defaultValue the value replacement - * @return the value or defaultValue - */ - template <typename DefaultValue> - Value valueOr(const std::string &name, Type type, DefaultValue &&defaultValue) const - { - if (m_type != Type::Object) - return defaultValue; - - auto it = m_object.find(name); - - if (it == m_object.end() || it->second.typeOf() != type) - return defaultValue; - - return it->second; - } - - /** - * Get a value from the object. - * - * @pre must be an object - * @param name the value key - * @return the value - * @throw std::out_of_range if not found - */ - inline const Value &at(const std::string &name) const - { - assert(isObject()); - - return m_object.at(name); - } - - /** - * Overloaded function. - * - * @pre must be an object - * @param name the value key - * @return the value - * @throw std::out_of_range if not found - */ - inline Value &at(const std::string &name) - { - assert(isObject()); - - return m_object.at(name); - } - - /** - * Get a value from the object. - * - * @pre must be an object - * @param name the value key - * @return the value - */ - inline Value &operator[](const std::string &name) - { - assert(isObject()); - - return m_object[name]; - } - - /** - * Find a value by key. - * - * @pre must be an object - * @param key the property key - * @return the iterator or past the end if not found - */ - inline iterator find(const std::string &key) - { - assert(isObject()); - - return iterator(*this, m_object.find(key)); - } - - /** - * Overloaded function. - * - * @pre must be an object - * @param key the property key - * @return the iterator or past the end if not found - */ - inline const_iterator find(const std::string &key) const - { - assert(isObject()); - - return const_iterator(*this, m_object.find(key)); - } - - /** - * Insert a new value. - * - * @pre must be an object - * @param name the key - * @param value the value - */ - inline void insert(std::string name, const Value &value) - { - assert(isObject()); - - m_object.insert({std::move(name), value}); - } - - /** - * Overloaded function. - * - * @pre must be an object - * @param name the key - * @param value the value - */ - inline void insert(std::string name, Value &&value) - { - assert(isObject()); - - m_object.insert({std::move(name), std::move(value)}); - } - - /** - * Check if a value exists. - * - * @pre must be an object - * @param key the key value - * @return true if exists - */ - inline bool contains(const std::string &key) const noexcept - { - assert(isObject()); - - return m_object.find(key) != m_object.end(); - } - - /** - * Remove a value of the specified key. - * - * @pre must be an object - * @param key the value key - */ - inline void erase(const std::string &key) - { - assert(isObject()); - - m_object.erase(key); - } - - /** - * Return this value as JSon representation. - * - * @param indent, the indentation to use (0 == compact, < 0 == tabs, > 0 == number of spaces) - * @param tabs, use tabs or not - * @return the string - */ - inline std::string toJson(int indent = 2) const - { - return toJson(indent, 0); - } -}; - -/** - * Escape the input. - * - * @param input the input - * @return the escaped string - */ -std::string escape(const std::string &input); - -/** - * Convenient function for creating array from initializer list. - * - * @param values the values - * @return the array - */ -inline Value array(std::initializer_list<Value> values) -{ - return Value(std::vector<Value>(values.begin(), values.end())); -} - -/** - * Convenient function for creating object from initializer list. - * - * @param values the values - * @return the object - */ -inline Value object(std::initializer_list<std::pair<std::string, Value>> values) -{ - return Value(std::map<std::string, Value>(values.begin(), values.end())); -} - -} // !json - -} // !irccd - -#endif // !IRCCD_JSON_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/json.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,1183 @@ +/* + * json.hpp -- C++14 JSON manipulation using jansson parser + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_JSON_HPP +#define IRCCD_JSON_HPP + +/** + * @file json.hpp + * @brief Jansson C++14 wrapper + * + * These classes can be used to build or parse JSON documents using jansson library. It is designed to be safe + * and explicit. It does not implement implicit sharing like jansson so when you access (e.g. Value::toObject) values + * you get real copies, thus when you read big documents it can has a performance cost. + */ + +#include <cassert> +#include <exception> +#include <initializer_list> +#include <map> +#include <string> +#include <utility> +#include <vector> + +namespace irccd { + +/** + * Json namespace. + */ +namespace json { + +/** + * @enum Type + * @brief Type of Value. + */ +enum class Type { + Array, //!< Value is an array [] + Boolean, //!< Value is boolean + Int, //!< Value is integer + Null, //!< Value is defined to null + Object, //!< Value is object {} + Real, //!< Value is float + String //!< Value is unicode string +}; + +/** + * @class Error + * @brief Error description. + */ +class Error : public std::exception { +private: + std::string m_text; + std::string m_source; + int m_line; + int m_column; + int m_position; + +public: + /** + * Create the error. + * + * @param text the text message + * @param source the source (e.g. file name) + * @param line the line number + * @param column the column number + * @param position the position + */ + inline Error(std::string text, std::string source, int line, int column, int position) noexcept + : m_text(std::move(text)) + , m_source(std::move(source)) + , m_line(line) + , m_column(column) + , m_position(position) + { + } + + /** + * Get the error message. + * + * @return the text + */ + inline const std::string &text() const noexcept + { + return m_text; + } + + /** + * Get the source (e.g. a file name). + * + * @return the source + */ + inline const std::string &source() const noexcept + { + return m_source; + } + + /** + * Get the line. + * + * @return the line + */ + inline int line() const noexcept + { + return m_line; + } + + /** + * Get the column. + * + * @return the column + */ + inline int column() const noexcept + { + return m_column; + } + + /** + * Get the position. + * + * @return the position + */ + inline int position() const noexcept + { + return m_position; + } + + /** + * Get the error message. + * + * @return the message + */ + const char *what() const noexcept override + { + return m_text.c_str(); + } +}; + +/** + * @class Buffer + * @brief Open JSON document from text. + */ +class Buffer { +public: + std::string text; //!< The JSON text +}; + +/** + * @class File + * @brief Open JSON document from a file. + */ +class File { +public: + std::string path; //!< The path to the file +}; + +/** + * @class Value + * @brief Generic JSON value wrapper. + */ +class Value { +private: + Type m_type{Type::Null}; + + union { + double m_number; + bool m_boolean; + int m_integer; + std::string m_string; + std::vector<Value> m_array; + std::map<std::string, Value> m_object; + }; + + void copy(const Value &); + void move(Value &&); + std::string toJson(int indent, int current) const; + + /** + * @class BaseIterator + * @brief This is the base class for iterator and const_iterator + * + * This iterator works for both arrays and objects. Because of that purpose, it is only available + * as forward iterator. + * + * When iterator comes from an object, you can use key() otherwise you can use index(). + */ + template <typename ValueType, typename ArrayIteratorType, typename ObjectIteratorType> + class BaseIterator : public std::iterator<std::forward_iterator_tag, ValueType> { + private: + friend class Value; + + ValueType &m_value; + ArrayIteratorType m_ita; + ObjectIteratorType m_itm; + + inline void increment() + { + if (m_value.isObject()) + m_itm++; + else + m_ita++; + } + + BaseIterator(ValueType &value, ObjectIteratorType it) + : m_value(value) + , m_itm(it) + { + } + + BaseIterator(ValueType &value, ArrayIteratorType it) + : m_value(value) + , m_ita(it) + { + } + + public: + /** + * Get the iterator key (for objects). + * + * @pre iterator must be dereferenceable + * @pre iterator must come from object + * @return the key + */ + inline const std::string &key() const noexcept + { + assert(m_value.isObject()); + assert(m_itm != m_value.m_object.end()); + + return m_itm->first; + } + + /** + * Get the iterator position (for arrays). + * + * @pre iterator must be dereferenceable + * @pre iterator must come from arrays + * @return the index + */ + inline unsigned index() const noexcept + { + assert(m_value.isArray()); + assert(m_ita != m_value.m_array.end()); + + return std::distance(m_value.m_array.begin(), m_ita); + } + + /** + * Dereference the iterator. + * + * @pre iterator be dereferenceable + * @return the value + */ + inline ValueType &operator*() noexcept + { + assert((m_value.isArray() && m_ita != m_value.m_array.end()) || + (m_value.isObject() && m_itm != m_value.m_object.end())); + + return (m_value.m_type == Type::Object) ? m_itm->second : *m_ita; + } + + /** + * Dereference the iterator as a pointer. + * + * @pre iterator must be dereferenceable + * @return the value + */ + inline ValueType *operator->() noexcept + { + assert((m_value.isArray() && m_ita != m_value.m_array.end()) || + (m_value.isObject() && m_itm != m_value.m_object.end())); + + return (m_value.m_type == Type::Object) ? &m_itm->second : &(*m_ita); + } + + /** + * Increment the iterator. (Prefix version). + * + * @pre iterator must be dereferenceable + * @return *this; + */ + inline BaseIterator &operator++() noexcept + { + assert((m_value.isArray() && m_ita != m_value.m_array.end()) || + (m_value.isObject() && m_itm != m_value.m_object.end())); + + increment(); + + return *this; + } + + /** + * Increment the iterator. (Postfix version). + * + * @pre iterator must be dereferenceable + * @return *this; + */ + inline BaseIterator &operator++(int) noexcept + { + assert((m_value.isArray() && m_ita != m_value.m_array.end()) || + (m_value.isObject() && m_itm != m_value.m_object.end())); + + increment(); + + return *this; + } + + /** + * Compare two iterators. + * + * @param it1 the first iterator + * @param it2 the second iterator + * @return true if they are same + */ + bool operator==(const BaseIterator &it) const noexcept + { + if (m_value.isObject() && it.m_value.isObject()) + return m_itm == it.m_itm; + if (m_value.isArray() && it.m_value.isArray()) + return m_ita == it.m_ita; + + return false; + } + + /** + * Test if the iterator is different. + * + * @param it the iterator + * @return true if they are different + */ + inline bool operator!=(const BaseIterator &it) const noexcept + { + return !(*this == it); + } + }; + +public: + /** + * Forward iterator. + */ + using iterator = BaseIterator<Value, typename std::vector<Value>::iterator, typename std::map<std::string, Value>::iterator>; + + /** + * Const forward iterator. + */ + using const_iterator = BaseIterator<const Value, typename std::vector<Value>::const_iterator, typename std::map<std::string, Value>::const_iterator>; + + /** + * Construct a null value. + */ + inline Value() + { + } + + /** + * Create a value with a specified type, this is usually only needed when you want to create an object or + * an array. + * + * For any other types, initialize with sane default value. + * + * @param type the type + */ + Value(Type type); + + /** + * Construct a null value. + */ + inline Value(std::nullptr_t) noexcept + : m_type(Type::Null) + { + } + + /** + * Construct a boolean value. + * + * @param value the boolean value + */ + inline Value(bool value) noexcept + : m_type(Type::Boolean) + , m_boolean(value) + { + } + + /** + * Create value from integer. + * + * @param value the value + */ + inline Value(int value) noexcept + : m_type(Type::Int) + , m_integer(value) + { + } + + /** + * Construct a value from a C-string. + * + * @param value the C-string + */ + inline Value(const char *value) + : m_type(Type::String) + { + new (&m_string) std::string(value ? value : ""); + } + + /** + * Construct a number value. + * + * @param value the real value + */ + inline Value(double value) noexcept + : m_type(Type::Real) + , m_number(value) + { + } + + /** + * Construct a string value. + * + * @param value the string + */ + inline Value(std::string value) noexcept + : m_type(Type::String) + { + new (&m_string) std::string(std::move(value)); + } + + /** + * Create an object from a map. + * + * @param values the values + * @see fromObject + */ + inline Value(std::map<std::string, Value> values) + : Value(Type::Object) + { + for (const auto &pair : values) + insert(pair.first, pair.second); + } + + /** + * Create an array from a vector. + * + * @param values the values + * @see fromArray + */ + inline Value(std::vector<Value> values) + : Value(Type::Array) + { + for (Value value : values) + append(std::move(value)); + } + + /** + * Construct a value from a buffer. + * + * @param buffer the text + * @throw Error on errors + */ + Value(const Buffer &buffer); + + /** + * Construct a value from a file. + * + * @param file the file + * @throw Error on errors + */ + Value(const File &file); + + /** + * Move constructor. + * + * @param other the value to move from + */ + inline Value(Value &&other) + { + move(std::move(other)); + } + + /** + * Copy constructor. + * + * @param other the value to copy from + */ + inline Value(const Value &other) + { + copy(other); + } + + /** + * Copy operator. + * + * @param other the value to copy from + * @return *this + */ + inline Value &operator=(const Value &other) + { + copy(other); + + return *this; + } + + /** + * Move operator. + * + * @param other the value to move from + */ + inline Value &operator=(Value &&other) + { + move(std::move(other)); + + return *this; + } + + /** + * Destructor. + */ + ~Value(); + + /** + * Get an iterator to the beginning. + * + * @pre must be an array or object + * @return the iterator + */ + inline iterator begin() noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? iterator(*this, m_object.begin()) : iterator(*this, m_array.begin()); + } + + /** + * Overloaded function. + * + * @pre must be an array or object + * @return the iterator + */ + inline const_iterator begin() const noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? const_iterator(*this, m_object.begin()) : const_iterator(*this, m_array.begin()); + } + + /** + * Overloaded function. + * + * @pre must be an array or object + * @return the iterator + */ + inline const_iterator cbegin() const noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? const_iterator(*this, m_object.cbegin()) : const_iterator(*this, m_array.cbegin()); + } + + /** + * Get an iterator to the end. + * + * @pre must be an array or object + * @return the iterator + */ + inline iterator end() noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? iterator(*this, m_object.end()) : iterator(*this, m_array.end()); + } + + /** + * Get an iterator to the end. + * + * @pre must be an array or object + * @return the iterator + */ + inline const_iterator end() const noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? const_iterator(*this, m_object.end()) : const_iterator(*this, m_array.end()); + } + + /** + * Get an iterator to the end. + * + * @pre must be an array or object + * @return the iterator + */ + inline const_iterator cend() const noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? const_iterator(*this, m_object.cend()) : const_iterator(*this, m_array.cend()); + } + + /** + * Get the value type. + * + * @return the type + */ + inline Type typeOf() const noexcept + { + return m_type; + } + + /** + * Get the value as boolean. + * + * @return the value or false if not a boolean + */ + bool toBool() const noexcept; + + /** + * Get the value as integer. + * + * @return the value or 0 if not a integer + */ + int toInt() const noexcept; + + /** + * Get the value as real. + * + * @return the value or 0 if not a real + */ + double toReal() const noexcept; + + /** + * Get the value as string. + * + * @param coerce set to true to coerce the value if not a string + * @return the value or empty string if not a string + */ + std::string toString(bool coerce = false) const noexcept; + + /** + * Check if the value is boolean type. + * + * @return true if boolean + */ + inline bool isBool() const noexcept + { + return m_type == Type::Boolean; + } + + /** + * Check if the value is integer type. + * + * @return true if integer + */ + inline bool isInt() const noexcept + { + return m_type == Type::Int; + } + + /** + * Check if the value is object type. + * + * @return true if object + */ + inline bool isObject() const noexcept + { + return m_type == Type::Object; + } + + /** + * Check if the value is array type. + * + * @return true if array + */ + inline bool isArray() const noexcept + { + return m_type == Type::Array; + } + + /** + * Check if the value is integer or real type. + * + * @return true if integer or real + * @see toInt + * @see toReal + */ + inline bool isNumber() const noexcept + { + return m_type == Type::Real || m_type == Type::Int; + } + + /** + * Check if the value is real type. + * + * @return true if real + */ + inline bool isReal() const noexcept + { + return m_type == Type::Real; + } + + /** + * Check if the value is null type. + * + * @return true if null + */ + inline bool isNull() const noexcept + { + return m_type == Type::Null; + } + + /** + * Check if the value is string type. + * + * @return true if string + */ + inline bool isString() const noexcept + { + return m_type == Type::String; + } + + /** + * Get the array or object size. + * + * @pre must be an array or object + * @return the size + */ + inline unsigned size() const noexcept + { + assert(isArray() || isObject()); + + if (m_type == Type::Object) + return m_object.size(); + + return m_array.size(); + } + + /** + * Remove all the values. + * + * @pre must be an array or an object + */ + inline void clear() noexcept + { + assert(isArray() || isObject()); + + if (m_type == Type::Array) + m_array.clear(); + else + m_object.clear(); + } + + /* + * Array functions + * ---------------------------------------------------------- + */ + + /** + * Get the value at the specified position or the defaultValue if position is out of bounds. + * + * @param position the position + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename DefaultValue> + inline Value valueOr(unsigned position, DefaultValue &&defaultValue) const + { + if (m_type != Type::Array || position >= m_array.size()) + return defaultValue; + + return m_array[position]; + } + + /** + * Overloaded function with type check. + * + * @param position the position + * @param type the requested type + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename DefaultValue> + inline Value valueOr(unsigned position, Type type, DefaultValue &&defaultValue) const + { + if (m_type != Type::Array || position >= m_array.size() || m_array[position].typeOf() != type) + return defaultValue; + + return m_array[position]; + } + + /** + * Get a value at the specified index. + * + * @pre must be an array + * @param position the position + * @return the value + * @throw std::out_of_range if out of bounds + */ + inline const Value &at(unsigned position) const + { + assert(isArray()); + + return m_array.at(position); + } + + /** + * Overloaded function. + * + * @pre must be an array + * @param position the position + * @return the value + * @throw std::out_of_range if out of bounds + */ + inline Value &at(unsigned position) + { + assert(isArray()); + + return m_array.at(position); + } + + /** + * Get a value at the specified index. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + * @return the value + */ + inline const Value &operator[](unsigned position) const + { + assert(isArray()); + assert(position < m_array.size()); + + return m_array[position]; + } + + /** + * Overloaded function. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + * @return the value + */ + inline Value &operator[](unsigned position) + { + assert(isArray()); + assert(position < m_array.size()); + + return m_array[position]; + } + + /** + * Push a value to the beginning of the array. + * + * @pre must be an array + * @param value the value to push + */ + inline void push(const Value &value) + { + assert(isArray()); + + m_array.insert(m_array.begin(), value); + } + + /** + * Overloaded function. + * + * @pre must be an array + * @param value the value to push + */ + inline void push(Value &&value) + { + assert(isArray()); + + m_array.insert(m_array.begin(), std::move(value)); + } + + /** + * Insert a value at the specified position. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + * @param value the value to push + */ + inline void insert(unsigned position, const Value &value) + { + assert(isArray()); + assert(position <= m_array.size()); + + m_array.insert(m_array.begin() + position, value); + } + + /** + * Overloaded function. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + * @param value the value to push + */ + inline void insert(unsigned position, Value &&value) + { + assert(isArray()); + assert(position <= m_array.size()); + + m_array.insert(m_array.begin() + position, std::move(value)); + } + + /** + * Add a new value to the end. + * + * @pre must be an array + * @param value the value to append + */ + inline void append(const Value &value) + { + assert(isArray()); + + m_array.push_back(value); + } + + /** + * Overloaded function. + * + * @pre must be an array + * @param value the value to append + */ + inline void append(Value &&value) + { + assert(isArray()); + + m_array.push_back(std::move(value)); + } + + /** + * Remove a value at the specified position. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + */ + inline void erase(unsigned position) + { + assert(isArray()); + assert(position < m_array.size()); + + m_array.erase(m_array.begin() + position); + } + + /* + * Object functions + * ---------------------------------------------------------- + */ + + /** + * Get the value at the specified key or the defaultValue if key is absent. + * + * @param name the name + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename DefaultValue> + Value valueOr(const std::string &name, DefaultValue &&defaultValue) const + { + if (m_type != Type::Object) + return defaultValue; + + auto it = m_object.find(name); + + if (it == m_object.end()) + return defaultValue; + + return it->second; + } + + /** + * Overloaded function with type check. + * + * @param name the name + * @param type the requested type + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename DefaultValue> + Value valueOr(const std::string &name, Type type, DefaultValue &&defaultValue) const + { + if (m_type != Type::Object) + return defaultValue; + + auto it = m_object.find(name); + + if (it == m_object.end() || it->second.typeOf() != type) + return defaultValue; + + return it->second; + } + + /** + * Get a value from the object. + * + * @pre must be an object + * @param name the value key + * @return the value + * @throw std::out_of_range if not found + */ + inline const Value &at(const std::string &name) const + { + assert(isObject()); + + return m_object.at(name); + } + + /** + * Overloaded function. + * + * @pre must be an object + * @param name the value key + * @return the value + * @throw std::out_of_range if not found + */ + inline Value &at(const std::string &name) + { + assert(isObject()); + + return m_object.at(name); + } + + /** + * Get a value from the object. + * + * @pre must be an object + * @param name the value key + * @return the value + */ + inline Value &operator[](const std::string &name) + { + assert(isObject()); + + return m_object[name]; + } + + /** + * Find a value by key. + * + * @pre must be an object + * @param key the property key + * @return the iterator or past the end if not found + */ + inline iterator find(const std::string &key) + { + assert(isObject()); + + return iterator(*this, m_object.find(key)); + } + + /** + * Overloaded function. + * + * @pre must be an object + * @param key the property key + * @return the iterator or past the end if not found + */ + inline const_iterator find(const std::string &key) const + { + assert(isObject()); + + return const_iterator(*this, m_object.find(key)); + } + + /** + * Insert a new value. + * + * @pre must be an object + * @param name the key + * @param value the value + */ + inline void insert(std::string name, const Value &value) + { + assert(isObject()); + + m_object.insert({std::move(name), value}); + } + + /** + * Overloaded function. + * + * @pre must be an object + * @param name the key + * @param value the value + */ + inline void insert(std::string name, Value &&value) + { + assert(isObject()); + + m_object.insert({std::move(name), std::move(value)}); + } + + /** + * Check if a value exists. + * + * @pre must be an object + * @param key the key value + * @return true if exists + */ + inline bool contains(const std::string &key) const noexcept + { + assert(isObject()); + + return m_object.find(key) != m_object.end(); + } + + /** + * Remove a value of the specified key. + * + * @pre must be an object + * @param key the value key + */ + inline void erase(const std::string &key) + { + assert(isObject()); + + m_object.erase(key); + } + + /** + * Return this value as JSon representation. + * + * @param indent, the indentation to use (0 == compact, < 0 == tabs, > 0 == number of spaces) + * @param tabs, use tabs or not + * @return the string + */ + inline std::string toJson(int indent = 2) const + { + return toJson(indent, 0); + } +}; + +/** + * Escape the input. + * + * @param input the input + * @return the escaped string + */ +std::string escape(const std::string &input); + +/** + * Convenient function for creating array from initializer list. + * + * @param values the values + * @return the array + */ +inline Value array(std::initializer_list<Value> values) +{ + return Value(std::vector<Value>(values.begin(), values.end())); +} + +/** + * Convenient function for creating object from initializer list. + * + * @param values the values + * @return the object + */ +inline Value object(std::initializer_list<std::pair<std::string, Value>> values) +{ + return Value(std::map<std::string, Value>(values.begin(), values.end())); +} + +} // !json + +} // !irccd + +#endif // !IRCCD_JSON_HPP
--- a/lib/irccd/logger.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/logger.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -23,14 +23,14 @@ #include <stdexcept> #include <streambuf> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> #if defined(HAVE_SYSLOG) # include <syslog.h> #endif // !HAVE_SYSLOG -#include "logger.h" -#include "system.h" +#include "logger.hpp" +#include "system.hpp" namespace irccd {
--- a/lib/irccd/logger.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/* - * logger.h -- irccd logging - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_LOGGER_H -#define IRCCD_LOGGER_H - -/** - * @file logger.h - * @brief Logging facilities. - */ - -#include <irccd/sysconfig.h> - -#include <memory> -#include <sstream> -#include <utility> - -namespace irccd { - -namespace log { - -/** - * @enum Level - * @brief Which level of warning - */ -enum class Level { - Info, //!< Standard information (disabled if verbose is false) - Warning, //!< Warning (always shown) - Debug //!< Debug message (only if compiled in debug mode) -}; - -/* -------------------------------------------------------- - * Interface -- abstract logging interface - * -------------------------------------------------------- */ - -/** - * @class Interface - * @brief Interface to implement new logger mechanisms - * - * Derive from this class and use Logger::setInterface() to change logging - * system. - * - * @see File - * @see Console - * @see Syslog - * @see Silent - */ -class Interface { -public: - /** - * Write the line to the logs. The line to write will never contains - * trailing new line character. - * - * @param level the level - * @param line the line without trailing \n - */ - virtual void write(Level level, const std::string &line) noexcept = 0; -}; - -/* -------------------------------------------------------- - * Console -- logs to console - * -------------------------------------------------------- */ - -/** - * @class Console - * @brief Logger implementation for console output - */ -class Console : public Interface { -public: - /** - * @copydoc Interface::write - */ - void write(Level level, const std::string &line) noexcept override; -}; - -/* -------------------------------------------------------- - * File -- logs to a file - * -------------------------------------------------------- */ - -/** - * @class File - * @brief Output to a file - */ -class File : public Interface { -private: - std::string m_outputNormal; - std::string m_outputError; - -public: - /** - * Outputs to files. Info and Debug are written in normal and Warnings - * in errors. - * - * The same path can be used for all levels. - * - * @param normal the path to the normal logs - * @param errors the path to the errors logs - */ - File(std::string normal, std::string errors); - - /** - * @copydoc Interface::write - */ - void write(Level level, const std::string &line) noexcept override; -}; - -/* -------------------------------------------------------- - * Silent -- disable all logs - * -------------------------------------------------------- */ - -/** - * @class Silent - * @brief Use to disable logs - * - * Useful for unit tests when some classes may emits log. - */ -class Silent : public Interface { -public: - /** - * @copydoc Interface::write - */ - void write(Level level, const std::string &line) noexcept override; -}; - -/* -------------------------------------------------------- - * Syslog -- system logger - * -------------------------------------------------------- */ - -#if defined(HAVE_SYSLOG) - -/** - * @class Syslog - * @brief Implements logger into syslog - */ -class Syslog : public Interface { -public: - /** - * Open the syslog. - */ - Syslog(); - - /** - * Close the syslog. - */ - ~Syslog(); - - /** - * @copydoc Interface::write - */ - void write(Level level, const std::string &line) noexcept override; -}; - -#endif // !HAVE_SYSLOG - -/* -------------------------------------------------------- - * Functions - * -------------------------------------------------------- */ - -/** - * Update the logger interface. - * - * @param iface the new interface - */ -void setInterface(std::unique_ptr<Interface> iface) noexcept; - -/** - * Get the stream for informational messages. - * - * @return the stream - * @note Has no effect if verbose is set to false. - */ -std::ostream &info() noexcept; - -/** - * Get the stream for warnings. - * - * @return the stream - */ -std::ostream &warning() noexcept; - -/** - * Get the stream for debug messages. - * - * @return the stream - * @note Has no effect if compiled in release mode. - */ -std::ostream &debug() noexcept; - -/** - * Tells if verbose is enabled. - * - * @return true if enabled - */ -bool isVerbose() noexcept; - -/** - * Set the verbosity mode. - * - * @param mode the new mode - */ -void setVerbose(bool mode) noexcept; - -} // !log - -} // !irccd - -#endif // !IRCCD_LOGGER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/logger.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,222 @@ +/* + * logger.hpp -- irccd logging + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_LOGGER_HPP +#define IRCCD_LOGGER_HPP + +/** + * @file logger.hpp + * @brief Logging facilities. + */ + +#include <irccd/sysconfig.hpp> + +#include <memory> +#include <sstream> +#include <utility> + +namespace irccd { + +namespace log { + +/** + * @enum Level + * @brief Which level of warning + */ +enum class Level { + Info, //!< Standard information (disabled if verbose is false) + Warning, //!< Warning (always shown) + Debug //!< Debug message (only if compiled in debug mode) +}; + +/* -------------------------------------------------------- + * Interface -- abstract logging interface + * -------------------------------------------------------- */ + +/** + * @class Interface + * @brief Interface to implement new logger mechanisms + * + * Derive from this class and use Logger::setInterface() to change logging + * system. + * + * @see File + * @see Console + * @see Syslog + * @see Silent + */ +class Interface { +public: + /** + * Write the line to the logs. The line to write will never contains + * trailing new line character. + * + * @param level the level + * @param line the line without trailing \n + */ + virtual void write(Level level, const std::string &line) noexcept = 0; +}; + +/* -------------------------------------------------------- + * Console -- logs to console + * -------------------------------------------------------- */ + +/** + * @class Console + * @brief Logger implementation for console output + */ +class Console : public Interface { +public: + /** + * @copydoc Interface::write + */ + void write(Level level, const std::string &line) noexcept override; +}; + +/* -------------------------------------------------------- + * File -- logs to a file + * -------------------------------------------------------- */ + +/** + * @class File + * @brief Output to a file + */ +class File : public Interface { +private: + std::string m_outputNormal; + std::string m_outputError; + +public: + /** + * Outputs to files. Info and Debug are written in normal and Warnings + * in errors. + * + * The same path can be used for all levels. + * + * @param normal the path to the normal logs + * @param errors the path to the errors logs + */ + File(std::string normal, std::string errors); + + /** + * @copydoc Interface::write + */ + void write(Level level, const std::string &line) noexcept override; +}; + +/* -------------------------------------------------------- + * Silent -- disable all logs + * -------------------------------------------------------- */ + +/** + * @class Silent + * @brief Use to disable logs + * + * Useful for unit tests when some classes may emits log. + */ +class Silent : public Interface { +public: + /** + * @copydoc Interface::write + */ + void write(Level level, const std::string &line) noexcept override; +}; + +/* -------------------------------------------------------- + * Syslog -- system logger + * -------------------------------------------------------- */ + +#if defined(HAVE_SYSLOG) + +/** + * @class Syslog + * @brief Implements logger into syslog + */ +class Syslog : public Interface { +public: + /** + * Open the syslog. + */ + Syslog(); + + /** + * Close the syslog. + */ + ~Syslog(); + + /** + * @copydoc Interface::write + */ + void write(Level level, const std::string &line) noexcept override; +}; + +#endif // !HAVE_SYSLOG + +/* -------------------------------------------------------- + * Functions + * -------------------------------------------------------- */ + +/** + * Update the logger interface. + * + * @param iface the new interface + */ +void setInterface(std::unique_ptr<Interface> iface) noexcept; + +/** + * Get the stream for informational messages. + * + * @return the stream + * @note Has no effect if verbose is set to false. + */ +std::ostream &info() noexcept; + +/** + * Get the stream for warnings. + * + * @return the stream + */ +std::ostream &warning() noexcept; + +/** + * Get the stream for debug messages. + * + * @return the stream + * @note Has no effect if compiled in release mode. + */ +std::ostream &debug() noexcept; + +/** + * Tells if verbose is enabled. + * + * @return true if enabled + */ +bool isVerbose() noexcept; + +/** + * Set the verbosity mode. + * + * @param mode the new mode + */ +void setVerbose(bool mode) noexcept; + +} // !log + +} // !irccd + +#endif // !IRCCD_LOGGER_HPP
--- a/lib/irccd/options.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/options.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,7 +18,7 @@ #include <cassert> -#include "options.h" +#include "options.hpp" namespace irccd {
--- a/lib/irccd/options.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - * options.h -- parse Unix command line options - * - * Copyright (c) 2015 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. - */ - -#ifndef IRCCD_OPTION_PARSER_H -#define IRCCD_OPTION_PARSER_H - -/** - * @file options.h - * @brief Basic options parsing. - */ - -#include <exception> -#include <map> -#include <string> -#include <utility> -#include <vector> - -namespace irccd { - -/** - * Namespace for options parsing. - */ -namespace parser { - -/** - * @class InvalidOption - * @brief This exception is thrown when an invalid option has been found. - */ -class InvalidOption : public std::exception { -private: - std::string message; - -public: - /** - * The invalid option given. - */ - std::string argument; - - /** - * Construct the exception. - * - * @param arg the argument missing - */ - inline InvalidOption(std::string arg) - : argument(std::move(arg)) - { - message = std::string("invalid option: ") + argument; - } - - /** - * Get the error message. - * - * @return the error message - */ - const char *what() const noexcept override - { - return message.c_str(); - } -}; - -/** - * @class MissingValue - * @brief This exception is thrown when an option requires a value and no value has been given - */ -class MissingValue : public std::exception { -private: - std::string message; - -public: - /** - * The argument that requires a value. - */ - std::string argument; - - /** - * Construct the exception. - * - * @param arg the argument that requires a value - */ - inline MissingValue(std::string arg) - : argument(std::move(arg)) - { - message = std::string("missing argument for: ") + argument; - } - - /** - * Get the error message. - * - * @return the error message - */ - const char *what() const noexcept override - { - return message.c_str(); - } -}; - -/** - * Packed multimap of options. - */ -using Result = std::multimap<std::string, std::string>; - -/** - * Define the allowed options. - */ -using Options = std::map<std::string, bool>; - -/** - * Extract the command line options and return a result. - * - * @param args the arguments - * @param definition - * @warning the arguments vector is modified in place to remove parsed options - * @throw MissingValue - * @throw InvalidOption - */ -Result read(std::vector<std::string> &args, const Options &definition); - -/** - * Overloaded function for usage with main() arguments. - * - * @param argc the number of arguments - * @param argv the argument vector - * @param definition - * @note don't forget to remove the first argv[0] argument - * @warning the argc and argv are modified in place to remove parsed options - * @throw MissingValue - * @throw InvalidOption - */ -Result read(int &argc, char **&argv, const Options &definition); - -} // !parser - -} // !irccd - -#endif // !IRCCD_OPTION_PARSER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/options.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,150 @@ +/* + * options.hpp -- parse Unix command line options + * + * Copyright (c) 2015 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. + */ + +#ifndef IRCCD_OPTION_PARSER_HPP +#define IRCCD_OPTION_PARSER_HPP + +/** + * @file options.hpp + * @brief Basic options parsing. + */ + +#include <exception> +#include <map> +#include <string> +#include <utility> +#include <vector> + +namespace irccd { + +/** + * Namespace for options parsing. + */ +namespace parser { + +/** + * @class InvalidOption + * @brief This exception is thrown when an invalid option has been found. + */ +class InvalidOption : public std::exception { +private: + std::string message; + +public: + /** + * The invalid option given. + */ + std::string argument; + + /** + * Construct the exception. + * + * @param arg the argument missing + */ + inline InvalidOption(std::string arg) + : argument(std::move(arg)) + { + message = std::string("invalid option: ") + argument; + } + + /** + * Get the error message. + * + * @return the error message + */ + const char *what() const noexcept override + { + return message.c_str(); + } +}; + +/** + * @class MissingValue + * @brief This exception is thrown when an option requires a value and no value has been given + */ +class MissingValue : public std::exception { +private: + std::string message; + +public: + /** + * The argument that requires a value. + */ + std::string argument; + + /** + * Construct the exception. + * + * @param arg the argument that requires a value + */ + inline MissingValue(std::string arg) + : argument(std::move(arg)) + { + message = std::string("missing argument for: ") + argument; + } + + /** + * Get the error message. + * + * @return the error message + */ + const char *what() const noexcept override + { + return message.c_str(); + } +}; + +/** + * Packed multimap of options. + */ +using Result = std::multimap<std::string, std::string>; + +/** + * Define the allowed options. + */ +using Options = std::map<std::string, bool>; + +/** + * Extract the command line options and return a result. + * + * @param args the arguments + * @param definition + * @warning the arguments vector is modified in place to remove parsed options + * @throw MissingValue + * @throw InvalidOption + */ +Result read(std::vector<std::string> &args, const Options &definition); + +/** + * Overloaded function for usage with main() arguments. + * + * @param argc the number of arguments + * @param argv the argument vector + * @param definition + * @note don't forget to remove the first argv[0] argument + * @warning the argc and argv are modified in place to remove parsed options + * @throw MissingValue + * @throw InvalidOption + */ +Result read(int &argc, char **&argv, const Options &definition); + +} // !parser + +} // !irccd + +#endif // !IRCCD_OPTION_PARSER_HPP
--- a/lib/irccd/path.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/path.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -21,7 +21,7 @@ #include <sstream> #include <stdexcept> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> #if defined(IRCCD_SYSTEM_WINDOWS) # include <Windows.h> @@ -53,13 +53,13 @@ # include <libproc.h> # endif -# include "xdg.h" +# include "xdg.hpp" #endif -#include "fs.h" -#include "path.h" -#include "system.h" -#include "util.h" +#include "fs.hpp" +#include "path.hpp" +#include "system.hpp" +#include "util.hpp" namespace irccd {
--- a/lib/irccd/path.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/* - * path.h -- special paths inside irccd - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_PATH_H -#define IRCCD_PATH_H - -/** - * @file path.h - * @brief Path management. - */ - -#include <string> -#include <vector> - -namespace irccd { - -namespace path { - -/** - * PATH separator, either : or ;. - */ -extern const char Separator; - -/** - * @enum Path - * @brief Which special path to get - */ -enum Path { - PathConfig, //!< Configuration files - PathData, //!< Data directory - PathCache, //!< Cache files - PathPlugins //!< Path to the plugins -}; - -/** - * @enum Owner - * @brief For paths, get the installation path or the user ones - */ -enum Owner { - OwnerSystem, //!< System wide - OwnerUser //!< User -}; - -/** - * This function must be called before at the beginning of the main. - * - * It use system dependant program path lookup if available and fallbacks to the path given as argument if any failure - * was encoutered. - * - * @param argv0 the path to the executable (argv[0]) - */ -void setApplicationPath(const std::string &argv0); - -/** - * Clean a path by removing any extra / or \ and add a trailing one. - * - * @param path the path - * @return the updated path - */ -std::string clean(std::string path); - -/** - * Generic function for path retrievement. - * - * The path is always terminated by a trailing / or \\. - * - * @pre setApplicationPath must have been called - * @param path the type of path - * @param owner system or user wide - * @return the path - */ -std::string get(Path path, Owner owner); - -/** - * Generic function for multiple paths. - * - * This function will add more directories than pathSystem*() and pathUser*() functions, for example - * it will add some path if irccd is relocatable. - * - * @pre setApplicationPath must have been called - * @param path the type of path - * @return the list of preferred directories in order - */ -std::vector<std::string> list(Path path); - -} // !path - -} // !irccd - -#endif // !IRCCD_PATH_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/path.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,105 @@ +/* + * path.hpp -- special paths inside irccd + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_PATH_HPP +#define IRCCD_PATH_HPP + +/** + * @file path.hpp + * @brief Path management. + */ + +#include <string> +#include <vector> + +namespace irccd { + +namespace path { + +/** + * PATH separator, either : or ;. + */ +extern const char Separator; + +/** + * @enum Path + * @brief Which special path to get + */ +enum Path { + PathConfig, //!< Configuration files + PathData, //!< Data directory + PathCache, //!< Cache files + PathPlugins //!< Path to the plugins +}; + +/** + * @enum Owner + * @brief For paths, get the installation path or the user ones + */ +enum Owner { + OwnerSystem, //!< System wide + OwnerUser //!< User +}; + +/** + * This function must be called before at the beginning of the main. + * + * It use system dependant program path lookup if available and fallbacks to the path given as argument if any failure + * was encoutered. + * + * @param argv0 the path to the executable (argv[0]) + */ +void setApplicationPath(const std::string &argv0); + +/** + * Clean a path by removing any extra / or \ and add a trailing one. + * + * @param path the path + * @return the updated path + */ +std::string clean(std::string path); + +/** + * Generic function for path retrievement. + * + * The path is always terminated by a trailing / or \\. + * + * @pre setApplicationPath must have been called + * @param path the type of path + * @param owner system or user wide + * @return the path + */ +std::string get(Path path, Owner owner); + +/** + * Generic function for multiple paths. + * + * This function will add more directories than pathSystem*() and pathUser*() functions, for example + * it will add some path if irccd is relocatable. + * + * @pre setApplicationPath must have been called + * @param path the type of path + * @return the list of preferred directories in order + */ +std::vector<std::string> list(Path path); + +} // !path + +} // !irccd + +#endif // !IRCCD_PATH_HPP
--- a/lib/irccd/plugin.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/plugin.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,7 +18,7 @@ #include <stdexcept> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> #if defined(HAVE_STAT) # include <sys/stat.h> @@ -26,22 +26,22 @@ # include <cstring> #endif -#include "fs.h" -#include "js-directory.h" -#include "js-elapsed-timer.h" -#include "js-file.h" -#include "js-irccd.h" -#include "js-logger.h" -#include "js-plugin.h" -#include "js-server.h" -#include "js-system.h" -#include "js-timer.h" -#include "js-unicode.h" -#include "js-util.h" -#include "path.h" -#include "plugin.h" -#include "server.h" -#include "util.h" +#include "fs.hpp" +#include "js-directory.hpp" +#include "js-elapsed-timer.hpp" +#include "js-file.hpp" +#include "js-irccd.hpp" +#include "js-logger.hpp" +#include "js-plugin.hpp" +#include "js-server.hpp" +#include "js-system.hpp" +#include "js-timer.hpp" +#include "js-unicode.hpp" +#include "js-util.hpp" +#include "path.hpp" +#include "plugin.hpp" +#include "server.hpp" +#include "util.hpp" using namespace std;
--- a/lib/irccd/plugin.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,369 +0,0 @@ -/* - * plugin.h -- irccd JavaScript plugin interface - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_PLUGIN_H -#define IRCCD_PLUGIN_H - -/** - * @file plugin.h - * @brief Irccd plugins - */ - -#include <memory> -#include <string> -#include <unordered_map> -#include <unordered_set> -#include <vector> - -#include "js.h" -#include "path.h" -#include "signals.h" -#include "timer.h" - -namespace irccd { - -class Server; -class ServerWhois; - -/** - * @class PluginInfo - * @brief Plugin information - */ -class PluginInfo { -public: - std::string name; //!< plugin name (from file on disk) - std::string parent; //!< parent directory - std::string path; //!< full path to the plugin file - - /* Metadata */ - std::string author{"unknown"}; //!< plugin author - std::string license{"unknown"}; //!< plugin license - std::string summary{"unknown"}; //!< short plugin description - std::string version{"unknown"}; //!< plugin version -}; - -/** - * Configuration map extract from config file. - */ -using PluginConfig = std::unordered_map<std::string, std::string>; - -/** - * Timers that a plugin owns. - */ -using PluginTimers = std::unordered_set<std::shared_ptr<Timer>>; - -/** - * @class Plugin - * @brief JavaScript plugin - * - * A plugin is identified by name and can be loaded and unloaded - * at runtime. - */ -class Plugin { -public: - /** - * Signal: onTimerSignal - * ------------------------------------------------ - * - * When a timer expires. - * - * Arguments: - * - the timer object - */ - Signal<std::shared_ptr<Timer>> onTimerSignal; - - /** - * Signal: onTimerEnd - * ------------------------------------------------ - * - * When a timer is finished. - * - * Arguments: - * - the timer object - */ - Signal<std::shared_ptr<Timer>> onTimerEnd; - -private: - /* JavaScript context */ - duk::Context m_context; - - /* Plugin info and its timers */ - PluginInfo m_info; - PluginTimers m_timers; - - /* Private helpers */ - void call(const std::string &name, unsigned nargs = 0); - void putVars(); - void putPath(const std::string &varname, const std::string &append, path::Path type); - void putPaths(); - void putConfig(const PluginConfig &config); - -public: - /** - * Correct constructor. - * - * @param name the plugin id - * @param path the fully resolved path to the plugin - * @param config the plugin configuration - * @throws std::runtime_error on errors - */ - Plugin(std::string name, std::string path, const PluginConfig &config = PluginConfig()); - - /** - * Temporary, close all timers. - */ - ~Plugin(); - - /** - * Get the plugin information. - */ - const PluginInfo &info() const; - - /** - * Add a timer to the plugin. - * - * @param timer the timer to add - */ - void addTimer(std::shared_ptr<Timer> timer) noexcept; - - /** - * Remove a timer from a plugin. - * - * @param timer - */ - void removeTimer(const std::shared_ptr<Timer> &timer) noexcept; - - /** - * Access the Duktape context. - * - * @return the context - */ - inline duk::Context &context() noexcept - { - return m_context; - } - - /** - * On channel message. This event will call onMessage or - * onCommand if the messages starts with the command character - * plus the plugin name. - * - * @param server the server - * @param origin the user who sent the message - * @param channel the channel - * @param message the message or command - */ - void onCommand(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); - - /** - * On successful connection. - * - * @param server the server - */ - void onConnect(std::shared_ptr<Server> server); - - /** - * On channel mode. - * - * @param server the server - * @param origin the ouser who has changed the mode - * @param channel the channel - * @param mode the mode - * @param arg the optional mode argument - */ - void onChannelMode(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string mode, std::string arg); - - /** - * On a channel notice. - * - * @param server the server - * @param origin the user who sent the notice - * @param channel on which channel - * @param notice the message - */ - void onChannelNotice(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string notice); - - /** - * On invitation. - * - * @param server the server - * @param origin the user who invited you - * @param channel the channel - */ - void onInvite(std::shared_ptr<Server> server, std::string origin, std::string channel); - - /** - * On join. - * - * @param server the server - * @param origin the user who joined - * @param channel the channel - */ - void onJoin(std::shared_ptr<Server> server, std::string origin, std::string channel); - - /** - * On kick. - * - * @param server the server - * @param origin the user who kicked the target - * @param channel the channel - * @param target the kicked target - * @param reason the optional reason - */ - void onKick(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string target, std::string reason); - - /** - * On load. - */ - void onLoad(); - - /** - * On channel message. - * - * @param server the server - * @param origin the user who sent the message - * @param channel the channel - * @param message the message or command - */ - void onMessage(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); - - /** - * On CTCP Action. - * - * @param server the server - * @param origin the user who sent the message - * @param channel the channel (may also be your nickname) - * @param message the message - */ - void onMe(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); - - /** - * On user mode change. - * - * @param server the server - * @param origin the person who changed the mode - * @param mode the new mode - */ - void onMode(std::shared_ptr<Server> server, std::string origin, std::string mode); - - /** - * On names listing. - * - * @param server the server - * @param channel the channel - * @param list the list of nicknames - */ - void onNames(std::shared_ptr<Server> server, std::string channel, std::vector<std::string> list); - - /** - * On nick change. - * - * @param server the server - * @param origin the user that changed its nickname - * @param nick the new nickname - */ - void onNick(std::shared_ptr<Server> server, std::string origin, std::string nick); - - /** - * On user notice. - * - * @param server the server - * @param origin the user who sent the notice - * @param notice the notice - */ - void onNotice(std::shared_ptr<Server> server, std::string origin, std::string notice); - - /** - * On part. - * - * @param server the server - * @param origin the user who left - * @param channel the channel - * @param reason the optional reason - */ - void onPart(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string reason); - - /** - * On user query. - * - * @param server the server - * @param origin the user who sent the query - * @param message the message - */ - void onQuery(std::shared_ptr<Server> server, std::string origin, std::string message); - - /** - * On user query command. - * - * @param server the server - * @param origin the user who sent the query - * @param message the message - */ - void onQueryCommand(std::shared_ptr<Server> server, std::string origin, std::string message); - - /** - * On reload. - */ - void onReload(); - - /** - * On topic change. - * - * @param server the server - * @param origin the user who sent the topic - * @param channel the channel - * @param topic the new topic - */ - void onTopic(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string topic); - - /** - * On unload. - */ - void onUnload(); - - /** - * On whois information. - * - * @param server the server - * @param info the info - */ - void onWhois(std::shared_ptr<Server> server, ServerWhois info); -}; - -namespace duk { - -/** - * @brief Push plugin information. - */ -template <> -class TypeTraits<irccd::PluginInfo> { -public: - /** - * Push the plugin information as JavaScript object. - * - * @param ctx the context - * @param info the plugin information - */ - static void push(ContextPtr ctx, const PluginInfo &info); -}; - -} // !duk - -} // !irccd - -#endif // !IRCCD_PLUGIN_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/plugin.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,369 @@ +/* + * plugin.hpp -- irccd JavaScript plugin interface + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_PLUGIN_HPP +#define IRCCD_PLUGIN_HPP + +/** + * @file plugin.hpp + * @brief Irccd plugins + */ + +#include <memory> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +#include "js.hpp" +#include "path.hpp" +#include "signals.hpp" +#include "timer.hpp" + +namespace irccd { + +class Server; +class ServerWhois; + +/** + * @class PluginInfo + * @brief Plugin information + */ +class PluginInfo { +public: + std::string name; //!< plugin name (from file on disk) + std::string parent; //!< parent directory + std::string path; //!< full path to the plugin file + + /* Metadata */ + std::string author{"unknown"}; //!< plugin author + std::string license{"unknown"}; //!< plugin license + std::string summary{"unknown"}; //!< short plugin description + std::string version{"unknown"}; //!< plugin version +}; + +/** + * Configuration map extract from config file. + */ +using PluginConfig = std::unordered_map<std::string, std::string>; + +/** + * Timers that a plugin owns. + */ +using PluginTimers = std::unordered_set<std::shared_ptr<Timer>>; + +/** + * @class Plugin + * @brief JavaScript plugin + * + * A plugin is identified by name and can be loaded and unloaded + * at runtime. + */ +class Plugin { +public: + /** + * Signal: onTimerSignal + * ------------------------------------------------ + * + * When a timer expires. + * + * Arguments: + * - the timer object + */ + Signal<std::shared_ptr<Timer>> onTimerSignal; + + /** + * Signal: onTimerEnd + * ------------------------------------------------ + * + * When a timer is finished. + * + * Arguments: + * - the timer object + */ + Signal<std::shared_ptr<Timer>> onTimerEnd; + +private: + /* JavaScript context */ + duk::Context m_context; + + /* Plugin info and its timers */ + PluginInfo m_info; + PluginTimers m_timers; + + /* Private helpers */ + void call(const std::string &name, unsigned nargs = 0); + void putVars(); + void putPath(const std::string &varname, const std::string &append, path::Path type); + void putPaths(); + void putConfig(const PluginConfig &config); + +public: + /** + * Correct constructor. + * + * @param name the plugin id + * @param path the fully resolved path to the plugin + * @param config the plugin configuration + * @throws std::runtime_error on errors + */ + Plugin(std::string name, std::string path, const PluginConfig &config = PluginConfig()); + + /** + * Temporary, close all timers. + */ + ~Plugin(); + + /** + * Get the plugin information. + */ + const PluginInfo &info() const; + + /** + * Add a timer to the plugin. + * + * @param timer the timer to add + */ + void addTimer(std::shared_ptr<Timer> timer) noexcept; + + /** + * Remove a timer from a plugin. + * + * @param timer + */ + void removeTimer(const std::shared_ptr<Timer> &timer) noexcept; + + /** + * Access the Duktape context. + * + * @return the context + */ + inline duk::Context &context() noexcept + { + return m_context; + } + + /** + * On channel message. This event will call onMessage or + * onCommand if the messages starts with the command character + * plus the plugin name. + * + * @param server the server + * @param origin the user who sent the message + * @param channel the channel + * @param message the message or command + */ + void onCommand(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); + + /** + * On successful connection. + * + * @param server the server + */ + void onConnect(std::shared_ptr<Server> server); + + /** + * On channel mode. + * + * @param server the server + * @param origin the ouser who has changed the mode + * @param channel the channel + * @param mode the mode + * @param arg the optional mode argument + */ + void onChannelMode(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string mode, std::string arg); + + /** + * On a channel notice. + * + * @param server the server + * @param origin the user who sent the notice + * @param channel on which channel + * @param notice the message + */ + void onChannelNotice(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string notice); + + /** + * On invitation. + * + * @param server the server + * @param origin the user who invited you + * @param channel the channel + */ + void onInvite(std::shared_ptr<Server> server, std::string origin, std::string channel); + + /** + * On join. + * + * @param server the server + * @param origin the user who joined + * @param channel the channel + */ + void onJoin(std::shared_ptr<Server> server, std::string origin, std::string channel); + + /** + * On kick. + * + * @param server the server + * @param origin the user who kicked the target + * @param channel the channel + * @param target the kicked target + * @param reason the optional reason + */ + void onKick(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string target, std::string reason); + + /** + * On load. + */ + void onLoad(); + + /** + * On channel message. + * + * @param server the server + * @param origin the user who sent the message + * @param channel the channel + * @param message the message or command + */ + void onMessage(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); + + /** + * On CTCP Action. + * + * @param server the server + * @param origin the user who sent the message + * @param channel the channel (may also be your nickname) + * @param message the message + */ + void onMe(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string message); + + /** + * On user mode change. + * + * @param server the server + * @param origin the person who changed the mode + * @param mode the new mode + */ + void onMode(std::shared_ptr<Server> server, std::string origin, std::string mode); + + /** + * On names listing. + * + * @param server the server + * @param channel the channel + * @param list the list of nicknames + */ + void onNames(std::shared_ptr<Server> server, std::string channel, std::vector<std::string> list); + + /** + * On nick change. + * + * @param server the server + * @param origin the user that changed its nickname + * @param nick the new nickname + */ + void onNick(std::shared_ptr<Server> server, std::string origin, std::string nick); + + /** + * On user notice. + * + * @param server the server + * @param origin the user who sent the notice + * @param notice the notice + */ + void onNotice(std::shared_ptr<Server> server, std::string origin, std::string notice); + + /** + * On part. + * + * @param server the server + * @param origin the user who left + * @param channel the channel + * @param reason the optional reason + */ + void onPart(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string reason); + + /** + * On user query. + * + * @param server the server + * @param origin the user who sent the query + * @param message the message + */ + void onQuery(std::shared_ptr<Server> server, std::string origin, std::string message); + + /** + * On user query command. + * + * @param server the server + * @param origin the user who sent the query + * @param message the message + */ + void onQueryCommand(std::shared_ptr<Server> server, std::string origin, std::string message); + + /** + * On reload. + */ + void onReload(); + + /** + * On topic change. + * + * @param server the server + * @param origin the user who sent the topic + * @param channel the channel + * @param topic the new topic + */ + void onTopic(std::shared_ptr<Server> server, std::string origin, std::string channel, std::string topic); + + /** + * On unload. + */ + void onUnload(); + + /** + * On whois information. + * + * @param server the server + * @param info the info + */ + void onWhois(std::shared_ptr<Server> server, ServerWhois info); +}; + +namespace duk { + +/** + * @brief Push plugin information. + */ +template <> +class TypeTraits<irccd::PluginInfo> { +public: + /** + * Push the plugin information as JavaScript object. + * + * @param ctx the context + * @param info the plugin information + */ + static void push(ContextPtr ctx, const PluginInfo &info); +}; + +} // !duk + +} // !irccd + +#endif // !IRCCD_PLUGIN_HPP
--- a/lib/irccd/rule.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/rule.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,9 +18,9 @@ #include <stdexcept> -#include "logger.h" -#include "rule.h" -#include "util.h" +#include "logger.hpp" +#include "rule.hpp" +#include "util.hpp" using namespace std;
--- a/lib/irccd/rule.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/* - * rule.h -- rule for server and channels - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_RULE_H -#define IRCCD_RULE_H - -/** - * @file rule.h - * @brief Rule description - */ - -#include <sstream> -#include <string> -#include <unordered_set> -#include <utility> -#include <vector> - -namespace irccd { - -/** - * List of criterias. - */ -using RuleSet = std::unordered_set<std::string>; - -/** - * @enum RuleAction - * @brief Rule action - */ -enum class RuleAction { - Accept, //!< The event is accepted (default) - Drop //!< The event is dropped -}; - -/** - * @class Rule - * @brief Manage rule to activate or deactive events. - */ -class Rule final { -private: - RuleSet m_servers; - RuleSet m_channels; - RuleSet m_origins; - RuleSet m_plugins; - RuleSet m_events; - RuleAction m_action{RuleAction::Accept}; - - /* - * Check if a map contains the value and return true if it is - * or return true if value is empty (which means applicable). - */ - bool matchMap(const RuleSet &map, const std::string &value) const noexcept; - -public: - /** - * Resolve the action to execute with the specified list of rules. - * - * @param rules the list of rules - * @param server the server name - * @param channel the channel name - * @param origin the origin - * @param plugin the plugin name - * @param event the event name (e.g onKick) - * @return true if the plugin must be called - */ - static bool solve(const std::vector<Rule> &rules, - const std::string &server, - const std::string &channel, - const std::string &origin, - const std::string &plugin, - const std::string &event) noexcept; - - /** - * Rule constructor. - * - * @param servers the server list - * @param channels the channels - * @param nicknames the nicknames - * @param plugins the plugins - * @param events the events - * @param action the rule action - * @throw std::invalid_argument if events are invalid - */ - Rule(RuleSet servers = RuleSet{}, - RuleSet channels = RuleSet{}, - RuleSet nicknames = RuleSet{}, - RuleSet plugins = RuleSet{}, - RuleSet events = RuleSet{}, - RuleAction action = RuleAction::Accept); - - /** - * Check if that rule apply for the given criterias. - * - * @param server the server - * @param channel the channel - * @param nick the origin - * @param plugin the plugin - * @param event the event - * @return true if match - */ - bool match(const std::string &server, - const std::string &channel, - const std::string &nick, - const std::string &plugin, - const std::string &event) const noexcept; - - /** - * Get the action. - * - * @return the action - */ - RuleAction action() const noexcept; - - /** - * Get the servers. - * - * @return the servers - */ - const RuleSet &servers() const noexcept; - - /** - * Get the channels. - * - * @return the channels - */ - const RuleSet &channels() const noexcept; - - /** - * Get the origins. - * - * @return the origins - */ - const RuleSet &origins() const noexcept; - - /** - * Get the plugins. - * - * @return the plugins - */ - const RuleSet &plugins() const noexcept; - - /** - * Get the events. - * - * @return the events - */ - const RuleSet &events() const noexcept; -}; - -} // !irccd - -#endif // !IRCCD_RULE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/rule.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,166 @@ +/* + * rule.hpp -- rule for server and channels + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_RULE_HPP +#define IRCCD_RULE_HPP + +/** + * @file rule.hpp + * @brief Rule description + */ + +#include <sstream> +#include <string> +#include <unordered_set> +#include <utility> +#include <vector> + +namespace irccd { + +/** + * List of criterias. + */ +using RuleSet = std::unordered_set<std::string>; + +/** + * @enum RuleAction + * @brief Rule action + */ +enum class RuleAction { + Accept, //!< The event is accepted (default) + Drop //!< The event is dropped +}; + +/** + * @class Rule + * @brief Manage rule to activate or deactive events. + */ +class Rule final { +private: + RuleSet m_servers; + RuleSet m_channels; + RuleSet m_origins; + RuleSet m_plugins; + RuleSet m_events; + RuleAction m_action{RuleAction::Accept}; + + /* + * Check if a map contains the value and return true if it is + * or return true if value is empty (which means applicable). + */ + bool matchMap(const RuleSet &map, const std::string &value) const noexcept; + +public: + /** + * Resolve the action to execute with the specified list of rules. + * + * @param rules the list of rules + * @param server the server name + * @param channel the channel name + * @param origin the origin + * @param plugin the plugin name + * @param event the event name (e.g onKick) + * @return true if the plugin must be called + */ + static bool solve(const std::vector<Rule> &rules, + const std::string &server, + const std::string &channel, + const std::string &origin, + const std::string &plugin, + const std::string &event) noexcept; + + /** + * Rule constructor. + * + * @param servers the server list + * @param channels the channels + * @param nicknames the nicknames + * @param plugins the plugins + * @param events the events + * @param action the rule action + * @throw std::invalid_argument if events are invalid + */ + Rule(RuleSet servers = RuleSet{}, + RuleSet channels = RuleSet{}, + RuleSet nicknames = RuleSet{}, + RuleSet plugins = RuleSet{}, + RuleSet events = RuleSet{}, + RuleAction action = RuleAction::Accept); + + /** + * Check if that rule apply for the given criterias. + * + * @param server the server + * @param channel the channel + * @param nick the origin + * @param plugin the plugin + * @param event the event + * @return true if match + */ + bool match(const std::string &server, + const std::string &channel, + const std::string &nick, + const std::string &plugin, + const std::string &event) const noexcept; + + /** + * Get the action. + * + * @return the action + */ + RuleAction action() const noexcept; + + /** + * Get the servers. + * + * @return the servers + */ + const RuleSet &servers() const noexcept; + + /** + * Get the channels. + * + * @return the channels + */ + const RuleSet &channels() const noexcept; + + /** + * Get the origins. + * + * @return the origins + */ + const RuleSet &origins() const noexcept; + + /** + * Get the plugins. + * + * @return the plugins + */ + const RuleSet &plugins() const noexcept; + + /** + * Get the events. + * + * @return the events + */ + const RuleSet &events() const noexcept; +}; + +} // !irccd + +#endif // !IRCCD_RULE_HPP
--- a/lib/irccd/server-private.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* - * server-private.h -- libircclient bridge - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_SERVER_PRIVATE_H -#define IRCCD_SERVER_PRIVATE_H - -#include <memory> - -#include <libircclient.h> - -#include "server.h" - -namespace irccd { - -/** - * @brief Bridge for libircclient - */ -class Server::Session { -public: - /** - * libircclient handle. - */ - using Handle = std::unique_ptr<irc_session_t, void (*)(irc_session_t *)>; - -private: - Handle m_handle; - -public: - /** - * Create a null session. - */ - inline Session() - : m_handle(nullptr, nullptr) - { - } - - /** - * Convert the libircclient session. - */ - inline operator const irc_session_t *() const noexcept - { - return m_handle.get(); - } - - /** - * Overloaded function. - */ - inline operator irc_session_t *() noexcept - { - return m_handle.get(); - } - - /** - * Get the handle. - * - * @return the handle - */ - inline Handle &handle() noexcept - { - return m_handle; - } -}; - -} // !irccd - -#endif // !IRCCD_SERVER_PRIVATE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/server-private.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,81 @@ +/* + * server-private.hpp -- libircclient bridge + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SERVER_PRIVATE_HPP +#define IRCCD_SERVER_PRIVATE_HPP + +#include <memory> + +#include <libircclient.h> + +#include "server.hpp" + +namespace irccd { + +/** + * @brief Bridge for libircclient + */ +class Server::Session { +public: + /** + * libircclient handle. + */ + using Handle = std::unique_ptr<irc_session_t, void (*)(irc_session_t *)>; + +private: + Handle m_handle; + +public: + /** + * Create a null session. + */ + inline Session() + : m_handle(nullptr, nullptr) + { + } + + /** + * Convert the libircclient session. + */ + inline operator const irc_session_t *() const noexcept + { + return m_handle.get(); + } + + /** + * Overloaded function. + */ + inline operator irc_session_t *() noexcept + { + return m_handle.get(); + } + + /** + * Get the handle. + * + * @return the handle + */ + inline Handle &handle() noexcept + { + return m_handle; + } +}; + +} // !irccd + +#endif // !IRCCD_SERVER_PRIVATE_HPP
--- a/lib/irccd/server-state.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/server-state.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,7 +18,7 @@ #include <cassert> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> #if !defined(_WIN32) # include <sys/types.h> @@ -27,8 +27,8 @@ # include <resolv.h> #endif -#include "server-state.h" -#include "server-private.h" +#include "server-state.hpp" +#include "server-private.hpp" namespace irccd {
--- a/lib/irccd/server-state.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - * server-state.h -- server current state - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_SERVER_STATE_H -#define IRCCD_SERVER_STATE_H - -/** - * @file server-state.h - * @brief Server state. - */ - -#include <irccd/sysconfig.h> - -#include "elapsed-timer.h" -#include "sockets.h" - -namespace irccd { - -class Server; - -/** - * @class ServerState - * @brief Server current state. - */ -class ServerState { -public: - /** - * @enum Type - * @brief Server state - */ - enum Type { - Undefined, //!< Not defined yet - Connecting, //!< Connecting to the server - Connected, //!< Connected and running - Disconnected, //!< Disconnected and waiting before retrying - }; - -private: - Type m_type; - - /* For ServerState::Connecting */ - bool m_started{false}; - ElapsedTimer m_timer; - - /* Private helpers */ - bool connect(Server &server); - - /* Different preparation */ - void prepareConnected(Server &, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd); - void prepareConnecting(Server &, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd); - void prepareDisconnected(Server &, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd); - -public: - /** - * Create the server state. - * - * @pre type must be valid - * @param type the type - */ - ServerState(Type type); - - /** - * Prepare the state. - * - * @param server the server - * @param setinput the read set - * @param setoutput the write set - * @param maxfd the maximum fd - */ - void prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd); - - /** - * Get the state type. - * - * @return the type - */ - inline Type type() const noexcept - { - return m_type; - } -}; - -} // !irccd - -#endif // !IRCCD_SERVER_STATE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/server-state.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,100 @@ +/* + * server-state.hpp -- server current state + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SERVER_STATE_HPP +#define IRCCD_SERVER_STATE_HPP + +/** + * @file server-state.hpp + * @brief Server state. + */ + +#include <irccd/sysconfig.hpp> + +#include "elapsed-timer.hpp" +#include "sockets.hpp" + +namespace irccd { + +class Server; + +/** + * @class ServerState + * @brief Server current state. + */ +class ServerState { +public: + /** + * @enum Type + * @brief Server state + */ + enum Type { + Undefined, //!< Not defined yet + Connecting, //!< Connecting to the server + Connected, //!< Connected and running + Disconnected, //!< Disconnected and waiting before retrying + }; + +private: + Type m_type; + + /* For ServerState::Connecting */ + bool m_started{false}; + ElapsedTimer m_timer; + + /* Private helpers */ + bool connect(Server &server); + + /* Different preparation */ + void prepareConnected(Server &, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd); + void prepareConnecting(Server &, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd); + void prepareDisconnected(Server &, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd); + +public: + /** + * Create the server state. + * + * @pre type must be valid + * @param type the type + */ + ServerState(Type type); + + /** + * Prepare the state. + * + * @param server the server + * @param setinput the read set + * @param setoutput the write set + * @param maxfd the maximum fd + */ + void prepare(Server &server, fd_set &setinput, fd_set &setoutput, net::Handle &maxfd); + + /** + * Get the state type. + * + * @return the type + */ + inline Type type() const noexcept + { + return m_type; + } +}; + +} // !irccd + +#endif // !IRCCD_SERVER_STATE_HPP
--- a/lib/irccd/server.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/server.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -23,9 +23,9 @@ #include <libirc_rfcnumeric.h> -#include "logger.h" -#include "server-private.h" -#include "util.h" +#include "logger.hpp" +#include "server-private.hpp" +#include "util.hpp" namespace irccd {
--- a/lib/irccd/server.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,765 +0,0 @@ -/* - * server.h -- an IRC server - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_SERVER_H -#define IRCCD_SERVER_H - -/** - * @file server.h - * @brief IRC Server. - */ - -#include <cstdint> -#include <functional> -#include <map> -#include <memory> -#include <queue> -#include <set> -#include <string> -#include <unordered_map> -#include <utility> -#include <vector> - -#include <irccd/sysconfig.h> - -#include "logger.h" -#include "server-state.h" -#include "signals.h" - -namespace irccd { - -/** - * @class ServerIdentity - * @brief Identity to use when connecting - */ -class ServerIdentity { -public: - std::string name{"irccd"}; //!< identity name - std::string nickname{"irccd"}; //!< nickname to show - std::string username{"irccd"}; //!< username to use for connection - std::string realname{"IRC Client Daemon"}; //!< the full real name - std::string ctcpversion{"IRC Client Daemon"}; //!< the CTCP version to define -}; - -/** - * @class ServerChannel - * @brief A channel to join with an optional password - */ -class ServerChannel { -public: - std::string name; //!< the channel to join - std::string password; //!< the optional password -}; - -/** - * List of channels. - */ -using ServerChannels = std::vector<ServerChannel>; - -/** - * @enum ServerChanMode - * @brief Prefixes for nicknames - */ -enum class ServerChanMode { - Creator = 'O', //!< Channel creator - HalfOperator = 'h', //!< Half operator - Operator = 'o', //!< Channel operator - Protection = 'a', //!< Unkillable - Voiced = 'v' //!< Voice power -}; - -/** - * @class ServerWhois - * @brief Describe a whois information - * - * This is provided when whois command was requested. - */ -class ServerWhois { -public: - std::string nick; //!< user's nickname - std::string user; //!< user's user - std::string host; //!< hostname - std::string realname; //!< realname - std::vector<std::string> channels; //!< the channels where the user is -}; - -/** - * @class ServerInfo - * @brief Server information - * - * This class contains everything needed to connect to a server. - */ -class ServerInfo { -public: - enum { - Ipv6 = (1 << 0), //!< Connect using IPv6 - Ssl = (1 << 1), //!< Use SSL - SslVerify = (1 << 2) //!< Verify SSL - }; - - std::string name; //!< Server's name - std::string host; //!< Hostname - std::string password; //!< Optional server password - std::uint16_t port{6667}; //!< Server's port - std::uint8_t flags{0}; //!< Optional flags - std::map<ServerChanMode, char> modes; //!< IRC modes (e.g. @~) -}; - -/** - * @class ServerSettings - * @brief Contains settings to tweak the server - * - * This class contains additional settings that tweaks the - * server operations. - */ -class ServerSettings { -public: - enum { - AutoRejoin = (1 << 0), //!< Auto rejoin a channel after being kicked - JoinInvite = (1 << 1) //!< Join a channel on invitation - }; - - ServerChannels channels; //!< List of channel to join - std::string command{"!"}; //!< The command character to trigger plugin command - std::int8_t recotries{-1}; //!< Number of tries to reconnect before giving up - std::uint16_t recotimeout{30}; //!< Number of seconds to wait before trying to connect - std::uint8_t flags{0}; //!< Optional flags - - /* Private */ - std::int8_t recocurrent{1}; //!< number of tries tested -}; - -/** - * Deferred command to send to the server. - * - * If the command returns true, it has been correctly buffered for outgoing - * and removed from the queue. - */ -using ServerCommand = std::function<bool ()>; - -/** - * @class Server - * @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 can be used directly by the user to connect to a server. - * - * The server has several signals that will be emitted when data has arrived. - * - * When adding a server to the irccd instance using Irccd::addServer, these signals are connected to generate - * events that will be dispatched to the plugins and to the transports. - * - * 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 { -public: - /** - * Bridge for libircclient. - */ - class Session; - - /** - * Signal: onChannelMode - * ------------------------------------------------ - * - * 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: 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: onConnect - * ------------------------------------------------ - * - * Triggered when the server is successfully connected. - */ - Signal<> onConnect; - - /** - * Signal: onDie - * ---------------------------------------------------------- - * - * The server is dead. - */ - Signal<> onDie; - - /** - * Signal: onInvite - * ------------------------------------------------ - * - * 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: 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: 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; - - /** - * 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: onMe - * ------------------------------------------------ - * - * 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: onMode - * ------------------------------------------------ - * - * Triggered when the server changed your user mode. - * - * Arguments: - * - the origin - * - the mode (e.g +i) - */ - Signal<std::string, std::string> 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: 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: onNotice - * ------------------------------------------------ - * - * Triggered when someone has sent a notice to you. - * - * Arguments: - * - the origin - * - the notice message - */ - Signal<std::string, std::string> 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: onQuery - * ------------------------------------------------ - * - * Triggered when someone has sent you a private message. - * - * Arguments: - * - the origin - * - the message - */ - Signal<std::string, std::string> 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: onWhois - * ------------------------------------------------ - * - * Triggered when whois information has been received. - * - * Arguments: - * - the whois object - */ - Signal<ServerWhois> onWhois; - -private: - using SessionPtr = std::unique_ptr<Session>; - using Queue = std::queue<ServerCommand>; - - /** - * List of NAMES being built. - */ - using NamesMap = std::unordered_map<std::string, std::set<std::string>>; - - /** - * List of WHOIS being built. - */ - using WhoisMap = std::unordered_map<std::string, ServerWhois>; - -private: - ServerInfo m_info; - ServerSettings m_settings; - ServerIdentity m_identity; - SessionPtr m_session; - ServerState m_state; - ServerState m_next; - Queue m_queue; - - /* - * The names map is being built by a successive call to handleNumeric so we need to store a temporary - * map by channels to list of names. Then, when we receive the end of names listing, we remove the - * temporary set of names and calls the appropriate signal. - */ - NamesMap m_namesMap; - WhoisMap m_whoisMap; - - bool isSelf(const std::string &nick) const noexcept; - void extractPrefixes(const std::string &line); - std::string cleanPrefix(std::string nickname) const noexcept; - - inline std::string strify(const char *s) - { - return (s == nullptr) ? "" : std::string(s); - } - - void handleChannel(const char *, const char **) noexcept; - void handleChannelMode(const char *, const char **) noexcept; - void handleChannelNotice(const char *, const char **) noexcept; - void handleConnect(const char *, const char **) noexcept; - void handleCtcpAction(const char *, const char **) noexcept; - void handleInvite(const char *, const char **) noexcept; - void handleJoin(const char *, const char **) noexcept; - void handleKick(const char *, const char **) noexcept; - void handleMode(const char *, const char **) noexcept; - void handleNick(const char *, const char **) noexcept; - void handleNotice(const char *, const char **) noexcept; - void handleNumeric(unsigned int, const char **, unsigned int) noexcept; - void handlePart(const char *, const char **) noexcept; - void handleQuery(const char *, const char **) noexcept; - void handleTopic(const char *, const char **) noexcept; - -public: - /** - * Split a channel from the form channel:password into a ServerChannel object. - * - * @param value the value - * @return a channel - */ - static ServerChannel splitChannel(const std::string &value); - - /** - * Construct a server. - * - * @param info the information - * @param identity the identity - * @param settings the settings - */ - Server(ServerInfo info, ServerIdentity identity = {}, ServerSettings settings = {}); - - /** - * Destructor. Close the connection if needed. - */ - virtual ~Server(); - - /** - * Set the next state to be used. This function is thread safe because - * the server manager may set the next state to the current state. - * - * If the server is installed into the ServerManager, it is called - * automatically. - * - * @param type the new state type - * @warning Not thread-safe - */ - inline void next(ServerState::Type type) - { - m_next = ServerState(type); - } - - /** - * Switch to next state if it has. - * - * If the server is installed into irccd, it is called automatically. - * - * @warning Not thread-safe - */ - void update() noexcept; - - /** - * Request to disconnect. This function does not notify the - * ServerService. - * - * @see Irccd::serverDisconnect - * @note Thread-safe - */ - void disconnect() noexcept; - - /** - * Asks for a reconnection. This function does not notify the - * ServerService. - * - * @see Irccd::serverReconnect - * @note Thread-safe - */ - void reconnect() noexcept; - - /** - * Flush the pending commands if possible. This function will send - * as much as possible commands. - * - * If the server is installed into the ServerManager, it is called - * automatically. - * - * @note Thread-safe - */ - void flush() noexcept; - - /** - * Prepare the IRC Session to the socket. - * - * If the server is installed into the ServerManager, it is called - * automatically. - * - * @warning Not thread-safe - */ - inline void prepare(fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) noexcept - { - m_state.prepare(*this, setinput, setoutput, maxfd); - } - - /** - * Process incoming/outgoing data after selection. - * - * If the server is installed into the ServerManager, it is called - * automatically. - * - * @param setinput - * @param setoutput - * @throw any exception that have been throw from user functions - */ - void sync(fd_set &setinput, fd_set &setoutput) noexcept; - - /** - * Get the server information. - * - * @warning This overload should not be used by the user, it is required to - * update the nickname. - * @return the server information - */ - inline ServerInfo &info() noexcept - { - return m_info; - } - - /** - * Get the server information. - * - * @return the server information - */ - inline const ServerInfo &info() const noexcept - { - return m_info; - } - - /** - * Get the server settings. - * - * @warning This overload should not be used by the user, it is required to - * update the reconnection information. - * @return the settings - */ - inline ServerSettings &settings() noexcept - { - return m_settings; - } - - /** - * Get the server settings. - * - * @return the settings - */ - inline const ServerSettings &settings() const noexcept - { - return m_settings; - } - - /** - * Get the identity. - * - * @return the identity - */ - inline ServerIdentity &identity() noexcept - { - return m_identity; - } - - /** - * Overloaded function - * - * @return the identity - */ - inline const ServerIdentity &identity() const noexcept - { - return m_identity; - } - - /** - * Get the current state identifier. Should not be used by user code. - * - * @note Thread-safe but the state may change just after the call - */ - inline ServerState::Type type() const noexcept - { - return m_state.type(); - } - - /** - * Get the private session. - * - * @return the session - */ - inline Session &session() noexcept - { - return *m_session; - } - - /** - * Change the channel mode. - * - * @param channel the channel - * @param mode the new mode - * @note Thread-safe - */ - void cmode(std::string channel, std::string mode); - - /** - * Send a channel notice. - * - * @param channel the channel - * @param message message notice - * @note Thread-safe - */ - void cnotice(std::string channel, std::string message) noexcept; - - /** - * Invite a user to a channel. - * - * @param target the target nickname - * @param channel the channel - * @note Thread-safe - */ - void invite(std::string target, std::string channel) noexcept; - - /** - * Join a channel, the password is optional and can be kept empty. - * - * @param channel the channel to join - * @param password the optional password - * @note Thread-safe - */ - void join(std::string channel, std::string password = "") noexcept; - - /** - * Kick someone from the channel. Please be sure to have the rights - * on that channel because errors won't be reported. - * - * @param target the target to kick - * @param channel from which channel - * @param reason the optional reason - * @note Thread-safe - */ - void kick(std::string target, std::string channel, std::string reason = "") noexcept; - - /** - * Send a CTCP Action as known as /me. The target may be either a - * channel or a nickname. - * - * @param target the nickname or the channel - * @param message the message - * @note Thread-safe - */ - void me(std::string target, std::string message); - - /** - * Send a message to the specified target or channel. - * - * @param target the target - * @param message the message - * @note Thread-safe - */ - void message(std::string target, std::string message); - - /** - * Change your user mode. - * - * @param mode the mode - * @note Thread-safe - */ - void mode(std::string mode); - - /** - * Request the list of names. - * - * @param channel the channel - * @note Thread-safe - */ - void names(std::string channel); - - /** - * Change your nickname. - * - * @param newnick the new nickname to use - * @note Thread-safe - */ - void nick(std::string newnick); - - /** - * Send a private notice. - * - * @param target the target - * @param message the notice message - * @note Thread-safe - */ - void notice(std::string target, std::string message); - - /** - * Part from a channel. - * - * Please note that the reason is not supported on all servers so if you want portability, don't provide it. - * - * @param channel the channel to leave - * @param reason the optional reason - * @note Thread-safe - */ - void part(std::string channel, std::string reason = ""); - - /** - * Send a raw message to the IRC server. You don't need to add - * message terminators. - * - * @warning Use this function with care - * @param raw the raw message (without `\r\n\r\n`) - * @note Thread-safe - */ - void send(std::string raw); - - /** - * Change the channel topic. - * - * @param channel the channel - * @param topic the desired topic - * @note Thread-safe - */ - void topic(std::string channel, std::string topic); - - /** - * Request for whois information. - * - * @param target the target nickname - * @note Thread-safe - */ - void whois(std::string target); -}; - -} // !irccd - -#endif // !IRCCD_SERVER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/server.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,765 @@ +/* + * server.hpp -- an IRC server + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SERVER_HPP +#define IRCCD_SERVER_HPP + +/** + * @file server.hpp + * @brief IRC Server. + */ + +#include <cstdint> +#include <functional> +#include <map> +#include <memory> +#include <queue> +#include <set> +#include <string> +#include <unordered_map> +#include <utility> +#include <vector> + +#include <irccd/sysconfig.hpp> + +#include "logger.hpp" +#include "server-state.hpp" +#include "signals.hpp" + +namespace irccd { + +/** + * @class ServerIdentity + * @brief Identity to use when connecting + */ +class ServerIdentity { +public: + std::string name{"irccd"}; //!< identity name + std::string nickname{"irccd"}; //!< nickname to show + std::string username{"irccd"}; //!< username to use for connection + std::string realname{"IRC Client Daemon"}; //!< the full real name + std::string ctcpversion{"IRC Client Daemon"}; //!< the CTCP version to define +}; + +/** + * @class ServerChannel + * @brief A channel to join with an optional password + */ +class ServerChannel { +public: + std::string name; //!< the channel to join + std::string password; //!< the optional password +}; + +/** + * List of channels. + */ +using ServerChannels = std::vector<ServerChannel>; + +/** + * @enum ServerChanMode + * @brief Prefixes for nicknames + */ +enum class ServerChanMode { + Creator = 'O', //!< Channel creator + HalfOperator = 'h', //!< Half operator + Operator = 'o', //!< Channel operator + Protection = 'a', //!< Unkillable + Voiced = 'v' //!< Voice power +}; + +/** + * @class ServerWhois + * @brief Describe a whois information + * + * This is provided when whois command was requested. + */ +class ServerWhois { +public: + std::string nick; //!< user's nickname + std::string user; //!< user's user + std::string host; //!< hostname + std::string realname; //!< realname + std::vector<std::string> channels; //!< the channels where the user is +}; + +/** + * @class ServerInfo + * @brief Server information + * + * This class contains everything needed to connect to a server. + */ +class ServerInfo { +public: + enum { + Ipv6 = (1 << 0), //!< Connect using IPv6 + Ssl = (1 << 1), //!< Use SSL + SslVerify = (1 << 2) //!< Verify SSL + }; + + std::string name; //!< Server's name + std::string host; //!< Hostname + std::string password; //!< Optional server password + std::uint16_t port{6667}; //!< Server's port + std::uint8_t flags{0}; //!< Optional flags + std::map<ServerChanMode, char> modes; //!< IRC modes (e.g. @~) +}; + +/** + * @class ServerSettings + * @brief Contains settings to tweak the server + * + * This class contains additional settings that tweaks the + * server operations. + */ +class ServerSettings { +public: + enum { + AutoRejoin = (1 << 0), //!< Auto rejoin a channel after being kicked + JoinInvite = (1 << 1) //!< Join a channel on invitation + }; + + ServerChannels channels; //!< List of channel to join + std::string command{"!"}; //!< The command character to trigger plugin command + std::int8_t recotries{-1}; //!< Number of tries to reconnect before giving up + std::uint16_t recotimeout{30}; //!< Number of seconds to wait before trying to connect + std::uint8_t flags{0}; //!< Optional flags + + /* Private */ + std::int8_t recocurrent{1}; //!< number of tries tested +}; + +/** + * Deferred command to send to the server. + * + * If the command returns true, it has been correctly buffered for outgoing + * and removed from the queue. + */ +using ServerCommand = std::function<bool ()>; + +/** + * @class Server + * @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 can be used directly by the user to connect to a server. + * + * The server has several signals that will be emitted when data has arrived. + * + * When adding a server to the irccd instance using Irccd::addServer, these signals are connected to generate + * events that will be dispatched to the plugins and to the transports. + * + * 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 { +public: + /** + * Bridge for libircclient. + */ + class Session; + + /** + * Signal: onChannelMode + * ------------------------------------------------ + * + * 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: 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: onConnect + * ------------------------------------------------ + * + * Triggered when the server is successfully connected. + */ + Signal<> onConnect; + + /** + * Signal: onDie + * ---------------------------------------------------------- + * + * The server is dead. + */ + Signal<> onDie; + + /** + * Signal: onInvite + * ------------------------------------------------ + * + * 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: 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: 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; + + /** + * 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: onMe + * ------------------------------------------------ + * + * 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: onMode + * ------------------------------------------------ + * + * Triggered when the server changed your user mode. + * + * Arguments: + * - the origin + * - the mode (e.g +i) + */ + Signal<std::string, std::string> 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: 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: onNotice + * ------------------------------------------------ + * + * Triggered when someone has sent a notice to you. + * + * Arguments: + * - the origin + * - the notice message + */ + Signal<std::string, std::string> 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: onQuery + * ------------------------------------------------ + * + * Triggered when someone has sent you a private message. + * + * Arguments: + * - the origin + * - the message + */ + Signal<std::string, std::string> 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: onWhois + * ------------------------------------------------ + * + * Triggered when whois information has been received. + * + * Arguments: + * - the whois object + */ + Signal<ServerWhois> onWhois; + +private: + using SessionPtr = std::unique_ptr<Session>; + using Queue = std::queue<ServerCommand>; + + /** + * List of NAMES being built. + */ + using NamesMap = std::unordered_map<std::string, std::set<std::string>>; + + /** + * List of WHOIS being built. + */ + using WhoisMap = std::unordered_map<std::string, ServerWhois>; + +private: + ServerInfo m_info; + ServerSettings m_settings; + ServerIdentity m_identity; + SessionPtr m_session; + ServerState m_state; + ServerState m_next; + Queue m_queue; + + /* + * The names map is being built by a successive call to handleNumeric so we need to store a temporary + * map by channels to list of names. Then, when we receive the end of names listing, we remove the + * temporary set of names and calls the appropriate signal. + */ + NamesMap m_namesMap; + WhoisMap m_whoisMap; + + bool isSelf(const std::string &nick) const noexcept; + void extractPrefixes(const std::string &line); + std::string cleanPrefix(std::string nickname) const noexcept; + + inline std::string strify(const char *s) + { + return (s == nullptr) ? "" : std::string(s); + } + + void handleChannel(const char *, const char **) noexcept; + void handleChannelMode(const char *, const char **) noexcept; + void handleChannelNotice(const char *, const char **) noexcept; + void handleConnect(const char *, const char **) noexcept; + void handleCtcpAction(const char *, const char **) noexcept; + void handleInvite(const char *, const char **) noexcept; + void handleJoin(const char *, const char **) noexcept; + void handleKick(const char *, const char **) noexcept; + void handleMode(const char *, const char **) noexcept; + void handleNick(const char *, const char **) noexcept; + void handleNotice(const char *, const char **) noexcept; + void handleNumeric(unsigned int, const char **, unsigned int) noexcept; + void handlePart(const char *, const char **) noexcept; + void handleQuery(const char *, const char **) noexcept; + void handleTopic(const char *, const char **) noexcept; + +public: + /** + * Split a channel from the form channel:password into a ServerChannel object. + * + * @param value the value + * @return a channel + */ + static ServerChannel splitChannel(const std::string &value); + + /** + * Construct a server. + * + * @param info the information + * @param identity the identity + * @param settings the settings + */ + Server(ServerInfo info, ServerIdentity identity = {}, ServerSettings settings = {}); + + /** + * Destructor. Close the connection if needed. + */ + virtual ~Server(); + + /** + * Set the next state to be used. This function is thread safe because + * the server manager may set the next state to the current state. + * + * If the server is installed into the ServerManager, it is called + * automatically. + * + * @param type the new state type + * @warning Not thread-safe + */ + inline void next(ServerState::Type type) + { + m_next = ServerState(type); + } + + /** + * Switch to next state if it has. + * + * If the server is installed into irccd, it is called automatically. + * + * @warning Not thread-safe + */ + void update() noexcept; + + /** + * Request to disconnect. This function does not notify the + * ServerService. + * + * @see Irccd::serverDisconnect + * @note Thread-safe + */ + void disconnect() noexcept; + + /** + * Asks for a reconnection. This function does not notify the + * ServerService. + * + * @see Irccd::serverReconnect + * @note Thread-safe + */ + void reconnect() noexcept; + + /** + * Flush the pending commands if possible. This function will send + * as much as possible commands. + * + * If the server is installed into the ServerManager, it is called + * automatically. + * + * @note Thread-safe + */ + void flush() noexcept; + + /** + * Prepare the IRC Session to the socket. + * + * If the server is installed into the ServerManager, it is called + * automatically. + * + * @warning Not thread-safe + */ + inline void prepare(fd_set &setinput, fd_set &setoutput, net::Handle &maxfd) noexcept + { + m_state.prepare(*this, setinput, setoutput, maxfd); + } + + /** + * Process incoming/outgoing data after selection. + * + * If the server is installed into the ServerManager, it is called + * automatically. + * + * @param setinput + * @param setoutput + * @throw any exception that have been throw from user functions + */ + void sync(fd_set &setinput, fd_set &setoutput) noexcept; + + /** + * Get the server information. + * + * @warning This overload should not be used by the user, it is required to + * update the nickname. + * @return the server information + */ + inline ServerInfo &info() noexcept + { + return m_info; + } + + /** + * Get the server information. + * + * @return the server information + */ + inline const ServerInfo &info() const noexcept + { + return m_info; + } + + /** + * Get the server settings. + * + * @warning This overload should not be used by the user, it is required to + * update the reconnection information. + * @return the settings + */ + inline ServerSettings &settings() noexcept + { + return m_settings; + } + + /** + * Get the server settings. + * + * @return the settings + */ + inline const ServerSettings &settings() const noexcept + { + return m_settings; + } + + /** + * Get the identity. + * + * @return the identity + */ + inline ServerIdentity &identity() noexcept + { + return m_identity; + } + + /** + * Overloaded function + * + * @return the identity + */ + inline const ServerIdentity &identity() const noexcept + { + return m_identity; + } + + /** + * Get the current state identifier. Should not be used by user code. + * + * @note Thread-safe but the state may change just after the call + */ + inline ServerState::Type type() const noexcept + { + return m_state.type(); + } + + /** + * Get the private session. + * + * @return the session + */ + inline Session &session() noexcept + { + return *m_session; + } + + /** + * Change the channel mode. + * + * @param channel the channel + * @param mode the new mode + * @note Thread-safe + */ + void cmode(std::string channel, std::string mode); + + /** + * Send a channel notice. + * + * @param channel the channel + * @param message message notice + * @note Thread-safe + */ + void cnotice(std::string channel, std::string message) noexcept; + + /** + * Invite a user to a channel. + * + * @param target the target nickname + * @param channel the channel + * @note Thread-safe + */ + void invite(std::string target, std::string channel) noexcept; + + /** + * Join a channel, the password is optional and can be kept empty. + * + * @param channel the channel to join + * @param password the optional password + * @note Thread-safe + */ + void join(std::string channel, std::string password = "") noexcept; + + /** + * Kick someone from the channel. Please be sure to have the rights + * on that channel because errors won't be reported. + * + * @param target the target to kick + * @param channel from which channel + * @param reason the optional reason + * @note Thread-safe + */ + void kick(std::string target, std::string channel, std::string reason = "") noexcept; + + /** + * Send a CTCP Action as known as /me. The target may be either a + * channel or a nickname. + * + * @param target the nickname or the channel + * @param message the message + * @note Thread-safe + */ + void me(std::string target, std::string message); + + /** + * Send a message to the specified target or channel. + * + * @param target the target + * @param message the message + * @note Thread-safe + */ + void message(std::string target, std::string message); + + /** + * Change your user mode. + * + * @param mode the mode + * @note Thread-safe + */ + void mode(std::string mode); + + /** + * Request the list of names. + * + * @param channel the channel + * @note Thread-safe + */ + void names(std::string channel); + + /** + * Change your nickname. + * + * @param newnick the new nickname to use + * @note Thread-safe + */ + void nick(std::string newnick); + + /** + * Send a private notice. + * + * @param target the target + * @param message the notice message + * @note Thread-safe + */ + void notice(std::string target, std::string message); + + /** + * Part from a channel. + * + * Please note that the reason is not supported on all servers so if you want portability, don't provide it. + * + * @param channel the channel to leave + * @param reason the optional reason + * @note Thread-safe + */ + void part(std::string channel, std::string reason = ""); + + /** + * Send a raw message to the IRC server. You don't need to add + * message terminators. + * + * @warning Use this function with care + * @param raw the raw message (without `\r\n\r\n`) + * @note Thread-safe + */ + void send(std::string raw); + + /** + * Change the channel topic. + * + * @param channel the channel + * @param topic the desired topic + * @note Thread-safe + */ + void topic(std::string channel, std::string topic); + + /** + * Request for whois information. + * + * @param target the target nickname + * @note Thread-safe + */ + void whois(std::string target); +}; + +} // !irccd + +#endif // !IRCCD_SERVER_HPP
--- a/lib/irccd/signals.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -/* - * signals.h -- synchronous observer mechanism - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_SIGNALS_H -#define IRCCD_SIGNALS_H - -#include <functional> -#include <stack> -#include <unordered_map> -#include <vector> - -/** - * @file signals.h - * @brief Similar Qt signal subsystem for irccd - */ - -namespace irccd { - -/** - * @class SignalConnection - * @brief Stores the reference to the callable - * - * This class can be stored to remove a registered function from a Signal, be - * careful to not mix connections between different signals as they are just - * referenced by ids. - */ -class SignalConnection { -private: - unsigned m_id; - -public: - /** - * Create a signal connection. - * - * @param id the id - */ - inline SignalConnection(unsigned id) noexcept - : m_id(id) - { - } - - /** - * Get the reference object. - * - * @return the id - */ - inline unsigned id() const noexcept - { - return m_id; - } -}; - -/** - * @class Signal - * @brief Stores and call registered functions - * - * This class is intended to be use as a public field in the desired object. - * - * The user just have to call one of connect(), disconnect() or the call - * operator to use this class. - * - * It stores the callable as std::function so type-erasure is complete. - * - * The user is responsible of taking care that the object is still alive - * in case that the function takes a reference to the object. - */ -template <typename... Args> -class Signal { -private: - using Function = std::function<void (Args...)>; - using FunctionMap = std::unordered_map<unsigned, Function>; - using Stack = std::stack<unsigned>; - - FunctionMap m_functions; - Stack m_stack; - unsigned m_max{0}; - -public: - /** - * Register a new function to the signal. - * - * @param function the function - * @return the connection in case you want to remove it - */ - inline SignalConnection connect(Function function) noexcept - { - unsigned id; - - if (!m_stack.empty()) { - id = m_stack.top(); - m_stack.pop(); - } else { - id = m_max ++; - } - - m_functions.emplace(id, std::move(function)); - - return SignalConnection{id}; - } - - /** - * Disconnect a connection. - * - * @param connection the connection - * @warning Be sure that the connection belongs to that signal - */ - inline void disconnect(const SignalConnection &connection) noexcept - { - auto value = m_functions.find(connection.id()); - - if (value != m_functions.end()) { - m_functions.erase(connection.id()); - m_stack.push(connection.id()); - } - } - - /** - * Remove all registered functions. - */ - inline void clear() - { - m_functions.clear(); - m_max = 0; - - while (!m_stack.empty()) - m_stack.pop(); - } - - /** - * Call every functions. - * - * @param args the arguments to pass to the signal - */ - void operator()(Args... args) const - { - /* - * Make a copy of the ids before iterating because the callbacks may eventually remove or modify - * the list. - */ - std::vector<unsigned> ids; - - for (auto &pair : m_functions) - ids.push_back(pair.first); - - /* - * Now iterate while checking if the next id is still available, however if any new signals were - * added while iterating, they will not be called immediately. - */ - for (unsigned i : ids) { - auto it = m_functions.find(i); - - if (it != m_functions.end()) - it->second(args...); - } - } -}; - -} // !irccd - -#endif // !IRCCD_SIGNALS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/signals.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,175 @@ +/* + * signals.h -- synchronous observer mechanism + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SIGNALS_H +#define IRCCD_SIGNALS_H + +#include <functional> +#include <stack> +#include <unordered_map> +#include <vector> + +/** + * @file signals.h + * @brief Similar Qt signal subsystem for irccd + */ + +namespace irccd { + +/** + * @class SignalConnection + * @brief Stores the reference to the callable + * + * This class can be stored to remove a registered function from a Signal, be + * careful to not mix connections between different signals as they are just + * referenced by ids. + */ +class SignalConnection { +private: + unsigned m_id; + +public: + /** + * Create a signal connection. + * + * @param id the id + */ + inline SignalConnection(unsigned id) noexcept + : m_id(id) + { + } + + /** + * Get the reference object. + * + * @return the id + */ + inline unsigned id() const noexcept + { + return m_id; + } +}; + +/** + * @class Signal + * @brief Stores and call registered functions + * + * This class is intended to be use as a public field in the desired object. + * + * The user just have to call one of connect(), disconnect() or the call + * operator to use this class. + * + * It stores the callable as std::function so type-erasure is complete. + * + * The user is responsible of taking care that the object is still alive + * in case that the function takes a reference to the object. + */ +template <typename... Args> +class Signal { +private: + using Function = std::function<void (Args...)>; + using FunctionMap = std::unordered_map<unsigned, Function>; + using Stack = std::stack<unsigned>; + + FunctionMap m_functions; + Stack m_stack; + unsigned m_max{0}; + +public: + /** + * Register a new function to the signal. + * + * @param function the function + * @return the connection in case you want to remove it + */ + inline SignalConnection connect(Function function) noexcept + { + unsigned id; + + if (!m_stack.empty()) { + id = m_stack.top(); + m_stack.pop(); + } else { + id = m_max ++; + } + + m_functions.emplace(id, std::move(function)); + + return SignalConnection{id}; + } + + /** + * Disconnect a connection. + * + * @param connection the connection + * @warning Be sure that the connection belongs to that signal + */ + inline void disconnect(const SignalConnection &connection) noexcept + { + auto value = m_functions.find(connection.id()); + + if (value != m_functions.end()) { + m_functions.erase(connection.id()); + m_stack.push(connection.id()); + } + } + + /** + * Remove all registered functions. + */ + inline void clear() + { + m_functions.clear(); + m_max = 0; + + while (!m_stack.empty()) + m_stack.pop(); + } + + /** + * Call every functions. + * + * @param args the arguments to pass to the signal + */ + void operator()(Args... args) const + { + /* + * Make a copy of the ids before iterating because the callbacks may eventually remove or modify + * the list. + */ + std::vector<unsigned> ids; + + for (auto &pair : m_functions) + ids.push_back(pair.first); + + /* + * Now iterate while checking if the next id is still available, however if any new signals were + * added while iterating, they will not be called immediately. + */ + for (unsigned i : ids) { + auto it = m_functions.find(i); + + if (it != m_functions.end()) + it->second(args...); + } + } +}; + +} // !irccd + +#endif // !IRCCD_SIGNALS_H
--- a/lib/irccd/sockets.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/sockets.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -23,7 +23,7 @@ #include <cstring> #include <mutex> -#include "sockets.h" +#include "sockets.hpp" namespace irccd {
--- a/lib/irccd/sockets.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4078 +0,0 @@ -/* - * sockets.h -- portable C++ socket wrappers - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_SOCKETS_H -#define IRCCD_SOCKETS_H - -/** - * @file sockets.h - * @brief Portable socket abstraction - * - * # Introduction - * - * This file is a portable networking library. - * - * ## Options - * - * The user may set the following variables before compiling these files: - * - * ### General options - * - * - **SOCKET_NO_AUTO_INIT**: (bool) Set to 0 if you don't want Socket class to - * automatically calls net::init function and net::finish functions. - * - **SOCKET_NO_SSL**: (bool) Set to 0 if you don't have access to OpenSSL library. - * - **SOCKET_NO_AUTO_SSL_INIT**: (bool) Set to 0 if you don't want Socket class with Tls to automatically init - * the OpenSSL library. You will need to call net::ssl::init and net::ssl::finish. - * - * ### Options for Listener class - * - * Feature detection, multiple implementations may be avaible, for example, Linux has poll, select and epoll. - * - * We assume that `select(2)` is always available. - * - * Of course, you can set the variables yourself if you test it with your build system. - * - * - **SOCKET_HAVE_POLL**: Defined on all BSD, Linux. Also defined on Windows - * if _WIN32_WINNT is set to 0x0600 or greater. - * - **SOCKET_HAVE_KQUEUE**: Defined on all BSD and Apple. - * - **SOCKET_HAVE_EPOLL**: Defined on Linux only. - * - **SOCKET_DEFAULT_BACKEND**: Which backend to use (e.g. `Select`). - * - * The preference priority is ordered from left to right. - * - * | System | Backend | Class name | - * |---------------|-------------------------|--------------| - * | Linux | epoll(7) | Epoll | - * | *BSD | kqueue(2) | Kqueue | - * | Windows | poll(2), select(2) | Poll, Select | - * | Mac OS X | kqueue(2) | Kqueue | - */ - -#if defined(_WIN32) -# if _WIN32_WINNT >= 0x0600 && !defined(SOCKET_HAVE_POLL) -# define SOCKET_HAVE_POLL -# endif -#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) -# if !defined(SOCKET_HAVE_KQUEUE) -# define SOCKET_HAVE_KQUEUE -# endif -# if !defined(SOCKET_HAVE_POLL) -# define SOCKET_HAVE_POLL -# endif -#elif defined(__linux__) -# if !defined(SOCKET_HAVE_EPOLL) -# define SOCKET_HAVE_EPOLL -# endif -# if !defined(SOCKET_HAVE_POLL) -# define SOCKET_HAVE_POLL -# endif -#endif - -/* - * Define SOCKET_DEFAULT_BACKEND - * ------------------------------------------------------------------ - */ - -/** - * Defines the default Listener backend to use. - * - * @note Do not rely on the value shown in doxygen. - */ -#if defined(_WIN32) -# if !defined(SOCKET_DEFAULT_BACKEND) -# if defined(SOCKET_HAVE_POLL) -# define SOCKET_DEFAULT_BACKEND Poll -# else -# define SOCKET_DEFAULT_BACKEND Select -# endif -# endif -#elif defined(__linux__) -# include <sys/epoll.h> - -# if !defined(SOCKET_DEFAULT_BACKEND) -# define SOCKET_DEFAULT_BACKEND Epoll -# endif -#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) -# include <sys/types.h> -# include <sys/event.h> -# include <sys/time.h> - -# if !defined(SOCKET_DEFAULT_BACKEND) -# define SOCKET_DEFAULT_BACKEND Kqueue -# endif -#else -# if !defined(SOCKET_DEFAULT_BACKEND) -# define SOCKET_DEFAULT_BACKEND Select -# endif -#endif - -#if defined(SOCKET_HAVE_POLL) && !defined(_WIN32) -# include <poll.h> -#endif - -/* - * Headers to include - * ------------------------------------------------------------------ - */ - -#if defined(_WIN32) -# include <cstdlib> - -# include <WinSock2.h> -# include <WS2tcpip.h> -#else -# include <cerrno> - -# include <sys/ioctl.h> -# include <sys/types.h> -# include <sys/socket.h> -# include <sys/un.h> - -# include <arpa/inet.h> - -# include <netinet/in.h> -# include <netinet/tcp.h> - -# include <fcntl.h> -# include <netdb.h> -# include <unistd.h> -#endif - -#if !defined(SOCKET_NO_SSL) -# include <openssl/err.h> -# include <openssl/evp.h> -# include <openssl/ssl.h> -#endif - -#include <cassert> -#include <chrono> -#include <cstdlib> -#include <cstring> -#include <exception> -#include <functional> -#include <map> -#include <memory> -#include <string> -#include <vector> - -namespace irccd { - -/** - * General network namespace. - */ -namespace net { - -/* - * Portables types - * ------------------------------------------------------------------ - * - * The following types are defined differently between Unix and Windows. - */ - -/* {{{ Protocols */ - -#if defined(_WIN32) - -/** - * Socket type, SOCKET. - */ -using Handle = SOCKET; - -/** - * Argument to pass to set. - */ -using ConstArg = const char *; - -/** - * Argument to pass to get. - */ -using Arg = char *; - -#else - -/** - * Socket type, int. - */ -using Handle = int; - -/** - * Argument to pass to set. - */ -using ConstArg = const void *; - -/** - * Argument to pass to get. - */ -using Arg = void *; - -#endif - -/* }}} */ - -/* - * Portable constants - * ------------------------------------------------------------------ - * - * These constants are needed to check functions return codes, they are rarely needed in end user code. - */ - -/* {{{ Constants */ - -/* - * The following constants are defined differently from Unix - * to Windows. - */ -#if defined(_WIN32) - -/** - * Socket creation failure or invalidation. - */ -extern const Handle Invalid; - -/** - * Socket operation failure. - */ -extern const int Failure; - -#else - -/** - * Socket creation failure or invalidation. - */ -extern const int Invalid; - -/** - * Socket operation failure. - */ -extern const int Failure; - -#endif - -#if !defined(SOCKET_NO_SSL) - -namespace ssl { - -/** - * @enum Method - * @brief Which OpenSSL method to use. - */ -enum Method { - Tlsv1, //!< TLS v1.2 (recommended) - Sslv3 //!< SSLv3 -}; - -} // !ssl - -#endif - -/* }}} */ - -/* - * Portable functions - * ------------------------------------------------------------------ - * - * The following free functions can be used to initialize the library or to get the last system error. - */ - -/* {{{ Functions */ - -/** - * Initialize the socket library. Except if you defined SOCKET_NO_AUTO_INIT, you don't need to call this - * function manually. - */ -void init() noexcept; - -/** - * Close the socket library. - */ -void finish() noexcept; - -#if !defined(SOCKET_NO_SSL) - -/** - * OpenSSL namespace. - */ -namespace ssl { - -/** - * Initialize the OpenSSL library. Except if you defined SOCKET_NO_AUTO_SSL_INIT, you don't need to call this function - * manually. - */ -void init() noexcept; - -/** - * Close the OpenSSL library. - */ -void finish() noexcept; - -} // !ssl - -#endif // SOCKET_NO_SSL - -/** - * Get the last socket system error. The error is set from errno or from - * WSAGetLastError on Windows. - * - * @return a string message - */ -std::string error(); - -/** - * Get the last system error. - * - * @param errn the error number (errno or WSAGetLastError) - * @return the error - */ -std::string error(int errn); - -/* }}} */ - -/* - * Error class - * ------------------------------------------------------------------ - * - * This is the main exception thrown on socket operations. - */ - -/* {{{ Error */ - -/** - * @class Error - * @brief Base class for sockets error - */ -class Error : public std::exception { -public: - /** - * @enum Code - * @brief Which kind of error - */ - enum Code { - Timeout, ///!< The action did timeout - System, ///!< There is a system error - Other ///!< Other custom error - }; - -private: - Code m_code; - std::string m_function; - std::string m_error; - -public: - /** - * Constructor that use the last system error. - * - * @param code which kind of error - * @param function the function name - */ - Error(Code code, std::string function); - - /** - * Constructor that use the system error set by the user. - * - * @param code which kind of error - * @param function the function name - * @param error the error - */ - Error(Code code, std::string function, int error); - - /** - * Constructor that set the error specified by the user. - * - * @param code which kind of error - * @param function the function name - * @param error the error - */ - Error(Code code, std::string function, std::string error); - - /** - * Get which function has triggered the error. - * - * @return the function name (e.g connect) - */ - inline const std::string &function() const noexcept - { - return m_function; - } - - /** - * The error code. - * - * @return the code - */ - inline Code code() const noexcept - { - return m_code; - } - - /** - * Get the error (only the error content). - * - * @return the error - */ - const char *what() const noexcept - { - return m_error.c_str(); - } -}; - -/* }}} */ - -/* - * State class - * ------------------------------------------------------------------ - * - * To facilitate higher-level stuff, the socket has a state. - */ - -/* {{{ State */ - -/** - * @enum State - * @brief Current socket state. - */ -enum class State { - Open, //!< Socket is open - Bound, //!< Socket is bound to an address - Connecting, //!< The connection is in progress - Connected, //!< Connection is complete - Accepted, //!< Socket has been accepted (client) - Accepting, //!< The client acceptation is in progress - Closed, //!< The socket has been closed - Disconnected, //!< The connection was lost -}; - -/* }}} */ - -/* - * Action enum - * ------------------------------------------------------------------ - * - * Defines the pending operation. - */ - -/* {{{ Action */ - -/** - * @enum Action - * @brief Define the current operation that must complete. - * - * Some operations like accept, connect, recv or send must sometimes do several round-trips to complete and the socket - * action is set with that enumeration. The user is responsible of calling accept, connect send or recv until the - * operation is complete. - * - * Note: the user must wait for the appropriate condition in Socket::condition to check if the required condition is - * met. - * - * It is important to complete the operation in the correct order because protocols like Tls may require to continue - * re-negociating when calling Socket::send or Socket::Recv. - */ -enum class Action { - None, //!< No action is required, socket is ready - Accept, //!< The socket is not yet accepted, caller must call accept() again - Connect, //!< The socket is not yet connected, caller must call connect() again - Receive, //!< The received operation has not succeeded yet, caller must call recv() or recvfrom() again - Send //!< The send operation has not succeded yet, caller must call send() or sendto() again -}; - -/* }}} */ - -/* - * Condition enum - * ------------------------------------------------------------------ - * - * Defines if we must wait for reading or writing. - */ - -/* {{{ Condition */ - -/** - * @enum Condition - * @brief Define the required condition for the socket. - * - * As explained in Action enumeration, some operations required to be called several times, before calling these - * operations, the user must wait the socket to be readable or writable. This can be checked with Socket::condition. - */ -enum class Condition { - None, //!< No condition is required - Readable = (1 << 0), //!< The socket must be readable - Writable = (1 << 1) //!< The socket must be writable -}; - -/** - * Apply bitwise XOR. - * - * @param v1 the first value - * @param v2 the second value - * @return the new value - */ -constexpr Condition operator^(Condition v1, Condition v2) noexcept -{ - return static_cast<Condition>(static_cast<int>(v1) ^ static_cast<int>(v2)); -} - -/** - * Apply bitwise AND. - * - * @param v1 the first value - * @param v2 the second value - * @return the new value - */ -constexpr Condition operator&(Condition v1, Condition v2) noexcept -{ - return static_cast<Condition>(static_cast<int>(v1) & static_cast<int>(v2)); -} - -/** - * Apply bitwise OR. - * - * @param v1 the first value - * @param v2 the second value - * @return the new value - */ -constexpr Condition operator|(Condition v1, Condition v2) noexcept -{ - return static_cast<Condition>(static_cast<int>(v1) | static_cast<int>(v2)); -} - -/** - * Apply bitwise NOT. - * - * @param v the value - * @return the complement - */ -constexpr Condition operator~(Condition v) noexcept -{ - return static_cast<Condition>(~static_cast<int>(v)); -} - -/** - * Assign bitwise OR. - * - * @param v1 the first value - * @param v2 the second value - * @return the new value - */ -inline Condition &operator|=(Condition &v1, Condition v2) noexcept -{ - v1 = static_cast<Condition>(static_cast<int>(v1) | static_cast<int>(v2)); - - return v1; -} - -/** - * Assign bitwise AND. - * - * @param v1 the first value - * @param v2 the second value - * @return the new value - */ -inline Condition &operator&=(Condition &v1, Condition v2) noexcept -{ - v1 = static_cast<Condition>(static_cast<int>(v1) & static_cast<int>(v2)); - - return v1; -} - -/** - * Assign bitwise XOR. - * - * @param v1 the first value - * @param v2 the second value - * @return the new value - */ -inline Condition &operator^=(Condition &v1, Condition v2) noexcept -{ - v1 = static_cast<Condition>(static_cast<int>(v1) ^ static_cast<int>(v2)); - - return v1; -} - -/* }}} */ - -/* - * Base Socket class - * ------------------------------------------------------------------ - * - * This base class has operations that are common to all types of sockets but you usually instanciate - * a SocketTcp or SocketUdp - */ - -/* {{{ Socket */ - -/** - * @class Socket - * @brief Base socket class for socket operations. - * - * **Important:** When using non-blocking sockets, some considerations must be taken. See the implementation of the - * underlying protocol for more details. - * - * @see protocol::Tls - * @see protocol::Tcp - * @see protocol::Udp - */ -template <typename Address, typename Protocol> -class Socket { -private: - Protocol m_proto; - State m_state{State::Closed}; - Action m_action{Action::None}; - Condition m_condition{Condition::None}; - -protected: - /** - * The native handle. - */ - Handle m_handle{Invalid}; - -public: - /** - * Create a socket handle. - * - * This is the primary function and the only one that creates the socket handle, all other constructors - * are just overloaded functions. - * - * @param domain the domain AF_* - * @param type the type SOCK_* - * @param protocol the protocol - * @param iface the implementation - * @throw net::Error on errors - * @post state is set to Open - * @post handle is not set to Invalid - */ - Socket(int domain, int type, int protocol, Protocol iface = {}) - : m_proto(std::move(iface)) - { -#if !defined(SOCKET_NO_AUTO_INIT) - init(); -#endif - m_handle = ::socket(domain, type, protocol); - - if (m_handle == Invalid) { - throw Error{Error::System, "socket"}; - } - - m_proto.create(*this); - m_state = State::Open; - - assert(m_handle != Invalid); - } - - /** - * This tries to create a socket. - * - * Domain and type are determined by the Address and Protocol object. - * - * @param protocol the protocol - * @param address which type of address - * @throw net::Error on errors - */ - explicit inline Socket(Protocol protocol = {}, const Address &address = {}) - : Socket{address.domain(), protocol.type(), 0, std::move(protocol)} - { - } - - /** - * Construct a socket with an already created descriptor. - * - * @param handle the native descriptor - * @param state specify the socket state - * @param protocol the type of socket implementation - * @post action is set to None - * @post condition is set to None - */ - explicit inline Socket(Handle handle, State state = State::Closed, Protocol protocol = {}) noexcept - : m_proto(std::move(protocol)) - , m_state{state} - , m_handle{handle} - { - assert(m_action == Action::None); - assert(m_condition == Condition::None); - } - - /** - * Create an invalid socket. Can be used when you cannot instanciate the socket immediately. - */ - explicit inline Socket(std::nullptr_t) noexcept - : m_handle{Invalid} - { - } - - /** - * Copy constructor deleted. - */ - Socket(const Socket &) = delete; - - /** - * Transfer ownership from other to this. - * - * @param other the other socket - */ - inline Socket(Socket &&other) noexcept - : m_proto(std::move(other.m_proto)) - , m_state{other.m_state} - , m_action{other.m_action} - , m_condition{other.m_condition} - , m_handle{other.m_handle} - { - /* Invalidate other */ - other.m_handle = Invalid; - other.m_state = State::Closed; - other.m_action = Action::None; - other.m_condition = Condition::None; - } - - /** - * Default destructor. - */ - virtual ~Socket() - { - close(); - } - - /** - * Access the implementation. - * - * @return the implementation - * @warning use this function with care - */ - inline const Protocol &protocol() const noexcept - { - return m_proto; - } - - /** - * Overloaded function. - * - * @return the implementation - */ - inline Protocol &protocol() noexcept - { - return m_proto; - } - - /** - * Get the current socket state. - * - * @return the state - */ - inline State state() const noexcept - { - return m_state; - } - - /** - * Change the current socket state. - * - * @param state the new state - * @warning only implementations should call this function - */ - inline void setState(State state) noexcept - { - m_state = state; - } - - /** - * Get the pending operation. - * - * @return the action to complete before continuing - * @note usually only needed in non-blocking sockets - */ - inline Action action() const noexcept - { - return m_action; - } - - /** - * Change the pending operation. - * - * @param action the action - * @warning you should not call this function yourself - */ - inline void setAction(Action action) noexcept - { - m_action = action; - } - - /** - * Get the condition to wait for. - * - * @return the condition - */ - inline Condition condition() const noexcept - { - return m_condition; - } - - /** - * Change the condition required. - * - * @param condition the condition - * @warning you should not call this function yourself - */ - inline void setCondition(Condition condition) noexcept - { - m_condition = condition; - } - - /** - * Set an option for the socket. Wrapper of setsockopt(2). - * - * @param level the setting level - * @param name the name - * @param arg the value - * @throw net::Error on errors - */ - template <typename Argument> - void set(int level, int name, const Argument &arg) - { - if (setsockopt(m_handle, level, name, (ConstArg)&arg, sizeof (arg)) == Failure) { - throw Error{Error::System, "set"}; - } - } - - /** - * Object-oriented option setter. - * - * The object must have `set(Socket<Address, Protocol> &) const`. - * - * @param option the option - * @throw net::Error on errors - */ - template <typename Option> - inline void set(const Option &option) - { - option.set(*this); - } - - /** - * Get an option for the socket. Wrapper of getsockopt(2). - * - * @param level the setting level - * @param name the name - * @throw net::Error on errors - */ - template <typename Argument> - Argument get(int level, int name) - { - Argument desired, result{}; - socklen_t size = sizeof (result); - - if (getsockopt(m_handle, level, name, (Arg)&desired, &size) == Failure) { - throw Error{Error::System, "get"}; - } - - std::memcpy(&result, &desired, size); - - return result; - } - - /** - * Object-oriented option getter. - * - * The object must have `T get(Socket<Address, Protocol> &) const`, T can be any type and it is the value - * returned from this function. - * - * @return the same value as get() in the option - * @throw net::Error on errors - */ - template <typename Option> - inline auto get() -> decltype(std::declval<Option>().get(*this)) - { - return Option{}.get(*this); - } - - /** - * Get the native handle. - * - * @return the handle - * @warning Not portable - */ - inline Handle handle() const noexcept - { - return m_handle; - } - - /** - * Bind using a native address. - * - * @param address the address - * @param length the size - * @pre state must not be Bound - * @throw net::Error on errors - */ - void bind(const sockaddr *address, socklen_t length) - { - assert(m_state != State::Bound); - - if (::bind(m_handle, address, length) == Failure) { - throw Error{Error::System, "bind"}; - } - - m_state = State::Bound; - } - - /** - * Overload that takes an address. - * - * @param address the address - * @throw net::Error on errors - */ - inline void bind(const Address &address) - { - bind(address.address(), address.length()); - } - - /** - * Listen for pending connection. - * - * @param max the maximum number - * @pre state must be Bound - * @throw net::Error on errors - */ - inline void listen(int max = 128) - { - assert(m_state == State::Bound); - - if (::listen(this->m_handle, max) == Failure) { - throw Error{Error::System, "listen"}; - } - } - - /** - * Connect to the address. - * - * If connection cannot be established immediately, connect with no argument must be called again. See - * the underlying protocol for more information. - * - * @pre state must be State::Open - * @param address the address - * @param length the the address length - * @throw net::Error on errors - * @post state is set to State::Connecting or State::Connected - * @note For non-blocking sockets, see the underlying protocol function for more details - */ - void connect(const sockaddr *address, socklen_t length) - { - assert(m_state == State::Open); - - m_action = Action::None; - m_condition = Condition::None; - - m_proto.connect(*this, address, length); - - assert((m_state == State::Connected && m_action == Action::None && m_condition == Condition::None) || - (m_state == State::Connecting && m_action == Action::Connect && m_condition != Condition::None)); - } - - /** - * Overloaded function. - * - * Effectively call connect(address.address(), address.length()); - * - * @param address the address - */ - inline void connect(const Address &address) - { - connect(address.address(), address.length()); - } - - /** - * Continue the connection, only required with non-blocking sockets. - * - * @pre state must be State::Connecting - * @throw net::Error on errors - */ - void connect() - { - assert(m_state == State::Connecting); - - m_action = Action::None; - m_condition = Condition::None; - - m_proto.connect(*this); - - assert((m_state == State::Connected && m_action == Action::None && m_condition == Condition::None) || - (m_state == State::Connecting && m_action == Action::Connect && m_condition != Condition::None)); - } - - /** - * Accept a new client. If there are no pending connection, throws an error. - * - * If the client cannot be accepted immediately, the client is returned and accept with no arguments - * must be called on it. See the underlying protocol for more information. - * - * @pre state must be State::Bound - * @param info the address where to store client's information (optional) - * @return the new socket - * @throw Error on errors - * @post returned client's state is set to State::Accepting or State::Accepted - * @note For non-blocking sockets, see the underlying protocol function for more details - */ - Socket<Address, Protocol> accept(Address *info) - { - assert(m_state == State::Bound); - - m_action = Action::None; - m_condition = Condition::None; - - sockaddr_storage storage; - socklen_t length = sizeof (storage); - - Socket<Address, Protocol> sc = m_proto.accept(*this, reinterpret_cast<sockaddr *>(&storage), &length); - - if (info) { - *info = Address{&storage, length}; - } - - /* Master do not change */ - assert(m_state == State::Bound); - assert(m_action == Action::None); - assert(m_condition == Condition::None); - - /* Client */ - assert( - (sc.state() == State::Accepting && sc.action() == Action::Accept && sc.condition() != Condition::None) || - (sc.state() == State::Accepted && sc.action() == Action::None && sc.condition() == Condition::None) - ); - - return sc; - } - - /** - * Continue the accept process on this client. This function must be called only when the socket is - * ready to be readable or writable! (see condition). - * - * @pre state must be State::Accepting - * @throw Error on errors - * @post if connection is complete, state is changed to State::Accepted, action and condition are unset - * @post if connection is still in progress, condition is set - */ - void accept() - { - assert(m_state == State::Accepting); - - m_action = Action::None; - m_condition = Condition::None; - - m_proto.accept(*this); - - assert( - (m_state == State::Accepting && m_action == Action::Accept && m_condition != Condition::None) || - (m_state == State::Accepted && m_action == Action::None && m_condition == Condition::None) - ); - } - - /** - * Get the local name. This is a wrapper of getsockname(). - * - * @return the address - * @throw Error on failures - * @pre state() must not be State::Closed - */ - Address address() const - { - assert(m_state != State::Closed); - - sockaddr_storage ss; - socklen_t length = sizeof (sockaddr_storage); - - if (::getsockname(m_handle, (sockaddr *)&ss, &length) == Failure) { - throw Error{Error::System, "getsockname"}; - } - - return Address(&ss, length); - } - - /** - * Receive some data. - * - * If the operation cannot be complete immediately, 0 is returned and user must call the function - * again when ready. See the underlying protocol for more information. - * - * If action is set to Action::None and result is set to 0, disconnection occured. - * - * @param data the destination buffer - * @param length the buffer length - * @pre action must not be Action::Send - * @return the number of bytes received or 0 - * @throw Error on error - * @note For non-blocking sockets, see the underlying protocol function for more details - */ - unsigned recv(void *data, unsigned length) - { - assert(m_action != Action::Send); - - m_action = Action::None; - m_condition = Condition::None; - - unsigned nbread = m_proto.recv(*this, data, length); - - return nbread; - } - - /** - * Overloaded function. - * - * @param count the number of bytes to receive - * @return the string - * @throw Error on error - */ - inline std::string recv(unsigned count) - { - std::string result; - - result.resize(count); - auto n = recv(const_cast<char *>(result.data()), count); - result.resize(n); - - return result; - } - - /** - * Send some data. - * - * If the operation cannot be complete immediately, 0 is returned and user must call the function - * again when ready. See the underlying protocol for more information. - * - * @param data the data buffer - * @param length the buffer length - * @return the number of bytes sent or 0 - * @pre action() must not be Flag::Receive - * @throw Error on error - * @note For non-blocking sockets, see the underlying protocol function for more details - */ - unsigned send(const void *data, unsigned length) - { - assert(m_action != Action::Receive); - - m_action = Action::None; - m_condition = Condition::None; - - unsigned nbsent = m_proto.send(*this, data, length); - - assert((m_action == Action::None && m_condition == Condition::None) || - (m_action == Action::Send && m_condition != Condition::None)); - - return nbsent; - } - - /** - * Overloaded function. - * - * @param data the string to send - * @return the number of bytes sent - * @throw Error on error - */ - inline unsigned send(const std::string &data) - { - return send(data.c_str(), data.size()); - } - - /** - * Send data to an end point. - * - * If the operation cannot be complete immediately, 0 is returned and user must call the function - * again when ready. See the underlying protocol for more information. - * - * @param data the buffer - * @param length the buffer length - * @param address the client address - * @param addrlen the address length - * @return the number of bytes sent - * @throw net::Error on errors - * @note For non-blocking sockets, see the underlying protocol function for more details - */ - inline unsigned sendto(const void *data, unsigned length, const sockaddr *address, socklen_t addrlen) - { - return m_proto.sendto(*this, data, length, address, addrlen); - } - - /** - * Overloaded function. - * - * @param data the buffer - * @param length the buffer length - * @param address the destination - * @return the number of bytes sent - * @throw net::Error on errors - */ - inline unsigned sendto(const void *data, unsigned length, const Address &address) - { - return sendto(data, length, address.address(), address.length()); - } - - /** - * Overloaded function. - * - * @param data the data - * @param address the address - * @return the number of bytes sent - * @throw net:;Error on errors - */ - inline unsigned sendto(const std::string &data, const Address &address) - { - return sendto(data.c_str(), data.length(), address); - } - - /** - * Receive data from an end point. - * - * If the operation cannot be complete immediately, 0 is returned and user must call the function - * again when ready. See the underlying protocol for more information. - * - * @param data the destination buffer - * @param length the buffer length - * @param address the address destination - * @param addrlen the address length (in/out) - * @return the number of bytes received - * @throw net::Error on errors - * @note For non-blocking sockets, see the underlying protocol function for more details - */ - inline unsigned recvfrom(void *data, unsigned length, sockaddr *address, socklen_t *addrlen) - { - return m_proto.recvfrom(*this, data, length, address, addrlen); - } - - /** - * Overloaded function. - * - * @param data the destination buffer - * @param length the buffer length - * @param info the address destination - * @return the number of bytes received - * @throw net::Error on errors - */ - inline unsigned recvfrom(void *data, unsigned length, Address *info = nullptr) - { - sockaddr_storage storage; - socklen_t addrlen = sizeof (sockaddr_storage); - - auto n = recvfrom(data, length, reinterpret_cast<sockaddr *>(&storage), &addrlen); - - if (info && n != 0) { - *info = Address{&storage, addrlen}; - } - - return n; - } - - /** - * Overloaded function. - * - * @param count the maximum number of bytes to receive - * @param info the client information - * @return the string - * @throw net::Error on errors - */ - std::string recvfrom(unsigned count, Address *info = nullptr) - { - std::string result; - - result.resize(count); - auto n = recvfrom(const_cast<char *>(result.data()), count, info); - result.resize(n); - - return result; - } - - /** - * Close the socket. - * - * Automatically called from the destructor. - */ - void close() - { - if (m_handle != Invalid) { -#if defined(_WIN32) - ::closesocket(m_handle); -#else - ::close(m_handle); -#endif - m_handle = Invalid; - } - - m_state = State::Closed; - m_action = Action::None; - m_condition = Condition::None; - } - - /** - * Assignment operator forbidden. - * - * @return *this - */ - Socket &operator=(const Socket &) = delete; - - /** - * Transfer ownership from other to this. The other socket is left - * invalid and will not be closed. - * - * @param other the other socket - * @return this - */ - Socket &operator=(Socket &&other) noexcept - { - m_handle = other.m_handle; - m_proto = std::move(other.m_proto); - m_state = other.m_state; - m_action = other.m_action; - m_condition = other.m_condition; - - /* Invalidate other */ - other.m_handle = Invalid; - other.m_state = State::Closed; - other.m_action = Action::None; - other.m_condition = Condition::None; - - return *this; - } -}; - -/** - * Compare two sockets. - * - * @param s1 the first socket - * @param s2 the second socket - * @return true if they equals - */ -template <typename Address, typename Protocol> -bool operator==(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) -{ - return s1.handle() == s2.handle(); -} - -/** - * Compare two sockets. - * - * @param s1 the first socket - * @param s2 the second socket - * @return true if they are different - */ -template <typename Address, typename Protocol> -bool operator!=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) -{ - return s1.handle() != s2.handle(); -} - -/** - * Compare two sockets. - * - * @param s1 the first socket - * @param s2 the second socket - * @return true if s1 < s2 - */ -template <typename Address, typename Protocol> -bool operator<(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) -{ - return s1.handle() < s2.handle(); -} - -/** - * Compare two sockets. - * - * @param s1 the first socket - * @param s2 the second socket - * @return true if s1 > s2 - */ -template <typename Address, typename Protocol> -bool operator>(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) -{ - return s1.handle() > s2.handle(); -} - -/** - * Compare two sockets. - * - * @param s1 the first socket - * @param s2 the second socket - * @return true if s1 <= s2 - */ -template <typename Address, typename Protocol> -bool operator<=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) -{ - return s1.handle() <= s2.handle(); -} - -/** - * Compare two sockets. - * - * @param s1 the first socket - * @param s2 the second socket - * @return true if s1 >= s2 - */ -template <typename Address, typename Protocol> -bool operator>=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) -{ - return s1.handle() >= s2.handle(); -} - -/* }}} */ - -/* - * Predefined options - * ------------------------------------------------------------------ - */ - -/* {{{ Options */ - -/** - * Namespace of predefined options. - */ -namespace option { - -/* - * Options for socket - * ------------------------------------------------------------------ - */ - -/* {{{ Options for socket */ - -/** - * @class SockBlockMode - * @brief Set or get the blocking-mode for a socket. - * @warning On Windows, it's not possible to check if the socket is blocking or not. - */ -class SockBlockMode { -public: - /** - * Set to false if you want non-blocking socket. - */ - bool value{false}; - - /** - * Set the option. - * - * @param sc the socket - * @throw Error on errors - */ - template <typename Address, typename Protocol> - void set(Socket<Address, Protocol> &sc) const - { -#if defined(O_NONBLOCK) && !defined(_WIN32) - int flags; - - if ((flags = fcntl(sc.handle(), F_GETFL, 0)) < 0) { - flags = 0; - } - - if (value) { - flags &= ~(O_NONBLOCK); - } else { - flags |= O_NONBLOCK; - } - - if (fcntl(sc.handle(), F_SETFL, flags) < 0) { - throw Error{Error::System, "fcntl"}; - } -#else - unsigned long flags = (value) ? 0 : 1; - - if (ioctlsocket(sc.handle(), FIONBIO, &flags) == Failure) { - throw Error{Error::System, "fcntl"}; - } -#endif - } - - /** - * Get the option. - * - * @return the value - * @throw Error on errors - */ - template <typename Address, typename Protocol> - bool get(Socket<Address, Protocol> &sc) const - { -#if defined(O_NONBLOCK) && !defined(_WIN32) - int flags = fcntl(sc.handle(), F_GETFL, 0); - - if (flags < 0) { - throw Error{Error::System, "fcntl"}; - } - - return !(flags & O_NONBLOCK); -#else - throw Error{Error::Other, "get", "Windows API cannot let you get the blocking status of a socket"}; -#endif - } -}; - -/** - * @class SockReuseAddress - * @brief Reuse address, must be used before calling Socket::bind - */ -class SockReuseAddress { -public: - /** - * Set to true if you want to set the SOL_SOCKET/SO_REUSEADDR option. - */ - bool value{true}; - - /** - * Set the option. - * - * @param sc the socket - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const - { - sc.set(SOL_SOCKET, SO_REUSEADDR, value ? 1 : 0); - } - - /** - * Get the option. - * - * @return the value - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline bool get(Socket<Address, Protocol> &sc) const - { - return static_cast<bool>(sc.template get<int>(SOL_SOCKET, SO_REUSEADDR)); - } -}; - -/** - * @class SockSendBuffer - * @brief Set or get the output buffer. - */ -class SockSendBuffer { -public: - /** - * Set to the buffer size. - */ - int value{2048}; - - /** - * Set the option. - * - * @param sc the socket - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const - { - sc.set(SOL_SOCKET, SO_SNDBUF, value); - } - - /** - * Get the option. - * - * @return the value - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline int get(Socket<Address, Protocol> &sc) const - { - return sc.template get<int>(SOL_SOCKET, SO_SNDBUF); - } -}; - -/** - * @class SockReceiveBuffer - * @brief Set or get the input buffer. - */ -class SockReceiveBuffer { -public: - /** - * Set to the buffer size. - */ - int value{2048}; - - /** - * Set the option. - * - * @param sc the socket - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const - { - sc.set(SOL_SOCKET, SO_RCVBUF, value); - } - - /** - * Get the option. - * - * @return the value - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline int get(Socket<Address, Protocol> &sc) const - { - return sc.template get<int>(SOL_SOCKET, SO_RCVBUF); - } -}; - -/* }}} */ - -/** - * @class TcpNoDelay - * @brief Set this option if you want to disable nagle's algorithm. - */ -class TcpNoDelay { -public: - /** - * Set to true to set TCP_NODELAY option. - */ - bool value{true}; - - /** - * Set the option. - * - * @param sc the socket - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const - { - sc.set(IPPROTO_TCP, TCP_NODELAY, value ? 1 : 0); - } - - /** - * Get the option. - * - * @return the value - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline bool get(Socket<Address, Protocol> &sc) const - { - return static_cast<bool>(sc.template get<int>(IPPROTO_TCP, TCP_NODELAY)); - } -}; - -/** - * @class Ipv6Only - * @brief Control IPPROTO_IPV6/IPV6_V6ONLY - * - * Note: some systems may or not set this option by default so it's a good idea to set it in any case to either - * false or true if portability is a concern. - */ -class Ipv6Only { -public: - /** - * Set this to use only IPv6. - */ - bool value{true}; - - /** - * Set the option. - * - * @param sc the socket - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline void set(Socket<Address, Protocol> &sc) const - { - sc.set(IPPROTO_IPV6, IPV6_V6ONLY, value ? 1 : 0); - } - - /** - * Get the option. - * - * @return the value - * @throw Error on errors - */ - template <typename Address, typename Protocol> - inline bool get(Socket<Address, Protocol> &sc) const - { - return static_cast<bool>(sc.template get<int>(IPPROTO_IPV6, IPV6_V6ONLY)); - } -}; - -} // !option - -/* }}} */ - -/* - * Predefined addressed to be used - * ------------------------------------------------------------------ - * - * - Ip, - * - Local. - */ - -/* {{{ Addresses */ - -/** - * Set of predefined addresses. - */ -namespace address { - -/** - * @class Ip - * @brief Base class for IPv6 and IPv4, you can use it if you don't know in advance if you'll use IPv6 or IPv4. - */ -class Ip { -public: - /** - * @enum Type - * @brief Type of ip address. - */ - enum Type { - v4 = AF_INET, //!< AF_INET - v6 = AF_INET6 //!< AF_INET6 - }; - -private: - /* - * Default domain when using default constructors. - * - * Note: AF_INET or AF_INET6, not - */ - static int m_default; - - union { - sockaddr_in m_sin; - sockaddr_in6 m_sin6; - }; - - socklen_t m_length{0}; - int m_domain{AF_INET}; - -public: - /** - * Set the default domain to use when using default Ip constructor. By default, AF_INET is used. - * - * @pre domain must be Type::v4 or Type::v6 - */ - static inline void setDefault(Type domain) noexcept - { - assert(domain == Type::v4 || domain == Type::v6); - - m_default = static_cast<int>(domain); - } - - /** - * Construct using the default domain. - */ - inline Ip() noexcept - : Ip(static_cast<Type>(m_default)) - { - } - - /** - * Default initialize the Ip domain. - * - * @pre domain must be AF_INET or AF_INET6 only - * @param domain the domain (AF_INET or AF_INET6) - */ - Ip(Type domain) noexcept; - - /** - * Construct an address suitable for bind() or connect(). - * - * @pre domain must be Type::v4 or Type::v6 - * @param domain the domain (AF_INET or AF_INET6) - * @param host the host (* for any) - * @param port the port number - * @throw Error on errors - */ - Ip(const std::string &host, int port, Type domain = v4); - - /** - * Construct an address from a storage. - * - * @pre storage's domain must be AF_INET or AF_INET6 only - * @param ss the storage - * @param length the length - */ - Ip(const sockaddr_storage *ss, socklen_t length) noexcept; - - /** - * Get the domain (AF_INET or AF_INET6). - * - * @return the domain - */ - inline int domain() const noexcept - { - return m_domain; - } - - /** - * Return the underlying address, either sockaddr_in6 or sockaddr_in. - * - * @return the address - */ - inline const sockaddr *address() const noexcept - { - if (m_domain == AF_INET6) { - return reinterpret_cast<const sockaddr *>(&m_sin6); - } - - return reinterpret_cast<const sockaddr *>(&m_sin); - } - - /** - * Return the underlying address length. - * - * @return the length - */ - inline socklen_t length() const noexcept - { - return m_length; - } - - /** - * Get the port. - * - * @return the port - */ - inline int port() const noexcept - { - if (m_domain == AF_INET6) { - return ntohs(m_sin6.sin6_port); - } - - return ntohs(m_sin.sin_port); - } -}; - -#if !defined(_WIN32) - -/** - * @class Local - * @brief unix family sockets - * - * Create an address to a specific path. Only available on Unix. - */ -class Local { -private: - sockaddr_un m_sun; - std::string m_path; - -public: - /** - * Get the domain AF_LOCAL. - * - * @return AF_LOCAL - */ - inline int domain() const noexcept - { - return AF_LOCAL; - } - - /** - * Default constructor. - */ - Local() noexcept; - - /** - * Construct an address to a path. - * - * @param path the path - * @param rm remove the file before (default: false) - */ - Local(std::string path, bool rm = false) noexcept; - - /** - * Construct an unix address from a storage address. - * - * @pre storage's domain must be AF_LOCAL - * @param ss the storage - * @param length the length - */ - Local(const sockaddr_storage *ss, socklen_t length) noexcept; - - /** - * Get the sockaddr_un. - * - * @return the address - */ - inline const sockaddr *address() const noexcept - { - return reinterpret_cast<const sockaddr *>(&m_sun); - } - - /** - * Get the address length. - * - * @return the length - */ - inline socklen_t length() const noexcept - { -#if defined(SOCKET_HAVE_SUN_LEN) - return SUN_LEN(&m_sun); -#else - return sizeof (m_sun); -#endif - } -}; - -#endif // !_WIN32 - -} // !address - -/* }}} */ - -/* - * Predefined protocols - * ------------------------------------------------------------------ - * - * - Tcp, for standard stream connections, - * - Udp, for standard datagram connections, - * - Tls, for secure stream connections. - */ - -/* {{{ Protocols */ - -/** - * Set of predefined protocols. - */ -namespace protocol { - -/* {{{ Tcp */ - -/** - * @class Tcp - * @brief Clear TCP implementation. - * - * This is the basic TCP protocol that implements recv, send, connect and accept as wrappers of the usual - * C functions. - */ -class Tcp { -public: - /** - * Socket type. - * - * @return SOCK_STREAM - */ - inline int type() const noexcept - { - return SOCK_STREAM; - } - - /** - * Do nothing. - * - * This function is just present for compatibility, it should never be called. - */ - template <typename Address> - inline void create(Socket<Address, Tcp> &) const noexcept - { - /* No-op */ - } - - /** - * Standard connect. - * - * If the socket is marked non-blocking and the connection cannot be established immediately, then the - * following is true: - * - * - state is set to State::Connecting, - * - action is set to Action::Connect, - * - condition is set to Condition::Writable. - * - * Then the user must wait until the socket is writable and call connect() with 0 arguments. - * - * If the socket is blocking, this function blocks until the connection is complete or an error occurs, in - * that case state is either set to State::Connected or State::Disconnected but action and condition are - * not set. - * - * @param sc the socket - * @param address the address - * @param length the length - * @throw net::Error on errors - * @note Wrapper of connect(2) - */ - template <typename Address, typename Protocol> - void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length) - { - if (::connect(sc.handle(), address, length) == Failure) { - /* - * Determine if the error comes from a non-blocking connect that cannot be - * accomplished yet. - */ -#if defined(_WIN32) - int error = WSAGetLastError(); - - if (error == WSAEWOULDBLOCK) { - sc.setState(State::Connecting); - sc.setAction(Action::Connect); - sc.setCondition(Condition::Writable); - } else { - sc.setState(State::Disconnected); - throw Error{Error::System, "connect", error}; - } -#else - if (errno == EINPROGRESS) { - sc.setState(State::Connecting); - sc.setAction(Action::Connect); - sc.setCondition(Condition::Writable); - } else { - sc.setState(State::Disconnected); - throw Error{Error::System, "connect"}; - } -#endif - } else { - sc.setState(State::Connected); - } - } - - /** - * Continue the connection. This function must only be called when the socket is ready for writing, - * the user is responsible of waiting for that condition. - * - * This function check for SOL_SOCKET/SO_ERROR status. - * - * If the connection is complete, status is set to State::Connected, otherwise it is set to - * State::Disconnected. In both cases, action and condition are not set. - * - * @param sc the socket - * @throw net::Error on errors - */ - template <typename Address, typename Protocol> - void connect(Socket<Address, Protocol> &sc) - { - int error = sc.template get<int>(SOL_SOCKET, SO_ERROR); - - if (error == Failure) { - sc.setState(State::Disconnected); - throw Error{Error::System, "connect", error}; - } - - sc.setState(State::Connected); - } - - /** - * Accept a clear client. - * - * If the socket is marked non-blocking and there are no pending connection, this function throws an - * error. The user must wait that the socket is readable before calling this function. - * - * If the socket is blocking, this function blocks until a new client is connected or throws an error on - * errors. - * - * If the socket is correctly returned, its state is set to State::Accepted and its action and condition - * are not set. - * - * In any case, action and condition of this socket are not set. - * - * @param sc the socket - * @param address the address destination - * @param length the address length - * @return the socket - * @throw net::Error on errors - * @note Wrapper of accept(2) - */ - template <typename Address, typename Protocol> - Socket<Address, Protocol> accept(Socket<Address, Protocol> &sc, sockaddr *address, socklen_t *length) - { - Handle handle = ::accept(sc.handle(), address, length); - - if (handle == Invalid) { - throw Error{Error::System, "accept"}; - } - - return Socket<Address, Protocol>{handle, State::Accepted}; - } - - /** - * Continue accept. - * - * This function is just present for compatibility, it should never be called. - */ - template <typename Address, typename Protocol> - inline void accept(Socket<Address, Protocol> &) const noexcept - { - /* no-op */ - } - - /** - * Receive data. - * - * If the socket is marked non-blocking and no data is available, 0 is returned and condition is set to - * Condition::Readable. If 0 is returned and condition is not set, then the state is set to - * State::Disconnected. - * - * If the socket is blocking, this function blocks until some data is available or if an error occurs. - * - * In any case, action is never set. - * - * @param sc the socket - * @param data the destination - * @param length the destination length - * @return the number of bytes read - * @throw Error on errors - * @note Wrapper of recv(2) - */ - template <typename Address> - unsigned recv(Socket<Address, Tcp> &sc, void *data, unsigned length) - { - int nbread = ::recv(sc.handle(), (Arg)data, length, 0); - - if (nbread == Failure) { -#if defined(_WIN32) - int error = WSAGetLastError(); - - if (error == WSAEWOULDBLOCK) { - nbread = 0; - sc.setCondition(Condition::Readable); - } else { - sc.setState(State::Disconnected); - throw Error{Error::System, "recv", error}; - } -#else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - sc.setCondition(Condition::Readable); - } else { - sc.setState(State::Disconnected); - throw Error{Error::System, "recv"}; - } -#endif - } else if (nbread == 0) { - sc.setState(State::Disconnected); - } - - return static_cast<unsigned>(nbread); - } - - /** - * Send some data. - * - * If the socket is marked non-blocking and the operation would block, then 0 is returned and condition is set to - * Condition::Writable. - * - * If the socket is blocking, this function blocks until the data has been sent. - * - * On any other errors, this function throw net::Error. - * - * @param sc the socket - * @param data the buffer to send - * @param length the buffer length - * @return the number of bytes sent - * @throw net::Error on errors - * @note Wrapper of send(2) - */ - template <typename Address> - unsigned send(Socket<Address, Tcp> &sc, const void *data, unsigned length) - { - int nbsent = ::send(sc.handle(), (ConstArg)data, length, 0); - - if (nbsent == Failure) { -#if defined(_WIN32) - int error = WSAGetLastError(); - - if (error == WSAEWOULDBLOCK) { - nbsent = 0; - sc.setCondition(Condition::Writable); - } else { - sc.setState(State::Disconnected); - throw Error{Error::System, "send", error}; - } -#else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - nbsent = 0; - sc.setCondition(Condition::Writable); - } else { - sc.setState(State::Disconnected); - throw Error{Error::System, "send"}; - } -#endif - } - - return static_cast<unsigned>(nbsent); - } -}; - -/* }}} */ - -/* {{{ Udp */ - -/** - * @class Udp - * @brief Clear UDP type. - * - * This class is the basic implementation of UDP sockets. - */ -class Udp { -public: - /** - * Socket type. - * - * @return SOCK_DGRAM - */ - inline int type() const noexcept - { - return SOCK_DGRAM; - } - - /** - * Do nothing. - */ - template <typename Address> - inline void create(Socket<Address, Udp> &) noexcept - { - /* No-op */ - } - - /** - * Receive data from an end point. - * - * If the socket is marked non-blocking and no data is available, 0 is returned and condition is set to - * Condition::Readable. - * - * If the socket is blocking, this functions blocks until some data is available or if an error occurs. - * - * @param sc the socket - * @param data the destination buffer - * @param length the buffer length - * @param address the address - * @param addrlen the initial address length - * @return the number of bytes received - * @throw Error on error - */ - template <typename Address> - unsigned recvfrom(Socket<Address, Udp> &sc, void *data, unsigned length, sockaddr *address, socklen_t *addrlen) - { - int nbread; - - nbread = ::recvfrom(sc.handle(), (Arg)data, length, 0, address, addrlen); - - if (nbread == Failure) { -#if defined(_WIN32) - int error = WSAGetLastError(); - - if (error == WSAEWOULDBLOCK) { - nbread = 0; - sc.setCondition(Condition::Readable); - } else { - throw Error{Error::System, "recvfrom"}; - } -#else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - nbread = 0; - sc.setCondition(Condition::Readable); - } else { - throw Error{Error::System, "recvfrom"}; - } -#endif - } - - return static_cast<unsigned>(nbread); - } - - /** - * Send data to an end point. - * - * If the socket is marked non-blocking and the operation would block, then 0 is returned and condition is set to - * Condition::Writable. - * - * If the socket is blocking, this functions blocks until the data has been sent. - * - * @param sc the socket - * @param data the buffer - * @param length the buffer length - * @param address the client address - * @param addrlen the adderss length - * @return the number of bytes sent - * @throw Error on error - */ - template <typename Address> - unsigned sendto(Socket<Address, Udp> &sc, const void *data, unsigned length, const sockaddr *address, socklen_t addrlen) - { - int nbsent; - - nbsent = ::sendto(sc.handle(), (ConstArg)data, length, 0, address, addrlen); - if (nbsent == Failure) { -#if defined(_WIN32) - int error = WSAGetLastError(); - - if (error == WSAEWOULDBLOCK) { - nbsent = 0; - sc.setCondition(Condition::Writable); - } else { - throw Error{Error::System, "sendto", error}; - } -#else - if (errno == EAGAIN || errno == EWOULDBLOCK) { - nbsent = 0; - sc.setCondition(Condition::Writable); - } else { - throw Error{Error::System, "sendto"}; - } -#endif - } - - return static_cast<unsigned>(nbsent); - } -}; - -/* }}} */ - -/* {{{ Tls */ - -#if !defined(SOCKET_NO_SSL) - -/** - * @class Tls - * @brief OpenSSL secure layer for TCP. - * - * **Note:** This protocol is much more difficult to use with non-blocking sockets, if some operations would block, the - * user is responsible of calling the function again by waiting for the appropriate condition. See the functions for - * more details. - * - * @see Tls::accept - * @see Tls::connect - * @see Tls::recv - * @see Tls::send - */ -class Tls : private Tcp { -private: - using Context = std::shared_ptr<SSL_CTX>; - using Ssl = std::unique_ptr<SSL, void (*)(SSL *)>; - - /* OpenSSL objects */ - Context m_context; - Ssl m_ssl{nullptr, nullptr}; - - /* Status */ - bool m_tcpconnected{false}; - - /* - * User definable parameters - */ - ssl::Method m_method{ssl::Tlsv1}; - std::string m_key; - std::string m_certificate; - bool m_verify{false}; - - /* - * Construct with a context and ssl, for Tls::accept. - */ - Tls(Context context, Ssl ssl) - : m_context{std::move(context)} - , m_ssl{std::move(ssl)} - { - } - - /* - * Get the OpenSSL error message. - */ - inline std::string error(int error) - { - auto msg = ERR_reason_error_string(error); - - return msg == nullptr ? "" : msg; - } - - /* - * Update the states after an uncompleted operation. - */ - template <typename Address, typename Protocol> - inline void updateStates(Socket<Address, Protocol> &sc, State state, Action action, int code) - { - assert(code == SSL_ERROR_WANT_READ || code == SSL_ERROR_WANT_WRITE); - - sc.setState(state); - sc.setAction(action); - - if (code == SSL_ERROR_WANT_READ) { - sc.setCondition(Condition::Readable); - } else { - sc.setCondition(Condition::Writable); - } - } - - /* - * Continue the connect operation. - */ - template <typename Address, typename Protocol> - void processConnect(Socket<Address, Protocol> &sc) - { - int ret = SSL_connect(m_ssl.get()); - - if (ret <= 0) { - int no = SSL_get_error(m_ssl.get(), ret); - - if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) { - updateStates(sc, State::Connecting, Action::Connect, no); - } else { - sc.setState(State::Disconnected); - throw Error{Error::System, "connect", error(no)}; - } - } else { - sc.setState(State::Connected); - } - } - - /* - * Continue accept. - */ - template <typename Address, typename Protocol> - void processAccept(Socket<Address, Protocol> &sc) - { - int ret = SSL_accept(m_ssl.get()); - - if (ret <= 0) { - int no = SSL_get_error(m_ssl.get(), ret); - - if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) { - updateStates(sc, State::Accepting, Action::Accept, no); - } else { - sc.setState(State::Disconnected); - throw Error(Error::System, "accept", error(no)); - } - } else { - sc.setState(State::Accepted); - } - } - -public: - /** - * @copydoc Tcp::type - */ - inline int type() const noexcept - { - return SOCK_STREAM; - } - - /** - * Empty TLS constructor. - */ - Tls() - { -#if !defined(SOCKET_NO_SSL_AUTO_INIT) - net::ssl::init(); -#endif - } - - /** - * Set the method. - * - * @param method the method - * @pre the socket must not be already created - */ - inline void setMethod(ssl::Method method) noexcept - { - assert(!m_context); - assert(!m_ssl); - - m_method = method; - } - - /** - * Use the specified private key file. - * - * @param file the path to the private key - */ - inline void setPrivateKey(std::string file) noexcept - { - m_key = std::move(file); - } - - /** - * Use the specified certificate file. - * - * @param file the path to the file - */ - inline void setCertificate(std::string file) noexcept - { - m_certificate = std::move(file); - } - - /** - * Set to true if we must verify the certificate and private key. - * - * @param verify the mode - */ - inline void setVerify(bool verify = true) noexcept - { - m_verify = verify; - } - - /** - * Initialize the SSL objects after have created. - * - * @param sc the socket - * @throw net::Error on errors - */ - template <typename Address> - inline void create(Socket<Address, Tls> &sc) - { - auto method = (m_method == ssl::Tlsv1) ? TLSv1_method() : SSLv23_method(); - - m_context = {SSL_CTX_new(method), SSL_CTX_free}; - m_ssl = {SSL_new(m_context.get()), SSL_free}; - - SSL_set_fd(m_ssl.get(), sc.handle()); - - /* Load certificates */ - if (m_certificate.size() > 0) { - SSL_CTX_use_certificate_file(m_context.get(), m_certificate.c_str(), SSL_FILETYPE_PEM); - } - if (m_key.size() > 0) { - SSL_CTX_use_PrivateKey_file(m_context.get(), m_key.c_str(), SSL_FILETYPE_PEM); - } - if (m_verify && !SSL_CTX_check_private_key(m_context.get())) { - throw Error{Error::System, "(openssl)", "unable to verify key"}; - } - } - - /** - * Connect to a secure host. - * - * If the socket is marked non-blocking and the connection cannot be established yet, then the state is set - * to State::Connecting, the condition is set to Condition::Readable or Condition::Writable, the user must - * wait for the appropriate condition before calling the overload connect which takes 0 argument. - * - * If the socket is blocking, this functions blocks until the connection is complete. - * - * If the connection was completed correctly the state is set to State::Connected. - * - * @param sc the socket - * @param address the address - * @param length the address length - * @throw net::Error on errors - */ - template <typename Address, typename Protocol> - void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length) - { - /* 1. Connect using raw TCP */ - Tcp::connect(sc, address, length); - - /* 2. If the connection is complete (e.g. non-blocking), try handshake */ - if (sc.state() == State::Connected) { - m_tcpconnected = true; - processConnect(sc); - } - } - - /** - * Continue the connection. - * - * This function must be called when the socket is ready for reading or writing (check with Socket::condition), - * the state may change exactly like the initial connect call. - * - * @param sc the socket - * @throw net::Error on errors - */ - template <typename Address, typename Protocol> - void connect(Socket<Address, Protocol> &sc) - { - /* 1. Be sure to complete standard connect before */ - if (!m_tcpconnected) { - Tcp::connect(sc); - m_tcpconnected = sc.state() == State::Connected; - } - - if (m_tcpconnected) { - processConnect(sc); - } - } - - /** - * Accept a secure client. - * - * Because SSL needs several round-trips, if the socket is marked non-blocking and the connection is not - * completed yet, a new socket is returned but with the State::Accepting state. Its condition is set to - * Condition::Readable or Condition::Writable, the user is responsible of calling accept overload which takes - * 0 arguments on the returned socket when the condition is met. - * - * If the socket is blocking, this function blocks until the client is accepted and returned. - * - * If the client is accepted correctly, its state is set to State::Accepted. This instance does not change. - * - * @param sc the socket - * @param address the address destination - * @param length the address length - * @return the client - * @throw net::Error on errors - */ - template <typename Address> - Socket<Address, Tls> accept(Socket<Address, Tls> &sc, sockaddr *address, socklen_t *length) - { - Socket<Address, Tls> client = Tcp::accept(sc, address, length); - Tls &proto = client.protocol(); - - /* 1. Share the context */ - proto.m_context = m_context; - - /* 2. Create new SSL instance */ - proto.m_ssl = Ssl{SSL_new(m_context.get()), SSL_free}; - SSL_set_fd(proto.m_ssl.get(), client.handle()); - - /* 3. Try accept process on the **new** client */ - proto.processAccept(client); - - return client; - } - - /** - * Continue accept. - * - * This function must be called on the client that is being accepted. - * - * Like accept or connect, user is responsible of calling this function until the connection is complete. - * - * @param sc the socket - * @throw net::Error on errors - */ - template <typename Address, typename Protocol> - inline void accept(Socket<Address, Protocol> &sc) - { - processAccept(sc); - } - - /** - * Receive some secure data. - * - * If the socket is marked non-blocking, 0 is returned if no data is available yet or if the connection - * needs renegociation. If renegociation is required case, the action is set to Action::Receive and condition - * is set to Condition::Readable or Condition::Writable. The user must wait that the condition is met and - * call this function again. - * - * @param sc the socket - * @param data the destination - * @param len the buffer length - * @return the number of bytes read - * @throw net::Error on errors - */ - template <typename Address> - unsigned recv(Socket<Address, Tls> &sc, void *data, unsigned len) - { - auto nbread = SSL_read(m_ssl.get(), data, len); - - if (nbread <= 0) { - auto no = SSL_get_error(m_ssl.get(), nbread); - - if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) { - nbread = 0; - updateStates(sc, sc.state(), Action::Receive, no); - } else { - throw Error{Error::System, "recv", error(no)}; - } - } - - return nbread; - } - - /** - * Send some data. - * - * Like recv, if the socket is marked non-blocking and no data can be sent or a negociation is required, - * condition and action are set. See receive for more details - * - * @param sc the socket - * @param data the data to send - * @param len the buffer length - * @return the number of bytes sent - * @throw net::Error on errors - */ - template <typename Address> - unsigned send(Socket<Address, Tls> &sc, const void *data, unsigned len) - { - auto nbsent = SSL_write(m_ssl.get(), data, len); - - if (nbsent <= 0) { - auto no = SSL_get_error(m_ssl.get(), nbsent); - - if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) { - nbsent = 0; - updateStates(sc, sc.state(), Action::Send, no); - } else { - throw Error{Error::System, "send", error(no)}; - } - } - - return nbsent; - } -}; - -#endif // !SOCKET_NO_SSL - -/* }}} */ - -} // !protocol - -/* }}} */ - -/* - * Convenient helpers - * ------------------------------------------------------------------ - * - * - SocketTcp<Address>, for TCP sockets, - * - SocketUdp<Address>, for UDP sockets, - * - SocketTls<Address>, for secure TCP sockets. - */ - -/* {{{ Helpers */ - -/** - * Helper to create TCP sockets. - */ -template <typename Address> -using SocketTcp = Socket<Address, protocol::Tcp>; - -/** - * Helper to create TCP/IP sockets. - */ -using SocketTcpIp = Socket<address::Ip, protocol::Tcp>; - -#if !defined(_WIN32) - -/** - * Helper to create TCP/Local sockets. - */ -using SocketTcpLocal = Socket<address::Local, protocol::Tcp>; - -#endif - -/** - * Helper to create UDP sockets. - */ -template <typename Address> -using SocketUdp = Socket<Address, protocol::Udp>; - -/** - * Helper to create UDP/IP sockets. - */ -using SocketUdpIp = Socket<address::Ip, protocol::Udp>; - -#if !defined(SOCKET_NO_SSL) - -/** - * Helper to create OpenSSL TCP sockets. - */ -template <typename Address> -using SocketTls = Socket<Address, protocol::Tls>; - -/** - * Helper to create OpenSSL TCP/Ip sockets. - */ -using SocketTlsIp = Socket<address::Ip, protocol::Tls>; - -#endif // !SOCKET_NO_SSL - -/* }}} */ - -/* - * Select wrapper - * ------------------------------------------------------------------ - * - * Wrapper for select(2) and other various implementations. - */ - -/* {{{ Listener */ - -/** - * @class ListenerStatus - * @brief Result of polling - * - * Result of a select call, returns the first ready socket found with its - * flags. - */ -class ListenerStatus { -public: - Handle socket; //!< which socket is ready - Condition flags; //!< the flags -}; - -/** - * Table used in the socket listener to store which sockets have been - * set in which directions. - */ -using ListenerTable = std::map<Handle, Condition>; - -/** - * @class Select - * @brief Implements select(2) - * - * This class is the fallback of any other method, it is not preferred at all for many reasons. - */ -class Select { -public: - /** - * No-op, uses the ListenerTable directly. - */ - inline void set(const ListenerTable &, Handle, Condition, bool) noexcept {} - - /** - * No-op, uses the ListenerTable directly. - */ - inline void unset(const ListenerTable &, Handle, Condition, bool) noexcept {} - - /** - * Return the sockets - */ - std::vector<ListenerStatus> wait(const ListenerTable &table, int ms); - - /** - * Backend identifier - */ - inline const char *name() const noexcept - { - return "select"; - } -}; - -#if defined(SOCKET_HAVE_POLL) - -/** - * @class Poll - * @brief Implements poll(2). - * - * Poll is widely supported and is better than select(2). It is still not the - * best option as selecting the sockets is O(n). - */ -class Poll { -private: - std::vector<pollfd> m_fds; - - short toPoll(Condition flags) const noexcept; - Condition toCondition(short &event) const noexcept; - -public: - /** - * Set the handle. - */ - void set(const ListenerTable &, Handle, Condition, bool); - - /** - * Unset the handle. - */ - void unset(const ListenerTable &, Handle, Condition, bool); - - /** - * Wait for events. - */ - std::vector<ListenerStatus> wait(const ListenerTable &, int ms); - - /** - * Backend identifier - */ - inline const char *name() const noexcept - { - return "poll"; - } -}; - -#endif - -#if defined(SOCKET_HAVE_EPOLL) - -/** - * @class Epoll - * @brief Linux's epoll. - */ -class Epoll { -private: - int m_handle; - std::vector<epoll_event> m_events; - - Epoll(const Epoll &) = delete; - Epoll &operator=(const Epoll &) = delete; - Epoll(const Epoll &&) = delete; - Epoll &operator=(const Epoll &&) = delete; - - uint32_t toEpoll(Condition flags) const noexcept; - Condition toCondition(uint32_t events) const noexcept; - void update(Handle sc, int op, int eflags); - -public: - /** - * Construct the epoll instance. - */ - Epoll(); - - /** - * Close the epoll instance. - */ - ~Epoll(); - - /** - * Set the handle. - */ - void set(const ListenerTable &, Handle, Condition, bool); - - /** - * Unset the handle. - */ - void unset(const ListenerTable &, Handle, Condition, bool); - - /** - * Wait for events. - */ - std::vector<ListenerStatus> wait(const ListenerTable &, int); - - /** - * Backend identifier - */ - inline const char *name() const noexcept - { - return "epoll"; - } -}; - -#endif - -#if defined(SOCKET_HAVE_KQUEUE) - -/** - * @class Kqueue - * @brief Implements kqueue(2). - * - * This implementation is available on all BSD and Mac OS X. It is better than - * poll(2) because it's O(1), however it's a bit more memory consuming. - */ -class Kqueue { -private: - std::vector<struct kevent> m_result; - int m_handle; - - Kqueue(const Kqueue &) = delete; - Kqueue &operator=(const Kqueue &) = delete; - Kqueue(Kqueue &&) = delete; - Kqueue &operator=(Kqueue &&) = delete; - - void update(Handle sc, int filter, int kflags); - -public: - /** - * Construct the kqueue instance. - */ - Kqueue(); - - /** - * Destroy the kqueue instance. - */ - ~Kqueue(); - - /** - * Set the handle. - */ - void set(const ListenerTable &, Handle, Condition, bool); - - /** - * Unset the handle. - */ - void unset(const ListenerTable &, Handle, Condition, bool); - - /** - * Wait for events. - */ - std::vector<ListenerStatus> wait(const ListenerTable &, int); - - /** - * Backend identifier - */ - inline const char *name() const noexcept - { - return "kqueue"; - } -}; - -#endif - -/** - * @class Listener - * @brief Synchronous multiplexing - * - * Convenient wrapper around the select() system call. - * - * This class is implemented using a bridge pattern to allow different uses - * of listener implementation. - * - * You should not reinstanciate a new Listener at each iteartion of your - * main loop as it can be extremely costly. Instead use the same listener that - * you can safely modify on the fly. - * - * Currently, poll, epoll, select and kqueue are available. - * - * To implement the backend, the following functions must be available: - * - * ### Set - * - * @code - * void set(const ListenerTable &, Handle sc, Condition condition, bool add); - * @endcode - * - * This function, takes the socket to be added and the flags. The condition is - * always guaranteed to be correct and the function will never be called twice - * even if the user tries to set the same flag again. - * - * An optional add argument is added for backends which needs to do different - * operation depending if the socket was already set before or if it is the - * first time (e.g EPOLL_CTL_ADD vs EPOLL_CTL_MOD for epoll(7). - * - * ### Unset - * - * @code - * void unset(const ListenerTable &, Handle sc, Condition condition, bool remove); - * @endcode - * - * Like set, this function is only called if the condition is actually set and will - * not be called multiple times. - * - * Also like set, an optional remove argument is set if the socket is being - * completely removed (e.g no more flags are set for this socket). - * - * ### Wait - * - * @code - * std::vector<ListenerStatus> wait(const ListenerTable &, int ms); - * @endcode - * - * Wait for the sockets to be ready with the specified milliseconds. Must return a list of ListenerStatus, - * may throw any exceptions. - * - * ### Name - * - * @code - * inline const char *name() const noexcept - * @endcode - * - * Returns the backend name. Usually the class in lower case. - */ -template <typename Backend = SOCKET_DEFAULT_BACKEND> -class Listener { -private: - Backend m_backend; - ListenerTable m_table; - -public: - /** - * Construct an empty listener. - */ - Listener() = default; - - /** - * Get the backend. - * - * @return the backend - */ - inline const Backend &backend() const noexcept - { - return m_backend; - } - - /** - * Get the non-modifiable table. - * - * @return the table - */ - inline const ListenerTable &table() const noexcept - { - return m_table; - } - - /** - * Overloaded function. - * - * @return the iterator - */ - inline ListenerTable::const_iterator begin() const noexcept - { - return m_table.begin(); - } - - /** - * Overloaded function. - * - * @return the iterator - */ - inline ListenerTable::const_iterator cbegin() const noexcept - { - return m_table.cbegin(); - } - - /** - * Overloaded function. - * - * @return the iterator - */ - inline ListenerTable::const_iterator end() const noexcept - { - return m_table.end(); - } - - /** - * Overloaded function. - * - * @return the iterator - */ - inline ListenerTable::const_iterator cend() const noexcept - { - return m_table.cend(); - } - - /** - * Add or update a socket to the listener. - * - * If the socket is already placed with the appropriate flags, the - * function is a no-op. - * - * If incorrect flags are passed, the function does nothing. - * - * @param sc the socket - * @param condition the condition (may be OR'ed) - * @throw Error if the backend failed to set - */ - void set(Handle sc, Condition condition) - { - /* Invalid or useless flags */ - if (condition == Condition::None || static_cast<int>(condition) > 0x3) - return; - - auto it = m_table.find(sc); - - /* - * Do not update the table if the backend failed to add - * or update. - */ - if (it == m_table.end()) { - m_backend.set(m_table, sc, condition, true); - m_table.emplace(sc, condition); - } else { - /* Remove flag if already present */ - if ((condition & Condition::Readable) == Condition::Readable && - (it->second & Condition::Readable) == Condition::Readable) { - condition &= ~(Condition::Readable); - } - if ((condition & Condition::Writable) == Condition::Writable && - (it->second & Condition::Writable) == Condition::Writable) { - condition &= ~(Condition::Writable); - } - - /* Still need a call? */ - if (condition != Condition::None) { - m_backend.set(m_table, sc, condition, false); - it->second |= condition; - } - } - } - - /** - * Unset a socket from the listener, only the flags is removed - * unless the two flagss are requested. - * - * For example, if you added a socket for both reading and writing, - * unsetting the write flags will keep the socket for reading. - * - * @param sc the socket - * @param condition the condition (may be OR'ed) - * @see remove - */ - void unset(Handle sc, Condition condition) - { - auto it = m_table.find(sc); - - /* Invalid or useless flags */ - if (condition == Condition::None || static_cast<int>(condition) > 0x3 || it == m_table.end()) - return; - - /* - * Like set, do not update if the socket is already at the appropriate - * state. - */ - if ((condition & Condition::Readable) == Condition::Readable && - (it->second & Condition::Readable) != Condition::Readable) { - condition &= ~(Condition::Readable); - } - if ((condition & Condition::Writable) == Condition::Writable && - (it->second & Condition::Writable) != Condition::Writable) { - condition &= ~(Condition::Writable); - } - - if (condition != Condition::None) { - /* Determine if it's a complete removal */ - bool removal = ((it->second) & ~(condition)) == Condition::None; - - m_backend.unset(m_table, sc, condition, removal); - - if (removal) { - m_table.erase(it); - } else { - it->second &= ~(condition); - } - } - } - - /** - * Remove completely the socket from the listener. - * - * It is a shorthand for unset(sc, Condition::Readable | Condition::Writable); - * - * @param sc the socket - */ - inline void remove(Handle sc) - { - unset(sc, Condition::Readable | Condition::Writable); - } - - /** - * Remove all sockets. - */ - inline void clear() - { - while (!m_table.empty()) { - remove(m_table.begin()->first); - } - } - - /** - * Get the number of sockets in the listener. - */ - inline ListenerTable::size_type size() const noexcept - { - return m_table.size(); - } - - /** - * Select a socket. Waits for a specific amount of time specified as the duration. - * - * @param duration the duration - * @return the socket ready - */ - template <typename Rep, typename Ratio> - inline ListenerStatus wait(const std::chrono::duration<Rep, Ratio> &duration) - { - assert(!m_table.empty()); - - auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration); - - return m_backend.wait(m_table, cvt.count())[0]; - } - - /** - * Overload with milliseconds. - * - * @param timeout the optional timeout in milliseconds - * @return the socket ready - */ - inline ListenerStatus wait(int timeout = -1) - { - return wait(std::chrono::milliseconds(timeout)); - } - - /** - * Select multiple sockets. - * - * @param duration the duration - * @return the socket ready - */ - template <typename Rep, typename Ratio> - inline std::vector<ListenerStatus> waitMultiple(const std::chrono::duration<Rep, Ratio> &duration) - { - assert(!m_table.empty()); - - auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration); - - return m_backend.wait(m_table, cvt.count()); - } - - /** - * Overload with milliseconds. - * - * @return the socket ready - */ - inline std::vector<ListenerStatus> waitMultiple(int timeout = -1) - { - return waitMultiple(std::chrono::milliseconds(timeout)); - } -}; - -/* }}} */ - -/* - * Callback - * ------------------------------------------------------------------ - * - * Function owner with tests. - */ - -/* {{{ Callback */ - -/** - * @class Callback - * @brief Convenient signal owner that checks if the target is valid. - * - * This class also catch all errors thrown from signals to avoid interfering with our process. - */ -template <typename... Args> -class Callback : public std::function<void (Args...)> { -public: - /** - * Inherited constructors. - */ - using std::function<void (Args...)>::function; - - /** - * Execute the callback only if a target is set. - */ - void operator()(Args... args) const - { - if (*this) { - try { - std::function<void (Args...)>::operator()(args...); - } catch (...) { - } - } - } -}; - -/* }}} */ - -/* - * StreamConnection - * ------------------------------------------------------------------ - * - * Client connected on the server side. - */ - -/* {{{ StreamConnection */ - -/** - * @class StreamConnection - * @brief Connected client on the server side. - * - * This object is created from StreamServer when a new client is connected, it is the higher - * level object of sockets and completely asynchronous. - */ -template <typename Address, typename Protocol> -class StreamConnection { -public: - /** - * Called when the output has changed. - */ - using WriteHandler = Callback<>; - -private: - /* Signals */ - WriteHandler m_onWrite; - - /* Sockets and output buffer */ - Socket<Address, Protocol> m_socket; - std::string m_output; - -public: - /** - * Create the connection. - * - * @param s the socket - */ - StreamConnection(Socket<Address, Protocol> s) - : m_socket{std::move(s)} - { - m_socket.set(net::option::SockBlockMode{false}); - } - - /** - * Access the underlying socket. - * - * @return the socket - * @warning use with care - */ - inline Socket<Address, Protocol> &socket() noexcept - { - return m_socket; - } - - /** - * Access the current output. - * - * @return the output - */ - inline const std::string &output() const noexcept - { - return m_output; - } - - /** - * Overloaded function - * - * @return the output - * @warning use with care, avoid modifying the output if you don't know what you're doing - */ - inline std::string &output() noexcept - { - return m_output; - } - - /** - * Post some data to be sent asynchronously. - * - * @param str the data to append - */ - inline void send(std::string str) - { - m_output += str; - m_onWrite(); - } - - /** - * Kill the client. - */ - inline void close() - { - m_socket.close(); - } - - /** - * Set the write handler, the signal is emitted when the output has changed so that the StreamServer owner - * knows that there are some data to send. - * - * @param handler the handler - * @warning you usually never need to set this yourself - */ - inline void setWriteHandler(WriteHandler handler) - { - m_onWrite = std::move(handler); - } -}; - -/* }}} */ - -/* - * StreamServer - * ------------------------------------------------------------------ - * - * Convenient stream oriented server. - */ - -/* {{{ StreamServer */ - -/** - * @class StreamServer - * @brief Convenient stream server for TCP and TLS. - * - * This class does all the things for you as accepting new clients, listening for it and sending data. It works - * asynchronously without blocking to let you control your process workflow. - * - * This class is not thread safe and you must not call any of the functions from different threads. - */ -template <typename Address, typename Protocol> -class StreamServer { -public: - /** - * Handler when a new client is connected. - */ - using ConnectionHandler = Callback<const std::shared_ptr<StreamConnection<Address, Protocol>> &>; - - /** - * Handler when a client is disconnected. - */ - using DisconnectionHandler = Callback<const std::shared_ptr<StreamConnection<Address, Protocol>> &>; - - /** - * Handler when data has been received from a client. - */ - using ReadHandler = Callback<const std::shared_ptr<StreamConnection<Address, Protocol>> &, const std::string &>; - - /** - * Handler when data has been correctly sent to a client. - */ - using WriteHandler = Callback<const std::shared_ptr<StreamConnection<Address, Protocol>> &, const std::string &>; - - /** - * Handler when an error occured. - */ - using ErrorHandler = Callback<const Error &>; - - /** - * Handler when there was a timeout. - */ - using TimeoutHandler = Callback<>; - -private: - using ClientMap = std::map<Handle, std::shared_ptr<StreamConnection<Address, Protocol>>>; - - /* Signals */ - ConnectionHandler m_onConnection; - DisconnectionHandler m_onDisconnection; - ReadHandler m_onRead; - WriteHandler m_onWrite; - ErrorHandler m_onError; - TimeoutHandler m_onTimeout; - - /* Sockets */ - Socket<Address, Protocol> m_master; - Listener<> m_listener; - ClientMap m_clients; - - /* - * Update flags depending on the required condition. - */ - void updateFlags(std::shared_ptr<StreamConnection<Address, Protocol>> &client) - { - assert(client->socket().action() != Action::None); - - m_listener.remove(client->socket().handle()); - m_listener.set(client->socket().handle(), client->socket().condition()); - } - - /* - * Continue accept process. - */ - template <typename AcceptCall> - void processAccept(std::shared_ptr<StreamConnection<Address, Protocol>> &client, const AcceptCall &acceptFunc) - { - try { - /* Do the accept */ - acceptFunc(); - - /* 1. First remove completely the client */ - m_listener.remove(client->socket().handle()); - - /* 2. If accept is not finished, wait for the appropriate condition */ - if (client->socket().state() == State::Accepted) { - /* 3. Client is accepted, notify the user */ - m_listener.set(client->socket().handle(), Condition::Readable); - m_onConnection(client); - } else { - /* Operation still in progress */ - updateFlags(client); - } - } catch (const Error &error) { - m_clients.erase(client->socket().handle()); - m_listener.remove(client->socket().handle()); - m_onError(error); - } - } - - /* - * Process initial accept of master socket, this is the initial accepting process. Except on errors, the - * socket is stored but the user will be notified only once the socket is completely accepted. - */ - void processInitialAccept() - { - // TODO: store address too. - std::shared_ptr<StreamConnection<Address, Protocol>> client = std::make_shared<StreamConnection<Address, Protocol>>(m_master.accept(nullptr)); - std::weak_ptr<StreamConnection<Address, Protocol>> ptr{client}; - - /* 1. Register output changed to update listener */ - client->setWriteHandler([this, ptr] () { - auto client = ptr.lock(); - - /* Do not update the listener immediately if an action is pending */ - if (client && client->socket().action() == Action::None && !client->output().empty()) { - m_listener.set(client->socket().handle(), Condition::Writable); - } - }); - - /* 2. Add the client */ - m_clients.insert(std::make_pair(client->socket().handle(), client)); - - /* - * 2. Do an initial check to set the listener flags, at this moment the socket may or not be - * completely accepted. - */ - processAccept(client, [&] () {}); - } - - /* - * Read or complete the read operation. - */ - void processRead(std::shared_ptr<StreamConnection<Address, Protocol>> &client) - { - /* - * Read because there is something to read or because the pending operation is - * read and must complete. - */ - auto buffer = client->socket().recv(512); - - /* - * Now the receive operation may be completed, in that case, two possibilities: - * - * 1. The action is set to None (completed) - * 2. The action is still not complete, update the flags - */ - if (client->socket().action() == Action::None) { - /* Empty mean normal disconnection */ - if (buffer.empty()) { - m_listener.remove(client->socket().handle()); - m_clients.erase(client->socket().handle()); - m_onDisconnection(client); - } else { - /* - * At this step, it is possible that we were completing a receive operation, in this - * case the write flag may be removed, add it if required. - */ - if (!client->output().empty()) { - m_listener.set(client->socket().handle(), Condition::Writable); - } - - m_onRead(client, buffer); - } - } else { - /* Operation in progress */ - updateFlags(client); - } - } - - /* - * Flush the output buffer. - */ - void processWrite(std::shared_ptr<StreamConnection<Address, Protocol>> &client) - { - auto &output = client->output(); - auto nsent = client->socket().send(output); - - if (client->socket().action() == Action::None) { - /* 1. Create a copy of content that has been sent */ - auto sent = output.substr(0, nsent); - - /* 2. Erase the content sent */ - output.erase(0, nsent); - - /* 3. Update listener */ - if (output.empty()) { - m_listener.unset(client->socket().handle(), Condition::Writable); - } - - /* 4. Notify user */ - m_onWrite(client, sent); - } else { - updateFlags(client); - } - } - - void processSync(std::shared_ptr<StreamConnection<Address, Protocol>> &client, Condition flags) - { - try { - auto action = client->socket().action(); - - if (action == Action::Receive || - (action == Action::None && (flags & Condition::Readable) == Condition::Readable)) { - processRead(client); - } else if ((flags & Condition::Writable) == Condition::Writable) { - processWrite(client); - } - } catch (const Error &error) { - m_onDisconnection(client); - m_listener.remove(client->socket().handle()); - m_clients.erase(client->socket().handle()); - } - } - -public: - /** - * Create a stream server with the specified address to bind. - * - * @param protocol the protocol (Tcp or Tls) - * @param address the address to bind - * @param max the max number to listen - * @throw Error on errors - */ - StreamServer(Protocol protocol, const Address &address, int max = 128) - : m_master{std::move(protocol), address} - { - // TODO: m_onError - m_master.set(SOL_SOCKET, SO_REUSEADDR, 1); - m_master.bind(address); - m_master.listen(max); - m_listener.set(m_master.handle(), Condition::Readable); - } - - /** - * Set the connection handler, called when a new client is connected. - * - * @param handler the handler - */ - inline void setConnectionHandler(ConnectionHandler handler) - { - m_onConnection = std::move(handler); - } - - /** - * Set the disconnection handler, called when a client died. - * - * @param handler the handler - */ - inline void setDisconnectionHandler(DisconnectionHandler handler) - { - m_onDisconnection = std::move(handler); - } - - /** - * Set the receive handler, called when a client has sent something. - * - * @param handler the handler - */ - inline void setReadHandler(ReadHandler handler) - { - m_onRead = std::move(handler); - } - - /** - * Set the writing handler, called when some data has been sent to a client. - * - * @param handler the handler - */ - inline void setWriteHandler(WriteHandler handler) - { - m_onWrite = std::move(handler); - } - - /** - * Set the error handler, called when unrecoverable error has occured. - * - * @param handler the handler - */ - inline void setErrorHandler(ErrorHandler handler) - { - m_onError = std::move(handler); - } - - /** - * Set the timeout handler, called when the selection has timeout. - * - * @param handler the handler - */ - inline void setTimeoutHandler(TimeoutHandler handler) - { - m_onTimeout = std::move(handler); - } - - /** - * Poll for the next event. - * - * @param timeout the timeout (-1 for indefinitely) - * @throw Error on errors - */ - void poll(int timeout = -1) - { - try { - auto st = m_listener.wait(timeout); - - if (st.socket == m_master.handle()) { - /* New client */ - processInitialAccept(); - } else { - /* Recv / Send / Accept on a client */ - auto client = m_clients[st.socket]; - - if (client->socket().state() == State::Accepted) { - processSync(client, st.flags); - } else { - processAccept(client, [&] () { client->socket().accept(); }); - } - } - } catch (const Error &error) { - if (error.code() == Error::Timeout) { - m_onTimeout(); - } else { - m_onError(error); - } - } - } -}; - -/* }}} */ - -/* - * StreamClient - * ------------------------------------------------------------------ - */ - -/* {{{ StreamClient */ - -/** - * @class StreamClient - * @brief Client side connection to a server. - * - * This class is not thread safe and you must not call any of the functions from different threads. - */ -template <typename Address, typename Protocol> -class StreamClient { -public: - /** - * Handler when connection is complete. - */ - using ConnectionHandler = Callback<>; - - /** - * Handler when data has been received. - */ - using ReadHandler = Callback<const std::string &>; - - /** - * Handler when data has been sent correctly. - */ - using WriteHandler = Callback<const std::string &>; - - /** - * Handler when disconnected. - */ - using DisconnectionHandler = Callback<>; - - /** - * Handler on unrecoverable error. - */ - using ErrorHandler = Callback<const Error &>; - - /** - * Handler when timeout occured. - */ - using TimeoutHandler = Callback<>; - -private: - /* Signals */ - ConnectionHandler m_onConnection; - ReadHandler m_onRead; - WriteHandler m_onWrite; - DisconnectionHandler m_onDisconnection; - ErrorHandler m_onError; - TimeoutHandler m_onTimeout; - - /* Socket */ - Socket<Address, Protocol> m_socket; - Listener<> m_listener; - - /* Output buffer */ - std::string m_output; - - /* - * Update the flags after an uncompleted operation. This function must only be called when the operation - * has not complete (e.g. connect, recv, send). - */ - void updateFlags() - { - assert(m_socket.action() != Action::None); - - m_listener.remove(m_socket.handle()); - m_listener.set(m_socket.handle(), m_socket.condition()); - } - - /* - * This is the generic connect helper, it will be used to both initiate the connection or to continue the - * connection process if needed. - * - * Thus the template parameter is the appropriate function to call either, m_socket.connect(address) or - * m_socket.connect(). - * - * See poll() and connect() to understand. - */ - template <typename ConnectCall> - void processConnect(const ConnectCall &connectFunc) - { - /* Call m_socket.connect() or m_socket.connect(address) */ - connectFunc(); - - /* Remove entirely */ - m_listener.remove(m_socket.handle()); - - if (m_socket.state() == State::Connected) { - m_onConnection(); - m_listener.set(m_socket.handle(), Condition::Readable); - } else { - /* Connection still in progress */ - updateFlags(); - } - } - - /* - * Receive or complete the receive command, if the command is not complete, the listener is updated - * accordingly. - */ - void processRead() - { - auto received = m_socket.recv(512); - - if (m_socket.action() == Action::None) { - /* 0 means disconnection */ - if (received.empty()) { - m_onDisconnection(); - } else { - /* - * At this step, it is possible that we were completing a receive operation, in this - * case the write flag may be removed, add it if required. - */ - if (m_output.empty()) { - m_listener.unset(m_socket.handle(), Condition::Writable); - } - - m_onRead(received); - } - } else { - /* Receive operation in progress */ - updateFlags(); - } - } - - /* - * Send or complete the send command, if the command is not complete, the listener is updated - * accordingly. - */ - void processWrite() - { - auto nsent = m_socket.send(m_output); - - if (m_socket.action() == Action::None) { - /* 1. Make a copy of what has been sent */ - auto sent = m_output.substr(0, nsent); - - /* 2. Erase sent content */ - m_output.erase(0, nsent); - - /* 3. Update flags if needed */ - if (m_output.empty()) { - m_listener.unset(m_socket.handle(), Condition::Writable); - } - - /* 4. Notify user */ - m_onWrite(sent); - } else { - /* Send operation in progress */ - updateFlags(); - } - } - - /* - * Receive or send. - */ - void processSync(Condition condition) - { - if ((m_socket.action() == Action::Receive) || - (m_socket.action() == Action::None && (condition & Condition::Readable) == Condition::Readable)) { - processRead(); - } else { - processWrite(); - } - } - -public: - /** - * Create a client. The client is automatically marked as non-blocking. - * - * @param protocol the protocol (Tcp or Tls) - * @param address the optional address - * @throw net::Error on failures - */ - StreamClient(Protocol protocol = {}, const Address &address = {}) - : m_socket{std::move(protocol), address} - { - m_socket.set(net::option::SockBlockMode{false}); - m_listener.set(m_socket.handle(), Condition::Readable); - } - - /** - * Set the connection handler, called when the connection succeed. - * - * @param handler the handler - */ - inline void setConnectionHandler(ConnectionHandler handler) - { - m_onConnection = std::move(handler); - } - - /** - * Set the disconnection handler, called when the server closed the connection. - * - * @param handler the handler - */ - inline void setDisconnectionHandler(DisconnectionHandler handler) - { - m_onDisconnection = std::move(handler); - } - - /** - * Set the read handler, called when we received something. - * - * @param handler the handler - */ - inline void setReadHandler(ReadHandler handler) - { - m_onRead = std::move(handler); - } - - /** - * Set the write handler, called when we successfully sent data. - * - * @param handler the handler - */ - inline void setWriteHandler(WriteHandler handler) - { - m_onWrite = std::move(handler); - } - - /** - * Set the error handler, called when unexpected error occurs. - * - * @param handler the handler - */ - inline void setErrorHandler(ErrorHandler handler) - { - m_onError = std::move(handler); - } - - /** - * Connect to a server, this function may connect immediately or not in any case the connection handler - * will be called when the connection completed. - * - * @param address the address to connect to - */ - void connect(const Address &address) noexcept - { - assert(m_socket.state() == State::Open); - - processConnect([&] () { m_socket.connect(address); }); - } - - /** - * Asynchronously send data to the server. - * - * @param str the data to append - */ - void send(std::string str) - { - m_output += str; - - /* Don't update the listener if there is a pending operation */ - if (m_socket.state() == State::Connected && m_socket.action() == Action::None && !m_output.empty()) { - m_listener.set(m_socket.handle(), Condition::Writable); - } - } - - /** - * Wait for the next event. - * - * @param timeout the time to wait in milliseconds - * @throw Error on errors - */ - void poll(int timeout = -1) noexcept - { - try { - auto st = m_listener.wait(timeout); - - if (m_socket.state() != State::Connected) { - /* Continue the connection */ - processConnect([&] () { m_socket.connect(); }); - } else { - /* Read / Write */ - processSync(st.flags); - } - } catch (const Error &error) { - if (error.code() == Error::Timeout) { - m_onTimeout(); - } else { - m_listener.remove(m_socket.handle()); - m_onError(error); - } - } - } -}; - -/* }}} */ - -} // !net - -} // !irccd - -#endif // !IRCCD_SOCKETS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/sockets.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,4078 @@ +/* + * sockets.hpp -- portable C++ socket wrappers + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SOCKETS_HPP +#define IRCCD_SOCKETS_HPP + +/** + * @file sockets.hpp + * @brief Portable socket abstraction + * + * # Introduction + * + * This file is a portable networking library. + * + * ## Options + * + * The user may set the following variables before compiling these files: + * + * ### General options + * + * - **SOCKET_NO_AUTO_INIT**: (bool) Set to 0 if you don't want Socket class to + * automatically calls net::init function and net::finish functions. + * - **SOCKET_NO_SSL**: (bool) Set to 0 if you don't have access to OpenSSL library. + * - **SOCKET_NO_AUTO_SSL_INIT**: (bool) Set to 0 if you don't want Socket class with Tls to automatically init + * the OpenSSL library. You will need to call net::ssl::init and net::ssl::finish. + * + * ### Options for Listener class + * + * Feature detection, multiple implementations may be avaible, for example, Linux has poll, select and epoll. + * + * We assume that `select(2)` is always available. + * + * Of course, you can set the variables yourself if you test it with your build system. + * + * - **SOCKET_HAVE_POLL**: Defined on all BSD, Linux. Also defined on Windows + * if _WIN32_WINNT is set to 0x0600 or greater. + * - **SOCKET_HAVE_KQUEUE**: Defined on all BSD and Apple. + * - **SOCKET_HAVE_EPOLL**: Defined on Linux only. + * - **SOCKET_DEFAULT_BACKEND**: Which backend to use (e.g. `Select`). + * + * The preference priority is ordered from left to right. + * + * | System | Backend | Class name | + * |---------------|-------------------------|--------------| + * | Linux | epoll(7) | Epoll | + * | *BSD | kqueue(2) | Kqueue | + * | Windows | poll(2), select(2) | Poll, Select | + * | Mac OS X | kqueue(2) | Kqueue | + */ + +#if defined(_WIN32) +# if _WIN32_WINNT >= 0x0600 && !defined(SOCKET_HAVE_POLL) +# define SOCKET_HAVE_POLL +# endif +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) +# if !defined(SOCKET_HAVE_KQUEUE) +# define SOCKET_HAVE_KQUEUE +# endif +# if !defined(SOCKET_HAVE_POLL) +# define SOCKET_HAVE_POLL +# endif +#elif defined(__linux__) +# if !defined(SOCKET_HAVE_EPOLL) +# define SOCKET_HAVE_EPOLL +# endif +# if !defined(SOCKET_HAVE_POLL) +# define SOCKET_HAVE_POLL +# endif +#endif + +/* + * Define SOCKET_DEFAULT_BACKEND + * ------------------------------------------------------------------ + */ + +/** + * Defines the default Listener backend to use. + * + * @note Do not rely on the value shown in doxygen. + */ +#if defined(_WIN32) +# if !defined(SOCKET_DEFAULT_BACKEND) +# if defined(SOCKET_HAVE_POLL) +# define SOCKET_DEFAULT_BACKEND Poll +# else +# define SOCKET_DEFAULT_BACKEND Select +# endif +# endif +#elif defined(__linux__) +# include <sys/epoll.h> + +# if !defined(SOCKET_DEFAULT_BACKEND) +# define SOCKET_DEFAULT_BACKEND Epoll +# endif +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) +# include <sys/types.h> +# include <sys/event.h> +# include <sys/time.h> + +# if !defined(SOCKET_DEFAULT_BACKEND) +# define SOCKET_DEFAULT_BACKEND Kqueue +# endif +#else +# if !defined(SOCKET_DEFAULT_BACKEND) +# define SOCKET_DEFAULT_BACKEND Select +# endif +#endif + +#if defined(SOCKET_HAVE_POLL) && !defined(_WIN32) +# include <poll.h> +#endif + +/* + * Headers to include + * ------------------------------------------------------------------ + */ + +#if defined(_WIN32) +# include <cstdlib> + +# include <WinSock2.h> +# include <WS2tcpip.h> +#else +# include <cerrno> + +# include <sys/ioctl.h> +# include <sys/types.h> +# include <sys/socket.h> +# include <sys/un.h> + +# include <arpa/inet.h> + +# include <netinet/in.h> +# include <netinet/tcp.h> + +# include <fcntl.h> +# include <netdb.h> +# include <unistd.h> +#endif + +#if !defined(SOCKET_NO_SSL) +# include <openssl/err.h> +# include <openssl/evp.h> +# include <openssl/ssl.h> +#endif + +#include <cassert> +#include <chrono> +#include <cstdlib> +#include <cstring> +#include <exception> +#include <functional> +#include <map> +#include <memory> +#include <string> +#include <vector> + +namespace irccd { + +/** + * General network namespace. + */ +namespace net { + +/* + * Portables types + * ------------------------------------------------------------------ + * + * The following types are defined differently between Unix and Windows. + */ + +/* {{{ Protocols */ + +#if defined(_WIN32) + +/** + * Socket type, SOCKET. + */ +using Handle = SOCKET; + +/** + * Argument to pass to set. + */ +using ConstArg = const char *; + +/** + * Argument to pass to get. + */ +using Arg = char *; + +#else + +/** + * Socket type, int. + */ +using Handle = int; + +/** + * Argument to pass to set. + */ +using ConstArg = const void *; + +/** + * Argument to pass to get. + */ +using Arg = void *; + +#endif + +/* }}} */ + +/* + * Portable constants + * ------------------------------------------------------------------ + * + * These constants are needed to check functions return codes, they are rarely needed in end user code. + */ + +/* {{{ Constants */ + +/* + * The following constants are defined differently from Unix + * to Windows. + */ +#if defined(_WIN32) + +/** + * Socket creation failure or invalidation. + */ +extern const Handle Invalid; + +/** + * Socket operation failure. + */ +extern const int Failure; + +#else + +/** + * Socket creation failure or invalidation. + */ +extern const int Invalid; + +/** + * Socket operation failure. + */ +extern const int Failure; + +#endif + +#if !defined(SOCKET_NO_SSL) + +namespace ssl { + +/** + * @enum Method + * @brief Which OpenSSL method to use. + */ +enum Method { + Tlsv1, //!< TLS v1.2 (recommended) + Sslv3 //!< SSLv3 +}; + +} // !ssl + +#endif + +/* }}} */ + +/* + * Portable functions + * ------------------------------------------------------------------ + * + * The following free functions can be used to initialize the library or to get the last system error. + */ + +/* {{{ Functions */ + +/** + * Initialize the socket library. Except if you defined SOCKET_NO_AUTO_INIT, you don't need to call this + * function manually. + */ +void init() noexcept; + +/** + * Close the socket library. + */ +void finish() noexcept; + +#if !defined(SOCKET_NO_SSL) + +/** + * OpenSSL namespace. + */ +namespace ssl { + +/** + * Initialize the OpenSSL library. Except if you defined SOCKET_NO_AUTO_SSL_INIT, you don't need to call this function + * manually. + */ +void init() noexcept; + +/** + * Close the OpenSSL library. + */ +void finish() noexcept; + +} // !ssl + +#endif // SOCKET_NO_SSL + +/** + * Get the last socket system error. The error is set from errno or from + * WSAGetLastError on Windows. + * + * @return a string message + */ +std::string error(); + +/** + * Get the last system error. + * + * @param errn the error number (errno or WSAGetLastError) + * @return the error + */ +std::string error(int errn); + +/* }}} */ + +/* + * Error class + * ------------------------------------------------------------------ + * + * This is the main exception thrown on socket operations. + */ + +/* {{{ Error */ + +/** + * @class Error + * @brief Base class for sockets error + */ +class Error : public std::exception { +public: + /** + * @enum Code + * @brief Which kind of error + */ + enum Code { + Timeout, ///!< The action did timeout + System, ///!< There is a system error + Other ///!< Other custom error + }; + +private: + Code m_code; + std::string m_function; + std::string m_error; + +public: + /** + * Constructor that use the last system error. + * + * @param code which kind of error + * @param function the function name + */ + Error(Code code, std::string function); + + /** + * Constructor that use the system error set by the user. + * + * @param code which kind of error + * @param function the function name + * @param error the error + */ + Error(Code code, std::string function, int error); + + /** + * Constructor that set the error specified by the user. + * + * @param code which kind of error + * @param function the function name + * @param error the error + */ + Error(Code code, std::string function, std::string error); + + /** + * Get which function has triggered the error. + * + * @return the function name (e.g connect) + */ + inline const std::string &function() const noexcept + { + return m_function; + } + + /** + * The error code. + * + * @return the code + */ + inline Code code() const noexcept + { + return m_code; + } + + /** + * Get the error (only the error content). + * + * @return the error + */ + const char *what() const noexcept + { + return m_error.c_str(); + } +}; + +/* }}} */ + +/* + * State class + * ------------------------------------------------------------------ + * + * To facilitate higher-level stuff, the socket has a state. + */ + +/* {{{ State */ + +/** + * @enum State + * @brief Current socket state. + */ +enum class State { + Open, //!< Socket is open + Bound, //!< Socket is bound to an address + Connecting, //!< The connection is in progress + Connected, //!< Connection is complete + Accepted, //!< Socket has been accepted (client) + Accepting, //!< The client acceptation is in progress + Closed, //!< The socket has been closed + Disconnected, //!< The connection was lost +}; + +/* }}} */ + +/* + * Action enum + * ------------------------------------------------------------------ + * + * Defines the pending operation. + */ + +/* {{{ Action */ + +/** + * @enum Action + * @brief Define the current operation that must complete. + * + * Some operations like accept, connect, recv or send must sometimes do several round-trips to complete and the socket + * action is set with that enumeration. The user is responsible of calling accept, connect send or recv until the + * operation is complete. + * + * Note: the user must wait for the appropriate condition in Socket::condition to check if the required condition is + * met. + * + * It is important to complete the operation in the correct order because protocols like Tls may require to continue + * re-negociating when calling Socket::send or Socket::Recv. + */ +enum class Action { + None, //!< No action is required, socket is ready + Accept, //!< The socket is not yet accepted, caller must call accept() again + Connect, //!< The socket is not yet connected, caller must call connect() again + Receive, //!< The received operation has not succeeded yet, caller must call recv() or recvfrom() again + Send //!< The send operation has not succeded yet, caller must call send() or sendto() again +}; + +/* }}} */ + +/* + * Condition enum + * ------------------------------------------------------------------ + * + * Defines if we must wait for reading or writing. + */ + +/* {{{ Condition */ + +/** + * @enum Condition + * @brief Define the required condition for the socket. + * + * As explained in Action enumeration, some operations required to be called several times, before calling these + * operations, the user must wait the socket to be readable or writable. This can be checked with Socket::condition. + */ +enum class Condition { + None, //!< No condition is required + Readable = (1 << 0), //!< The socket must be readable + Writable = (1 << 1) //!< The socket must be writable +}; + +/** + * Apply bitwise XOR. + * + * @param v1 the first value + * @param v2 the second value + * @return the new value + */ +constexpr Condition operator^(Condition v1, Condition v2) noexcept +{ + return static_cast<Condition>(static_cast<int>(v1) ^ static_cast<int>(v2)); +} + +/** + * Apply bitwise AND. + * + * @param v1 the first value + * @param v2 the second value + * @return the new value + */ +constexpr Condition operator&(Condition v1, Condition v2) noexcept +{ + return static_cast<Condition>(static_cast<int>(v1) & static_cast<int>(v2)); +} + +/** + * Apply bitwise OR. + * + * @param v1 the first value + * @param v2 the second value + * @return the new value + */ +constexpr Condition operator|(Condition v1, Condition v2) noexcept +{ + return static_cast<Condition>(static_cast<int>(v1) | static_cast<int>(v2)); +} + +/** + * Apply bitwise NOT. + * + * @param v the value + * @return the complement + */ +constexpr Condition operator~(Condition v) noexcept +{ + return static_cast<Condition>(~static_cast<int>(v)); +} + +/** + * Assign bitwise OR. + * + * @param v1 the first value + * @param v2 the second value + * @return the new value + */ +inline Condition &operator|=(Condition &v1, Condition v2) noexcept +{ + v1 = static_cast<Condition>(static_cast<int>(v1) | static_cast<int>(v2)); + + return v1; +} + +/** + * Assign bitwise AND. + * + * @param v1 the first value + * @param v2 the second value + * @return the new value + */ +inline Condition &operator&=(Condition &v1, Condition v2) noexcept +{ + v1 = static_cast<Condition>(static_cast<int>(v1) & static_cast<int>(v2)); + + return v1; +} + +/** + * Assign bitwise XOR. + * + * @param v1 the first value + * @param v2 the second value + * @return the new value + */ +inline Condition &operator^=(Condition &v1, Condition v2) noexcept +{ + v1 = static_cast<Condition>(static_cast<int>(v1) ^ static_cast<int>(v2)); + + return v1; +} + +/* }}} */ + +/* + * Base Socket class + * ------------------------------------------------------------------ + * + * This base class has operations that are common to all types of sockets but you usually instanciate + * a SocketTcp or SocketUdp + */ + +/* {{{ Socket */ + +/** + * @class Socket + * @brief Base socket class for socket operations. + * + * **Important:** When using non-blocking sockets, some considerations must be taken. See the implementation of the + * underlying protocol for more details. + * + * @see protocol::Tls + * @see protocol::Tcp + * @see protocol::Udp + */ +template <typename Address, typename Protocol> +class Socket { +private: + Protocol m_proto; + State m_state{State::Closed}; + Action m_action{Action::None}; + Condition m_condition{Condition::None}; + +protected: + /** + * The native handle. + */ + Handle m_handle{Invalid}; + +public: + /** + * Create a socket handle. + * + * This is the primary function and the only one that creates the socket handle, all other constructors + * are just overloaded functions. + * + * @param domain the domain AF_* + * @param type the type SOCK_* + * @param protocol the protocol + * @param iface the implementation + * @throw net::Error on errors + * @post state is set to Open + * @post handle is not set to Invalid + */ + Socket(int domain, int type, int protocol, Protocol iface = {}) + : m_proto(std::move(iface)) + { +#if !defined(SOCKET_NO_AUTO_INIT) + init(); +#endif + m_handle = ::socket(domain, type, protocol); + + if (m_handle == Invalid) { + throw Error{Error::System, "socket"}; + } + + m_proto.create(*this); + m_state = State::Open; + + assert(m_handle != Invalid); + } + + /** + * This tries to create a socket. + * + * Domain and type are determined by the Address and Protocol object. + * + * @param protocol the protocol + * @param address which type of address + * @throw net::Error on errors + */ + explicit inline Socket(Protocol protocol = {}, const Address &address = {}) + : Socket{address.domain(), protocol.type(), 0, std::move(protocol)} + { + } + + /** + * Construct a socket with an already created descriptor. + * + * @param handle the native descriptor + * @param state specify the socket state + * @param protocol the type of socket implementation + * @post action is set to None + * @post condition is set to None + */ + explicit inline Socket(Handle handle, State state = State::Closed, Protocol protocol = {}) noexcept + : m_proto(std::move(protocol)) + , m_state{state} + , m_handle{handle} + { + assert(m_action == Action::None); + assert(m_condition == Condition::None); + } + + /** + * Create an invalid socket. Can be used when you cannot instanciate the socket immediately. + */ + explicit inline Socket(std::nullptr_t) noexcept + : m_handle{Invalid} + { + } + + /** + * Copy constructor deleted. + */ + Socket(const Socket &) = delete; + + /** + * Transfer ownership from other to this. + * + * @param other the other socket + */ + inline Socket(Socket &&other) noexcept + : m_proto(std::move(other.m_proto)) + , m_state{other.m_state} + , m_action{other.m_action} + , m_condition{other.m_condition} + , m_handle{other.m_handle} + { + /* Invalidate other */ + other.m_handle = Invalid; + other.m_state = State::Closed; + other.m_action = Action::None; + other.m_condition = Condition::None; + } + + /** + * Default destructor. + */ + virtual ~Socket() + { + close(); + } + + /** + * Access the implementation. + * + * @return the implementation + * @warning use this function with care + */ + inline const Protocol &protocol() const noexcept + { + return m_proto; + } + + /** + * Overloaded function. + * + * @return the implementation + */ + inline Protocol &protocol() noexcept + { + return m_proto; + } + + /** + * Get the current socket state. + * + * @return the state + */ + inline State state() const noexcept + { + return m_state; + } + + /** + * Change the current socket state. + * + * @param state the new state + * @warning only implementations should call this function + */ + inline void setState(State state) noexcept + { + m_state = state; + } + + /** + * Get the pending operation. + * + * @return the action to complete before continuing + * @note usually only needed in non-blocking sockets + */ + inline Action action() const noexcept + { + return m_action; + } + + /** + * Change the pending operation. + * + * @param action the action + * @warning you should not call this function yourself + */ + inline void setAction(Action action) noexcept + { + m_action = action; + } + + /** + * Get the condition to wait for. + * + * @return the condition + */ + inline Condition condition() const noexcept + { + return m_condition; + } + + /** + * Change the condition required. + * + * @param condition the condition + * @warning you should not call this function yourself + */ + inline void setCondition(Condition condition) noexcept + { + m_condition = condition; + } + + /** + * Set an option for the socket. Wrapper of setsockopt(2). + * + * @param level the setting level + * @param name the name + * @param arg the value + * @throw net::Error on errors + */ + template <typename Argument> + void set(int level, int name, const Argument &arg) + { + if (setsockopt(m_handle, level, name, (ConstArg)&arg, sizeof (arg)) == Failure) { + throw Error{Error::System, "set"}; + } + } + + /** + * Object-oriented option setter. + * + * The object must have `set(Socket<Address, Protocol> &) const`. + * + * @param option the option + * @throw net::Error on errors + */ + template <typename Option> + inline void set(const Option &option) + { + option.set(*this); + } + + /** + * Get an option for the socket. Wrapper of getsockopt(2). + * + * @param level the setting level + * @param name the name + * @throw net::Error on errors + */ + template <typename Argument> + Argument get(int level, int name) + { + Argument desired, result{}; + socklen_t size = sizeof (result); + + if (getsockopt(m_handle, level, name, (Arg)&desired, &size) == Failure) { + throw Error{Error::System, "get"}; + } + + std::memcpy(&result, &desired, size); + + return result; + } + + /** + * Object-oriented option getter. + * + * The object must have `T get(Socket<Address, Protocol> &) const`, T can be any type and it is the value + * returned from this function. + * + * @return the same value as get() in the option + * @throw net::Error on errors + */ + template <typename Option> + inline auto get() -> decltype(std::declval<Option>().get(*this)) + { + return Option{}.get(*this); + } + + /** + * Get the native handle. + * + * @return the handle + * @warning Not portable + */ + inline Handle handle() const noexcept + { + return m_handle; + } + + /** + * Bind using a native address. + * + * @param address the address + * @param length the size + * @pre state must not be Bound + * @throw net::Error on errors + */ + void bind(const sockaddr *address, socklen_t length) + { + assert(m_state != State::Bound); + + if (::bind(m_handle, address, length) == Failure) { + throw Error{Error::System, "bind"}; + } + + m_state = State::Bound; + } + + /** + * Overload that takes an address. + * + * @param address the address + * @throw net::Error on errors + */ + inline void bind(const Address &address) + { + bind(address.address(), address.length()); + } + + /** + * Listen for pending connection. + * + * @param max the maximum number + * @pre state must be Bound + * @throw net::Error on errors + */ + inline void listen(int max = 128) + { + assert(m_state == State::Bound); + + if (::listen(this->m_handle, max) == Failure) { + throw Error{Error::System, "listen"}; + } + } + + /** + * Connect to the address. + * + * If connection cannot be established immediately, connect with no argument must be called again. See + * the underlying protocol for more information. + * + * @pre state must be State::Open + * @param address the address + * @param length the the address length + * @throw net::Error on errors + * @post state is set to State::Connecting or State::Connected + * @note For non-blocking sockets, see the underlying protocol function for more details + */ + void connect(const sockaddr *address, socklen_t length) + { + assert(m_state == State::Open); + + m_action = Action::None; + m_condition = Condition::None; + + m_proto.connect(*this, address, length); + + assert((m_state == State::Connected && m_action == Action::None && m_condition == Condition::None) || + (m_state == State::Connecting && m_action == Action::Connect && m_condition != Condition::None)); + } + + /** + * Overloaded function. + * + * Effectively call connect(address.address(), address.length()); + * + * @param address the address + */ + inline void connect(const Address &address) + { + connect(address.address(), address.length()); + } + + /** + * Continue the connection, only required with non-blocking sockets. + * + * @pre state must be State::Connecting + * @throw net::Error on errors + */ + void connect() + { + assert(m_state == State::Connecting); + + m_action = Action::None; + m_condition = Condition::None; + + m_proto.connect(*this); + + assert((m_state == State::Connected && m_action == Action::None && m_condition == Condition::None) || + (m_state == State::Connecting && m_action == Action::Connect && m_condition != Condition::None)); + } + + /** + * Accept a new client. If there are no pending connection, throws an error. + * + * If the client cannot be accepted immediately, the client is returned and accept with no arguments + * must be called on it. See the underlying protocol for more information. + * + * @pre state must be State::Bound + * @param info the address where to store client's information (optional) + * @return the new socket + * @throw Error on errors + * @post returned client's state is set to State::Accepting or State::Accepted + * @note For non-blocking sockets, see the underlying protocol function for more details + */ + Socket<Address, Protocol> accept(Address *info) + { + assert(m_state == State::Bound); + + m_action = Action::None; + m_condition = Condition::None; + + sockaddr_storage storage; + socklen_t length = sizeof (storage); + + Socket<Address, Protocol> sc = m_proto.accept(*this, reinterpret_cast<sockaddr *>(&storage), &length); + + if (info) { + *info = Address{&storage, length}; + } + + /* Master do not change */ + assert(m_state == State::Bound); + assert(m_action == Action::None); + assert(m_condition == Condition::None); + + /* Client */ + assert( + (sc.state() == State::Accepting && sc.action() == Action::Accept && sc.condition() != Condition::None) || + (sc.state() == State::Accepted && sc.action() == Action::None && sc.condition() == Condition::None) + ); + + return sc; + } + + /** + * Continue the accept process on this client. This function must be called only when the socket is + * ready to be readable or writable! (see condition). + * + * @pre state must be State::Accepting + * @throw Error on errors + * @post if connection is complete, state is changed to State::Accepted, action and condition are unset + * @post if connection is still in progress, condition is set + */ + void accept() + { + assert(m_state == State::Accepting); + + m_action = Action::None; + m_condition = Condition::None; + + m_proto.accept(*this); + + assert( + (m_state == State::Accepting && m_action == Action::Accept && m_condition != Condition::None) || + (m_state == State::Accepted && m_action == Action::None && m_condition == Condition::None) + ); + } + + /** + * Get the local name. This is a wrapper of getsockname(). + * + * @return the address + * @throw Error on failures + * @pre state() must not be State::Closed + */ + Address address() const + { + assert(m_state != State::Closed); + + sockaddr_storage ss; + socklen_t length = sizeof (sockaddr_storage); + + if (::getsockname(m_handle, (sockaddr *)&ss, &length) == Failure) { + throw Error{Error::System, "getsockname"}; + } + + return Address(&ss, length); + } + + /** + * Receive some data. + * + * If the operation cannot be complete immediately, 0 is returned and user must call the function + * again when ready. See the underlying protocol for more information. + * + * If action is set to Action::None and result is set to 0, disconnection occured. + * + * @param data the destination buffer + * @param length the buffer length + * @pre action must not be Action::Send + * @return the number of bytes received or 0 + * @throw Error on error + * @note For non-blocking sockets, see the underlying protocol function for more details + */ + unsigned recv(void *data, unsigned length) + { + assert(m_action != Action::Send); + + m_action = Action::None; + m_condition = Condition::None; + + unsigned nbread = m_proto.recv(*this, data, length); + + return nbread; + } + + /** + * Overloaded function. + * + * @param count the number of bytes to receive + * @return the string + * @throw Error on error + */ + inline std::string recv(unsigned count) + { + std::string result; + + result.resize(count); + auto n = recv(const_cast<char *>(result.data()), count); + result.resize(n); + + return result; + } + + /** + * Send some data. + * + * If the operation cannot be complete immediately, 0 is returned and user must call the function + * again when ready. See the underlying protocol for more information. + * + * @param data the data buffer + * @param length the buffer length + * @return the number of bytes sent or 0 + * @pre action() must not be Flag::Receive + * @throw Error on error + * @note For non-blocking sockets, see the underlying protocol function for more details + */ + unsigned send(const void *data, unsigned length) + { + assert(m_action != Action::Receive); + + m_action = Action::None; + m_condition = Condition::None; + + unsigned nbsent = m_proto.send(*this, data, length); + + assert((m_action == Action::None && m_condition == Condition::None) || + (m_action == Action::Send && m_condition != Condition::None)); + + return nbsent; + } + + /** + * Overloaded function. + * + * @param data the string to send + * @return the number of bytes sent + * @throw Error on error + */ + inline unsigned send(const std::string &data) + { + return send(data.c_str(), data.size()); + } + + /** + * Send data to an end point. + * + * If the operation cannot be complete immediately, 0 is returned and user must call the function + * again when ready. See the underlying protocol for more information. + * + * @param data the buffer + * @param length the buffer length + * @param address the client address + * @param addrlen the address length + * @return the number of bytes sent + * @throw net::Error on errors + * @note For non-blocking sockets, see the underlying protocol function for more details + */ + inline unsigned sendto(const void *data, unsigned length, const sockaddr *address, socklen_t addrlen) + { + return m_proto.sendto(*this, data, length, address, addrlen); + } + + /** + * Overloaded function. + * + * @param data the buffer + * @param length the buffer length + * @param address the destination + * @return the number of bytes sent + * @throw net::Error on errors + */ + inline unsigned sendto(const void *data, unsigned length, const Address &address) + { + return sendto(data, length, address.address(), address.length()); + } + + /** + * Overloaded function. + * + * @param data the data + * @param address the address + * @return the number of bytes sent + * @throw net:;Error on errors + */ + inline unsigned sendto(const std::string &data, const Address &address) + { + return sendto(data.c_str(), data.length(), address); + } + + /** + * Receive data from an end point. + * + * If the operation cannot be complete immediately, 0 is returned and user must call the function + * again when ready. See the underlying protocol for more information. + * + * @param data the destination buffer + * @param length the buffer length + * @param address the address destination + * @param addrlen the address length (in/out) + * @return the number of bytes received + * @throw net::Error on errors + * @note For non-blocking sockets, see the underlying protocol function for more details + */ + inline unsigned recvfrom(void *data, unsigned length, sockaddr *address, socklen_t *addrlen) + { + return m_proto.recvfrom(*this, data, length, address, addrlen); + } + + /** + * Overloaded function. + * + * @param data the destination buffer + * @param length the buffer length + * @param info the address destination + * @return the number of bytes received + * @throw net::Error on errors + */ + inline unsigned recvfrom(void *data, unsigned length, Address *info = nullptr) + { + sockaddr_storage storage; + socklen_t addrlen = sizeof (sockaddr_storage); + + auto n = recvfrom(data, length, reinterpret_cast<sockaddr *>(&storage), &addrlen); + + if (info && n != 0) { + *info = Address{&storage, addrlen}; + } + + return n; + } + + /** + * Overloaded function. + * + * @param count the maximum number of bytes to receive + * @param info the client information + * @return the string + * @throw net::Error on errors + */ + std::string recvfrom(unsigned count, Address *info = nullptr) + { + std::string result; + + result.resize(count); + auto n = recvfrom(const_cast<char *>(result.data()), count, info); + result.resize(n); + + return result; + } + + /** + * Close the socket. + * + * Automatically called from the destructor. + */ + void close() + { + if (m_handle != Invalid) { +#if defined(_WIN32) + ::closesocket(m_handle); +#else + ::close(m_handle); +#endif + m_handle = Invalid; + } + + m_state = State::Closed; + m_action = Action::None; + m_condition = Condition::None; + } + + /** + * Assignment operator forbidden. + * + * @return *this + */ + Socket &operator=(const Socket &) = delete; + + /** + * Transfer ownership from other to this. The other socket is left + * invalid and will not be closed. + * + * @param other the other socket + * @return this + */ + Socket &operator=(Socket &&other) noexcept + { + m_handle = other.m_handle; + m_proto = std::move(other.m_proto); + m_state = other.m_state; + m_action = other.m_action; + m_condition = other.m_condition; + + /* Invalidate other */ + other.m_handle = Invalid; + other.m_state = State::Closed; + other.m_action = Action::None; + other.m_condition = Condition::None; + + return *this; + } +}; + +/** + * Compare two sockets. + * + * @param s1 the first socket + * @param s2 the second socket + * @return true if they equals + */ +template <typename Address, typename Protocol> +bool operator==(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +{ + return s1.handle() == s2.handle(); +} + +/** + * Compare two sockets. + * + * @param s1 the first socket + * @param s2 the second socket + * @return true if they are different + */ +template <typename Address, typename Protocol> +bool operator!=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +{ + return s1.handle() != s2.handle(); +} + +/** + * Compare two sockets. + * + * @param s1 the first socket + * @param s2 the second socket + * @return true if s1 < s2 + */ +template <typename Address, typename Protocol> +bool operator<(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +{ + return s1.handle() < s2.handle(); +} + +/** + * Compare two sockets. + * + * @param s1 the first socket + * @param s2 the second socket + * @return true if s1 > s2 + */ +template <typename Address, typename Protocol> +bool operator>(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +{ + return s1.handle() > s2.handle(); +} + +/** + * Compare two sockets. + * + * @param s1 the first socket + * @param s2 the second socket + * @return true if s1 <= s2 + */ +template <typename Address, typename Protocol> +bool operator<=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +{ + return s1.handle() <= s2.handle(); +} + +/** + * Compare two sockets. + * + * @param s1 the first socket + * @param s2 the second socket + * @return true if s1 >= s2 + */ +template <typename Address, typename Protocol> +bool operator>=(const Socket<Address, Protocol> &s1, const Socket<Address, Protocol> &s2) +{ + return s1.handle() >= s2.handle(); +} + +/* }}} */ + +/* + * Predefined options + * ------------------------------------------------------------------ + */ + +/* {{{ Options */ + +/** + * Namespace of predefined options. + */ +namespace option { + +/* + * Options for socket + * ------------------------------------------------------------------ + */ + +/* {{{ Options for socket */ + +/** + * @class SockBlockMode + * @brief Set or get the blocking-mode for a socket. + * @warning On Windows, it's not possible to check if the socket is blocking or not. + */ +class SockBlockMode { +public: + /** + * Set to false if you want non-blocking socket. + */ + bool value{false}; + + /** + * Set the option. + * + * @param sc the socket + * @throw Error on errors + */ + template <typename Address, typename Protocol> + void set(Socket<Address, Protocol> &sc) const + { +#if defined(O_NONBLOCK) && !defined(_WIN32) + int flags; + + if ((flags = fcntl(sc.handle(), F_GETFL, 0)) < 0) { + flags = 0; + } + + if (value) { + flags &= ~(O_NONBLOCK); + } else { + flags |= O_NONBLOCK; + } + + if (fcntl(sc.handle(), F_SETFL, flags) < 0) { + throw Error{Error::System, "fcntl"}; + } +#else + unsigned long flags = (value) ? 0 : 1; + + if (ioctlsocket(sc.handle(), FIONBIO, &flags) == Failure) { + throw Error{Error::System, "fcntl"}; + } +#endif + } + + /** + * Get the option. + * + * @return the value + * @throw Error on errors + */ + template <typename Address, typename Protocol> + bool get(Socket<Address, Protocol> &sc) const + { +#if defined(O_NONBLOCK) && !defined(_WIN32) + int flags = fcntl(sc.handle(), F_GETFL, 0); + + if (flags < 0) { + throw Error{Error::System, "fcntl"}; + } + + return !(flags & O_NONBLOCK); +#else + throw Error{Error::Other, "get", "Windows API cannot let you get the blocking status of a socket"}; +#endif + } +}; + +/** + * @class SockReuseAddress + * @brief Reuse address, must be used before calling Socket::bind + */ +class SockReuseAddress { +public: + /** + * Set to true if you want to set the SOL_SOCKET/SO_REUSEADDR option. + */ + bool value{true}; + + /** + * Set the option. + * + * @param sc the socket + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline void set(Socket<Address, Protocol> &sc) const + { + sc.set(SOL_SOCKET, SO_REUSEADDR, value ? 1 : 0); + } + + /** + * Get the option. + * + * @return the value + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline bool get(Socket<Address, Protocol> &sc) const + { + return static_cast<bool>(sc.template get<int>(SOL_SOCKET, SO_REUSEADDR)); + } +}; + +/** + * @class SockSendBuffer + * @brief Set or get the output buffer. + */ +class SockSendBuffer { +public: + /** + * Set to the buffer size. + */ + int value{2048}; + + /** + * Set the option. + * + * @param sc the socket + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline void set(Socket<Address, Protocol> &sc) const + { + sc.set(SOL_SOCKET, SO_SNDBUF, value); + } + + /** + * Get the option. + * + * @return the value + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline int get(Socket<Address, Protocol> &sc) const + { + return sc.template get<int>(SOL_SOCKET, SO_SNDBUF); + } +}; + +/** + * @class SockReceiveBuffer + * @brief Set or get the input buffer. + */ +class SockReceiveBuffer { +public: + /** + * Set to the buffer size. + */ + int value{2048}; + + /** + * Set the option. + * + * @param sc the socket + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline void set(Socket<Address, Protocol> &sc) const + { + sc.set(SOL_SOCKET, SO_RCVBUF, value); + } + + /** + * Get the option. + * + * @return the value + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline int get(Socket<Address, Protocol> &sc) const + { + return sc.template get<int>(SOL_SOCKET, SO_RCVBUF); + } +}; + +/* }}} */ + +/** + * @class TcpNoDelay + * @brief Set this option if you want to disable nagle's algorithm. + */ +class TcpNoDelay { +public: + /** + * Set to true to set TCP_NODELAY option. + */ + bool value{true}; + + /** + * Set the option. + * + * @param sc the socket + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline void set(Socket<Address, Protocol> &sc) const + { + sc.set(IPPROTO_TCP, TCP_NODELAY, value ? 1 : 0); + } + + /** + * Get the option. + * + * @return the value + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline bool get(Socket<Address, Protocol> &sc) const + { + return static_cast<bool>(sc.template get<int>(IPPROTO_TCP, TCP_NODELAY)); + } +}; + +/** + * @class Ipv6Only + * @brief Control IPPROTO_IPV6/IPV6_V6ONLY + * + * Note: some systems may or not set this option by default so it's a good idea to set it in any case to either + * false or true if portability is a concern. + */ +class Ipv6Only { +public: + /** + * Set this to use only IPv6. + */ + bool value{true}; + + /** + * Set the option. + * + * @param sc the socket + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline void set(Socket<Address, Protocol> &sc) const + { + sc.set(IPPROTO_IPV6, IPV6_V6ONLY, value ? 1 : 0); + } + + /** + * Get the option. + * + * @return the value + * @throw Error on errors + */ + template <typename Address, typename Protocol> + inline bool get(Socket<Address, Protocol> &sc) const + { + return static_cast<bool>(sc.template get<int>(IPPROTO_IPV6, IPV6_V6ONLY)); + } +}; + +} // !option + +/* }}} */ + +/* + * Predefined addressed to be used + * ------------------------------------------------------------------ + * + * - Ip, + * - Local. + */ + +/* {{{ Addresses */ + +/** + * Set of predefined addresses. + */ +namespace address { + +/** + * @class Ip + * @brief Base class for IPv6 and IPv4, you can use it if you don't know in advance if you'll use IPv6 or IPv4. + */ +class Ip { +public: + /** + * @enum Type + * @brief Type of ip address. + */ + enum Type { + v4 = AF_INET, //!< AF_INET + v6 = AF_INET6 //!< AF_INET6 + }; + +private: + /* + * Default domain when using default constructors. + * + * Note: AF_INET or AF_INET6, not + */ + static int m_default; + + union { + sockaddr_in m_sin; + sockaddr_in6 m_sin6; + }; + + socklen_t m_length{0}; + int m_domain{AF_INET}; + +public: + /** + * Set the default domain to use when using default Ip constructor. By default, AF_INET is used. + * + * @pre domain must be Type::v4 or Type::v6 + */ + static inline void setDefault(Type domain) noexcept + { + assert(domain == Type::v4 || domain == Type::v6); + + m_default = static_cast<int>(domain); + } + + /** + * Construct using the default domain. + */ + inline Ip() noexcept + : Ip(static_cast<Type>(m_default)) + { + } + + /** + * Default initialize the Ip domain. + * + * @pre domain must be AF_INET or AF_INET6 only + * @param domain the domain (AF_INET or AF_INET6) + */ + Ip(Type domain) noexcept; + + /** + * Construct an address suitable for bind() or connect(). + * + * @pre domain must be Type::v4 or Type::v6 + * @param domain the domain (AF_INET or AF_INET6) + * @param host the host (* for any) + * @param port the port number + * @throw Error on errors + */ + Ip(const std::string &host, int port, Type domain = v4); + + /** + * Construct an address from a storage. + * + * @pre storage's domain must be AF_INET or AF_INET6 only + * @param ss the storage + * @param length the length + */ + Ip(const sockaddr_storage *ss, socklen_t length) noexcept; + + /** + * Get the domain (AF_INET or AF_INET6). + * + * @return the domain + */ + inline int domain() const noexcept + { + return m_domain; + } + + /** + * Return the underlying address, either sockaddr_in6 or sockaddr_in. + * + * @return the address + */ + inline const sockaddr *address() const noexcept + { + if (m_domain == AF_INET6) { + return reinterpret_cast<const sockaddr *>(&m_sin6); + } + + return reinterpret_cast<const sockaddr *>(&m_sin); + } + + /** + * Return the underlying address length. + * + * @return the length + */ + inline socklen_t length() const noexcept + { + return m_length; + } + + /** + * Get the port. + * + * @return the port + */ + inline int port() const noexcept + { + if (m_domain == AF_INET6) { + return ntohs(m_sin6.sin6_port); + } + + return ntohs(m_sin.sin_port); + } +}; + +#if !defined(_WIN32) + +/** + * @class Local + * @brief unix family sockets + * + * Create an address to a specific path. Only available on Unix. + */ +class Local { +private: + sockaddr_un m_sun; + std::string m_path; + +public: + /** + * Get the domain AF_LOCAL. + * + * @return AF_LOCAL + */ + inline int domain() const noexcept + { + return AF_LOCAL; + } + + /** + * Default constructor. + */ + Local() noexcept; + + /** + * Construct an address to a path. + * + * @param path the path + * @param rm remove the file before (default: false) + */ + Local(std::string path, bool rm = false) noexcept; + + /** + * Construct an unix address from a storage address. + * + * @pre storage's domain must be AF_LOCAL + * @param ss the storage + * @param length the length + */ + Local(const sockaddr_storage *ss, socklen_t length) noexcept; + + /** + * Get the sockaddr_un. + * + * @return the address + */ + inline const sockaddr *address() const noexcept + { + return reinterpret_cast<const sockaddr *>(&m_sun); + } + + /** + * Get the address length. + * + * @return the length + */ + inline socklen_t length() const noexcept + { +#if defined(SOCKET_HAVE_SUN_LEN) + return SUN_LEN(&m_sun); +#else + return sizeof (m_sun); +#endif + } +}; + +#endif // !_WIN32 + +} // !address + +/* }}} */ + +/* + * Predefined protocols + * ------------------------------------------------------------------ + * + * - Tcp, for standard stream connections, + * - Udp, for standard datagram connections, + * - Tls, for secure stream connections. + */ + +/* {{{ Protocols */ + +/** + * Set of predefined protocols. + */ +namespace protocol { + +/* {{{ Tcp */ + +/** + * @class Tcp + * @brief Clear TCP implementation. + * + * This is the basic TCP protocol that implements recv, send, connect and accept as wrappers of the usual + * C functions. + */ +class Tcp { +public: + /** + * Socket type. + * + * @return SOCK_STREAM + */ + inline int type() const noexcept + { + return SOCK_STREAM; + } + + /** + * Do nothing. + * + * This function is just present for compatibility, it should never be called. + */ + template <typename Address> + inline void create(Socket<Address, Tcp> &) const noexcept + { + /* No-op */ + } + + /** + * Standard connect. + * + * If the socket is marked non-blocking and the connection cannot be established immediately, then the + * following is true: + * + * - state is set to State::Connecting, + * - action is set to Action::Connect, + * - condition is set to Condition::Writable. + * + * Then the user must wait until the socket is writable and call connect() with 0 arguments. + * + * If the socket is blocking, this function blocks until the connection is complete or an error occurs, in + * that case state is either set to State::Connected or State::Disconnected but action and condition are + * not set. + * + * @param sc the socket + * @param address the address + * @param length the length + * @throw net::Error on errors + * @note Wrapper of connect(2) + */ + template <typename Address, typename Protocol> + void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length) + { + if (::connect(sc.handle(), address, length) == Failure) { + /* + * Determine if the error comes from a non-blocking connect that cannot be + * accomplished yet. + */ +#if defined(_WIN32) + int error = WSAGetLastError(); + + if (error == WSAEWOULDBLOCK) { + sc.setState(State::Connecting); + sc.setAction(Action::Connect); + sc.setCondition(Condition::Writable); + } else { + sc.setState(State::Disconnected); + throw Error{Error::System, "connect", error}; + } +#else + if (errno == EINPROGRESS) { + sc.setState(State::Connecting); + sc.setAction(Action::Connect); + sc.setCondition(Condition::Writable); + } else { + sc.setState(State::Disconnected); + throw Error{Error::System, "connect"}; + } +#endif + } else { + sc.setState(State::Connected); + } + } + + /** + * Continue the connection. This function must only be called when the socket is ready for writing, + * the user is responsible of waiting for that condition. + * + * This function check for SOL_SOCKET/SO_ERROR status. + * + * If the connection is complete, status is set to State::Connected, otherwise it is set to + * State::Disconnected. In both cases, action and condition are not set. + * + * @param sc the socket + * @throw net::Error on errors + */ + template <typename Address, typename Protocol> + void connect(Socket<Address, Protocol> &sc) + { + int error = sc.template get<int>(SOL_SOCKET, SO_ERROR); + + if (error == Failure) { + sc.setState(State::Disconnected); + throw Error{Error::System, "connect", error}; + } + + sc.setState(State::Connected); + } + + /** + * Accept a clear client. + * + * If the socket is marked non-blocking and there are no pending connection, this function throws an + * error. The user must wait that the socket is readable before calling this function. + * + * If the socket is blocking, this function blocks until a new client is connected or throws an error on + * errors. + * + * If the socket is correctly returned, its state is set to State::Accepted and its action and condition + * are not set. + * + * In any case, action and condition of this socket are not set. + * + * @param sc the socket + * @param address the address destination + * @param length the address length + * @return the socket + * @throw net::Error on errors + * @note Wrapper of accept(2) + */ + template <typename Address, typename Protocol> + Socket<Address, Protocol> accept(Socket<Address, Protocol> &sc, sockaddr *address, socklen_t *length) + { + Handle handle = ::accept(sc.handle(), address, length); + + if (handle == Invalid) { + throw Error{Error::System, "accept"}; + } + + return Socket<Address, Protocol>{handle, State::Accepted}; + } + + /** + * Continue accept. + * + * This function is just present for compatibility, it should never be called. + */ + template <typename Address, typename Protocol> + inline void accept(Socket<Address, Protocol> &) const noexcept + { + /* no-op */ + } + + /** + * Receive data. + * + * If the socket is marked non-blocking and no data is available, 0 is returned and condition is set to + * Condition::Readable. If 0 is returned and condition is not set, then the state is set to + * State::Disconnected. + * + * If the socket is blocking, this function blocks until some data is available or if an error occurs. + * + * In any case, action is never set. + * + * @param sc the socket + * @param data the destination + * @param length the destination length + * @return the number of bytes read + * @throw Error on errors + * @note Wrapper of recv(2) + */ + template <typename Address> + unsigned recv(Socket<Address, Tcp> &sc, void *data, unsigned length) + { + int nbread = ::recv(sc.handle(), (Arg)data, length, 0); + + if (nbread == Failure) { +#if defined(_WIN32) + int error = WSAGetLastError(); + + if (error == WSAEWOULDBLOCK) { + nbread = 0; + sc.setCondition(Condition::Readable); + } else { + sc.setState(State::Disconnected); + throw Error{Error::System, "recv", error}; + } +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) { + sc.setCondition(Condition::Readable); + } else { + sc.setState(State::Disconnected); + throw Error{Error::System, "recv"}; + } +#endif + } else if (nbread == 0) { + sc.setState(State::Disconnected); + } + + return static_cast<unsigned>(nbread); + } + + /** + * Send some data. + * + * If the socket is marked non-blocking and the operation would block, then 0 is returned and condition is set to + * Condition::Writable. + * + * If the socket is blocking, this function blocks until the data has been sent. + * + * On any other errors, this function throw net::Error. + * + * @param sc the socket + * @param data the buffer to send + * @param length the buffer length + * @return the number of bytes sent + * @throw net::Error on errors + * @note Wrapper of send(2) + */ + template <typename Address> + unsigned send(Socket<Address, Tcp> &sc, const void *data, unsigned length) + { + int nbsent = ::send(sc.handle(), (ConstArg)data, length, 0); + + if (nbsent == Failure) { +#if defined(_WIN32) + int error = WSAGetLastError(); + + if (error == WSAEWOULDBLOCK) { + nbsent = 0; + sc.setCondition(Condition::Writable); + } else { + sc.setState(State::Disconnected); + throw Error{Error::System, "send", error}; + } +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) { + nbsent = 0; + sc.setCondition(Condition::Writable); + } else { + sc.setState(State::Disconnected); + throw Error{Error::System, "send"}; + } +#endif + } + + return static_cast<unsigned>(nbsent); + } +}; + +/* }}} */ + +/* {{{ Udp */ + +/** + * @class Udp + * @brief Clear UDP type. + * + * This class is the basic implementation of UDP sockets. + */ +class Udp { +public: + /** + * Socket type. + * + * @return SOCK_DGRAM + */ + inline int type() const noexcept + { + return SOCK_DGRAM; + } + + /** + * Do nothing. + */ + template <typename Address> + inline void create(Socket<Address, Udp> &) noexcept + { + /* No-op */ + } + + /** + * Receive data from an end point. + * + * If the socket is marked non-blocking and no data is available, 0 is returned and condition is set to + * Condition::Readable. + * + * If the socket is blocking, this functions blocks until some data is available or if an error occurs. + * + * @param sc the socket + * @param data the destination buffer + * @param length the buffer length + * @param address the address + * @param addrlen the initial address length + * @return the number of bytes received + * @throw Error on error + */ + template <typename Address> + unsigned recvfrom(Socket<Address, Udp> &sc, void *data, unsigned length, sockaddr *address, socklen_t *addrlen) + { + int nbread; + + nbread = ::recvfrom(sc.handle(), (Arg)data, length, 0, address, addrlen); + + if (nbread == Failure) { +#if defined(_WIN32) + int error = WSAGetLastError(); + + if (error == WSAEWOULDBLOCK) { + nbread = 0; + sc.setCondition(Condition::Readable); + } else { + throw Error{Error::System, "recvfrom"}; + } +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) { + nbread = 0; + sc.setCondition(Condition::Readable); + } else { + throw Error{Error::System, "recvfrom"}; + } +#endif + } + + return static_cast<unsigned>(nbread); + } + + /** + * Send data to an end point. + * + * If the socket is marked non-blocking and the operation would block, then 0 is returned and condition is set to + * Condition::Writable. + * + * If the socket is blocking, this functions blocks until the data has been sent. + * + * @param sc the socket + * @param data the buffer + * @param length the buffer length + * @param address the client address + * @param addrlen the adderss length + * @return the number of bytes sent + * @throw Error on error + */ + template <typename Address> + unsigned sendto(Socket<Address, Udp> &sc, const void *data, unsigned length, const sockaddr *address, socklen_t addrlen) + { + int nbsent; + + nbsent = ::sendto(sc.handle(), (ConstArg)data, length, 0, address, addrlen); + if (nbsent == Failure) { +#if defined(_WIN32) + int error = WSAGetLastError(); + + if (error == WSAEWOULDBLOCK) { + nbsent = 0; + sc.setCondition(Condition::Writable); + } else { + throw Error{Error::System, "sendto", error}; + } +#else + if (errno == EAGAIN || errno == EWOULDBLOCK) { + nbsent = 0; + sc.setCondition(Condition::Writable); + } else { + throw Error{Error::System, "sendto"}; + } +#endif + } + + return static_cast<unsigned>(nbsent); + } +}; + +/* }}} */ + +/* {{{ Tls */ + +#if !defined(SOCKET_NO_SSL) + +/** + * @class Tls + * @brief OpenSSL secure layer for TCP. + * + * **Note:** This protocol is much more difficult to use with non-blocking sockets, if some operations would block, the + * user is responsible of calling the function again by waiting for the appropriate condition. See the functions for + * more details. + * + * @see Tls::accept + * @see Tls::connect + * @see Tls::recv + * @see Tls::send + */ +class Tls : private Tcp { +private: + using Context = std::shared_ptr<SSL_CTX>; + using Ssl = std::unique_ptr<SSL, void (*)(SSL *)>; + + /* OpenSSL objects */ + Context m_context; + Ssl m_ssl{nullptr, nullptr}; + + /* Status */ + bool m_tcpconnected{false}; + + /* + * User definable parameters + */ + ssl::Method m_method{ssl::Tlsv1}; + std::string m_key; + std::string m_certificate; + bool m_verify{false}; + + /* + * Construct with a context and ssl, for Tls::accept. + */ + Tls(Context context, Ssl ssl) + : m_context{std::move(context)} + , m_ssl{std::move(ssl)} + { + } + + /* + * Get the OpenSSL error message. + */ + inline std::string error(int error) + { + auto msg = ERR_reason_error_string(error); + + return msg == nullptr ? "" : msg; + } + + /* + * Update the states after an uncompleted operation. + */ + template <typename Address, typename Protocol> + inline void updateStates(Socket<Address, Protocol> &sc, State state, Action action, int code) + { + assert(code == SSL_ERROR_WANT_READ || code == SSL_ERROR_WANT_WRITE); + + sc.setState(state); + sc.setAction(action); + + if (code == SSL_ERROR_WANT_READ) { + sc.setCondition(Condition::Readable); + } else { + sc.setCondition(Condition::Writable); + } + } + + /* + * Continue the connect operation. + */ + template <typename Address, typename Protocol> + void processConnect(Socket<Address, Protocol> &sc) + { + int ret = SSL_connect(m_ssl.get()); + + if (ret <= 0) { + int no = SSL_get_error(m_ssl.get(), ret); + + if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) { + updateStates(sc, State::Connecting, Action::Connect, no); + } else { + sc.setState(State::Disconnected); + throw Error{Error::System, "connect", error(no)}; + } + } else { + sc.setState(State::Connected); + } + } + + /* + * Continue accept. + */ + template <typename Address, typename Protocol> + void processAccept(Socket<Address, Protocol> &sc) + { + int ret = SSL_accept(m_ssl.get()); + + if (ret <= 0) { + int no = SSL_get_error(m_ssl.get(), ret); + + if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) { + updateStates(sc, State::Accepting, Action::Accept, no); + } else { + sc.setState(State::Disconnected); + throw Error(Error::System, "accept", error(no)); + } + } else { + sc.setState(State::Accepted); + } + } + +public: + /** + * @copydoc Tcp::type + */ + inline int type() const noexcept + { + return SOCK_STREAM; + } + + /** + * Empty TLS constructor. + */ + Tls() + { +#if !defined(SOCKET_NO_SSL_AUTO_INIT) + net::ssl::init(); +#endif + } + + /** + * Set the method. + * + * @param method the method + * @pre the socket must not be already created + */ + inline void setMethod(ssl::Method method) noexcept + { + assert(!m_context); + assert(!m_ssl); + + m_method = method; + } + + /** + * Use the specified private key file. + * + * @param file the path to the private key + */ + inline void setPrivateKey(std::string file) noexcept + { + m_key = std::move(file); + } + + /** + * Use the specified certificate file. + * + * @param file the path to the file + */ + inline void setCertificate(std::string file) noexcept + { + m_certificate = std::move(file); + } + + /** + * Set to true if we must verify the certificate and private key. + * + * @param verify the mode + */ + inline void setVerify(bool verify = true) noexcept + { + m_verify = verify; + } + + /** + * Initialize the SSL objects after have created. + * + * @param sc the socket + * @throw net::Error on errors + */ + template <typename Address> + inline void create(Socket<Address, Tls> &sc) + { + auto method = (m_method == ssl::Tlsv1) ? TLSv1_method() : SSLv23_method(); + + m_context = {SSL_CTX_new(method), SSL_CTX_free}; + m_ssl = {SSL_new(m_context.get()), SSL_free}; + + SSL_set_fd(m_ssl.get(), sc.handle()); + + /* Load certificates */ + if (m_certificate.size() > 0) { + SSL_CTX_use_certificate_file(m_context.get(), m_certificate.c_str(), SSL_FILETYPE_PEM); + } + if (m_key.size() > 0) { + SSL_CTX_use_PrivateKey_file(m_context.get(), m_key.c_str(), SSL_FILETYPE_PEM); + } + if (m_verify && !SSL_CTX_check_private_key(m_context.get())) { + throw Error{Error::System, "(openssl)", "unable to verify key"}; + } + } + + /** + * Connect to a secure host. + * + * If the socket is marked non-blocking and the connection cannot be established yet, then the state is set + * to State::Connecting, the condition is set to Condition::Readable or Condition::Writable, the user must + * wait for the appropriate condition before calling the overload connect which takes 0 argument. + * + * If the socket is blocking, this functions blocks until the connection is complete. + * + * If the connection was completed correctly the state is set to State::Connected. + * + * @param sc the socket + * @param address the address + * @param length the address length + * @throw net::Error on errors + */ + template <typename Address, typename Protocol> + void connect(Socket<Address, Protocol> &sc, const sockaddr *address, socklen_t length) + { + /* 1. Connect using raw TCP */ + Tcp::connect(sc, address, length); + + /* 2. If the connection is complete (e.g. non-blocking), try handshake */ + if (sc.state() == State::Connected) { + m_tcpconnected = true; + processConnect(sc); + } + } + + /** + * Continue the connection. + * + * This function must be called when the socket is ready for reading or writing (check with Socket::condition), + * the state may change exactly like the initial connect call. + * + * @param sc the socket + * @throw net::Error on errors + */ + template <typename Address, typename Protocol> + void connect(Socket<Address, Protocol> &sc) + { + /* 1. Be sure to complete standard connect before */ + if (!m_tcpconnected) { + Tcp::connect(sc); + m_tcpconnected = sc.state() == State::Connected; + } + + if (m_tcpconnected) { + processConnect(sc); + } + } + + /** + * Accept a secure client. + * + * Because SSL needs several round-trips, if the socket is marked non-blocking and the connection is not + * completed yet, a new socket is returned but with the State::Accepting state. Its condition is set to + * Condition::Readable or Condition::Writable, the user is responsible of calling accept overload which takes + * 0 arguments on the returned socket when the condition is met. + * + * If the socket is blocking, this function blocks until the client is accepted and returned. + * + * If the client is accepted correctly, its state is set to State::Accepted. This instance does not change. + * + * @param sc the socket + * @param address the address destination + * @param length the address length + * @return the client + * @throw net::Error on errors + */ + template <typename Address> + Socket<Address, Tls> accept(Socket<Address, Tls> &sc, sockaddr *address, socklen_t *length) + { + Socket<Address, Tls> client = Tcp::accept(sc, address, length); + Tls &proto = client.protocol(); + + /* 1. Share the context */ + proto.m_context = m_context; + + /* 2. Create new SSL instance */ + proto.m_ssl = Ssl{SSL_new(m_context.get()), SSL_free}; + SSL_set_fd(proto.m_ssl.get(), client.handle()); + + /* 3. Try accept process on the **new** client */ + proto.processAccept(client); + + return client; + } + + /** + * Continue accept. + * + * This function must be called on the client that is being accepted. + * + * Like accept or connect, user is responsible of calling this function until the connection is complete. + * + * @param sc the socket + * @throw net::Error on errors + */ + template <typename Address, typename Protocol> + inline void accept(Socket<Address, Protocol> &sc) + { + processAccept(sc); + } + + /** + * Receive some secure data. + * + * If the socket is marked non-blocking, 0 is returned if no data is available yet or if the connection + * needs renegociation. If renegociation is required case, the action is set to Action::Receive and condition + * is set to Condition::Readable or Condition::Writable. The user must wait that the condition is met and + * call this function again. + * + * @param sc the socket + * @param data the destination + * @param len the buffer length + * @return the number of bytes read + * @throw net::Error on errors + */ + template <typename Address> + unsigned recv(Socket<Address, Tls> &sc, void *data, unsigned len) + { + auto nbread = SSL_read(m_ssl.get(), data, len); + + if (nbread <= 0) { + auto no = SSL_get_error(m_ssl.get(), nbread); + + if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) { + nbread = 0; + updateStates(sc, sc.state(), Action::Receive, no); + } else { + throw Error{Error::System, "recv", error(no)}; + } + } + + return nbread; + } + + /** + * Send some data. + * + * Like recv, if the socket is marked non-blocking and no data can be sent or a negociation is required, + * condition and action are set. See receive for more details + * + * @param sc the socket + * @param data the data to send + * @param len the buffer length + * @return the number of bytes sent + * @throw net::Error on errors + */ + template <typename Address> + unsigned send(Socket<Address, Tls> &sc, const void *data, unsigned len) + { + auto nbsent = SSL_write(m_ssl.get(), data, len); + + if (nbsent <= 0) { + auto no = SSL_get_error(m_ssl.get(), nbsent); + + if (no == SSL_ERROR_WANT_READ || no == SSL_ERROR_WANT_WRITE) { + nbsent = 0; + updateStates(sc, sc.state(), Action::Send, no); + } else { + throw Error{Error::System, "send", error(no)}; + } + } + + return nbsent; + } +}; + +#endif // !SOCKET_NO_SSL + +/* }}} */ + +} // !protocol + +/* }}} */ + +/* + * Convenient helpers + * ------------------------------------------------------------------ + * + * - SocketTcp<Address>, for TCP sockets, + * - SocketUdp<Address>, for UDP sockets, + * - SocketTls<Address>, for secure TCP sockets. + */ + +/* {{{ Helpers */ + +/** + * Helper to create TCP sockets. + */ +template <typename Address> +using SocketTcp = Socket<Address, protocol::Tcp>; + +/** + * Helper to create TCP/IP sockets. + */ +using SocketTcpIp = Socket<address::Ip, protocol::Tcp>; + +#if !defined(_WIN32) + +/** + * Helper to create TCP/Local sockets. + */ +using SocketTcpLocal = Socket<address::Local, protocol::Tcp>; + +#endif + +/** + * Helper to create UDP sockets. + */ +template <typename Address> +using SocketUdp = Socket<Address, protocol::Udp>; + +/** + * Helper to create UDP/IP sockets. + */ +using SocketUdpIp = Socket<address::Ip, protocol::Udp>; + +#if !defined(SOCKET_NO_SSL) + +/** + * Helper to create OpenSSL TCP sockets. + */ +template <typename Address> +using SocketTls = Socket<Address, protocol::Tls>; + +/** + * Helper to create OpenSSL TCP/Ip sockets. + */ +using SocketTlsIp = Socket<address::Ip, protocol::Tls>; + +#endif // !SOCKET_NO_SSL + +/* }}} */ + +/* + * Select wrapper + * ------------------------------------------------------------------ + * + * Wrapper for select(2) and other various implementations. + */ + +/* {{{ Listener */ + +/** + * @class ListenerStatus + * @brief Result of polling + * + * Result of a select call, returns the first ready socket found with its + * flags. + */ +class ListenerStatus { +public: + Handle socket; //!< which socket is ready + Condition flags; //!< the flags +}; + +/** + * Table used in the socket listener to store which sockets have been + * set in which directions. + */ +using ListenerTable = std::map<Handle, Condition>; + +/** + * @class Select + * @brief Implements select(2) + * + * This class is the fallback of any other method, it is not preferred at all for many reasons. + */ +class Select { +public: + /** + * No-op, uses the ListenerTable directly. + */ + inline void set(const ListenerTable &, Handle, Condition, bool) noexcept {} + + /** + * No-op, uses the ListenerTable directly. + */ + inline void unset(const ListenerTable &, Handle, Condition, bool) noexcept {} + + /** + * Return the sockets + */ + std::vector<ListenerStatus> wait(const ListenerTable &table, int ms); + + /** + * Backend identifier + */ + inline const char *name() const noexcept + { + return "select"; + } +}; + +#if defined(SOCKET_HAVE_POLL) + +/** + * @class Poll + * @brief Implements poll(2). + * + * Poll is widely supported and is better than select(2). It is still not the + * best option as selecting the sockets is O(n). + */ +class Poll { +private: + std::vector<pollfd> m_fds; + + short toPoll(Condition flags) const noexcept; + Condition toCondition(short &event) const noexcept; + +public: + /** + * Set the handle. + */ + void set(const ListenerTable &, Handle, Condition, bool); + + /** + * Unset the handle. + */ + void unset(const ListenerTable &, Handle, Condition, bool); + + /** + * Wait for events. + */ + std::vector<ListenerStatus> wait(const ListenerTable &, int ms); + + /** + * Backend identifier + */ + inline const char *name() const noexcept + { + return "poll"; + } +}; + +#endif + +#if defined(SOCKET_HAVE_EPOLL) + +/** + * @class Epoll + * @brief Linux's epoll. + */ +class Epoll { +private: + int m_handle; + std::vector<epoll_event> m_events; + + Epoll(const Epoll &) = delete; + Epoll &operator=(const Epoll &) = delete; + Epoll(const Epoll &&) = delete; + Epoll &operator=(const Epoll &&) = delete; + + uint32_t toEpoll(Condition flags) const noexcept; + Condition toCondition(uint32_t events) const noexcept; + void update(Handle sc, int op, int eflags); + +public: + /** + * Construct the epoll instance. + */ + Epoll(); + + /** + * Close the epoll instance. + */ + ~Epoll(); + + /** + * Set the handle. + */ + void set(const ListenerTable &, Handle, Condition, bool); + + /** + * Unset the handle. + */ + void unset(const ListenerTable &, Handle, Condition, bool); + + /** + * Wait for events. + */ + std::vector<ListenerStatus> wait(const ListenerTable &, int); + + /** + * Backend identifier + */ + inline const char *name() const noexcept + { + return "epoll"; + } +}; + +#endif + +#if defined(SOCKET_HAVE_KQUEUE) + +/** + * @class Kqueue + * @brief Implements kqueue(2). + * + * This implementation is available on all BSD and Mac OS X. It is better than + * poll(2) because it's O(1), however it's a bit more memory consuming. + */ +class Kqueue { +private: + std::vector<struct kevent> m_result; + int m_handle; + + Kqueue(const Kqueue &) = delete; + Kqueue &operator=(const Kqueue &) = delete; + Kqueue(Kqueue &&) = delete; + Kqueue &operator=(Kqueue &&) = delete; + + void update(Handle sc, int filter, int kflags); + +public: + /** + * Construct the kqueue instance. + */ + Kqueue(); + + /** + * Destroy the kqueue instance. + */ + ~Kqueue(); + + /** + * Set the handle. + */ + void set(const ListenerTable &, Handle, Condition, bool); + + /** + * Unset the handle. + */ + void unset(const ListenerTable &, Handle, Condition, bool); + + /** + * Wait for events. + */ + std::vector<ListenerStatus> wait(const ListenerTable &, int); + + /** + * Backend identifier + */ + inline const char *name() const noexcept + { + return "kqueue"; + } +}; + +#endif + +/** + * @class Listener + * @brief Synchronous multiplexing + * + * Convenient wrapper around the select() system call. + * + * This class is implemented using a bridge pattern to allow different uses + * of listener implementation. + * + * You should not reinstanciate a new Listener at each iteartion of your + * main loop as it can be extremely costly. Instead use the same listener that + * you can safely modify on the fly. + * + * Currently, poll, epoll, select and kqueue are available. + * + * To implement the backend, the following functions must be available: + * + * ### Set + * + * @code + * void set(const ListenerTable &, Handle sc, Condition condition, bool add); + * @endcode + * + * This function, takes the socket to be added and the flags. The condition is + * always guaranteed to be correct and the function will never be called twice + * even if the user tries to set the same flag again. + * + * An optional add argument is added for backends which needs to do different + * operation depending if the socket was already set before or if it is the + * first time (e.g EPOLL_CTL_ADD vs EPOLL_CTL_MOD for epoll(7). + * + * ### Unset + * + * @code + * void unset(const ListenerTable &, Handle sc, Condition condition, bool remove); + * @endcode + * + * Like set, this function is only called if the condition is actually set and will + * not be called multiple times. + * + * Also like set, an optional remove argument is set if the socket is being + * completely removed (e.g no more flags are set for this socket). + * + * ### Wait + * + * @code + * std::vector<ListenerStatus> wait(const ListenerTable &, int ms); + * @endcode + * + * Wait for the sockets to be ready with the specified milliseconds. Must return a list of ListenerStatus, + * may throw any exceptions. + * + * ### Name + * + * @code + * inline const char *name() const noexcept + * @endcode + * + * Returns the backend name. Usually the class in lower case. + */ +template <typename Backend = SOCKET_DEFAULT_BACKEND> +class Listener { +private: + Backend m_backend; + ListenerTable m_table; + +public: + /** + * Construct an empty listener. + */ + Listener() = default; + + /** + * Get the backend. + * + * @return the backend + */ + inline const Backend &backend() const noexcept + { + return m_backend; + } + + /** + * Get the non-modifiable table. + * + * @return the table + */ + inline const ListenerTable &table() const noexcept + { + return m_table; + } + + /** + * Overloaded function. + * + * @return the iterator + */ + inline ListenerTable::const_iterator begin() const noexcept + { + return m_table.begin(); + } + + /** + * Overloaded function. + * + * @return the iterator + */ + inline ListenerTable::const_iterator cbegin() const noexcept + { + return m_table.cbegin(); + } + + /** + * Overloaded function. + * + * @return the iterator + */ + inline ListenerTable::const_iterator end() const noexcept + { + return m_table.end(); + } + + /** + * Overloaded function. + * + * @return the iterator + */ + inline ListenerTable::const_iterator cend() const noexcept + { + return m_table.cend(); + } + + /** + * Add or update a socket to the listener. + * + * If the socket is already placed with the appropriate flags, the + * function is a no-op. + * + * If incorrect flags are passed, the function does nothing. + * + * @param sc the socket + * @param condition the condition (may be OR'ed) + * @throw Error if the backend failed to set + */ + void set(Handle sc, Condition condition) + { + /* Invalid or useless flags */ + if (condition == Condition::None || static_cast<int>(condition) > 0x3) + return; + + auto it = m_table.find(sc); + + /* + * Do not update the table if the backend failed to add + * or update. + */ + if (it == m_table.end()) { + m_backend.set(m_table, sc, condition, true); + m_table.emplace(sc, condition); + } else { + /* Remove flag if already present */ + if ((condition & Condition::Readable) == Condition::Readable && + (it->second & Condition::Readable) == Condition::Readable) { + condition &= ~(Condition::Readable); + } + if ((condition & Condition::Writable) == Condition::Writable && + (it->second & Condition::Writable) == Condition::Writable) { + condition &= ~(Condition::Writable); + } + + /* Still need a call? */ + if (condition != Condition::None) { + m_backend.set(m_table, sc, condition, false); + it->second |= condition; + } + } + } + + /** + * Unset a socket from the listener, only the flags is removed + * unless the two flagss are requested. + * + * For example, if you added a socket for both reading and writing, + * unsetting the write flags will keep the socket for reading. + * + * @param sc the socket + * @param condition the condition (may be OR'ed) + * @see remove + */ + void unset(Handle sc, Condition condition) + { + auto it = m_table.find(sc); + + /* Invalid or useless flags */ + if (condition == Condition::None || static_cast<int>(condition) > 0x3 || it == m_table.end()) + return; + + /* + * Like set, do not update if the socket is already at the appropriate + * state. + */ + if ((condition & Condition::Readable) == Condition::Readable && + (it->second & Condition::Readable) != Condition::Readable) { + condition &= ~(Condition::Readable); + } + if ((condition & Condition::Writable) == Condition::Writable && + (it->second & Condition::Writable) != Condition::Writable) { + condition &= ~(Condition::Writable); + } + + if (condition != Condition::None) { + /* Determine if it's a complete removal */ + bool removal = ((it->second) & ~(condition)) == Condition::None; + + m_backend.unset(m_table, sc, condition, removal); + + if (removal) { + m_table.erase(it); + } else { + it->second &= ~(condition); + } + } + } + + /** + * Remove completely the socket from the listener. + * + * It is a shorthand for unset(sc, Condition::Readable | Condition::Writable); + * + * @param sc the socket + */ + inline void remove(Handle sc) + { + unset(sc, Condition::Readable | Condition::Writable); + } + + /** + * Remove all sockets. + */ + inline void clear() + { + while (!m_table.empty()) { + remove(m_table.begin()->first); + } + } + + /** + * Get the number of sockets in the listener. + */ + inline ListenerTable::size_type size() const noexcept + { + return m_table.size(); + } + + /** + * Select a socket. Waits for a specific amount of time specified as the duration. + * + * @param duration the duration + * @return the socket ready + */ + template <typename Rep, typename Ratio> + inline ListenerStatus wait(const std::chrono::duration<Rep, Ratio> &duration) + { + assert(!m_table.empty()); + + auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration); + + return m_backend.wait(m_table, cvt.count())[0]; + } + + /** + * Overload with milliseconds. + * + * @param timeout the optional timeout in milliseconds + * @return the socket ready + */ + inline ListenerStatus wait(int timeout = -1) + { + return wait(std::chrono::milliseconds(timeout)); + } + + /** + * Select multiple sockets. + * + * @param duration the duration + * @return the socket ready + */ + template <typename Rep, typename Ratio> + inline std::vector<ListenerStatus> waitMultiple(const std::chrono::duration<Rep, Ratio> &duration) + { + assert(!m_table.empty()); + + auto cvt = std::chrono::duration_cast<std::chrono::milliseconds>(duration); + + return m_backend.wait(m_table, cvt.count()); + } + + /** + * Overload with milliseconds. + * + * @return the socket ready + */ + inline std::vector<ListenerStatus> waitMultiple(int timeout = -1) + { + return waitMultiple(std::chrono::milliseconds(timeout)); + } +}; + +/* }}} */ + +/* + * Callback + * ------------------------------------------------------------------ + * + * Function owner with tests. + */ + +/* {{{ Callback */ + +/** + * @class Callback + * @brief Convenient signal owner that checks if the target is valid. + * + * This class also catch all errors thrown from signals to avoid interfering with our process. + */ +template <typename... Args> +class Callback : public std::function<void (Args...)> { +public: + /** + * Inherited constructors. + */ + using std::function<void (Args...)>::function; + + /** + * Execute the callback only if a target is set. + */ + void operator()(Args... args) const + { + if (*this) { + try { + std::function<void (Args...)>::operator()(args...); + } catch (...) { + } + } + } +}; + +/* }}} */ + +/* + * StreamConnection + * ------------------------------------------------------------------ + * + * Client connected on the server side. + */ + +/* {{{ StreamConnection */ + +/** + * @class StreamConnection + * @brief Connected client on the server side. + * + * This object is created from StreamServer when a new client is connected, it is the higher + * level object of sockets and completely asynchronous. + */ +template <typename Address, typename Protocol> +class StreamConnection { +public: + /** + * Called when the output has changed. + */ + using WriteHandler = Callback<>; + +private: + /* Signals */ + WriteHandler m_onWrite; + + /* Sockets and output buffer */ + Socket<Address, Protocol> m_socket; + std::string m_output; + +public: + /** + * Create the connection. + * + * @param s the socket + */ + StreamConnection(Socket<Address, Protocol> s) + : m_socket{std::move(s)} + { + m_socket.set(net::option::SockBlockMode{false}); + } + + /** + * Access the underlying socket. + * + * @return the socket + * @warning use with care + */ + inline Socket<Address, Protocol> &socket() noexcept + { + return m_socket; + } + + /** + * Access the current output. + * + * @return the output + */ + inline const std::string &output() const noexcept + { + return m_output; + } + + /** + * Overloaded function + * + * @return the output + * @warning use with care, avoid modifying the output if you don't know what you're doing + */ + inline std::string &output() noexcept + { + return m_output; + } + + /** + * Post some data to be sent asynchronously. + * + * @param str the data to append + */ + inline void send(std::string str) + { + m_output += str; + m_onWrite(); + } + + /** + * Kill the client. + */ + inline void close() + { + m_socket.close(); + } + + /** + * Set the write handler, the signal is emitted when the output has changed so that the StreamServer owner + * knows that there are some data to send. + * + * @param handler the handler + * @warning you usually never need to set this yourself + */ + inline void setWriteHandler(WriteHandler handler) + { + m_onWrite = std::move(handler); + } +}; + +/* }}} */ + +/* + * StreamServer + * ------------------------------------------------------------------ + * + * Convenient stream oriented server. + */ + +/* {{{ StreamServer */ + +/** + * @class StreamServer + * @brief Convenient stream server for TCP and TLS. + * + * This class does all the things for you as accepting new clients, listening for it and sending data. It works + * asynchronously without blocking to let you control your process workflow. + * + * This class is not thread safe and you must not call any of the functions from different threads. + */ +template <typename Address, typename Protocol> +class StreamServer { +public: + /** + * Handler when a new client is connected. + */ + using ConnectionHandler = Callback<const std::shared_ptr<StreamConnection<Address, Protocol>> &>; + + /** + * Handler when a client is disconnected. + */ + using DisconnectionHandler = Callback<const std::shared_ptr<StreamConnection<Address, Protocol>> &>; + + /** + * Handler when data has been received from a client. + */ + using ReadHandler = Callback<const std::shared_ptr<StreamConnection<Address, Protocol>> &, const std::string &>; + + /** + * Handler when data has been correctly sent to a client. + */ + using WriteHandler = Callback<const std::shared_ptr<StreamConnection<Address, Protocol>> &, const std::string &>; + + /** + * Handler when an error occured. + */ + using ErrorHandler = Callback<const Error &>; + + /** + * Handler when there was a timeout. + */ + using TimeoutHandler = Callback<>; + +private: + using ClientMap = std::map<Handle, std::shared_ptr<StreamConnection<Address, Protocol>>>; + + /* Signals */ + ConnectionHandler m_onConnection; + DisconnectionHandler m_onDisconnection; + ReadHandler m_onRead; + WriteHandler m_onWrite; + ErrorHandler m_onError; + TimeoutHandler m_onTimeout; + + /* Sockets */ + Socket<Address, Protocol> m_master; + Listener<> m_listener; + ClientMap m_clients; + + /* + * Update flags depending on the required condition. + */ + void updateFlags(std::shared_ptr<StreamConnection<Address, Protocol>> &client) + { + assert(client->socket().action() != Action::None); + + m_listener.remove(client->socket().handle()); + m_listener.set(client->socket().handle(), client->socket().condition()); + } + + /* + * Continue accept process. + */ + template <typename AcceptCall> + void processAccept(std::shared_ptr<StreamConnection<Address, Protocol>> &client, const AcceptCall &acceptFunc) + { + try { + /* Do the accept */ + acceptFunc(); + + /* 1. First remove completely the client */ + m_listener.remove(client->socket().handle()); + + /* 2. If accept is not finished, wait for the appropriate condition */ + if (client->socket().state() == State::Accepted) { + /* 3. Client is accepted, notify the user */ + m_listener.set(client->socket().handle(), Condition::Readable); + m_onConnection(client); + } else { + /* Operation still in progress */ + updateFlags(client); + } + } catch (const Error &error) { + m_clients.erase(client->socket().handle()); + m_listener.remove(client->socket().handle()); + m_onError(error); + } + } + + /* + * Process initial accept of master socket, this is the initial accepting process. Except on errors, the + * socket is stored but the user will be notified only once the socket is completely accepted. + */ + void processInitialAccept() + { + // TODO: store address too. + std::shared_ptr<StreamConnection<Address, Protocol>> client = std::make_shared<StreamConnection<Address, Protocol>>(m_master.accept(nullptr)); + std::weak_ptr<StreamConnection<Address, Protocol>> ptr{client}; + + /* 1. Register output changed to update listener */ + client->setWriteHandler([this, ptr] () { + auto client = ptr.lock(); + + /* Do not update the listener immediately if an action is pending */ + if (client && client->socket().action() == Action::None && !client->output().empty()) { + m_listener.set(client->socket().handle(), Condition::Writable); + } + }); + + /* 2. Add the client */ + m_clients.insert(std::make_pair(client->socket().handle(), client)); + + /* + * 2. Do an initial check to set the listener flags, at this moment the socket may or not be + * completely accepted. + */ + processAccept(client, [&] () {}); + } + + /* + * Read or complete the read operation. + */ + void processRead(std::shared_ptr<StreamConnection<Address, Protocol>> &client) + { + /* + * Read because there is something to read or because the pending operation is + * read and must complete. + */ + auto buffer = client->socket().recv(512); + + /* + * Now the receive operation may be completed, in that case, two possibilities: + * + * 1. The action is set to None (completed) + * 2. The action is still not complete, update the flags + */ + if (client->socket().action() == Action::None) { + /* Empty mean normal disconnection */ + if (buffer.empty()) { + m_listener.remove(client->socket().handle()); + m_clients.erase(client->socket().handle()); + m_onDisconnection(client); + } else { + /* + * At this step, it is possible that we were completing a receive operation, in this + * case the write flag may be removed, add it if required. + */ + if (!client->output().empty()) { + m_listener.set(client->socket().handle(), Condition::Writable); + } + + m_onRead(client, buffer); + } + } else { + /* Operation in progress */ + updateFlags(client); + } + } + + /* + * Flush the output buffer. + */ + void processWrite(std::shared_ptr<StreamConnection<Address, Protocol>> &client) + { + auto &output = client->output(); + auto nsent = client->socket().send(output); + + if (client->socket().action() == Action::None) { + /* 1. Create a copy of content that has been sent */ + auto sent = output.substr(0, nsent); + + /* 2. Erase the content sent */ + output.erase(0, nsent); + + /* 3. Update listener */ + if (output.empty()) { + m_listener.unset(client->socket().handle(), Condition::Writable); + } + + /* 4. Notify user */ + m_onWrite(client, sent); + } else { + updateFlags(client); + } + } + + void processSync(std::shared_ptr<StreamConnection<Address, Protocol>> &client, Condition flags) + { + try { + auto action = client->socket().action(); + + if (action == Action::Receive || + (action == Action::None && (flags & Condition::Readable) == Condition::Readable)) { + processRead(client); + } else if ((flags & Condition::Writable) == Condition::Writable) { + processWrite(client); + } + } catch (const Error &error) { + m_onDisconnection(client); + m_listener.remove(client->socket().handle()); + m_clients.erase(client->socket().handle()); + } + } + +public: + /** + * Create a stream server with the specified address to bind. + * + * @param protocol the protocol (Tcp or Tls) + * @param address the address to bind + * @param max the max number to listen + * @throw Error on errors + */ + StreamServer(Protocol protocol, const Address &address, int max = 128) + : m_master{std::move(protocol), address} + { + // TODO: m_onError + m_master.set(SOL_SOCKET, SO_REUSEADDR, 1); + m_master.bind(address); + m_master.listen(max); + m_listener.set(m_master.handle(), Condition::Readable); + } + + /** + * Set the connection handler, called when a new client is connected. + * + * @param handler the handler + */ + inline void setConnectionHandler(ConnectionHandler handler) + { + m_onConnection = std::move(handler); + } + + /** + * Set the disconnection handler, called when a client died. + * + * @param handler the handler + */ + inline void setDisconnectionHandler(DisconnectionHandler handler) + { + m_onDisconnection = std::move(handler); + } + + /** + * Set the receive handler, called when a client has sent something. + * + * @param handler the handler + */ + inline void setReadHandler(ReadHandler handler) + { + m_onRead = std::move(handler); + } + + /** + * Set the writing handler, called when some data has been sent to a client. + * + * @param handler the handler + */ + inline void setWriteHandler(WriteHandler handler) + { + m_onWrite = std::move(handler); + } + + /** + * Set the error handler, called when unrecoverable error has occured. + * + * @param handler the handler + */ + inline void setErrorHandler(ErrorHandler handler) + { + m_onError = std::move(handler); + } + + /** + * Set the timeout handler, called when the selection has timeout. + * + * @param handler the handler + */ + inline void setTimeoutHandler(TimeoutHandler handler) + { + m_onTimeout = std::move(handler); + } + + /** + * Poll for the next event. + * + * @param timeout the timeout (-1 for indefinitely) + * @throw Error on errors + */ + void poll(int timeout = -1) + { + try { + auto st = m_listener.wait(timeout); + + if (st.socket == m_master.handle()) { + /* New client */ + processInitialAccept(); + } else { + /* Recv / Send / Accept on a client */ + auto client = m_clients[st.socket]; + + if (client->socket().state() == State::Accepted) { + processSync(client, st.flags); + } else { + processAccept(client, [&] () { client->socket().accept(); }); + } + } + } catch (const Error &error) { + if (error.code() == Error::Timeout) { + m_onTimeout(); + } else { + m_onError(error); + } + } + } +}; + +/* }}} */ + +/* + * StreamClient + * ------------------------------------------------------------------ + */ + +/* {{{ StreamClient */ + +/** + * @class StreamClient + * @brief Client side connection to a server. + * + * This class is not thread safe and you must not call any of the functions from different threads. + */ +template <typename Address, typename Protocol> +class StreamClient { +public: + /** + * Handler when connection is complete. + */ + using ConnectionHandler = Callback<>; + + /** + * Handler when data has been received. + */ + using ReadHandler = Callback<const std::string &>; + + /** + * Handler when data has been sent correctly. + */ + using WriteHandler = Callback<const std::string &>; + + /** + * Handler when disconnected. + */ + using DisconnectionHandler = Callback<>; + + /** + * Handler on unrecoverable error. + */ + using ErrorHandler = Callback<const Error &>; + + /** + * Handler when timeout occured. + */ + using TimeoutHandler = Callback<>; + +private: + /* Signals */ + ConnectionHandler m_onConnection; + ReadHandler m_onRead; + WriteHandler m_onWrite; + DisconnectionHandler m_onDisconnection; + ErrorHandler m_onError; + TimeoutHandler m_onTimeout; + + /* Socket */ + Socket<Address, Protocol> m_socket; + Listener<> m_listener; + + /* Output buffer */ + std::string m_output; + + /* + * Update the flags after an uncompleted operation. This function must only be called when the operation + * has not complete (e.g. connect, recv, send). + */ + void updateFlags() + { + assert(m_socket.action() != Action::None); + + m_listener.remove(m_socket.handle()); + m_listener.set(m_socket.handle(), m_socket.condition()); + } + + /* + * This is the generic connect helper, it will be used to both initiate the connection or to continue the + * connection process if needed. + * + * Thus the template parameter is the appropriate function to call either, m_socket.connect(address) or + * m_socket.connect(). + * + * See poll() and connect() to understand. + */ + template <typename ConnectCall> + void processConnect(const ConnectCall &connectFunc) + { + /* Call m_socket.connect() or m_socket.connect(address) */ + connectFunc(); + + /* Remove entirely */ + m_listener.remove(m_socket.handle()); + + if (m_socket.state() == State::Connected) { + m_onConnection(); + m_listener.set(m_socket.handle(), Condition::Readable); + } else { + /* Connection still in progress */ + updateFlags(); + } + } + + /* + * Receive or complete the receive command, if the command is not complete, the listener is updated + * accordingly. + */ + void processRead() + { + auto received = m_socket.recv(512); + + if (m_socket.action() == Action::None) { + /* 0 means disconnection */ + if (received.empty()) { + m_onDisconnection(); + } else { + /* + * At this step, it is possible that we were completing a receive operation, in this + * case the write flag may be removed, add it if required. + */ + if (m_output.empty()) { + m_listener.unset(m_socket.handle(), Condition::Writable); + } + + m_onRead(received); + } + } else { + /* Receive operation in progress */ + updateFlags(); + } + } + + /* + * Send or complete the send command, if the command is not complete, the listener is updated + * accordingly. + */ + void processWrite() + { + auto nsent = m_socket.send(m_output); + + if (m_socket.action() == Action::None) { + /* 1. Make a copy of what has been sent */ + auto sent = m_output.substr(0, nsent); + + /* 2. Erase sent content */ + m_output.erase(0, nsent); + + /* 3. Update flags if needed */ + if (m_output.empty()) { + m_listener.unset(m_socket.handle(), Condition::Writable); + } + + /* 4. Notify user */ + m_onWrite(sent); + } else { + /* Send operation in progress */ + updateFlags(); + } + } + + /* + * Receive or send. + */ + void processSync(Condition condition) + { + if ((m_socket.action() == Action::Receive) || + (m_socket.action() == Action::None && (condition & Condition::Readable) == Condition::Readable)) { + processRead(); + } else { + processWrite(); + } + } + +public: + /** + * Create a client. The client is automatically marked as non-blocking. + * + * @param protocol the protocol (Tcp or Tls) + * @param address the optional address + * @throw net::Error on failures + */ + StreamClient(Protocol protocol = {}, const Address &address = {}) + : m_socket{std::move(protocol), address} + { + m_socket.set(net::option::SockBlockMode{false}); + m_listener.set(m_socket.handle(), Condition::Readable); + } + + /** + * Set the connection handler, called when the connection succeed. + * + * @param handler the handler + */ + inline void setConnectionHandler(ConnectionHandler handler) + { + m_onConnection = std::move(handler); + } + + /** + * Set the disconnection handler, called when the server closed the connection. + * + * @param handler the handler + */ + inline void setDisconnectionHandler(DisconnectionHandler handler) + { + m_onDisconnection = std::move(handler); + } + + /** + * Set the read handler, called when we received something. + * + * @param handler the handler + */ + inline void setReadHandler(ReadHandler handler) + { + m_onRead = std::move(handler); + } + + /** + * Set the write handler, called when we successfully sent data. + * + * @param handler the handler + */ + inline void setWriteHandler(WriteHandler handler) + { + m_onWrite = std::move(handler); + } + + /** + * Set the error handler, called when unexpected error occurs. + * + * @param handler the handler + */ + inline void setErrorHandler(ErrorHandler handler) + { + m_onError = std::move(handler); + } + + /** + * Connect to a server, this function may connect immediately or not in any case the connection handler + * will be called when the connection completed. + * + * @param address the address to connect to + */ + void connect(const Address &address) noexcept + { + assert(m_socket.state() == State::Open); + + processConnect([&] () { m_socket.connect(address); }); + } + + /** + * Asynchronously send data to the server. + * + * @param str the data to append + */ + void send(std::string str) + { + m_output += str; + + /* Don't update the listener if there is a pending operation */ + if (m_socket.state() == State::Connected && m_socket.action() == Action::None && !m_output.empty()) { + m_listener.set(m_socket.handle(), Condition::Writable); + } + } + + /** + * Wait for the next event. + * + * @param timeout the time to wait in milliseconds + * @throw Error on errors + */ + void poll(int timeout = -1) noexcept + { + try { + auto st = m_listener.wait(timeout); + + if (m_socket.state() != State::Connected) { + /* Continue the connection */ + processConnect([&] () { m_socket.connect(); }); + } else { + /* Read / Write */ + processSync(st.flags); + } + } catch (const Error &error) { + if (error.code() == Error::Timeout) { + m_onTimeout(); + } else { + m_listener.remove(m_socket.handle()); + m_onError(error); + } + } + } +}; + +/* }}} */ + +} // !net + +} // !irccd + +#endif // !IRCCD_SOCKETS_HPP
--- a/lib/irccd/system.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/system.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -20,7 +20,7 @@ #include <ctime> #include <stdexcept> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> #if defined(HAVE_SETPROGNAME) # include <cstdlib> @@ -43,7 +43,6 @@ # include <sys/utsname.h> # include <sys/time.h> # include <sys/types.h> - # include <unistd.h> # include <cerrno> @@ -67,10 +66,10 @@ # include <pwd.h> #endif -#include "fs.h" -#include "logger.h" -#include "system.h" -#include "util.h" +#include "fs.hpp" +#include "logger.hpp" +#include "system.hpp" +#include "util.hpp" namespace irccd {
--- a/lib/irccd/system.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * system.h -- platform dependent functions for system inspection - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_SYSTEM_H -#define IRCCD_SYSTEM_H - -/** - * @file system.h - * @brief System dependant functions - */ - -#include <irccd/sysconfig.h> - -#include <cstdint> -#include <string> - -namespace irccd { - -namespace sys { - -/** - * Set the program name, needed for some functions or some systems. - * - * @param name the program name - */ -void setProgramName(std::string name) noexcept; - -/** - * Get the program name. - * - * @return the program name - */ -const std::string &programName() noexcept; - -/** - * Get the system name. - * - * @return the name - */ -std::string name(); - -/** - * Get the system version. - * - * @return the version - */ -std::string version(); - -/** - * Get the number of seconds elapsed since the boottime. - * - * @return the number of seconds - */ -uint64_t uptime(); - -/** - * Get the milliseconds elapsed since the application - * startup. - * - * @return the milliseconds - */ -uint64_t ticks(); - -/** - * Get an environment variable. - * - * @return the value or empty string - */ -std::string env(const std::string &var); - -/** - * Get home directory usually /home/foo - * - * @return the home directory - */ -std::string home(); - -#if defined(HAVE_SETUID) - -/** - * Set the effective uid by name or numeric value. - * - * @param value the value - */ -void setUid(const std::string &value); - -#endif - -#if defined(HAVE_SETGID) - -/** - * Set the effective gid by name or numeric value. - * - * @param value the value - */ -void setGid(const std::string &value); - -#endif - -} // !sys - -} // !irccd - -#endif // !IRCCD_SYSTEM_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/system.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,119 @@ +/* + * system.hpp -- platform dependent functions for system inspection + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_SYSTEM_HPP +#define IRCCD_SYSTEM_HPP + +/** + * @file system.hpp + * @brief System dependant functions + */ + +#include <irccd/sysconfig.hpp> + +#include <cstdint> +#include <string> + +namespace irccd { + +namespace sys { + +/** + * Set the program name, needed for some functions or some systems. + * + * @param name the program name + */ +void setProgramName(std::string name) noexcept; + +/** + * Get the program name. + * + * @return the program name + */ +const std::string &programName() noexcept; + +/** + * Get the system name. + * + * @return the name + */ +std::string name(); + +/** + * Get the system version. + * + * @return the version + */ +std::string version(); + +/** + * Get the number of seconds elapsed since the boottime. + * + * @return the number of seconds + */ +uint64_t uptime(); + +/** + * Get the milliseconds elapsed since the application + * startup. + * + * @return the milliseconds + */ +uint64_t ticks(); + +/** + * Get an environment variable. + * + * @return the value or empty string + */ +std::string env(const std::string &var); + +/** + * Get home directory usually /home/foo + * + * @return the home directory + */ +std::string home(); + +#if defined(HAVE_SETUID) + +/** + * Set the effective uid by name or numeric value. + * + * @param value the value + */ +void setUid(const std::string &value); + +#endif + +#if defined(HAVE_SETGID) + +/** + * Set the effective gid by name or numeric value. + * + * @param value the value + */ +void setGid(const std::string &value); + +#endif + +} // !sys + +} // !irccd + +#endif // !IRCCD_SYSTEM_HPP
--- a/lib/irccd/timer.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/timer.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -19,7 +19,7 @@ #include <cassert> #include <chrono> -#include "timer.h" +#include "timer.hpp" namespace irccd {
--- a/lib/irccd/timer.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * timer.h -- threaded timers - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_TIMER_H -#define IRCCD_TIMER_H - -/** - * @file timer.h - * @brief Provides interval based timers for JavaScript - */ - -#include <atomic> -#include <condition_variable> -#include <functional> -#include <mutex> -#include <thread> - -#include "signals.h" - -namespace irccd { - -/** - * @enum TimerType - * @brief Type of timer - */ -enum class TimerType { - Single, //!< The timer ends after execution - Repeat //!< The timer loops -}; - -/** - * @class Timer - * @brief Timer class - * - * A timer is a thread object that emits a signal periodically or just one time. It is perfectly pausable and resumable - * to reuse the same object. - * - * The delay is configured in milliseconds and the user has choice to use any - * delay needed. - * - * We use a condition variable to wait for the specified delay unless the timer - * must be stopped. - */ -class Timer { -public: - /** - * Signal: onSignal - * ---------------------------------------------------------- - * - * Called when the timeout expires. - */ - Signal<> onSignal; - - /** - * Signal: onEnd - * ---------------------------------------------------------- - * - * Called when the timeout ends. - */ - Signal<> onEnd; - -private: - enum { - Paused, - Running, - Stopped - }; - - TimerType m_type; - unsigned m_delay; - - /* Thread management */ - std::atomic<int> m_state{Paused}; - std::mutex m_mutex; - std::condition_variable m_condition; - std::thread m_thread; - - void run(); - -public: - /** - * Timer constructor. - * - * The timer is not started, use start(). - * - * @param type the timer type - * @param delay the delay in milliseconds - * @post isRunning() returns false - */ - Timer(TimerType type, unsigned delay) noexcept; - - /** - * Destructor, closes the thread. - * - * @pre stop() must have been called. - */ - virtual ~Timer(); - - /** - * Start the thread. - * - * @pre isRunning() must return false - * @pre onSignal() must have been called - * @pre onEnd() must have been called - * @note Thread-safe - */ - void start(); - - /** - * Stop the timer, may be used by the user to stop it. - * - * @note Thread-safe - */ - void stop(); - - /** - * Get the type of timer. - * - * @return the type. - */ - inline TimerType type() const noexcept - { - return m_type; - } - - /** - * Tells if the timer has still a running thread. - * - * @return true if still alive - * @note Thread-safe - */ - inline bool isRunning() const noexcept - { - return m_state == Running; - } -}; - -} // !irccd - -#endif // !IRCCD_TIMER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/timer.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,155 @@ +/* + * timer.hpp -- threaded timers + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_TIMER_HPP +#define IRCCD_TIMER_HPP + +/** + * @file timer.hpp + * @brief Provides interval based timers for JavaScript + */ + +#include <atomic> +#include <condition_variable> +#include <functional> +#include <mutex> +#include <thread> + +#include "signals.hpp" + +namespace irccd { + +/** + * @enum TimerType + * @brief Type of timer + */ +enum class TimerType { + Single, //!< The timer ends after execution + Repeat //!< The timer loops +}; + +/** + * @class Timer + * @brief Timer class + * + * A timer is a thread object that emits a signal periodically or just one time. It is perfectly pausable and resumable + * to reuse the same object. + * + * The delay is configured in milliseconds and the user has choice to use any + * delay needed. + * + * We use a condition variable to wait for the specified delay unless the timer + * must be stopped. + */ +class Timer { +public: + /** + * Signal: onSignal + * ---------------------------------------------------------- + * + * Called when the timeout expires. + */ + Signal<> onSignal; + + /** + * Signal: onEnd + * ---------------------------------------------------------- + * + * Called when the timeout ends. + */ + Signal<> onEnd; + +private: + enum { + Paused, + Running, + Stopped + }; + + TimerType m_type; + unsigned m_delay; + + /* Thread management */ + std::atomic<int> m_state{Paused}; + std::mutex m_mutex; + std::condition_variable m_condition; + std::thread m_thread; + + void run(); + +public: + /** + * Timer constructor. + * + * The timer is not started, use start(). + * + * @param type the timer type + * @param delay the delay in milliseconds + * @post isRunning() returns false + */ + Timer(TimerType type, unsigned delay) noexcept; + + /** + * Destructor, closes the thread. + * + * @pre stop() must have been called. + */ + virtual ~Timer(); + + /** + * Start the thread. + * + * @pre isRunning() must return false + * @pre onSignal() must have been called + * @pre onEnd() must have been called + * @note Thread-safe + */ + void start(); + + /** + * Stop the timer, may be used by the user to stop it. + * + * @note Thread-safe + */ + void stop(); + + /** + * Get the type of timer. + * + * @return the type. + */ + inline TimerType type() const noexcept + { + return m_type; + } + + /** + * Tells if the timer has still a running thread. + * + * @return true if still alive + * @note Thread-safe + */ + inline bool isRunning() const noexcept + { + return m_state == Running; + } +}; + +} // !irccd + +#endif // !IRCCD_TIMER_HPP
--- a/lib/irccd/transport-client.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/transport-client.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,9 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "json.h" -#include "logger.h" -#include "transport-client.h" +#include "json.hpp" +#include "logger.hpp" +#include "transport-client.hpp" namespace irccd {
--- a/lib/irccd/transport-client.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,207 +0,0 @@ -/* - * transport-client.h -- client connected to irccd - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_TRANSPORT_CLIENT_H -#define IRCCD_TRANSPORT_CLIENT_H - -/** - * @file transport-client.h - * @brief Client connected to irccd - */ - -#include <functional> -#include <memory> -#include <stdexcept> -#include <string> - -#include "server.h" -#include "signals.h" -#include "sockets.h" - -namespace irccd { - -namespace json { - -class Value; - -} // !json - -/** - * @class TransportClient - * @brief Client connected to irccd. - * - * This class emits a warning upon clients request through onCommand signal. - */ -class TransportClient { -public: - /** - * Signal: onCommand - * ---------------------------------------------------------- - * - * Arguments: - * - the command - */ - Signal<const json::Value &> onCommand; - - /** - * Signal: onDie - * ---------------------------------------------------------- - * - * The client has disconnected. - */ - Signal<> onDie; - -protected: - std::string m_input; - std::string m_output; - - /* Parse input buffer */ - void parse(const std::string &); - - /* Do I/O */ - virtual void receive() = 0; - virtual void send() = 0; - -public: - /** - * Virtual destructor defaulted. - */ - virtual ~TransportClient() = default; - - /** - * Send or receive data, called after a select. - * - * @param setinput the input fd_set - * @param setoutput the output fd_set - */ - void sync(fd_set &setinput, fd_set &setoutput); - -#if 0 - /** - * Notify the client that the command succeeded. - * - * @param command the command name - */ - void ok(const std::string &command); - - /** - * Send an error message to the client. - * - * @param command the command name - * @param message the error message - */ - void error(const std::string &command, std::string message); -#endif - - /** - * Send some data, it will be pushed to the outgoing buffer. - * - * This function appends "\r\n\r\n" after the message so you don't have - * to do it manually. - * - * @param message the message - */ - void send(std::string message); - - /** - * Tell if the client has data pending for output. - * - * @return true if has pending data to write - */ - inline bool hasOutput() const noexcept - { - return !m_output.empty(); - } - - /** - * Get the underlying socket handle. - * - * @return the socket - */ - virtual net::Handle handle() noexcept = 0; -}; - -/** - * @brief Template class for Tcp and Ssl sockets - */ -template <typename Address> -class TransportClientBase : public TransportClient { -private: - net::SocketTcp<Address> m_socket; - -protected: - void send() override; - void receive() override; - -public: - /** - * Create a client. - * - * @param socket the socket - */ - inline TransportClientBase(net::SocketTcp<Address> socket) - : m_socket(std::move(socket)) - { - } - - /** - * @copydoc TransportClient::handle - */ - net::Handle handle() noexcept override - { - return m_socket.handle(); - } -}; - -template <typename Address> -void TransportClientBase<Address>::receive() -{ - try { - auto message = m_socket.recv(512); - - if (message.empty()) - onDie(); - - m_input += message; - } catch (const std::exception &) { - onDie(); - } - - std::string::size_type pos; - while ((pos = m_input.find("\r\n\r\n")) != std::string::npos) { - /* - * Make a copy and erase it in case that onComplete function - * throws. - */ - auto message = m_input.substr(0, pos); - - m_input.erase(m_input.begin(), m_input.begin() + pos + 4); - - parse(message); - } -} - -template <typename Address> -void TransportClientBase<Address>::send() -{ - m_output.erase(0, m_socket.send(m_output)); -} - -} // !irccd - -#endif // !IRCCD_TRANSPORT_CLIENT_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/transport-client.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,207 @@ +/* + * transport-client.hpp -- client connected to irccd + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_TRANSPORT_CLIENT_HPP +#define IRCCD_TRANSPORT_CLIENT_HPP + +/** + * @file transport-client.hpp + * @brief Client connected to irccd + */ + +#include <functional> +#include <memory> +#include <stdexcept> +#include <string> + +#include "server.hpp" +#include "signals.hpp" +#include "sockets.hpp" + +namespace irccd { + +namespace json { + +class Value; + +} // !json + +/** + * @class TransportClient + * @brief Client connected to irccd. + * + * This class emits a warning upon clients request through onCommand signal. + */ +class TransportClient { +public: + /** + * Signal: onCommand + * ---------------------------------------------------------- + * + * Arguments: + * - the command + */ + Signal<const json::Value &> onCommand; + + /** + * Signal: onDie + * ---------------------------------------------------------- + * + * The client has disconnected. + */ + Signal<> onDie; + +protected: + std::string m_input; + std::string m_output; + + /* Parse input buffer */ + void parse(const std::string &); + + /* Do I/O */ + virtual void receive() = 0; + virtual void send() = 0; + +public: + /** + * Virtual destructor defaulted. + */ + virtual ~TransportClient() = default; + + /** + * Send or receive data, called after a select. + * + * @param setinput the input fd_set + * @param setoutput the output fd_set + */ + void sync(fd_set &setinput, fd_set &setoutput); + +#if 0 + /** + * Notify the client that the command succeeded. + * + * @param command the command name + */ + void ok(const std::string &command); + + /** + * Send an error message to the client. + * + * @param command the command name + * @param message the error message + */ + void error(const std::string &command, std::string message); +#endif + + /** + * Send some data, it will be pushed to the outgoing buffer. + * + * This function appends "\r\n\r\n" after the message so you don't have + * to do it manually. + * + * @param message the message + */ + void send(std::string message); + + /** + * Tell if the client has data pending for output. + * + * @return true if has pending data to write + */ + inline bool hasOutput() const noexcept + { + return !m_output.empty(); + } + + /** + * Get the underlying socket handle. + * + * @return the socket + */ + virtual net::Handle handle() noexcept = 0; +}; + +/** + * @brief Template class for Tcp and Ssl sockets + */ +template <typename Address> +class TransportClientBase : public TransportClient { +private: + net::SocketTcp<Address> m_socket; + +protected: + void send() override; + void receive() override; + +public: + /** + * Create a client. + * + * @param socket the socket + */ + inline TransportClientBase(net::SocketTcp<Address> socket) + : m_socket(std::move(socket)) + { + } + + /** + * @copydoc TransportClient::handle + */ + net::Handle handle() noexcept override + { + return m_socket.handle(); + } +}; + +template <typename Address> +void TransportClientBase<Address>::receive() +{ + try { + auto message = m_socket.recv(512); + + if (message.empty()) + onDie(); + + m_input += message; + } catch (const std::exception &) { + onDie(); + } + + std::string::size_type pos; + while ((pos = m_input.find("\r\n\r\n")) != std::string::npos) { + /* + * Make a copy and erase it in case that onComplete function + * throws. + */ + auto message = m_input.substr(0, pos); + + m_input.erase(m_input.begin(), m_input.begin() + pos + 4); + + parse(message); + } +} + +template <typename Address> +void TransportClientBase<Address>::send() +{ + m_output.erase(0, m_socket.send(m_output)); +} + +} // !irccd + +#endif // !IRCCD_TRANSPORT_CLIENT_HPP
--- a/lib/irccd/transport-server.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/transport-server.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -22,7 +22,7 @@ #include <sstream> -#include "transport-server.h" +#include "transport-server.hpp" namespace irccd {
--- a/lib/irccd/transport-server.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/* - * transport-server.h -- I/O for irccd clients (acceptors) - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_TRANSPORT_SERVER_H -#define IRCCD_TRANSPORT_SERVER_H - -/** - * @file transport-server.h - * @brief Transports for irccd - */ - -#include <memory> -#include <string> - -#include <irccd/sysconfig.h> - -#include "sockets.h" -#include "transport-client.h" - -namespace irccd { - -/** - * @class TransportServer - * @brief Bring networking between irccd and irccdctl - * - * This class contains a master sockets for listening to TCP connections, it is then processed by irccd. - * - * The transport class supports the following domains: - * - * | Domain | Class | - * |-----------------------|-----------------------| - * | IPv4, IPv6 | TransportServerIp | - * | Unix (not on Windows) | TransportServerUnix | - * - * Note: IPv4 and IPv6 can be combined, using TransportServer::IPv6 and its option. - */ -class TransportServer { -private: - TransportServer(const TransportServer &) = delete; - TransportServer(TransportServer &&) = delete; - - TransportServer &operator=(const TransportServer &) = delete; - TransportServer &operator=(TransportServer &&) = delete; - -public: - /** - * Default constructor. - */ - TransportServer() = default; - - /** - * Destructor defaulted. - */ - virtual ~TransportServer() = default; - - /** - * Retrieve the underlying socket handle. - * - * @return the socket - */ - virtual net::Handle handle() noexcept = 0; - - /** - * Accept a new client depending on the domain. - * - * @return the new client - */ - virtual std::shared_ptr<TransportClient> accept() = 0; -}; - -/** - * @class TransportServerIp - * @brief Base class for both IPv4 and IPv6 servers. - */ -class TransportServerIp : public TransportServer { -protected: - net::SocketTcp<net::address::Ip> m_socket; - -public: - /** - * Create a IP transport, use IPv6 or IPv4 address. - * - * @param domain AF_INET or AF_INET6 - * @param address the address or "*" for any - * @param port the port number - * @param ipv6only set to true to disable IPv4 - * @throw net::Error on failures - */ - TransportServerIp(int domain, const std::string &address, int port, bool ipv6only = true); - - /** - * @copydoc TransportServer::socket - */ - net::Handle handle() noexcept override; - - /** - * @copydoc TransportServer::accept - */ - std::shared_ptr<TransportClient> accept() override; -}; - -#if !defined(IRCCD_SYSTEM_WINDOWS) - -/** - * @class TransportServerUnix - * @brief Implementation of transports for Unix sockets. - */ -class TransportServerUnix : public TransportServer { -private: - net::SocketTcp<net::address::Local> m_socket; - std::string m_path; - -public: - /** - * Create a Unix transport. - * - * @param path the path - */ - TransportServerUnix(std::string path); - - /** - * Destroy the transport and remove the file. - */ - ~TransportServerUnix(); - - /** - * @copydoc TransportServer::socket - */ - net::Handle handle() noexcept override; - - /** - * @copydoc TransportServer::accept - */ - std::shared_ptr<TransportClient> accept() override; -}; - -#endif // !_WIN32 - -} // !irccd - -#endif // !IRCCD_TRANSPORT_SERVER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/transport-server.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,156 @@ +/* + * transport-server.hpp -- I/O for irccd clients (acceptors) + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_TRANSPORT_SERVER_HPP +#define IRCCD_TRANSPORT_SERVER_HPP + +/** + * @file transport-server.hpp + * @brief Transports for irccd + */ + +#include <memory> +#include <string> + +#include <irccd/sysconfig.hpp> + +#include "sockets.hpp" +#include "transport-client.hpp" + +namespace irccd { + +/** + * @class TransportServer + * @brief Bring networking between irccd and irccdctl + * + * This class contains a master sockets for listening to TCP connections, it is then processed by irccd. + * + * The transport class supports the following domains: + * + * | Domain | Class | + * |-----------------------|-----------------------| + * | IPv4, IPv6 | TransportServerIp | + * | Unix (not on Windows) | TransportServerUnix | + * + * Note: IPv4 and IPv6 can be combined, using TransportServer::IPv6 and its option. + */ +class TransportServer { +private: + TransportServer(const TransportServer &) = delete; + TransportServer(TransportServer &&) = delete; + + TransportServer &operator=(const TransportServer &) = delete; + TransportServer &operator=(TransportServer &&) = delete; + +public: + /** + * Default constructor. + */ + TransportServer() = default; + + /** + * Destructor defaulted. + */ + virtual ~TransportServer() = default; + + /** + * Retrieve the underlying socket handle. + * + * @return the socket + */ + virtual net::Handle handle() noexcept = 0; + + /** + * Accept a new client depending on the domain. + * + * @return the new client + */ + virtual std::shared_ptr<TransportClient> accept() = 0; +}; + +/** + * @class TransportServerIp + * @brief Base class for both IPv4 and IPv6 servers. + */ +class TransportServerIp : public TransportServer { +protected: + net::SocketTcp<net::address::Ip> m_socket; + +public: + /** + * Create a IP transport, use IPv6 or IPv4 address. + * + * @param domain AF_INET or AF_INET6 + * @param address the address or "*" for any + * @param port the port number + * @param ipv6only set to true to disable IPv4 + * @throw net::Error on failures + */ + TransportServerIp(int domain, const std::string &address, int port, bool ipv6only = true); + + /** + * @copydoc TransportServer::socket + */ + net::Handle handle() noexcept override; + + /** + * @copydoc TransportServer::accept + */ + std::shared_ptr<TransportClient> accept() override; +}; + +#if !defined(IRCCD_SYSTEM_WINDOWS) + +/** + * @class TransportServerUnix + * @brief Implementation of transports for Unix sockets. + */ +class TransportServerUnix : public TransportServer { +private: + net::SocketTcp<net::address::Local> m_socket; + std::string m_path; + +public: + /** + * Create a Unix transport. + * + * @param path the path + */ + TransportServerUnix(std::string path); + + /** + * Destroy the transport and remove the file. + */ + ~TransportServerUnix(); + + /** + * @copydoc TransportServer::socket + */ + net::Handle handle() noexcept override; + + /** + * @copydoc TransportServer::accept + */ + std::shared_ptr<TransportClient> accept() override; +}; + +#endif // !_WIN32 + +} // !irccd + +#endif // !IRCCD_TRANSPORT_SERVER_HPP
--- a/lib/irccd/unicode.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/unicode.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "unicode.h" +#include "unicode.hpp" /* * The following code has been generated from Go mkrunetype adapted to our
--- a/lib/irccd/unicode.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,241 +0,0 @@ -/* - * unicode.h -- UTF-8 to UTF-32 conversions and various operations - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_UNICODE_H -#define IRCCD_UNICODE_H - -/** - * @file unicode.h - * @brief UTF-8 to UTF-32 conversions - */ - -#include <stdexcept> -#include <string> - -namespace irccd { - -namespace unicode { - -void encode(char32_t point, char res[5]) noexcept; -void decode(char32_t &c, const char *res) noexcept; - -/** - * Get the number of bytes for the first multi byte character from a - * utf-8 string. - * - * This can be used to iterate a valid UTF-8 string to jump to the next - * real character. - * - * @param c the first multi byte character - * @return the number of bytes [1-4] - */ -int nbytesUtf8(char c) noexcept; - -/** - * Get the number of bytes for the unicode point. - * - * @param point the unicode point - * @return the number of bytes [1-4] or -1 on invalid - */ -int nbytesPoint(char32_t point) noexcept; - -/** - * Get real number of character in a string. - * - * @param str the string - * @return the length - * @throw std::invalid_argument on invalid sequence - */ -int length(const std::string &str); - -/** - * Iterate over all real characters in the UTF-8 string. - * - * The function must have the following signature: - * void f(char ch) - * - * @param str the UTF-8 string - * @throw std::invalid_argument on invalid sequence - */ -template <typename Func> -void forEach(const std::string &str, Func function) -{ - for (size_t i = 0; i < str.size(); ) { - char32_t point = 0; - int size = nbytesUtf8(str[i]); - - if (size < 0) { - throw std::invalid_argument("invalid sequence"); - } - - decode(point, str.data() + i); - function(point); - - i += size; - } -} - -/** - * Convert a UTF-32 string to UTF-8 string. - * - * @param array the UTF-32 string - * @return the UTF-8 string - * @throw std::invalid_argument on invalid sequence - */ -std::string toUtf8(const std::u32string &array); - -/** - * Convert a UTF-8 string to UTF-32 string. - * - * @param str the UTF-8 string - * @return the UTF-32 string - * @throw std::invalid_argument on invalid sequence - */ -std::u32string toUtf32(const std::string &str); - -/** - * Check if the unicode character is space. - * - * @param c the character - * @return true if space - */ -bool isspace(char32_t c) noexcept; - -/** - * Check if the unicode character is digit. - * - * @param c the character - * @return true if digit - */ -bool isdigit(char32_t c) noexcept; - -/** - * Check if the unicode character is alpha category. - * - * @param c the character - * @return true if alpha - */ -bool isalpha(char32_t c) noexcept; - -/** - * Check if the unicode character is upper case. - * - * @param c the character - * @return true if upper case - */ -bool isupper(char32_t c) noexcept; - -/** - * Check if the unicode character is lower case. - * - * @param c the character - * @return true if lower case - */ -bool islower(char32_t c) noexcept; - -/** - * Check if the unicode character is title case. - * - * @param c the character - * @return true if title case - */ -bool istitle(char32_t c) noexcept; - -/** - * Convert to upper case. - * - * @param c the character - * @return the upper case character - */ -char32_t toupper(char32_t c) noexcept; - -/** - * Convert to lower case. - * - * @param c the character - * @return the lower case character - */ -char32_t tolower(char32_t c) noexcept; - -/** - * Convert to title case. - * - * @param c the character - * @return the title case character - */ -char32_t totitle(char32_t c) noexcept; - -/** - * Convert the UTF-32 string to upper case. - * - * @param str the str - * @return the upper case string - */ -inline std::u32string toupper(std::u32string str) -{ - for (size_t i = 0; i < str.size(); ++i) { - str[i] = toupper(str[i]); - } - - return str; -} - -/** - * Convert the UTF-8 string to upper case. - * - * @param str the str - * @return the upper case string - * @warning very slow at the moment - */ -inline std::string toupper(const std::string &str) -{ - return toUtf8(toupper(toUtf32(str))); -} - -/** - * Convert the UTF-32 string to lower case. - * - * @param str the str - * @return the lower case string - */ -inline std::u32string tolower(std::u32string str) -{ - for (size_t i = 0; i < str.size(); ++i) { - str[i] = tolower(str[i]); - } - - return str; -} - -/** - * Convert the UTF-8 string to lower case. - * - * @param str the str - * @return the lower case string - * @warning very slow at the moment - */ -inline std::string tolower(const std::string &str) -{ - return toUtf8(tolower(toUtf32(str))); -} - -} // !unicode - -} // !irccd - -#endif // !IRCCD_UNICODE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/unicode.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,241 @@ +/* + * unicode.hpp -- UTF-8 to UTF-32 conversions and various operations + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_UNICODE_HPP +#define IRCCD_UNICODE_HPP + +/** + * @file unicode.hpp + * @brief UTF-8 to UTF-32 conversions + */ + +#include <stdexcept> +#include <string> + +namespace irccd { + +namespace unicode { + +void encode(char32_t point, char res[5]) noexcept; +void decode(char32_t &c, const char *res) noexcept; + +/** + * Get the number of bytes for the first multi byte character from a + * utf-8 string. + * + * This can be used to iterate a valid UTF-8 string to jump to the next + * real character. + * + * @param c the first multi byte character + * @return the number of bytes [1-4] + */ +int nbytesUtf8(char c) noexcept; + +/** + * Get the number of bytes for the unicode point. + * + * @param point the unicode point + * @return the number of bytes [1-4] or -1 on invalid + */ +int nbytesPoint(char32_t point) noexcept; + +/** + * Get real number of character in a string. + * + * @param str the string + * @return the length + * @throw std::invalid_argument on invalid sequence + */ +int length(const std::string &str); + +/** + * Iterate over all real characters in the UTF-8 string. + * + * The function must have the following signature: + * void f(char ch) + * + * @param str the UTF-8 string + * @throw std::invalid_argument on invalid sequence + */ +template <typename Func> +void forEach(const std::string &str, Func function) +{ + for (size_t i = 0; i < str.size(); ) { + char32_t point = 0; + int size = nbytesUtf8(str[i]); + + if (size < 0) { + throw std::invalid_argument("invalid sequence"); + } + + decode(point, str.data() + i); + function(point); + + i += size; + } +} + +/** + * Convert a UTF-32 string to UTF-8 string. + * + * @param array the UTF-32 string + * @return the UTF-8 string + * @throw std::invalid_argument on invalid sequence + */ +std::string toUtf8(const std::u32string &array); + +/** + * Convert a UTF-8 string to UTF-32 string. + * + * @param str the UTF-8 string + * @return the UTF-32 string + * @throw std::invalid_argument on invalid sequence + */ +std::u32string toUtf32(const std::string &str); + +/** + * Check if the unicode character is space. + * + * @param c the character + * @return true if space + */ +bool isspace(char32_t c) noexcept; + +/** + * Check if the unicode character is digit. + * + * @param c the character + * @return true if digit + */ +bool isdigit(char32_t c) noexcept; + +/** + * Check if the unicode character is alpha category. + * + * @param c the character + * @return true if alpha + */ +bool isalpha(char32_t c) noexcept; + +/** + * Check if the unicode character is upper case. + * + * @param c the character + * @return true if upper case + */ +bool isupper(char32_t c) noexcept; + +/** + * Check if the unicode character is lower case. + * + * @param c the character + * @return true if lower case + */ +bool islower(char32_t c) noexcept; + +/** + * Check if the unicode character is title case. + * + * @param c the character + * @return true if title case + */ +bool istitle(char32_t c) noexcept; + +/** + * Convert to upper case. + * + * @param c the character + * @return the upper case character + */ +char32_t toupper(char32_t c) noexcept; + +/** + * Convert to lower case. + * + * @param c the character + * @return the lower case character + */ +char32_t tolower(char32_t c) noexcept; + +/** + * Convert to title case. + * + * @param c the character + * @return the title case character + */ +char32_t totitle(char32_t c) noexcept; + +/** + * Convert the UTF-32 string to upper case. + * + * @param str the str + * @return the upper case string + */ +inline std::u32string toupper(std::u32string str) +{ + for (size_t i = 0; i < str.size(); ++i) { + str[i] = toupper(str[i]); + } + + return str; +} + +/** + * Convert the UTF-8 string to upper case. + * + * @param str the str + * @return the upper case string + * @warning very slow at the moment + */ +inline std::string toupper(const std::string &str) +{ + return toUtf8(toupper(toUtf32(str))); +} + +/** + * Convert the UTF-32 string to lower case. + * + * @param str the str + * @return the lower case string + */ +inline std::u32string tolower(std::u32string str) +{ + for (size_t i = 0; i < str.size(); ++i) { + str[i] = tolower(str[i]); + } + + return str; +} + +/** + * Convert the UTF-8 string to lower case. + * + * @param str the str + * @return the lower case string + * @warning very slow at the moment + */ +inline std::string tolower(const std::string &str) +{ + return toUtf8(tolower(toUtf32(str))); +} + +} // !unicode + +} // !irccd + +#endif // !IRCCD_UNICODE_HPP
--- a/lib/irccd/util.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/lib/irccd/util.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -24,10 +24,10 @@ #include <sstream> #include <stdexcept> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include "util.h" -#include "unicode.h" +#include "util.hpp" +#include "unicode.hpp" using namespace std::string_literals;
--- a/lib/irccd/util.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,246 +0,0 @@ -/* - * util.h -- some utilities - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef IRCCD_UTIL_H -#define IRCCD_UTIL_H - -/** - * @file util.h - * @brief Utilities. - */ - -#include <ctime> -#include <initializer_list> -#include <regex> -#include <sstream> -#include <string> -#include <unordered_map> -#include <vector> - -namespace irccd { - -namespace util { - -/** - * @enum MessageType - * @brief Describe which type of message has been received - * - * On channels and queries, you may have a special command or a standard message depending on the - * beginning of the message. - * - * Example: `!reminder help' may invoke the command event if a plugin reminder exists. - */ -enum class MessageType { - Command, //!< special command - Message //!< standard message -}; - -/** - * @brief Combine the type of message and its content. - */ -using MessagePair = std::pair<std::string, MessageType>; - -/** - * @class Substitution - * @brief Used for format() function. - */ -class Substitution { -public: - /** - * Fill that field if you want a date. - */ - std::time_t time{std::time(nullptr)}; - - /** - * Fill that map if you want to replace keywords. - */ - std::unordered_map<std::string, std::string> keywords; -}; - -/** - * Format a string and update all templates. - * - * ## Syntax - * - * The syntax is <strong>?{}</strong> where <strong>?</strong> is replaced by one of the token defined below. Braces - * are mandatory and cannot be ommited. - * - * To write a literal template construct, prepend the token twice. - * - * ## Availables templates - * - * The following templates are available: - * - * - <strong>\#{name}</strong>: name will be substituted from the keywords in params, - * - <strong>\${name}</strong>: name will be substituted from the environment variable, - * - <strong>\@{attributes}</strong>: the attributes will be substituted to IRC colors (see below), - * - <strong>%</strong>, any format accepted by strftime(3). - * - * ## Attributes - * - * The attribute format is composed of three parts, foreground, background and modifiers, each separated by a comma. - * - * **Note:** you cannot omit parameters, to specify the background, you must specify the foreground. - * - * ## Examples - * - * ### Valid constructs - * - * - <strong>\#{target}, welcome</strong>: if target is set to "irccd", becomes "irccd, welcome", - * - <strong>\@{red}\#{target}</strong>: if target is specified, it is written in red, - * - * ### Invalid or literals constructs - * - * - <strong>\#\#{target}</strong>: will output "\#{target}", - * - <strong>\#\#</strong>: will output "\#\#", - * - <strong>\#target</strong>: will output "\#target", - * - <strong>\#{target</strong>: will throw std::invalid_argument. - * - * ### Colors & attributes - * - * - <strong>\@{red,blue}</strong>: will write text red on blue background, - * - <strong>\@{default,yellow}</strong>: will write default color text on yellow background, - * - <strong>\@{white,black,bold,underline}</strong>: will write white text on black in both bold and underline. - */ -std::string format(std::string text, const Substitution ¶ms = {}); - -/** - * Remove leading and trailing spaces. - * - * @param str the string - * @return the removed white spaces - */ -std::string strip(std::string str); - -/** - * Split a string by delimiters. - * - * @param list the string to split - * @param delimiters a list of delimiters - * @param max max number of split - * @return a list of string splitted - */ -std::vector<std::string> split(const std::string &list, const std::string &delimiters, int max = -1); - -/** - * Join values by a separator and return a string. - * - * @param first the first iterator - * @param last the last iterator - * @param delim the optional delimiter - */ -template <typename InputIt, typename DelimType = char> -std::string join(InputIt first, InputIt last, DelimType delim = ':') -{ - std::ostringstream oss; - - if (first != last) { - oss << *first; - - while (++first != last) - oss << delim << *first; - } - - return oss.str(); -} - -/** - * Convenient overload. - * - * @param list the initializer list - * @param delim the delimiter - * @return the string - */ -template <typename T, typename DelimType = char> -inline std::string join(std::initializer_list<T> list, DelimType delim = ':') -{ - return join(list.begin(), list.end(), delim); -} - -/** - * Parse IRC message and determine if it's a command or a simple message. - * - * @param message the message line - * @param commandChar the command char (e.g '!') - * @param plugin the plugin name - * @return the pair - */ -MessagePair parseMessage(std::string message, const std::string &commandChar, const std::string &plugin); - -/** - * Server and identities must have strict names. This function can - * be used to ensure that they are valid. - * - * @param name the identifier name - * @return true if is valid - */ -inline bool isIdentifierValid(const std::string &name) -{ - return std::regex_match(name, std::regex("[A-Za-z0-9-_]+")); -} - -/** - * Check if the value is a boolean, 1, yes and true are accepted. - * - * @param value the value - * @return true if is boolean - * @note this function is case-insensitive - */ -bool isBoolean(std::string value) noexcept; - -/** - * Check if the string is an integer. - * - * @param value the input - * @param base the optional base - * @return true if integer - */ -bool isInt(const std::string &value, int base = 10) noexcept; - -/** - * Check if the string is real. - * - * @param value the value - * @return true if real - */ -bool isReal(const std::string &value) noexcept; - -/** - * Check if the string is a number. - * - * @param value the value - * @return true if it is a number - */ -inline bool isNumber(const std::string &value) noexcept -{ - return isInt(value) || isReal(value); -} - -/** - * Parse a network message from an input buffer and remove it from it. - * - * @param input the buffer, will be updated - * @return the message or empty string if there is nothing - */ -std::string nextNetwork(std::string &input); - -} // !util - -} // !irccd - -#endif // !IRCCD_UTIL_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/util.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,246 @@ +/* + * util.hpp -- some utilities + * + * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_UTIL_HPP +#define IRCCD_UTIL_HPP + +/** + * @file util.hpp + * @brief Utilities. + */ + +#include <ctime> +#include <initializer_list> +#include <regex> +#include <sstream> +#include <string> +#include <unordered_map> +#include <vector> + +namespace irccd { + +namespace util { + +/** + * @enum MessageType + * @brief Describe which type of message has been received + * + * On channels and queries, you may have a special command or a standard message depending on the + * beginning of the message. + * + * Example: `!reminder help' may invoke the command event if a plugin reminder exists. + */ +enum class MessageType { + Command, //!< special command + Message //!< standard message +}; + +/** + * @brief Combine the type of message and its content. + */ +using MessagePair = std::pair<std::string, MessageType>; + +/** + * @class Substitution + * @brief Used for format() function. + */ +class Substitution { +public: + /** + * Fill that field if you want a date. + */ + std::time_t time{std::time(nullptr)}; + + /** + * Fill that map if you want to replace keywords. + */ + std::unordered_map<std::string, std::string> keywords; +}; + +/** + * Format a string and update all templates. + * + * ## Syntax + * + * The syntax is <strong>?{}</strong> where <strong>?</strong> is replaced by one of the token defined below. Braces + * are mandatory and cannot be ommited. + * + * To write a literal template construct, prepend the token twice. + * + * ## Availables templates + * + * The following templates are available: + * + * - <strong>\#{name}</strong>: name will be substituted from the keywords in params, + * - <strong>\${name}</strong>: name will be substituted from the environment variable, + * - <strong>\@{attributes}</strong>: the attributes will be substituted to IRC colors (see below), + * - <strong>%</strong>, any format accepted by strftime(3). + * + * ## Attributes + * + * The attribute format is composed of three parts, foreground, background and modifiers, each separated by a comma. + * + * **Note:** you cannot omit parameters, to specify the background, you must specify the foreground. + * + * ## Examples + * + * ### Valid constructs + * + * - <strong>\#{target}, welcome</strong>: if target is set to "irccd", becomes "irccd, welcome", + * - <strong>\@{red}\#{target}</strong>: if target is specified, it is written in red, + * + * ### Invalid or literals constructs + * + * - <strong>\#\#{target}</strong>: will output "\#{target}", + * - <strong>\#\#</strong>: will output "\#\#", + * - <strong>\#target</strong>: will output "\#target", + * - <strong>\#{target</strong>: will throw std::invalid_argument. + * + * ### Colors & attributes + * + * - <strong>\@{red,blue}</strong>: will write text red on blue background, + * - <strong>\@{default,yellow}</strong>: will write default color text on yellow background, + * - <strong>\@{white,black,bold,underline}</strong>: will write white text on black in both bold and underline. + */ +std::string format(std::string text, const Substitution ¶ms = {}); + +/** + * Remove leading and trailing spaces. + * + * @param str the string + * @return the removed white spaces + */ +std::string strip(std::string str); + +/** + * Split a string by delimiters. + * + * @param list the string to split + * @param delimiters a list of delimiters + * @param max max number of split + * @return a list of string splitted + */ +std::vector<std::string> split(const std::string &list, const std::string &delimiters, int max = -1); + +/** + * Join values by a separator and return a string. + * + * @param first the first iterator + * @param last the last iterator + * @param delim the optional delimiter + */ +template <typename InputIt, typename DelimType = char> +std::string join(InputIt first, InputIt last, DelimType delim = ':') +{ + std::ostringstream oss; + + if (first != last) { + oss << *first; + + while (++first != last) + oss << delim << *first; + } + + return oss.str(); +} + +/** + * Convenient overload. + * + * @param list the initializer list + * @param delim the delimiter + * @return the string + */ +template <typename T, typename DelimType = char> +inline std::string join(std::initializer_list<T> list, DelimType delim = ':') +{ + return join(list.begin(), list.end(), delim); +} + +/** + * Parse IRC message and determine if it's a command or a simple message. + * + * @param message the message line + * @param commandChar the command char (e.g '!') + * @param plugin the plugin name + * @return the pair + */ +MessagePair parseMessage(std::string message, const std::string &commandChar, const std::string &plugin); + +/** + * Server and identities must have strict names. This function can + * be used to ensure that they are valid. + * + * @param name the identifier name + * @return true if is valid + */ +inline bool isIdentifierValid(const std::string &name) +{ + return std::regex_match(name, std::regex("[A-Za-z0-9-_]+")); +} + +/** + * Check if the value is a boolean, 1, yes and true are accepted. + * + * @param value the value + * @return true if is boolean + * @note this function is case-insensitive + */ +bool isBoolean(std::string value) noexcept; + +/** + * Check if the string is an integer. + * + * @param value the input + * @param base the optional base + * @return true if integer + */ +bool isInt(const std::string &value, int base = 10) noexcept; + +/** + * Check if the string is real. + * + * @param value the value + * @return true if real + */ +bool isReal(const std::string &value) noexcept; + +/** + * Check if the string is a number. + * + * @param value the value + * @return true if it is a number + */ +inline bool isNumber(const std::string &value) noexcept +{ + return isInt(value) || isReal(value); +} + +/** + * Parse a network message from an input buffer and remove it from it. + * + * @param input the buffer, will be updated + * @return the message or empty string if there is nothing + */ +std::string nextNetwork(std::string &input); + +} // !util + +} // !irccd + +#endif // !IRCCD_UTIL_HPP
--- a/lib/irccd/xdg.h Tue Apr 19 10:17:52 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * xdg.h -- XDG directory specifications - * - * Copyright (c) 2013, 2014, 2015 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. - */ - -#ifndef IRCCD_XDG_H -#define IRCCD_XDG_H - -/** - * @file xdg.h - * @brief Read XDG standard specifications - */ - -#include <vector> -#include <string> - -namespace irccd { - -/** - * @class Xdg - * @brief XDG specifications - * - * Read and get XDG directories. This file contains exports thingies so it can - * compiles successfully on Windows but its usage is discouraged. - */ -class Xdg { -public: - /** - * list of directories. - */ - using List = std::vector<std::string>; - -private: - std::string m_configHome; - std::string m_dataHome; - std::string m_cacheHome; - std::string m_runtimeDir; - List m_configDirs; - List m_dataDirs; - -public: - /** - * Open an xdg instance and load directories. - * - * @throw std::runtime_error on failures - */ - Xdg(); - - /** - * Get the config directory. ${XDG_CONFIG_HOME} or ${HOME}/.config - * - * @return the config directory - */ - const std::string &configHome() const noexcept; - - /** - * Get the data directory. ${XDG_DATA_HOME} or ${HOME}/.local/share - * - * @return the data directory - */ - const std::string &dataHome() const noexcept; - - /** - * Get the cache directory. ${XDG_CACHE_HOME} or ${HOME}/.cache - * - * @return the cache directory - */ - const std::string &cacheHome() const noexcept; - - /** - * Get the runtime directory. ${XDG_RUNTIME_DIR} must be set, - * if not, it throws an exception. - * - * The XDG standard says that application should handle XDG_RUNTIME_DIR by - * themselves. - * - * @return the runtime directory - * @throw std::runtime_error on error - */ - const std::string &runtimeDir() const; - - /** - * Get the standard config directories. ${XDG_CONFIG_DIRS} or { "/etc/xdg" } - * - * @return the list of config directories - */ - const List &configDirs() const noexcept; - - /** - * Get the data directories. ${XDG_DATA_DIRS} or { "/usr/local/share", "/usr/share" } - * - * @return the list of data directories - */ - const List &dataDirs() const noexcept; -}; - -} // !irccd - -#endif // !IRCCD_XDG_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/xdg.hpp Wed Apr 20 19:45:00 2016 +0200 @@ -0,0 +1,112 @@ +/* + * xdg.h -- XDG directory specifications + * + * Copyright (c) 2013, 2014, 2015 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. + */ + +#ifndef IRCCD_XDG_H +#define IRCCD_XDG_H + +/** + * @file xdg.h + * @brief Read XDG standard specifications + */ + +#include <vector> +#include <string> + +namespace irccd { + +/** + * @class Xdg + * @brief XDG specifications + * + * Read and get XDG directories. This file contains exports thingies so it can + * compiles successfully on Windows but its usage is discouraged. + */ +class Xdg { +public: + /** + * list of directories. + */ + using List = std::vector<std::string>; + +private: + std::string m_configHome; + std::string m_dataHome; + std::string m_cacheHome; + std::string m_runtimeDir; + List m_configDirs; + List m_dataDirs; + +public: + /** + * Open an xdg instance and load directories. + * + * @throw std::runtime_error on failures + */ + Xdg(); + + /** + * Get the config directory. ${XDG_CONFIG_HOME} or ${HOME}/.config + * + * @return the config directory + */ + const std::string &configHome() const noexcept; + + /** + * Get the data directory. ${XDG_DATA_HOME} or ${HOME}/.local/share + * + * @return the data directory + */ + const std::string &dataHome() const noexcept; + + /** + * Get the cache directory. ${XDG_CACHE_HOME} or ${HOME}/.cache + * + * @return the cache directory + */ + const std::string &cacheHome() const noexcept; + + /** + * Get the runtime directory. ${XDG_RUNTIME_DIR} must be set, + * if not, it throws an exception. + * + * The XDG standard says that application should handle XDG_RUNTIME_DIR by + * themselves. + * + * @return the runtime directory + * @throw std::runtime_error on error + */ + const std::string &runtimeDir() const; + + /** + * Get the standard config directories. ${XDG_CONFIG_DIRS} or { "/etc/xdg" } + * + * @return the list of config directories + */ + const List &configDirs() const noexcept; + + /** + * Get the data directories. ${XDG_DATA_DIRS} or { "/usr/local/share", "/usr/share" } + * + * @return the list of data directories + */ + const List &dataDirs() const noexcept; +}; + +} // !irccd + +#endif // !IRCCD_XDG_H
--- a/tests/elapsedtimer/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/elapsedtimer/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -20,7 +20,7 @@ #include <gtest/gtest.h> -#include <irccd/elapsed-timer.h> +#include <irccd/elapsed-timer.hpp> using namespace irccd; using namespace std::chrono_literals;
--- a/tests/js-elapsedtimer/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/js-elapsedtimer/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -20,8 +20,8 @@ #include <thread> -#include <irccd/js-irccd.h> -#include <irccd/js-elapsed-timer.h> +#include <irccd/js-irccd.hpp> +#include <irccd/js-elapsed-timer.hpp> using namespace irccd; using namespace std::chrono_literals;
--- a/tests/js-file/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/js-file/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -20,8 +20,8 @@ #include <gtest/gtest.h> -#include <irccd/js-file.h> -#include <irccd/js-irccd.h> +#include <irccd/js-file.hpp> +#include <irccd/js-irccd.hpp> using namespace irccd;
--- a/tests/js-irccd/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/js-irccd/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,10 +18,10 @@ #include <gtest/gtest.h> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include <irccd/js-irccd.h> -#include <irccd/logger.h> +#include <irccd/js-irccd.hpp> +#include <irccd/logger.hpp> using namespace irccd;
--- a/tests/js-logger/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/js-logger/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,11 +18,11 @@ #include <gtest/gtest.h> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include <irccd/js-irccd.h> -#include <irccd/js-logger.h> -#include <irccd/logger.h> +#include <irccd/js-irccd.hpp> +#include <irccd/js-logger.hpp> +#include <irccd/logger.hpp> using namespace irccd;
--- a/tests/js-system/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/js-system/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,9 +18,9 @@ #include <gtest/gtest.h> -#include <irccd/js-irccd.h> -#include <irccd/js-system.h> -#include <irccd/system.h> +#include <irccd/js-irccd.hpp> +#include <irccd/js-system.hpp> +#include <irccd/system.hpp> using namespace irccd;
--- a/tests/js-timer/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/js-timer/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,9 +18,9 @@ #include <gtest/gtest.h> -#include <irccd/elapsed-timer.h> -#include <irccd/irccd.h> -#include <irccd/system.h> +#include <irccd/elapsed-timer.hpp> +#include <irccd/irccd.hpp> +#include <irccd/system.hpp> using namespace irccd;
--- a/tests/js-unicode/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/js-unicode/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -22,8 +22,8 @@ #include <gtest/gtest.h> -#include <irccd/js-irccd.h> -#include <irccd/js-unicode.h> +#include <irccd/js-irccd.hpp> +#include <irccd/js-unicode.hpp> using namespace irccd;
--- a/tests/js-util/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/js-util/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,8 +18,8 @@ #include <gtest/gtest.h> -#include <irccd/js-irccd.h> -#include <irccd/js-util.h> +#include <irccd/js-irccd.hpp> +#include <irccd/js-util.hpp> using namespace irccd;
--- a/tests/path/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/path/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,10 +18,10 @@ #include <gtest/gtest.h> -#include <irccd/sysconfig.h> +#include <irccd/sysconfig.hpp> -#include <irccd/logger.h> -#include <irccd/path.h> +#include <irccd/logger.hpp> +#include <irccd/path.hpp> namespace irccd {
--- a/tests/rules/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/rules/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,7 +18,7 @@ #include <gtest/gtest.h> -#include <irccd/rule.h> +#include <irccd/rule.hpp> namespace irccd {
--- a/tests/timer/main.cpp Tue Apr 19 10:17:52 2016 +0200 +++ b/tests/timer/main.cpp Wed Apr 20 19:45:00 2016 +0200 @@ -18,8 +18,8 @@ #include <gtest/gtest.h> -#include <irccd/elapsed-timer.h> -#include <irccd/timer.h> +#include <irccd/elapsed-timer.hpp> +#include <irccd/timer.hpp> using namespace irccd; using namespace std::chrono_literals;