X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fmpdclient.c;h=1801ad2dc7973b94e927131f5bdd1c3a95127f7d;hb=911d7e95dc5f469938a6d06786f7c6651df02e17;hp=7bf29ea921e20dbda7aae906e7754aaf979e1f20;hpb=0796b270b1699336f29908d11bca92d64da0653c;p=ncmpc.git diff --git a/src/mpdclient.c b/src/mpdclient.c index 7bf29ea..1801ad2 100644 --- a/src/mpdclient.c +++ b/src/mpdclient.c @@ -1,63 +1,130 @@ /* ncmpc (Ncurses MPD Client) - * (c) 2004-2010 The Music Player Daemon Project + * (c) 2004-2017 The Music Player Daemon Project * Project homepage: http://musicpd.org - + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ + */ #include "mpdclient.h" +#include "callbacks.h" #include "filelist.h" -#include "screen_client.h" #include "config.h" -#include "options.h" -#include "strfsong.h" -#include "utils.h" #include "gidle.h" +#include "charset.h" + +#ifdef ENABLE_ASYNC_CONNECT +#include "aconnect.h" +#endif #include -#include -#include -#include -#include +#include -#define BUFSIZE 1024 +static gboolean +mpdclient_enter_idle_callback(gpointer user_data) +{ + struct mpdclient *c = user_data; + assert(c->enter_idle_source_id != 0); + assert(c->source != NULL); + assert(!c->idle); -/* sort by list-format */ -gint -compare_filelistentry_format(gconstpointer filelist_entry1, - gconstpointer filelist_entry2) + c->enter_idle_source_id = 0; + c->idle = mpd_glib_enter(c->source); + return false; +} + +static void +mpdclient_schedule_enter_idle(struct mpdclient *c) { - const struct mpd_entity *e1, *e2; - char key1[BUFSIZE], key2[BUFSIZE]; - int n = 0; + assert(c != NULL); + assert(c->source != NULL); - e1 = ((const struct filelist_entry *)filelist_entry1)->entity; - e2 = ((const struct filelist_entry *)filelist_entry2)->entity; + if (c->enter_idle_source_id == 0) + /* automatically re-enter MPD "idle" mode */ + c->enter_idle_source_id = + g_idle_add(mpdclient_enter_idle_callback, c); +} - if (e1 && e2 && - mpd_entity_get_type(e1) == MPD_ENTITY_TYPE_SONG && - mpd_entity_get_type(e2) == MPD_ENTITY_TYPE_SONG) { - strfsong(key1, BUFSIZE, options.list_format, mpd_entity_get_song(e1)); - strfsong(key2, BUFSIZE, options.list_format, mpd_entity_get_song(e2)); - n = strcmp(key1,key2); +static void +mpdclient_cancel_enter_idle(struct mpdclient *c) +{ + if (c->enter_idle_source_id != 0) { + g_source_remove(c->enter_idle_source_id); + c->enter_idle_source_id = 0; } +} + +static void +mpdclient_invoke_error_callback(enum mpd_error error, + const char *message) +{ + char *allocated; + if (error == MPD_ERROR_SERVER) + /* server errors are UTF-8, the others are locale */ + message = allocated = utf8_to_locale(message); + else + allocated = NULL; + + mpdclient_error_callback(message); + g_free(allocated); +} + +static void +mpdclient_invoke_error_callback1(struct mpdclient *c) +{ + assert(c != NULL); + assert(c->connection != NULL); + + struct mpd_connection *connection = c->connection; + + enum mpd_error error = mpd_connection_get_error(connection); + assert(error != MPD_ERROR_SUCCESS); - return n; + mpdclient_invoke_error_callback(error, + mpd_connection_get_error_message(connection)); } +static void +mpdclient_gidle_callback(enum mpd_error error, + gcc_unused enum mpd_server_error server_error, + const char *message, enum mpd_idle events, + void *ctx) +{ + struct mpdclient *c = ctx; + + c->idle = false; + + assert(mpdclient_is_connected(c)); + + if (error != MPD_ERROR_SUCCESS) { + mpdclient_invoke_error_callback(error, message); + mpdclient_disconnect(c); + mpdclient_lost_callback(); + return; + } + + c->events |= events; + mpdclient_update(c); + + mpdclient_idle_callback(c->events); + + c->events = 0; + + if (c->source != NULL) + mpdclient_schedule_enter_idle(c); +} /****************************************************************************/ /*** mpdclient functions ****************************************************/ @@ -72,33 +139,70 @@ mpdclient_handle_error(struct mpdclient *c) if (error == MPD_ERROR_SERVER && mpd_connection_get_server_error(c->connection) == MPD_SERVER_ERROR_PERMISSION && - screen_auth(c)) + mpdclient_auth_callback(c)) return true; - mpdclient_ui_error(mpd_connection_get_error_message(c->connection)); + mpdclient_invoke_error_callback(error, + mpd_connection_get_error_message(c->connection)); - if (!mpd_connection_clear_error(c->connection)) + if (!mpd_connection_clear_error(c->connection)) { mpdclient_disconnect(c); + mpdclient_lost_callback(); + } return false; } +#ifdef ENABLE_ASYNC_CONNECT +#ifndef WIN32 + static bool -mpdclient_finish_command(struct mpdclient *c) +is_local_socket(const char *host) { - return mpd_response_finish(c->connection) - ? true : mpdclient_handle_error(c); + return *host == '/' || *host == '@'; } +static bool +settings_is_local_socket(const struct mpd_settings *settings) +{ + const char *host = mpd_settings_get_host(settings); + return host != NULL && is_local_socket(host); +} + +#endif +#endif + struct mpdclient * -mpdclient_new(void) +mpdclient_new(const gchar *host, unsigned port, + unsigned timeout_ms, const gchar *password) { - struct mpdclient *c; + struct mpdclient *c = g_new0(struct mpdclient, 1); + +#ifdef ENABLE_ASYNC_CONNECT + c->settings = mpd_settings_new(host, port, timeout_ms, + NULL, NULL); + if (c->settings == NULL) + g_error("Out of memory"); + +#ifndef WIN32 + c->settings2 = host == NULL && port == 0 && + settings_is_local_socket(c->settings) + ? mpd_settings_new(host, 6600, timeout_ms, NULL, NULL) + : NULL; +#endif + +#else + c->host = host; + c->port = port; +#endif + + c->timeout_ms = timeout_ms; + c->password = password; - c = g_new0(struct mpdclient, 1); playlist_init(&c->playlist); c->volume = -1; c->events = 0; + c->playing = false; return c; } @@ -110,25 +214,94 @@ mpdclient_free(struct mpdclient *c) mpdclient_playlist_free(&c->playlist); +#ifdef ENABLE_ASYNC_CONNECT + mpd_settings_free(c->settings); + +#ifndef WIN32 + if (c->settings2 != NULL) + mpd_settings_free(c->settings2); +#endif +#endif + g_free(c); } +static char * +settings_name(const struct mpd_settings *settings) +{ + assert(settings != NULL); + + const char *host = mpd_settings_get_host(settings); + if (host == NULL) + host = "unknown"; + + if (host[0] == '/') + return g_strdup(host); + + unsigned port = mpd_settings_get_port(settings); + if (port == 0 || port == 6600) + return g_strdup(host); + + return g_strdup_printf("%s:%u", host, port); +} + +char * +mpdclient_settings_name(const struct mpdclient *c) +{ + assert(c != NULL); + +#ifdef ENABLE_ASYNC_CONNECT + return settings_name(c->settings); +#else + struct mpd_settings *settings = + mpd_settings_new(c->host, c->port, 0, NULL, NULL); + if (settings == NULL) + return g_strdup("unknown"); + + char *name = settings_name(settings); + mpd_settings_free(settings); + return name; +#endif +} + +static void +mpdclient_status_free(struct mpdclient *c) +{ + if (c->status == NULL) + return; + + mpd_status_free(c->status); + c->status = NULL; + + c->volume = -1; + c->playing = false; +} + void mpdclient_disconnect(struct mpdclient *c) { +#ifdef ENABLE_ASYNC_CONNECT + if (c->async_connect != NULL) { + aconnect_cancel(c->async_connect); + c->async_connect = NULL; + } +#endif + + mpdclient_cancel_enter_idle(c); + if (c->source != NULL) { mpd_glib_free(c->source); c->source = NULL; c->idle = false; } - if (c->connection) + if (c->connection) { mpd_connection_free(c->connection); + ++c->connection_id; + } c->connection = NULL; - if (c->status) - mpd_status_free(c->status); - c->status = NULL; + mpdclient_status_free(c); playlist_clear(&c->playlist); @@ -136,90 +309,163 @@ mpdclient_disconnect(struct mpdclient *c) c->song = NULL; /* everything has changed after a disconnect */ - c->events |= MPD_IDLE_DATABASE|MPD_IDLE_STORED_PLAYLIST| - MPD_IDLE_QUEUE|MPD_IDLE_PLAYER|MPD_IDLE_MIXER|MPD_IDLE_OUTPUT| - MPD_IDLE_OPTIONS|MPD_IDLE_UPDATE; + c->events |= MPD_IDLE_ALL; } -bool -mpdclient_connect(struct mpdclient *c, - const gchar *host, - gint port, - gfloat _timeout, - const gchar *password) +static bool +mpdclient_connected(struct mpdclient *c, + struct mpd_connection *connection) { - /* close any open connection */ - if( c->connection ) - mpdclient_disconnect(c); + c->connection = connection; - /* connect to MPD */ - c->connection = mpd_connection_new(host, port, _timeout * 1000); - if (c->connection == NULL) - g_error("Out of memory"); - - if (mpd_connection_get_error(c->connection) != MPD_ERROR_SUCCESS) { - mpdclient_handle_error(c); + if (mpd_connection_get_error(connection) != MPD_ERROR_SUCCESS) { + mpdclient_invoke_error_callback1(c); mpdclient_disconnect(c); + mpdclient_failed_callback(); return false; } +#ifdef ENABLE_ASYNC_CONNECT + if (c->timeout_ms > 0) + mpd_connection_set_timeout(connection, c->timeout_ms); +#endif + /* send password */ - if (password != NULL && !mpd_run_password(c->connection, password)) { - mpdclient_handle_error(c); + if (c->password != NULL && + !mpd_run_password(connection, c->password)) { + mpdclient_invoke_error_callback1(c); mpdclient_disconnect(c); + mpdclient_failed_callback(); return false; } + c->source = mpd_glib_new(connection, + mpdclient_gidle_callback, c); + mpdclient_schedule_enter_idle(c); + + ++c->connection_id; + + mpdclient_connected_callback(); return true; } +#ifdef ENABLE_ASYNC_CONNECT + +static void +mpdclient_aconnect_start(struct mpdclient *c, + const struct mpd_settings *settings); + +static const struct mpd_settings * +mpdclient_get_settings(const struct mpdclient *c) +{ +#ifndef WIN32 + if (c->connecting2) + return c->settings2; +#endif + + return c->settings; +} + +static void +mpdclient_connect_success(struct mpd_connection *connection, void *ctx) +{ + struct mpdclient *c = ctx; + assert(c->async_connect != NULL); + c->async_connect = NULL; + + const char *password = + mpd_settings_get_password(mpdclient_get_settings(c)); + if (password != NULL && !mpd_run_password(connection, password)) { + mpdclient_error_callback(mpd_connection_get_error_message(connection)); + mpd_connection_free(connection); + mpdclient_failed_callback(); + return; + } + + mpdclient_connected(c, connection); +} + +static void +mpdclient_connect_error(const char *message, void *ctx) +{ + struct mpdclient *c = ctx; + assert(c->async_connect != NULL); + c->async_connect = NULL; + +#ifndef WIN32 + if (!c->connecting2 && c->settings2 != NULL) { + c->connecting2 = true; + mpdclient_aconnect_start(c, c->settings2); + return; + } +#endif + + mpdclient_error_callback(message); + mpdclient_failed_callback(); +} + +static const struct aconnect_handler mpdclient_connect_handler = { + .success = mpdclient_connect_success, + .error = mpdclient_connect_error, +}; + +static void +mpdclient_aconnect_start(struct mpdclient *c, + const struct mpd_settings *settings) +{ + aconnect_start(&c->async_connect, + mpd_settings_get_host(settings), + mpd_settings_get_port(settings), + &mpdclient_connect_handler, c); +} + +#endif + +void +mpdclient_connect(struct mpdclient *c) +{ + /* close any open connection */ + mpdclient_disconnect(c); + +#ifdef ENABLE_ASYNC_CONNECT +#ifndef WIN32 + c->connecting2 = false; +#endif + mpdclient_aconnect_start(c, c->settings); +#else + /* connect to MPD */ + struct mpd_connection *connection = + mpd_connection_new(c->host, c->port, c->timeout_ms); + if (connection == NULL) + g_error("Out of memory"); + + mpdclient_connected(c, connection); +#endif +} + bool mpdclient_update(struct mpdclient *c) { struct mpd_connection *connection = mpdclient_get_connection(c); - c->volume = -1; - if (connection == NULL) return false; - /* always announce these options as long as we don't have - "idle" support */ - if (c->source == NULL) - c->events |= MPD_IDLE_PLAYER|MPD_IDLE_OPTIONS; - /* free the old status */ - if (c->status) - mpd_status_free(c->status); + mpdclient_status_free(c); /* retrieve new status */ c->status = mpd_run_status(connection); if (c->status == NULL) return mpdclient_handle_error(c); - if (c->source == NULL && - c->update_id != mpd_status_get_update_id(c->status)) { - c->events |= MPD_IDLE_UPDATE; - - if (c->update_id > 0) - c->events |= MPD_IDLE_DATABASE; - } - - c->update_id = mpd_status_get_update_id(c->status); - - if (c->source == NULL && - c->volume != mpd_status_get_volume(c->status)) - c->events |= MPD_IDLE_MIXER; - c->volume = mpd_status_get_volume(c->status); + c->playing = mpd_status_get_state(c->status) == MPD_STATE_PLAY; /* check if the playlist needs an update */ if (c->playlist.version != mpd_status_get_queue_version(c->status)) { bool retval; - if (c->source == NULL) - c->events |= MPD_IDLE_QUEUE; - if (!playlist_is_empty(&c->playlist)) retval = mpdclient_playlist_update_changes(c); else @@ -243,29 +489,20 @@ mpdclient_get_connection(struct mpdclient *c) if (c->source != NULL && c->idle) { c->idle = false; mpd_glib_leave(c->source); + + if (c->source != NULL) + mpdclient_schedule_enter_idle(c); } return c->connection; } -void -mpdclient_put_connection(struct mpdclient *c) -{ - assert(c->source == NULL || c->connection != NULL); - - if (c->source != NULL && !c->idle) { - c->idle = mpd_glib_enter(c->source); - } -} - static struct mpd_status * mpdclient_recv_status(struct mpdclient *c) { - struct mpd_status *status; - assert(c->connection != NULL); - status = mpd_recv_status(c->connection); + struct mpd_status *status = mpd_recv_status(c->connection); if (status == NULL) { mpdclient_handle_error(c); return NULL; @@ -283,32 +520,24 @@ mpdclient_recv_status(struct mpdclient *c) bool mpdclient_cmd_crop(struct mpdclient *c) { - struct mpd_connection *connection; - int length, current; - if (!mpdclient_is_playing(c)) return false; - length = mpd_status_get_queue_length(c->status); - current = mpd_status_get_song_pos(c->status); + int length = mpd_status_get_queue_length(c->status); + int current = mpd_status_get_song_pos(c->status); if (current < 0 || mpd_status_get_queue_length(c->status) < 2) return true; - connection = mpdclient_get_connection(c); + struct mpd_connection *connection = mpdclient_get_connection(c); if (connection == NULL) return false; mpd_command_list_begin(connection, false); - if (mpd_connection_cmp_server_version(connection, 0, 16, 0) >= 0) { - if (current < length - 1) - mpd_send_delete_range(connection, current + 1, length); - if (current > 0) - mpd_send_delete_range(connection, 0, current); - } else - while (--length >= 0) - if (length != current) - mpd_send_delete(connection, length); + if (current < length - 1) + mpd_send_delete_range(connection, current + 1, length); + if (current > 0) + mpd_send_delete_range(connection, 0, current); mpd_command_list_end(connection); @@ -319,8 +548,6 @@ bool mpdclient_cmd_clear(struct mpdclient *c) { struct mpd_connection *connection = mpdclient_get_connection(c); - struct mpd_status *status; - if (connection == NULL) return false; @@ -333,7 +560,7 @@ mpdclient_cmd_clear(struct mpdclient *c) /* receive the new status, store it in the mpdclient struct */ - status = mpdclient_recv_status(c); + struct mpd_status *status = mpdclient_recv_status(c); if (status == NULL) return false; @@ -348,6 +575,7 @@ mpdclient_cmd_clear(struct mpdclient *c) reducing the UI latency */ playlist_clear(&c->playlist); c->playlist.version = mpd_status_get_queue_version(status); + c->song = NULL; } c->events |= MPD_IDLE_QUEUE; @@ -368,39 +596,26 @@ mpdclient_cmd_volume(struct mpdclient *c, gint value) bool mpdclient_cmd_volume_up(struct mpdclient *c) { + if (c->volume < 0 || c->volume >= 100) + return true; + struct mpd_connection *connection = mpdclient_get_connection(c); if (connection == NULL) return false; - if (c->status == NULL || - mpd_status_get_volume(c->status) == -1) - return true; - - if (c->volume < 0) - c->volume = mpd_status_get_volume(c->status); - - if (c->volume >= 100) - return true; - return mpdclient_cmd_volume(c, ++c->volume); } bool mpdclient_cmd_volume_down(struct mpdclient *c) { + if (c->volume <= 0) + return true; + struct mpd_connection *connection = mpdclient_get_connection(c); if (connection == NULL) return false; - if (c->status == NULL || mpd_status_get_volume(c->status) < 0) - return true; - - if (c->volume < 0) - c->volume = mpd_status_get_volume(c->status); - - if (c->volume <= 0) - return true; - return mpdclient_cmd_volume(c, --c->volume); } @@ -411,20 +626,17 @@ mpdclient_cmd_add_path(struct mpdclient *c, const gchar *path_utf8) if (connection == NULL) return false; - mpd_send_add(connection, path_utf8); - return mpdclient_finish_command(c); + return mpd_send_add(connection, path_utf8)? + mpdclient_finish_command(c) : false; } bool mpdclient_cmd_add(struct mpdclient *c, const struct mpd_song *song) { - struct mpd_connection *connection = mpdclient_get_connection(c); - struct mpd_status *status; - struct mpd_song *new_song; - assert(c != NULL); assert(song != NULL); + struct mpd_connection *connection = mpdclient_get_connection(c); if (connection == NULL || c->status == NULL) return false; @@ -443,14 +655,14 @@ mpdclient_cmd_add(struct mpdclient *c, const struct mpd_song *song) c->events |= MPD_IDLE_QUEUE; - status = mpdclient_recv_status(c); + struct mpd_status *status = mpdclient_recv_status(c); if (status == NULL) return false; if (!mpd_response_next(connection)) return mpdclient_handle_error(c); - new_song = mpd_recv_song(connection); + struct mpd_song *new_song = mpd_recv_song(connection); if (!mpd_response_finish(connection) || new_song == NULL) { if (new_song != NULL) mpd_song_free(new_song); @@ -480,8 +692,6 @@ bool mpdclient_cmd_delete(struct mpdclient *c, gint idx) { struct mpd_connection *connection = mpdclient_get_connection(c); - const struct mpd_song *song; - struct mpd_status *status; if (connection == NULL || c->status == NULL) return false; @@ -489,7 +699,7 @@ mpdclient_cmd_delete(struct mpdclient *c, gint idx) if (idx < 0 || (guint)idx >= playlist_length(&c->playlist)) return false; - song = playlist_get(&c->playlist, idx); + const struct mpd_song *song = playlist_get(&c->playlist, idx); /* send the delete command to mpd; at the same time, get the new status (to verify the playlist id) */ @@ -502,7 +712,7 @@ mpdclient_cmd_delete(struct mpdclient *c, gint idx) c->events |= MPD_IDLE_QUEUE; - status = mpdclient_recv_status(c); + struct mpd_status *status = mpdclient_recv_status(c); if (status == NULL) return false; @@ -527,52 +737,18 @@ mpdclient_cmd_delete(struct mpdclient *c, gint idx) return true; } -/** - * Fallback for mpdclient_cmd_delete_range() on MPD older than 0.16. - * It emulates the "delete range" command with a list of simple - * "delete" commands. - */ -static bool -mpdclient_cmd_delete_range_fallback(struct mpdclient *c, - unsigned start, unsigned end) -{ - struct mpd_connection *connection = mpdclient_get_connection(c); - if (connection == NULL) - return false; - - if (!mpd_command_list_begin(connection, false)) - return mpdclient_handle_error(c); - - for (; start < end; --end) - mpd_send_delete(connection, start); - - if (!mpd_command_list_end(connection) || - !mpd_response_finish(connection)) - return mpdclient_handle_error(c); - - return true; -} - bool mpdclient_cmd_delete_range(struct mpdclient *c, unsigned start, unsigned end) { - struct mpd_connection *connection; - struct mpd_status *status; - if (end == start + 1) /* if that's not really a range, we choose to use the safer "deleteid" version */ return mpdclient_cmd_delete(c, start); - connection = mpdclient_get_connection(c); + struct mpd_connection *connection = mpdclient_get_connection(c); if (connection == NULL) return false; - if (mpd_connection_cmp_server_version(connection, 0, 16, 0) < 0) - return mpdclient_cmd_delete_range_fallback(c, start, end); - - /* MPD 0.16 supports "delete" with a range argument */ - /* send the delete command to mpd; at the same time, get the new status (to verify the playlist id) */ @@ -584,7 +760,7 @@ mpdclient_cmd_delete_range(struct mpdclient *c, unsigned start, unsigned end) c->events |= MPD_IDLE_QUEUE; - status = mpdclient_recv_status(c); + struct mpd_status *status = mpdclient_recv_status(c); if (status == NULL) return false; @@ -616,13 +792,10 @@ mpdclient_cmd_delete_range(struct mpdclient *c, unsigned start, unsigned end) bool mpdclient_cmd_move(struct mpdclient *c, unsigned dest_pos, unsigned src_pos) { - struct mpd_connection *connection; - struct mpd_status *status; - if (dest_pos == src_pos) return true; - connection = mpdclient_get_connection(c); + struct mpd_connection *connection = mpdclient_get_connection(c); if (connection == NULL) return false; @@ -637,7 +810,7 @@ mpdclient_cmd_move(struct mpdclient *c, unsigned dest_pos, unsigned src_pos) c->events |= MPD_IDLE_QUEUE; - status = mpdclient_recv_status(c); + struct mpd_status *status = mpdclient_recv_status(c); if (status == NULL) return false; @@ -658,6 +831,74 @@ mpdclient_cmd_move(struct mpdclient *c, unsigned dest_pos, unsigned src_pos) return true; } +/* The client-to-client protocol (MPD 0.17.0) */ + +bool +mpdclient_cmd_subscribe(struct mpdclient *c, const char *channel) +{ + struct mpd_connection *connection = mpdclient_get_connection(c); + + if (connection == NULL) + return false; + + if (!mpd_send_subscribe(connection, channel)) + return mpdclient_handle_error(c); + + return mpdclient_finish_command(c); +} + +bool +mpdclient_cmd_unsubscribe(struct mpdclient *c, const char *channel) +{ + struct mpd_connection *connection = mpdclient_get_connection(c); + if (connection == NULL) + return false; + + if (!mpd_send_unsubscribe(connection, channel)) + return mpdclient_handle_error(c); + + return mpdclient_finish_command(c); +} + +bool +mpdclient_cmd_send_message(struct mpdclient *c, const char *channel, + const char *text) +{ + struct mpd_connection *connection = mpdclient_get_connection(c); + if (connection == NULL) + return false; + + if (!mpd_send_send_message(connection, channel, text)) + return mpdclient_handle_error(c); + + return mpdclient_finish_command(c); +} + +bool +mpdclient_send_read_messages(struct mpdclient *c) +{ + struct mpd_connection *connection = mpdclient_get_connection(c); + if (connection == NULL) + return false; + + return mpd_send_read_messages(connection)? + true : mpdclient_handle_error(c); +} + +struct mpd_message * +mpdclient_recv_message(struct mpdclient *c) +{ + struct mpd_connection *connection = mpdclient_get_connection(c); + if (connection == NULL) + return false; + + struct mpd_message *message = mpd_recv_message(connection); + if (message == NULL && + mpd_connection_get_error(connection) != MPD_ERROR_SUCCESS) + mpdclient_handle_error(c); + + return message; +} /****************************************************************************/ /*** Playlist management functions ******************************************/ @@ -668,14 +909,14 @@ bool mpdclient_playlist_update(struct mpdclient *c) { struct mpd_connection *connection = mpdclient_get_connection(c); - struct mpd_entity *entity; - if (connection == NULL) return false; playlist_clear(&c->playlist); mpd_send_list_queue_meta(connection); + + struct mpd_entity *entity; while ((entity = mpd_recv_entity(connection))) { if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) playlist_append(&c->playlist, mpd_entity_get_song(entity)); @@ -694,14 +935,13 @@ bool mpdclient_playlist_update_changes(struct mpdclient *c) { struct mpd_connection *connection = mpdclient_get_connection(c); - struct mpd_song *song; - guint length; if (connection == NULL) return false; mpd_send_queue_changes_meta(connection, c->playlist.version); + struct mpd_song *song; while ((song = mpd_recv_song(connection)) != NULL) { int pos = mpd_song_get_pos(song); @@ -718,7 +958,7 @@ mpdclient_playlist_update_changes(struct mpdclient *c) /* remove trailing songs */ - length = mpd_status_get_queue_length(c->status); + unsigned length = mpd_status_get_queue_length(c->status); while (length < c->playlist.list->len) { guint pos = c->playlist.list->len - 1; @@ -741,8 +981,6 @@ bool mpdclient_filelist_add_all(struct mpdclient *c, struct filelist *fl) { struct mpd_connection *connection = mpdclient_get_connection(c); - guint i; - if (connection == NULL) return false; @@ -751,7 +989,7 @@ mpdclient_filelist_add_all(struct mpdclient *c, struct filelist *fl) mpd_command_list_begin(connection, false); - for (i = 0; i < filelist_length(fl); ++i) { + for (unsigned i = 0; i < filelist_length(fl); ++i) { struct filelist_entry *entry = filelist_get(fl, i); struct mpd_entity *entity = entry->entity;