diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h
index 7cc980f9952c6fd67e43540115cf0375b342b3d2..a923d8069f47e76b695bddaa7525b588b30fa448 100644
--- a/inc/lektor/commands.h
+++ b/inc/lektor/commands.h
@@ -89,4 +89,11 @@ bool command_set_playback_option(struct lkt_state *srv,
                                  enum lkt_playback_option opt,
                                  char *args[LKT_MESSAGE_ARGS_MAX]);
 
-
+/* Authentificate users */
+bool command_password(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]);
+bool command_user_add(sqlite3 *db, char *argv[LKT_MESSAGE_ARGS_MAX]);
+
+/* Program management control */
+bool command_restart(struct lkt_state *srv, size_t c);
+bool command_kill(struct lkt_state *srv, size_t c);
+bool command_rescan(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]);
diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index 8bf8a71ce041834370990f84a13770e260c1ffa8..a65a28a94a3ce7c483ba2a9b192ff8fe707491b7 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -47,7 +47,8 @@ bool database_sync_mpv_state(sqlite3 *db, mpv_handle **mpv);
 
 /* Update the database. */
 bool database_update(sqlite3 *db, const char *kara_dir);
-bool database_update_add(sqlite3 *db, const char *kara_path, struct kara_metadata *mdt, uint64_t id);
+bool database_update_add(sqlite3 *db, const char *kara_path, struct kara_metadata *mdt, uint64_t id,
+                         bool avail);
 
 /* Control the content of the queue. */
 bool database_queue_add_id(sqlite3 *db, int id, int priority);
@@ -121,3 +122,7 @@ bool database_plt_export(sqlite3 *db, const char *name, const char *file);
 bool database_plt_import(sqlite3 *db, const char *name, const char *file);
 
 bool database_plt_add_uri(sqlite3 *db, const char *name, struct lkt_uri_t *uri);
+
+/* User control, yeah, MPD authentification sucks. */
+bool database_user_authentificate(sqlite3 *db, const char *password);
+bool database_user_add(sqlite3 *db, const char *username, const char *password);
diff --git a/inc/lektor/mkv.h b/inc/lektor/mkv.h
index 0528029e813832d8492270c676a51c250b47258f..dbc23e5079b9f95f84fab6d7c3f91bc197905fd7 100644
--- a/inc/lektor/mkv.h
+++ b/inc/lektor/mkv.h
@@ -37,10 +37,18 @@ struct kara_metadata {
     int song_number;
 };
 
+enum kara_action {
+    kara_action_none    = 0,        /* Do nothing               */
+    kara_action_add     = (1 << 1), /* Add to database          */
+    kara_action_delete  = (1 << 2), /* Delete from database     */
+    kara_action_unavail = (1 << 3), /* Mark kara as unavailable */
+};
+
 struct kara {
-    struct kara_metadata mdt;
-    char filename[PATH_MAX];
-    size_t id;
+    enum kara_action action;    /* What to do with this kara.       */
+    size_t id;                  /* Should never be NULL. NEVER!!    */
+    struct kara_metadata mdt;   /* The metadata of the kara.        */
+    char filename[PATH_MAX];    /* The path to the matroska file.   */
 };
 
 /* Reads the .mkv file at `filename` and stores its metadata in `dst`.
diff --git a/inc/lektor/net.h b/inc/lektor/net.h
index ff624a750c07d75f6a40da25dc379e45c7ad42f4..c1ce1b2031b62544440422b06de4b6a47790d3b4 100644
--- a/inc/lektor/net.h
+++ b/inc/lektor/net.h
@@ -72,5 +72,8 @@ void lkt_state_send(struct lkt_state *srv, size_t c, struct lkt_message *msg);
  * Return a pointer to the client's mask */
 long long int *lkt_client_get_mask(struct lkt_state *srv, size_t c);
 
+/* Register a client as authentificated. */
+bool lkt_client_auth(struct lkt_state *srv, size_t c, bool set_auth);
+
 /* The server's listen function. */
 int lkt_listen(lkt_config_t conf);
