diff --git a/doc/lektord.1 b/doc/lektord.1 index a49ff0118060fd5c1f0497eb8746bb80c085489e..d1d4a421f88ead5ae5f037fe1150a0d469c50df6 100644 --- a/doc/lektord.1 +++ b/doc/lektord.1 @@ -25,11 +25,15 @@ commands from: .PD 0 .TP .PD -\fB\-\-help\fP / \fB\-h\fP +\fB\-h\fP Prints the help message. .TP -\fB\-\-version\fP / \fB\-v\fP -Print the version of the lektor daemon. +\fB\-f\fP <config-file> +Specify a config file manually. +.TP +\fB\-F\fP +Don't check if the database is not already opened by another instance. +Usefull in case of non-really-clean shutdown of lektord. .PP If the lektor daemon is launched without a configuration file, it will exit with the code \fB1\fP. To init the default configuration file (normally done @@ -39,7 +43,7 @@ by meson during the install), you should just use: .nf \fB % mkdir ~/.config/lektor/ -% lktadm init conf > ~/.config/lektor/lektor.ini +% lkt admin config > ~/.config/lektor/lektor.ini % lektord .fi \fR .P diff --git a/inc/lektor/database.h b/inc/lektor/database.h index ba37a9faa1756f97bc068e67596dafc546627964..080c507b0b88f84e734a54abe5a8c3fa6cd76863 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -34,6 +34,7 @@ bool database_init (const char *dbpath); bool database_open (volatile sqlite3 *db, const char *dbpath, bool check); bool database_attach(volatile sqlite3 *db, const char *name, const char *dbpath); bool database_detach(volatile sqlite3 *db, const char *name); +void database_close_all(void); /* Get information on the queue and currently playing kara. */ bool database_queue_state (volatile sqlite3 *db, struct lkt_queue_state *res); diff --git a/inc/lektor/net.h b/inc/lektor/net.h index 325e6d3ad185721218991dda4846eeaa5dc8d717..e7d244bb356414064b60588d5479ff8a87fd0998 100644 --- a/inc/lektor/net.h +++ b/inc/lektor/net.h @@ -7,6 +7,7 @@ #include <lektor/thread.h> #include <lektor/uri.h> +#include <pthread.h> #include <sqlite3.h> #include <mpv/client.h> #include <curl/curl.h> @@ -77,6 +78,7 @@ struct lkt_state { const char *kara_prefix; mpd_idle_flag mpd_idle_events; + pthread_mutex_t lock; struct lkt_repo repo; struct lkt_win win; @@ -93,7 +95,9 @@ void lkt_set_continuation(struct lkt_state *srv, size_t c, int i); /* Get the mask to watch for events for a given client, to be used with the `idle` command. * Return a pointer to the client's mask */ -mpd_idle_flag *lkt_client_get_mask(struct lkt_state *srv, size_t c); +int lkt_client_get_mask(struct lkt_state *srv, size_t c); +void lkt_client_add_mask(struct lkt_state *srv, size_t c, mpd_idle_flag add); +void lkt_client_clear_mask(struct lkt_state *srv, size_t c); /* Register a client as authentificated. */ bool lkt_client_auth(struct lkt_state *srv, size_t c, bool set_auth); diff --git a/src/commands.c b/src/commands.c index 83a199e02b292d22f34a8ac8f86bc01b8ff85933..9ad34084ef1317c2dadf1b3ef0b0e2488e2a49b6 100644 --- a/src/commands.c +++ b/src/commands.c @@ -29,6 +29,7 @@ command_restart(struct lkt_state *srv, size_t c) return false; } close(srv->fds[0].fd); + database_close_all(); execv(executable_name, (char *const *) argv); LOG_ERROR_SCT("GENERAL", "%s", "Failed to exec lektor or OS not supported"); return false; @@ -73,6 +74,7 @@ command_kill(struct lkt_state *srv, size_t c) RETURN_UNLESS(lkt_client_auth(srv, c, false), "Failed to authentificate user", false); LOG_INFO_SCT("GENERAL", "%s", "Stopping lektord"); close(srv->fds[0].fd); + database_close_all(); exit(EXIT_SUCCESS); } @@ -336,44 +338,42 @@ command_help(struct lkt_state *srv, size_t c) bool command_idle(struct lkt_state *srv, size_t c, struct lkt_command *cmd) { - mpd_idle_flag *clt_mask = lkt_client_get_mask(srv, c); - bool once = false; - - for (size_t i = 0; cmd->args[i]; ++i) { - once |= true; + bool once; + size_t i; + for (once = false, i = 0; cmd->args[i]; ++i, once |= true) { if (STR_MATCH(cmd->args[i], "database")) - *clt_mask |= MPD_IDLE_DATABASE; + lkt_client_add_mask(srv, c, MPD_IDLE_DATABASE); else if (STR_MATCH(cmd->args[i], "update")) - *clt_mask |= MPD_IDLE_UPDATE; + lkt_client_add_mask(srv, c, MPD_IDLE_UPDATE); else if (STR_MATCH(cmd->args[i], "stored_playlist")) - *clt_mask |= MPD_IDLE_STORED_PLAYLIST; + lkt_client_add_mask(srv, c, MPD_IDLE_STORED_PLAYLIST); else if (STR_MATCH(cmd->args[i], "playlist")) - *clt_mask |= MPD_IDLE_PLAYLIST; + lkt_client_add_mask(srv, c, MPD_IDLE_PLAYLIST); else if (STR_MATCH(cmd->args[i], "player")) - *clt_mask |= MPD_IDLE_PLAYER; + lkt_client_add_mask(srv, c, MPD_IDLE_PLAYER); else if (STR_MATCH(cmd->args[i], "mixer")) - *clt_mask |= MPD_IDLE_MIXER; + lkt_client_add_mask(srv, c, MPD_IDLE_MIXER); else if (STR_MATCH(cmd->args[i], "output")) - *clt_mask |= MPD_IDLE_OUTPUT; + lkt_client_add_mask(srv, c, MPD_IDLE_OUTPUT); else if (STR_MATCH(cmd->args[i], "options")) - *clt_mask |= MPD_IDLE_OPTIONS; + lkt_client_add_mask(srv, c, MPD_IDLE_OPTIONS); else if (STR_MATCH(cmd->args[i], "partition")) - *clt_mask |= MPD_IDLE_PARTITION; + lkt_client_add_mask(srv, c, MPD_IDLE_PARTITION); else if (STR_MATCH(cmd->args[i], "sticker")) - *clt_mask |= MPD_IDLE_STICKER; + lkt_client_add_mask(srv, c, MPD_IDLE_STICKER); else if (STR_MATCH(cmd->args[i], "subscription")) - *clt_mask |= MPD_IDLE_SUBSCRIPTION; + lkt_client_add_mask(srv, c, MPD_IDLE_SUBSCRIPTION); else if (STR_MATCH(cmd->args[i], "message")) - *clt_mask |= MPD_IDLE_MESSAGE; + lkt_client_add_mask(srv, c, MPD_IDLE_MESSAGE); else - *clt_mask = MPD_IDLE_ALL; + lkt_client_add_mask(srv, c, MPD_IDLE_ALL); } if (!once) - *clt_mask = MPD_IDLE_ALL; + lkt_client_add_mask(srv, c, MPD_IDLE_ALL); - LOG_INFO_SCT("COMMAND", "Idle mask for client number %ld is 0x%X", c, *clt_mask); + LOG_INFO_SCT("COMMAND", "Idle mask for client number %ld is 0x%X", c, lkt_client_get_mask(srv, c)); return true; } @@ -381,8 +381,7 @@ command_idle(struct lkt_state *srv, size_t c, struct lkt_command *cmd) inline bool command_noidle(struct lkt_state *srv, size_t c) { - mpd_idle_flag *clt_mask = lkt_client_get_mask(srv, c); - *clt_mask = MPD_IDLE_NONE; + lkt_client_clear_mask(srv, c); return true; } diff --git a/src/database/open.c b/src/database/open.c index dcaabf62ea14c8df963226adb34356f86871a458..6cc01a60cfb485142881b78f45942a949334db73 100644 --- a/src/database/open.c +++ b/src/database/open.c @@ -7,6 +7,7 @@ #include <stdlib.h> #include <string.h> #include <strings.h> +#include <pthread.h> extern unsigned char ___src_database_disk_sql[]; extern unsigned char ___src_database_memory_sql[]; @@ -21,6 +22,7 @@ struct named_db { }; static struct stack db_stack = {0}; static int atexited = 0; +static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; static inline void __dec(volatile sqlite3 *db, const char *name) @@ -29,14 +31,18 @@ __dec(volatile sqlite3 *db, const char *name) safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, "UPDATE %s.misc SET opened = 0;", name); SQLITE_EXEC(db, SQL, error); + LOG_INFO_SCT("DB", "Dec open count on db '%s'", name); return; error: LOG_ERROR_SCT("DB", "%s", "Faield to close database"); } void -__close_databases(void) +database_close_all(void) { + LOG_INFO_SCT("GARBAGE", "%s", "Closing all db"); + if (pthread_mutex_trylock(&mtx)) + return; struct named_db *item; while (!stack_empty(&db_stack)) { stack_pop(&db_stack, (void **) &item); @@ -44,7 +50,7 @@ __close_databases(void) free((void *) item->name); free(item); } - LOG_INFO_SCT("DB", "%s", "All db closed"); + LOG_INFO_SCT("GARBAGE", "%s", "All db closed"); stack_free(&db_stack); } @@ -53,23 +59,20 @@ __inc(volatile sqlite3 *db, const char *name) { SQLITE_EXEC(db, "UPDATE misc SET opened = (SELECT opened + 1 FROM misc);", error); + if (!atexited) { atexited = 1; if (stack_new(&db_stack)) goto out_of_memory; - if (atexit(__close_databases)) { - LOG_ERROR_SCT("GENERAL", "%s", - "Failed to set function in 'atexit'"); - exit(EXIT_FAILURE); - } - struct named_db *item = malloc(sizeof(struct named_db)); - if (!item) - goto out_of_memory; - item->name = strdup(name); - item->db = db; - if (stack_push(&db_stack, item)) - goto out_of_memory; } + + struct named_db *item = malloc(sizeof(struct named_db)); + if (!item) + goto out_of_memory; + item->name = strdup(name); + item->db = db; + if (stack_push(&db_stack, item)) + goto out_of_memory; return; error: LOG_ERROR_SCT("DB", "%s", "Database already in use"); diff --git a/src/database/queue.c b/src/database/queue.c index 3559d3f2f2d4dd3435ba306eb78951b6a57d698c..ed6ddc6f5882527407c52c9fd4d858bfa2b0eec3 100644 --- a/src/database/queue.c +++ b/src/database/queue.c @@ -293,7 +293,8 @@ database_queue_del_id(volatile sqlite3 *db, int id) { static const char *SQL_TEMPLATE = "BEGIN TRANSACTION;" - "CREATE TEMPORARY TABLE queue_tmp (position INTEGER, kara_id INTEGER, priority INTEGER);" + "CREATE TEMPORARY TABLE IF NOT EXISTS queue_tmp (position INTEGER, kara_id INTEGER, priority INTEGER);" + "DELETE FROM queue_tmp;" /* Move the current 'pointer' */ "UPDATE queue_state SET current = (SELECT NULLIF(COUNT(position), 0) FROM queue JOIN queue_state ON position <= current AND kara_id != %d);" "DELETE FROM queue WHERE kara_id = %d;" /* Delete any kara with the specified id */ @@ -301,7 +302,6 @@ database_queue_del_id(volatile sqlite3 *db, int id) "DELETE FROM queue;" "INSERT INTO queue(priority, position, kara_id) SELECT priority, ROW_NUMBER() OVER(ORDER BY position ASC), kara_id FROM queue_tmp;" "UPDATE sqlite_sequence SET seq = (SELECT COUNT(*) FROM queue) WHERE name = 'queue';" /* Update the sqlite_sequence */ - "DROP TABLE queue_tmp;" /* Erase queue_tmp */ "COMMIT;"; char SQL[LKT_MAX_SQLITE_STATEMENT]; safe_snprintf(SQL, LKT_MAX_SQLITE_STATEMENT, SQL_TEMPLATE, id, id); @@ -568,11 +568,13 @@ database_queue_shuffle(volatile sqlite3 *db) const char *SQL = "BEGIN TRANSACTION;" /* Create temporary queue */ - "CREATE TEMPORARY TABLE queue_tmp" + "CREATE TEMPORARY TABLE IF NOT EXISTS queue_tmp" " ( position INTEGER PRIMARY KEY AUTOINCREMENT CHECK(position > 0)" " , kara_id INTEGER" " , priority INTEGER NOT NULL DEFAULT 1 CHECK(priority > 0 AND priority < 6)" " );" + "DELETE FROM sqlite_sequence WHERE name = 'queue_tmp';" + "DELETE FROM queue_tmp;" /* When current is NULL, that thing is also NULL, so no insertion is done */ "INSERT INTO queue_tmp (kara_id, priority)" " SELECT kara_id, 5" @@ -594,8 +596,6 @@ database_queue_shuffle(volatile sqlite3 *db) " SELECT position, kara_id, priority" " FROM queue_tmp" " ORDER BY priority, position;" - "DROP TABLE queue_tmp;" - "DELETE FROM sqlite_sequence WHERE name = 'queue_tmp';" /* Set the current to the right kara when needed */ "UPDATE queue_state" " SET current = CASE" diff --git a/src/main/server.c b/src/main/server.c index d801d4dcfa55739b80399e5582533d7caa6032b2..e13c0d1cc537faf8610c70f5c54c43c477f98fdb 100644 --- a/src/main/server.c +++ b/src/main/server.c @@ -35,77 +35,90 @@ REG_ADD(load_x11) #endif REG_END() -static void -__sig_exit(int sig) -{ - LOG_ERROR_SCT("SIGNAL", "Exit because of signal %d", sig); - exit(EXIT_FAILURE); -} - int main(int argc, char *argv[]) { struct passwd *pw = getpwuid(getuid()); char exe[PATH_MAX]; + int autoclear, check_exclusive = 1, opt; + char *conf_file = safe_zero_malloc(PATH_MAX * sizeof(char)); pthread_t th; executable_name = "lektord"; - UNUSED(argv); - assert(!signal(SIGTERM, __sig_exit)); - assert(!signal(SIGQUIT, __sig_exit)); - assert(!signal(SIGINT, __sig_exit)); if (argc <= 1) goto normal_launch; - help__(); - return EXIT_FAILURE; + + /* Check args */ + while ((opt = getopt(argc, argv, "hFf:")) != -1) { + switch (opt) { + case 'F': + check_exclusive = 0; + break; + case 'f': + strncpy(conf_file, optarg, PATH_MAX); + break; + case 'h': + default: + help__(); + exit(EXIT_SUCCESS); + } + } normal_launch: - LOG_INFO("Lektor launched by user %s (shell: %s, home: %s)", pw->pw_name, pw->pw_shell, pw->pw_dir); + LOG_INFO_SCT("GENERAL", "Lektor launched by user %s (shell: %s, home: %s)", + pw->pw_name, pw->pw_shell, pw->pw_dir); reg_set(server_reg); mthread_init(); pthread_create(&th, NULL, mthread_main, NULL); if (read_self_exe(exe, PATH_MAX)) - LOG_WARN_SCT("GENERAL", "%s", "Failed to read self executable path, restart may not work"); + LOG_WARN_SCT("GENERAL", "%s", "Failed to read self executable path, " + "restart may not work"); executable_name = exe; /* Init the server */ - char *memory = (char *) safe_malloc((2 * PATH_MAX + HOST_NAME_MAX + 3) * sizeof(char)); - RETURN_UNLESS(memory, "Out of memory", 5); - struct lkt_state srv; - int autoclear, check_exclusive = 1; - char *const db_path = safe_malloc(PATH_MAX * sizeof(char)); - char *const kara_dir = safe_malloc(PATH_MAX * sizeof(char)); - char conf_file[PATH_MAX]; + char *db_path = safe_malloc(PATH_MAX * sizeof(char)); + char *kara_dir = safe_malloc(PATH_MAX * sizeof(char)); memset(&srv, 0, sizeof(struct lkt_state)); /* Initialize the system. */ - RETURN_UNLESS(database_new(&srv.db), "Failed to initialize the memory database", 1); - RETURN_IF (config_detect_file(conf_file, PATH_MAX), "Failed to find a config file", 1); - RETURN_IF (config_new(srv.db, conf_file), "Failed to read configuration file", 1); + if (!database_new(&srv.db)) { + LOG_ERROR_SCT("INIT", "%s", "Failed to init memory db"); + exit(EXIT_FAILURE); + } + + if (conf_file[0] == '\0' && config_detect_file(conf_file, PATH_MAX)) { + LOG_ERROR_SCT("INIT", "%s", "Failed to find a config file"); + exit(EXIT_FAILURE); + } + + if (config_new(srv.db, conf_file)) { + LOG_ERROR_SCT("INIT", "%s", "Failed to read the config"); + exit(EXIT_FAILURE); + } + free(conf_file); /* Finish to initialize. */ - RETURN_UNLESS(database_config_get_text(srv.db, "database", "db_path", db_path, PATH_MAX), "Cfg error", 2); - RETURN_UNLESS(database_open(srv.db, db_path, check_exclusive), "Can't open database", 1); + database_config_get_text(srv.db, "database", "db_path", db_path, PATH_MAX); + RETURN_UNLESS(database_open(srv.db, db_path, check_exclusive), "Can't open database", 1); + free(db_path); - /* Read the configuration. */ - RETURN_UNLESS(database_config_get_int (srv.db, "player", "autoclear", &autoclear), "Cfg error", 2); - RETURN_UNLESS(database_config_get_text(srv.db, "database", "kara_dir", kara_dir, PATH_MAX), "Cfg error", 2); - RETURN_UNLESS(database_config_get_text(srv.db, "server", "host", srv.host, HOST_NAME_MAX), "Cfg error", 2); - RETURN_UNLESS(database_config_get_text(srv.db, "server", "port", srv.port, 5), "Cfg error", 2); + /* Read the configuration. We already know that the config is valid */ + database_config_get_int (srv.db, "player", "autoclear", &autoclear); + database_config_get_text(srv.db, "database", "kara_dir", kara_dir, PATH_MAX); + database_config_get_text(srv.db, "server", "host", srv.host, HOST_NAME_MAX); + database_config_get_text(srv.db, "server", "port", srv.port, 5); if (kara_dir[strlen(kara_dir) - 1] != '/') strncat(kara_dir, "/", PATH_MAX - 1); - srv.kara_prefix = kara_dir; - database_config_queue_default(srv.db); + database_config_queue_default(srv.db); if (autoclear) database_queue_clear(srv.db); RETURN_IF(load_module_by_name(&srv, "player", &srv.win), "Can't load module player", 3); RETURN_IF(load_module_by_name(&srv, "repo", &srv.repo), "Can't load module repo", 3); lkt_listen(&srv); - srv.win.free(&srv.win); return EXIT_FAILURE; } diff --git a/src/mkv/utils.c b/src/mkv/utils.c index bd721a065e45716d6862ac4a8237214fdd294a69..2e21974189e2420e0a99cf04eff2b5fd00974e8f 100644 --- a/src/mkv/utils.c +++ b/src/mkv/utils.c @@ -12,7 +12,7 @@ mdtcat(struct kara_metadata *mdt, char **ret) size_t size = strlen(mdt->song_name) + strlen(mdt->source_name) + strlen(mdt->category) + strlen(mdt->language) + strlen(mdt->author_name) + strlen(mdt->song_type) + - /* Null byte */ 1 + /* Separators */ 12 + + /* Null byte */ 1 + /* Separators */ 12 + 5 + long_length(mdt->song_number); *ret = malloc(sizeof(char) * size); if (!*ret) { @@ -20,7 +20,7 @@ mdtcat(struct kara_metadata *mdt, char **ret) return; } - safe_snprintf(*ret, size, "%s - %s / %s - %s%d - %s", mdt->category, + safe_snprintf(*ret, size, "%s - %s / %s - %s%d - %s [ %s ]", mdt->category, mdt->language, mdt->source_name, mdt->song_type, - mdt->song_number, mdt->song_name); + mdt->song_number, mdt->song_name, mdt->author_name); } diff --git a/src/module/module_sdl2.c b/src/module/module_sdl2.c index 43060f06edeb5724cb7e732da8717c032fabf3e7..e2f75ec4dad88d46a1334a7c2ae185d37f1829ff 100644 --- a/src/module/module_sdl2.c +++ b/src/module/module_sdl2.c @@ -8,6 +8,7 @@ #include <lektor/thread.h> #include <sched.h> +#include <assert.h> #include <string.h> #include <unistd.h> #include <stdlib.h> @@ -98,7 +99,6 @@ init_mpv_gl__(mpv_handle *mpv, mpv_render_context **mpv_gl, mpv_render_context_set_update_callback(*mpv_gl, on_mpv_render_update, NULL); return 0; } -/* Thread related functions */ static void * sdl_thread__(struct poller_thread_arg *arg) @@ -157,6 +157,8 @@ sdl_thread__(struct poller_thread_arg *arg) loop: SDL_WaitEvent(&event); + if (sdl2->launched == 2) + goto end; switch (event.type) { case SDL_QUIT: @@ -263,6 +265,9 @@ loop: sched_yield(); goto loop; /* A loop without indentation. */ +end: + sdl2->launched = 0; + return NULL; } /* Exported functions */ @@ -321,7 +326,7 @@ module_sdl2_new(struct lkt_win *const win) /* Finish */ SDL_SetWindowTitle((SDL_Window *) ((struct module_sdl2_window *) - win->window)->window, "Lektord"); + win->window)->window, "Lektord"); SDL_DisableScreenSaver(); ((struct module_sdl2_window *) win->window)->launched = 1; return true; @@ -344,9 +349,9 @@ module_sdl2_free(struct lkt_win *const win) { RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING); struct module_sdl2_window *sdl2 = win->window; - mpv_render_context_free((mpv_render_context *) sdl2->mpv_gl); - sdl2->mpv_gl = NULL; - lmpv_free((mpv_handle **) &sdl2->mpv); + sdl2->launched = 2; + while (sdl2->launched) + sched_yield(); } bool @@ -393,16 +398,6 @@ module_sdl2_get_elapsed(struct lkt_win *const win, int *elapsed_sec) return true; } -void -module_sdl2_attach(struct lkt_win *const win, void *server) -{ - RETURN_UNLESS(win && server, "Invalid arguments", NOTHING); - struct lkt_state *srv = server; - struct module_sdl2_window *sdl2 = win->window; - sdl2->db = srv->db; - sdl2->mpd_idle_events = &srv->mpd_idle_events; -} - bool module_sdl2_handle_events(struct lkt_win *const win, volatile sqlite3 *db, mpd_idle_flag *mpd_idle_events) diff --git a/src/module/module_x11.c b/src/module/module_x11.c index 6b1d4572f84083ae3a9dabbb3580cc347f7545f5..d9231806ea682d52f5f3d3984b9c9b2b5990618a 100644 --- a/src/module/module_x11.c +++ b/src/module/module_x11.c @@ -222,12 +222,6 @@ module_x11_free(struct lkt_win *const win) win->window = NULL; } -void -module_x11_attach(struct lkt_win *const win, void *server) -{ - UNUSED(win, server); -} - bool module_x11_toggle_pause(struct lkt_win *const win) { diff --git a/src/module/repo.c b/src/module/repo.c index c12a40c2229b00a236022ed0b6deeb60ec23c62f..5c08094c52665406058196bf86a1760fcf7822a1 100644 --- a/src/module/repo.c +++ b/src/module/repo.c @@ -342,7 +342,7 @@ __handle_got_json(volatile sqlite3 *db, struct lkt_repo *repo, RETURN_UNLESS(len > 0 && json_object_get_array(json), "Json invalid or array empty", NOTHING); RETURN_UNLESS(database_config_get_text(db, "externals", "mkvpropedit", - mkvpropedit, PATH_MAX - 1), + mkvpropedit, PATH_MAX - 1), "Can't get the mkvpropedit executable path", NOTHING); LOG_INFO_SCT("REPO", "Starting to process json for repo %s", repo->name); diff --git a/src/net/listen.c b/src/net/listen.c index 3713cd19ca0f7832f5a30d5679aec569671d3f57..37d1cbe38b34d83dbcaca97953d4277f0b17ad47 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -150,7 +150,7 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) { int err = 0, continuation = 0; - switch (*lkt_client_get_mask(srv, c)) { + switch (lkt_client_get_mask(srv, c)) { case MPD_IDLE_NONE: /* Commands that requires authentification. */ if (STR_MATCH(cmd.name, "__adduser")) @@ -645,27 +645,27 @@ handle_idle_events(struct lkt_state *srv) if (MPD_IDLE_DATABASE & common_mask) strncat(msg->data, "database ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_UPDATE & common_mask) + if (MPD_IDLE_UPDATE & common_mask) strncat(msg->data, "update ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_STORED_PLAYLIST & common_mask) + if (MPD_IDLE_STORED_PLAYLIST & common_mask) strncat(msg->data, "stored_playlist ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_PLAYLIST & common_mask) + if (MPD_IDLE_PLAYLIST & common_mask) strncat(msg->data, "playlist ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_PLAYER & common_mask) + if (MPD_IDLE_PLAYER & common_mask) strncat(msg->data, "player ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_MIXER & common_mask) + if (MPD_IDLE_MIXER & common_mask) strncat(msg->data, "mixer ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_OUTPUT & common_mask) + if (MPD_IDLE_OUTPUT & common_mask) strncat(msg->data, "output ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_OPTIONS & common_mask) + if (MPD_IDLE_OPTIONS & common_mask) strncat(msg->data, "options ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_PARTITION & common_mask) + if (MPD_IDLE_PARTITION & common_mask) strncat(msg->data, "partition ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_STICKER & common_mask) + if (MPD_IDLE_STICKER & common_mask) strncat(msg->data, "sticker ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_SUBSCRIPTION & common_mask) + if (MPD_IDLE_SUBSCRIPTION & common_mask) strncat(msg->data, "subscritpion ", LKT_MESSAGE_MAX - 1); - else if (MPD_IDLE_MESSAGE & common_mask) + if (MPD_IDLE_MESSAGE & common_mask) strncat(msg->data, "message ", LKT_MESSAGE_MAX - 1); msg->data_len = strlen(msg->data); @@ -683,10 +683,28 @@ handle_idle_events(struct lkt_state *srv) return 0; } -mpd_idle_flag * +int lkt_client_get_mask(struct lkt_state *srv, size_t c) { - return &(srv->clients[c - 1].mpd_idle_watch); + return srv->clients[c - 1].mpd_idle_watch; +} + +void +lkt_client_add_mask(struct lkt_state *srv, size_t c, mpd_idle_flag add) +{ + if (pthread_mutex_lock(&srv->lock)) + return; + srv->clients[c - 1].mpd_idle_watch |= add; + pthread_mutex_unlock(&srv->lock); +} + +void +lkt_client_clear_mask(struct lkt_state *srv, size_t c) +{ + if (pthread_mutex_lock(&srv->lock)) + return; + srv->clients[c - 1].mpd_idle_watch = MPD_IDLE_NONE; + pthread_mutex_unlock(&srv->lock); } inline bool