diff --git a/inc/common/common.h b/inc/common/common.h
index 501996fc78aba176e750d2d641b9033bde8bcfdb..074fd87b94972d8a69b397bbd103ee3202cf7da9 100644
--- a/inc/common/common.h
+++ b/inc/common/common.h
@@ -36,3 +36,5 @@ char *trim(char *str, size_t len, char c);
 int get_stdin_line(const char *prompt, char *buf, size_t len);
 
 int read_self_exe(char *path, size_t len);
+
+int safe_snprintf(char *dest, const size_t max_len, const char *format, ...);
diff --git a/inc/common/macro.h b/inc/common/macro.h
index cc89cf2431af3263d8c6aa0eba34bf5e531d3d35..cb3393ec5df88049776bc6a641be6e34b1316e1d 100644
--- a/inc/common/macro.h
+++ b/inc/common/macro.h
@@ -169,3 +169,6 @@ typedef volatile enum {
 
 #define SQLITE_DO_ROLLBACK(db)                                          \
     sqlite3_exec((sqlite3 *) db, "ROLLBACK TRANSACTION;\n", NULL, NULL, NULL);
+
+#define STR_MATCH(str1, str2)           (! strcasecmp(str1, str2))
+#define STR_NMATCH(str1, str2, n)       (! strncasecmp(str1, str2, n))
diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h
index ba3cb7af0435577c45810c65413a68aaa5db95e2..53067fe5f6c6752625b7d1d1e0bc08dae8444828 100644
--- a/inc/lektor/commands.h
+++ b/inc/lektor/commands.h
@@ -28,7 +28,8 @@ bool command_stop    (volatile sqlite3 *db, struct lkt_win *win,
 bool command_set_pos(volatile sqlite3 *db, struct lkt_win *win, mpd_idle_flag *watch_mask_ptr, int index);
 
 /* The queue */
-bool command_add    (volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr, int priority);
+bool command_add    (volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr,
+                     int priority);
 bool command_addid  (volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
 bool command_del    (volatile sqlite3 *db, struct lkt_win *win, char *pos_range,                  mpd_idle_flag *watch_mask_ptr);
 bool command_delid  (volatile sqlite3 *db, struct lkt_win *win, char *id,                         mpd_idle_flag *watch_mask_ptr);
@@ -60,7 +61,7 @@ bool command_noidle(struct lkt_state *srv, size_t c);
 
 /* Find and send karas in the db that match the search expression */
 bool command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation,
-                  bool (*init)(volatile sqlite3 *, char *, char *, struct lkt_search *));
+                  bool (*init)(volatile sqlite3 *, struct lkt_search *));
 
 /* Set options for the lektor such as `random`, `single`, `repeat`, etc */
 enum lkt_playback_option {
diff --git a/inc/lektor/database.h b/inc/lektor/database.h
index 4da2d086ac7ee9ca666078a5a341594198ef4f21..2923dc854a8616e850d06b0eca577cbec253440f 100644
--- a/inc/lektor/database.h
+++ b/inc/lektor/database.h
@@ -96,6 +96,9 @@ struct lkt_search {
     const char *name;       /* Stickers and playlists                       */
     int st_value;           /* The value of a sticker                       */
     int st_uri;             /* URI of a sticker                             */
+    char st_op;             /* Comparaison operator for stickers            */
+    char *st_type;          /* Type of sticker                              */
+    char *ka_rgx;           /* Regex for the content of the selected column */
 };
 
 typedef bool (*lkt_search_init_add_func)(volatile sqlite3 *, struct lkt_uri *, int);
@@ -103,9 +106,9 @@ typedef bool (*lkt_search_database_func)(struct lkt_state *srv, size_t c, int id
 typedef bool (*lkt_search_queue_func)   (struct lkt_state *srv, size_t c, int id, int id_len, const char *row);
 typedef bool (*lkt_search_sticker_func) (struct lkt_state *srv, size_t c, const char *sticker, const char *type, int uri, int value);
 
-bool database_search_database_init(volatile sqlite3 *db, char *col_name, char *rgx,  struct lkt_search *ret);
-bool database_search_queue_init   (volatile sqlite3 *db, char *col_name, char *rgx,  struct lkt_search *ret);
-bool database_search_sticker_init (volatile sqlite3 *db, char *type,     char *name, struct lkt_search *ret);
+bool database_search_database_init(volatile sqlite3 *db, struct lkt_search *ret);
+bool database_search_queue_init   (volatile sqlite3 *db, struct lkt_search *ret);
+bool database_search_sticker_init (volatile sqlite3 *db, struct lkt_search *ret);
 bool database_search_iter(struct lkt_search *item);
 
 /* Next and prev operation on the queue. */
@@ -147,17 +150,7 @@ bool database_user_authentificate(volatile sqlite3 *db, const char *password);
 bool database_user_add(volatile sqlite3 *db, const char *username, const char *password);
 
 /* Stickers manipulations. */
-struct sticker_callback {
-    struct lkt_state *srv;
-    size_t c;
-    int uri, value, is_ok;
-    const char *name;
-    bool (*call)(void *args, const char *sticker, const char *type, int uri, int value);
-};
-
 bool database_sticker_create        (volatile sqlite3 *db, const char *name);
 bool database_sticker_delete        (volatile sqlite3 *db, const char *name);
 bool database_sticker_delete_specify(volatile sqlite3 *sb, const char *type, int uri, const char *name);
-bool database_sticker_list          (volatile sqlite3 *db, const char *type, struct sticker_callback *call);
 bool database_sticker_set           (volatile sqlite3 *db, const char *type, const char *name, int uri, int value);
-bool database_sticker_get           (volatile sqlite3 *db, const char *type, const char *name, int uri, struct sticker_callback *call);
diff --git a/scripts/init.sql b/scripts/init.sql
index 040b0ff1005adb785082cc1a462f9e2436df7318..d4e3e1c3c422e4be0017a0f470a40ef6b6e760b6 100644
--- a/scripts/init.sql
+++ b/scripts/init.sql
@@ -3,7 +3,6 @@ PRAGMA encoding            = 'UTF-8';
 PRAGMA recursive_triggers  = true;
 PRAGMA foreign_keys        = true;
 
-
 -- Definition of a kara
 
 CREATE TABLE IF NOT EXISTS kara
@@ -98,6 +97,7 @@ INSERT OR REPLACE INTO users (username, password) VALUES ('sakura', 'hashire');
 -- Used to implement the stickers MPD functionnality, documentation can be found
 -- here: https://www.musicpd.org/doc/html/protocol.html#stickers. Need to be
 -- authentified to use stickers commands. Support tags for `song` and `plt`.
+-- URIs in stickers are kara/playlist IDs.
 
 CREATE TABLE IF NOT EXISTS 'stickers'
   ( id      INTEGER PRIMARY KEY
diff --git a/src/commands.c b/src/commands.c
index 4e2b1a5b585ca60cc51a95184d2eca6f70f1671a..f1f3843d91069f1bed7874a3234fed2620635877 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -84,15 +84,15 @@ command_currentsong(struct lkt_state *srv, size_t c)
         LOG_ERROR_SCT("COMMAND", "%s", "Failed to get information about the current kara");
 
     out = lkt_message_new();
-    idx = snprintf(out->data, LKT_MESSAGE_MAX,
+    idx = safe_snprintf(out->data, LKT_MESSAGE_MAX,
                    "Title: %s\n"
                    "Author: %s\n"
                    "Source: %s\n"
                    "Type: %s%d\n"
                    "Category: %s\n"
                    "Language: %s\n",
-                   kara.song_name, kara.author_name, kara.source_name, kara.category,
-                   kara.song_number, kara.song_type, kara.language);
+                   kara.song_name, kara.author_name, kara.source_name, kara.song_type,
+                   kara.song_number, kara.category, kara.language);
     out->data_len = idx;
     lkt_state_send(srv, c, out);
 
@@ -119,7 +119,7 @@ command_status(struct lkt_state *srv, size_t c)
     play_state = queue_state.current <= 0
                  ? "stop"
                  : (queue_state.paused ? "pause" : "play");
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX,
+    out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX,
                              "volume: %d\n"
                              "repeat: %d\n"
                              "random: %d\n"
@@ -312,10 +312,8 @@ bool
 command_help(struct lkt_state *srv, size_t c)
 {
     struct lkt_message *out;
-    int idx;
     out = lkt_message_new();
-    idx = snprintf(out->data, LKT_MESSAGE_MAX, "HELP\n");
-    out->data_len = idx;
+    out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX, "HELP\n");
     lkt_state_send(srv, c, out);
     return true;
 }
@@ -329,29 +327,29 @@ command_idle(struct lkt_state *srv, size_t c, struct lkt_command *cmd)
     for (size_t i = 0; cmd->args[i]; ++i) {
         once |= true;
 
-        if (strcmp(cmd->args[i], "database") == 0)
+        if (STR_MATCH(cmd->args[i], "database"))
             *clt_mask |= MPD_IDLE_DATABASE;
-        else if (strcmp(cmd->args[i], "update") == 0)
+        else if (STR_MATCH(cmd->args[i], "update"))
             *clt_mask |= MPD_IDLE_UPDATE;
-        else if (strcmp(cmd->args[i], "stored_playlist") == 0)
+        else if (STR_MATCH(cmd->args[i], "stored_playlist"))
             *clt_mask |= MPD_IDLE_STORED_PLAYLIST;
-        else if (strcmp(cmd->args[i], "playlist") == 0)
+        else if (STR_MATCH(cmd->args[i], "playlist"))
             *clt_mask |= MPD_IDLE_PLAYLIST;
-        else if (strcmp(cmd->args[i], "player") == 0)
+        else if (STR_MATCH(cmd->args[i], "player"))
             *clt_mask |= MPD_IDLE_PLAYER;
-        else if (strcmp(cmd->args[i], "mixer") == 0)
+        else if (STR_MATCH(cmd->args[i], "mixer"))
             *clt_mask |= MPD_IDLE_MIXER;
-        else if (strcmp(cmd->args[i], "output") == 0)
+        else if (STR_MATCH(cmd->args[i], "output"))
             *clt_mask |= MPD_IDLE_OUTPUT;
-        else if (strcmp(cmd->args[i], "options") == 0)
+        else if (STR_MATCH(cmd->args[i], "options"))
             *clt_mask |= MPD_IDLE_OPTIONS;
-        else if (strcmp(cmd->args[i], "partition") == 0)
+        else if (STR_MATCH(cmd->args[i], "partition"))
             *clt_mask |= MPD_IDLE_PARTITION;
-        else if (strcmp(cmd->args[i], "sticker") == 0)
+        else if (STR_MATCH(cmd->args[i], "sticker"))
             *clt_mask |= MPD_IDLE_STICKER;
-        else if (strcmp(cmd->args[i], "subscription") == 0)
+        else if (STR_MATCH(cmd->args[i], "subscription"))
             *clt_mask |= MPD_IDLE_SUBSCRIPTION;
-        else if (strcmp(cmd->args[i], "message") == 0)
+        else if (STR_MATCH(cmd->args[i], "message"))
             *clt_mask |= MPD_IDLE_MESSAGE;
         else
             *clt_mask = MPD_IDLE_ALL;
@@ -380,7 +378,7 @@ lkt_callback_send_row_v1(void *_args, int pos_len, int pos, int id, int id_len,
     struct lkt_callback *args = (struct lkt_callback *) _args;
     struct lkt_message *out;
     out = lkt_message_new();
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%*d: %*d %s\n", pos_len, pos, id_len, id, sql_row);
+    out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX, "%*d: %*d %s\n", pos_len, pos, id_len, id, sql_row);
     lkt_state_send(args->srv, args->c, out);
     return true;
 }
@@ -389,16 +387,16 @@ bool
 lkt_callback_send_row_v2(struct lkt_state *srv, size_t c, int id, int id_len, const char *sql_row)
 {
     struct lkt_message *out = lkt_message_new();
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%*d %s\n", id_len, id, sql_row);
+    out->data_len = safe_snprintf(out->data, LKT_MESSAGE_MAX, "%*d %s\n", id_len, id, sql_row);
     lkt_state_send(srv, c, out);
     return true;
 }
 
 bool
 command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation,
-             bool(*init)(volatile sqlite3 *, char *, char *, struct lkt_search *))
+             bool(*init)(volatile sqlite3 *, struct lkt_search *))
 {
-    char rgx[PATH_MAX], *col_name, *mpd_tag;
+    char rgx[PATH_MAX], *mpd_tag;
     int count;
     struct lkt_search search = {
         .srv = srv,
@@ -406,6 +404,7 @@ command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MA
         .continuation = continuation,
         .msg_count = lkt_remaining_msg(srv, c) - 3, /* Reserve slots for OK/ACK and continue: */
         .call = (void(*)(void)) lkt_callback_send_row_v2,
+        .ka_rgx = rgx,
     };
 
     /* Check args */
@@ -413,20 +412,26 @@ command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MA
 
     /* Select the right column */
     mpd_tag = cmd_args[0];
-    if (!strcasecmp("any", mpd_tag) || !strcasecmp("all", mpd_tag) || !strcasecmp("query", mpd_tag) ||
-        !strcasecmp("source", mpd_tag) || !strcasecmp("title", mpd_tag)) {
-        col_name = LKT_DATABASE_KARA_COLUMNT_ANY;
-    } else if (!strcasecmp("author", mpd_tag)) {
-        col_name = LKT_DATABASE_NAME_KAUTHOR;
-    } else if (!strcasecmp("category", mpd_tag) || !strcasecmp("cat", mpd_tag)) {
-        col_name = LKT_DATABASE_NAME_KCAT;
-    } else if (!strcasecmp("type", mpd_tag)) {
-        col_name = LKT_DATABASE_NAME_KTYPE;
-    } else if (!strcasecmp("language", mpd_tag) || !strcasecmp("lang", mpd_tag)) {
-        col_name = LKT_DATABASE_NAME_KLANG;
-    } else if (!strcasecmp("id", mpd_tag)) {
-        col_name = LKT_DATABASE_NAME_KID;
-    } else
+    if (STR_MATCH("any", mpd_tag) || STR_MATCH("all", mpd_tag) || STR_MATCH("query", mpd_tag) ||
+        STR_MATCH("source", mpd_tag) || STR_MATCH("title", mpd_tag))
+        search.name = LKT_DATABASE_KARA_COLUMNT_ANY;
+
+    else if (STR_MATCH("author", mpd_tag))
+        search.name = LKT_DATABASE_NAME_KAUTHOR;
+
+    else if (STR_MATCH("category", mpd_tag) || STR_MATCH("cat", mpd_tag))
+        search.name = LKT_DATABASE_NAME_KCAT;
+
+    else if (STR_MATCH("type", mpd_tag))
+        search.name = LKT_DATABASE_NAME_KTYPE;
+
+    else if (STR_MATCH("language", mpd_tag) || STR_MATCH("lang", mpd_tag))
+        search.name = LKT_DATABASE_NAME_KLANG;
+
+    else if (STR_MATCH("id", mpd_tag))
+        search.name = LKT_DATABASE_NAME_KID;
+
+    else
         return false;
 
     /* Get the regex */
@@ -440,7 +445,7 @@ command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MA
     }
 
     /* Make the search langand do the right action */
-    RETURN_UNLESS(init(srv->db, col_name, rgx, &search), "Failed to init search", false);
+    RETURN_UNLESS(init(srv->db, &search), "Failed to init search", false);
 
     for (count = 0; database_search_iter(&search); ++count)
         continue;
@@ -713,82 +718,11 @@ command_user_add(struct lkt_state *srv, size_t c, volatile sqlite3 *db, char *ar
 /* Stickers */
 
 static bool
-sticker_send_one_value(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    UNUSED(sticker, type, uri);
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    struct lkt_message *out = lkt_message_new();
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "value: %d\n", value);
-    lkt_state_send(args->srv, args->c, out);
-    return false;
-}
-
-static bool
-sticker_send_all(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    struct lkt_message *out = lkt_message_new();
-    out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%s: %d\nsticker: %s\nvalue: %d\n",
-                             type, uri, sticker, value);
-    lkt_state_send(args->srv, args->c, out);
-    return true;
-}
-
-static bool
-sticker_send_check_uri(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    UNUSED(type);
-
-    if (uri == args->uri) {
-        struct lkt_message *out = lkt_message_new();
-        out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "%s: %d\n", sticker, value);
-        lkt_state_send(args->srv, args->c, out);
-    }
-
-    return true;
-}
-
-static bool
-sticker_send_value_check_uri_name(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    struct lkt_message *out;
-    UNUSED(type);
-
-    if (uri == args->uri || !strcasecmp(sticker, args->name)) {
-        out = lkt_message_new();
-        out->data_len = snprintf(out->data, LKT_MESSAGE_MAX, "value: %d\n", value);
-        lkt_state_send(args->srv, args->c, out);
-    }
-
-    return true;
-}
-
-static bool
-sticker_check_is_present_eq(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    UNUSED(type);
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    args->is_ok |= (uri == args->uri) && !strcasecmp(sticker, args->name) && (value == args->value);
-    return true;
-}
-
-static bool
-sticker_check_is_present_lt(void *_args, const char *sticker, const char *type, int uri, int value)
-{
-    UNUSED(type);
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    args->is_ok |= (uri == args->uri) && !strcasecmp(sticker, args->name) && (value < args->value);
-    return true;
-}
-
-static bool
-sticker_check_is_present_gt(void *_args, const char *sticker, const char *type, int uri, int value)
+sticker_send(struct lkt_state *srv, size_t c, char *name, int id, int value)
 {
-    UNUSED(type);
-    struct sticker_callback *args = (struct sticker_callback *) _args;
-    args->is_ok |= (uri == args->uri) && !strcasecmp(sticker, args->name) && (value > args->value);
+    struct lkt_message *msg = lkt_message_new();
+    msg->data_len = safe_snprintf(msg->data, LKT_MESSAGE_ARGS_MAX, "%d: %s . %d", id, name, value);
+    lkt_state_send(srv, c, msg);
     return true;
 }
 
