X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fmpdclient.c;h=d60436946a378753538c1711cb653d0ce4bc9c16;hb=f46b959ea0ef555e27ef80c764ef808096f32bb3;hp=a688162a1832640f0938051d4b1a08afe90e6176;hpb=d636c08bcdbcd404c27c0ec8477d22c2406748f0;p=ncmpc.git diff --git a/src/mpdclient.c b/src/mpdclient.c index a688162..d604369 100644 --- a/src/mpdclient.c +++ b/src/mpdclient.c @@ -19,7 +19,7 @@ #include "mpdclient.h" #include "filelist.h" -#include "screen_utils.h" +#include "screen_client.h" #include "config.h" #include "options.h" #include "strfsong.h" @@ -32,11 +32,7 @@ #include #include -#undef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD /* broken with song id's */ -#define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE #define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE -#define ENABLE_SONG_ID -#define ENABLE_PLCHANGES #define BUFSIZE 1024 @@ -105,7 +101,7 @@ compare_filelistentry_format(gconstpointer filelist_entry1, /*** mpdclient functions ****************************************************/ /****************************************************************************/ -static gint +gint mpdclient_handle_error(struct mpdclient *c) { enum mpd_error error = mpd_connection_get_error(c->connection); @@ -114,17 +110,13 @@ 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) == 0) + screen_auth(c)) return 0; if (error == MPD_ERROR_SERVER) error = error | (mpd_connection_get_server_error(c->connection) << 8); - for (GList *list = c->error_callbacks; list != NULL; - list = list->next) { - mpdc_error_cb_t cb = list->data; - cb(c, error, mpd_connection_get_error_message(c->connection)); - } + mpdclient_ui_error(mpd_connection_get_error_message(c->connection)); if (!mpd_connection_clear_error(c->connection)) mpdclient_disconnect(c); @@ -132,7 +124,7 @@ mpdclient_handle_error(struct mpdclient *c) return error; } -gint +static gint mpdclient_finish_command(struct mpdclient *c) { return mpd_response_finish(c->connection) @@ -146,7 +138,8 @@ mpdclient_new(void) c = g_new0(struct mpdclient, 1); playlist_init(&c->playlist); - c->volume = MPD_STATUS_NO_VOLUME; + c->volume = -1; + c->events = 0; return c; } @@ -158,13 +151,10 @@ mpdclient_free(struct mpdclient *c) mpdclient_playlist_free(&c->playlist); - g_list_free(c->error_callbacks); - g_list_free(c->playlist_callbacks); - g_list_free(c->browse_callbacks); g_free(c); } -gint +void mpdclient_disconnect(struct mpdclient *c) { if (c->connection) @@ -179,19 +169,15 @@ mpdclient_disconnect(struct mpdclient *c) if (c->song) c->song = NULL; - - return 0; } -gint +bool mpdclient_connect(struct mpdclient *c, const gchar *host, gint port, gfloat _timeout, const gchar *password) { - gint retval = 0; - /* close any open connection */ if( c->connection ) mpdclient_disconnect(c); @@ -202,34 +188,34 @@ mpdclient_connect(struct mpdclient *c, g_error("Out of memory"); if (mpd_connection_get_error(c->connection) != MPD_ERROR_SUCCESS) { - retval = mpdclient_handle_error(c); - if (retval != 0) { - mpd_connection_free(c->connection); - c->connection = NULL; - } - - return retval; + mpdclient_handle_error(c); + mpdclient_disconnect(c); + return false; } /* send password */ - if( password ) { - mpd_send_password(c->connection, password); - retval = mpdclient_finish_command(c); + if (password != NULL && !mpd_run_password(c->connection, password)) { + mpdclient_handle_error(c); + mpdclient_disconnect(c); + return false; } - c->need_update = TRUE; - return retval; + return true; } -gint +bool mpdclient_update(struct mpdclient *c) { - gint retval = 0; + bool retval; - c->volume = MPD_STATUS_NO_VOLUME; + c->volume = -1; if (MPD_ERROR(c)) - return -1; + return false; + + /* always announce these options as long as we don't have real + "idle" support */ + c->events |= MPD_IDLE_PLAYER|MPD_IDLE_OPTIONS; /* free the old status */ if (c->status) @@ -238,30 +224,39 @@ mpdclient_update(struct mpdclient *c) /* retrieve new status */ c->status = mpd_run_status(c->connection); if (c->status == NULL) - return mpdclient_handle_error(c); + return mpdclient_handle_error(c) == 0; + + if (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; + } - if (c->updatingdb && - c->updatingdb != mpd_status_get_update_id(c->status)) - mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL); + c->update_id = mpd_status_get_update_id(c->status); + + if (c->volume != mpd_status_get_volume(c->status)) + c->events |= MPD_IDLE_MIXER; - c->updatingdb = mpd_status_get_update_id(c->status); c->volume = mpd_status_get_volume(c->status); /* check if the playlist needs an update */ - if (c->playlist.id != mpd_status_get_queue_version(c->status)) { - if (playlist_is_empty(&c->playlist)) + if (c->playlist.version != mpd_status_get_queue_version(c->status)) { + c->events |= MPD_IDLE_PLAYLIST; + + if (!playlist_is_empty(&c->playlist)) retval = mpdclient_playlist_update_changes(c); else retval = mpdclient_playlist_update(c); - } + } else + retval = true; /* update the current song */ if (!c->song || mpd_status_get_song_id(c->status)) { - c->song = playlist_get_song(c, mpd_status_get_song_pos(c->status)); + c->song = playlist_get_song(&c->playlist, + mpd_status_get_song_pos(c->status)); } - c->need_update = FALSE; - return retval; } @@ -273,8 +268,7 @@ mpdclient_update(struct mpdclient *c) gint mpdclient_cmd_play(struct mpdclient *c, gint idx) { -#ifdef ENABLE_SONG_ID - struct mpd_song *song = playlist_get_song(c, idx); + const struct mpd_song *song = playlist_get_song(&c->playlist, idx); if (MPD_ERROR(c)) return -1; @@ -283,23 +277,7 @@ mpdclient_cmd_play(struct mpdclient *c, gint idx) mpd_send_play_id(c->connection, mpd_song_get_id(song)); else mpd_send_play(c->connection); -#else - if (MPD_ERROR(c)) - return -1; - - mpd_sendPlayCommand(c->connection, idx); -#endif - c->need_update = TRUE; - return mpdclient_finish_command(c); -} -gint -mpdclient_cmd_pause(struct mpdclient *c, gint value) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_pause(c->connection, value); return mpdclient_finish_command(c); } @@ -338,64 +316,10 @@ mpdclient_cmd_crop(struct mpdclient *c) return mpdclient_finish_command(c); } -gint -mpdclient_cmd_stop(struct mpdclient *c) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_stop(c->connection); - return mpdclient_finish_command(c); -} - -gint -mpdclient_cmd_next(struct mpdclient *c) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_next(c->connection); - c->need_update = TRUE; - return mpdclient_finish_command(c); -} - -gint -mpdclient_cmd_prev(struct mpdclient *c) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_previous(c->connection); - c->need_update = TRUE; - return mpdclient_finish_command(c); -} - -gint -mpdclient_cmd_seek(struct mpdclient *c, gint id, gint pos) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_seek_id(c->connection, id, pos); - return mpdclient_finish_command(c); -} - -gint -mpdclient_cmd_shuffle(struct mpdclient *c) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_shuffle(c->connection); - c->need_update = TRUE; - return mpdclient_finish_command(c); -} - gint mpdclient_cmd_shuffle_range(struct mpdclient *c, guint start, guint end) { mpd_send_shuffle_range(c->connection, start, end); - c->need_update = TRUE; return mpdclient_finish_command(c); } @@ -409,80 +333,11 @@ mpdclient_cmd_clear(struct mpdclient *c) mpd_send_clear(c->connection); retval = mpdclient_finish_command(c); - /* call playlist updated callback */ - mpdclient_playlist_callback(c, PLAYLIST_EVENT_CLEAR, NULL); - c->need_update = TRUE; - return retval; -} - -gint -mpdclient_cmd_repeat(struct mpdclient *c, gint value) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_repeat(c->connection, value); - return mpdclient_finish_command(c); -} - -gint -mpdclient_cmd_random(struct mpdclient *c, gint value) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_random(c->connection, value); - return mpdclient_finish_command(c); -} - -gint -mpdclient_cmd_single(struct mpdclient *c, gint value) -{ - if (MPD_ERROR(c)) - return -1; - mpd_send_single(c->connection, value); - return mpdclient_finish_command(c); -} + if (retval) + c->events |= MPD_IDLE_PLAYLIST; -gint -mpdclient_cmd_consume(struct mpdclient *c, gint value) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_consume(c->connection, value); - return mpdclient_finish_command(c); -} - -gint -mpdclient_cmd_crossfade(struct mpdclient *c, gint value) -{ - if (MPD_ERROR(c)) - return -1; - - mpd_send_crossfade(c->connection, value); - return mpdclient_finish_command(c); -} - -gint -mpdclient_cmd_db_update(struct mpdclient *c, const gchar *path) -{ - gint ret; - - if (MPD_ERROR(c)) - return -1; - - mpd_send_update(c->connection, path ? path : ""); - ret = mpdclient_finish_command(c); - - if (ret == 0) - /* set updatingDb to make sure the browse callback - gets called even if the update has finished before - status is updated */ - c->updatingdb = 1; - - return ret; + return retval; } gint @@ -501,10 +356,10 @@ gint mpdclient_cmd_volume_up(struct mpdclient *c) return -1; if (c->status == NULL || - mpd_status_get_volume(c->status) == MPD_STATUS_NO_VOLUME) + mpd_status_get_volume(c->status) == -1) return 0; - if (c->volume == MPD_STATUS_NO_VOLUME) + if (c->volume < 0) c->volume = mpd_status_get_volume(c->status); if (c->volume >= 100) @@ -518,11 +373,10 @@ gint mpdclient_cmd_volume_down(struct mpdclient *c) if (MPD_ERROR(c)) return -1; - if (c->status == NULL || - mpd_status_get_volume(c->status) == MPD_STATUS_NO_VOLUME) + if (c->status == NULL || mpd_status_get_volume(c->status) < 0) return 0; - if (c->volume == MPD_STATUS_NO_VOLUME) + if (c->volume < 0) c->volume = mpd_status_get_volume(c->status); if (c->volume <= 0) @@ -544,42 +398,73 @@ mpdclient_cmd_add_path(struct mpdclient *c, const gchar *path_utf8) gint mpdclient_cmd_add(struct mpdclient *c, const struct mpd_song *song) { - gint retval = 0; + struct mpd_status *status; + struct mpd_song *new_song; - if (MPD_ERROR(c)) - return -1; + assert(c != NULL); + assert(song != NULL); - if (song == NULL) + if (MPD_ERROR(c) || c->status == NULL) return -1; - /* send the add command to mpd */ - mpd_send_add(c->connection, mpd_song_get_uri(song)); - if( (retval=mpdclient_finish_command(c)) ) - return retval; + /* send the add command to mpd; at the same time, get the new + status (to verify the new playlist id) and the last song + (we hope that's the song we just added) */ -#ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD - /* add the song to playlist */ - playlist_append(&c->playlist, song); + if (!mpd_command_list_begin(c->connection, true) || + !mpd_send_add(c->connection, mpd_song_get_uri(song)) || + !mpd_send_status(c->connection) || + !mpd_send_get_queue_song_pos(c->connection, + playlist_length(&c->playlist)) || + !mpd_command_list_end(c->connection) || + !mpd_response_next(c->connection)) + return mpdclient_handle_error(c); - /* increment the playlist id, so we don't retrieve a new playlist */ - c->playlist.id++; + c->events |= MPD_IDLE_PLAYLIST; - /* call playlist updated callback */ - mpdclient_playlist_callback(c, PLAYLIST_EVENT_ADD, (gpointer) song); -#else - c->need_update = TRUE; -#endif + status = mpd_recv_status(c->connection); + if (status != NULL) { + if (c->status != NULL) + mpd_status_free(c->status); + c->status = status; + } - return 0; + if (!mpd_response_next(c->connection)) + return mpdclient_handle_error(c); + + new_song = mpd_recv_song(c->connection); + if (!mpd_response_finish(c->connection) || new_song == NULL) { + if (new_song != NULL) + mpd_song_free(new_song); + + return mpd_connection_clear_error(c->connection) + ? 0 : mpdclient_handle_error(c); + } + + if (mpd_status_get_queue_length(status) == playlist_length(&c->playlist) + 1 && + mpd_status_get_queue_version(status) == c->playlist.version + 1) { + /* the cheap route: match on the new playlist length + and its version, we can keep our local playlist + copy in sync */ + c->playlist.version = mpd_status_get_queue_version(status); + + /* the song we just received has the correct id; + append it to the local playlist */ + playlist_append(&c->playlist, new_song); + } + + mpd_song_free(new_song); + + return -0; } gint mpdclient_cmd_delete(struct mpdclient *c, gint idx) { - gint retval = 0; - struct mpd_song *song; + const struct mpd_song *song; + struct mpd_status *status; - if (MPD_ERROR(c)) + if (MPD_ERROR(c) || c->status == NULL) return -1; if (idx < 0 || (guint)idx >= playlist_length(&c->playlist)) @@ -587,36 +472,119 @@ mpdclient_cmd_delete(struct mpdclient *c, gint idx) song = playlist_get(&c->playlist, idx); - /* send the delete command to mpd */ -#ifdef ENABLE_SONG_ID - mpd_send_delete_id(c->connection, mpd_song_get_id(song)); -#else - mpd_send_delete(c->connection, idx); -#endif - if( (retval=mpdclient_finish_command(c)) ) - return retval; + /* send the delete command to mpd; at the same time, get the + new status (to verify the playlist id) */ -#ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE - /* increment the playlist id, so we don't retrieve a new playlist */ - c->playlist.id++; + if (!mpd_command_list_begin(c->connection, false) || + !mpd_send_delete_id(c->connection, mpd_song_get_id(song)) || + !mpd_send_status(c->connection) || + !mpd_command_list_end(c->connection)) + return mpdclient_handle_error(c); + + c->events |= MPD_IDLE_PLAYLIST; - /* remove the song from the playlist */ - playlist_remove_reuse(&c->playlist, idx); + status = mpd_recv_status(c->connection); + if (status != NULL) { + if (c->status != NULL) + mpd_status_free(c->status); + c->status = status; + } + + if (!mpd_response_finish(c->connection)) + return mpdclient_handle_error(c); - /* call playlist updated callback */ - mpdclient_playlist_callback(c, PLAYLIST_EVENT_DELETE, (gpointer) song); + if (mpd_status_get_queue_length(status) == playlist_length(&c->playlist) - 1 && + mpd_status_get_queue_version(status) == c->playlist.version + 1) { + /* the cheap route: match on the new playlist length + and its version, we can keep our local playlist + copy in sync */ + c->playlist.version = mpd_status_get_queue_version(status); - /* remove references to the song */ - if (c->song == song) { - c->song = NULL; - c->need_update = TRUE; + /* remove the song from the local playlist */ + playlist_remove(&c->playlist, idx); + + /* remove references to the song */ + if (c->song == song) + c->song = NULL; } - mpd_song_free(song); + return 0; +} -#else - c->need_update = TRUE; -#endif +/** + * 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 gint +mpdclient_cmd_delete_range_fallback(struct mpdclient *c, + unsigned start, unsigned end) +{ + if (!mpd_command_list_begin(c->connection, false)) + return mpdclient_handle_error(c); + + for (; start < end; --end) + mpd_send_delete(c->connection, start); + + if (!mpd_command_list_end(c->connection) || + !mpd_response_finish(c->connection)) + return mpdclient_handle_error(c); + + return 0; +} + +gint +mpdclient_cmd_delete_range(struct mpdclient *c, unsigned start, unsigned end) +{ + struct mpd_status *status; + + if (MPD_ERROR(c)) + return -1; + + if (mpd_connection_cmp_server_version(c->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) */ + + if (!mpd_command_list_begin(c->connection, false) || + !mpd_send_delete_range(c->connection, start, end) || + !mpd_send_status(c->connection) || + !mpd_command_list_end(c->connection)) + return mpdclient_handle_error(c); + + c->events |= MPD_IDLE_PLAYLIST; + + status = mpd_recv_status(c->connection); + if (status != NULL) { + if (c->status != NULL) + mpd_status_free(c->status); + c->status = status; + } + + if (!mpd_response_finish(c->connection)) + return mpdclient_handle_error(c); + + if (mpd_status_get_queue_length(status) == playlist_length(&c->playlist) - (end - start) && + mpd_status_get_queue_version(status) == c->playlist.version + 1) { + /* the cheap route: match on the new playlist length + and its version, we can keep our local playlist + copy in sync */ + c->playlist.version = mpd_status_get_queue_version(status); + + /* remove the song from the local playlist */ + while (end > start) { + --end; + + /* remove references to the song */ + if (c->song == playlist_get(&c->playlist, end)) + c->song = NULL; + + playlist_remove(&c->playlist, end); + } + } return 0; } @@ -638,12 +606,8 @@ mpdclient_cmd_move(struct mpdclient *c, gint old_index, gint new_index) song2 = playlist_get(&c->playlist, new_index); /* send the move command to mpd */ -#ifdef ENABLE_SONG_ID mpd_send_swap_id(c->connection, mpd_song_get_id(song1), mpd_song_get_id(song2)); -#else - mpd_send_move(c->connection, old_index, new_index); -#endif if( (n=mpdclient_finish_command(c)) ) return n; @@ -652,14 +616,10 @@ mpdclient_cmd_move(struct mpdclient *c, gint old_index, gint new_index) playlist_swap(&c->playlist, old_index, new_index); /* increment the playlist id, so we don't retrieve a new playlist */ - c->playlist.id++; - -#else - c->need_update = TRUE; + c->playlist.version++; #endif - /* call playlist updated callback */ - mpdclient_playlist_callback(c, PLAYLIST_EVENT_MOVE, (gpointer) &new_index); + c->events |= MPD_IDLE_PLAYLIST; return 0; } @@ -673,8 +633,10 @@ mpdclient_cmd_save_playlist(struct mpdclient *c, const gchar *filename_utf8) return -1; mpd_send_save(c->connection, filename_utf8); - if ((retval = mpdclient_finish_command(c)) == 0) - mpdclient_browse_callback(c, BROWSE_PLAYLIST_SAVED, NULL); + if ((retval = mpdclient_finish_command(c)) == 0) { + c->events |= MPD_IDLE_STORED_PLAYLIST; + } + return retval; } @@ -685,7 +647,6 @@ mpdclient_cmd_load_playlist(struct mpdclient *c, const gchar *filename_utf8) return -1; mpd_send_load(c->connection, filename_utf8); - c->need_update = TRUE; return mpdclient_finish_command(c); } @@ -699,73 +660,9 @@ mpdclient_cmd_delete_playlist(struct mpdclient *c, const gchar *filename_utf8) mpd_send_rm(c->connection, filename_utf8); if ((retval = mpdclient_finish_command(c)) == 0) - mpdclient_browse_callback(c, BROWSE_PLAYLIST_DELETED, NULL); - return retval; -} - - -/****************************************************************************/ -/*** Callback management functions ******************************************/ -/****************************************************************************/ - -static void -do_list_callbacks(struct mpdclient *c, GList *list, gint event, gpointer data) -{ - while (list) { - mpdc_list_cb_t fn = list->data; - - fn(c, event, data); - list = list->next; - } -} - -void -mpdclient_playlist_callback(struct mpdclient *c, int event, gpointer data) -{ - do_list_callbacks(c, c->playlist_callbacks, event, data); -} - -void -mpdclient_install_playlist_callback(struct mpdclient *c,mpdc_list_cb_t cb) -{ - c->playlist_callbacks = g_list_append(c->playlist_callbacks, cb); -} - -void -mpdclient_remove_playlist_callback(struct mpdclient *c, mpdc_list_cb_t cb) -{ - c->playlist_callbacks = g_list_remove(c->playlist_callbacks, cb); -} - -void -mpdclient_browse_callback(struct mpdclient *c, int event, gpointer data) -{ - do_list_callbacks(c, c->browse_callbacks, event, data); -} - - -void -mpdclient_install_browse_callback(struct mpdclient *c,mpdc_list_cb_t cb) -{ - c->browse_callbacks = g_list_append(c->browse_callbacks, cb); -} + c->events |= MPD_IDLE_STORED_PLAYLIST; -void -mpdclient_remove_browse_callback(struct mpdclient *c, mpdc_list_cb_t cb) -{ - c->browse_callbacks = g_list_remove(c->browse_callbacks, cb); -} - -void -mpdclient_install_error_callback(struct mpdclient *c, mpdc_error_cb_t cb) -{ - c->error_callbacks = g_list_append(c->error_callbacks, cb); -} - -void -mpdclient_remove_error_callback(struct mpdclient *c, mpdc_error_cb_t cb) -{ - c->error_callbacks = g_list_remove(c->error_callbacks, cb); + return retval; } @@ -774,13 +671,13 @@ mpdclient_remove_error_callback(struct mpdclient *c, mpdc_error_cb_t cb) /****************************************************************************/ /* update playlist */ -gint +bool mpdclient_playlist_update(struct mpdclient *c) { struct mpd_entity *entity; if (MPD_ERROR(c)) - return -1; + return false; playlist_clear(&c->playlist); @@ -792,28 +689,23 @@ mpdclient_playlist_update(struct mpdclient *c) mpd_entity_free(entity); } - c->playlist.id = mpd_status_get_queue_version(c->status); + c->playlist.version = mpd_status_get_queue_version(c->status); c->song = NULL; - /* call playlist updated callbacks */ - mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL); - - return mpdclient_finish_command(c); + return mpdclient_finish_command(c) == 0; } -#ifdef ENABLE_PLCHANGES - /* update playlist (plchanges) */ -gint +bool mpdclient_playlist_update_changes(struct mpdclient *c) { struct mpd_song *song; guint length; if (MPD_ERROR(c)) - return -1; + return false; - mpd_send_queue_changes_meta(c->connection, c->playlist.id); + mpd_send_queue_changes_meta(c->connection, c->playlist.version); while ((song = mpd_recv_song(c->connection)) != NULL) { int pos = mpd_song_get_pos(song); @@ -840,20 +732,10 @@ mpdclient_playlist_update_changes(struct mpdclient *c) } c->song = NULL; - c->playlist.id = mpd_status_get_queue_version(c->status); - - mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL); - - return 0; -} + c->playlist.version = mpd_status_get_queue_version(c->status); -#else -gint -mpdclient_playlist_update_changes(struct mpdclient *c) -{ - return mpdclient_playlist_update(c); + return mpdclient_finish_command(c) == 0; } -#endif /****************************************************************************/ @@ -871,15 +753,14 @@ mpdclient_filelist_get(struct mpdclient *c, const gchar *path) mpd_send_list_meta(c->connection, path); filelist = filelist_new(); - if (path && path[0] && strcmp(path, "/")) - /* add a dummy entry for ./.. */ - filelist_append(filelist, NULL); while ((entity = mpd_recv_entity(c->connection)) != NULL) filelist_append(filelist, entity); - /* If there's an error, ignore it. We'll return an empty filelist. */ - mpdclient_finish_command(c); + if (mpdclient_finish_command(c)) { + filelist_free(filelist); + return NULL; + } filelist_sort_dir_play(filelist, compare_filelistentry);