diff --git a/inc/lektor/repo.h b/inc/lektor/repo.h
index 4c7d4e330eb9fca157b31d7a84e96c4ccdf53f79..829011b95bdcf5d4d46f7b3a03a347eddbbf023b 100644
--- a/inc/lektor/repo.h
+++ b/inc/lektor/repo.h
@@ -14,6 +14,7 @@ struct lkt_repo {
     const char *name;
     const char *base_url;
     const char *kara_dir;
+    const char *get_all_json;
     const char *get_id_json;
     const char *get_id_file;
     const uint64_t version;
@@ -28,6 +29,8 @@ int repo_join_thread(void);
 
 /* Get metadata of a kara. */
 int repo_get_id(struct lkt_repo *const repo, const uint64_t id, struct kara_metadata *mdt);
+int repo_get_alljson_sync(struct lkt_repo *const repo, struct json_object **json);
+int repo_get_allid_async(void);
 
 /* Download a kara. */
 int repo_download_id_sync(struct lkt_repo *const repo, sqlite3 *db, const uint64_t id,
diff --git a/init.sql b/init.sql
index b2ab788bc478403b5bb0878eaa184328e857450f..73fe4ef72962ca6da48cbb540e3e52f329761fc9 100644
--- a/init.sql
+++ b/init.sql
@@ -18,9 +18,11 @@ CREATE TABLE IF NOT EXISTS kara
   , is_new      INTEGER NOT NULL
   , author_name TEXT
   , author_year INTEGER CHECK(author_year > 0)
+  , available   INTEGER CHECK(available = 0 OR available = 1) DEFAULT 1 NOT NULL
   , string      TEXT GENERATED ALWAYS AS
     ( song_type || ' - ' || language || ' / ' || source_name || ' - ' || category ||
-      song_number || ' - ' || song_name || ' [ ' || author_name || ' ]'
+      song_number || ' - ' || song_name || ' [ ' || author_name || ' ]' ||
+      CASE WHEN available = 0 THEN '(U)' ELSE '' END
     ) STORED
   );
 
@@ -77,6 +79,20 @@ CREATE TABLE IF NOT EXISTS queue
   );
 
 
+-- The user table
+-- Used for the [password {passwd}] MPD command. The documentation can be found
+-- here: https://www.musicpd.org/doc/html/protocol.html#connection-settings.
+-- The password command is used to restrict access to specific commands.
+
+CREATE TABLE IF NOT EXISTS users
+  ( username TEXT NOT NULL UNIQUE
+  , password TEXT NOT NULL UNIQUE
+  , PRIMARY KEY (username, password)
+  ) WITHOUT ROWID;
+
+INSERT INTO users (username, password) VALUES ('sakura', 'hashire');
+
+
 -- Some useful values:
 -- last_update is the timestamp of the last time the table of kara has been
 -- updated.  This is so lektor doesn't have to read all kara in the filesystem,
diff --git a/meson.build b/meson.build
index 8d05c839462ec612e1affeb55141cb743a128f48..5a881e22ab03d0a8cc817d85fe770aa70ff49c1b 100644
--- a/meson.build
+++ b/meson.build
@@ -7,7 +7,8 @@ project( 'lektor'
                           , 'warning_level=3'
                           , 'werror=true'
                           , 'strip=true'
-                          , 'buildtype=debugoptimized'
+                          , 'debug=true'
+                          , 'buildtype=debug'
                           , 'b_sanitize=undefined'
                           ]
        )
@@ -34,6 +35,7 @@ core_sources =  [ 'src/mkv/bufferfd.c'
                 , 'src/database/find.c'
                 , 'src/database/config.c'
                 , 'src/database/playlist.c'
+                , 'src/database/user.c'
                 , 'src/mkv/mkv.c'
                 , 'src/net/command.c'
                 , 'src/net/listen.c'
@@ -59,11 +61,11 @@ core_deps = [ dependency('sqlite3', version : '>= 3.31.0')
             , dependency('threads', required : true)
             ]
 
-lib = library( meson.project_name()
-             , files(core_sources)
-             , include_directories : includes
-             , dependencies : [ core_deps, libdl ]
-             )
+lib = static_library( meson.project_name()
+                    , files(core_sources)
+                    , include_directories : includes
+                    , dependencies : [ core_deps, libdl ]
+                    )
 
 bin_deps =  core_deps + [ declare_dependency( link_with: lib, include_directories: includes) ]
 
diff --git a/src/commands.c b/src/commands.c
index d1b487039c8bbcb5fded3150a8cbb7362b1a8ccd..b0db806537bf457c157122d91a7502f7404e98a2 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -4,6 +4,7 @@
 #include <lektor/database.h>
 #include <lektor/net.h>
 #include <lektor/uri.h>
+#include <lektor/repo.h>
 
 #include <errno.h>
 #include <linux/limits.h>
@@ -13,6 +14,71 @@
 #include <string.h>
 #include <strings.h>
 #include <limits.h>
+#include <poll.h>
+#include <unistd.h>
+
+#define SELF_EXECUTABLE_LINUX   "/proc/self/exe"
+#define SELF_EXECUTABLE_FREEBSD "/proc/curproc/file"
+#define SELF_EXECUTABLE_SOLARIS "/proc/self/path/a.out"
+
+inline bool
+command_restart(struct lkt_state *srv, size_t c)
+{
+    char exe[PATH_MAX];
+    char *const argv[] = { exe, NULL };
+
+    if (!lkt_client_auth(srv, c, false)) {
+        fprintf(stderr, " ! command_restart: Failed to restart, user not authentificated %lu\n", c);
+        return false;
+    }
+
+    if (readlink(SELF_EXECUTABLE_LINUX, exe, PATH_MAX - 1) > 0) {
+        fprintf(stderr, " * Restart lektord\n");
+        close(srv->fds[0].fd);
+        execv(exe, argv);
+    }
+
+    if (readlink(SELF_EXECUTABLE_FREEBSD, exe, PATH_MAX - 1) > 0) {
+        fprintf(stderr, " * Restart lektord\n");
+        close(srv->fds[0].fd);
+        execv(exe, argv);
+    }
+
+    if (readlink(SELF_EXECUTABLE_SOLARIS, exe, PATH_MAX - 1) > 0) {
+        fprintf(stderr, " * Restart lektord\n");
+        close(srv->fds[0].fd);
+        execv(exe, argv);
+    }
+
+    fprintf(stderr, " ! command_restart: Failed to exec lektor or OS not supported\n");
+    abort();
+}
+
+bool
+command_rescan(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX])
+{
+    (void) argv;
+
+    if (!lkt_client_auth(srv, c, false)) {
+        fprintf(stderr, " ! command_rescan: Failed, user %lu not authentificated\n", c);
+        return false;
+    }
+
+    return ! repo_get_allid_async();
+}
+
+inline bool
+command_kill(struct lkt_state *srv, size_t c)
+{
+    if (!lkt_client_auth(srv, c, false)) {
+        fprintf(stderr, " ! command_restart: Failed to restart, user not authentificated %lu\n", c);
+        return false;
+    }
+
+    fprintf(stderr, " * Stopping lektord\n");
+    close(srv->fds[0].fd);
+    exit(EXIT_SUCCESS);
+}
 
 bool
 command_currentsong(struct lkt_state *srv, size_t c)