@@ -796,16 +730,22 @@ bool
 command_sticker_get(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(argv[0] && argv[1] && argv[2] && !argv[3], "Invalid argument", false);
-    int uri, err;
-    char *endptr;
+    long uri;
+    char *endptr, err;
     STRTOL(uri, argv[1], endptr, err);
     RETURN_IF(err, "STRTOL failed", false);
-    struct sticker_callback cb = {
+    struct lkt_search cb = {
+        .call = (void(*)(void)) sticker_send,
         .srv = srv,
         .c = c,
-        .call = sticker_send_one_value,
+        .name = argv[2],
+        .st_type = argv[0],
+        .st_uri = (int) uri,
     };
-    RETURN_UNLESS(database_sticker_get(srv->db, argv[0], argv[2], uri, &cb), "Failed to get sticker", false);
+    if (!database_search_sticker_init(srv->db, &cb))
+        return false;
+    while (database_search_iter(&cb))
+        continue;
     return true;
 }
 
@@ -827,66 +767,54 @@ command_sticker_set(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS
 bool
 command_sticker_list(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX])
 {
-    struct sticker_callback callback = {
+    struct lkt_search callback = {
         .srv = srv,
         .c = c,
+        .call = (void(*)(void)) sticker_send,
+        .st_type = argv[0],
     };
 
     /* Simple list {type} {uri} command */
-    if (argv[0] != NULL && argv[1] != NULL && argv[2] == NULL)
-        goto simple_list_command;
+    if (argv[0] != NULL && argv[1] != NULL && argv[2] == NULL) {
+        callback.st_uri = atoi(argv[1]);
+        if (database_search_sticker_init(srv->db, &callback))
+            goto iter;
+    }
 
     /* list {type} {uri} {name} command */
     else if (argv[0] != NULL && argv[1] != NULL &&
-             argv[2] != NULL && argv[3] == NULL)
-        goto list_stickers_in_uri;
+             argv[2] != NULL && argv[3] == NULL) {
+        callback.name = argv[2];
+        callback.st_uri = atoi(argv[1]);
+        if (database_search_sticker_init(srv->db, &callback))
+            goto iter;
+    }
 
     /* list {type} {uri} {name} `op` {value} command */
     else if (argv[0] != NULL && argv[1] != NULL &&
              argv[2] != NULL && argv[3] != NULL &&
-             argv[4] != NULL && argv[5] == NULL)
-        goto list_stickers_check_value;
+             argv[4] != NULL && argv[5] == NULL) {
+        callback.name = argv[2];
+        callback.st_uri = atoi(argv[1]);
+        callback.st_op = argv[3][0];
+        callback.st_value = atoi(argv[4]);
+        if (database_search_sticker_init(srv->db, &callback))
+            goto iter;
+    }
 
     /* Just list all stickers */
-    else if ( (argv[0] != NULL && argv[1] == NULL) || argv[0] == NULL )
-        goto just_list_all;
+    else if ( (argv[0] != NULL && argv[1] == NULL) || argv[0] == NULL ) {
+        if (database_search_sticker_init(srv->db, &callback))
+            goto iter;
+    }
 
     else
         goto unknown;
 
-just_list_all:
-    callback.call = sticker_send_all;
-    return database_sticker_list(srv->db, argv[0], &callback);
-
-simple_list_command:
-    callback.uri  = atoi(argv[1]);   /* FIXME: Use strtol. */
-    callback.call = sticker_send_check_uri;
-    return database_sticker_list(srv->db, argv[0], &callback);
-
-list_stickers_in_uri:
-    callback.uri  = atoi(argv[1]);  /* FIXME: Use strtol. */
-    callback.name = argv[2];
-    callback.call = sticker_send_value_check_uri_name;
-    return database_sticker_list(srv->db, argv[0], &callback);
-    return false;
-
-list_stickers_check_value:
-    callback.uri   = atoi(argv[1]); /* FIXME: Use strtol. */
-    callback.value = atoi(argv[4]); /* FIXME: Use strtol. */
-    callback.name  = argv[2];
-    switch (argv[3][0]) {
-    case '=':
-        callback.call = sticker_check_is_present_eq;
-        return database_sticker_list(srv->db, argv[0], &callback);
-    case '<':
-        callback.call = sticker_check_is_present_lt;
-        return database_sticker_list(srv->db, argv[0], &callback);
-    case '>':
-        callback.call = sticker_check_is_present_gt;
-        return database_sticker_list(srv->db, argv[0], &callback);
-    default:
-        return 0;
-    }
+iter:
+    while (database_search_iter(&callback))
+        continue;
+    return true;
 
 unknown:
     LOG_ERROR_SCT("COMMAND", "%s", "Specified command is invalid or unknown");
diff --git a/src/common.c b/src/common.c
index f301ac07491d5fc6ca53711aae491f1987c91276..636bf3d5459a7f8a8810b99c27418ef7994f60c7 100644
--- a/src/common.c
+++ b/src/common.c
@@ -5,6 +5,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 #include <sys/stat.h>
 
 void
@@ -157,3 +158,14 @@ read_self_exe(char *path, size_t len)
            (readlink(SELF_EXECUTABLE_FREEBSD, path, len - 1) > 0) ||
            (readlink(SELF_EXECUTABLE_SOLARIS, path, len - 1) > 0);
 }
