9a9154caafb4f57de45d462dc7db54218a140af2
1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2009 The Music Player Daemon Project
3 * Project homepage: http://musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
20 #include "mpdclient.h"
21 #include "filelist.h"
22 #include "screen_client.h"
23 #include "config.h"
24 #include "options.h"
25 #include "strfsong.h"
26 #include "utils.h"
28 #include <mpd/client.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <time.h>
33 #include <string.h>
35 #define BUFSIZE 1024
37 static bool
38 MPD_ERROR(const struct mpdclient *client)
39 {
40 return !mpdclient_is_connected(client) ||
41 mpd_connection_get_error(client->connection) != MPD_ERROR_SUCCESS;
42 }
44 /* filelist sorting functions */
45 static gint
46 compare_filelistentry(gconstpointer filelist_entry1,
47 gconstpointer filelist_entry2)
48 {
49 const struct mpd_entity *e1, *e2;
50 int n = 0;
52 e1 = ((const struct filelist_entry *)filelist_entry1)->entity;
53 e2 = ((const struct filelist_entry *)filelist_entry2)->entity;
55 if (e1 != NULL && e2 != NULL &&
56 mpd_entity_get_type(e1) == mpd_entity_get_type(e2)) {
57 switch (mpd_entity_get_type(e1)) {
58 case MPD_ENTITY_TYPE_UNKNOWN:
59 break;
60 case MPD_ENTITY_TYPE_DIRECTORY:
61 n = g_utf8_collate(mpd_directory_get_path(mpd_entity_get_directory(e1)),
62 mpd_directory_get_path(mpd_entity_get_directory(e2)));
63 break;
64 case MPD_ENTITY_TYPE_SONG:
65 break;
66 case MPD_ENTITY_TYPE_PLAYLIST:
67 n = g_utf8_collate(mpd_playlist_get_path(mpd_entity_get_playlist(e1)),
68 mpd_playlist_get_path(mpd_entity_get_playlist(e2)));
69 }
70 }
71 return n;
72 }
74 /* sort by list-format */
75 gint
76 compare_filelistentry_format(gconstpointer filelist_entry1,
77 gconstpointer filelist_entry2)
78 {
79 const struct mpd_entity *e1, *e2;
80 char key1[BUFSIZE], key2[BUFSIZE];
81 int n = 0;
83 e1 = ((const struct filelist_entry *)filelist_entry1)->entity;
84 e2 = ((const struct filelist_entry *)filelist_entry2)->entity;
86 if (e1 && e2 &&
87 mpd_entity_get_type(e1) == MPD_ENTITY_TYPE_SONG &&
88 mpd_entity_get_type(e2) == MPD_ENTITY_TYPE_SONG) {
89 strfsong(key1, BUFSIZE, options.list_format, mpd_entity_get_song(e1));
90 strfsong(key2, BUFSIZE, options.list_format, mpd_entity_get_song(e2));
91 n = strcmp(key1,key2);
92 }
94 return n;
95 }
98 /****************************************************************************/
99 /*** mpdclient functions ****************************************************/
100 /****************************************************************************/
102 bool
103 mpdclient_handle_error(struct mpdclient *c)
104 {
105 enum mpd_error error = mpd_connection_get_error(c->connection);
107 assert(error != MPD_ERROR_SUCCESS);
109 if (error == MPD_ERROR_SERVER &&
110 mpd_connection_get_server_error(c->connection) == MPD_SERVER_ERROR_PERMISSION &&
111 screen_auth(c))
112 return true;
114 mpdclient_ui_error(mpd_connection_get_error_message(c->connection));
116 if (!mpd_connection_clear_error(c->connection))
117 mpdclient_disconnect(c);
119 return false;
120 }
122 static bool
123 mpdclient_finish_command(struct mpdclient *c)
124 {
125 return mpd_response_finish(c->connection)
126 ? true : mpdclient_handle_error(c);
127 }
129 struct mpdclient *
130 mpdclient_new(void)
131 {
132 struct mpdclient *c;
134 c = g_new0(struct mpdclient, 1);
135 playlist_init(&c->playlist);
136 c->volume = -1;
137 c->events = 0;
139 return c;
140 }
142 void
143 mpdclient_free(struct mpdclient *c)
144 {
145 mpdclient_disconnect(c);
147 mpdclient_playlist_free(&c->playlist);
149 g_free(c);
150 }
152 void
153 mpdclient_disconnect(struct mpdclient *c)
154 {
155 if (c->connection)
156 mpd_connection_free(c->connection);
157 c->connection = NULL;
159 if (c->status)
160 mpd_status_free(c->status);
161 c->status = NULL;
163 playlist_clear(&c->playlist);
165 if (c->song)
166 c->song = NULL;
167 }
169 bool
170 mpdclient_connect(struct mpdclient *c,
171 const gchar *host,
172 gint port,
173 gfloat _timeout,
174 const gchar *password)
175 {
176 /* close any open connection */
177 if( c->connection )
178 mpdclient_disconnect(c);
180 /* connect to MPD */
181 c->connection = mpd_connection_new(host, port, _timeout * 1000);
182 if (c->connection == NULL)
183 g_error("Out of memory");
185 if (mpd_connection_get_error(c->connection) != MPD_ERROR_SUCCESS) {
186 mpdclient_handle_error(c);
187 mpdclient_disconnect(c);
188 return false;
189 }
191 /* send password */
192 if (password != NULL && !mpd_run_password(c->connection, password)) {
193 mpdclient_handle_error(c);
194 mpdclient_disconnect(c);
195 return false;
196 }
198 return true;
199 }
201 bool
202 mpdclient_update(struct mpdclient *c)
203 {
204 bool retval;
206 c->volume = -1;
208 if (MPD_ERROR(c))
209 return false;
211 /* always announce these options as long as we don't have real
212 "idle" support */
213 c->events |= MPD_IDLE_PLAYER|MPD_IDLE_OPTIONS;
215 /* free the old status */
216 if (c->status)
217 mpd_status_free(c->status);
219 /* retrieve new status */
220 c->status = mpd_run_status(c->connection);
221 if (c->status == NULL)
222 return mpdclient_handle_error(c);
224 if (c->update_id != mpd_status_get_update_id(c->status)) {
225 c->events |= MPD_IDLE_UPDATE;
227 if (c->update_id > 0)
228 c->events |= MPD_IDLE_DATABASE;
229 }
231 c->update_id = mpd_status_get_update_id(c->status);
233 if (c->volume != mpd_status_get_volume(c->status))
234 c->events |= MPD_IDLE_MIXER;
236 c->volume = mpd_status_get_volume(c->status);
238 /* check if the playlist needs an update */
239 if (c->playlist.version != mpd_status_get_queue_version(c->status)) {
240 c->events |= MPD_IDLE_PLAYLIST;
242 if (!playlist_is_empty(&c->playlist))
243 retval = mpdclient_playlist_update_changes(c);
244 else
245 retval = mpdclient_playlist_update(c);
246 } else
247 retval = true;
249 /* update the current song */
250 if (!c->song || mpd_status_get_song_id(c->status)) {
251 c->song = playlist_get_song(&c->playlist,
252 mpd_status_get_song_pos(c->status));
253 }
255 return retval;
256 }
259 /****************************************************************************/
260 /*** MPD Commands **********************************************************/
261 /****************************************************************************/
263 bool
264 mpdclient_cmd_play(struct mpdclient *c, gint idx)
265 {
266 const struct mpd_song *song = playlist_get_song(&c->playlist, idx);
268 if (MPD_ERROR(c))
269 return false;
271 if (song)
272 mpd_send_play_id(c->connection, mpd_song_get_id(song));
273 else
274 mpd_send_play(c->connection);
276 return mpdclient_finish_command(c);
277 }
279 bool
280 mpdclient_cmd_crop(struct mpdclient *c)
281 {
282 struct mpd_status *status;
283 bool playing;
284 int length, current;
286 if (MPD_ERROR(c))
287 return false;
289 status = mpd_run_status(c->connection);
290 if (status == NULL)
291 return mpdclient_handle_error(c);
293 playing = mpd_status_get_state(status) == MPD_STATE_PLAY ||
294 mpd_status_get_state(status) == MPD_STATE_PAUSE;
295 length = mpd_status_get_queue_length(status);
296 current = mpd_status_get_song_pos(status);
298 mpd_status_free(status);
300 if (!playing || length < 2)
301 return true;
303 mpd_command_list_begin(c->connection, false);
305 while (--length >= 0)
306 if (length != current)
307 mpd_send_delete(c->connection, length);
309 mpd_command_list_end(c->connection);
311 return mpdclient_finish_command(c);
312 }
314 bool
315 mpdclient_cmd_clear(struct mpdclient *c)
316 {
317 bool retval;
319 if (MPD_ERROR(c))
320 return false;
322 mpd_send_clear(c->connection);
323 retval = mpdclient_finish_command(c);
325 if (retval)
326 c->events |= MPD_IDLE_PLAYLIST;
328 return retval;
329 }
331 bool
332 mpdclient_cmd_volume(struct mpdclient *c, gint value)
333 {
334 if (MPD_ERROR(c))
335 return false;
337 mpd_send_set_volume(c->connection, value);
338 return mpdclient_finish_command(c);
339 }
341 bool
342 mpdclient_cmd_volume_up(struct mpdclient *c)
343 {
344 if (MPD_ERROR(c))
345 return false;
347 if (c->status == NULL ||
348 mpd_status_get_volume(c->status) == -1)
349 return true;
351 if (c->volume < 0)
352 c->volume = mpd_status_get_volume(c->status);
354 if (c->volume >= 100)
355 return true;
357 return mpdclient_cmd_volume(c, ++c->volume);
358 }
360 bool
361 mpdclient_cmd_volume_down(struct mpdclient *c)
362 {
363 if (MPD_ERROR(c))
364 return false;
366 if (c->status == NULL || mpd_status_get_volume(c->status) < 0)
367 return true;
369 if (c->volume < 0)
370 c->volume = mpd_status_get_volume(c->status);
372 if (c->volume <= 0)
373 return true;
375 return mpdclient_cmd_volume(c, --c->volume);
376 }
378 bool
379 mpdclient_cmd_add_path(struct mpdclient *c, const gchar *path_utf8)
380 {
381 if (MPD_ERROR(c))
382 return false;
384 mpd_send_add(c->connection, path_utf8);
385 return mpdclient_finish_command(c);
386 }
388 bool
389 mpdclient_cmd_add(struct mpdclient *c, const struct mpd_song *song)
390 {
391 struct mpd_status *status;
392 struct mpd_song *new_song;
394 assert(c != NULL);
395 assert(song != NULL);
397 if (MPD_ERROR(c) || c->status == NULL)
398 return false;
400 /* send the add command to mpd; at the same time, get the new
401 status (to verify the new playlist id) and the last song
402 (we hope that's the song we just added) */
404 if (!mpd_command_list_begin(c->connection, true) ||
405 !mpd_send_add(c->connection, mpd_song_get_uri(song)) ||
406 !mpd_send_status(c->connection) ||
407 !mpd_send_get_queue_song_pos(c->connection,
408 playlist_length(&c->playlist)) ||
409 !mpd_command_list_end(c->connection) ||
410 !mpd_response_next(c->connection))
411 return mpdclient_handle_error(c);
413 c->events |= MPD_IDLE_PLAYLIST;
415 status = mpd_recv_status(c->connection);
416 if (status != NULL) {
417 if (c->status != NULL)
418 mpd_status_free(c->status);
419 c->status = status;
420 }
422 if (!mpd_response_next(c->connection))
423 return mpdclient_handle_error(c);
425 new_song = mpd_recv_song(c->connection);
426 if (!mpd_response_finish(c->connection) || new_song == NULL) {
427 if (new_song != NULL)
428 mpd_song_free(new_song);
430 return mpd_connection_clear_error(c->connection) ||
431 mpdclient_handle_error(c);
432 }
434 if (mpd_status_get_queue_length(status) == playlist_length(&c->playlist) + 1 &&
435 mpd_status_get_queue_version(status) == c->playlist.version + 1) {
436 /* the cheap route: match on the new playlist length
437 and its version, we can keep our local playlist
438 copy in sync */
439 c->playlist.version = mpd_status_get_queue_version(status);
441 /* the song we just received has the correct id;
442 append it to the local playlist */
443 playlist_append(&c->playlist, new_song);
444 }
446 mpd_song_free(new_song);
448 return true;
449 }
451 bool
452 mpdclient_cmd_delete(struct mpdclient *c, gint idx)
453 {
454 const struct mpd_song *song;
455 struct mpd_status *status;
457 if (MPD_ERROR(c) || c->status == NULL)
458 return false;
460 if (idx < 0 || (guint)idx >= playlist_length(&c->playlist))
461 return false;
463 song = playlist_get(&c->playlist, idx);
465 /* send the delete command to mpd; at the same time, get the
466 new status (to verify the playlist id) */
468 if (!mpd_command_list_begin(c->connection, false) ||
469 !mpd_send_delete_id(c->connection, mpd_song_get_id(song)) ||
470 !mpd_send_status(c->connection) ||
471 !mpd_command_list_end(c->connection))
472 return mpdclient_handle_error(c);
474 c->events |= MPD_IDLE_PLAYLIST;
476 status = mpd_recv_status(c->connection);
477 if (status != NULL) {
478 if (c->status != NULL)
479 mpd_status_free(c->status);
480 c->status = status;
481 }
483 if (!mpd_response_finish(c->connection))
484 return mpdclient_handle_error(c);
486 if (mpd_status_get_queue_length(status) == playlist_length(&c->playlist) - 1 &&
487 mpd_status_get_queue_version(status) == c->playlist.version + 1) {
488 /* the cheap route: match on the new playlist length
489 and its version, we can keep our local playlist
490 copy in sync */
491 c->playlist.version = mpd_status_get_queue_version(status);
493 /* remove the song from the local playlist */
494 playlist_remove(&c->playlist, idx);
496 /* remove references to the song */
497 if (c->song == song)
498 c->song = NULL;
499 }
501 return true;
502 }
504 /**
505 * Fallback for mpdclient_cmd_delete_range() on MPD older than 0.16.
506 * It emulates the "delete range" command with a list of simple
507 * "delete" commands.
508 */
509 static bool
510 mpdclient_cmd_delete_range_fallback(struct mpdclient *c,
511 unsigned start, unsigned end)
512 {
513 if (!mpd_command_list_begin(c->connection, false))
514 return mpdclient_handle_error(c);
516 for (; start < end; --end)
517 mpd_send_delete(c->connection, start);
519 if (!mpd_command_list_end(c->connection) ||
520 !mpd_response_finish(c->connection))
521 return mpdclient_handle_error(c);
523 return true;
524 }
526 bool
527 mpdclient_cmd_delete_range(struct mpdclient *c, unsigned start, unsigned end)
528 {
529 struct mpd_status *status;
531 if (MPD_ERROR(c))
532 return false;
534 if (mpd_connection_cmp_server_version(c->connection, 0, 16, 0) < 0)
535 return mpdclient_cmd_delete_range_fallback(c, start, end);
537 /* MPD 0.16 supports "delete" with a range argument */
539 /* send the delete command to mpd; at the same time, get the
540 new status (to verify the playlist id) */
542 if (!mpd_command_list_begin(c->connection, false) ||
543 !mpd_send_delete_range(c->connection, start, end) ||
544 !mpd_send_status(c->connection) ||
545 !mpd_command_list_end(c->connection))
546 return mpdclient_handle_error(c);
548 c->events |= MPD_IDLE_PLAYLIST;
550 status = mpd_recv_status(c->connection);
551 if (status != NULL) {
552 if (c->status != NULL)
553 mpd_status_free(c->status);
554 c->status = status;
555 }
557 if (!mpd_response_finish(c->connection))
558 return mpdclient_handle_error(c);
560 if (mpd_status_get_queue_length(status) == playlist_length(&c->playlist) - (end - start) &&
561 mpd_status_get_queue_version(status) == c->playlist.version + 1) {
562 /* the cheap route: match on the new playlist length
563 and its version, we can keep our local playlist
564 copy in sync */
565 c->playlist.version = mpd_status_get_queue_version(status);
567 /* remove the song from the local playlist */
568 while (end > start) {
569 --end;
571 /* remove references to the song */
572 if (c->song == playlist_get(&c->playlist, end))
573 c->song = NULL;
575 playlist_remove(&c->playlist, end);
576 }
577 }
579 return true;
580 }
582 bool
583 mpdclient_cmd_move(struct mpdclient *c, gint old_index, gint new_index)
584 {
585 const struct mpd_song *song1, *song2;
586 struct mpd_status *status;
588 if (MPD_ERROR(c))
589 return false;
591 if (old_index == new_index || new_index < 0 ||
592 (guint)new_index >= c->playlist.list->len)
593 return false;
595 song1 = playlist_get(&c->playlist, old_index);
596 song2 = playlist_get(&c->playlist, new_index);
598 /* send the delete command to mpd; at the same time, get the
599 new status (to verify the playlist id) */
601 if (!mpd_command_list_begin(c->connection, false) ||
602 !mpd_send_swap_id(c->connection, mpd_song_get_id(song1),
603 mpd_song_get_id(song2)) ||
604 !mpd_send_status(c->connection) ||
605 !mpd_command_list_end(c->connection))
606 return mpdclient_handle_error(c);
608 c->events |= MPD_IDLE_PLAYLIST;
610 status = mpd_recv_status(c->connection);
611 if (status != NULL) {
612 if (c->status != NULL)
613 mpd_status_free(c->status);
614 c->status = status;
615 }
617 if (!mpd_response_finish(c->connection))
618 return mpdclient_handle_error(c);
620 if (mpd_status_get_queue_length(status) == playlist_length(&c->playlist) &&
621 mpd_status_get_queue_version(status) == c->playlist.version + 1) {
622 /* the cheap route: match on the new playlist length
623 and its version, we can keep our local playlist
624 copy in sync */
625 c->playlist.version = mpd_status_get_queue_version(status);
627 /* swap songs in the local playlist */
628 playlist_swap(&c->playlist, old_index, new_index);
629 }
631 return true;
632 }
635 /****************************************************************************/
636 /*** Playlist management functions ******************************************/
637 /****************************************************************************/
639 /* update playlist */
640 bool
641 mpdclient_playlist_update(struct mpdclient *c)
642 {
643 struct mpd_entity *entity;
645 if (MPD_ERROR(c))
646 return false;
648 playlist_clear(&c->playlist);
650 mpd_send_list_queue_meta(c->connection);
651 while ((entity = mpd_recv_entity(c->connection))) {
652 if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG)
653 playlist_append(&c->playlist, mpd_entity_get_song(entity));
655 mpd_entity_free(entity);
656 }
658 c->playlist.version = mpd_status_get_queue_version(c->status);
659 c->song = NULL;
661 return mpdclient_finish_command(c);
662 }
664 /* update playlist (plchanges) */
665 bool
666 mpdclient_playlist_update_changes(struct mpdclient *c)
667 {
668 struct mpd_song *song;
669 guint length;
671 if (MPD_ERROR(c))
672 return false;
674 mpd_send_queue_changes_meta(c->connection, c->playlist.version);
676 while ((song = mpd_recv_song(c->connection)) != NULL) {
677 int pos = mpd_song_get_pos(song);
679 if (pos >= 0 && (guint)pos < c->playlist.list->len) {
680 /* update song */
681 playlist_replace(&c->playlist, pos, song);
682 } else {
683 /* add a new song */
684 playlist_append(&c->playlist, song);
685 }
687 mpd_song_free(song);
688 }
690 /* remove trailing songs */
692 length = mpd_status_get_queue_length(c->status);
693 while (length < c->playlist.list->len) {
694 guint pos = c->playlist.list->len - 1;
696 /* Remove the last playlist entry */
697 playlist_remove(&c->playlist, pos);
698 }
700 c->song = NULL;
701 c->playlist.version = mpd_status_get_queue_version(c->status);
703 return mpdclient_finish_command(c);
704 }
707 /****************************************************************************/
708 /*** Filelist functions *****************************************************/
709 /****************************************************************************/
711 struct filelist *
712 mpdclient_filelist_get(struct mpdclient *c, const gchar *path)
713 {
714 struct filelist *filelist;
715 struct mpd_entity *entity;
717 if (MPD_ERROR(c))
718 return NULL;
720 mpd_send_list_meta(c->connection, path);
721 filelist = filelist_new();
723 while ((entity = mpd_recv_entity(c->connection)) != NULL)
724 filelist_append(filelist, entity);
726 if (!mpdclient_finish_command(c)) {
727 filelist_free(filelist);
728 return NULL;
729 }
731 filelist_sort_dir_play(filelist, compare_filelistentry);
733 return filelist;
734 }
736 static struct filelist *
737 mpdclient_recv_filelist_response(struct mpdclient *c)
738 {
739 struct filelist *filelist;
740 struct mpd_entity *entity;
742 filelist = filelist_new();
744 while ((entity = mpd_recv_entity(c->connection)) != NULL)
745 filelist_append(filelist, entity);
747 if (!mpdclient_finish_command(c)) {
748 filelist_free(filelist);
749 return NULL;
750 }
752 return filelist;
753 }
755 struct filelist *
756 mpdclient_filelist_search(struct mpdclient *c,
757 int exact_match,
758 enum mpd_tag_type tag,
759 gchar *filter_utf8)
760 {
761 if (MPD_ERROR(c))
762 return NULL;
764 mpd_search_db_songs(c->connection, exact_match);
765 mpd_search_add_tag_constraint(c->connection, MPD_OPERATOR_DEFAULT,
766 tag, filter_utf8);
767 mpd_search_commit(c->connection);
769 return mpdclient_recv_filelist_response(c);
770 }
772 bool
773 mpdclient_filelist_add_all(struct mpdclient *c, struct filelist *fl)
774 {
775 guint i;
777 if (MPD_ERROR(c))
778 return false;
780 if (filelist_is_empty(fl))
781 return true;
783 mpd_command_list_begin(c->connection, false);
785 for (i = 0; i < filelist_length(fl); ++i) {
786 struct filelist_entry *entry = filelist_get(fl, i);
787 struct mpd_entity *entity = entry->entity;
789 if (entity != NULL &&
790 mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
791 const struct mpd_song *song =
792 mpd_entity_get_song(entity);
793 const char *uri = mpd_song_get_uri(song);
795 if (uri != NULL)
796 mpd_send_add(c->connection, uri);
797 }
798 }
800 mpd_command_list_end(c->connection);
801 return mpdclient_finish_command(c);
802 }
804 GList *
805 mpdclient_get_artists(struct mpdclient *c)
806 {
807 GList *list = NULL;
808 struct mpd_pair *pair;
810 if (MPD_ERROR(c))
811 return NULL;
813 mpd_search_db_tags(c->connection, MPD_TAG_ARTIST);
814 mpd_search_commit(c->connection);
816 while ((pair = mpd_recv_pair_tag(c->connection,
817 MPD_TAG_ARTIST)) != NULL) {
818 list = g_list_append(list, g_strdup(pair->value));
819 mpd_return_pair(c->connection, pair);
820 }
822 if (!mpdclient_finish_command(c))
823 return string_list_free(list);
825 return list;
826 }
828 GList *
829 mpdclient_get_albums(struct mpdclient *c, const gchar *artist_utf8)
830 {
831 GList *list = NULL;
832 struct mpd_pair *pair;
834 if (MPD_ERROR(c))
835 return NULL;
837 mpd_search_db_tags(c->connection, MPD_TAG_ALBUM);
838 if (artist_utf8 != NULL)
839 mpd_search_add_tag_constraint(c->connection,
840 MPD_OPERATOR_DEFAULT,
841 MPD_TAG_ARTIST, artist_utf8);
842 mpd_search_commit(c->connection);
844 while ((pair = mpd_recv_pair_tag(c->connection,
845 MPD_TAG_ALBUM)) != NULL) {
846 list = g_list_append(list, g_strdup(pair->value));
847 mpd_return_pair(c->connection, pair);
848 }
850 if (!mpdclient_finish_command(c))
851 return string_list_free(list);
853 return list;
854 }