diff --git a/README.md b/README.md index 6e55ce985d0209de9df78ce5fd09d9c48aea3647..8008095b418f4c4d55f58b325bd62ff0a0deba27 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,10 @@ Prerequisites: - the [json-c](https://github.com/json-c/json-c) development library - a POSIX.1-2008 compatible system (i.e. not MS Windows) -For the module x11, you will need the folowing prerequisites: +For the module x11 and sdl2, you will need the folowing prerequisites: - the [mpv](https://mpv.io/) development library +- the [sdl2](https://www.libsdl.org/) development library - you will need `x11` for the default window module You will also need the following executables, with their path setted in the @@ -43,6 +44,12 @@ You may need to put the `lib_window_x11.so` in the right directory to have the lektor player actually playing something (see the ini file). This path can be setted manually in the INI file. +On archlinux, you need only to install the package: + +```sh +makepkg -si +``` + ## Preparing a kara for lektor A karamaker needs at least python3, with `mkvpropedit` (often installed with the diff --git a/doc/lkt.1 b/doc/lkt.1 index 73c36811edd4d8ab56b7b51d306c3c4f0fd5fdb1..069f193d18d2bfe32808fe3d6f7ab3e240c0ec79 100644 --- a/doc/lkt.1 +++ b/doc/lkt.1 @@ -134,13 +134,17 @@ Search in the queue and prints the karas that match the query .PD 0 .TP .PD +\fBsticker create\fP <name> +Create a sticker that can be used to tag \fIkara\fP and \fIplt\fP objects +.TP \fBsticker get\fP <type> <uri> [ <name> [ <op> <value> ] ] List the stickers of an object \fIuri\fP. The object \fItype\fP can be \fIkara\fP or \fIplt\fP. A condition can be defined on the value of the sticker with an operator -\fIop\fP and an integer value \fIvalue\fP. Supported operators are \fI<\fP, -\fI=\fP and \fI>\fP. Operations are not strict. +\fIop\fP and an integer value \fIvalue\fP. Supported operators are \fIl\fP +for 'less than', \fIe\fP for 'equal to' and \fIg\fP for 'greater than'. +Operations are not strict. .TP \fBsticker set\fP <type> <uri> <name> <value> Set the value of a sticker \fIname\fP to \fIvalue\fP for the object with the @@ -149,12 +153,6 @@ id \fIuri\fP \fBsticker delete\fP <type> <uri> [name] Delete all the stickers or only one (specified by \fIname\fP) of the object with the id \fIuri\fP -.TP -\fBksticker\fP ... -An alias for the sticker commands with the type \fIkara\fP -.TP -\fBpsticker\fP ... -An alias for the sticker commands with the type \fIplt\fP .PP \fIADMIN-COMMANDS\fP diff --git a/inc/common/macro.h b/inc/common/macro.h index 3e220015527cf73428f3a5799b45d417e6c0b9e5..8b1b527e5c3c1f4460b5f478af963b791b52f3e4 100644 --- a/inc/common/macro.h +++ b/inc/common/macro.h @@ -161,7 +161,6 @@ typedef volatile enum { #define SQLITE_STEP_ROW(db, stmt, error) SQLITE_STEP(db, stmt, SQLITE_ROW, error) #define SQLITE_STEP_DONE(db, stmt, error) SQLITE_STEP(db, stmt, SQLITE_DONE, error) -#define SQLITE_STEP_OK(db, stmt, error) SQLITE_STEP(db, stmt, SQLITE_OK, error) #define SQLITE_DO_ROLLBACK(db) \ sqlite3_exec((sqlite3 *) db, "ROLLBACK TRANSACTION;\n", NULL, NULL, NULL); diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h index 53067fe5f6c6752625b7d1d1e0bc08dae8444828..9b18e0e9ca38c0781a55a07d16dae456cde2f4d7 100644 --- a/inc/lektor/commands.h +++ b/inc/lektor/commands.h @@ -86,7 +86,7 @@ bool command_update (struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARG bool command_rescan (struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]); /* Sticker management */ +bool command_sticker_create(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]); bool command_sticker_get (struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]); bool command_sticker_set (struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]); bool command_sticker_delete(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]); -bool command_sticker_list (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 c2d090799c38f9184c682abf0a28af80f9d4ec4a..b0383152b10acc95f9d82f029f2a74fafa7e6b47 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -50,6 +50,7 @@ bool database_update (volatile sqlite3 *db, const char *kara_dir, i bool database_update_add (volatile sqlite3 *db, const char *kara_path, struct kara_metadata *mdt, uint64_t id, bool avail); bool database_update_set_available(volatile sqlite3 *db, int id); void database_update_del (volatile sqlite3 *db, int id); +void database_update_touch (volatile sqlite3 *db, int id); /* Control the content of the queue. */ bool database_queue_add_uri(volatile sqlite3 *db, struct lkt_uri *uri, int priority); diff --git a/meson.build b/meson.build index 70e40f579baf6f0bedd218cbe01c12329e5c36e3..caaaf1bb6d5337f0cfe0596cca81bd061280b7d2 100644 --- a/meson.build +++ b/meson.build @@ -82,20 +82,21 @@ mthread_deps = [ declare_dependency( link_with: static_library( 'mthread' , include_directories: includes , dependencies: [ common_deps ] ) ] -generated_deps = [ declare_dependency( link_with: static_library( 'generated' - , [ custom_target( 'sqlinit' - , output: 'sqlinit.c' - , input: 'src/database/disk.sql' - , command: [ find_program('xxd'), '-i', '@INPUT@', '@OUTPUT@' ] ) ] - , [ custom_target( 'sqlmemory' - , output: 'sqlmemory.c' - , input: 'src/database/memory.sql' - , command: [ find_program('xxd'), '-i', '@INPUT@', '@OUTPUT@' ] ) ] - , [ custom_target( 'manpath' - , output: 'manpath.c' - , input: 'meson.build' - , command: [ find_program('sh'), '-c', 'echo \'const char *man_executable_path = "\'"$(which man)"\'";\' > @OUTPUT@' ] ) ] ) - ) ] +generated_deps = [ declare_dependency( + link_with: static_library( 'generated' + , [ custom_target( 'sqlinit' + , output: 'sqlinit.c' + , input: 'src/database/disk.sql' + , command: [ find_program('xxd'), '-i', '@INPUT@', '@OUTPUT@' ] ) ] + , [ custom_target( 'sqlmemory' + , output: 'sqlmemory.c' + , input: 'src/database/memory.sql' + , command: [ find_program('xxd'), '-i', '@INPUT@', '@OUTPUT@' ] ) ] + , [ custom_target( 'manpath' + , output: 'manpath.c' + , input: 'meson.build' + , command: [ find_program('sh'), '-c', 'echo \'const char *man_executable_path = "\'"$(which man)"\'";\' > @OUTPUT@' ] ) ] ) + ) ] lib = static_library( 'lektor' , files(core_sources) diff --git a/src/commands.c b/src/commands.c index f3337062feb3b3712edbe6f2a553996ab9c548c5..66a78d43c4d83d72de65062e0762c315dc8a9d7e 100644 --- a/src/commands.c +++ b/src/commands.c @@ -728,55 +728,47 @@ command_user_add(struct lkt_state *srv, size_t c, volatile sqlite3 *db, char *ar /* Stickers */ static bool -sticker_send(struct lkt_state *srv, size_t c, char *name, int id, int value) +sticker_send(struct lkt_state *srv, size_t c, char *name, char *type, int id, int value) { + UNUSED(type); struct lkt_message *msg = lkt_message_new(); - msg->data_len = safe_snprintf(msg->data, LKT_MESSAGE_ARGS_MAX, "%d: %s . %d", id, name, value); + msg->data_len = safe_snprintf(msg->data, LKT_MESSAGE_ARGS_MAX, "%d: %s -> %d\n", id, name, value); lkt_state_send(srv, c, msg); return true; } bool -command_sticker_get(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) +command_sticker_create(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); - long uri; - char *endptr, err; - STRTOL(uri, argv[1], endptr, err); - RETURN_IF(err, "STRTOL failed", false); - struct lkt_search cb = { - .call = (void(*)(void)) sticker_send, - .srv = srv, - .c = c, - .name = argv[2], - .st_type = argv[0], - .st_uri = (int) uri, - }; - if (!database_search_sticker_init(srv->db, &cb)) + LOG_INFO_SCT("COMMAND", "Client %ld is using the sticker create command", c); + RETURN_UNLESS(argv[0], "Invalid argument", false); + if (!database_sticker_create(srv->db, argv[0])) { + LOG_ERROR_SCT("COMMAND", "Failed to create sticker '%s'", argv[0]); return false; - while (database_search_iter(&cb)) - continue; + } + LOG_INFO_SCT("COMMAND", "Created sticker '%s'", argv[0]); return true; } bool command_sticker_set(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) { - UNUSED(c); RETURN_UNLESS(argv[0] && argv[1] && argv[2] && argv[3] && !argv[4], "Invalid argument", false); - int uri, value, err1, err2; - char *endptr; + long uri, value; + char *endptr, err1, err2; STRTOL(uri, argv[1], endptr, err1); - STRTOL(value, argv[4], endptr, err2); + STRTOL(value, argv[3], endptr, err2); RETURN_IF(err1 || err2, "STRTOL failed", false); + LOG_INFO_SCT("COMMAND", "Client %ld is using the sticker set command", c); RETURN_UNLESS(database_sticker_set(srv->db, argv[0], argv[2], uri, value), "Failed to get sticker", false); srv->mpd_idle_events |= MPD_IDLE_STICKER; return true; } bool -command_sticker_list(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) +command_sticker_get(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) { + LOG_INFO_SCT("COMMAND", "Client %ld is using the sticker get command", c); struct lkt_search callback = { .srv = srv, .c = c, @@ -787,8 +779,8 @@ command_sticker_list(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARG /* Simple list {type} {uri} 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; + if (!database_search_sticker_init(srv->db, &callback)) + return false; } /* list {type} {uri} {name} command */ @@ -796,8 +788,8 @@ command_sticker_list(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARG 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; + if (!database_search_sticker_init(srv->db, &callback)) + return false; } /* list {type} {uri} {name} `op` {value} command */ @@ -808,20 +800,20 @@ command_sticker_list(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARG 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; + if (!database_search_sticker_init(srv->db, &callback)) + return false; } /* Just list all stickers */ else if ( (argv[0] != NULL && argv[1] == NULL) || argv[0] == NULL ) { - if (database_search_sticker_init(srv->db, &callback)) - goto iter; + if (!database_search_sticker_init(srv->db, &callback)) + return false; } else goto unknown; -iter: + /* Send results */ while (database_search_iter(&callback)) continue; return true; @@ -834,9 +826,17 @@ unknown: bool command_sticker_delete(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) { - UNUSED(c); - RETURN_UNLESS(argv[0] && argv[1], "Invalid argument", false); + LOG_INFO_SCT("COMMAND", "Client %ld is using the sticker delete command", c); + RETURN_UNLESS(argv[0] && argv[1] && argv[2], "Invalid argument", false); int uri = atoi(argv[1]); srv->mpd_idle_events |= MPD_IDLE_STICKER; return database_sticker_delete_specify(srv->db, argv[0], uri, argv[2]); } + +bool +command_sticker_destroy(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) +{ + LOG_INFO_SCT("COMMAND", "Client %ld is using the sticker destroy command", c); + RETURN_UNLESS(argv[0], "Invalid argument", false); + return database_sticker_delete(srv->db, argv[0]); +} diff --git a/src/database/disk.sql b/src/database/disk.sql index 285457514f1585114e3412b91a7b73c46e9147fa..5ebe5772cd1e061d34a1e58bdad9f94b445d42ef 100644 --- a/src/database/disk.sql +++ b/src/database/disk.sql @@ -104,7 +104,7 @@ CREATE TABLE IF NOT EXISTS 'stickers' , name TEXT NOT NULL UNIQUE ); -CREATE TABLE IF NOT EXISTS 'stickers.song' +CREATE TABLE IF NOT EXISTS 'stickers.kara' ( id INTEGER REFERENCES kara ON DELETE CASCADE , sticker INTEGER REFERENCES stickers ON DELETE CASCADE , value INTEGER NOT NULL diff --git a/src/database/find.c b/src/database/find.c index 8cab8488045c254566baf24ab05c845ff6fff6b3..5fbc5c468dbafa856317a81d3ea71a4b0c26f522 100644 --- a/src/database/find.c +++ b/src/database/find.c @@ -37,35 +37,36 @@ 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 = - "SELECT name, sts.id, value FROM 'stickers' LEFT OUTER JOIN " - "( SELECT id, sticker, value FROM 'stickers.song'" + "SELECT name, sts.id, value FROM 'stickers' JOIN " + "( SELECT id, sticker, value, 'kara' FROM 'stickers.kara'" " UNION" - " SELECT id, sticker, value FROM 'stickers.plt'" + " SELECT id, sticker, value , 'plt' FROM 'stickers.plt'" ") AS sts" "ON sts.sticker = 'stickers'.id"; static const char *SQL_one_type = - "SELECT name, 'stickers.%s'.id, value " - "FROM 'stickers.%s' AS sts" - "LEFT OUTER JOIN 'stickers' " + "SELECT name, sts.id, value, '%s' " + "FROM 'stickers.%s' AS sts " + "JOIN 'stickers' " "ON 'stickers'.id = sts.sticker"; char SQL[LKT_MAX_SQLITE_STATEMENT]; + ret->type = lkt_search_sticker; if (ret->st_type == NULL) memcpy(SQL, SQL_all_types, strlen(SQL_all_types) + 1); else 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); + sprintf(SQL + strlen(SQL), " AND sts.id = %d", ret->st_uri); if (ret->st_op != 0) - sprintf(SQL, " AND sts.value %s %d", + sprintf(SQL + strlen(SQL), " AND sts.value %s %d", ret->st_op == '>' ? ">=" : ret->st_op == '<' ? "<=" : "=", ret->st_value); - strcat(SQL, ret->name ? " AND name = ?;" : ";"); + strcat(SQL, !ret->name ? ";" : " AND name = ?;"); SQLITE_PREPARE(db, ret->stmt, SQL, error); if (ret->name) - SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->name, error) - return true; + SQLITE_BIND_TEXT(db, ret->stmt, 1, ret->name, error); + return true; error: sqlite3_finalize(ret->stmt); return false; @@ -100,7 +101,7 @@ error: bool database_search_iter(struct lkt_search *item) { - const char *sql_row; + const char *sql_row, *type; int id, code, id_len; RETURN_UNLESS(item, "Exit because item is NULL, end iterations", false); GOTO_UNLESS(item->call, "Call function is NULL, terminate the search", end); @@ -116,15 +117,17 @@ database_search_iter(struct lkt_search *item) switch (item->type) { case lkt_search_database: - id = sqlite3_column_int(item->stmt, 0); - sql_row = (const char *) sqlite3_column_text(item->stmt, 1); - id_len = sqlite3_column_int(item->stmt, 2); - return ((lkt_search_database_func) item->call)(item->srv, item->c, id, id_len, sql_row); case lkt_search_queue: - id = sqlite3_column_int(item->stmt, 0); + id = sqlite3_column_int(item->stmt, 0); sql_row = (const char *) sqlite3_column_text(item->stmt, 1); - id_len = sqlite3_column_int(item->stmt, 2); - return ((lkt_search_queue_func) item->call)(item->srv, item->c, id, id_len, sql_row); + id_len = sqlite3_column_int(item->stmt, 2); + return ((lkt_search_database_func) item->call)(item->srv, item->c, id, id_len, sql_row); + case lkt_search_sticker: + sql_row = (const char *) sqlite3_column_text(item->stmt, 0); /* Name */ + id = sqlite3_column_int(item->stmt, 1); /* Id */ + code = sqlite3_column_int(item->stmt, 2); /* Value */ + type = (const char *) sqlite3_column_text(item->stmt, 3); /* Type */ + return ((lkt_search_sticker_func) item->call)(item->srv, item->c, sql_row, type, id, code); case lkt_search_playlist: default: LOG_WARN_SCT("DB", "Search operation %d is not implemented", item->type); diff --git a/src/database/playlist.c b/src/database/playlist.c index a805e47b214f86c4d35dbb9eadbd3430f6c3ac36..b3d259ab8066d934b47fe7c4be47940baf215330 100644 --- a/src/database/playlist.c +++ b/src/database/playlist.c @@ -51,7 +51,7 @@ database_plt_remove_pos(volatile sqlite3 *db, const char *name, int pos) SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); SQLITE_BIND_INT(db, stmt, 2, pos, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); sta = true; error: sqlite3_finalize(stmt); @@ -67,7 +67,7 @@ database_plt_clear(volatile sqlite3 *db, const char *name) bool sta = false; SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); sta = true; error: sqlite3_finalize(stmt); @@ -83,7 +83,7 @@ database_plt_rename(volatile sqlite3 *db, const char *old_name, const char *new_ SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, new_name, error); SQLITE_BIND_TEXT(db, stmt, 2, old_name, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); sta = true; error: sqlite3_finalize(stmt); diff --git a/src/database/queue.c b/src/database/queue.c index abce4426ed9a77a7d5833570b8a04f71a51a907a..fbdf30dc7ac4d51a84792699819b39fc0c10f8a8 100644 --- a/src/database/queue.c +++ b/src/database/queue.c @@ -9,7 +9,7 @@ #define sqlite_just_exec(func, query) \ bool func (volatile sqlite3 *db) { \ - SQLITE_EXEC(db, "BEGIN TRANSACTION;" #query "COMMIT;", error); \ + SQLITE_EXEC(db, "BEGIN TRANSACTION;" query "COMMIT;", error); \ return true; \ error: \ SQLITE_DO_ROLLBACK(db); \ @@ -18,8 +18,10 @@ sqlite_just_exec(database_queue_toggle_pause, "UPDATE queue_state SET paused = 1 - paused;") sqlite_just_exec(database_queue_crop, "DELETE FROM queue WHERE queue.kara_id <> (SELECT current FROM queue_state LIMIT 1);") sqlite_just_exec(database_queue_stop, "UPDATE queue_state SET current = NULL;") -sqlite_just_exec(database_queue_clear, "DELETE FROM queue;DELETE FROM sqlite_sequence WHERE name = 'queue';UPDATE queue_state SET current = NULL;") -sqlite_just_exec(database_config_queue_default, "UPDATE queue_state SET volume = 100, paused = 1, random = 0, repeat = 0, single = 0, consume = 0, current = NULL, duration = 0;") +sqlite_just_exec(database_queue_clear, + "DELETE FROM queue;DELETE FROM sqlite_sequence WHERE name = 'queue';UPDATE queue_state SET current = NULL;") +sqlite_just_exec(database_config_queue_default, + "UPDATE queue_state SET volume = 100, paused = 1, random = 0, repeat = 0, single = 0, consume = 0, current = NULL, duration = 0;") #undef sqlite_just_exec bool diff --git a/src/database/stickers.c b/src/database/stickers.c index 8863b827b0d3ac61f982c31ff1d42f0180c3d811..223a9ac99232b8d4883767d6adaa89115b6b95ac 100644 --- a/src/database/stickers.c +++ b/src/database/stickers.c @@ -7,22 +7,27 @@ #include <stdlib.h> #include <stdio.h> +static inline int +__check_type(const char *type) +{ + return ! ( STR_MATCH(type, "kara") || STR_MATCH(type, "plt") ); +} + bool database_sticker_create(volatile sqlite3 *db, const char *name) { static const char *INSERT = - "WITH id_max (id) AS (SELECT MAX(id) FROM 'stickers')" "INSERT INTO 'stickers' (id, name)" - " SELECT CASE WHEN id_max.id IS NULL THEN 1 ELSE id_max.id + 1 END, ?" - " FROM id_max" - "WHERE NOT EXISTS (SELECT 1 FROM 'stickers' WHERE name = ?);"; + " SELECT CASE WHEN MAX(id) IS NULL THEN 1 ELSE MAX(id) + 1 END, ?" + " FROM 'stickers'" + "WHERE (SELECT COUNT(*) FROM 'stickers' WHERE name = ?) = 0;"; sqlite3_stmt *stmt; int ret = false; RETURN_IF(strlen(name) == 0, "A sticker name must be at least one character long", ret); SQLITE_PREPARE(db, stmt, INSERT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); SQLITE_BIND_TEXT(db, stmt, 2, name, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); @@ -38,7 +43,7 @@ database_sticker_delete(volatile sqlite3 *db, const char *name) RETURN_IF(strlen(name) == 0, "A sticker name must be at least one character long", ret); SQLITE_PREPARE(db, stmt, INSERT, error); SQLITE_BIND_TEXT(db, stmt, 1, name, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); @@ -48,38 +53,33 @@ error: bool database_sticker_set(volatile sqlite3 *db, const char *type, const char *name, int uri, int value) { - const char *SQL = NULL; + static const char *SQL_TEMPLATE = + "INSERT OR REPLACE INTO 'stickers.%s' (id, sticker, value) " + "SELECT ?, 'stickers'.id, ? " + "FROM 'stickers' " + "WHERE 'stickers'.name = ?;"; + char SQL[LKT_MAX_SQLITE_STATEMENT]; sqlite3_stmt *stmt; int ret = false; + if (__check_type(type)) { + LOG_ERROR_SCT("DB", "Type '%s' is invalid", type); + return false; + } + + safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, SQL_TEMPLATE, type); + /* Bindings: * 1 -> the uri of the plalist or kara * 2 -> the value of the sticker * 3 -> the name of the sticker */ - if (!strcasecmp(type, "song")) - SQL = - "INSERT OR REPLACE INTO 'stickers.song' (id, sticker, value) " - "SELECT ?, 'stickers'.id, ? " - "FROM 'stickers'" - "WHERE 'stickers'.id = ?;\n"; - else if (!strcasecmp(type, "plt")) - SQL = - "INSERT OR REPLACE INTO 'stickers.plt' (id, sticker, value) " - "SELECT ?, 'stickers'.id, ? " - "FROM 'stickers'" - "WHERE 'stickers'.id = ?;\n"; - else { - LOG_ERROR_SCT("DB", "Type '%s' is invalid", type); - return false; - } - SQLITE_PREPARE(db, stmt, SQL, error); SQLITE_BIND_INT(db, stmt, 1, uri, error); SQLITE_BIND_INT(db, stmt, 2, value, error); SQLITE_BIND_TEXT(db, stmt, 3, name, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); @@ -92,9 +92,7 @@ database_sticker_delete_specify(volatile sqlite3 *db, const char *type, int uri, char SQL[LKT_MAX_SQLITE_STATEMENT]; sqlite3_stmt *stmt; int ret = false; - - /* Base query. */ - if (strcasecmp("plt", type) && strcasecmp("song", type)) { + if (__check_type(type)) { LOG_ERROR_SCT("DB", "Type '%s' is invalid", type); return false; } @@ -118,7 +116,7 @@ database_sticker_delete_specify(volatile sqlite3 *db, const char *type, int uri, if (name) SQLITE_BIND_TEXT(db, stmt, 2, name, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); ret = true; error: sqlite3_finalize(stmt); diff --git a/src/database/update.c b/src/database/update.c index 7ff464aa795b96b77fc3bd8d34e054de40049a3c..4966e6302c20e2120315289506f051d600934bde 100644 --- a/src/database/update.c +++ b/src/database/update.c @@ -24,7 +24,7 @@ __add_kara_to_update_job(volatile sqlite3 *db, size_t id) sqlite3_stmt *stmt; SQLITE_PREPARE(db, stmt, SQL, error); SQLITE_BIND_INT(db, stmt, 1, (int) id, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); return true; error: return false; @@ -115,7 +115,6 @@ database_update_set_available(volatile sqlite3 *db, int id) if (sqlite3_step(stmt) != SQLITE_DONE) goto error; sqlite3_finalize(stmt); - LOG_INFO_SCT("DB", "Kara %d is now available", id); return true; error: sqlite3_finalize(stmt); @@ -224,7 +223,7 @@ database_deleted_kara(volatile sqlite3 *db, int **kara_id, size_t *len) while (sqlite3_step(stmt) == SQLITE_ROW) { if (size == *len) { - new = realloc((void *) kara_id, (*len) * 2 * sizeof(void *)); + new = realloc(*kara_id, size * 2 * sizeof(int)); GOTO_UNLESS(new, "Out of memory", out); size *= 2; *kara_id = new; @@ -254,6 +253,12 @@ error: LOG_WARN_SCT("DB", "Failed to get informations about the last update: %s", sqlite3_errmsg((sqlite3 *) db)); } +void +database_update_touch(volatile sqlite3 *db, int id) +{ + __add_kara_to_update_job(db, id); +} + void database_update_del(volatile sqlite3 *db, int id) { @@ -261,7 +266,7 @@ database_update_del(volatile sqlite3 *db, int id) sqlite3_stmt *stmt = NULL; SQLITE_PREPARE(db, stmt, SQL, error); SQLITE_BIND_INT(db, stmt, 1, id, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); LOG_WARN_SCT("DB", "Deleted kara with id '%d' from database", id); error: return; @@ -269,7 +274,7 @@ error: #define sqlite_just_exec(func, query) \ void func (volatile sqlite3 *db) { \ - SQLITE_EXEC(db, #query, error); \ + SQLITE_EXEC(db, query, error); \ error: return; \ } sqlite_just_exec(database_stamp, "UPDATE misc SET last_update = strftime('%s','now');") diff --git a/src/database/user.c b/src/database/user.c index cad67826f5fec56ab1e9b58dea3121d729de8a28..8460216eb5cb5f174506a908b92f19bd586bc3b0 100644 --- a/src/database/user.c +++ b/src/database/user.c @@ -29,7 +29,7 @@ database_user_add(volatile sqlite3 *db, const char *username, const char *passwo SQLITE_PREPARE(db, stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, stmt, 1, username, error); SQLITE_BIND_TEXT(db, stmt, 2, password, error); - SQLITE_STEP_OK(db, stmt, error); + SQLITE_STEP_DONE(db, stmt, error); LOG_INFO_SCT("DB", "User '%s' successfully added", username); ret = true; error: diff --git a/src/main/lkt.c b/src/main/lkt.c index 8ab454adb96e83f47c107f01ffd2efb5396a9049..06050b755d6e095a7a3e9d796fc721b789886be3 100644 --- a/src/main/lkt.c +++ b/src/main/lkt.c @@ -28,11 +28,9 @@ #define LKT_KEY_VALUE_SEP ": \n\t\0" #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)) -#define write_socket(sock, buff, len) (fwrite(buff, sizeof(char), len, sock) != len) #define exit_with_status(sock, buff) { \ - fail_if(read_socket(sock, buff, 2) == 0, "ACK"); \ + read_socket(sock, buff, 2); \ fail_if(buff[0] != 'O' && buff[1] != 'K', "ACK"); \ exit(EXIT_SUCCESS); \ } @@ -76,34 +74,12 @@ read_socket(FILE *sock, char *buff, size_t max_len) for (i = 0; i < max_len; ++i) { len = fread(buff + i, sizeof(char), 1, sock); if (buff[i] == '\n' || len != 1) - return i; + break; } + fail_if(len == 0, "Connexion error"); return i; } -static int -write_socket_format(FILE *sock, const char *format, ...) -{ - int ret = 1, size; - char buff[LKT_MESSAGE_MAX]; - va_list ap; - - va_start(ap, format); - size = vsnprintf(buff, LKT_MESSAGE_MAX - 1, format, ap); - buff[LKT_MESSAGE_MAX - 1] = 0; - - if (size < 0) - goto err; - - if (fwrite(buff, sizeof(char), size, sock) < (unsigned int) size) - goto err; - - ret = 0; -err: - va_end(ap); - return ret; -} - static FILE * create_socket(const char *host, const char *port) { @@ -137,15 +113,38 @@ static FILE * lkt_connect(void) { char buff[LKT_MESSAGE_MAX]; - size_t recv_len; - FILE *sock = create_socket(host, port); - recv_len = read_socket(sock, buff, LKT_MESSAGE_MAX); - - fail_if(recv_len == 0, "Failed to connect to lektord"); + read_socket(sock, buff, LKT_MESSAGE_MAX); return sock; } +static void +write_socket(FILE *sock, const char *format, ...) +{ + int size; + char buff[LKT_MESSAGE_MAX]; + va_list ap; + + va_start(ap, format); + size = vsnprintf(buff, LKT_MESSAGE_MAX - 1, format, ap); + buff[LKT_MESSAGE_MAX - 1] = 0; + + if (size < 0) + fail("Connexion error") + + if (fwrite(buff, sizeof(char), size, sock) < (unsigned int) size) + fail("Connexion error") + + va_end(ap); +} + +noreturn static inline void +lkt_send_and_exit(const char *buffer, size_t len) +{ + write_socket(lkt_connect(), buffer, len); + exit(EXIT_SUCCESS); +} + static char * lkt_skip_key(char *buffer) { @@ -166,22 +165,36 @@ send_cmd_with_uri(FILE *sock, char *cmd, int argc, const char **argv) } 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); + write_socket(sock, "%s %s://%s", cmd, argv[0], buf); } /* Functions implementing options. */ +#define just_send_one_arg(func, cmd) \ +noreturn void func (struct lkt_cmd_args *args) { \ + fail_if(args->argc != 1, "Invalid argument"); \ + FILE *sock = lkt_connect(); \ + char buff[2]; \ + write_socket(sock, cmd " %s\n", args->argv[0]); \ + exit_with_status(sock, buff); \ +} +just_send_one_arg(stickers_create__, "sticker __create") +just_send_one_arg(stickers_destroy__, "sticker __destroy") +just_send_one_arg(plt_destroy__, "rm") +just_send_one_arg(plt_create__, "playlistadd") +#undef just_send_one_arg + #define just_send(func, msg) /* Just send a simple string functions */ \ noreturn void func (struct lkt_cmd_args *args) { \ fail_if(args->argc, "This command takes no arguments"); \ lkt_send_and_exit(msg, sizeof(msg)); \ } -just_send(queue_clear__, "clear\nclose\n") -just_send(queue_crop__, "crop\nclose\n") -just_send(next__, "next\nclose\n") -just_send(prev__, "previous\nclose\n") -just_send(stop__, "stop\nclose\n") -just_send(shuffle__, "shuffle\nplay\nclose\n") +just_send(queue_clear__, "clear\n") +just_send(queue_crop__, "crop\n") +just_send(next__, "next\n") +just_send(prev__, "previous\n") +just_send(stop__, "stop\n") +just_send(shuffle__, "shuffle\nplay\n") #undef just_send noreturn void @@ -189,9 +202,12 @@ simple_send_with_password__(const char *cmd) { if (!password) fail("Password not provided"); - static const char cmd__[] = "password %s\n%s\nclose\n"; FILE *sock = lkt_connect(); - exit(write_socket_format(sock, cmd__, password, cmd)); + write_socket(sock, "command_list_begin\n"); + write_socket(sock, "password %s\n", password); + write_socket(sock, "%s\n", cmd); + write_socket(sock, "command_list_end\n"); + exit(EXIT_SUCCESS); } noreturn void @@ -220,18 +236,25 @@ rescan_or_update__(struct lkt_cmd_args *args, const char *cmd) int i; /* All the db */ - if (args->argc == 0) - exit(write_socket_format(sock, "password %s\n%s\n", password, cmd)); + if (args->argc == 0) { + write_socket(sock, "command_list_begin\n"); + write_socket(sock, "password %s\n", password); + write_socket(sock, "%s\n", cmd); + write_socket(sock, "command_list_end\n"); + } /* With a query */ else { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); for (i = 0; i < args->argc; ++i) strncat(buff, args->argv[i], LKT_MESSAGE_MAX - 1); - exit(write_socket_format(sock, "password %s\n%s %s\n", password, cmd, buff)); + write_socket(sock, "command_list_begin\n"); + write_socket(sock, "password %s\n", password); + write_socket(sock, "%s %s\n", cmd, buff); + write_socket(sock, "command_list_end\n"); } - abort(); + exit(EXIT_SUCCESS); } noreturn void @@ -257,22 +280,17 @@ play__(struct lkt_cmd_args *args) pos = atoi(args->argv[0]); static const char status__[] = "status\n"; - static const char cmd_play__[] = "play\nclose\n"; - static const char cmd_play_from__[] = "play %d\nclose\n"; - static const char cmd_pause__[] = "pause\nclose\n"; + static const char cmd_play__[] = "play\n"; + static const char cmd_play_from__[] = "play %d\n"; + static const char cmd_pause__[] = "pause\n"; char buff[LKT_MESSAGE_MAX]; - FILE *sock = lkt_connect(); - - if (write_socket(sock, status__, sizeof(status__))) /* In bytes. */ - exit(EXIT_FAILURE); + write_socket(sock, status__); for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0) - exit(EXIT_FAILURE); - + read_socket(sock, buff, LKT_MESSAGE_MAX - 1); size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); if (STR_NMATCH(buff, "state", len)) { @@ -281,8 +299,10 @@ play__(struct lkt_cmd_args *args) if (STR_NMATCH(lkt_skip_key(buff), "stop", 4)) { if (!pos) lkt_send_and_exit(cmd_play__, sizeof(cmd_play__)); /* In bytes. */ - else - exit(write_socket_format(lkt_connect(), cmd_play_from__, pos)); + else { + write_socket(lkt_connect(), cmd_play_from__, pos); + exit(EXIT_SUCCESS); + } } else @@ -300,13 +320,11 @@ ping__(struct lkt_cmd_args *args) fail("Invalid argument, the ping command takes no arguments"); char buff[6] = {0}; FILE *sock = lkt_connect(); - if (write_socket(sock, "ping\nclose\n", sizeof("ping\n"))) - 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"); + write_socket(sock, "ping\n"); + read_socket(sock, buff, 6 * sizeof(char)); if (!STR_NMATCH(buff, "OK", 2)) fail("ACK"); - exit(write(1, "OK\n", sizeof("OK\n")) > 0); + exit(write(1, "OK\n", sizeof("OK\n")) == 0); } noreturn void @@ -321,9 +339,7 @@ current__(struct lkt_cmd_args *args) char *mem = NULL; FILE *sock = lkt_connect(); - if (write_socket(sock, current_song__, sizeof(current_song__))) /* In bytes. */ - exit(EXIT_FAILURE); - + write_socket(sock, current_song__); assert(mem = calloc(6 * LKT_MESSAGE_MAX, sizeof(char))); assert(memset(mem, 0, 6 * LKT_MESSAGE_MAX * sizeof(char))); @@ -336,8 +352,7 @@ current__(struct lkt_cmd_args *args) for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0) - exit(EXIT_FAILURE); + read_socket(sock, buff, LKT_MESSAGE_MAX - 1); const size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); char *value = lkt_skip_key(buff); @@ -388,16 +403,12 @@ queue_pop__(struct lkt_cmd_args *args) FILE *sock = lkt_connect(); /* Get lektor's status. */ - - if (write_socket(sock, "status\n", sizeof("status\n"))) - goto error; + write_socket(sock, "status\n"); #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) - goto error; - + read_socket(sock, buff, LKT_MESSAGE_MAX - 1); size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); assign_int("songid", songid) @@ -405,18 +416,16 @@ queue_pop__(struct lkt_cmd_args *args) if (STR_NMATCH(buff, "OK", 2)) break; else if (STR_NMATCH(buff, "ACK", 3)) - goto error; + exit(EXIT_FAILURE); } #undef assign_int fclose(sock); sock = lkt_connect(); if (!songid) - goto error; - write_socket_format(sock, "next\ndeleteid %d\n", songid); + exit(EXIT_FAILURE); + write_socket(sock, "next\ndeleteid %d\n", songid); exit_with_status(sock, buff); -error: - exit(EXIT_FAILURE); } noreturn void @@ -439,16 +448,13 @@ status__(struct lkt_cmd_args *args) /* Get lektor's status. */ - if (write_socket(sock, status_str__, strlen(status_str__))) - goto error; + write_socket(sock, status_str__); #define assign_flag(str, f) if (STR_NMATCH(buff, str, len) && (atoi(lkt_skip_key(buff)) == 1)) { flags[it++] = f; 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) - goto error; - + read_socket(sock, buff, LKT_MESSAGE_MAX - 1); size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); if (STR_NMATCH(buff, "state", len)) { @@ -502,14 +508,14 @@ queue_delete__(struct lkt_cmd_args *args) if (args->argc != 1) fail("Invalid argument, need onlt one argument: queue delete <id>"); - static const char *cmd_id__ = "deleteid %d\nclose\n"; + static const char *cmd_id__ = "deleteid %d\n"; int dumy = 0; FILE *sock = lkt_connect(); char buff[3]; sscanf(args->argv[0], "%d", &dumy); if (dumy != 0) { - fail_if(write_socket_format(sock, cmd_id__, dumy), "ACK"); + write_socket(sock, cmd_id__, dumy); exit_with_status(sock, buff); } @@ -555,7 +561,7 @@ queue_seek__(struct lkt_cmd_args *args) fail("Invalid argument, must be only one integer"); FILE *sock = lkt_connect(); - fail_if(write_socket_format(sock, "playid %ld\n", id), "ACK"); + write_socket(sock, "playid %ld\n", id); exit_with_status(sock, buf); } @@ -585,12 +591,14 @@ queue_pos__(struct lkt_cmd_args *args) FILE *sock = NULL; redo: sock = lkt_connect(); - fail_if(up != 0 && write_socket_format(sock, "playlist %d:%d\n", continuation, up), "ACK"); - fail_if(up == 0 && write_socket_format(sock, "playlist %d\n", continuation), "ACK"); + if (up != 0) + write_socket(sock, "playlist %d:%d\n", continuation, up); + else + write_socket(sock, "playlist %d\n", continuation); for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - assert(read_socket(sock, buff, LKT_MESSAGE_MAX - 1) > 0); + read_socket(sock, buff, LKT_MESSAGE_MAX - 1); if (STR_NMATCH(buff, "continue:", strlen("continue:"))) { continuation = atoi(lkt_skip_key(buff)); @@ -634,15 +642,12 @@ queue_list__(struct lkt_cmd_args *args) /* Get the current pos to get limits for the playlist command. */ sock = lkt_connect(); - if (write_socket(sock, "status\n", sizeof("status\n"))) - fail("Communication error"); + write_socket(sock, "status\n"); #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) - fail("Connextion error"); - + read_socket(sock, buff, LKT_MESSAGE_MAX - 1); size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); assign_int("song", song_index); @@ -688,32 +693,35 @@ plt_delete__(struct lkt_cmd_args *args) exit_with_status(sock, buff); } -noreturn void -plt_destroy__(struct lkt_cmd_args *args) -{ - fail_if(args->argc != 1, "Invalid argument"); - FILE *sock = lkt_connect(); - char buff[2]; - write_socket_format(sock, "rm %s\n", args->argv[0]); - exit_with_status(sock, buff); -} - -noreturn void -plt_create__(struct lkt_cmd_args *args) -{ - fail_if(args->argc != 1, "Invalid argument"); - - FILE *sock = lkt_connect(); - char buff[2]; - write_socket_format(sock, "playlistadd %s\n", args->argv[0]); - exit_with_status(sock, buff); -} - noreturn void stickers_get__(struct lkt_cmd_args *args) { - UNUSED(args); - exit(EXIT_FAILURE); + char buff[LKT_MESSAGE_MAX]; + FILE *sock; + if (args->argc == 2) + write_socket(sock = lkt_connect(), "sticker get %s %s\n", args->argv[0], args->argv[1]); + else if (args->argc == 3) + write_socket(sock = lkt_connect(), "sticker get %s %s %s\n", args->argv[0], args->argv[1], + args->argv[2]); + else if (args->argc == 5) { + const char *op = args->argv[3]; + op = op[0] == 'e' ? "=" : op[0] == 'l' ? "<" : op[0] == 'g' ? ">" : NULL; + fail_if(!op, "Invalid argument"); + write_socket(sock = lkt_connect(), "sticker get %s %s %s %s %s\n", args->argv[0], + args->argv[1], args->argv[2], op, args->argv[4]); + } + else + fail("Invalid argument"); + + for (;;) { + memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); + read_socket(sock, buff, LKT_MESSAGE_MAX - 1); + if (STR_NMATCH(buff, "OK", 2)) + exit(EXIT_SUCCESS); + else if (STR_NMATCH(buff, "ACK", 3)) + exit(EXIT_FAILURE); + fprintf(stdout, "%s", buff); + } } noreturn void @@ -722,8 +730,8 @@ stickers_set__(struct lkt_cmd_args *args) fail_if(args->argc != 4, "Invalid argument"); FILE *sock = lkt_connect(); char buff[2]; - write_socket_format(sock, "sticker set %s %s %s %s\n", args->argv[0], - args->argv[1], args->argv[2], args->argv[3]); + write_socket(sock, "sticker set %s %s %s %s\n", args->argv[0], + args->argv[1], args->argv[2], args->argv[3]); exit_with_status(sock, buff); } @@ -733,11 +741,11 @@ stickers_delete__(struct lkt_cmd_args *args) FILE *sock; char buff[2]; if (args->argc == 2) - write_socket_format(sock = lkt_connect(), "sticker delete %s %s", - args->argv[0], args->argv[1]); + write_socket(sock = lkt_connect(), "sticker delete %s %s", + args->argv[0], args->argv[1]); else if (args->argc == 3) - write_socket_format(sock = lkt_connect(), "sticker delete %s %s %s", - args->argv[0], args->argv[1], args->argv[2]); + write_socket(sock = lkt_connect(), "sticker delete %s %s %s", + args->argv[0], args->argv[1], args->argv[2]); else fail("Invalid argument"); exit_with_status(sock, buff); @@ -757,14 +765,14 @@ search_with_cmd__(struct lkt_cmd_args *args, const char *cmd) redo: sock = lkt_connect(); - write_socket_format(sock, "%d %s", continuation, cmd); + write_socket(sock, "%d %s", continuation, cmd); for (i = 0; i < args->argc; ++i) - write_socket_format(sock, " %s", args->argv[i]); - (void) write_socket(sock, "\n", sizeof("\n") / sizeof(char)); + write_socket(sock, " %s", args->argv[i]); + write_socket(sock, "\n"); for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - assert(read_socket(sock, buff, LKT_MESSAGE_MAX - 1) > 0); + read_socket(sock, buff, LKT_MESSAGE_MAX - 1); if (STR_NMATCH(buff, "continue:", strlen("continue:"))) { continuation = atoi(lkt_skip_key(buff)); @@ -832,6 +840,8 @@ static struct lkt_cmd_opt options_stickers[] = { { .name = "get", .call = stickers_get__ }, { .name = "set", .call = stickers_set__ }, { .name = "delete", .call = stickers_delete__ }, + { .name = "create", .call = stickers_create__ }, + { .name = "destroy", .call = stickers_destroy__ }, LKT_OPT_NULL, }; diff --git a/src/main/lktadm.c b/src/main/lktadm.c index 009d93d6114d08fdbc84ff663dcc28edbd12bafe..1a5e561d1e0c905750b8570d20e5a24751e0b11c 100644 --- a/src/main/lktadm.c +++ b/src/main/lktadm.c @@ -25,7 +25,7 @@ fail(const char *format, ...) va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); - exit(write(2, "\n", 1) > 0); + exit(write(2, "\n", 1) == 0); } /* ----------------- * diff --git a/src/module/module_sdl2.c b/src/module/module_sdl2.c index bce1e3b6477a10186a90fa27d08bbe84a9bcdb8c..8421533b22ad4f8bf115a43e60954c9fcb304c33 100644 --- a/src/module/module_sdl2.c +++ b/src/module/module_sdl2.c @@ -277,6 +277,7 @@ module_sdl2_close(struct lkt_win *const win) { RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING); struct module_sdl2_window *sdl2 = win->window; + sdl2->mpv_time_pos = (sdl2->mpv_duration = 0); RETURN_UNLESS(sdl2->mpv, "Missing mpv ctx", NOTHING); static const char *cmd[] = { "stop", NULL }; mpv_command_async((mpv_handle *) sdl2->mpv, 0, cmd); diff --git a/src/module/module_x11.c b/src/module/module_x11.c index 5852a9c4cf6cd70f0cf56bc65eb59be70694b8b1..521acfdad421a92e82e09050ac7d0403b2ed8757 100644 --- a/src/module/module_x11.c +++ b/src/module/module_x11.c @@ -200,7 +200,7 @@ module_x11_close(struct lkt_win *const win) struct module_x11_window *const x11_win = win->window; lmpv_free(&x11_win->mpv); x11_win->child_display = NULL; - x11_win->child_win = 0; + x11_win->child_win = (x11_win->mpv_time_pos = (x11_win->mpv_duration = 0)); } void diff --git a/src/module/mpv.c b/src/module/mpv.c index 492ac110f59a2a7f779bf8bcba5fd7225447707e..f1b891cbc1f33643eb90034e55e4b986b9f003d5 100644 --- a/src/module/mpv.c +++ b/src/module/mpv.c @@ -75,7 +75,7 @@ lmpv_new(unsigned long int wid) goto error; } - LOG_ERROR_SCT("WINDOW", "%s", "Create mpv context"); + LOG_INFO_SCT("WINDOW", "%s", "Create mpv context"); return ctx; error: lmpv_free(&ctx); @@ -151,6 +151,7 @@ loop: break; case MPV_EVENT_SHUTDOWN: + *time_pos = (*time_duration = 0); database_queue_stop(db); win->close(win); return 1; diff --git a/src/net/downloader.c b/src/net/downloader.c index 9606701e0e7a89b1bd3f3e15430df3f142864528..d0d58690ed052d6cf32c3b70c1f31ade34f2468f 100644 --- a/src/net/downloader.c +++ b/src/net/downloader.c @@ -369,6 +369,8 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec database_get_update(db, &db_timestamp, NULL, NULL); if (db_timestamp >= filestamp && filestamp > timestamp && ! kara_metadata_equals(&kara.mdt, kara.filename)) { + database_update_touch(db, kara.id); + database_update_set_available(db, kara.id); LOG_INFO_SCT("REPO", "Ignore kara '%ld' with path '%s'", kara.id, kara.filename); continue; } @@ -390,7 +392,7 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, struct json_objec continue; } - if (!database_update_set_available((sqlite3 *) db, kara.id)) { + if (!database_update_set_available(db, kara.id)) { LOG_WARN_SCT("REPO", "Could not set kara %ld available", kara.id); continue; } @@ -407,12 +409,12 @@ __handle_deleted_kara(volatile sqlite3 *db) int *kara_ids; char filepath[PATH_MAX]; database_deleted_kara(db, &kara_ids, &len); - for (i = 0; i < len; ++i) { if (!database_get_kara_path(db, kara_ids[i], filepath)) continue; database_update_del(db, kara_ids[i]); } + free(kara_ids); } void * diff --git a/src/net/listen.c b/src/net/listen.c index 01389c300c467881a113920f753388ba11d44bd0..5f50167b3cd08a4b377bda6667477fcc66bd7a9d 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -200,14 +200,14 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) err = ! command_find(srv, c, cmd.args, cmd.cont, database_search_queue_init); else if (STR_MATCH(cmd.name, "sticker") && cmd.args[0]) { - if (STR_MATCH(cmd.args[0], "get")) + if (STR_MATCH(cmd.args[0], "get") || STR_MATCH(cmd.args[0], "list") || STR_MATCH(cmd.args[0], "find")) err = ! command_sticker_get(srv, c, &cmd.args[1]); else if (STR_MATCH(cmd.args[0], "set")) err = ! command_sticker_set(srv, c, &cmd.args[1]); else if (STR_MATCH(cmd.args[0], "delete")) err = ! command_sticker_delete(srv, c, &cmd.args[1]); - 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 (STR_MATCH(cmd.args[0], "__create")) + err = ! command_sticker_create(srv, c, &cmd.args[1]); } else if (STR_MATCH(cmd.name, "help")) @@ -523,7 +523,7 @@ accept_all(int listen_fd, struct pollfd *fds, size_t fds_max, size_t *fds_len) char *host = inet_ntoa(peer_addr.sin_addr); uint16_t port = htons(peer_addr.sin_port); - printf(" * New connection from %s:%d.\n", host, port); + LOG_WARN_SCT("NETWORK", "New connection from %s:%d", host, port); fds->fd = fd; fds->events = POLLIN; @@ -597,7 +597,7 @@ handle_network_events(struct lkt_state *srv) if (srv->fds[i].fd > 0) continue; - printf(" * Connection closed.\n"); + LOG_WARN_SCT("NETWORK", "Connection closed by client %ld", i); srv->fds[i] = srv->fds[srv->fds_len - 1]; srv->clients[i - 1] = srv->clients[srv->fds_len - 2]; srv->fds_len--;