+
+int
+safe_snprintf(char *dest, const size_t max_len, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    int ret = vsnprintf(dest, max_len, format, ap);
+    dest[max_len - 1] = '\0';
+    va_end(ap);
+    return ret;
+}
diff --git a/src/database/config.c b/src/database/config.c
index 00c82c62750cafcf78cfb4fa33f35e0c4738abe9..eb09db8541c459fc983e2f50da364853b18380fd 100644
--- a/src/database/config.c
+++ b/src/database/config.c
@@ -119,8 +119,7 @@ database_config_queue(volatile sqlite3 *db, const char *option, int value)
     if (value > 100)
         value = 100;
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TMP, option);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TMP, option);
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     SQLITE_BIND_INT(db, stmt, 1, value, error);
 
@@ -162,8 +161,7 @@ database_get_config(volatile sqlite3 *db, const char *option, int *value)
     sqlite3_stmt *stmt = 0;
     bool ret = false;
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TMP, option);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TMP, option);
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     SQLITE_STEP_ROW(db, stmt, error);
     *value = sqlite3_column_int(stmt, 0);
diff --git a/src/database/find.c b/src/database/find.c
index c95a2374aa30b9ff2ad2c5716b0f00da61c56889..8cab8488045c254566baf24ab05c845ff6fff6b3 100644
--- a/src/database/find.c
+++ b/src/database/find.c
@@ -9,7 +9,7 @@
 #include <string.h>
 
 bool
-database_search_database_init(volatile sqlite3 *db, char *col_name, char *rgx, struct lkt_search *ret)
+database_search_database_init(volatile sqlite3 *db, struct lkt_search *ret)
 {
     RETURN_UNLESS(ret, "Exit because return pointer is NULL", false);
     static const char *SQL_STMT_TEMPLATE =
@@ -22,11 +22,9 @@ database_search_database_init(volatile sqlite3 *db, char *col_name, char *rgx, s
     ret->type = lkt_search_database;
 
     /* Search part */
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TEMPLATE, col_name,
-             ret->msg_count, ret->continuation);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TEMPLATE, ret->name, ret->msg_count, ret->continuation);
     SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error);
-    SQLITE_BIND_TEXT(db, ret->stmt, 1, rgx, error);
+    SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->ka_rgx, error);
     ret->db = db;
     return true;
 error:
@@ -35,7 +33,7 @@ error:
 }
 
 bool
-database_search_sticker_init(volatile sqlite3 *db, char *type, char *name, struct lkt_search *ret)
+database_search_sticker_init(volatile sqlite3 *db, struct lkt_search *ret)
 {
     /* No bound checks in strcats, should be fine. Possible SQL injection, depend on the `type`. */
     static const char *SQL_all_types =
@@ -47,21 +45,26 @@ database_search_sticker_init(volatile sqlite3 *db, char *type, char *name, struc
         "ON sts.sticker = 'stickers'.id";
     static const char *SQL_one_type =
         "SELECT name, 'stickers.%s'.id, value "
-        "FROM 'stickers' "
+        "FROM 'stickers.%s' AS sts"
         "LEFT OUTER JOIN 'stickers' "
-        "ON 'stickers'.id = 'stickers.%s'.sticker";
-    static const char *SQL_check_name = " AND name = ?;";
+        "ON 'stickers'.id = sts.sticker";
     char SQL[LKT_MAX_SQLITE_STATEMENT];
 
-    if (type == NULL)
+    if (ret->st_type == NULL)
         memcpy(SQL, SQL_all_types, strlen(SQL_all_types) + 1);
     else
-        sprintf(SQL, SQL_one_type, type, type);
-    strcat(SQL, name ? SQL_check_name : ";");
+        sprintf(SQL, SQL_one_type, ret->st_type, ret->st_type);
+    if (ret->st_uri != 0)
+        sprintf(SQL, " AND sts.id = %d", ret->st_uri);
+    if (ret->st_op != 0)
+        sprintf(SQL, " AND sts.value %s %d",
+                ret->st_op == '>' ? ">=" : ret->st_op == '<' ? "<=" : "=",
+                ret->st_value);
+    strcat(SQL, ret->name ? " AND name = ?;" : ";");
 
     SQLITE_PREPARE(db, ret->stmt, SQL, error);
-    if (name)
-        SQLITE_BIND_TEXT(db, ret->stmt, 1, name, error)
+    if (ret->name)
+        SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->name, error)
         return true;
 error:
     sqlite3_finalize(ret->stmt);
@@ -69,7 +72,7 @@ error:
 }
 
 bool
-database_search_queue_init(volatile sqlite3 *db, char *col_name, char *rgx, struct lkt_search *ret)
+database_search_queue_init(volatile sqlite3 *db, struct lkt_search *ret)
 {
     RETURN_UNLESS(ret, "Exit because return pointer is NULL", false);
     static const char *SQL_STMT_TEMPLATE =
@@ -84,11 +87,9 @@ database_search_queue_init(volatile sqlite3 *db, char *col_name, char *rgx, stru
     ret->type = lkt_search_queue;
 
     /* Search part */
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT_TEMPLATE, col_name,
-             ret->msg_count, ret->continuation);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_STMT_TEMPLATE, ret->name, ret->msg_count, ret->continuation);
     SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error);
-    SQLITE_BIND_TEXT(db, ret->stmt, 1, rgx, error);
+    SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->ka_rgx, error);
     ret->db = db;
     return true;
 error:
diff --git a/src/database/open.c b/src/database/open.c
index 24b9fec3fcb855b49a9700cf81c4a1c71533bebc..9c28886822cbb722d6601585f31646453b383418 100644
--- a/src/database/open.c
+++ b/src/database/open.c
@@ -78,8 +78,7 @@ __attach(volatile sqlite3 *db, const char *name, const char *path)
     char SQL_ATTACH[LKT_MAX_SQLITE_STATEMENT];
     bool ret = false;
 
-    snprintf(SQL_ATTACH, LKT_MAX_SQLITE_STATEMENT - 1, SQL_ATTACH_TEMPLATE, path, name);
-    SQL_ATTACH[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_ATTACH, LKT_MAX_SQLITE_STATEMENT, SQL_ATTACH_TEMPLATE, path, name);
     SQLITE_EXEC(db, SQL_ATTACH, err_no_attach);
     LOG_INFO_SCT("DB", "Attached database '%s' with path '%s'", name, path);
     ret = true;
@@ -94,8 +93,7 @@ __detach(volatile sqlite3 *db, const char *name)
     char SQL_DETACH[LKT_MAX_SQLITE_STATEMENT];
     bool ret = false;
 
-    snprintf(SQL_DETACH, LKT_MAX_SQLITE_STATEMENT - 1, SQL_DETACH_TEMPLATE, name);
-    SQL_DETACH[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_DETACH, LKT_MAX_SQLITE_STATEMENT, SQL_DETACH_TEMPLATE, name);
     SQLITE_EXEC(db, SQL_DETACH, err_no_detach);
     LOG_INFO_SCT("DB", "Detached database '%s'", name);
     ret = true;
diff --git a/src/database/playlist.c b/src/database/playlist.c
index 96f704f075d18d16f217122741422ef532095640..a805e47b214f86c4d35dbb9eadbd3430f6c3ac36 100644
--- a/src/database/playlist.c
+++ b/src/database/playlist.c
@@ -108,8 +108,7 @@ database_plt_export(volatile sqlite3 *db, const char *name)
     GOTO_UNLESS(strcasecmp(name, PROTECTED_DATABASE), "Name '"PROTECTED_DATABASE
                 "' is protected, you can't use it for a playlist name", error);
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_SCHEM, name);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_SCHEM, name);
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     code = sqlite3_step(stmt);
 
@@ -141,8 +140,7 @@ database_plt_import(volatile sqlite3 *db, const char *name)
     GOTO_UNLESS(strcasecmp(name, PROTECTED_DATABASE), "Name '"PROTECTED_DATABASE
                 "' is protected, you can't use it for a playlist name", error);
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL_SCHEM, name, name, name);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL_SCHEM, name, name, name);
     SQLITE_EXEC(db, SQL_STMT, error);
     ret = true;
 error:
@@ -184,8 +182,7 @@ database_plt_add_uri(volatile sqlite3 *db, const char *name, struct lkt_uri *uri
         return false;
     }
 
-    snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT - 1, SQL, column);
-    SQL_STMT[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL_STMT, LKT_MAX_SQLITE_STATEMENT, SQL, column);
     SQLITE_PREPARE(db, stmt, SQL_STMT, error);
     SQLITE_BIND_TEXT(db, stmt, 1, name, error);
     SQLITE_BIND_TEXT(db, stmt, 2, (char *) uri->value, error);
diff --git a/src/database/queue.c b/src/database/queue.c
index 550463d5a222530896c618283294b1d6f4a7fd9d..8ff68e8410714f2e5dc0c04859ca77b7832760b5 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -126,8 +126,7 @@ queue_add_with_col_like_str(volatile sqlite3 *db, const char *col, const char *v
     SQLITE_EXEC(db, "BEGIN TRANSACTION;", error);
 
     /* Insert at the end of the queue */
-    snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT, col);
-    SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, SQL_STMT, col);
     SQLITE_PREPARE(db, stmt, SQL, error);
     SQLITE_BIND_INT(db, stmt, 1, priority, error);
     SQLITE_BIND_TEXT(db, stmt, 2, val, error);
@@ -252,21 +251,21 @@ database_queue_add_uri(volatile sqlite3 *db, struct lkt_uri *uri, int priority)
 bool
 database_queue_del_id(volatile sqlite3 *db, int id)
 {
+    /* FIXME: Can't pop if its the last kara */
 #define POS_OF_ID "(SELECT position FROM queue WHERE kara_id = %d)"
     static const char *SQL_TEMPLATE =
         "BEGIN TRANSACTION;"
         "WITH before(pos) AS (SELECT position FROM queue JOIN queue_state WHERE position < current ORDER BY position DESC LIMIT 1) "
         "UPDATE queue_state SET current = CASE WHEN current IS NULL THEN NULL ELSE (SELECT pos FROM before) END WHERE current > " POS_OF_ID ";"
-        "UPDATE queue SET position = position - 1 WHERE position > " POS_OF_ID ";"
-        "DELETE FROM queue WHERE kara_id = %d;"
-        "COMMIT TRANSACTION;";
+        "UPDATE OR REPLACE queue SET position = position - 1 WHERE position > " POS_OF_ID ";"
+        "COMMIT;";
 #undef POS_OF_ID
     char SQL[LKT_MAX_SQLITE_STATEMENT];
-    snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, SQL_TEMPLATE, id, id, id, id);
-    SQL[LKT_MAX_SQLITE_STATEMENT - 1] = '\0';
+    safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, SQL_TEMPLATE, id, id, id, id);
     SQLITE_EXEC(db, SQL, error);
     return true;
 error:
+    SQLITE_DO_ROLLBACK(db);
     return false;
 }
 
@@ -295,8 +294,7 @@ database_queue_next(volatile sqlite3 *db, char filepath[PATH_MAX])
 
     if (code == SQLITE_ROW) {
         id = MAX(1, sqlite3_column_int(stmt, 1));
-        snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT - 1, "UPDATE queue_state SET current = %d;", id);
-        SQL_UPDATE[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+        safe_snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT, "UPDATE queue_state SET current = %d;", id);
 
         if (filepath != NULL)
             strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
@@ -355,8 +353,7 @@ database_queue_prev(volatile sqlite3 *db, char filepath[PATH_MAX])
 
     if (code == SQLITE_ROW) {
         id = MAX(1, sqlite3_column_int(stmt, 1));
-        snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT - 1, "UPDATE queue_state SET current = %d;", id);
-        SQL_UPDATE[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+        safe_snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT, "UPDATE queue_state SET current = %d;", id);
 
         if (filepath != NULL)
             strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
@@ -391,10 +388,11 @@ database_queue_clear(volatile sqlite3 *db)
         "DELETE FROM queue;"
         "DELETE FROM sqlite_sequence WHERE name = 'queue';"
         "UPDATE queue_state SET current = NULL;"
-        "COMMIT TRANSACTION;";
+        "COMMIT;";
     SQLITE_EXEC(db, SQL_STMT, error);
     return true;
 error:
+    SQLITE_DO_ROLLBACK(db);
     return false;
 }
 
@@ -421,7 +419,7 @@ database_queue_move(volatile sqlite3 *db, int from, int to)
         "BEGIN TRANSACTION;"
         "UPDATE queue SET position = position + 1 WHERE position >= ?;"
         "UPDATE queue SET position = ? WHERE position = ?;"
-        "COMMIT TRANSACTION;";
+        "COMMIT;";
     sqlite3_stmt *stmt = 0;
     bool ret = false;
     int code;
@@ -490,9 +488,8 @@ database_queue_set_current_index(volatile sqlite3 *db, int idx)
         return false;
     }
 
-    RETURN_IF(snprintf(SQL_GET, LKT_MAX_SQLITE_STATEMENT - 1, SQL_GET_TEMPLATE, idx) < 0, "Snprintf failed",
-              false);
-    SQL_GET[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
+    RETURN_IF(safe_snprintf(SQL_GET, LKT_MAX_SQLITE_STATEMENT, SQL_GET_TEMPLATE, idx) < 0,
+              "Snprintf failed", false);
     SQLITE_EXEC(db, SQL_GET, error);
     return true;
 error:
@@ -584,6 +581,7 @@ database_queue_shuffle(volatile sqlite3 *db)
     SQLITE_EXEC(db, SQL, error);
     return true;
 error:
+    SQLITE_DO_ROLLBACK(db);
     return false;
 }
 
diff --git a/src/database/stickers.c b/src/database/stickers.c
index 376621987d250e6819dd9feb44637f7a6e44d2ad..a0a7c7f001c9961549b5f016f6e859501e04bbe0 100644
--- a/src/database/stickers.c
+++ b/src/database/stickers.c
@@ -45,66 +45,6 @@ error:
     return ret;
 }
 
