diff --git a/doc/footer b/doc/footer index 505654ab7b32158c1bb022e91b6a5b4b52ce3034..ec6a4acee7b6427a7f400e4ac2b6dad4d42fc3cc 100644 --- a/doc/footer +++ b/doc/footer @@ -1,23 +1,3 @@ -.SH "AUTHOR AND AVAILABILITY" -Lektor is a karaoke player for POSIX compliant systems (i.e. not MS-Windows) -writen initially in C. Some may call it Lektor mk 7. It was writen by Hubert -\'Taiite' HIRTZ, Maël 'Kubat' MARTIN and Louis 'Elliu' GOYARD. These people -also helped: Loïc 'Sting' ALLÈGRE and Etienne 'Pelle' BRATEAU. -.PP -The up\-to\-date source code is available via Git from Gitlab\&. See -\fBhttps://git\&.iiens\&.net/martin2018/lektor\fP. The source code is -provided under the \fIISC\fP licence. -.fi -.SH "RELATED SITES AND THE LEKTOR FAQ" -Just see one of the dev from lektor or a bakateux if you have some questions -about lektor. -.PP -.PD 0 -.TP -\fBhttps://kurisu.iiens.net\fP The depo site for the karaoke base -.TP -\fBhttps://manga.iiens.net\fP The home website for the Bakaclub -.PD .SH "FILES" .PD 0 .TP diff --git a/doc/lektor.1 b/doc/lektor.1 index d10932c648eb3379ddb799c7e99cd0be201126dc..8bfa28950ddd1977c257ee23b8ce28b43bca02d4 100644 --- a/doc/lektor.1 +++ b/doc/lektor.1 @@ -84,13 +84,37 @@ the \fBarg\fP should be the author of the kara the \fBarg\fP should be a sqlite3 query. The formating string on which the query is applied is like \fB"${cat}/${source} - ${type}${song_num?} - ${title}"\fP. You usually want to do this. -.PP + .SH "SUPPORTED LANGUAGES" The supported languages in lektor are: \fBjp\fP, \fBfr\fP, \fBsp\fP, \fBen\fP, \fBlatin\fP, \fBit\fP, \fBru\fP, \fBmulti\fP and \fBundefined\fP. + .SH "SUPPORTED TYPES" The supported types in lektor are: \fBOP\fP, \fBED\fP, \fBIS\fP, \fBAMV\fP, \fBVOCA\fP, \fBMV\fP, \fBPV\fP and \fBLIVE\fP. + .SH "SUPPORTED CATEGORIES" The supported categories in lektor are: \fBvo\fP, \fBva\fP, \fBcdg\fP, \fBamv\fP, \fBvocaloid\fP and \fBautres\fP. + +.SH "AUTHOR AND AVAILABILITY" +Lektor is a karaoke player for POSIX compliant systems (i.e. not MS-Windows) +writen initially in C. Some may call it Lektor mk 7. It was writen by Hubert +\'Taiite' HIRTZ, Maël 'Kubat' MARTIN and Louis 'Elliu' GOYARD. These people +also helped: Loïc 'Sting' ALLÈGRE and Etienne 'Pelle' BRATEAU. +.PP +The up\-to\-date source code is available via Git from Gitlab\&. See +\fBhttps://git\&.iiens\&.net/martin2018/lektor\fP. The source code is +provided under the \fIISC\fP licence. +.fi + +.SH "RELATED SITES AND THE LEKTOR FAQ" +Just see one of the dev from lektor or a bakateux if you have some questions +about lektor. +.PP +.PD 0 +.TP +\fBhttps://kurisu.iiens.net\fP The depo site for the karaoke base +.TP +\fBhttps://manga.iiens.net\fP The home website for the Bakaclub +.PD diff --git a/doc/lkt.1 b/doc/lkt.1 index 153952886d9b2be3df10003ebaae9e221a8f783f..d1ce04e5380170d681ef25c6670d445a445a2354 100644 --- a/doc/lkt.1 +++ b/doc/lkt.1 @@ -92,6 +92,9 @@ This can work only if the currently playong kara is not the last \fBqueue add\fP <query> Add karas to the queue at the end of it with a valid query .TP +\fBqueue insert\fP <query> +Add karas to the queue just after the currently playing kara +.TP \fBqueue seek\fP <id> Goto to the kara with the specified id in the queue .TP @@ -115,12 +118,6 @@ playing one \fBsearch get\fP <query> Search and prints the kara that correspond to the query in the database .TP -\fBsearch add\fP <query> -Search, prints and add to the queue the karas that match the query -.TP -\fBsearch insert\fP <query> -Search, prints and insert into the queue the karas that match the query -.TP \fBsearch plt\fP <plt-name> <query> Search, prints and add to an existing playlist the karas that match the query diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h index c685230874d05f8d158d6faf8ae724ebbc32b643..ba3cb7af0435577c45810c65413a68aaa5db95e2 100644 --- a/inc/lektor/commands.h +++ b/inc/lektor/commands.h @@ -3,6 +3,7 @@ #include <common/common.h> #include <lektor/net.h> #include <lektor/window.h> +#include <lektor/database.h> #include <stdbool.h> @@ -27,7 +28,7 @@ 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); +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); @@ -38,7 +39,6 @@ bool command_shuffle(volatile sqlite3 *db, bool command_playid (volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr); bool command_queue_list(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_MAX]); -bool command_queue_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation); /* The playlists */ bool command_plt_create(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr); @@ -58,17 +58,9 @@ bool command_idle(struct lkt_state *srv, size_t c, struct lkt_command *cmd); /* Cancel the call to the `idle` command. */ bool command_noidle(struct lkt_state *srv, size_t c); -/* Find commands */ -enum lkt_find_action { - LKT_FND_ACT_NONE = 0, - LKT_FND_ACT_RESPOND = 1, - LKT_FND_ACT_PRINT = 2, - LKT_FND_ACT_ENQUEUE = 3, - LKT_FND_ACT_ADD = 4, -}; - /* 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, enum lkt_find_action action); +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 *)); /* 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 7494f9a21e70a520a8182a5e5fbafb017088cf79..4da2d086ac7ee9ca666078a5a341594198ef4f21 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -50,14 +50,7 @@ bool database_update_add (volatile sqlite3 *db, const char *kara_path, bool database_update_set_available(volatile sqlite3 *db, uint64_t id); /* Control the content of the queue. */ -bool database_queue_add_id (volatile sqlite3 *db, int id, int priority); -bool database_queue_add_query (volatile sqlite3 *db, const char *query, int priority); -bool database_queue_add_author (volatile sqlite3 *db, const char *author, int priority); -bool database_queue_add_language(volatile sqlite3 *db, const char *author, int priority); -bool database_queue_add_category(volatile sqlite3 *db, const char *author, int priority); -bool database_queue_add_type (volatile sqlite3 *db, const char *author, int priority); -bool database_queue_add_plt (volatile sqlite3 *db, const char *plt_name, int priority); - +bool database_queue_add_uri(volatile sqlite3 *db, struct lkt_uri *uri, int priority); bool database_queue_del_id (volatile sqlite3 *db, int id); bool database_queue_del_pos(volatile sqlite3 *db, int pos); bool database_queue_clear (volatile sqlite3 *db); @@ -73,7 +66,7 @@ bool database_queue_stop (volatile sqlite3 *db); /* A search callback to be called after each matched row */ struct lkt_callback { - bool (*call)(void *args, int id, int id_len, const char *sql_row); + bool (*call)(void *args, int pos, int pos_len, int id, int id_len, const char *sql_row); struct lkt_state *srv; size_t c; int iterations; @@ -90,19 +83,29 @@ struct lkt_search { lkt_search_database, lkt_search_playlist, lkt_search_queue, + lkt_search_sticker, } type; - void (*call)(void); /* Will be casted. */ + + void (*call)(void); /* Called during the iter phase, casted */ + struct lkt_state *srv; size_t c; - long continuation; /* Is this a continuation from a previous command? */ - int msg_count; /* How much messages we can send. */ + + long continuation; /* The continuation state of the client */ + int msg_count; /* How much messages we can send */ + const char *name; /* Stickers and playlists */ + int st_value; /* The value of a sticker */ + int st_uri; /* URI of a sticker */ }; -typedef bool (*lkt_search_database_func)(struct lkt_state *srv, size_t c, int id, int id_len, - const char *row); +typedef bool (*lkt_search_init_add_func)(volatile sqlite3 *, struct lkt_uri *, int); +typedef bool (*lkt_search_database_func)(struct lkt_state *srv, size_t c, int id, int id_len, const char *row); +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_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_iter(struct lkt_search *item); /* Next and prev operation on the queue. */ diff --git a/src/commands.c b/src/commands.c index bd3dea5d37f13c8c75cf0b095385e4e1a174d4a9..4e2b1a5b585ca60cc51a95184d2eca6f70f1671a 100644 --- a/src/commands.c +++ b/src/commands.c @@ -177,18 +177,16 @@ bool command_play(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr) { *watch_mask_ptr |= MPD_IDLE_PLAYER; - char *endptr; - long pos = 0; + char *endptr, err; + long pos = 1; /* Argument handle. */ - - pos = args[0] == NULL ? 1 : strtol(args[0], &endptr, 10); - RETURN_IF((errno == ERANGE && (pos == LONG_MAX || pos == LONG_MIN)) || (errno != 0 && pos == 0), - "Failed: strtol", false); - RETURN_IF(endptr == args[0], "No digit found", false); + if (args[0]) { + STRTOL(pos, args[0], endptr, err); + RETURN_IF(err, "STRTOL failed", false); + } /* Do the actual job here. */ - database_queue_stop(db); RETURN_UNLESS(win->new (win), "Can't create window", false); return __play_that_file(db, win, pos); @@ -198,20 +196,16 @@ bool command_playid(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr) { *watch_mask_ptr |= MPD_IDLE_PLAYER; - char *endptr; + char *endptr, err; int pos = 0; long id; /* Argument handle. */ - RETURN_IF(args[0] == NULL, "Invalid argument", false); - id = strtol(args[0], &endptr, 10); - RETURN_IF((errno == ERANGE && (id == LONG_MAX || id == LONG_MIN)) || (errno != 0 && id == 0), - "Failed: strtol", false); - RETURN_IF(endptr == args[0], "No digit found", false); + STRTOL(id, args[0], endptr, err); + RETURN_IF(err, "STRTOL failed", false); /* Do the work. */ - database_queue_stop(db); RETURN_UNLESS(win->new (win), "Can't create window", false); database_queue_seekid(db, (int) id, &pos); @@ -229,45 +223,19 @@ command_stop(volatile sqlite3 *db, struct lkt_win *win, mpd_idle_flag *watch_mas } bool -command_add(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr) +command_add(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr, int priority) { RETURN_UNLESS(args, "Invalid argument", false); *watch_mask_ptr |= MPD_IDLE_PLAYLIST; struct lkt_uri uri; char *query = args[0]; - int ret, priority = 1; /* To be modified according to the command (insert or add) later (TODO) */ - UNUSED(win); /* No callbacks to the window for the moment */ + int ret; /* To be modified according to the command (insert or add) later (TODO) */ + UNUSED(win); /* No callbacks to the window for the moment */ RETURN_UNLESS(lkt_uri_from(&uri, query), "Failed to parse query", false); - - switch (uri.type) { - case uri_query: - case uri_fs: - ret = database_queue_add_query(db, uri.value, priority); - break; - case uri_id: - ret = database_queue_add_id(db, *(int *) uri.value, priority); - break; - case uri_type: - ret = database_queue_add_type(db, (char *) uri.value, priority); - break; - case uri_category: - ret = database_queue_add_category(db, (char *) uri.value, priority); - break; - case uri_language: - ret = database_queue_add_language(db, (char *) uri.value, priority); - break; - case uri_author: - ret = database_queue_add_author(db, (char *) uri.value, priority); - break; - case uri_playlist: - ret = database_queue_add_plt(db, (char *) uri.value, priority); - break; - default: - ret = false; - break; - } - + ret = database_queue_add_uri(db, &uri, priority); lkt_uri_free(&uri); + if (!ret) + LOG_ERROR_SCT("COMMAND", "Failed to add with priority %d in queue", priority); return ret; } @@ -275,19 +243,15 @@ bool command_addid(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr) { UNUSED(win); - long id; - char *endptr, *id_str; - int priority = 1; - RETURN_UNLESS(args, "Invalid argument", false); - id_str = args[0]; - errno = 0; + long id; + char *endptr = NULL, err = 0; + struct lkt_uri uri = { .type = uri_id }; *watch_mask_ptr |= MPD_IDLE_PLAYLIST; - id = strtol(id_str, &endptr, 10); - RETURN_IF((errno == ERANGE && (id == LONG_MAX || id == LONG_MIN)) || (errno != 0 && id == 0), - "Failed: strtol", false); - RETURN_IF(endptr == args[0], "No digit found", false); - return database_queue_add_id(db, id, priority); + STRTOL(id, args[0], endptr, err); + RETURN_IF(err, "STRTOL failed", false); + uri.value = (void *) (size_t) id; + return database_queue_add_uri(db, &uri, 1); } inline bool @@ -309,15 +273,12 @@ command_delid(volatile sqlite3 *db, struct lkt_win *win, char *id_str, mpd_idle_ { UNUSED(win); long id; - char *endptr; + char *endptr = NULL, err = 0; int uri = 0; - errno = 0; *watch_mask_ptr |= MPD_IDLE_PLAYLIST; - id = strtol(id_str, &endptr, 10); - RETURN_IF((errno == ERANGE && (id == LONG_MAX || id == LONG_MIN)) || (errno != 0 && id == 0), - "Failed: strtol", false); - RETURN_IF(endptr == id_str, "No digit found", false); + STRTOL(id, id_str, endptr, err); + RETURN_IF(err, "STRTOL failed", false); /* If one day we allow suppression of the current kara, will need the `win` pointer to reload the kara in the same position (but the kara won't be @@ -331,25 +292,18 @@ bool command_move(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr) { long from, to; - char *endptr; + char *endptr, err; RETURN_UNLESS(args && args[0] && args[1], "Invalid argument", false); - errno = 0; *watch_mask_ptr |= MPD_IDLE_PLAYLIST; /* First argument: from */ - - from = strtol(args[0], &endptr, 10); - RETURN_IF((errno == ERANGE && (from == LONG_MAX || from == LONG_MIN)) || (errno != 0 && from == 0), - "Failed: strtol", false); - RETURN_IF(endptr == args[0], "No digit found", false); + STRTOL(from, args[0], endptr, err); + RETURN_IF(err, "STRTOL failed", false); /* Second argument: to */ - - to = strtol(args[1], &endptr, 10); - RETURN_IF((errno == ERANGE && (to == LONG_MAX || to == LONG_MIN)) || (errno != 0 && to == 0), - "Failed: strtol", false); - RETURN_IF(endptr == args[0], "No digit found", false); + STRTOL(to, args[1], endptr, err); + RETURN_IF(err, "STRTOL failed", false); return database_queue_move(db, from, to); } @@ -420,26 +374,18 @@ command_noidle(struct lkt_state *srv, size_t c) } /* Functions for the searchadd and the search mpd commands */ -static bool -lkt_callback_print_row_v1(struct lkt_state *srv, size_t c, int id, int id_len, const char *sql_row) -{ - UNUSED(srv); - printf(" . from client %ld:\t%*d:%s\n", c, id_len, id, sql_row); - return true; -} - -static bool -lkt_callback_send_row_v1(void *_args, int id, int id_len, const char *sql_row) +bool +lkt_callback_send_row_v1(void *_args, int pos_len, int pos, int id, int id_len, const char *sql_row) { 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 %s\n", id_len, id, sql_row); + out->data_len = 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; } -static bool +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(); @@ -448,25 +394,9 @@ lkt_callback_send_row_v2(struct lkt_state *srv, size_t c, int id, int id_len, co return true; } -static bool -lkt_callback_insert_v1(struct lkt_state *srv, size_t c, int id, int id_len, const char *sql_row) -{ - UNUSED(sql_row, id_len, c); - return database_queue_add_id(srv->db, id, 5) && - lkt_callback_send_row_v2(srv, c, id, id_len, sql_row); -} - -static bool -lkt_callback_add_v2(struct lkt_state *srv, size_t c, int id, int id_len, const char *sql_row) -{ - UNUSED(sql_row, id_len, c); - return database_queue_add_id(srv->db, id, 1) && - lkt_callback_send_row_v2(srv, c, id, id_len, sql_row); -} - -static bool -__find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation, - enum lkt_find_action action, bool(*init)(volatile sqlite3 *, char *, char *, struct lkt_search *)) +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 *)) { char rgx[PATH_MAX], *col_name, *mpd_tag; int count; @@ -475,62 +405,31 @@ __find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], lo .c = c, .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, }; /* Check args */ - RETURN_UNLESS(cmd_args && cmd_args[0], "Invalid argument", false); - /* Select callback */ - - switch (action) { - case LKT_FND_ACT_RESPOND: - search.call = (void(*)(void)) lkt_callback_send_row_v2; - break; - case LKT_FND_ACT_PRINT: - search.call = (void(*)(void)) lkt_callback_print_row_v1; - break; - case LKT_FND_ACT_ENQUEUE: - search.call = (void(*)(void)) lkt_callback_insert_v1; - srv->mpd_idle_events |= MPD_IDLE_PLAYLIST; - break; - case LKT_FND_ACT_ADD: - search.call = (void(*)(void)) lkt_callback_add_v2; - srv->mpd_idle_events |= MPD_IDLE_PLAYLIST; - break; - default: - return false; - } - /* Select the right column */ - mpd_tag = cmd_args[0]; - - if (!strcasecmp("any", mpd_tag) || - !strcasecmp("all", mpd_tag) || - !strcasecmp("a", mpd_tag)) + 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)) + } else if (!strcasecmp("author", mpd_tag)) { col_name = LKT_DATABASE_NAME_KAUTHOR; - else if (!strcasecmp("source", mpd_tag)) - col_name = LKT_DATABASE_NAME_KNAME; - else if (!strcasecmp("title", mpd_tag)) - col_name = LKT_DATABASE_NAME_KTITLE; - else if (!strcasecmp("category", mpd_tag) || !strcasecmp("cat", mpd_tag)) + } else if (!strcasecmp("category", mpd_tag) || !strcasecmp("cat", mpd_tag)) { col_name = LKT_DATABASE_NAME_KCAT; - else if (!strcasecmp("type", mpd_tag)) + } else if (!strcasecmp("type", mpd_tag)) { col_name = LKT_DATABASE_NAME_KTYPE; - else if (!strcasecmp("language", mpd_tag) || !strcasecmp("lang", mpd_tag)) + } else if (!strcasecmp("language", mpd_tag) || !strcasecmp("lang", mpd_tag)) { col_name = LKT_DATABASE_NAME_KLANG; - else if (!strcasecmp("date", mpd_tag)) - col_name = LKT_DATABASE_NAME_KAUTHOR_YEAR; - else if (!strcasecmp("id", mpd_tag)) + } else if (!strcasecmp("id", mpd_tag)) { col_name = LKT_DATABASE_NAME_KID; - else + } else return false; /* Get the regex */ - RETURN_UNLESS(cmd_args[1], "No regex", false); memset(rgx, 0, PATH_MAX * sizeof(char)); @@ -541,7 +440,6 @@ __find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], lo } /* Make the search langand do the right action */ - RETURN_UNLESS(init(srv->db, col_name, rgx, &search), "Failed to init search", false); for (count = 0; database_search_iter(&search); ++count) @@ -549,41 +447,27 @@ __find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], lo if (count) lkt_set_continuation(srv, c, continuation + count); + else + LOG_WARN_SCT("COMMAND", "%s", "Nothing found"); return true; } -bool -command_queue_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation) -{ - return __find(srv, c, cmd_args, continuation, LKT_FND_ACT_RESPOND, database_search_queue_init); -} - -bool -command_find(struct lkt_state *srv, size_t c, char *cmd_args[LKT_MESSAGE_ARGS_MAX], long continuation, - enum lkt_find_action action) -{ - return __find(srv, c, cmd_args, continuation, action, database_search_database_init); -} - bool command_set_playback_option(struct lkt_state *srv, size_t c, enum lkt_playback_option opt, char *args[LKT_MESSAGE_MAX]) { RETURN_UNLESS(srv, "Invalid argument", false); UNUSED(c); - long val, ret = false; - char *endptr; + long val; + char *endptr, ret = false; struct lkt_win *win = &srv->win; if (args == NULL || args[0] == NULL) val = 0; else { - errno = 0; - val = strtol(args[0], &endptr, 10); - RETURN_IF((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0), - "Failed: strtol", false); - RETURN_IF(endptr == args[0], "No digit found", false); + STRTOL(val, args[0], endptr, ret); + RETURN_IF(ret, "STRTOL failed", false); // No values can exceed those boundings, no matter the option // if (val < 0) @@ -668,21 +552,17 @@ end_plt_add_uri: bool command_plt_remove(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr) { - char *endptr; - long pos; - RETURN_UNLESS(args && args[0], "Invalid argument", false); + char *endptr, err; + long pos; if (args[1] == NULL) { *watch_mask_ptr |= MPD_IDLE_PLAYLIST; return database_plt_remove(db, args[0]); } - pos = strtol(args[1], &endptr, 10); - RETURN_IF((errno == ERANGE && (pos == LONG_MAX || pos == LONG_MIN)) || (errno != 0 && pos == 0), - "Failed: strtol", false); - RETURN_IF(endptr == args[1], "No digit found", false); - + STRTOL(pos, args[1], endptr, err); + RETURN_IF(err, "STRTOL failed", false); *watch_mask_ptr |= MPD_IDLE_PLAYLIST; return database_plt_remove_pos(db, args[0], pos); } @@ -755,7 +635,7 @@ command_queue_list(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_ { unsigned int from, to, tmp_switch; long val; - char *endptr, *str; + char *endptr, err, *str; struct lkt_callback callback = { .call = lkt_callback_send_row_v1, .srv = srv, @@ -765,13 +645,8 @@ command_queue_list(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_ RETURN_UNLESS(args && args[0] && strlen(args[0]), "Invalid argument", false); /* Convert the first integer. */ - errno = 0; - str = args[0] + strspn(args[0], "-+ "); // Skip not permited chars (NO NEGATIVE!) // - val = (unsigned int) strtol(str, &endptr, 0); - RETURN_IF((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0), - "Invalid argument", false); - RETURN_IF(endptr == args[0], "No digit found", false); - + STRTOL(val, args[0], endptr, err); + RETURN_IF(err, "STRTOL failed (from)", false); from = labs(val); /* There is nothing after, is is the song pos version. */ @@ -781,12 +656,9 @@ command_queue_list(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_ /* There is something after, this is the absolute forme of the command. Then parse the second value. Skip the supposed ':' character. */ else { - str = endptr + strspn(endptr, "-+: "); // NO NEGATIVE! // - val = strtol(str, &endptr, 0); - RETURN_IF((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0), - "Invalid argument", false); - RETURN_IF(endptr == args[0], "No digit found", false); - + str = endptr + strspn(endptr, "-+: "); + STRTOL(val, str, endptr, err); + RETURN_IF(err, "STRTOL failed (to)", false); to = labs(val); if (to < from) { @@ -809,9 +681,11 @@ only_one: /* The command is used with a range specifier. */ is_a_range: if (to - from + 1 < lkt_remaining_msg(srv, c) - 2) { + LOG_INFO_SCT("COMMAND", "Got range %d:%d, no continuation needed", from, to); lkt_set_continuation(srv, c, 0); return database_queue_list(srv->db, from, to, &callback); } else { + LOG_INFO_SCT("COMMAND", "Got range %d:%d, continuation needed", from, to); to = from + lkt_remaining_msg(srv, c) - 3; lkt_set_continuation(srv, c, to + 1); return database_queue_list(srv->db, from, to, &callback); @@ -922,14 +796,16 @@ 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 = atoi(argv[1]); /* FIXME: Use strtol. */ + int uri, err; + char *endptr; + STRTOL(uri, argv[1], endptr, err); + RETURN_IF(err, "STRTOL failed", false); struct sticker_callback cb = { .srv = srv, .c = c, .call = sticker_send_one_value, }; - RETURN_UNLESS(database_sticker_get(srv->db, argv[0], argv[2], uri, &cb), "Failed to get sticker", - false); + RETURN_UNLESS(database_sticker_get(srv->db, argv[0], argv[2], uri, &cb), "Failed to get sticker", false); return true; } @@ -938,8 +814,11 @@ command_sticker_set(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS { UNUSED(c); RETURN_UNLESS(argv[0] && argv[1] && argv[2] && argv[3] && !argv[4], "Invalid argument", false); - int uri = atoi(argv[1]); /* FIXME: Use strtol. */ - int value = atoi(argv[4]); /* FIXME: Use strtol. */ + int uri, value, err1, err2; + char *endptr; + STRTOL(uri, argv[1], endptr, err1); + STRTOL(value, argv[4], endptr, err2); + RETURN_IF(err1 || err2, "STRTOL failed", false); 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; diff --git a/src/database/find.c b/src/database/find.c index 9956610cdab7b533234b3cfa46a2280f3910ecf0..c95a2374aa30b9ff2ad2c5716b0f00da61c56889 100644 --- a/src/database/find.c +++ b/src/database/find.c @@ -3,6 +3,7 @@ #include <common/common.h> #include <lektor/database.h> +#include <strings.h> #include <limits.h> #include <stdio.h> #include <string.h> @@ -18,20 +19,54 @@ database_search_database_init(volatile sqlite3 *db, char *col_name, char *rgx, s "SELECT id, any_col, (SELECT MAX(len) FROM content)" "FROM content LIMIT %d OFFSET %d;"; char SQL_STMT[LKT_MAX_SQLITE_STATEMENT]; + 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; SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, ret->stmt, 1, rgx, error); ret->db = db; - /* Assign the callback. */ return true; error: sqlite3_finalize(ret->stmt); return false; } +bool +database_search_sticker_init(volatile sqlite3 *db, char *type, char *name, 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'" + " UNION" + " SELECT id, sticker, value FROM 'stickers.plt'" + ") AS sts" + "ON sts.sticker = 'stickers'.id"; + static const char *SQL_one_type = + "SELECT name, 'stickers.%s'.id, value " + "FROM 'stickers' " + "LEFT OUTER JOIN 'stickers' " + "ON 'stickers'.id = 'stickers.%s'.sticker"; + static const char *SQL_check_name = " AND name = ?;"; + char SQL[LKT_MAX_SQLITE_STATEMENT]; + + if (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 : ";"); + + SQLITE_PREPARE(db, ret->stmt, SQL, error); + if (name) + SQLITE_BIND_TEXT(db, ret->stmt, 1, name, error) + return true; +error: + sqlite3_finalize(ret->stmt); + return false; +} bool database_search_queue_init(volatile sqlite3 *db, char *col_name, char *rgx, struct lkt_search *ret) @@ -46,14 +81,15 @@ database_search_queue_init(volatile sqlite3 *db, char *col_name, char *rgx, stru "SELECT id, any_col, (SELECT MAX(len) FROM content)" "FROM content LIMIT %d OFFSET %d;"; char SQL_STMT[LKT_MAX_SQLITE_STATEMENT]; + 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; SQLITE_PREPARE(db, ret->stmt, SQL_STMT, error); SQLITE_BIND_TEXT(db, ret->stmt, 1, rgx, error); ret->db = db; - /* Assign the callback. */ return true; error: sqlite3_finalize(ret->stmt); @@ -65,16 +101,17 @@ database_search_iter(struct lkt_search *item) { const char *sql_row; int id, code, id_len; - - code = sqlite3_step(item->stmt); - RETURN_UNLESS(item, "Exit because item is NULL, end iterations", false); + GOTO_UNLESS(item->call, "Call function is NULL, terminate the search", end); + code = sqlite3_step(item->stmt); if (code == SQLITE_DONE) - goto error_or_done; + goto end; - if (code != SQLITE_ROW) - goto error; + if (code != SQLITE_ROW) { + LOG_ERROR_SCT("DB", "Step failed, expected a ROW or a DONE: %s", sqlite3_errmsg((sqlite3 *) item->db)); + goto end; + } switch (item->type) { case lkt_search_database: @@ -83,14 +120,17 @@ database_search_iter(struct lkt_search *item) 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); + 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); case lkt_search_playlist: default: - goto error; + LOG_WARN_SCT("DB", "Search operation %d is not implemented", item->type); + goto end; } -error: - LOG_ERROR_SCT("DB", "sqlite3_step failed: %s", sqlite3_errmsg((sqlite3 *) item->db)); -error_or_done: +end: sqlite3_finalize(item->stmt); return false; } diff --git a/src/database/queue.c b/src/database/queue.c index a8bf8a55a43b2bbc35a200e051b169aaaa37d76e..c936b1fccc79cdb696268487faf1455c7eb08605 100644 --- a/src/database/queue.c +++ b/src/database/queue.c @@ -106,15 +106,13 @@ queue_add_with_col_like_str(volatile sqlite3 *db, const char *col, const char *v " );" /* Separate karas that are after the current one */ "INSERT INTO queue_tmp (kara_id, priority)" - " SELECT kara_id, priority" - " FROM queue" - " WHERE position > " CURRENT_POS_OR_0 ";" + " SELECT kara_id, priority FROM queue WHERE position > " CURRENT_POS_OR_0 + " ORDER BY priority DESC, position ASC;" "DELETE FROM queue WHERE position > " CURRENT_POS_OR_0 ";" /* Insert back */ "INSERT INTO queue (position, kara_id, priority)" " SELECT position + " CURRENT_POS_OR_0 ", kara_id, priority" - " FROM queue_tmp" - " ORDER BY priority, position;" + " FROM queue_tmp;" /* Drop temporary tables */ "DROP TABLE queue_tmp;" "DELETE FROM sqlite_sequence WHERE name = 'queue_tmp';"; @@ -137,8 +135,10 @@ queue_add_with_col_like_str(volatile sqlite3 *db, const char *col, const char *v sqlite3_finalize(stmt); /* Reorder kara that are after the current one, do this shit only if priority > 1... */ - if (priority > 1) + if (priority > 1) { SQLITE_EXEC(db, SQL_REORDER, error); + LOG_INFO_SCT("DB", "%s", "Queue has been reordered"); + } /* End */ SQLITE_EXEC(db, "COMMIT;", error); @@ -172,13 +172,14 @@ database_queue_add_plt(volatile sqlite3 *db, const char *plt_name, int priority) " , priority INTEGER NOT NULL DEFAULT 1 CHECK(priority > 0 AND priority < 6)" " );" /* Separate karas that are after the current one */ - "INSERT INTO queue_tmp (kara_id, priority) SELECT kara_id, priority FROM queue WHERE position > " CURRENT_POS_OR_0 ";" + "INSERT INTO queue_tmp (kara_id, priority)" + " SELECT kara_id, priority FROM queue WHERE position > " CURRENT_POS_OR_0 + " ORDER BY priority DESC, position ASC;" "DELETE FROM queue WHERE position > " CURRENT_POS_OR_0 ";" /* Insert back */ "INSERT INTO queue (position, kara_id, priority)" " SELECT position + " CURRENT_POS_OR_0 ", kara_id, priority" - " FROM queue_tmp" - " ORDER BY priority, position;" + " FROM queue_tmp;" /* Drop temporary tables */ "DROP TABLE queue_tmp;" "DELETE FROM sqlite_sequence WHERE name = 'queue_tmp';"; @@ -207,22 +208,6 @@ error: return false; } -#define database_queue_add(suffix, column_name) \ - bool \ - database_queue_add_ ## suffix (volatile sqlite3 *db, const char *query, int priority) \ - { \ - bool status = queue_add_with_col_like_str(db, column_name, query, priority); \ - LOG_INFO("%s " #suffix " '%s' with priority of %d", \ - status ? "Successfully added" : "Failed to add", query, priority); \ - return status; \ - } -database_queue_add(query, LKT_DATABASE_KARA_ALL) -database_queue_add(author, LKT_DATABASE_NAME_KAUTHOR) -database_queue_add(language, LKT_DATABASE_NAME_KLANG) -database_queue_add(category, LKT_DATABASE_NAME_KCAT) -database_queue_add(type, LKT_DATABASE_NAME_KTYPE) -#undef database_queue_add - bool database_queue_add_id(volatile sqlite3 *db, int id, int priority) { @@ -239,6 +224,31 @@ error: return status; } +bool +database_queue_add_uri(volatile sqlite3 *db, struct lkt_uri *uri, int priority) +{ + switch (uri->type) { + case uri_query: + case uri_fs: + return queue_add_with_col_like_str(db, LKT_DATABASE_KARA_ALL, uri->value, priority); + case uri_id: + return database_queue_add_id(db, *(int *) uri->value, priority); + case uri_type: + return queue_add_with_col_like_str(db, LKT_DATABASE_NAME_KTYPE, uri->value, priority); + case uri_category: + return queue_add_with_col_like_str(db, LKT_DATABASE_NAME_KCAT, uri->value, priority); + case uri_language: + return queue_add_with_col_like_str(db, LKT_DATABASE_NAME_KLANG, uri->value, priority); + case uri_author: + return queue_add_with_col_like_str(db, LKT_DATABASE_NAME_KAUTHOR, uri->value, priority); + case uri_playlist: + return database_queue_add_plt(db, (char *) uri->value, priority); + default: + LOG_WARN_SCT("DB", "Add to queue for uri of type %d is not implemented", uri->type); + return false; + } +} + bool database_queue_del_id(volatile sqlite3 *db, int id) { @@ -582,13 +592,13 @@ database_queue_list(volatile sqlite3 *db, size_t from, size_t to, struct lkt_cal { const char *SQL_STMT = "WITH content AS (" - " SELECT kara.id AS id, string, LENGTH(CAST(kara.id AS TEXT)) AS len" + " SELECT kara.id AS id, string, LENGTH(CAST(kara.id AS TEXT)) AS len, position, LENGTH(CAST(position AS TEXT)) AS pos_len" " FROM queue" " JOIN kara ON kara_id = kara.id" " WHERE position >= ? AND position <= ?" " GROUP BY position ORDER BY position ASC, priority DESC)" - "SELECT id, string, (SELECT MAX(len) FROM content) FROM content;"; - int code, id, id_len; + "SELECT id, string, (SELECT MAX(len) FROM content), position, (SELECT MAX(pos_len) FROM content) FROM content;"; + int code, id, id_len, pos, pos_len; const char *row; bool ret = false; sqlite3_stmt *stmt; @@ -600,13 +610,14 @@ database_queue_list(volatile sqlite3 *db, size_t from, size_t to, struct lkt_cal for (;;) { code = sqlite3_step(stmt); - if (code == SQLITE_ROW) { id = sqlite3_column_int(stmt, 0); row = (const char *) sqlite3_column_text(stmt, 1); id_len = sqlite3_column_int(stmt, 2); + pos = sqlite3_column_int(stmt, 3); + pos_len = sqlite3_column_int(stmt, 4); ++(callback->iterations); - if (callback->call(callback, id, id_len, row)) + if (callback->call(callback, pos_len, pos, id, id_len, row)) continue; else break; @@ -615,8 +626,10 @@ database_queue_list(volatile sqlite3 *db, size_t from, size_t to, struct lkt_cal else if (code == SQLITE_OK || code == SQLITE_DONE) goto done; - else + else { + LOG_ERROR_SCT("DB", "Failed: %s", sqlite3_errmsg((sqlite3 *) db)); break; + } } done: diff --git a/src/main/lkt.c b/src/main/lkt.c index a3230844dd5b6ad15864405a3c37e4cfabbc03ea..ea03894d8bd2574d6c0eb9acca7b65c1d0bafae6 100644 --- a/src/main/lkt.c +++ b/src/main/lkt.c @@ -63,6 +63,7 @@ lkt_valid_type(const char *type) { return (STR_MATCH(type, "all") || STR_MATCH(type, "any") || + STR_MATCH(type, "query") || STR_MATCH(type, "id") || STR_MATCH(type, "title") || STR_MATCH(type, "type") || @@ -510,32 +511,39 @@ 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) { char buff[3]; - int i; - - if (args->argc < 1) - fail("Invalid argument, the add command should takes at least two arguments: queue add <query>"); - - if (!lkt_valid_type(args->argv[0])) - fail("Invalid argument, the type given to the add command is invalid"); - + fail_if(args->argc < 1, "Invalid arguments"); + fail_if(!lkt_valid_type(args->argv[0]), "Invalid query type"); FILE *sock = lkt_connect(); + send_cmd_with_uri(sock, "add", args->argc, args->argv); + exit_with_status(sock, buff); +} - (void) write_socket(sock, "add ", 4 * sizeof(char)); - (void) write_socket(sock, args->argv[0], strlen(args->argv[0])); - (void) write_socket(sock, "://", 3 * 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)); +noreturn void +queue_insert__(struct lkt_cmd_args *args) +{ + char buff[3]; + fail_if(args->argc < 1, "Invalid arguments"); + fail_if(!lkt_valid_type(args->argv[0]), "Invalid query type"); + FILE *sock = lkt_connect(); + send_cmd_with_uri(sock, "__insert", args->argc, args->argv); exit_with_status(sock, buff); } @@ -791,8 +799,6 @@ redo: #define search_with_cmd(func, cmd) /* I don't want to write always the same things */ \ noreturn void func (struct lkt_cmd_args *args) { search_with_cmd__(args, #cmd); } search_with_cmd(search_get__, search) -search_with_cmd(search_add__, searchadd) -search_with_cmd(search_insert__, __insert) search_with_cmd(search_plt__, listplaylist) search_with_cmd(search_count__, count) search_with_cmd(search_queue__, playlistfind) @@ -801,6 +807,7 @@ search_with_cmd(search_queue__, playlistfind) /* Parsing stuff. */ static struct lkt_cmd_opt options_queue[] = { + { .name = "insert", .call = queue_insert__ }, { .name = "pos", .call = queue_pos__ }, { .name = "pop", .call = queue_pop__ }, { .name = "add", .call = queue_add__ }, @@ -821,8 +828,6 @@ static struct lkt_cmd_opt options_plt[] = { static struct lkt_cmd_opt options_search[] = { { .name = "get", .call = search_get__ }, - { .name = "add", .call = search_add__ }, - { .name = "insert", .call = search_insert__ }, { .name = "plt", .call = search_plt__ }, { .name = "count", .call = search_count__ }, { .name = "queue", .call = search_queue__ }, diff --git a/src/net/listen.c b/src/net/listen.c index 23d4fddf2cb64900788e5dbca88b132ba662518b..0aa570f4ab740bf10aa4c14bf05b84976c4a90cb 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -197,7 +197,7 @@ 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, "playlistfind") || !strcmp(cmd.name, "playlistsearch")) - err = ! command_queue_find(srv, c, cmd.args, cmd.cont); + 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")) @@ -213,8 +213,10 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) else if (!strcmp(cmd.name, "help")) err = !command_help(srv, c); - else if (!strcmp(cmd.name, "add")) - err = !command_add((sqlite3 *) srv->db, &srv->win, cmd.args, &srv->mpd_idle_events); + else if (!strcmp(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")) + err = !command_add((sqlite3 *) srv->db, &srv->win, cmd.args, &srv->mpd_idle_events, 1); else if (!strcmp(cmd.name, "addid")) err = !command_addid((sqlite3 *) srv->db, &srv->win, cmd.args, &srv->mpd_idle_events); else if (!strcmp(cmd.name, "deleteid")) @@ -253,14 +255,8 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd) else if (!strcmp(cmd.name, "idle")) { err = !command_idle(srv, c, &cmd); goto end_no_send_status; - } else if (!strcmp(cmd.name, "searchadd") || - !strcmp(cmd.name, "findadd")) - err = ! command_find(srv, c, cmd.args, cmd.cont, LKT_FND_ACT_ADD); - else if (!strcmp(cmd.name, "search") || - !strcmp(cmd.name, "find")) - err = ! command_find(srv, c, cmd.args, cmd.cont, LKT_FND_ACT_RESPOND); - else if (!strcmp(cmd.name, "__insert")) - err = ! command_find(srv, c, cmd.args, cmd.cont, LKT_FND_ACT_ENQUEUE); + } else if (!strcmp(cmd.name, "search") || !strcmp(cmd.name, "find")) + err = ! command_find(srv, c, cmd.args, cmd.cont, database_search_database_init); else err = 2; @@ -391,7 +387,7 @@ handle_outgoing_data(struct lkt_state *srv, size_t c) for (size_t i = 0; i < cli->buffer_out_len; i++) { struct lkt_message *msg = cli->buffer_out[i]; - int n = send(srv->fds[c].fd, msg->data, msg->data_len, 0); + int n = send(srv->fds[c].fd, msg->data, msg->data_len, MSG_NOSIGNAL); if (n <= 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) { cli->buffer_out_len -= i; @@ -399,6 +395,10 @@ handle_outgoing_data(struct lkt_state *srv, size_t c) cli->buffer_out_len); return 0; } + if (errno == EPIPE) { + LOG_WARN_SCT("NETWORK", "Client %ld is out, free all its messages", c); + handle_disconnected_client(srv, i); + } return -1; }