@@ -946,3 +1012,38 @@ is_absolute:
     return database_queue_list_abs(srv->db, from, to, &callback_args,
                                    lkt_callback_send_row_v1);
 }
+
+bool
+command_password(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX])
+{
+    if (argv[0] == NULL || argv[1] != NULL) {
+        fprintf(stderr, " ! command_password: Invalid arguments, need only one argument\n");
+        return false;
+    }
+
+    if (database_user_authentificate(srv->db, argv[0])) {
+        fprintf(stderr, " . command_password: Authentificate user successfully for client %lu\n", c);
+        lkt_client_auth(srv, c, true);
+        return true;
+    } else {
+        fprintf(stderr, " . command_password: Failed to authentificate client %lu\n", c);
+        return false;
+    }
+}
+
+bool
+command_user_add(sqlite3 *db, char *argv[LKT_MESSAGE_ARGS_MAX])
+{
+    if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL) {
+        fprintf(stderr, " ! command_user_add: Invalid arguments, need only two arguments\n");
+        return false;
+    }
+
+    if (database_user_add(db, argv[0], argv[1])) {
+        fprintf(stderr, " . command_user_add: Successfully added user %s\n", argv[0]);
+        return true;
+    }
+
+    return false;
+    fprintf(stderr, " . command_user_add: Failed to add user %s\n", argv[0]);
+}
diff --git a/src/database/open.c b/src/database/open.c
index 006499eef466e93ae191fde24a25d70802c750a7..cdc78a1298e64af7d07f918818f460596a327dc3 100644
--- a/src/database/open.c
+++ b/src/database/open.c
@@ -34,17 +34,17 @@ static const char *const SQL_MEM_SCHEM =
 #define HEAP_LIMIT_SOFT         100 * 1024 * 1024
 #define HEAP_LIMIT_HARD         150 * 1024 * 1024
 