-bool
-database_sticker_list(volatile sqlite3 *db, const char *type, struct sticker_callback *call)
-{
-    const char *SQL = NULL;
-    int ret = false, uri, value;
-    sqlite3_stmt *stmt;
-    const char *sticker;
-
-    if (type == NULL)
-        SQL =
-            "SELECT name, sts.id, value FROM 'stickers' LEFT OUTER JOIN "
-            "( SELECT id, sticker, value FROM 'stickers.song'"
-            "  UNION"
-            "  SELECT id, sticker, value FROM 'stickers.plt'"
-            ") AS sts"
-            "ON sts.sticker = 'stickers'.id;";
-    else if (!strcasecmp(type, "plt"))
-        SQL =
-            "SELECT name, 'stickers.plt'.id, value "
-            "FROM 'stickers' "
-            "LEFT OUTER JOIN 'stickers' "
-            "ON 'stickers'.id = 'stickers.plt'.sticker;";
-    else if (!strcasecmp(type, "song"))
-        SQL =
-            "SELECT name, 'stickers.song'.id, value "
-            "FROM 'stickers' "
-            "LEFT OUTER JOIN 'stickers' "
-            "ON 'stickers'.id = 'stickers.song'.sticker;";
-    else {
-        LOG_ERROR_SCT("DB", "Type '%s' is invalid", type);
-        return false;
-    }
-
-    SQLITE_PREPARE(db, stmt, SQL, error);
-
-    for (;;) {
-        switch (sqlite3_step(stmt)) {
-        case SQLITE_ROW:
-            sticker = (const char *) sqlite3_column_text(stmt, 0);
-            uri     = sqlite3_column_int(stmt, 1);
-            value   = sqlite3_column_int(stmt, 2);
-            if (!call->call(call, sticker, type, uri, value))
-                goto end_loop;
-            continue;
-
-        case SQLITE_DONE:
-            goto end_loop;
-
-        default:
-            goto error;
-        }
-    }
-
-end_loop:
-    ret = true;
-error:
-    sqlite3_finalize(stmt);
-    return ret;
-}
-
 bool
 database_sticker_set(volatile sqlite3 *db, const char *type, const char *name, int uri, int value)
 {
@@ -146,58 +86,6 @@ error:
     return ret;
 }
 
-bool
-database_sticker_get(volatile sqlite3 *db, const char *type, const char *name, int uri, struct sticker_callback *call)
-{
-    const char *SQL = NULL;
-    sqlite3_stmt *stmt;
-    int ret = false, value;
-
-    if (!strcasecmp(type, "song"))
-        SQL =
-            "SELECT value "
-            "FROM 'stickers' "
-            "JOIN 'stickers.song'"
-            " ON 'stickers'.id = 'stickers.song'.sticker"
-            " AND 'stickers'.name = ?;\n";
-    else if (!strcasecmp(type, "plt"))
-        SQL =
-            "SELECT value "
-            "FROM 'stickers' "
-            "JOIN 'stickers.plt'"
-            " ON 'stickers'.id = 'stickers.plt'.sticker"
-            " AND 'stickers'.name = ?;\n";
-    else {
-        LOG_ERROR_SCT("DB", "Type '%s' is invalid", type);
-        return false;
-    }
-
-    SQLITE_PREPARE(db, stmt, SQL, error);
-    SQLITE_BIND_TEXT(db, stmt, 1, name, error);
-
-    for (;;) {
-        switch (sqlite3_step(stmt)) {
-        case SQLITE_ROW:
-            value = sqlite3_column_int(stmt, 1);
-            if (!call->call(call, name, type, uri, value))
-                goto end_loop;
-            continue;
-
-        case SQLITE_DONE:
-            goto end_loop;
-
-        default:
-            goto error;
-        }
-    }
-
-end_loop:
-    ret = true;
-error:
-    sqlite3_finalize(stmt);
-    return ret;
-}
-
 bool
 database_sticker_delete_specify(volatile sqlite3 *db, const char *type, int uri, const char *name)
 {
@@ -211,9 +99,8 @@ database_sticker_delete_specify(volatile sqlite3 *db, const char *type, int uri,
         return false;
     }
 
-    snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, "DELETE FROM 'stickers.%s' "
+    safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, "DELETE FROM 'stickers.%s' "
              "WHERE 'stickers.%s' = ? ", type, type);
-    SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
 
     /* If there is a name specified. */
     if (!name) {
diff --git a/src/database/update.c b/src/database/update.c
index cacb7badeb5217a6cf4aea91aaf457526981849d..145a60199a5eccdded3248c6c834ae3e27ab8145 100644
--- a/src/database/update.c
+++ b/src/database/update.c
@@ -27,7 +27,7 @@ database_add_kara(volatile sqlite3 *db, const char *filename)
     time_t the_time = time(NULL);
     struct tm *the_local_time = localtime(&the_time);
     char year[10];
-    code = snprintf(year, 10, "%d", the_local_time->tm_year + 1900);
+    code = safe_snprintf(year, 10, "%d", the_local_time->tm_year + 1900);
     RETURN_IF(code < 0 || code >= 10, "Failed to get the year of the current date", false);
 
     if (kara_metadata_read(&data, filename) != 0) {
@@ -89,7 +89,7 @@ database_update_add(volatile sqlite3 *db, const char *kara_path, struct kara_met
     time_t the_time = time(NULL);
     struct tm *the_local_time = localtime(&the_time);
     char year[10];
-    code = snprintf(year, 10, "%d", the_local_time->tm_year + 1900);
+    code = safe_snprintf(year, 10, "%d", the_local_time->tm_year + 1900);
     GOTO_IF(code < 0 || code >= 10, "Failed to get the year of the current date", error_no_sqlite);
 
     /* From here we initialize the sqlite stmt. */
@@ -146,8 +146,8 @@ database_update(volatile sqlite3 *db, const char *kara_dir)
         }
 
         else if (dir->d_type == DT_DIR          &&
-                 strcmp(dir->d_name, ".")  != 0 &&
-                 strcmp(dir->d_name, "..") != 0)
+                 !STR_MATCH(dir->d_name, ".")   &&
+                 !STR_MATCH(dir->d_name, ".."))
             database_update(db, path);
     }
 
diff --git a/src/main/lkt.c b/src/main/lkt.c
index ea03894d8bd2574d6c0eb9acca7b65c1d0bafae6..87282296a414035f9f0bcbd0674441680e2e2348 100644
--- a/src/main/lkt.c
+++ b/src/main/lkt.c
@@ -26,8 +26,6 @@
 #include <limits.h>
 
 #define LKT_KEY_VALUE_SEP               ": \n\t\0"
-#define STR_MATCH(str1, str2)           (! strcasecmp(str1, str2))
-#define STR_NMATCH(str1, str2, n)       (! strncasecmp(str1, str2, n))
 #define fail_if(cond, msg)              { if (cond) { LOG_ERROR("%s", msg); exit(EXIT_FAILURE); } }
 #define fail(msg)                       { LOG_ERROR("%s", msg); exit(EXIT_FAILURE); }
 #define lkt_send_and_exit(buffer, len)  exit(write_socket(lkt_connect(), buffer, len))
@@ -61,19 +59,14 @@ static const char *LKT_QUEUE_DEFAULT[] = { "10" };
 static int
 lkt_valid_type(const char *type)
 {
-    return (STR_MATCH(type, "all")      ||
-            STR_MATCH(type, "any")      ||
-            STR_MATCH(type, "query")    ||
+    return (STR_MATCH(type, "all") || STR_MATCH(type, "any") || STR_MATCH(type, "query")    ||
+            STR_MATCH(type, "cat") || STR_MATCH(type, "category")                           ||
+            STR_MATCH(type, "author") || STR_MATCH(type, "auth")                            ||
+            STR_MATCH(type, "lang") || STR_MATCH(type, "language")                          ||
             STR_MATCH(type, "id")       ||
             STR_MATCH(type, "title")    ||
             STR_MATCH(type, "type")     ||
-            STR_MATCH(type, "cat")      ||
-            STR_MATCH(type, "category") ||
-            STR_MATCH(type, "author")   ||
-            STR_MATCH(type, "auth")     ||
-            STR_MATCH(type, "source")   ||
-            STR_MATCH(type, "lang")     ||
-            STR_MATCH(type, "language"));
+            STR_MATCH(type, "source"));
 }
 
 static int
@@ -82,7 +75,6 @@ read_socket(FILE *sock, char *buff, size_t max_len)
     size_t i, len;
     for (i = 0; i < max_len; ++i) {
         len = fread(buff + i, sizeof(char), 1, sock);
-
         if (buff[i] == '\n' || len != 1)
             return i;
     }
@@ -136,8 +128,8 @@ create_socket(const char *host, const char *port)
     if (cx <= 0 || connect(cx, &sock, sock_len))
         exit(EXIT_FAILURE);
 
-    assert(socket_desc = fdopen(cx, "r+"));
-
+    socket_desc = fdopen(cx, "r+");
+    fail_if(!socket_desc, "Failed to connect to lektord");
     return socket_desc;
 }
 
@@ -150,8 +142,7 @@ lkt_connect(void)
     FILE *sock = create_socket(host, port);
     recv_len = read_socket(sock, buff, LKT_MESSAGE_MAX);
 
-    assert(recv_len > 0);
-
+    fail_if(recv_len == 0, "Failed to connect to lektord");
     return sock;
 }
 
@@ -164,6 +155,20 @@ lkt_skip_key(char *buffer)
     return ret + len;
 }
 
+static inline void
+send_cmd_with_uri(FILE *sock, char *cmd, int argc, const char **argv)
+{
+    int i;
+    char buf[LKT_MESSAGE_MAX] = {0};
+    for (i = 1; i < argc - 1; ++i) {
+        strncat(buf, argv[i], LKT_MESSAGE_MAX - 1);
+        strncat(buf, " ", LKT_MESSAGE_MAX - 1);
+    }
+    strncat(buf, argv[i], LKT_MESSAGE_MAX - 1);
+    strncat(buf, "\n", LKT_MESSAGE_MAX - 1);
+    (void) write_socket_format(sock, "%s %s://%s", cmd, argv[0], buf);
+}
+
 /* Functions implementing options. */
 
 #define just_send(func, msg) /* Just send a simple string functions */  \
@@ -299,7 +304,7 @@ ping__(struct lkt_cmd_args *args)
         fail("Failed to send the ping to lektord");
     if (read_socket(sock, buff, 6 * sizeof(char)) <= 0)
         fail("Failed to recieve the response of lektord");
-    if (strncmp(buff, "OK", 2))
+    if (!STR_NMATCH(buff, "OK", 2))
         fail("ACK");
     write(1, "OK\n", sizeof("OK\n"));
     exit(EXIT_SUCCESS);
