diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h index 424e6524eaeba06889160cb8ed3f0c221f963b0c..3329c8a48a5e26e2799d045e74eae4251f1797ed 100644 --- a/inc/lektor/commands.h +++ b/inc/lektor/commands.h @@ -98,3 +98,9 @@ bool command_user_add(sqlite3 *db, char *argv[LKT_MESSAGE_ARGS_MAX]); bool command_restart(struct lkt_state *srv, size_t c); bool command_kill(struct lkt_state *srv, size_t c); bool command_rescan(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]); + +/* Sticker management */ +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 d5632e3c18bbc0632e7e7c2edaf33a6d706e5af0..e26b78f14089117b8bc4c83e49ecf6e248bbf5a9 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -131,6 +131,8 @@ typedef bool (*database_sticker_callback_t)(void *args, const char *sticker, con bool database_sticker_create(sqlite3 *db, const char *name); bool database_sticker_delete(sqlite3 *db, const char *name); +bool database_sticker_delete_specify(sqlite3 *sb, const char *type, int uri, + const char *name /* Can be null */); bool database_sticker_list(sqlite3 *db, const char *type, void *args, database_sticker_callback_t call); bool database_sticker_set(sqlite3 *db, const char *type, const char *name, int uri, int value); bool database_sticker_get(sqlite3 *db, const char *type, const char *name, int uri, void *args, diff --git a/src/commands.c b/src/commands.c index 23792ffc375facddf208015c3552e3c8222d71f0..2282c9bb041d216aabab8ceaf51ea43681a0bb48 100644 --- a/src/commands.c +++ b/src/commands.c @@ -21,6 +21,15 @@ #define SELF_EXECUTABLE_FREEBSD "/proc/curproc/file" #define SELF_EXECUTABLE_SOLARIS "/proc/self/path/a.out" +struct _client_trace_t { + struct lkt_state *srv; + size_t c; + int uri; + const char *name; + int value; + bool is_ok; +}; + inline bool command_restart(struct lkt_state *srv, size_t c) { @@ -549,11 +558,6 @@ command_noidle(struct lkt_state *srv, size_t c) } /* Functions for the searchadd and the search mpd commands */ -struct _client_trace_t { - struct lkt_state *srv; - size_t c; -}; - static bool lkt_callback_print_row_v1(void *args, int id, int id_len, const char *sql_row) { @@ -1074,3 +1078,210 @@ command_user_add(sqlite3 *db, char *argv[LKT_MESSAGE_ARGS_MAX]) return false; fprintf(stderr, " . command_user_add: Failed to add user %s\n", argv[0]); } + +static bool +sticker_send_one_value(void *_args, const char *sticker, const char *type, int uri, int value) +{ + struct _client_trace_t *args = (struct _client_trace_t *) _args; + struct lkt_message *out; + (void) sticker; + (void) type; + (void) uri; + + 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 _client_trace_t *args = (struct _client_trace_t *) _args; + struct lkt_message *out; + + 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 _client_trace_t *args = (struct _client_trace_t *) _args; + struct lkt_message *out; + (void) type; + + if (uri == args->uri) { + 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 _client_trace_t *args = (struct _client_trace_t *) _args; + struct lkt_message *out; + (void) 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) +{ + (void) type; + struct _client_trace_t *args = (struct _client_trace_t *) _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) +{ + (void) type; + struct _client_trace_t *args = (struct _client_trace_t *) _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) +{ + (void) type; + struct _client_trace_t *args = (struct _client_trace_t *) _args; + args->is_ok |= (uri == args->uri) && !strcasecmp(sticker, args->name) && (value > args->value); + return true; +} + +bool +command_sticker_get(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) +{ + if (argv[0] == NULL || argv[1] == NULL || argv[2] == NULL || argv[3] != NULL) { + fprintf(stderr, " ! command_sticker_get: Invalid argument, need only 3 arguments\n"); + return false; + } + + int uri = atoi(argv[1]); /* FIXME: Use strtol. */ + struct _client_trace_t args = { + .srv = srv, + .c = c, + }; + + if (!database_sticker_get(srv->db, argv[0], argv[2], uri, &args, sticker_send_one_value)) { + fprintf(stderr, " . command_sticker_get: Failed to get sticker '%s' for object %s(%d)\n", + argv[2], argv[0], uri); + return false; + } + + return true; +} + +bool +command_sticker_set(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) +{ + if (argv[0] == NULL || argv[1] == NULL || argv[2] == NULL || argv[3] == NULL || argv[4] != NULL) { + fprintf(stderr, " ! command_sticker_get: Invalid argument, need only 3 arguments\n"); + return false; + } + + (void) c; + int uri = atoi(argv[1]); /* FIXME: Use strtol. */ + int value = atoi(argv[4]); /* FIXME: Use strtol. */ + + if (!database_sticker_set(srv->db, argv[0], argv[2], uri, value)) { + fprintf(stderr, " . command_sticker_get: Failed to get sticker '%s' to value %d for object " + "%s(%d)\n", argv[2], value, argv[0], uri); + return false; + } + + return true; +} + +bool +command_sticker_list(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) +{ + struct _client_trace_t args = { + .srv = srv, + .c = c, + }; + + /* Simple list {type} {uri} command */ + if (argv[0] != NULL && argv[1] != NULL && argv[2] == NULL) + goto simple_list_command; + + /* list {type} {uri} {name} command */ + else if (argv[0] != NULL && argv[1] != NULL && + argv[2] != NULL && argv[3] == NULL) + goto list_stickers_in_uri; + + /* 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; + + /* Just list all stickers */ + else if ( (argv[0] != NULL && argv[1] == NULL) || argv[0] == NULL ) + goto just_list_all; + + else + goto unknown; + +just_list_all: + return database_sticker_list(srv->db, argv[0], &args, sticker_send_all); + +simple_list_command: + args.uri = atoi(argv[1]); /* FIXME: Use strtol. */ + return database_sticker_list(srv->db, argv[0], &args, sticker_send_check_uri); + +list_stickers_in_uri: + args.uri = atoi(argv[1]); /* FIXME: Use strtol. */ + args.name = argv[2]; + return database_sticker_list(srv->db, argv[0], &args, sticker_send_value_check_uri_name); + return false; + +list_stickers_check_value: + args.uri = atoi(argv[1]); /* FIXME: Use strtol. */ + args.value = atoi(argv[4]); /* FIXME: Use strtol. */ + args.name = argv[2]; + switch (argv[3][0]) { + case '=': + return database_sticker_list(srv->db, argv[0], &args, sticker_check_is_present_eq); + case '<': + return database_sticker_list(srv->db, argv[0], &args, sticker_check_is_present_lt); + case '>': + return database_sticker_list(srv->db, argv[0], &args, sticker_check_is_present_gt); + default: + return 0; + } + +unknown: + fprintf(stderr, " . command_sticker_list: Specified command is invalid or unknown\n"); + return false; +} + +bool +command_sticker_delete(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]) +{ + if (argv[0] == NULL || argv[1] == NULL) { + fprintf(stderr, " . command_sticker_delete: Invalid argument\n"); + return false; + } + + (void) c; + int uri = atoi(argv[1]); + return database_sticker_delete_specify(srv->db, argv[0], uri, argv[2]); +} diff --git a/src/database/stickers.c b/src/database/stickers.c index 0100955c498f1f495d6be2b6db23b5354bb2ece0..4b8661b800f249bdf5fc9fd3cb7c80552c1a7b23 100644 --- a/src/database/stickers.c +++ b/src/database/stickers.c @@ -113,7 +113,7 @@ database_sticker_list(sqlite3 *db, const char *type, void *args, uri = sqlite3_column_int(stmt, 1); value = sqlite3_column_int(stmt, 2); if (!call(args, sticker, type, uri, value)) - goto error; + goto end_loop; continue; case SQLITE_DONE: @@ -150,7 +150,7 @@ database_sticker_set(sqlite3 *db, const char *type, const char *name, int uri, i "SELECT ?, 'stickers'.id, ? " "FROM 'stickers'" "WHERE 'stickers'.id = ?;\n"; - else if (!strcasecmp(type, "song")) + else if (!strcasecmp(type, "plt")) SQL = "INSERT OR REPLACE INTO 'stickers.plt' (id, sticker, value) " "SELECT ?, 'stickers'.id, ? " @@ -193,12 +193,12 @@ database_sticker_get(sqlite3 *db, const char *type, const char *name, int uri, v "JOIN 'stickers.song'" " ON 'stickers'.id = 'stickers.song'.sticker" " AND 'stickers'.name = ?;\n"; - else if (!strcasecmp(type, "song")) + else if (!strcasecmp(type, "plt")) SQL = "SELECT value " "FROM 'stickers' " - "JOIN 'stickers.song'" - " ON 'stickers'.id = 'stickers.song'.sticker" + "JOIN 'stickers.plt'" + " ON 'stickers'.id = 'stickers.plt'.sticker" " AND 'stickers'.name = ?;\n"; else { fprintf(stderr, " . database_sticker_get: Type '%s' is invalid\n", type); @@ -213,7 +213,7 @@ database_sticker_get(sqlite3 *db, const char *type, const char *name, int uri, v case SQLITE_ROW: value = sqlite3_column_int(stmt, 1); if (!call(args, name, type, uri, value)) - goto error; + goto end_loop; continue; case SQLITE_DONE: @@ -230,3 +230,46 @@ error: sqlite3_finalize(stmt); return ret; } + +bool +database_sticker_delete_specify(sqlite3 *db, const char *type, int uri, const char *name) +{ + char SQL[LKT_MAX_SQLITE_STATEMENT]; + sqlite3_stmt *stmt; + int ret = false; + + /* Base query. */ + if (strcasecmp("plt", type) && strcasecmp("song", type)) { + fprintf(stderr, " . database_sticker_get: Type '%s' is invalid\n", type); + return false; + } + + snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, "DELETE FROM 'stickers.%s' " + "WHERE 'stickers.%s' = ? ", type, type); + SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0; + + /* If there is a name specified. */ + if (!name) { + strncat(SQL, ";", LKT_MAX_SQLITE_STATEMENT - 1); + SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0; + } else { + strncat(SQL, "AND sticker = (SELECT id FROM 'stickers' WHERE name = ? LIMIT 1);", + LKT_MAX_SQLITE_STATEMENT - 1); + SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0; + } + + SQLITE_PREPARE(db, stmt, SQL, error); + SQLITE_BIND_INT(db, stmt, 1, uri, error); + + if (name) + SQLITE_BIND_TEXT(db, stmt, 2, name, error); + + if (! (ret = (sqlite3_step(stmt) == SQLITE_OK))) { + fprintf(stderr, " . database_sticker_delete_specify: Failed to delete sticker\n"); + goto error; + } + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} diff --git a/src/net/listen.c b/src/net/listen.c index 049cf75e93610c3cf20cdd397c723de2afc452bf..d42e68ffd5973791b9665e9c2bcf73282570daa4 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -162,6 +162,8 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) else if (!strcmp(cmd.name, "close")) err = !lkt_close_client(srv, c); + else if (!strcmp(cmd.name, "ping")) + err = 0; else if (!strcmp(cmd.name, "next")) err = !command_next(srv->db, &srv->win, &srv->mpd_idle_events); @@ -186,6 +188,17 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) else if (!strcmp(cmd.name, "playlist") || !strcmp(cmd.name, "playlistinfo")) err = !command_queue_list(srv, c, cmd.args); + else if (!strcmp(cmd.name, "sticker") && cmd.args[0]) { + if (!strcmp(cmd.args[0], "get")) + err = ! command_sticker_get(srv, c, &cmd.args[1]); + else if (!strcmp(cmd.args[0], "set")) + err = ! command_sticker_set(srv, c, &cmd.args[1]); + else if (!strcmp(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")) + err = ! command_sticker_delete(srv, c, &cmd.args[1]); + } + else if (!strcmp(cmd.name, "help")) err = !command_help(srv, c); else if (!strcmp(cmd.name, "__dbupdate")) @@ -647,8 +660,7 @@ handle_idle_events(struct lkt_state *srv) } enum mpd_idle_flag * -lkt_client_get_mask(struct lkt_state *srv, size_t c) -{ +lkt_client_get_mask(struct lkt_state *srv, size_t c) { return &(srv->clients[c - 1].mpd_idle_watch); }