-static inline int
-is_dbpath_invalid(const char *dbpath)
+int
+is_sql_str_invalid(const char *str)
 {
-    size_t len = strlen(dbpath);
-    return strcspn(dbpath, INVALID_CHARS_DBPATH) != len;
+    size_t len = strlen(str);
+    return strcspn(str, INVALID_CHARS_DBPATH) != len;
 }
 
 bool
 database_open(sqlite3 **db, const char *dbpath)
 {
-    if (is_dbpath_invalid(dbpath)) {
+    if (is_sql_str_invalid(dbpath)) {
         fprintf(stderr, " ! database_open: The database path %s is invalid\n", dbpath);
         return false;
     }
diff --git a/src/database/queue.c b/src/database/queue.c
index 6a2bbf2d3cc7bd0241ac5e258a0d83651ab29251..eb1d450949d3f9c51406d7517a97484937297d57 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -6,6 +6,9 @@
 
 #define max(a, b) ((a) < (b) ? (b) : (a))
 
+/* Find in in database/open.c */
+extern int is_sql_str_invalid(const char *);
+
 bool
 database_queue_state(sqlite3 *db, struct lkt_queue_state *res)
 {
@@ -97,12 +100,17 @@ error:
 static bool
 queue_add_with_col_like_str(sqlite3 *db, const char *col, const char *val, int priority)
 {
+    if (is_sql_str_invalid(col)) {
+        fprintf(stderr, " ! queue_add_with_col_like_str: Column name %s is invalid\n", col);
+        return false;
+    }
+
     char SQL[1024];
     static const char *SQL_STMT =
         "INSERT INTO queue (kara_id, priority)"
         "  SELECT id, ?"
         "  FROM kara"
-        "  WHERE %s LIKE ?" /* XXX: Here be carefull, may be subject to sql injections.  */
+        "  WHERE %s LIKE ? AND available = 1"
         "  ORDER BY RANDOM();";
     bool status = false;
     sqlite3_stmt *stmt = NULL;
@@ -137,6 +145,11 @@ error:
 static bool
 queue_insert_with_col_like_str(sqlite3 *db, const char *col, const char *val, int pos)
 {
+    if (is_sql_str_invalid(col)) {
+        fprintf(stderr, " ! queue_insert_with_col_like_str: Column name %s is invalid\n", col);
+        return false;
+    }
+
     char SQL[4096];
     static const char *SQL_STMT =
         "BEGIN TRANSACTION;"
@@ -153,7 +166,7 @@ queue_insert_with_col_like_str(sqlite3 *db, const char *col, const char *val, in
         "INSERT INTO queue (kara_id, priority)"
         "SELECT id, priority"
         "  FROM kara"
-        "  WHERE %s LIKE ?" /* XXX: Here be carefull, may be subject to sql injections.  */
+        "  WHERE %s LIKE ? AND available = 1"
         "  ORDER BY RANDOM();"
         "INSERT INTO queue (kara_id, priority)"
         "  SELECT kara_id_tmp, priority"
@@ -211,7 +224,7 @@ database_queue_add_plt(sqlite3 *db, const char *plt_name, int priority)
         "INSERT INTO queue (kara_id, priority) "
         "SELECT kara.id, ?"
         "  FROM kara"
-        "  JOIN kara_playlist ON kara_id = kara.id"
+        "  JOIN kara_playlist ON kara_id = kara.id AND kara.available = 1"
         "  JOIN playlist ON playlist_id = playlist.id AND playlist.name = ?"
         "  ORDER BY RANDOM();";
     bool status = false;
@@ -838,7 +851,9 @@ database_queue_list_from(sqlite3 *db, unsigned int count, void *args,
     const char *SQL_TEMPLATE =
         "SELECT kara.id, string"
         "  FROM queue_"
-        "  JOIN queue_state ON queue_.position >= queue_state.current"
+        "  JOIN queue_state ON queue_.position >= CASE"
+        "    WHEN queue_state.current IS NULL THEN 1"
+        "    ELSE queue_state.current END"
         "  JOIN kara ON kara_id = kara.id"
         "  ORDER BY position"
         "  LIMIT %d;";
diff --git a/src/database/update.c b/src/database/update.c
index bae310eaae2c59db7fb1cf15816213eb0799c5c4..6320bb5a421745e775aed42fdb55072cc0fd4ce0 100644
--- a/src/database/update.c
+++ b/src/database/update.c
@@ -80,7 +80,7 @@ error:
 }
 
 bool
-database_update_add(sqlite3 *db, const char *kara_path, struct kara_metadata *mdt, uint64_t id)
+database_update_add(sqlite3 *db, const char *kara_path, struct kara_metadata *mdt, uint64_t id, bool avail)
 {
     if (db == NULL || kara_path == NULL || mdt == NULL) {
         fprintf(stderr, " ! database_add_kara: Invalid arguments\n");
@@ -89,9 +89,9 @@ database_update_add(sqlite3 *db, const char *kara_path, struct kara_metadata *md
     }
 
     static const char *SQL_STMT =
-        "INSERT INTO "
-        "kara (song_name, source_name, category, song_type, language, file_path, is_new, author_name, author_year, song_number, id)"
-        "SELECT ?, ?, ?, ?, ?, ?, ?, ?, strftime('%s','now'), ?, ?";
+        "INSERT OR REPLACE INTO "
+        "kara (song_name, source_name, category, song_type, language, file_path, is_new, author_name, author_year, song_number, id, available)"
+        "SELECT ?, ?, ?, ?, ?, ?, ?, ?, strftime('%s','now'), ?, ?, ?";
     sqlite3_stmt *stmt = NULL;
     int code = SQLITE_OK;
     bool ret = false;
@@ -119,10 +119,11 @@ database_update_add(sqlite3 *db, const char *kara_path, struct kara_metadata *md
         (sqlite3_bind_text(stmt, 4, mdt->song_type, -1, 0) != SQLITE_OK)    ||
         (sqlite3_bind_text(stmt, 5, mdt->language, -1, 0) != SQLITE_OK)     ||
         (sqlite3_bind_text(stmt, 6, kara_path, -1, 0) != SQLITE_OK)         ||
-        (sqlite3_bind_int(stmt, 7, 0) != SQLITE_OK)                         ||  /* No new kara added (TODO). */
+        (sqlite3_bind_int(stmt, 7, 0) != SQLITE_OK) /* TODO */              ||  /* No new kara added (TODO). */
         (sqlite3_bind_text(stmt, 8, mdt->author_name, -1, 0) != SQLITE_OK)  ||
         (sqlite3_bind_int(stmt,  9, mdt->song_number) != SQLITE_OK)         ||
-        (sqlite3_bind_int(stmt, 10, id) != SQLITE_OK)
+        (sqlite3_bind_int(stmt, 10, id) != SQLITE_OK)                       ||
+        (sqlite3_bind_int(stmt, 11, avail) != SQLITE_OK)
        ) {
         fprintf(stderr, " ! database_update_add: failed to bind argument to stmt statement for kara %s: %s\n",
                 kara_path, sqlite3_errmsg(db));
diff --git a/src/database/user.c b/src/database/user.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ac954db857128ab989b9d4ecc10f99880afe2cf
--- /dev/null
+++ b/src/database/user.c
@@ -0,0 +1,71 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <lektor/database.h>
+#include <stdio.h>
+
+bool
+database_user_authentificate(sqlite3 *db, const char *password)
+{
+    static const char *SQL_STMT = "SELECT username FROM users WHERE password = ?";
+    sqlite3_stmt *stmt = 0;
+    bool ret = false;
+
+    if (sqlite3_prepare_v2(db, SQL_STMT, -1, &stmt, 0) != SQLITE_OK) {
+        fprintf(stderr, " ! database_user_authentificate: Failed to prepare statement: %s\n",
+                sqlite3_errmsg(db));
+        goto error;
+    }
+
+    if (sqlite3_bind_text(stmt, 1, password, -1, 0) != SQLITE_OK) {
+        fprintf(stderr, " ! database_user_authentificate: Failed to bind password: %s\n",
+                sqlite3_errmsg(db));
+        goto error;
+    }
+
+    if (sqlite3_step(stmt) != SQLITE_ROW) {
+        fprintf(stderr, " ! database_user_authentificate: No user found\n");
+        goto error;
+    }
+
+    fprintf(stderr, " * User authentification was successfull for user %s\n",
+            sqlite3_column_text(stmt, 0));
+
+    ret = true;
+error:
+    sqlite3_finalize(stmt);
+    return ret;
+}
+
+bool
+database_user_add(sqlite3 *db, const char *username, const char *password)
+{
+    static const char *SQL_STMT = "INSERT INTO users (username, password) VALUES (?, ?)";
+    sqlite3_stmt *stmt = 0;
+    bool ret = false;
+
+    if (sqlite3_prepare_v2(db, SQL_STMT, -1, &stmt, 0) != SQLITE_OK) {
+        fprintf(stderr, " ! database_user_add: Failed to prepare statement: %s\n",
+                sqlite3_errmsg(db));
+        goto error;
+    }
+
+    if (sqlite3_bind_text(stmt, 1, username, -1, 0) != SQLITE_OK &&
+        sqlite3_bind_text(stmt, 2, password, -1, 0) != SQLITE_OK) {
+        fprintf(stderr, " ! database_user_add: Failed to bind : %s\n",
+                sqlite3_errmsg(db));
+        goto error;
+    }
+
+    if (sqlite3_step(stmt) != SQLITE_OK) {
+        fprintf(stderr, " ! database_user_add: Failed to add user %s: %s\n",
+                username, sqlite3_errmsg(db));
+        goto error;
+    }
+
+    fprintf(stderr, " * User %s added successfully\n", username);
+
+    ret = true;
+error:
+    sqlite3_finalize(stmt);
+    return ret;
+}
diff --git a/src/net/listen.c b/src/net/listen.c
index a315ae840cea1b263aab00bd73d8afc0aecc7fd1..7c7dc5d59b4c8ee7c00e75d3542b188b8854d2a3 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -51,6 +51,8 @@ struct lkt_client {
 
     long long int mpd_idle_watch;
     bool request_close;
+
+    bool authentificated;
 };
 
 static bool
@@ -134,6 +136,23 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
 
     switch (*lkt_client_get_mask(srv, c)) {
     case MPD_IDLE_NONE:
+        /* Commands that require authentification. */
+        if (lkt_client_auth(srv, c, false)) {
+            if (!strcmp(cmd.name, "__adduser")) {
+                err = !command_user_add(srv->db, cmd.args);
+                break;
+            } else if (!strcmp(cmd.name, "__restart")) {
+                err = !command_restart(srv, c);
+                break;
+            } else if (!strcmp(cmd.name, "kill")) {
+                err = !command_kill(srv, c);
+                break;
+            } else if (!strcmp(cmd.name, "rescan")) {
+                err = !command_rescan(srv, c, cmd.args);
+                break;
+            }
+        }
+
         /* Commands that are available if not in idle mode */
         if (!strcmp(cmd.name, "currentsong"))
             err = !command_currentsong(srv, c);
@@ -168,7 +187,7 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
 
         else if (!strcmp(cmd.name, "help"))
             err = !command_help(srv, c);
-        else if (!strcmp(cmd.name, "db-update"))
+        else if (!strcmp(cmd.name, "__dbupdate"))
             err = !command_update(srv, &srv->mpd_idle_events);
 
         else if (!strcmp(cmd.name, "add"))
@@ -204,6 +223,9 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
         else if (!strcmp(cmd.name, "consume"))
             err = !command_set_playback_option(srv, c, lkt_playback_option_consume, cmd.args);
 
+        else if (!strcmp(cmd.name, "password"))
+            err = !command_password(srv, c, cmd.args);
+
         else if (!strcmp(cmd.name, "idle")) {
             err = !command_idle(srv, c, &cmd);
             goto end_no_send_status;
@@ -625,6 +647,12 @@ lkt_client_get_mask(struct lkt_state *srv, size_t c)
     return &(srv->clients[c - 1].mpd_idle_watch);
 }
 
+inline bool
+lkt_client_auth(struct lkt_state *srv, size_t c, bool set)
+{
+    return srv->clients[c - 1].authentificated |= set;
+}
+
 static inline void
 handle_repo_hevents(struct lkt_state *srv)
 {
@@ -634,14 +662,38 @@ handle_repo_hevents(struct lkt_state *srv)
         if (repo_get_kara_async(&kara))
             goto get_out;
 
-        if (!database_update_add(srv->db, kara->filename, &kara->mdt, kara->id)) {
-            fprintf(stderr, " ! handle_repo_hevents: Failed to add downloaded kara with id %lu and path %s\n",
+        switch (kara->action) {
+        /* Add the downloaded kara to the database. */
+        case kara_action_add:
+            if (!database_update_add(srv->db, kara->filename, &kara->mdt, kara->id, true)) {
+                fprintf(stderr, " ! handle_repo_hevents: Failed to add downloaded kara with id %lu and path %s\n",
+                        kara->id, kara->filename);
+                goto get_out;
+            }
+
+            fprintf(stderr, " * Added kara %lu with path %s to database\n",
                     kara->id, kara->filename);
-            goto get_out;
+
+            break;
+
+        /* Add the mdt of the kara to the database. Mark it unavailable. */
+        case kara_action_unavail:
+            if (!database_update_add(srv->db, kara->filename, &kara->mdt, kara->id, false)) {
+                fprintf(stderr, " ! handle_repo_hevents: Failed to add kara with id %lu with flag unavailable\n",
+                        kara->id);
+                goto get_out;
+            }
+
+            fprintf(stderr, " * Added kara %lu to database and set it to unavailable\n",
+                    kara->id);
+
+            break;
+
+        case kara_action_none:
+        default:
+            break;
         }
 
-        fprintf(stderr, " * Added kara %lu with path %s to database\n",
-                kara->id, kara->filename);
         free(kara);
         kara = NULL;
     }
diff --git a/src/repo/async.c b/src/repo/async.c
index 3f444548bf69d33f317526f41d5ae5982a427e35..36bd2e7949b6645ec8fb8eb200c6d942e100ef4e 100644
--- a/src/repo/async.c
+++ b/src/repo/async.c
@@ -12,26 +12,115 @@
 #define LKT_DEFAULT_LIST_SIZE 10
 
 static struct lkt_thread repo_thread;
+
+static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
 static volatile int init = 0;
 static volatile int stop = 0;
+static volatile int all_json = 0;
 
 int
 repo_join_thread(void)
 {
+    int ret = 1;
+
+    if (pthread_mutex_lock(&mtx)) {
+        fprintf(stderr, " ! repo_join_thread: Failed to lock mutex\n");
+        return 3;
+    }
+
     if (!init) {
         fprintf(stderr, " ! repo_join_thread: repo thread is not launched, can't join\n");
-        return 2;
+        goto error;
     }
 
     stop = 1;
 
     if (pthread_join(repo_thread.th, NULL)) {
         fprintf(stderr, " ! repo_join_thread: failed to join repo thread\n");
-        return 1;
+        goto error;
     }
 
     fprintf(stderr, " . repo_join_thread: repo thread joined\n");
-    return 0;
+
+    ret = 0;
+error:
+    if (pthread_mutex_unlock(&mtx)) {
+        fprintf(stderr, " ! repo_join_thread: Failed to unlock mutex\n");
+        ret = 3;
+    }
+    return ret;
+}
+
+/* Find it in the repo/curl.c file. */
+extern int
+safe_json_get_string(struct json_object *jobj, const char *key, char *content, const size_t len);
+extern int
+safe_json_get_int32(struct json_object *json, const char *key, int32_t *ret);
+
+static inline void
+__handle_got_json(struct lkt_thread *self, struct lkt_repo *repo, struct json_object *json)
+{
+    size_t i, len = json_object_array_length(json);
+    struct json_object *kara_json;
+    int32_t integer;
+    struct kara *kara;
+    int err;
+
+    if (len <= 0 || NULL == json_object_get_array(json)) {
+        fprintf(stderr, "__handle_got_json: Got json is invalid or the array is empty\n");
+        return;
+    }
+
+    for (i = 0; i < len; ++i) {
+        kara_json = json_object_array_get_idx(json, i);
+        kara = calloc(1, sizeof(struct kara));
+        err = 0;
+
+        /* Get the id of the kara. */
+        if (safe_json_get_int32(kara_json, "id", &integer))
+            goto err;
+
+        /* Craft a fake filepath here, it will be used later. */
+        size_t kara_dir_len = strlen(repo->kara_dir);
+        memcpy(kara->filename, repo->kara_dir, sizeof(char) * (kara_dir_len + 1));
+        if (kara->filename[kara_dir_len - 1] != '/') {
+            strncat(kara->filename, "/", PATH_MAX - 1);
+            kara->filename[++kara_dir_len] = 0;
+        }
+        integer = snprintf(kara->filename + kara_dir_len, PATH_MAX - kara_dir_len, "%d", integer);
+        kara->filename[PATH_MAX] = 0;
+        fprintf(stderr, " . __handle_got_json: Crafted filename is '%s'\n", kara->filename);
+
+        if (!kara) {
+            fprintf(stderr, " ! __handle_got_json: Out of memory\n");
+            return;
+        }
+
+        /* Get the fields from the json. */
+        err |= safe_json_get_string(kara_json, "song_name", kara->mdt.song_name, LEKTOR_TAG_MAX);
+        err |= safe_json_get_string(kara_json, "source_name", kara->mdt.source_name, LEKTOR_TAG_MAX);
+        err |= safe_json_get_string(kara_json, "category", kara->mdt.category, LEKTOR_TAG_MAX);
+        err |= safe_json_get_string(kara_json, "language", kara->mdt.language, LEKTOR_TAG_MAX);
+        err |= safe_json_get_string(kara_json, "author_name", kara->mdt.author_name, LEKTOR_TAG_MAX);
+        err |= safe_json_get_string(kara_json, "song_type", kara->mdt.song_type, LEKTOR_TAG_MAX);
+
+        if (err)
+            goto err;
+
+        /* Get the song number. */
+        if (safe_json_get_int32(kara_json, "song_number", &kara->mdt.song_number))
+            goto err;
+
+        /* Append. */
+        if (lkt_th_append_output(self, kara)) {
+            fprintf(stderr, " . __handle_got_json: Could not append downloaded kara mdt\n");
+            goto err;
+        }
+
+        continue;
+err:
+        free(kara);
+    }
 }
 
 static void *
@@ -41,14 +130,29 @@ __repo_thread_function(struct lkt_thread_arg *arg)
     struct lkt_repo *repo = arg->args;
     struct lkt_thread *self = arg->self;
     struct kara *kara;
+    struct json_object *json = NULL;
     char path[PATH_MAX];
     free(arg);
 
     fprintf(stderr, " . __repo_thread_function: Starting the repo thread\n");
 
     for (;;) {
-        if (stop)
+        if (pthread_mutex_lock(&mtx)) {
+            fprintf(stderr, " ! __repo_thread_function: Failed to lock mutex\n");
+            goto end_loop;
+        }
+
+        if (all_json) {
+            repo_get_alljson_sync(repo, &json);
+            __handle_got_json(self, repo, json);
+            json_object_put(json);
+        }
+
+        if (stop) {
+            if (pthread_mutex_unlock(&mtx))
+                fprintf(stderr, " ! __repo_thread_function: Failed to unlock mutex\n");
             break;
+        }
 
         head = 0;
 
@@ -77,6 +181,7 @@ __repo_thread_function(struct lkt_thread_arg *arg)
         }
 
         /* Copy data to the structure that we will pass to the main thread. */
+        kara->action = kara_action_add;
         kara->id = head;
         memcpy(kara->filename, path, (strlen(path) + 1) * sizeof(char));
 
@@ -161,3 +266,21 @@ err:
     *downloaded = NULL;
     return 1;
 }
+
+inline int
+repo_get_allid_async(void)
+{
+    if (pthread_mutex_lock(&mtx)) {
+        fprintf(stderr, " ! repo_get_allid_async: Failed to lock mutex\n");
+        return 3;
+    }
+
+    all_json = 1;
+
+    if (pthread_mutex_unlock(&mtx)) {
+        fprintf(stderr, " ! repo_get_allid_async: Failed to unlock mutex\n");
+        return 3;
+    }
+
+    return 0;
+}
diff --git a/src/repo/curl.c b/src/repo/curl.c
index 6469ae825030f96ce3dac6c6f0b099f1b346d789..277c489234cbffbe58c12222e25af3b028fb96d6 100644
--- a/src/repo/curl.c
+++ b/src/repo/curl.c
@@ -89,6 +89,7 @@ repo_new(struct lkt_repo *const repo_, const char *name_, const char *url_)
         .base_url = url_,
         .get_id_json = GET_ID_JSON,
         .get_id_file = GET_ID_FILE,
+        .get_all_json = DEFAULT_URL "/api_karas.php",
         .kara_dir = "/home/kara/", // TODO
         .version = 1,
     };
@@ -109,7 +110,7 @@ repo_free(struct lkt_repo *const repo)
         curl_global_cleanup();
 }
 
-static inline int
+int
 safe_json_get_string(struct json_object *jobj, const char *key, char *content, const size_t len)
 {
     int ret = 1;
@@ -136,10 +137,76 @@ err:
     return ret;
 }
 
+int
+safe_json_get_int32(struct json_object *json, const char *key, int32_t *ret)
+{
+    struct json_object *field;
+
+    if (!json_object_object_get_ex(json, key, &field)) {
+        fprintf(stderr, " . safe_json_get_int32: No object with key '%s' in json, error\n", key);
+        goto err;
+    }
+
+    errno = 0;
+    *ret = json_object_get_int(field);
+
+    if (errno == EINVAL) {
+        fprintf(stderr, " . __handle_got_json: Invalid integer for field with key 'song_number'\n");
+        goto err;
+    }
+
+    if (*ret == INT32_MAX || *ret == INT32_MIN) {
+        fprintf(stderr, " . __handle_got_json: Out of bound integer for field with key 'song_number'\n");
+        goto err;
+    }
+
+    return 0;
+err:
+    return 1;
+}
+
+int
+repo_get_alljson_sync(struct lkt_repo *const repo, struct json_object **json)
+{
+    if (!json) {
+        fprintf(stderr, " ! repo_get_alljson_sync: Invalid argument\n");
+        return 1;
+    }
+
+    CURL *curl_handle;
+    CURLcode res;
+    int ret = 1;
+
+    struct memory file = {
+        .mem = NULL,
+        .size = 0.
+    };
+
+    curl_handle = curl_easy_init();
+    curl_easy_setopt(curl_handle, CURLOPT_URL, repo->get_all_json);
+    curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_mem__);
+    curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &file);
+    curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
+    res = curl_easy_perform(curl_handle);
+
+    if (res != CURLE_OK) {
+        fprintf(stderr, " ! repo_get_alljson_sync: curl_easy_perform failed: %s\n",
+                curl_easy_strerror(res));
+        free(file.mem);
+        goto err;
+    }
+
+    *json = json_tokener_parse(file.mem);
+
+    ret = 0;
+err:
+    curl_easy_cleanup(curl_handle);
+    return ret;
+}
+
 int
 repo_get_id(struct lkt_repo *const repo, const uint64_t id, struct kara_metadata *mdt)
 {
-    struct memory file;
     CURL *curl_handle;
     CURLcode res;
     struct json_object *jobj, *field;
@@ -155,8 +222,10 @@ repo_get_id(struct lkt_repo *const repo, const uint64_t id, struct kara_metadata
         return ENOMEM;
     }
 
-    file.mem = NULL;
-    file.size = 0;
+    struct memory file = {
+        .mem = NULL,
+        .size = 0,
+    };
 
     memset(url, 0, URL_MAX_LEN * sizeof(char));
     snprintf(url, URL_MAX_LEN - 1, repo->get_id_json, id);
@@ -299,7 +368,7 @@ repo_download_id_sync(struct lkt_repo *const repo, sqlite3 *db, const uint64_t i
         goto no_db_update;
     }
 
-    if (! database_update_add(db, kara_path, mdt_ret ? mdt_ret : &mdt, id)) {
+    if (! database_update_add(db, kara_path, mdt_ret ? mdt_ret : &mdt, id, true)) {
         fprintf(stderr, " ! repo_download_id_sync: Failed to add kara to database\n");
         goto err;
     }