diff --git a/README.md b/README.md
index a49bf413337929998b4c7071f5c119df95da2402..749c74c16ddf988f593241e40b0727d61218055d 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,6 @@ Prerequisites:
 
 - [meson](https://mesonbuild.com/)
 - a C compiler with C18 support (e.g. `gcc>8.1`, `clang>7.0`)
-- the [libpcre](http://www.pcre.org/) development library
 - the [sqlite3](https://www.sqlite.org/) development library, version 3.31.0 or
   newer for [generated columns](https://www.sqlite.org/gencol.html) support
 - the [json-c](https://github.com/json-c/json-c) development library
@@ -25,16 +24,19 @@ configuration file:
 
 - mkvpropedit from [mkvtoolnix](https://gitlab.com/mbunkus/mkvtoolnix)
 - the bourn shell again: [bash](https://git.savannah.gnu.org/cgit/bash.git)
-- the command line tool [sqlite](https://www.sqlite.org/)
+- the command line tool xxd, is distributed in the
+  [vim](https://www.archlinux.org/packages/extra/x86_64/vim/) and
+  [gvim](https://www.archlinux.org/packages/extra/x86_64/gvim/) packages on
+  archlinux, seems to be distributed in its own package on debian:
+  [xxd](https://packages.debian.org/sid/xxd)
 
 The manual way of installing and setting up lektor:
 
 ```sh
-meson build
-ninja -C build
-./build/lktadm init database            # Create the database
-./build/lktadm init metadata            # Modify mkv, if the metadata ar already set do not do this
-./build/lktadm init populate            # Papulate the database with karas on the filesystem
+sudo mkdir /home/kara && sudo chown USER:USER /home/kara
+meson build && cd build
+ninja && ninja install
+sudo chown USER:USER /home/kara/kara.db
 ```
 
 You may need to put the `lib_window_x11.so` in the right directory to have the
@@ -52,20 +54,14 @@ lektor can store it in its database. This information is to be directly
 written in the `.mkv` file.
 
 For that purpose, run the `karadata` from the command-line, with your kara as an
-argument, like:
+argument. For that, karas must be placed in a folder hierarchy like the following:
 
 ```
-./lktadm --file /path/to/my/kara.mkv
+/some/directory/$CAT/$LANG/$AUTH/$SOURCE - $TYPE$NUM - $TITLE.mkv
 ```
 
-or
-
-```
-./lktadm --prompt-file /path/to/my/kara.mkv
-```
-
-A karamaker may use the `scripts/karafont.py` to set the right MIME type for
-fonts (stored as attachments in the mkv).
+The ideal way of populating lektor is using *Kurisu*. The *update* and *rescan*
+commands are here for that.
 
 ## How to launch lektor
 
@@ -78,6 +74,8 @@ card with optimus (in almose every laptop), please use `optirun` or `primusrun`:
 optirun ./lektord
 ```
 
+The `x11` module may have some issues with `optirun` and `primusrun`.
+
 ## How to use lektor
 
 Lektor is compatible with mpd, which means that you can use any client (only mpc is
@@ -94,7 +92,7 @@ done by the same INI file using diferent sections.
 Lektor searches for the configuration file in that order:
 
 - `$(pwd)/lektor.ini`
-- if XDG_CONFIG_HOME defined then `$XDG_CONFIG_HOME/lektor/lektor.ini` else
+- if `XDG_CONFIG_HOME` defined then `$XDG_CONFIG_HOME/lektor/lektor.ini` else
   `$HOME/.config/lektor/lektor.ini`
 - `/opt/lektor/lektor.ini`
 - `/usr/local/etc/lektor.ini`
@@ -103,7 +101,11 @@ Lektor searches for the configuration file in that order:
 The first one to be found is picked up by lektor. Note that if the environment
 variable `XDG_CONFIG_HOME` is not defined, it is replaced by `HOME/.config`.
 
-To get the default config file, you can use the `lktadm` command.
+To get the default config file, you can use the `lktadm` command. To see what
+are the settings used by lektor, you can also use the `lktadm` command.
+
+Be aware that if the home directory or the `XDG_CONFIG_HOME` are too long
+they will be ignored.
 
 ## Modules
 
@@ -114,12 +116,14 @@ function named `module_set_function` which takes a `void *` and a
 The name of this function can be defined in the INI file.
 
 Module can be configured with the ini configuration file in a section named
-`module_${name}`.
+`module_${name}`, this a convention but it can be anything as long as it
+don't make collision with sections used by lektor (may be fine, but don't to
+this!).
 
 Like in the *player*, modules are loaded into slots and **must be** refered by
 their section name. The function used to load the `.so` file will be determied
-depending on the context in which the module is configured and will pass the
-option corresponding on the section's name.
+by the `load_function` property. The path to the `.so` file is determined by
+the `path` property.
 
 ## MPD
 
diff --git a/doc/lktadm.1 b/doc/lktadm.1
index f7309e8b9180698700a7f169fd75555b76c59b03..50bac19f2e341d6d1497111141d4a97f64006f51 100644
--- a/doc/lktadm.1
+++ b/doc/lktadm.1
@@ -36,6 +36,10 @@ Display the metadata of a kara specified by the its path
 .TP
 \fBconf\fP
 Prints the default configuration file to stdout
+.TP
+\fBsource\fP
+Prints the configuration that is red by lektor, this is the configuration that
+will use \fBlektord\fP when launched. Usefull when debuging
 
 .PP
 \fIINITIALISATION-COMMANDS\fP
diff --git a/inc/common/common.h b/inc/common/common.h
index 010317a55701bac4c098445ba77458d04ac06c93..1b930726ff83c7dedf59c4ddde86a6c0fd10dbaa 100644
--- a/inc/common/common.h
+++ b/inc/common/common.h
@@ -1,7 +1,8 @@
 #pragma once
 
-#include <common/define.h>
 #include <common/macro.h>
+#include <unistd.h>
+#include <stdint.h>
 
 #define not_implemented() __not_implemented(__func__,__FILE__,__LINE__)
 extern void __not_implemented(const char *func, char *file, int line);
@@ -10,3 +11,26 @@ extern void __not_implemented(const char *func, char *file, int line);
 void __unused(void *, ...);
 
 long get_mtime(const char *path);
+
+void *safe_malloc(size_t size);
+
+int is_utf8(const char *string);
+
+/* Read `bytes` as the big endian representation of a 32-bit unsigned integer.
+   `n` is the number of bytes in `bytes`
+   Returns 0 if n is 0.
+   Restriction: n <= 4 */
+uint32_t be_uint32_t(const uint8_t bytes[], size_t n);
+
+/* Same as `be_uint32_t` but for 64-bit unsigned integers.
+   Restriction: n <= 8 */
+uint64_t be_uint64_t(const uint8_t bytes[], size_t n);
+
+/* Trim the string `str` of the char `c` from the right and the left.
+   The string may not be null terminated.
+   Returns a pointer to the the trimmed string
+   Restrictions: the len of the string must be `len`. */
+char *trim(char *str, size_t len, char c);
+
+/* Get a line from stdin safely. */
+int get_stdin_line(const char *prompt, char *buf, size_t len);
diff --git a/inc/common/define.h b/inc/common/define.h
deleted file mode 100644
index 3fd65003f2c1f471413b237d3729e0936506567e..0000000000000000000000000000000000000000
--- a/inc/common/define.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-/* Max value for any buffer, to not squash the stack. */
-#define BUFFER_MAX 4096
-
-#ifndef __GNUC__
-#define inline
-#endif
-
diff --git a/inc/common/macro.h b/inc/common/macro.h
index b2b3340067b940ff9498ab4449c27025fcb05fe4..cc89cf2431af3263d8c6aa0eba34bf5e531d3d35 100644
--- a/inc/common/macro.h
+++ b/inc/common/macro.h
@@ -1,5 +1,17 @@
 #pragma once
 
+#include <stdint.h>
+#include <stdlib.h>
+
+/* Max value for any buffer, to not squash the stack. */
+#define BUFFER_MAX 4096
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+/* Macros */
+
 #define BRACKETS_THAT(that) (that)
 
 #ifndef MAX
@@ -51,3 +63,109 @@
 #define LOG_WARN(format, ...)                   LOG_WARN_SCT("", format, __VA_ARGS__)
 #define LOG_ERROR(format, ...)                  LOG_DEBUG_SCT("", format, __VA_ARGS__)
 #define LOG_DEBUG(format, ...)                  LOG_DEBUG_SCT("", format, __VA_ARGS__)
+
+/* Defines for lektor */
+
+#define INI_MAX_LINE_LEN    512
+#define INI_MAX_SECTION_LEN 80
+
+#define URL_MAX_LEN         1024
+#define DEFAULT_URL         "https://kurisu.iiens.net"
+#define GET_ID_JSON         DEFAULT_URL "/api_karas.php?id=%ld"
+#define GET_ID_FILE         DEFAULT_URL "/download.php?id=%ld"
+
+#define SELF_EXECUTABLE_LINUX           "/proc/self/exe"
+#define SELF_EXECUTABLE_FREEBSD         "/proc/curproc/file"
+#define SELF_EXECUTABLE_SOLARIS         "/proc/self/path/a.out"
+
+
+#define LKT_MAX_SQLITE_STATEMENT        1024
+#define PROTECTED_DATABASE              "disk"
+
+#define LKT_DATABASE_NAME_KID           "id"
+#define LKT_DATABASE_NAME_KNAME         "source_name"
+#define LKT_DATABASE_NAME_KTITLE        "song_title"
+#define LKT_DATABASE_NAME_KCAT          "category"
+#define LKT_DATABASE_NAME_KTYPE         "song_type"
+#define LKT_DATABASE_NAME_KAUTHOR       "author_name"
+#define LKT_DATABASE_NAME_KAUTHOR_YEAR  "author_year"
+#define LKT_DATABASE_NAME_KLANG         "language"
+#define LKT_DATABASE_KARA_COLUMNT_ANY   "any_col"
+#define LKT_DATABASE_KARA_ALL           "string"
+
+#define LEKTOR_TAG_MAX                  256
+#define LKT_MESSAGE_ARGS_MAX            32
+#define LKT_MESSAGE_MAX                 2048
+#define LKT_DEFAULT_LIST_SIZE           10
+
+typedef volatile enum {
+    MPD_IDLE_NONE               = 0,
+
+    MPD_IDLE_DATABASE           = ( 1 << 1  ),
+    MPD_IDLE_UPDATE             = ( 1 << 2  ),
+    MPD_IDLE_STORED_PLAYLIST    = ( 1 << 3  ),
+    MPD_IDLE_PLAYLIST           = ( 1 << 4  ),
+    MPD_IDLE_PLAYER             = ( 1 << 5  ),
+    MPD_IDLE_MIXER              = ( 1 << 6  ),
+    MPD_IDLE_OUTPUT             = ( 1 << 7  ),
+    MPD_IDLE_OPTIONS            = ( 1 << 8  ),
+    MPD_IDLE_PARTITION          = ( 1 << 9  ),
+    MPD_IDLE_STICKER            = ( 1 << 10 ),
+    MPD_IDLE_SUBSCRIPTION       = ( 1 << 11 ),
+    MPD_IDLE_MESSAGE            = ( 1 << 12 ),
+
+    MPD_IDLE_ALL =
+        MPD_IDLE_DATABASE | MPD_IDLE_UPDATE | MPD_IDLE_STORED_PLAYLIST  |
+        MPD_IDLE_PLAYLIST | MPD_IDLE_PLAYER | MPD_IDLE_MIXER            |
+        MPD_IDLE_OUTPUT | MPD_IDLE_OPTIONS | MPD_IDLE_PARTITION         |
+        MPD_IDLE_STICKER | MPD_IDLE_SUBSCRIPTION | MPD_IDLE_MESSAGE,
+} mpd_idle_flag;
+
+#define LKT_BACKLOG         32
+#define COMMAND_LIST_MAX    64
+#define BUFFER_OUT_MAX      16
+#define MPD_VERSION         "0.21.16"
+
+/* Macros */
+
+#define SQLITE_PREPARE(db, stmt, SQL, goto_label)                               \
+    if (sqlite3_prepare_v2((sqlite3 *) db, SQL, -1, &(stmt), 0) != SQLITE_OK) { \
+        LOG_ERROR_SCT("DB", "Failed to prepare statement: %s",                  \
+                      sqlite3_errmsg((sqlite3 *) db));                          \
+        goto goto_label;                                                        \
+    }
+
+#define SQLITE_EXEC(db, SQL, goto_label)                                        \
+    if (sqlite3_exec((sqlite3 *) db, SQL, NULL, NULL, NULL) != SQLITE_OK) {     \
+        LOG_ERROR_SCT("DB", "Failed to exec statement: %s",                     \
+                      sqlite3_errmsg((sqlite3 *) db));                          \
+        goto goto_label;                                                        \
+    }
+
+#define SQLITE_BIND_TEXT(db, stmt, pos, text, error)                    \
+    if (sqlite3_bind_text(stmt, pos, text, -1, 0) != SQLITE_OK) {       \
+        LOG_ERROR_SCT("DB", "Failed to bind text %s at pos %d: %s",     \
+                      text, pos, sqlite3_errmsg((sqlite3 *) db));       \
+        goto error;                                                     \
+    }
+
+#define SQLITE_BIND_INT(db, stmt, pos, integer, error)                  \
+    if (sqlite3_bind_int(stmt, pos, integer) != SQLITE_OK) {            \
+        LOG_ERROR_SCT("DB", "Failed to bind int %d at pos %d: %s",      \
+                      integer, pos, sqlite3_errmsg((sqlite3 *) db));    \
+        goto error;                                                     \
+    }
+
+#define SQLITE_STEP(db, stmt, code, error)                              \
+    if (sqlite3_step(stmt) != code) {                                   \
+        LOG_ERROR_SCT("DB", "Failed to step: %s",                       \
+                      sqlite3_errmsg((sqlite3 *) db));                  \
+        goto error;                                                     \
+    }
+
+#define SQLITE_STEP_ROW(db, stmt, error)    SQLITE_STEP(db, stmt, SQLITE_ROW, error)
+#define SQLITE_STEP_DONE(db, stmt, error)   SQLITE_STEP(db, stmt, SQLITE_DONE, error)
+#define SQLITE_STEP_OK(db, stmt, error)     SQLITE_STEP(db, stmt, SQLITE_OK, error)
+
+#define SQLITE_DO_ROLLBACK(db)                                          \
+    sqlite3_exec((sqlite3 *) db, "ROLLBACK TRANSACTION;\n", NULL, NULL, NULL);
diff --git a/inc/ini/ini.h b/inc/ini/ini.h
deleted file mode 100644
index 449d2dce0d01f9d0dc8c60f89ee2c6fece17d9ce..0000000000000000000000000000000000000000
--- a/inc/ini/ini.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* inih -- simple .INI file parser
-   SPDX-License-Identifier: BSD-3-Clause
-   Copyright (C) 2009-2020, Ben Hoyt */
-
-#ifndef __INI_H__
-#define __INI_H__
-
-/* Make this header file easier to include in C++ code */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h>
-
-/* Nonzero if ini_handler callback should accept lineno parameter. */
-#ifndef INI_HANDLER_LINENO
-#define INI_HANDLER_LINENO 0
-#endif
-
-/* Typedef for prototype of handler function. */
-#if INI_HANDLER_LINENO
-typedef int (*ini_handler)(void *user, const char *section,
-                           const char *name, const char *value,
-                           int lineno);
-#else
-typedef int (*ini_handler)(void *user, const char *section,
-                           const char *name, const char *value);
-#endif
-
-/* Typedef for prototype of fgets-style reader function. */
-typedef char *(*ini_reader)(char *str, int num, void *stream);
-
-/* Parse given INI-style file. May have [section]s, name=value pairs
-   (whitespace stripped), and comments starting with ';' (semicolon). Section
-   is "" if name=value pair parsed before any section heading. name:value
-   pairs are also supported as a concession to Python's configparser.
-
-   For each name=value pair parsed, call handler function with given user
-   pointer as well as section, name, and value (data only valid for duration
-   of handler call). Handler should return nonzero on success, zero on error.
-
-   Returns 0 on success, line number of first error on parse error (doesn't
-   stop on first error), -1 on file open error, or -2 on memory allocation
-   error (only when INI_USE_STACK is zero).
-*/
-int ini_parse(const char *filename, ini_handler handler, void *user);
-
-/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
-   close the file when it's finished -- the caller must do that. */
-int ini_parse_file(FILE *file, ini_handler handler, void *user);
-
-/* Same as ini_parse(), but takes an ini_reader function pointer instead of
-   filename. Used for implementing custom or string-based I/O (see also
-   ini_parse_string). */
-int ini_parse_stream(ini_reader reader, void *stream, ini_handler handler,
-                     void *user);
-
-/* Same as ini_parse(), but takes a zero-terminated string with the INI data
-instead of a file. Useful for parsing INI data from a network socket or
-already in memory. */
-int ini_parse_string(const char *string, ini_handler handler, void *user);
-
-/* Nonzero to allow multi-line value parsing, in the style of Python's
-   configparser. If allowed, ini_parse() will call the handler with the same
-   name for each subsequent line parsed. */
-#ifndef INI_ALLOW_MULTILINE
-#define INI_ALLOW_MULTILINE 1
-#endif
-
-/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
-   the file. See https://github.com/benhoyt/inih/issues/21 */
-#ifndef INI_ALLOW_BOM
-#define INI_ALLOW_BOM 1
-#endif
-
-/* Chars that begin a start-of-line comment. Per Python configparser, allow
-   both ; and # comments at the start of a line by default. */
-#ifndef INI_START_COMMENT_PREFIXES
-#define INI_START_COMMENT_PREFIXES ";#"
-#endif
-
-/* Nonzero to allow inline comments (with valid inline comment characters
-   specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
-   Python 3.2+ configparser behaviour. */
-#ifndef INI_ALLOW_INLINE_COMMENTS
-#define INI_ALLOW_INLINE_COMMENTS 1
-#endif
-#ifndef INI_INLINE_COMMENT_PREFIXES
-#define INI_INLINE_COMMENT_PREFIXES ";"
-#endif
-
-/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */
-#ifndef INI_USE_STACK
-#define INI_USE_STACK 1
-#endif
-
-/* Maximum line length for any line in INI file (stack or heap). Note that
-   this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */
-#ifndef INI_MAX_LINE
-#define INI_MAX_LINE 200
-#endif
-
-/* Nonzero to allow heap line buffer to grow via realloc(), zero for a
-   fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is
-   zero. */
-#ifndef INI_ALLOW_REALLOC
-#define INI_ALLOW_REALLOC 0
-#endif
-
-/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK
-   is zero. */
-#ifndef INI_INITIAL_ALLOC
-#define INI_INITIAL_ALLOC 200
-#endif
-
-/* Stop parsing on first error (default is to keep parsing). */
-#ifndef INI_STOP_ON_FIRST_ERROR
-#define INI_STOP_ON_FIRST_ERROR 0
-#endif
-
-/* Nonzero to call the handler at the start of each new section (with
-   name and value NULL). Default is to only call the handler on
-   each name=value pair. */
-#ifndef INI_CALL_HANDLER_ON_NEW_SECTION
-#define INI_CALL_HANDLER_ON_NEW_SECTION 0
-#endif
-
-/* Nonzero to allow a name without a value (no '=' or ':' on the line) and
-   call the handler with value NULL in this case. Default is to treat
-   no-value lines as an error. */
-#ifndef INI_ALLOW_NO_VALUE
-#define INI_ALLOW_NO_VALUE 0
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __INI_H__ */
diff --git a/inc/lektor/bufferfd.h b/inc/lektor/bufferfd.h
index c6e4ccbc826bcc4608bc1f67618aa2bff3c36f71..ffc4aacd4cf2fc56693cb4bdf501d2840c82fa92 100644
--- a/inc/lektor/bufferfd.h
+++ b/inc/lektor/bufferfd.h
@@ -23,7 +23,7 @@
 
 #pragma once
 
-#include <lektor/common.h>
+#include <common/common.h>
 #include <stdint.h>
 #include <stdlib.h>
 
diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h
index 452d46bb66de87a963e52de47934b0e08912540e..a447ef3604501b192301410c5a365e592b11092e 100644
--- a/inc/lektor/commands.h
+++ b/inc/lektor/commands.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <lektor/common.h>
+#include <common/common.h>
 #include <lektor/net.h>
 #include <lektor/window.h>
 
diff --git a/inc/lektor/common.h b/inc/lektor/common.h
deleted file mode 100644
index ebb7faabb2356896afd2c17fd0c5f8a8b32745e5..0000000000000000000000000000000000000000
--- a/inc/lektor/common.h
+++ /dev/null
@@ -1,130 +0,0 @@
-#pragma once
-
-#include <common/macro.h>
-#include <common/define.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/* Defines */
-
-#define URL_MAX_LEN     1024
-#define DEFAULT_URL     "https://kurisu.iiens.net"
-#define GET_ID_JSON     DEFAULT_URL "/api_karas.php?id=%ld"
-#define GET_ID_FILE     DEFAULT_URL "/download.php?id=%ld"
-
-#define SELF_EXECUTABLE_LINUX           "/proc/self/exe"
-#define SELF_EXECUTABLE_FREEBSD         "/proc/curproc/file"
-#define SELF_EXECUTABLE_SOLARIS         "/proc/self/path/a.out"
-
-
-#define LKT_MAX_SQLITE_STATEMENT        1024
-#define PROTECTED_DATABASE              "disk"
-
-#define LKT_DATABASE_NAME_KID           "id"
-#define LKT_DATABASE_NAME_KNAME         "source_name"
-#define LKT_DATABASE_NAME_KTITLE        "song_title"
-#define LKT_DATABASE_NAME_KCAT          "category"
-#define LKT_DATABASE_NAME_KTYPE         "song_type"
-#define LKT_DATABASE_NAME_KAUTHOR       "author_name"
-#define LKT_DATABASE_NAME_KAUTHOR_YEAR  "author_year"
-#define LKT_DATABASE_NAME_KLANG         "language"
-#define LKT_DATABASE_KARA_COLUMNT_ANY   "any_col"
-#define LKT_DATABASE_KARA_ALL           "string"
-
-#define LEKTOR_TAG_MAX                  256
-#define LKT_MESSAGE_ARGS_MAX            32
-#define LKT_MESSAGE_MAX                 2048
-#define LKT_DEFAULT_LIST_SIZE           10
-
-typedef volatile enum {
-    MPD_IDLE_NONE               = 0,
-
-    MPD_IDLE_DATABASE           = ( 1 << 1  ),
-    MPD_IDLE_UPDATE             = ( 1 << 2  ),
-    MPD_IDLE_STORED_PLAYLIST    = ( 1 << 3  ),
-    MPD_IDLE_PLAYLIST           = ( 1 << 4  ),
-    MPD_IDLE_PLAYER             = ( 1 << 5  ),
-    MPD_IDLE_MIXER              = ( 1 << 6  ),
-    MPD_IDLE_OUTPUT             = ( 1 << 7  ),
-    MPD_IDLE_OPTIONS            = ( 1 << 8  ),
-    MPD_IDLE_PARTITION          = ( 1 << 9  ),
-    MPD_IDLE_STICKER            = ( 1 << 10 ),
-    MPD_IDLE_SUBSCRIPTION       = ( 1 << 11 ),
-    MPD_IDLE_MESSAGE            = ( 1 << 12 ),
-
-    MPD_IDLE_ALL =
-        MPD_IDLE_DATABASE | MPD_IDLE_UPDATE | MPD_IDLE_STORED_PLAYLIST  |
-        MPD_IDLE_PLAYLIST | MPD_IDLE_PLAYER | MPD_IDLE_MIXER            |
-        MPD_IDLE_OUTPUT | MPD_IDLE_OPTIONS | MPD_IDLE_PARTITION         |
-        MPD_IDLE_STICKER | MPD_IDLE_SUBSCRIPTION | MPD_IDLE_MESSAGE,
-} mpd_idle_flag;
-
-#define LKT_BACKLOG         32
-#define COMMAND_LIST_MAX    64
-#define BUFFER_OUT_MAX      16
-#define MPD_VERSION         "0.21.16"
-
-/* Macros */
-
-#define SQLITE_PREPARE(db, stmt, SQL, goto_label)                               \
-    if (sqlite3_prepare_v2((sqlite3 *) db, SQL, -1, &(stmt), 0) != SQLITE_OK) { \
-        LOG_ERROR_SCT("DB", "Failed to prepare statement: %s",                  \
-                      sqlite3_errmsg((sqlite3 *) db));                          \
-        goto goto_label;                                                        \
-    }
-
-#define SQLITE_EXEC(db, SQL, goto_label)                                        \
-    if (sqlite3_exec((sqlite3 *) db, SQL, NULL, NULL, NULL) != SQLITE_OK) {     \
-        LOG_ERROR_SCT("DB", "Failed to exec statement: %s",                     \
-                      sqlite3_errmsg((sqlite3 *) db));                          \
-        goto goto_label;                                                        \
-    }
-
-#define SQLITE_BIND_TEXT(db, stmt, pos, text, error)                    \
-    if (sqlite3_bind_text(stmt, pos, text, -1, 0) != SQLITE_OK) {       \
-        LOG_ERROR_SCT("DB", "Failed to bind text %s at pos %d: %s",     \
-                      text, pos, sqlite3_errmsg((sqlite3 *) db));       \
-        goto error;                                                     \
-    }
-
-#define SQLITE_BIND_INT(db, stmt, pos, integer, error)                  \
-    if (sqlite3_bind_int(stmt, pos, integer) != SQLITE_OK) {            \
-        LOG_ERROR_SCT("DB", "Failed to bind int %d at pos %d: %s",      \
-                      integer, pos, sqlite3_errmsg((sqlite3 *) db));    \
-        goto error;                                                     \
-    }
-
-#define SQLITE_STEP(db, stmt, code, error)                              \
-    if (sqlite3_step(stmt) != code) {                                   \
-        LOG_ERROR_SCT("DB", "Failed to step: %s",                       \
-                      sqlite3_errmsg((sqlite3 *) db));                  \
-        goto error;                                                     \
-    }
-
-#define SQLITE_STEP_ROW(db, stmt, error)    SQLITE_STEP(db, stmt, SQLITE_ROW, error)
-#define SQLITE_STEP_DONE(db, stmt, error)   SQLITE_STEP(db, stmt, SQLITE_DONE, error)
-#define SQLITE_STEP_OK(db, stmt, error)     SQLITE_STEP(db, stmt, SQLITE_OK, error)
-
-#define SQLITE_DO_ROLLBACK(db)                                          \
-    sqlite3_exec((sqlite3 *) db, "ROLLBACK TRANSACTION;\n", NULL, NULL, NULL);
-
-/* Random things */
-
-/* Read `bytes` as the big endian representation of a 32-bit unsigned integer.
-   `n` is the number of bytes in `bytes`
-   Returns 0 if n is 0.
-   Restriction: n <= 4 */
-uint32_t be_uint32_t(const uint8_t bytes[], size_t n);
-
-/* Same as `be_uint32_t` but for 64-bit unsigned integers.
-   Restriction: n <= 8 */
-uint64_t be_uint64_t(const uint8_t bytes[], size_t n);
-
-/* Trim the string `str` of the char `c` from the right and the left.
-   The string may not be null terminated.
-   Returns a pointer to the the trimmed string
-   Restrictions: the len of the string must be `len`. */
-char *trim(char *str, size_t len, char c);
-
-/* Get a line from stdin safely. */
-int get_stdin_line(const char *prompt, char *buf, size_t len);
diff --git a/inc/lektor/config.h b/inc/lektor/config.h
index 323e900ba5c80c9aebe43a449fed2052e33c7bdd..9affc9529330628379d66d95ba60885222b68321 100644
--- a/inc/lektor/config.h
+++ b/inc/lektor/config.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <lektor/common.h>
+#include <common/common.h>
 #include <stddef.h>
 #include <sqlite3.h>
 
@@ -30,7 +30,7 @@ static const char *const lkt_default_config_file =
     "; can be seen.\n"
     "[player]\n"
     "autoclear = true            ; Clear the queue when starting\n"
-    "module = module_winx11      ; Default module for the window\n"
+    "module = module_x11         ; Default module for the window\n"
     "def_random = false          ; Play at random per default\n"
     "def_consume = false         ; Consume per default\n"
     "def_single = false          ; Single per default\n"
diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index eb9b08cca9607c09c4cbd57770f9a32b1452058c..7494f9a21e70a520a8182a5e5fbafb017088cf79 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <lektor/common.h>
+#include <common/common.h>
 #include <lektor/mkv.h>
 #include <lektor/uri.h>
 
diff --git a/inc/lektor/mkv.h b/inc/lektor/mkv.h
index c88114269b99f7087f27a031160f77922faf0cff..21b3808c0b7ea7d3d27f99d101787729fafa5de2 100644
--- a/inc/lektor/mkv.h
+++ b/inc/lektor/mkv.h
@@ -23,7 +23,7 @@
  */
 #pragma once
 
-#include <lektor/common.h>
+#include <common/common.h>
 #include <linux/limits.h>
 #include <stddef.h>
 
diff --git a/inc/lektor/module/mpv.h b/inc/lektor/module/mpv.h
index a05fdaf900d5e2ad7a42de29dfaa929551fe7f87..db2070c48575be514ae6249d8e94449817cd7095 100644
--- a/inc/lektor/module/mpv.h
+++ b/inc/lektor/module/mpv.h
@@ -3,7 +3,7 @@
 #include <sqlite3.h>
 #include <mpv/client.h>
 #include <lektor/net.h>
-#include <lektor/common.h>
+#include <common/common.h>
 
 void lmpv_free(mpv_handle **ctx);
 mpv_handle *lmpv_new(unsigned long int wid);
diff --git a/inc/lektor/net.h b/inc/lektor/net.h
index fa721922d37e843e5d50cb0c82554779421a5950..1a4e96a780a486f11ab23410574468788560f8f2 100644
--- a/inc/lektor/net.h
+++ b/inc/lektor/net.h
@@ -1,7 +1,7 @@
 #pragma once
 
+#include <common/common.h>
 #include <lektor/mkv.h>
-#include <lektor/common.h>
 #include <lektor/config.h>
 #include <lektor/window.h>
 #include <lektor/thread.h>
diff --git a/inc/lektor/thread.h b/inc/lektor/thread.h
index 3e5e07a7ec809eedcda4642e8ac47233f2fd4e75..7a85147f7ab09ec0901a43f1559386f63a32e3fe 100644
--- a/inc/lektor/thread.h
+++ b/inc/lektor/thread.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <lektor/common.h>
+#include <common/common.h>
 #include <pthread.h>
 #include <sys/types.h>
 
diff --git a/inc/lektor/uri.h b/inc/lektor/uri.h
index c9a4d932566e8432b932bcbe676d69803d6cab41..b9ab50874ab07d438ef3a30bc666c337a9f41348 100644
--- a/inc/lektor/uri.h
+++ b/inc/lektor/uri.h
@@ -1,6 +1,5 @@
 #pragma once
 
-#include <lektor/common.h>
 #include <stddef.h>
 #include <stddef.h>
 #include <stdbool.h>
diff --git a/inc/lektor/window.h b/inc/lektor/window.h
index ab5f43b8b7e453874f393558029a0a6eb60e69fd..d61ed465718bf5ceced7d0dd2e7bdb335947b999 100644
--- a/inc/lektor/window.h
+++ b/inc/lektor/window.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <lektor/common.h>
+#include <common/common.h>
 #include <stdbool.h>
 #include <sqlite3.h>
 
diff --git a/inc/mthread/mthread_internal.h b/inc/mthread/mthread_internal.h
index 0462d0cf9ea8a4139e3178279770d6941a23a504..285f337ed5d1ad1393382f36a9d2c4983a9cdcfb 100644
--- a/inc/mthread/mthread_internal.h
+++ b/inc/mthread/mthread_internal.h
@@ -60,8 +60,6 @@ void mthread_spinlock_lock  (mthread_tst_t *atomic);
 void mthread_spinlock_unlock(mthread_tst_t *atomic);
 int  mthread_get_vp_rank();
 
-void *safe_malloc(size_t size);
-
 void mthread_insert_first(struct mthread_s *item, mthread_list_t *list);
 void mthread_insert_last (struct mthread_s *item, mthread_list_t *list);
 int  mthread_list_test   (struct mthread_s *item, mthread_list_t *list);
diff --git a/meson.build b/meson.build
index 3a06d3244e75a7e7d510f9cf1145b1ffa5bae427..b84a924c06bfdff7bbc79a2594d7aadf20d29dde 100644
--- a/meson.build
+++ b/meson.build
@@ -31,7 +31,6 @@ add_global_arguments('-D_REENTRANT', language: 'c')
 ## Sources for mthread
 mthread_sources = [ 'src/mthread/mthread.c'
                   , 'src/mthread/mthread_cond.c'
-                  , 'src/mthread/mthread_debug.c'
                   , 'src/mthread/mthread_key.c'
                   , 'src/mthread/mthread_mutex.c'
                   , 'src/mthread/mthread_once.c'
@@ -58,7 +57,6 @@ core_sources =  [ 'src/mkv/bufferfd.c'
                 , 'src/net/downloader.c'
                 , 'src/config.c'
                 , 'src/uri.c'
-                , 'src/ini/ini.c'
                 , 'src/thread.c'
                 ]
 
diff --git a/scripts/getmanpath.sh b/scripts/getmanpath.sh
old mode 100644
new mode 100755
diff --git a/scripts/install.sh b/scripts/install.sh
index 213e4d297b180ad3dd690cbb977f0053e75a6872..71fac2d1db4b2aa0633aff936f6e0e5af0409d92 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -15,4 +15,5 @@ type $LKTADM &>/dev/null
 $LKTADM conf > $LKT_INI                             || die
 sed "s+LKT_PREFIX+$MESON_INSTALL_PREFIX+g" $LKT_INI || die
 mkdir /home/kara >&/dev/null                        || echo '/home/kara already exists'
+$LKTADM source                                      || die
 $LKTADM init database                               || die
diff --git a/src/cmd.c b/src/cmd.c
index 4a38bddccedf921471fde4fc149ccc5fc8f28a01..b56e868ed499b0c89bbeb5c51b6b93f6d8180e30 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -1,7 +1,7 @@
 #define _POSIX_C_SOURCE 200809L
 
 #include <lektor/cmd.h>
-#include <lektor/common.h>
+#include <common/common.h>
 #include <sys/types.h>
 #include <stdlib.h>
 #include <strings.h>
@@ -17,7 +17,7 @@ help__()
 {
     if (!executable_name)
         exit(EXIT_FAILURE);
-    const char *const args[] = { man_executable_path, executable_name };
+    const char *const args[] = { man_executable_path, executable_name, NULL };
     execv(args[0], (char *const *) args);
     exit(EXIT_FAILURE);
 }
@@ -29,8 +29,8 @@ lkt_cmd_parse(struct lkt_cmd_opt *opts, int argc, const char **argv)
     struct lkt_cmd_opt *it = opts;
     lkt_cmd_callback call[2] = { NULL, NULL };
 
-    if (argc == 0 || *argv == NULL || strcasecmp(argv[0], "help") ||
-        strcasecmp(argv[0], "--help") || strcasecmp(argv[0], "-help"))
+    if (argc == 0 || *argv == NULL || ! strcasecmp(argv[0], "help") ||
+        ! strcasecmp(argv[0], "--help") || ! strcasecmp(argv[0], "-help"))
         goto help;
 
     /* Find the command */
diff --git a/src/commands.c b/src/commands.c
index 709d7f4f8c7fbb475289f0d84b1832524ac75715..03b289c1b91fecf2d38ba0100c0adf704a1e09e0 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -1,7 +1,6 @@
 #define _POSIX_C_SOURCE 200809L
 
 #include <common/common.h>
-#include <lektor/common.h>
 #include <lektor/commands.h>
 #include <lektor/database.h>
 #include <lektor/net.h>
diff --git a/src/common.c b/src/common.c
index 6b906e78c4bce33b04ba60c3e9c465ddba1ea56d..95a57368d5fa2f998cb34b0158861678d48df5f3 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1,3 +1,5 @@
+#define _POSIX_C_SOURCE 200809L
+
 #include <common/common.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -135,3 +137,15 @@ get_mtime(const char *path)
     struct stat statbuf;
     return (stat(path, &statbuf) == -1) ? 0 : statbuf.st_mtime;
 }
+
+void *
+safe_malloc(size_t size)
+{
+    void *tmp;
+    tmp = malloc(size);
+    if (!tmp) {
+        LOG_ERROR_SCT("GENERAL", "Out of memory, can't alloc '%ld' Bytes", size);
+        exit(1);
+    }
+    return tmp;
+}
diff --git a/src/config.c b/src/config.c
index cfc6e2b3eaef579628ad42f7a251ba7be3880aeb..707c48ecd7d904405b0863e7467cda4942b4b1b4 100644
--- a/src/config.c
+++ b/src/config.c
@@ -3,7 +3,6 @@
 #include <common/common.h>
 #include <lektor/config.h>
 #include <lektor/database.h>
-#include <ini/ini.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
@@ -14,6 +13,103 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <limits.h>
+#include <ctype.h>
+
+typedef int (*ini_handler)(volatile sqlite3 *db, const char *section, const char *name, const char *value);
+
+static inline char *
+strip(char *s)
+{
+    char *p = s + strlen(s);
+    while (p > s && isspace(*(--p)))
+        *p = 0;
+    return s;
+}
+
+static inline char *
+skip(char *s)
+{
+    while (*s && isspace(*s))
+        s++;
+    return s;
+}
+
+static inline int
+ini_parse(const char *path, ini_handler handle, volatile sqlite3 *db)
+{
+    char *start, *end, *name, *value;
+    char section[INI_MAX_SECTION_LEN], line[INI_MAX_LINE_LEN];
+    int error = 0, linenum = 0, len;
+    FILE *file = fopen(path, "r");
+    if (!file) {
+        LOG_ERROR_SCT("PARSER", "Failed to open config file '%s'", path);
+        return 1;
+    }
+
+    /* Parse the file */
+    while (NULL != fgets(line, INI_MAX_LINE_LEN, file)) {
+        ++linenum;
+        start = skip(strip(line));
+
+        /* Skip comments */
+        if (strspn(start, ";#"))
+            continue;
+
+        /* Handle sections */
+        else if (start[0] == '[') {
+            end = &start[1 + strcspn(start + 1, "]")];
+            if (end[0] == ']') {
+                end[0] = '\0';
+                len = strlen(&start[1]);
+                len = MIN(len + 1, INI_MAX_SECTION_LEN);
+                memcpy(section, &start[1], len);
+                section[INI_MAX_SECTION_LEN - 1] = '\0';
+            }
+
+            else {
+                error = 1;
+                LOG_ERROR_SCT("PARSER", "Invalid section name at line '%d'", linenum);
+            }
+        }
+
+        /* Handle name[:=]name pair */
+        else if (start[0]) {
+            end = &start[1 + strcspn(start + 1, ":=")];
+            if (end[0] == '=' || end[0] == ':') {
+                end[0] = '\0';
+                name   = strip(start);
+                value  = &end[1];
+
+                /* Find a comment */
+                end = &value[strcspn(value, ";#")];
+                if (end[0])
+                    end[0] = '\0';
+
+                /* Skip all spaces */
+                value = skip(value);
+                strip(value);
+
+                /* Handle the SECTION, NAME[:=]VALUE */
+                if (handle(db, section, name, value)) {
+                    error = 1;
+                    LOG_ERROR_SCT("PARSER", "Failed to '[handle] %s, %s{:,=}%s' at line '%d'",
+                                  section, name, value, linenum);
+                }
+            }
+
+            else {
+                error = 1;
+                LOG_ERROR_SCT("PARSER", "Invalid name[:=]value pair at line '%d'", linenum);
+            }
+        }
+    }
+
+    /* End of the function */
+    fclose(file);
+    if (error)
+        LOG_ERROR_SCT("PARSER", "An error occured while parsing the file '%s'", path);
+    return error;
+}
 
 int
 load_so(const char *const mod_path, const char *const mod_init, void *mod)
@@ -46,10 +142,10 @@ load_so(const char *const mod_path, const char *const mod_init, void *mod)
 inline int
 load_module_by_name(volatile sqlite3 *db, const char *name, void *mod)
 {
-    char mod_path[PATH_MAX], mod_load[INI_MAX_LINE];
+    char mod_path[PATH_MAX], mod_load[INI_MAX_LINE_LEN];
 
     if (!database_config_get_text(db, name, "path", mod_path, PATH_MAX) ||
-        !database_config_get_text(db, name, "load_function", mod_load, INI_MAX_LINE)) {
+        !database_config_get_text(db, name, "load_function", mod_load, INI_MAX_LINE_LEN)) {
         LOG_ERROR("Module named %s is incomplete or is not defined in config file", name);
         return 1;
     }
@@ -67,37 +163,31 @@ validate_conf(volatile sqlite3 *db)
     }
 
     CHK_OPTION("externals", "mkvpropedit");
-    CHK_OPTION("externals", "sqlite3");
 
     CHK_OPTION("server", "host");
     CHK_OPTION("server", "port");
     CHK_OPTION("server", "max_clients");
 
-    CHK_OPTION("player", "module");
+    CHK_OPTION("database", "kara_dir");
+    CHK_OPTION("database", "db_path");
+
     CHK_OPTION("player", "autoclear");
     CHK_OPTION("player", "def_random");
     CHK_OPTION("player", "def_consume");
     CHK_OPTION("player", "def_single");
     CHK_OPTION("player", "def_repeat");
-
-    CHK_OPTION("database", "kara_dir");
-    CHK_OPTION("database", "db_path");
+    CHK_OPTION("player", "module");
+#undef CHK_OPTION
 
     return 0;
 }
 
 static int
-#if INI_HANDLER_LINENO
-handler(void *user, const char *section, const char *name, const char *value, int lineno)
+handler(volatile sqlite3 *user, const char *section, const char *name, const char *value)
 {
-    UNUSED(lineno);
-#else
-handler(void *user, const char *section, const char *name, const char *value)
-{
-#endif
     RETURN_UNLESS(section && name && value, "I can't complete the database with incomplete lines", 1);
-    RETURN_UNLESS(database_config_set(user, section, name, value), "Failed to update the database", 0);
-    return 1;
+    RETURN_UNLESS(database_config_set(user, section, name, value), "Failed to update the database", 1);
+    return 0;
 }
 
 int
@@ -122,6 +212,12 @@ config_detect_file(char *conf, size_t conf_len)
 
     /* Try the config file from the config directory. */
     home = getenv("XDG_CONFIG_HOME");
+    if (home && strlen(home) < conf_len) {
+        /* Skip the strncat to not append the '.config/' to
+           the XDG_CONFIG_HOME which must already have this directory in it */
+        strncat(conf, "/lektor/lektor.ini", conf_len - 1);
+        goto skip_this_strcat;
+    }
     if (!home || (strlen(home) >= conf_len))
         home = getenv("HOME");
     if (!home || (strlen(home) >= conf_len))
@@ -130,6 +226,7 @@ config_detect_file(char *conf, size_t conf_len)
         goto no_config_directory;
     memcpy(conf, home, (strlen(home) + 1) * sizeof(char));
     strncat(conf, "/.config/lektor/lektor.ini", conf_len - 1);
+skip_this_strcat:
     LOG_INFO("Trying %s", conf);
     if (!access(conf, R_OK | F_OK))
         goto found;
@@ -166,7 +263,7 @@ found:
 int
 config_new(volatile sqlite3 *db, const char *conf)
 {
-    if (ini_parse(conf, handler, (void *) db)) {
+    if (ini_parse(conf, handler, db)) {
         LOG_ERROR("Failed to parse file %s", conf);
         return 1;
     }
diff --git a/src/database/config.c b/src/database/config.c
index c2802ffdc9ae32a7d2179d26c27013c3ebc11ab5..00c82c62750cafcf78cfb4fa33f35e0c4738abe9 100644
--- a/src/database/config.c
+++ b/src/database/config.c
@@ -1,7 +1,7 @@
 #define _POSIX_C_SOURCE 200809L
 
+#include <common/common.h>
 #include <lektor/database.h>
-#include <lektor/common.h>
 
 #include <limits.h>
 #include <stdio.h>
diff --git a/src/database/find.c b/src/database/find.c
index ffc4b43706745737dbf21e8289763ac18fdae11c..61205fe97ecf03b34acd92738de91f71d17cc970 100644
--- a/src/database/find.c
+++ b/src/database/find.c
@@ -1,7 +1,7 @@
 #define _POSIX_C_SOURCE 200809L
 
+#include <common/common.h>
 #include <lektor/database.h>
-#include <lektor/common.h>
 
 #include <limits.h>
 #include <stdio.h>
diff --git a/src/database/open.c b/src/database/open.c
index dfc470ee46d78c0fdea3151cc90342f8621e0862..24b9fec3fcb855b49a9700cf81c4a1c71533bebc 100644
--- a/src/database/open.c
+++ b/src/database/open.c
@@ -1,7 +1,7 @@
 #define _POSIX_C_SOURCE 200809L
 
+#include <common/common.h>
 #include <lektor/database.h>
-#include <lektor/common.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/src/database/playlist.c b/src/database/playlist.c
index 2079ec836c5b8433595b031cee830a1ec7b0f2c6..96f704f075d18d16f217122741422ef532095640 100644
--- a/src/database/playlist.c
+++ b/src/database/playlist.c
@@ -2,7 +2,6 @@
 
 #include <common/common.h>
 #include <lektor/database.h>
-#include <lektor/common.h>
 #include <stdio.h>
 #include <strings.h>
 
diff --git a/src/database/queue.c b/src/database/queue.c
index aba0e00df63b2d16178907f0c83c4a5dd0abe431..24d5931661284d8428334ef0c5191572cda4d817 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -1,7 +1,7 @@
 #define _POSIX_C_SOURCE 200809L
 
+#include <common/common.h>
 #include <lektor/database.h>
-#include <lektor/common.h>
 
 #include <linux/limits.h>
 #include <stdio.h>
diff --git a/src/database/stickers.c b/src/database/stickers.c
index e2fc96ee246307692c49f3f56c9c3f4c4c522ce3..376621987d250e6819dd9feb44637f7a6e44d2ad 100644
--- a/src/database/stickers.c
+++ b/src/database/stickers.c
@@ -1,6 +1,6 @@
 #define _POSIX_C_SOURCE 200809L
 
-#include <lektor/common.h>
+#include <common/common.h>
 #include <lektor/database.h>
 #include <string.h>
 #include <strings.h>
diff --git a/src/database/update.c b/src/database/update.c
index 80429007333c98526a9efa5988b88f498ddbcd33..cacb7badeb5217a6cf4aea91aaf457526981849d 100644
--- a/src/database/update.c
+++ b/src/database/update.c
@@ -3,7 +3,6 @@
 
 #include <common/common.h>
 #include <lektor/database.h>
-#include <lektor/common.h>
 
 #include <stdbool.h>
 #include <sqlite3.h>
diff --git a/src/database/user.c b/src/database/user.c
index ab347f401611a764df89a91429c9ecd3cca6ba7b..cad67826f5fec56ab1e9b58dea3121d729de8a28 100644
--- a/src/database/user.c
+++ b/src/database/user.c
@@ -1,7 +1,7 @@
 #define _POSIX_C_SOURCE 200809L
 
+#include <common/common.h>
 #include <lektor/database.h>
-#include <lektor/common.h>
 #include <stdio.h>
 
 bool
diff --git a/src/ini/ini.c b/src/ini/ini.c
deleted file mode 100644
index 25e3870318e7efb1201ff8e3831067e1777f7e1e..0000000000000000000000000000000000000000
--- a/src/ini/ini.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/* inih -- simple .INI file parser
-   SPDX-License-Identifier: BSD-3-Clause
-   Copyright (C) 2009-2020, Ben Hoyt */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-
-#include <ini/ini.h>
-
-#if !INI_USE_STACK
-#include <stdlib.h>
-#endif
-
-#define MAX_SECTION 50
-#define MAX_NAME 50
-
-/* Used by ini_parse_string() to keep track of string parsing state. */
-typedef struct {
-    const char *ptr;
-    size_t num_left;
-} ini_parse_string_ctx;
-
-/* Strip whitespace chars off end of given string, in place. Return s. */
-static char *
-rstrip(char *s)
-{
-    char *p = s + strlen(s);
-    while (p > s && isspace((unsigned char)(*--p)))
-        *p = '\0';
-    return s;
-}
-
-/* Return pointer to first non-whitespace char in given string. */
-static char *
-lskip(const char *s)
-{
-    while (*s && isspace((unsigned char)(*s)))
-        s++;
-    return (char *)s;
-}
-
-/* Return pointer to first char (of chars) or inline comment in given string,
-   or pointer to null at end of string if neither found. Inline comment must
-   be prefixed by a whitespace character to register as a comment. */
-static char *
-find_chars_or_comment(const char *s, const char *chars)
-{
-#if INI_ALLOW_INLINE_COMMENTS
-    int was_space = 0;
-    while (*s && (!chars || !strchr(chars, *s)) &&
-           !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
-        was_space = isspace((unsigned char)(*s));
-        s++;
-    }
-#else
-    while (*s && (!chars || !strchr(chars, *s)))
-        s++;
-#endif
-    return (char *)s;
-}
-
-/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
-static char *
-strncpy0(char *dest, const char *src, size_t size)
-{
-    strncpy(dest, src, size - 1);
-    dest[size - 1] = '\0';
-    return dest;
-}
-
-/* See documentation in header file. */
-int
-ini_parse_stream(ini_reader reader, void *stream, ini_handler handler,
-                 void *user)
-{
-    /* Uses a fair bit of stack (use heap instead if you need to) */
-#if INI_USE_STACK
-    char line[INI_MAX_LINE];
-    int max_line = INI_MAX_LINE;
-#else
-    char *line;
-    size_t max_line = INI_INITIAL_ALLOC;
-#endif
-#if INI_ALLOW_REALLOC && !INI_USE_STACK
-    char *new_line;
-    size_t offset;
-#endif
-    char section[MAX_SECTION] = "";
-    char prev_name[MAX_NAME] = "";
-
-    char *start;
-    char *end;
-    char *name;
-    char *value;
-    int lineno = 0;
-    int error = 0;
-
-#if !INI_USE_STACK
-    line = (char *)malloc(INI_INITIAL_ALLOC);
-    if (!line)
-        return -2;
-#endif
-
-#if INI_HANDLER_LINENO
-#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
-#else
-#define HANDLER(u, s, n, v) handler(u, s, n, v)
-#endif
-
-    /* Scan through stream line by line */
-    while (reader(line, (int)max_line, stream) != NULL) {
-#if INI_ALLOW_REALLOC && !INI_USE_STACK
-        offset = strlen(line);
-        while (offset == max_line - 1 && line[offset - 1] != '\n') {
-            max_line *= 2;
-            if (max_line > INI_MAX_LINE)
-                max_line = INI_MAX_LINE;
-            new_line = realloc(line, max_line);
-            if (!new_line) {
-                free(line);
-                return -2;
-            }
-            line = new_line;
-            if (reader(line + offset, (int)(max_line - offset), stream) == NULL)
-                break;
-            if (max_line >= INI_MAX_LINE)
-                break;
-            offset += strlen(line + offset);
-        }
-#endif
-
-        lineno++;
-
-        start = line;
-#if INI_ALLOW_BOM
-        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
-            (unsigned char)start[1] == 0xBB &&
-            (unsigned char)start[2] == 0xBF)
-            start += 3;
-#endif
-        start = lskip(rstrip(start));
-
-        if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
-            /* Start-of-line comment */
-        }
-#if INI_ALLOW_MULTILINE
-        else if (*prev_name && *start && start > line) {
-            /* Non-blank line with leading whitespace, treat as continuation
-               of previous name's value (as per Python configparser). */
-            if (!HANDLER(user, section, prev_name, start) && !error)
-                error = lineno;
-        }
-#endif
-        else if (*start == '[') {
-            /* A "[section]" line */
-            end = find_chars_or_comment(start + 1, "]");
-            if (*end == ']') {
-                *end = '\0';
-                strncpy0(section, start + 1, sizeof(section));
-                *prev_name = '\0';
-#if INI_CALL_HANDLER_ON_NEW_SECTION
-                if (!HANDLER(user, section, NULL, NULL) && !error)
-                    error = lineno;
-#endif
-            } else if (!error) {
-                /* No ']' found on section line */
-                error = lineno;
-            }
-        } else if (*start) {
-            /* Not a comment, must be a name[=:]value pair */
-            end = find_chars_or_comment(start, "=:");
-            if (*end == '=' || *end == ':') {
-                *end = '\0';
-                name = rstrip(start);
-                value = end + 1;
-#if INI_ALLOW_INLINE_COMMENTS
-                end = find_chars_or_comment(value, NULL);
-                if (*end)
-                    *end = '\0';
-#endif
-                value = lskip(value);
-                rstrip(value);
-
-                /* Valid name[=:]value pair found, call handler */
-                strncpy0(prev_name, name, sizeof(prev_name));
-                if (!HANDLER(user, section, name, value) && !error)
-                    error = lineno;
-            } else if (!error) {
-                /* No '=' or ':' found on name[=:]value line */
-#if INI_ALLOW_NO_VALUE
-                *end = '\0';
-                name = rstrip(start);
-                if (!HANDLER(user, section, name, NULL) && !error)
-                    error = lineno;
-#else
-                error = lineno;
-#endif
-            }
-        }
-
-#if INI_STOP_ON_FIRST_ERROR
-        if (error)
-            break;
-#endif
-    }
-
-#if !INI_USE_STACK
-    free(line);
-#endif
-
-    return error;
-}
-
-/* See documentation in header file. */
-int
-ini_parse_file(FILE *file, ini_handler handler, void *user)
-{
-    return ini_parse_stream((ini_reader)fgets, file, handler, user);
-}
-
-/* See documentation in header file. */
-int
-ini_parse(const char *filename, ini_handler handler, void *user)
-{
-    FILE *file;
-    int error;
-
-    file = fopen(filename, "r");
-    if (!file) {
-        fprintf(stderr, " ! ini_parse: Failed to open file %s\n", filename);
-        return -1;
-    }
-    error = ini_parse_file(file, handler, user);
-    fclose(file);
-    if (error)
-        fprintf(stderr, " ! ini_parse: Got an error, code is %d\n", error);
-    return error;
-}
-
-/* An ini_reader function to read the next line from a string buffer. This
-   is the fgets() equivalent used by ini_parse_string(). */
-static char *
-ini_reader_string(char *str, int num, void *stream)
-{
-    ini_parse_string_ctx *ctx = (ini_parse_string_ctx *)stream;
-    const char *ctx_ptr = ctx->ptr;
-    size_t ctx_num_left = ctx->num_left;
-    char *strp = str;
-    char c;
-
-    if (ctx_num_left == 0 || num < 2)
-        return NULL;
-
-    while (num > 1 && ctx_num_left != 0) {
-        c = *ctx_ptr++;
-        ctx_num_left--;
-        *strp++ = c;
-        if (c == '\n')
-            break;
-        num--;
-    }
-
-    *strp = '\0';
-    ctx->ptr = ctx_ptr;
-    ctx->num_left = ctx_num_left;
-    return str;
-}
-
-/* See documentation in header file. */
-int
-ini_parse_string(const char *string, ini_handler handler, void *user)
-{
-    ini_parse_string_ctx ctx;
-
-    ctx.ptr = string;
-    ctx.num_left = strlen(string);
-    return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
-                            user);
-}
diff --git a/src/main/lkt.c b/src/main/lkt.c
index 8ea952bd2556dd90061d75f69a3ad4465eed3293..94114a9475e01a9b5a7c1da0275c6280a22b2a30 100644
--- a/src/main/lkt.c
+++ b/src/main/lkt.c
@@ -3,6 +3,7 @@
 #include <common/common.h>
 #include <lektor/net.h>
 #include <lektor/cmd.h>
+
 #include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/socket.h>
diff --git a/src/main/lktadm.c b/src/main/lktadm.c
index df2846b693e25559d8deb3eb7c803af1095b7455..d4b25a85a70ef67216438c99410045e56ca384cf 100644
--- a/src/main/lktadm.c
+++ b/src/main/lktadm.c
@@ -8,7 +8,6 @@
 #include <lektor/mkv.h>
 #include <lektor/database.h>
 #include <lektor/net.h>
-#include <lektor/common.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -228,6 +227,48 @@ download__(struct lkt_cmd_args *args)
     exit(EXIT_SUCCESS);
 }
 
+noreturn void
+source__(struct lkt_cmd_args *args)
+{
+    if (args->argc != 0)
+        fail("The source command takes no arguments");
+    char value[INI_MAX_LINE_LEN];
+    char player_mod[INI_MAX_LINE_LEN];
+    open_db();
+    if (!database_open(db, db_path))
+        fail("Failed to open database");
+
+#define CHK_OPTION(section, name)                                                   \
+    if (!database_config_get_text(db, section, name, value, INI_MAX_LINE_LEN)) {    \
+        LOG_ERROR("Failed to get value for option '[%s] %s'", section, name);       \
+        exit(EXIT_FAILURE);                                                         \
+    }                                                                               \
+    printf("[%s]\t%s -> %s\n", section, name, value);
+
+    CHK_OPTION("externals", "mkvpropedit");
+
+    CHK_OPTION("server", "host");
+    CHK_OPTION("server", "port");
+    CHK_OPTION("server", "max_clients");
+
+    CHK_OPTION("player", "module");
+    memcpy(player_mod, value, INI_MAX_LINE_LEN);
+    CHK_OPTION("player", "autoclear");
+    CHK_OPTION("player", "def_random");
+    CHK_OPTION("player", "def_consume");
+    CHK_OPTION("player", "def_single");
+    CHK_OPTION("player", "def_repeat");
+
+    CHK_OPTION("database", "kara_dir");
+    CHK_OPTION("database", "db_path");
+
+    CHK_OPTION(player_mod, "path");
+    CHK_OPTION(player_mod, "load_function");
+#undef CHK_OPTION
+
+    exit(EXIT_SUCCESS);
+}
+
 static struct lkt_cmd_opt options_init[] = {
     { .name = "database",   .call = init_database__  },
     { .name = "populate",   .call = init_populate__  },
@@ -248,6 +289,7 @@ static struct lkt_cmd_opt options[] = {
     { .name = "download",   .call = download__ },
     { .name = "cat",        .call = cat__      },
     { .name = "conf",       .call = conf__     },
+    { .name = "source",     .call = source__   },
     LKT_OPT_NULL,
 };
 
diff --git a/src/main/server.c b/src/main/server.c
index 434784e236c647b1bed0f592bff44b040160470e..ad3e0959c49d01f6ec0297bf4d8a630a7a021d9d 100644
--- a/src/main/server.c
+++ b/src/main/server.c
@@ -5,6 +5,7 @@
 #include <lektor/net.h>
 #include <lektor/database.h>
 #include <mthread/mthread.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
diff --git a/src/mkv/mkv.c b/src/mkv/mkv.c
index 39efb961d862e45aed4616d9259ae61693524455..a62d536f4603c6a1e8d5c0fce12c0383e53cb0c6 100644
--- a/src/mkv/mkv.c
+++ b/src/mkv/mkv.c
@@ -1,3 +1,5 @@
+#define _POSIX_C_SOURCE 200809L
+
 #include <fcntl.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -7,7 +9,7 @@
 
 #include <lektor/bufferfd.h>
 #include <lektor/mkv.h>
-#include <lektor/common.h>
+#include <common/common.h>
 
 #define MKV_TAG_MAX 64
 
diff --git a/src/module/module_x11.c b/src/module/module_x11.c
index 8fd16618577280c9f22cdb50e4e6714c8702bebf..5852a9c4cf6cd70f0cf56bc65eb59be70694b8b1 100644
--- a/src/module/module_x11.c
+++ b/src/module/module_x11.c
@@ -2,7 +2,6 @@
 
 #include <common/common.h>
 #include <lektor/module/module_x11.h>
-#include <lektor/common.h>
 #include <lektor/module/mpv.h>
 #include <lektor/database.h>
 #include <lektor/commands.h>
diff --git a/src/module/mpv.c b/src/module/mpv.c
index 2fc401d0166cf1898fc1dd121d341fa5072e7956..b29d71532d5f98becd77e64223070b5c23a43d83 100644
--- a/src/module/mpv.c
+++ b/src/module/mpv.c
@@ -4,7 +4,6 @@
 #include <lektor/module/mpv.h>
 #include <lektor/commands.h>
 #include <lektor/database.h>
-#include <lektor/common.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
diff --git a/src/mthread/mthread_debug.c b/src/mthread/mthread_debug.c
deleted file mode 100644
index 3230f8163e040045d7781b1c524770ec013b4ed5..0000000000000000000000000000000000000000
--- a/src/mthread/mthread_debug.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#define _POSIX_C_SOURCE 200809L
-
-#include <mthread/mthread_internal.h>
-#include <assert.h>
-
-void *
-safe_malloc(size_t size)
-{
-    void *tmp;
-    tmp = malloc(size);
-    assert(tmp != NULL);
-    return tmp;
-}
diff --git a/src/net/downloader.c b/src/net/downloader.c
index 96abec51a631caf426e3a7b6593d4ccfa285a93b..9df9b1bae07918d97f759d4c2c93d74336d46c0e 100644
--- a/src/net/downloader.c
+++ b/src/net/downloader.c
@@ -12,7 +12,6 @@
 
 #include <common/common.h>
 #include <mthread/mthread.h>
-#include <lektor/common.h>
 #include <lektor/database.h>
 #include <lektor/net.h>
 
diff --git a/src/net/listen.c b/src/net/listen.c
index 30f5e5789f7a32e17ff3dbde969b269ae9560e6f..4c73ff20c836f587d0e71dcf9997d8549c05bbe0 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -1,10 +1,9 @@
 #define _POSIX_C_SOURCE 200809L
 
+#include <common/common.h>
 #include <lektor/commands.h>
-#include <lektor/common.h>
 #include <lektor/database.h>
 #include <lektor/net.h>
-#include <ini/ini.h>
 
 #include <sqlite3.h>
 
@@ -688,7 +687,7 @@ lkt_client_auth(struct lkt_state *srv, size_t c, bool set)
 int
 lkt_listen(void)
 {
-    char *memory = (char *) calloc(2 * PATH_MAX + HOST_NAME_MAX + 3, sizeof(char));
+    char *memory = (char *) safe_malloc((2 * PATH_MAX + HOST_NAME_MAX + 3) * sizeof(char));
     RETURN_UNLESS(memory, "Out of memory", 5);
 
     struct lkt_state srv;
@@ -697,25 +696,25 @@ lkt_listen(void)
     char *const kara_dir = memory + PATH_MAX + 1;   /* Size is PATH_MAX.        */
     char *const host     = kara_dir + PATH_MAX + 1; /* Size is HOST_NAME_MAX.   */
     char port[7];   /* Maximal port number is 65535, +2 for '\n' and '\0' */
-    char player_mod[INI_MAX_LINE];
+    char player_mod[INI_MAX_LINE_LEN];
     char conf_file[PATH_MAX];
     memset(&srv, 0, sizeof(struct lkt_state));
 
     /* Initialize the system. */
-    RETURN_UNLESS(database_new(&srv.db), "Failed to initialize the memory database", 1);
-    RETURN_IF(config_detect_file(conf_file, PATH_MAX), "Failed to find a config file", 1);
-    RETURN_IF(config_new(srv.db, conf_file), "Failed to read configuration file", 1);
+    RETURN_UNLESS(database_new(&srv.db),                   "Failed to initialize the memory database", 1);
+    RETURN_IF    (config_detect_file(conf_file, PATH_MAX), "Failed to find a config file",             1);
+    RETURN_IF    (config_new(srv.db, conf_file),           "Failed to read configuration file",        1);
 
     /* Finish to initialize. */
-    RETURN_UNLESS(database_config_get_text(srv.db, "database", "db_path", db_path, PATH_MAX), "Cfg error", 2);
-    RETURN_UNLESS(database_open(srv.db, db_path), "Can't open database", 1);
+    RETURN_UNLESS(database_config_get_text(srv.db, "database", "db_path", db_path, PATH_MAX), "Cfg error",           2);
+    RETURN_UNLESS(database_open(srv.db, db_path),                                             "Can't open database", 1);
 
     /* Read the configuration. */
-    RETURN_UNLESS(database_config_get_int (srv.db, "player",   "autoclear", &autoclear),               "Cfg error", 2);
-    RETURN_UNLESS(database_config_get_text(srv.db, "database", "kara_dir",  kara_dir, PATH_MAX),       "Cfg error", 2);
-    RETURN_UNLESS(database_config_get_text(srv.db, "server",   "host",      host, HOST_NAME_MAX),      "Cfg error", 2);
-    RETURN_UNLESS(database_config_get_text(srv.db, "server",   "port",      port, 5),                  "Cfg error", 2);
-    RETURN_UNLESS(database_config_get_text(srv.db, "player",   "module",    player_mod, INI_MAX_LINE), "Cfg error", 2);
+    RETURN_UNLESS(database_config_get_int (srv.db, "player",   "autoclear", &autoclear),                   "Cfg error", 2);
+    RETURN_UNLESS(database_config_get_text(srv.db, "database", "kara_dir",  kara_dir, PATH_MAX),           "Cfg error", 2);
+    RETURN_UNLESS(database_config_get_text(srv.db, "server",   "host",      host, HOST_NAME_MAX),          "Cfg error", 2);
+    RETURN_UNLESS(database_config_get_text(srv.db, "server",   "port",      port, 5),                      "Cfg error", 2);
+    RETURN_UNLESS(database_config_get_text(srv.db, "player",   "module",    player_mod, INI_MAX_LINE_LEN), "Cfg error", 2);
 
     if (kara_dir[strlen(kara_dir) - 1] != '/')
         strncat(kara_dir, "/", PATH_MAX - 1);
@@ -737,10 +736,10 @@ lkt_listen(void)
     if (autoclear)
         database_queue_clear(srv.db);
 
-    RETURN_UNLESS(load_module_by_name(srv.db, player_mod, &srv.win), "Can't load module", 3);
-    RETURN_UNLESS(srv.win.new(&srv.win), "Can't create window", 3);
+    RETURN_IF    (repo_new(&srv.repo, "kurisu", "https://kurisu.iiens.net", srv.db), "Failed to create repo", 4);
+    RETURN_UNLESS(load_module_by_name(srv.db, player_mod, &srv.win),                 "Can't load module",     3);
+    RETURN_UNLESS(srv.win.new(&srv.win),                                             "Can't create window",   3);
     srv.win.attach(&srv.win, &srv);
-    RETURN_IF(repo_new(&srv.repo, "kurisu", "https://kurisu.iiens.net", srv.db), "Failed to create repo", 4);
 
     for (;;) {
         if (handle_network_events(&srv) < 0)
diff --git a/src/net/message.c b/src/net/message.c
index 16dab3836b85a9e16298ab5a1edd227f121b8028..21d3bf32488ed13450827e790d684b069a7438e5 100644
--- a/src/net/message.c
+++ b/src/net/message.c
@@ -1,5 +1,6 @@
-#include <lektor/net.h>
+#define _POSIX_C_SOURCE 200809L
 
+#include <lektor/net.h>
 #include <stdlib.h>
 
 struct lkt_message *
diff --git a/src/uri.c b/src/uri.c
index ac8634be845720818b767601c8f5358d318dcd2d..ec076ed25e67e30fc1eeb8418efffa51107092f7 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -1,3 +1,6 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <common/common.h>
 #include <lektor/uri.h>
 #include <stdlib.h>
 #include <string.h>