@@ -378,7 +383,7 @@ ok:
 noreturn void
 queue_pop__(struct lkt_cmd_args *args)
 {
-    fail_if(!args->argc, "Invalid argument");
+    fail_if(args->argc, "Invalid argument");
     int songid = 0;
     char buff[LKT_MESSAGE_MAX];
     FILE *sock = lkt_connect();
@@ -388,7 +393,7 @@ queue_pop__(struct lkt_cmd_args *args)
     if (write_socket(sock, "status\n", sizeof("status\n")))
         goto error;
 
-#define assign_int(str, var) if (! strncmp(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; }
+#define assign_int(str, var) if (STR_NMATCH(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; }
     for (;;) {
         memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char));
         if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0)
@@ -409,7 +414,8 @@ queue_pop__(struct lkt_cmd_args *args)
     sock = lkt_connect();
     if (!songid)
         goto error;
-    exit(write_socket_format(sock, "next\ndeleteid %d\n", songid));
+    write_socket_format(sock, "next\ndeleteid %d\n", songid);
+    exit_with_status(sock, buff);
 error:
     exit(EXIT_FAILURE);
 }
@@ -448,8 +454,8 @@ status__(struct lkt_cmd_args *args)
 
         if (STR_NMATCH(buff, "state", len)) {
             char *it = lkt_skip_key(buff);
-            play = ! strncmp(it, "play", 4);
-            stopped = ! strncmp(it, "stop", 4);
+            play = STR_NMATCH(it, "play", 4);
+            stopped = STR_NMATCH(it, "stop", 4);
             continue;
         }
 
@@ -511,20 +517,6 @@ queue_delete__(struct lkt_cmd_args *args)
     fail("Invalid argument");
 }
 
-static inline void
-send_cmd_with_uri(FILE *sock, char *cmd, int argc, const char **argv)
-{
-    int i;
-    char buf[LKT_MESSAGE_MAX] = {0};
-    for (i = 1; i < argc - 1; ++i) {
-        strncat(buf, argv[i], LKT_MESSAGE_MAX - 1);
-        strncat(buf, " ", LKT_MESSAGE_MAX - 1);
-    }
-    strncat(buf, argv[i], LKT_MESSAGE_MAX - 1);
-    strncat(buf, "\n", LKT_MESSAGE_MAX - 1);
-    (void) write_socket_format(sock, "%s %s://%s", cmd, argv[0], buf);
-}
-
 noreturn void
 queue_add__(struct lkt_cmd_args *args)
 {
@@ -601,7 +593,7 @@ redo:
         memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char));
         assert(read_socket(sock, buff, LKT_MESSAGE_MAX - 1) > 0);
 
-        if (! strncmp(buff, "continue:", strlen("continue:"))) {
+        if (STR_NMATCH(buff, "continue:", strlen("continue:"))) {
             continuation = atoi(lkt_skip_key(buff));
             if (continuation > 0) {
                 fclose(sock);
@@ -646,7 +638,7 @@ queue_list__(struct lkt_cmd_args *args)
     if (write_socket(sock, "status\n", sizeof("status\n")))
         fail("Communication error");
 
-#define assign_int(str, var) if (! strncmp(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; }
+#define assign_int(str, var) if (STR_NMATCH(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; }
     for (;;) {
         memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char));
         if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0)
@@ -668,8 +660,7 @@ queue_list__(struct lkt_cmd_args *args)
 
     continuation = labs(continuation);
     song_index = MAX(song_index + 1, 1);
-    snprintf(buff, LKT_MESSAGE_MAX - 1, "%ld:%ld", song_index, song_index + continuation - 1);
-    buff[LKT_MESSAGE_MAX - 1] = '\0';
+    safe_snprintf(buff, LKT_MESSAGE_MAX, "%ld:%ld", song_index, song_index + continuation - 1);
     args->argc = 1;
     args->argv[0] = buff;
     queue_pos__(args);
@@ -680,27 +671,11 @@ queue_list__(struct lkt_cmd_args *args)
 noreturn void
 plt_add__(struct lkt_cmd_args *args)
 {
-    int i;
     char buff[2];
     FILE *sock = lkt_connect();
-
     fail_if(args->argc < 3,                 "Invalid argument, need at least three arguments: plt add <plt> <query>");
     fail_if(!lkt_valid_type(args->argv[1]), "Invalid argument, type for the query is invalid");
-
-    (void) write_socket(sock, "playlistadd ", strlen("playlistadd "));
-    (void) write_socket(sock, args->argv[0], strlen(args->argv[0]));
-    (void) write_socket(sock, " ", sizeof(char));
-    (void) write_socket(sock, args->argv[1], strlen(args->argv[1]));
-    (void) write_socket(sock, "://", 3 * sizeof(char));
-
-    for (i = 2; i < args->argc - 1; ++i) {
-        (void) write_socket(sock, args->argv[i], strlen(args->argv[i]));
-        (void) write_socket(sock, " ", sizeof(char));
-    }
-
-    /* Here we have `i == argc - 1`. */
-    (void) write_socket(sock, args->argv[i], strlen(args->argv[i]));
-    (void) write_socket(sock, "\n", sizeof(char));
+    send_cmd_with_uri(sock, "playlistadd", args->argc, args->argv);
     exit_with_status(sock, buff);
 }
 
@@ -709,22 +684,8 @@ plt_delete__(struct lkt_cmd_args *args)
 {
     FILE *sock = lkt_connect();
     char buff[2];
-    int i;
-
     fail_if(args->argc < 1, "Invalid argument");
-
-    (void) write_socket(sock, "playlistdelete ", strlen("playlistdelete "));
-    (void) write_socket(sock, args->argv[0], strlen(args->argv[0]));
-    (void) write_socket(sock, " ", sizeof(char));
-
-    for (i = 1; i < args->argc - 1; ++i) {
-        (void) write_socket(sock, args->argv[i], strlen(args->argv[i]));
-        (void) write_socket(sock, " ", sizeof(char));
-    }
-
-    /* Here we have `i == argc - 1`. */
-    (void) write_socket(sock, args->argv[i], strlen(args->argv[i]));
-    (void) write_socket(sock, "\n", sizeof(char));
+    send_cmd_with_uri(sock, "playlistdelete", args->argc, args->argv);
     exit_with_status(sock, buff);
 }
 
@@ -732,14 +693,9 @@ noreturn void
 plt_destroy__(struct lkt_cmd_args *args)
 {
     fail_if(args->argc != 1, "Invalid argument");
-
     FILE *sock = lkt_connect();
     char buff[2];
-    const char *name = args->argv[0];
-
-    (void) write_socket(sock, "rm ", 3 * sizeof(char));
-    (void) write_socket(sock, name, strlen(name));
-    (void) write_socket(sock, "\n", sizeof(char));
+    write_socket_format(sock, "rm %s\n", args->argv[0]);
     exit_with_status(sock, buff);
 }
 
@@ -750,11 +706,7 @@ plt_create__(struct lkt_cmd_args *args)
 
     FILE *sock = lkt_connect();
     char buff[2];
-    const char *name = args->argv[0];
-
-    (void) write_socket(sock, "playlistadd ", strlen("playlistadd "));
-    (void) write_socket(sock, name, strlen(name));
-    (void) write_socket(sock, "\n", sizeof(char));
+    write_socket_format(sock, "playlistadd %s\n", args->argv[0]);
     exit_with_status(sock, buff);
 }
 
@@ -916,16 +868,12 @@ parse_args(args_t *args, int argc, const char **argv)
     args->argc = argc - (got + 1);
 }
 
