# HG changeset patch # User David Demelier # Date 1613586780 -3600 # Node ID 201ddc48780721cd436339f6632d54fa78a628d8 # Parent 936cbd66b4b8c5a1935cfaefd092eacc0b83e21c irccd: add irccd.conf file diff -r 936cbd66b4b8 -r 201ddc487807 INSTALL.md --- a/INSTALL.md Tue Feb 16 22:59:00 2021 +0100 +++ b/INSTALL.md Wed Feb 17 19:33:00 2021 +0100 @@ -1,22 +1,21 @@ IRC Client Daemon INSTALL ========================= -This guide will help you to install irccd on your computer. +This guide will help you to install irccd Requirements ------------ -- GCC 7.0 or Clang 6.0, -- [Boost](http://boost.org), -- [CMake](http://www.cmake.org). - -Optional: +Build dependencies: -- [OpenSSL](http://openssl.org), Used for SSL connections to IRC servers, - recommended, -- [UriParser](https://uriparser.github.io), Required for the links plugin, -- [Doxygen](http://www.stack.nl/~dimitri/doxygen), For the documentation about - irccd internals. +- C99 and few features from C11 (stdatomics, stdnoreturn). +- [Bison][] and [Flex][]: For configuration files. +- [CMake][]: Portable build system. + +Optional runtime dependencies: + +- [OpenSSL][]: Used for SSL connections to IRC servers (recommended). +- [CURL][]: Required for the links plugin. Basic installation ------------------ @@ -30,3 +29,9 @@ cmake .. -DCMAKE_BUILD_TYPE=Release make sudo make install + +[Bison]: https://www.gnu.org/software/bison +[CMake]: http://www.cmake.org +[CURL]: https://curl.se +[Flex]: https://github.com/westes/flex +[OpenSSL]: http://openssl.org diff -r 936cbd66b4b8 -r 201ddc487807 STYLE.md --- a/STYLE.md Tue Feb 16 22:59:00 2021 +0100 +++ b/STYLE.md Wed Feb 17 19:33:00 2021 +0100 @@ -1,12 +1,12 @@ -IRC Client Daemon CODING STYLE -============================== +irccd CODING STYLE +================== File content ============ - Use UTF-8 charset, - Use Unix line endings, -- Never write two blank consecutives blank lines. +- Never write two consecutives blank lines. Indent ====== @@ -49,14 +49,13 @@ This example will not align correctly if tabstops are not set to 8. -C++ -=== +C += Style ----- -- Do not exceed 120 columns for lines of code, -- Do not exceed 80 columns for comments, +- Do not exceed 80 columns. ### Braces @@ -65,7 +64,7 @@ Do not put braces for single line statements. -```cpp +```c if (condition) { apply(); add(); @@ -82,19 +81,14 @@ Functions require braces on their own lines. -```cpp -void function() +```c +void +function() { } ``` -And a lambda has its braces on the same lines too: - -```cpp -sort([&] (auto&) { - return true; -}); -``` +Note: the type of a function is broken into its own line. ### Spaces @@ -103,75 +97,73 @@ Normal function calls do not require it. -```cpp +```c if (foo) destroy(sizeof (int)); ``` -### References and pointers +### Pointers -References and pointers are always next to the type name and not the variable. +Pointers are always next variable name. -```cpp -auto get(const std::string& name) -> T&; - -int* p = &x; +```c +void +cleanup(struct owner *owner); ``` -### Trailing return syntax +### Typedefs -We use trailing return syntax everywhere, it has the following benefits: +Do not use typedef for non-opaque objects. It is allowed for function pointers. -- Inner types don't need to be prefixed by class name, -- Functions are kept aligned correctly, focusing on the function name. +```c +struct pack { + int x; + int y; +}; -```cpp -auto func() -> std::string; +typedef void (*logger)(const char *line); ``` +Note: do never add `_t` suffix to typedef's. + ### Naming - English names, -- Member variables have trailing underscore (e.g foo\_bar\_), -- No hungarian notation. +- No hungarian notation, -Everything is in `underscore_case` except template parameters and macros. +Almost everything is in `underscore_case` except macros and enumeration +constants. -```cpp +```c #if defined(FOO) # include #endif -namespace baz { +#define MAJOR 1 +#define MINOR 0 +#define PATCH 0 -class object { -private: - std::string name_; - -public: - auto name() const noexcept -> const std::string&; +enum color { + COLOR_RED, + COLOR_GREEN, + COLOR_BLUE }; -template -void open(const Archive& ar) -{ - bool is_valid = false; -} - -} // !baz +void +add_widget(const struct widget *widget_to_add); ``` ### Header guards Do not use `#pragma once`. -Header guards are usually named `PROJECT_COMPONENT_FILENAME_HPP`. +Header guards are usually named `PROJECT_COMPONENT_FILENAME_H`. -```cpp -#ifndef FOO_COMMON_UTIL_HPP -#define FOO_COMMON_UTIL_HPP +```c +#ifndef FOO_COMMON_UTIL_H +#define FOO_COMMON_UTIL_H -#endif // !FOO_COMMON_UTIL_HPP +#endif /* !FOO_COMMON_UTIL_HPP */ ``` ### Enums @@ -179,13 +171,13 @@ Enumerations constants are always defined in separate line to allow commenting them as doxygen. -Enum class are encouraged. +Note: enumeration constants are prefixed with its name. -```cpp -enum class color { - blue, - red, - green +```c +enum color { + COLOR_RED, + COLOR_GREEN, + COLOR_BLUE }; ``` @@ -194,7 +186,7 @@ In a switch case statement, you **must** not declare variables and not indent cases. -```cpp +```c switch (variable) { case foo: do_some_stuff(); @@ -206,27 +198,26 @@ ### Files -- Use `.cpp` and `.hpp` as file extensions, +- Use `.c` and `.h` as file extensions, - Filenames are all lowercase. ### Comments Avoid useless comments in source files. Comment complex things or why it is done -like this. However any public function in the .hpp **must** be documented as -doxygen without exception. +like this. Do not use `//` style comments in C. -```cpp +```c /* * Multi line comments look like * this. */ -// Short comment +/* Short comment. */ ``` Use `#if 0` to comment blocks of code. -```cpp +```c #if 0 broken_stuff(); #endif @@ -236,195 +227,53 @@ The includes should always come in the following order. -1. C++ headers +1. System headers (POSIX mostly) 2. C header 3. Third party libraries 4. Application headers in "" -```cpp -#include -#include - +```c +#include #include +#include #include #include "foo.h" ``` -Note: always use C++ headers for C equivalent, stdio.h -> cstdio, etc. - Programming ----------- -### C language - -Do not use old C stuff like `void*`, `srand/rand`, `printf` or anything that -can be rewritten in modern C++. - -### RTTI - -Usage of `dynamic_cast` and `typeid` are completely disallowed in any shape of -form. - -### Arguments - -It is recommended to pass parameters by value or const reference. Usage of -non-const reference as output parameter is **discouraged** and should be avoided -in many case because it does not allow chaining of expressions like: +### C Standard -```cpp -std::cout << reverse(upper(clean(" hello world! "))) << std::endl; -``` - -If your function is designed to return a modified value passed as argument, it -is better to take it by value and modify it directly. - -```cpp -auto clean(std::string input) -> std::string -{ - if (!input.empty() && input.back() == '\r') - input.pop_back(); - - return input; -} -``` - -Never pass primitive types as const value. +Use C11 standard without extensions. ### Assertions -Use the `assert` macro from the cassert header file to verify programming +Use the `assert` macro from the assert.h header file to verify programming errors. For example, you may use `assert` to verify that the developer access the data between the bounds of an array: -```cpp -auto operator[](unsigned index) -> T& +```c +int +get(struct data *data, unsigned index) { - assert(index < length_); + assert(index < data->length); - return data_[index]; + return data->buffer[index]; } ``` The `assert` macro is not meant to check that a function succeeded, this code must not be written that way: -```cpp +```c assert(listen(10)); ``` -### Exceptions - -You must use exceptions to indicate an error that was unexpected such as: - -- Failing to open a file, -- I/O unexpected errors, -- Parsing errors, -- User errors. - -You may use the C++ standard exceptions defined in the stdexcept header but if -you need to carry more data within your exception, you should derive from -`std::exception`. - -### Error code - -You should not use error codes to indicate errors, instead use exceptions. -Error codes are allowed in Boost.Asio though. - -### Free functions - -Basic utility functions should be defined in a namespace as a free function not -as a static member function, we're doing C++ not Java. - -Example: - -```cpp -namespace util { - -auto clean(std::string input) -> std::string; - -} // !util -``` - -### Variables initialization - -Use parentheses to initialize non primitive types: - -```cpp -throw std::runtime_error("foo"); - -my_class obj("bar"); -``` - -Use brace initialization when you want to use an initializer list, type -elision: - -```cpp -std::vector v{1, 2, 3}; - -foo({1, 2}); // type deduced - -return { "true", false }; // std::pair returned -``` - -Use the assignment for primitive types: - -```cpp -int x = 123; -bool is_valid = true; -``` - -### Classes - -Classes are usually defined in the following order: - -1. Public inner types (enums, classes), -2. Protected/private members and functions -3. Public static functions. -3. Public member functions -4. Public virtual functions. - -```cpp -class foo { -public: - enum class type { - a, - b - }; - -private: - int member_{0}; - -public: - void some_function(); -}; -``` - -### Structs - -Use structs for objects that only need to store public data and have no -invariants. For example PODs and traits match this criteria: - -```cpp -struct point { - int x{0}; - int y{0}; -}; - -template <> -struct info_traits { - template - static void serialize(Archive& ar, const point& point) - { - ar.write(point.x); - ar.write(point.y); - } -}; -``` - ### Return The preferred style is to return early in case of errors. That makes the code @@ -432,18 +281,16 @@ This code is preferred: -```cpp +```c if (a_condition_is_not_valid) - return nullptr; + return false; if (an_other_condition) - return nullptr; + return false; -auto x = std::make_shared(); +start(); +save(); -x->start(); -x->save(); - -return x; +return true; ``` Additional rules: @@ -451,61 +298,63 @@ - Do never put parentheses between the returned value, - Do not put a else branch after a return. -### Auto - -We encorage usage of `auto`, it reduces code maintainance as you don't need to -change your code when your rename types. +Shell +===== -```cpp -auto it = std::find_if(v.begin(), v.end(), [&] (const auto& obj) { - return obj.key() == "foo"; -}); +Write POSIX shell only with no bash, zsh or any extension. -for (const auto& pair : a_map) - std::cout << pair.first << " = " << pair.second << std::endl; -``` - -But do not use `auto` to write code like in python, this is not acceptable: +Style +----- -```cpp -auto o = my_object("foo"); -``` +- Try to keep lines shorter than 80 columns -### String views +Functions +--------- -Use `std::string_view` each time you need a string that you will not own, this -includes: temporary arguments, return values, compile time constants. +Don't use `function` keyword, just keep the function name. -```cpp -const std::string_view version("1.0"); - -void load(std::string_view id, std::string_view path) +```sh +usage() { - std::cout << "loading: " << id << " from path: " << path << std::endl; } ``` -### Optional values - -Use `std::optional` to indicate a null value considered as valid. For example, -searching a value that may not exist. +It's usually recommended to prefix functions names with the program name to +avoid collisions with global commands. -```cpp -auto find(std::string_view id) -> std::optional +```sh +foo_clean() { - if (auto it = foo.find(id); it != foo.end()) - return it->second; +} - return std::nullopt; +foo_process() +{ } ``` -### Avoid definitions in headers +Options +------- + +For options, use `getopts` and prefer short options to long unless necessary. +Also set OPTERR=0 to avoid printing errors and do it yourself for UX +consistency. -Try to avoid as much as possible function definition in header file. It slow -down compilation because the compiler has to parse the syntax over and over. -It's even worse as you may need to recompile a lot of files when you change a -header rather than a source file. +```sh +OPTERR=0 +while getopts "v" arg; do + case $arg in + v) + verbose=1 + ;; + esac +done +``` + +Naming +------ + +Use `UPPERCASE` variables for global variables and `lowercase` for temporary or +local variables. CMake ===== @@ -513,7 +362,7 @@ Style ----- -- Try to keep line shorter than 80 columns +- Try to keep lines shorter than 80 columns ### Spaces @@ -674,7 +523,7 @@ ----------- You can use three backticks and the language specifier or just indent a block by -for leading spaces if you don't need syntax. +for leading tabs if you don't need syntax. ```cpp std::cout << "hello world" << std::endl; diff -r 936cbd66b4b8 -r 201ddc487807 irccd/CMakeLists.txt --- a/irccd/CMakeLists.txt Tue Feb 16 22:59:00 2021 +0100 +++ b/irccd/CMakeLists.txt Wed Feb 17 19:33:00 2021 +0100 @@ -94,5 +94,6 @@ set_target_properties(irccd PROPERTIES ENABLE_EXPORTS On) target_link_libraries(irccd irccd-fe) install(TARGETS irccd DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(FILES irccd.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR} RENAME irccd.conf.sample) source_group(TREE ${irccd_SOURCE_DIR} FILES ${SOURCES}) diff -r 936cbd66b4b8 -r 201ddc487807 irccd/irccd.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccd/irccd.conf Wed Feb 17 19:33:00 2021 +0100 @@ -0,0 +1,131 @@ +# +# This is an example of irccd.conf file. +# +# Comments start with a '#' like this header and until the end of lines. +# +# See the irccd.conf(5) manual page for details of the file syntax and +# available options. +# + +# +# logs +# ---------------------------------------------------------------------- +# +# You can configure verbosity and adapter which can be console to log to +# stdout/stderr, syslog for system logging or a unique file. +# +# Default is non-verbose on console + +logs to console + +# +# Verbose on syslog +# logs verbose to syslog +# +# Explicitly quiet to a file +# logs quiet to file "/var/log/irccd/messages" +# + +# +# transport +# ---------------------------------------------------------------------- +# +# Enable irccd control through a UNIX domain socket via TCP. This is required +# for the irccdctl utility. +# +# Default is /tmp/irccd.sock +# + +transport to /tmp/irccd.sock + +# +# server +# ---------------------------------------------------------------------- +# +# Connect to an IRC server. Create a block for every server you want irccd to +# connect to. +# +# The options `hostname', `port' and `ident' are required. +# +# It is recommended to put quotes around the server identifiers to avoid +# colliding with syntax keywords. +# +# server "example" { +# hostname "example.org"; # Quotes are preferred. +# port 6667; # Don't use quotes, it's a number. +# ident "frc" "frc" "frc"; # Nickname, Username and Real name. There are no +# # comma because it's not a list. +# ssl; # Set to enable SSL. +# channels "#test", "#staff"; # List of channels to join. +# options AUTO-REJOIN; # Enable auto-rejoin after a kick. +# prefix "!"; # Prefix for invoking plugins. +# } +# + +# +# rule +# ---------------------------------------------------------------------- +# +# Create rules to filter plugins and their usage depending on criteria. They are +# evaluated in order they are defined. An empty block match every event. +# +# This rule drop *everything*. +# rule drop +# +# This rule `reallows' plugins hangman on channel #games and #test from the +# server example. +# +# rule accept { +# servers "example"; +# plugins "hangman"; +# channels "#test", "#games"; +# } +# + +# +# hooks +# ---------------------------------------------------------------------- +# +# Hooks are independant approach to capturing events. They are invoked as-is +# from irccd upon a new event. They can be written in any language as long as +# they are executable. They can't be filtered through rules. +# +# hook "notify" to "/usr/local/bin/myscript.sh" +# + +# +# plugins +# ---------------------------------------------------------------------- +# +# Load Javascript and native C plugins. The block options is optional, if not +# present the plugin is searched through a standard set of directories. +# +# It is recommended to put quotes around the plugin identifiers to avoid +# colliding with syntax keywords. +# +# This will load the plugin `ask' from default path and default options. +# plugin "ask" +# +# This will load the plugin `hangman' and set custom configuration options and +# templates. +# plugin "hangman" { +# config { +# "collaborative" "false"; +# } +# templates { +# "win" "Congrats #{nickname}, you found #{word}"; +# } +# } +# +# This will load a plugin `custom' with a custom location and override its +# paths. +# plugin "custom" { +# location "/opt/custom.js"; +# +# paths { +# "data" "/opt/custom/data"; +# "cache" "/opt/custom/cache"; +# "config" "/opt/custom"; +# } +# } +# diff -r 936cbd66b4b8 -r 201ddc487807 man/irccd.conf.5 --- a/man/irccd.conf.5 Tue Feb 16 22:59:00 2021 +0100 +++ b/man/irccd.conf.5 Wed Feb 17 19:33:00 2021 +0100 @@ -195,7 +195,7 @@ the current event. .Pp The following directives are allowed in the -.Em options +.Em criteria block: .Bl -tag -width "channels list" .It Ar servers list diff -r 936cbd66b4b8 -r 201ddc487807 plugins/CMakeLists.txt --- a/plugins/CMakeLists.txt Tue Feb 16 22:59:00 2021 +0100 +++ b/plugins/CMakeLists.txt Wed Feb 17 19:33:00 2021 +0100 @@ -16,16 +16,42 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # +set( + JS_PLUGINS + ask + auth + hangman + history + joke + logger + plugin + roulette + tictactoe +) + +set( + C_PLUGINS + links +) + +foreach (p ${C_PLUGINS} ${JS_PLUGINS}) + string(TOUPPER ${p} opt) + option(IRCCD_WITH_PLUGIN_${opt} "Enable ${p} plugin" On) +endforeach () + if (IRCCD_WITH_JS) - add_subdirectory(ask) - add_subdirectory(auth) - add_subdirectory(hangman) - add_subdirectory(history) - add_subdirectory(joke) - add_subdirectory(logger) - add_subdirectory(plugin) - add_subdirectory(roulette) - add_subdirectory(tictactoe) + foreach (p ${JS_PLUGINS}) + string(TOUPPER ${p} p) + if (IRCCD_WITH_PLUGIN_${p}) + add_subdirectory(${p}) + endif () + endforeach () endif () -add_subdirectory(links) +foreach (p ${C_PLUGINS}) + string(TOUPPER ${p} p) + + if (IRCCD_WITH_PLUGIN_${p}) + add_subdirectory(links) + endif () +endforeach ()