-/* Functions that make a command happen on lektor. */
-
-/* Playlist functions. */
-
 int
 main(int argc, const char **argv)
 {
     executable_name = "lkt";
-    assert(NULL != setlocale(LC_ALL, "en_US.UTF-8"));   /* BECAUSE!         */
-    assert(!signal(SIGPIPE, sigpipe__));                /* Argument checks. */
+    assert(NULL != setlocale(LC_ALL, "en_US.UTF-8"));   /* BECAUSE! */
+    assert(!signal(SIGPIPE, sigpipe__));
 
     args_t args = {
         .host = "localhost",
diff --git a/src/mkv/mkv.c b/src/mkv/mkv.c
index a62d536f4603c6a1e8d5c0fce12c0383e53cb0c6..fe1b6fff80086c99968c79fb866793a318fc5800 100644
--- a/src/mkv/mkv.c
+++ b/src/mkv/mkv.c
@@ -5,6 +5,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
 
 #include <lektor/bufferfd.h>
@@ -431,20 +432,20 @@ static void
 kara_add_simple_tag(struct kara_metadata *dst, struct mkv_simple_tag *t,
                     uint64_t target_type_value)
 {
-    if (!strcmp("TITLE", t->name)) {
+    if (STR_MATCH("TITLE", t->name)) {
         if (target_type_value == 50)
             strncpy(dst->song_name, t->value, LEKTOR_TAG_MAX - 1);
         else if (target_type_value == 70)
             strncpy(dst->source_name, t->value, LEKTOR_TAG_MAX - 1);
-    } else if (!strcmp("CONTENT_TYPE", t->name))
+    } else if (STR_MATCH("CONTENT_TYPE", t->name))
         strncpy(dst->category, t->value, LEKTOR_TAG_MAX - 1);
-    else if (!strcmp("ADDRESS", t->name))
+    else if (STR_MATCH("ADDRESS", t->name))
         strncpy(dst->language, t->value, LEKTOR_TAG_MAX - 1);
-    else if (!strcmp("ARTIST", t->name))
+    else if (STR_MATCH("ARTIST", t->name))
         strncpy(dst->author_name, t->value, LEKTOR_TAG_MAX - 1);
-    else if (!strcmp("GENRE", t->name))
+    else if (STR_MATCH("GENRE", t->name))
         strncpy(dst->song_type, t->value, LEKTOR_TAG_MAX - 1);
-    else if (!strcmp("TRACK", t->name))
+    else if (STR_MATCH("TRACK", t->name))
         dst->song_number = (int) strtol(t->value, NULL, 10);
 }
 
diff --git a/src/mkv/write.c b/src/mkv/write.c
index c5caa8c0d45cef00fcfa3e4dc6f709487b249051..d366c6bf3dc86999c5bba1357d72b5e771efb711 100644
--- a/src/mkv/write.c
+++ b/src/mkv/write.c
@@ -3,6 +3,7 @@
 
 #include <common/common.h>
 #include <lektor/mkv.h>
+#include <strings.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -204,13 +205,13 @@ metadata_set_directory(const char *kara_dir, const char *mkvpropedit)
         strncat(path, "/", PATH_MAX - 1);
         strncat(path, dir->d_name, PATH_MAX - 1);
 
-        if (dir->d_type == DT_REG &&
-            metadata_from_path(path, &meta) &&
+        if (dir->d_type == DT_REG               &&
+            metadata_from_path(path, &meta)     &&
             kara_metadata_write(&meta, path, mkvpropedit))
             continue;
-        else if (dir->d_type == DT_DIR &&
-                 strcmp(dir->d_name, ".") != 0 &&
-                 strcmp(dir->d_name, "..") != 0)
+        else if (dir->d_type == DT_DIR          &&
+                 !STR_MATCH(dir->d_name, ".")   &&
+                 !STR_MATCH(dir->d_name, ".."))
             metadata_set_directory(path, mkvpropedit);
     }
 
diff --git a/src/module/mpv.c b/src/module/mpv.c
index b29d71532d5f98becd77e64223070b5c23a43d83..3f101b9c51be6406f9bad78df40378080753b13c 100644
--- a/src/module/mpv.c
+++ b/src/module/mpv.c
@@ -4,6 +4,7 @@
 #include <lektor/module/mpv.h>
 #include <lektor/commands.h>
 #include <lektor/database.h>
+#include <strings.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
@@ -88,7 +89,7 @@ lmpv_set_volume(mpv_handle *ctx, int vol)
     int status;
     char str[5];
     memset(str, 0, 5);
-    snprintf(str, 4, "%d", vol);
+    safe_snprintf(str, 4, "%d", vol);
     const char *cmd[] = {"set", "ao-volume", str, NULL};
     if ((status = mpv_command_async(ctx, 0, cmd)) < 0) {
         LOG_ERROR_SCT("WINDOW", "Failed to execute command: %s", mpv_error_string(status));
@@ -162,24 +163,24 @@ loop:
         if (prop->format == MPV_FORMAT_NONE)
             break;
         // MPV volume (BUG: The flag is not MPV_FORMAT_NONE only at the end of the song...) //
-        if (!strcmp(prop->name, "ao-volume")
+        if (STR_MATCH(prop->name, "ao-volume")
             && prop->format == MPV_FORMAT_INT64) {
             ao_volume = *(int *) prop->data;
             database_config_queue(db, "volume", ao_volume);
         }
         // File duration //
-        if (!strcmp(prop->name, "duration")
+        if (STR_MATCH(prop->name, "duration")
             && prop->format == MPV_FORMAT_INT64) {
             *time_duration = *(int *) prop->data;
             database_config_queue(db, "duration", *(int *) prop->data);
         }
-        if (!strcmp(prop->name, "time-pos")
+        if (STR_MATCH(prop->name, "time-pos")
             && prop->format == MPV_FORMAT_INT64) {
             *time_pos = *(int *) prop->data;
             database_config_queue(db, "elapsed", *(int *) prop->data);
         }
         // Pause state //
-        if (!strcmp(prop->name, "pause")
+        if (STR_MATCH(prop->name, "pause")
             && prop->format == MPV_FORMAT_FLAG)
             database_queue_set_paused(db, *(bool *) prop->data);
         break;
diff --git a/src/net/downloader.c b/src/net/downloader.c
index 9df9b1bae07918d97f759d4c2c93d74336d46c0e..9645a50b446424eccad001a8fae29b33cb9841e7 100644
--- a/src/net/downloader.c
+++ b/src/net/downloader.c
@@ -184,8 +184,7 @@ repo_get_id(struct lkt_repo *const repo, const uint64_t id, struct kara_metadata
     };
 
     memset(url, 0, URL_MAX_LEN * sizeof(char));
-    snprintf(url, URL_MAX_LEN - 1, repo->get_id_json, id);
-    url[URL_MAX_LEN - 1] = 0;
+    safe_snprintf(url, URL_MAX_LEN, repo->get_id_json, id);
     curl_handle = curl_easy_init();
     curl_easy_setopt(curl_handle, CURLOPT_URL, url);
     curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_mem__);
@@ -315,8 +314,7 @@ repo_download_id_sync(struct lkt_repo *const repo, const uint64_t id, const char
     }
 
     memset(url, 0, URL_MAX_LEN * sizeof(char));
-    snprintf(url, URL_MAX_LEN - 1, repo->get_id_file, id);
-    url[URL_MAX_LEN - 1] = 0;
+    safe_snprintf(url, URL_MAX_LEN, repo->get_id_file, id);
 
     if (__download_kara(url, kara_path, false)) {
         LOG_ERROR_SCT("REPO", "Failed to download kara '%s' with url '%s'", kara_path, url);
@@ -363,8 +361,7 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec
             strncat(kara->filename, "/", PATH_MAX - 1);
             kara->filename[++kara_dir_len] = 0;
         }
-        snprintf(kara->filename + kara_dir_len, PATH_MAX - kara_dir_len, "%d.mkv", integer);
-        kara->filename[PATH_MAX - 1] = 0;
+        safe_snprintf(kara->filename + kara_dir_len, PATH_MAX - kara_dir_len, "%d.mkv", integer);
         LOG_INFO_SCT("REPO", "Crafted filename is '%s'", kara->filename);
 
         /* Timestamp verification */
@@ -397,8 +394,7 @@ do_it:
             continue;
         }
 
-        snprintf(url, URL_MAX_LEN - 1, repo->get_id_file, kara->id);
-        url[URL_MAX_LEN - 1] = '\0';
+        safe_snprintf(url, URL_MAX_LEN, repo->get_id_file, kara->id);
 
         if (__download_kara(url, kara->filename, true)) {
             LOG_WARN_SCT("REPO", "Could not download kara %ld at path '%s'", kara->id, kara->filename);
diff --git a/src/net/listen.c b/src/net/listen.c
index 0aa570f4ab740bf10aa4c14bf05b84976c4a90cb..84ec3db308ef37eaa5a69c25adb0c7eca123369e 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -7,6 +7,7 @@
 
 #include <sqlite3.h>
 
+#include <strings.h>
 #include <sched.h>
 #include <assert.h>
 #include <arpa/inet.h>
@@ -85,8 +86,7 @@ static inline void
 send_continue(struct lkt_state *srv, size_t c, int i)
 {
     struct lkt_message *cont = lkt_message_new();
-    cont->data_len = snprintf(cont->data, LKT_MESSAGE_MAX, "continue: %d\n", i);
-    cont->data[LKT_MESSAGE_MAX - 1] = '\0';
+    cont->data_len = safe_snprintf(cont->data, LKT_MESSAGE_MAX, "continue: %d\n", i);
     lkt_state_send(srv, c, cont);
 }
 
@@ -151,111 +151,111 @@ 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 requires authentification. */
-        if (!strcmp(cmd.name, "__adduser"))
+        if (STR_MATCH(cmd.name, "__adduser"))
             err = ! command_user_add(srv, c, (sqlite3 *) srv->db, cmd.args);
-        else if (!strcmp(cmd.name, "__restart"))
+        else if (STR_MATCH(cmd.name, "__restart"))
             err = ! command_restart(srv, c);
-        else if (!strcmp(cmd.name, "kill"))
+        else if (STR_MATCH(cmd.name, "kill"))
             err = ! command_kill(srv, c);
-        else if (!strcmp(cmd.name, "update"))
+        else if (STR_MATCH(cmd.name, "update"))
             err = ! command_update(srv, c, cmd.args);
-        else if (!strcmp(cmd.name, "rescan"))
+        else if (STR_MATCH(cmd.name, "rescan"))
             err = ! command_rescan(srv, c, cmd.args);
 
         /* Commands that are available if not in idle mode */
-        else if (!strcmp(cmd.name, "currentsong"))
+        else if (STR_MATCH(cmd.name, "currentsong"))
             err = !command_currentsong(srv, c);
-        else if (!strcmp(cmd.name, "status"))
+        else if (STR_MATCH(cmd.name, "status"))
             err = !command_status(srv, c);
 
-        else if (!strcmp(cmd.name, "close"))
+        else if (STR_MATCH(cmd.name, "close"))
             err = !lkt_close_client(srv, c);
-        else if (!strcmp(cmd.name, "ping"))
+        else if (STR_MATCH(cmd.name, "ping"))
             err = 0;
 
-        else if (!strcmp(cmd.name, "next"))
+        else if (STR_MATCH(cmd.name, "next"))
             err = !command_next((sqlite3 *) srv->db, &srv->win, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "pause"))
+        else if (STR_MATCH(cmd.name, "pause"))
             err = !command_pause((sqlite3 *) srv->db, &srv->win, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "previous"))
+        else if (STR_MATCH(cmd.name, "previous"))
             err = !command_previous((sqlite3 *) srv->db, &srv->win, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "play"))
+        else if (STR_MATCH(cmd.name, "play"))
             err = ! command_play((sqlite3 *) srv->db, &srv->win, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "playid"))
+        else if (STR_MATCH(cmd.name, "playid"))
             err = ! command_playid((sqlite3 *) srv->db, &srv->win, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "stop"))
+        else if (STR_MATCH(cmd.name, "stop"))
             err = !command_stop((sqlite3 *) srv->db, &srv->win, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "clear"))
+        else if (STR_MATCH(cmd.name, "clear"))
             err = !command_clear((sqlite3 *) srv->db, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "crop"))
+        else if (STR_MATCH(cmd.name, "crop"))
             err = !command_crop((sqlite3 *) srv->db, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "moveid"))
+        else if (STR_MATCH(cmd.name, "moveid"))
             err = !command_move((sqlite3 *) srv->db, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "shuffle"))
+        else if (STR_MATCH(cmd.name, "shuffle"))
             err = !command_shuffle((sqlite3 *) srv->db, &srv->mpd_idle_events);
 
-        else if (!strcmp(cmd.name, "playlist") || !strcmp(cmd.name, "playlistinfo"))
+        else if (STR_MATCH(cmd.name, "playlist") || STR_MATCH(cmd.name, "playlistinfo"))
             err = !command_queue_list(srv, c, cmd.args);
-        else if (!strcmp(cmd.name, "playlistfind") || !strcmp(cmd.name, "playlistsearch"))
+        else if (STR_MATCH(cmd.name, "playlistfind") || STR_MATCH(cmd.name, "playlistsearch"))
             err = ! command_find(srv, c, cmd.args, cmd.cont, database_search_queue_init);
 
-        else if (!strcmp(cmd.name, "sticker") && cmd.args[0]) {
-            if (!strcmp(cmd.args[0], "get"))
+        else if (STR_MATCH(cmd.name, "sticker") && cmd.args[0]) {
+            if (STR_MATCH(cmd.args[0], "get"))
                 err = ! command_sticker_get(srv, c, &cmd.args[1]);
-            else if (!strcmp(cmd.args[0], "set"))
+            else if (STR_MATCH(cmd.args[0], "set"))
                 err = ! command_sticker_set(srv, c, &cmd.args[1]);
-            else if (!strcmp(cmd.args[0], "delete"))
+            else if (STR_MATCH(cmd.args[0], "delete"))
                 err = ! command_sticker_delete(srv, c, &cmd.args[1]);
-            else if (!strcmp(cmd.args[0], "list") || !strcmp(cmd.args[0], "find"))
+            else if (STR_MATCH(cmd.args[0], "list") || STR_MATCH(cmd.args[0], "find"))
                 err = ! command_sticker_delete(srv, c, &cmd.args[1]);
         }
 
-        else if (!strcmp(cmd.name, "help"))
+        else if (STR_MATCH(cmd.name, "help"))
             err = !command_help(srv, c);
 
-        else if (!strcmp(cmd.name, "__insert"))
+        else if (STR_MATCH(cmd.name, "__insert"))
             err = !command_add((sqlite3 *) srv->db, &srv->win, cmd.args, &srv->mpd_idle_events, 5);
-        else if (!strcmp(cmd.name, "searchadd") || !strcmp(cmd.name, "findadd") || !strcmp(cmd.name, "add"))
+        else if (STR_MATCH(cmd.name, "searchadd") || STR_MATCH(cmd.name, "findadd") || STR_MATCH(cmd.name, "add"))
             err = !command_add((sqlite3 *) srv->db, &srv->win, cmd.args, &srv->mpd_idle_events, 1);
-        else if (!strcmp(cmd.name, "addid"))
+        else if (STR_MATCH(cmd.name, "addid"))
             err = !command_addid((sqlite3 *) srv->db, &srv->win, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "deleteid"))
+        else if (STR_MATCH(cmd.name, "deleteid"))
             err = ! (cmd.args[0] != NULL &&
                      command_delid((sqlite3 *) srv->db, &srv->win, cmd.args[0], &srv->mpd_idle_events));
 
-        else if (!strcmp(cmd.name, "playlistclear"))
+        else if (STR_MATCH(cmd.name, "playlistclear"))
             err = ! command_plt_clear((sqlite3 *) srv->db, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "rename"))
+        else if (STR_MATCH(cmd.name, "rename"))
             err = ! command_plt_rename((sqlite3 * ) srv->db, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "playlistdelete"))
+        else if (STR_MATCH(cmd.name, "playlistdelete"))
             err = ! command_plt_remove((sqlite3 *) srv->db, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "playlistadd"))
+        else if (STR_MATCH(cmd.name, "playlistadd"))
             err = ! command_plt_add((sqlite3 *) srv->db, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "rm") && cmd.args[0] != NULL && cmd.args[1] == NULL)
+        else if (STR_MATCH(cmd.name, "rm") && cmd.args[0] != NULL && cmd.args[1] == NULL)
             err = ! command_plt_remove((sqlite3 *) srv->db, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "save"))
+        else if (STR_MATCH(cmd.name, "save"))
             err = ! command_plt_export((sqlite3 *) srv->db, cmd.args, &srv->mpd_idle_events);
-        else if (!strcmp(cmd.name, "__import"))
+        else if (STR_MATCH(cmd.name, "__import"))
             err = ! command_plt_import((sqlite3 *) srv->db, cmd.args, &srv->mpd_idle_events);
 
-        else if (!strcmp(cmd.name, "random"))
+        else if (STR_MATCH(cmd.name, "random"))
             err = !command_set_playback_option(srv, c, lkt_playback_option_random, cmd.args);
-        else if (!strcmp(cmd.name, "repeat"))
+        else if (STR_MATCH(cmd.name, "repeat"))
             err = !command_set_playback_option(srv, c, lkt_playback_option_repeat, cmd.args);
-        else if (!strcmp(cmd.name, "setvol"))
+        else if (STR_MATCH(cmd.name, "setvol"))
             err = !command_set_playback_option(srv, c, lkt_playback_option_volume, cmd.args);
-        else if (!strcmp(cmd.name, "single"))
+        else if (STR_MATCH(cmd.name, "single"))
             err = !command_set_playback_option(srv, c, lkt_playback_option_single, cmd.args);
-        else if (!strcmp(cmd.name, "consume"))
+        else if (STR_MATCH(cmd.name, "consume"))
             err = !command_set_playback_option(srv, c, lkt_playback_option_consume, cmd.args);
 
-        else if (!strcmp(cmd.name, "password"))
+        else if (STR_MATCH(cmd.name, "password"))
             err = !command_password(srv, c, cmd.args);
 
-        else if (!strcmp(cmd.name, "idle")) {
+        else if (STR_MATCH(cmd.name, "idle")) {
             err = !command_idle(srv, c, &cmd);
             goto end_no_send_status;
-        } else if (!strcmp(cmd.name, "search") || !strcmp(cmd.name, "find"))
+        } else if (STR_MATCH(cmd.name, "search") || STR_MATCH(cmd.name, "find"))
             err = ! command_find(srv, c, cmd.args, cmd.cont, database_search_database_init);
         else
             err = 2;
@@ -264,10 +264,10 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
 
     default:
         /* commands available only in idle mode */
-        if (!strcmp(cmd.name, "idle")) {
+        if (STR_MATCH(cmd.name, "idle")) {
             err = !command_idle(srv, c, &cmd);
             goto end_no_send_status;
-        } else if (!strcmp(cmd.name, "noidle"))
+        } else if (STR_MATCH(cmd.name, "noidle"))
             err = !command_noidle(srv, c);
         else
             err = 2;
@@ -314,11 +314,11 @@ handle_command(struct lkt_state *srv, size_t i, struct lkt_command cmd)
     struct lkt_client *cli = &srv->clients[i - 1];
     int err = 0;
 
-    if (!strcmp(cmd.name, "command_list_begin"))
+    if (STR_MATCH(cmd.name, "command_list_begin"))
         err = command_list_begin(srv, i, 0);
-    else if (!strcmp(cmd.name, "command_list_ok_begin"))
+    else if (STR_MATCH(cmd.name, "command_list_ok_begin"))
         err = command_list_begin(srv, i, 1);
-    else if (!strcmp(cmd.name, "command_list_end"))
+    else if (STR_MATCH(cmd.name, "command_list_end"))
         err = command_list_end(srv, i);
     else if (cli->command_list_mode != LKT_COMMAND_LIST_OFF)
         cli->command_list[cli->command_list_len++] = lkt_command_clone(&cmd);
diff --git a/src/uri.c b/src/uri.c
index ec076ed25e67e30fc1eeb8418efffa51107092f7..4f6fe5690d2946c4e7fbe9e2a9e9f21c7ea1ea0f 100644
--- a/src/uri.c
+++ b/src/uri.c
@@ -98,19 +98,19 @@ __lkt_to_str(struct lkt_uri *uri, char *ret, size_t len)
 {
     switch (uri->type) {
     case uri_id:
-        snprintf(ret, len - 1, "id=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "id=%s", (char *) uri->value);
         break;
     case uri_type:
-        snprintf(ret, len - 1, "type=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "type=%s", (char *) uri->value);
         break;
     case uri_author:
-        snprintf(ret, len - 1, "author=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "author=%s", (char *) uri->value);
         break;
     case uri_category:
-        snprintf(ret, len - 1, "cat=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "cat=%s", (char *) uri->value);
         break;
     case uri_query:
-        snprintf(ret, len - 1, "search=%s", (char *) uri->value);
+        safe_snprintf(ret, len, "search=%s", (char *) uri->value);
         break;
     default:
         LOG_ERROR("URI type %d may not be supported by kurisu, generate an error", uri->type);