Code

0897e8607471bba86dbee1bf26dced9e7527b5f2
[ncmpc.git] / src / mpdclient.c
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 "screen_utils.h"
22 #include "config.h"
23 #include "options.h"
24 #include "strfsong.h"
25 #include "utils.h"
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <time.h>
30 #include <string.h>
32 #undef  ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD /* broken with song id's */
33 #define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
34 #define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
35 #define ENABLE_SONG_ID
36 #define ENABLE_PLCHANGES
38 #define BUFSIZE 1024
40 static bool
41 MPD_ERROR(const struct mpdclient *client)
42 {
43         return client->connection == NULL;
44 }
46 /* filelist sorting functions */
47 static gint
48 compare_filelistentry(gconstpointer filelist_entry1,
49                           gconstpointer filelist_entry2)
50 {
51         const mpd_InfoEntity *e1, *e2;
52         int n = 0;
54         e1 = ((const filelist_entry_t *)filelist_entry1)->entity;
55         e2 = ((const filelist_entry_t *)filelist_entry2)->entity;
57         if (e1 && e2 && e1->type == e2->type) {
58                 switch (e1->type) {
59                 case MPD_INFO_ENTITY_TYPE_DIRECTORY:
60                         n = g_utf8_collate(e1->info.directory->path,
61                                         e2->info.directory->path);
62                         break;
63                 case MPD_INFO_ENTITY_TYPE_SONG:
64                         break;
65                 case MPD_INFO_ENTITY_TYPE_PLAYLISTFILE:
66                         n = g_utf8_collate(e1->info.playlistFile->path,
67                                         e2->info.playlistFile->path);
68                 }
69         }
70         return n;
71 }
73 /* sort by list-format */
74 gint
75 compare_filelistentry_format(gconstpointer filelist_entry1,
76                              gconstpointer filelist_entry2)
77 {
78         const mpd_InfoEntity *e1, *e2;
79         char key1[BUFSIZE], key2[BUFSIZE];
80         int n = 0;
82         e1 = ((const filelist_entry_t *)filelist_entry1)->entity;
83         e2 = ((const filelist_entry_t *)filelist_entry2)->entity;
85         if (e1 && e2 &&
86             e1->type == MPD_INFO_ENTITY_TYPE_SONG &&
87             e2->type == MPD_INFO_ENTITY_TYPE_SONG) {
88                 strfsong(key1, BUFSIZE, options.list_format, e1->info.song);
89                 strfsong(key2, BUFSIZE, options.list_format, e2->info.song);
90                 n = strcmp(key1,key2);
91         }
93         return n;
94 }
97 /* Error callbacks */
98 static gint
99 error_cb(mpdclient_t *c, gint error, const gchar *msg)
101         GList *list = c->error_callbacks;
103         if (list == NULL)
104                 fprintf(stderr, "error [%d]: %s\n", (error & 0xFF), msg);
106         while (list) {
107                 mpdc_error_cb_t cb = list->data;
108                 if (cb)
109                         cb(c, error, msg);
110                 list = list->next;
111         }
113         mpd_clearError(c->connection);
114         return error;
118 /****************************************************************************/
119 /*** mpdclient functions ****************************************************/
120 /****************************************************************************/
122 static gint
123 mpdclient_handle_error(mpdclient_t *c)
125         enum mpd_error error = c->connection->error;
126         bool is_fatal = error != MPD_ERROR_ACK;
128         if (error == MPD_ERROR_SUCCESS)
129                 return 0;
131         if (error == MPD_ERROR_ACK &&
132             c->connection->errorCode == MPD_ACK_ERROR_PERMISSION &&
133             screen_auth(c) == 0)
134                 return 0;
136         if (error == MPD_ERROR_ACK)
137                 error = error | (c->connection->errorCode << 8);
139         error_cb(c, error, c->connection->errorStr);
141         if (is_fatal)
142                 mpdclient_disconnect(c);
144         return error;
147 gint
148 mpdclient_finish_command(mpdclient_t *c)
150         mpd_finishCommand(c->connection);
151         return mpdclient_handle_error(c);
154 mpdclient_t *
155 mpdclient_new(void)
157         mpdclient_t *c;
159         c = g_malloc0(sizeof(mpdclient_t));
160         playlist_init(&c->playlist);
161         c->volume = MPD_STATUS_NO_VOLUME;
163         return c;
166 void
167 mpdclient_free(mpdclient_t *c)
169         mpdclient_disconnect(c);
171         mpdclient_playlist_free(&c->playlist);
173         g_list_free(c->error_callbacks);
174         g_list_free(c->playlist_callbacks);
175         g_list_free(c->browse_callbacks);
176         g_free(c);
179 gint
180 mpdclient_disconnect(mpdclient_t *c)
182         if (c->connection)
183                 mpd_closeConnection(c->connection);
184         c->connection = NULL;
186         if (c->status)
187                 mpd_freeStatus(c->status);
188         c->status = NULL;
190         playlist_clear(&c->playlist);
192         if (c->song)
193                 c->song = NULL;
195         return 0;
198 gint
199 mpdclient_connect(mpdclient_t *c,
200                   const gchar *host,
201                   gint port,
202                   gfloat _timeout,
203                   const gchar *password)
205         gint retval = 0;
207         /* close any open connection */
208         if( c->connection )
209                 mpdclient_disconnect(c);
211         /* connect to MPD */
212         c->connection = mpd_newConnection(host, port, _timeout);
213         if (c->connection->error) {
214                 retval = error_cb(c, c->connection->error,
215                                   c->connection->errorStr);
216                 if (retval != 0) {
217                         mpd_closeConnection(c->connection);
218                         c->connection = NULL;
219                 }
221                 return retval;
222         }
224         /* send password */
225         if( password ) {
226                 mpd_sendPasswordCommand(c->connection, password);
227                 retval = mpdclient_finish_command(c);
228         }
229         c->need_update = TRUE;
231         return retval;
234 gint
235 mpdclient_update(mpdclient_t *c)
237         gint retval = 0;
239         c->volume = MPD_STATUS_NO_VOLUME;
241         if (MPD_ERROR(c))
242                 return -1;
244         /* free the old status */
245         if (c->status)
246                 mpd_freeStatus(c->status);
248         /* retrieve new status */
249         mpd_sendStatusCommand(c->connection);
250         c->status = mpd_getStatus(c->connection);
251         if ((retval=mpdclient_finish_command(c)))
252                 return retval;
254         if (c->updatingdb && c->updatingdb != c->status->updatingDb)
255                 mpdclient_browse_callback(c, BROWSE_DB_UPDATED, NULL);
257         c->updatingdb = c->status->updatingDb;
258         c->volume = c->status->volume;
260         /* check if the playlist needs an update */
261         if (c->playlist.id != c->status->playlist) {
262                 if (playlist_is_empty(&c->playlist))
263                         retval = mpdclient_playlist_update_changes(c);
264                 else
265                         retval = mpdclient_playlist_update(c);
266         }
268         /* update the current song */
269         if (!c->song || c->status->songid != c->song->id) {
270                 c->song = playlist_get_song(c, c->status->song);
271         }
273         c->need_update = FALSE;
275         return retval;
279 /****************************************************************************/
280 /*** MPD Commands  **********************************************************/
281 /****************************************************************************/
283 gint
284 mpdclient_cmd_play(mpdclient_t *c, gint idx)
286 #ifdef ENABLE_SONG_ID
287         struct mpd_song *song = playlist_get_song(c, idx);
289         if (MPD_ERROR(c))
290                 return -1;
292         if (song)
293                 mpd_sendPlayIdCommand(c->connection, song->id);
294         else
295                 mpd_sendPlayIdCommand(c->connection, MPD_PLAY_AT_BEGINNING);
296 #else
297         if (MPD_ERROR(c))
298                 return -1;
300         mpd_sendPlayCommand(c->connection, idx);
301 #endif
302         c->need_update = TRUE;
303         return mpdclient_finish_command(c);
306 gint
307 mpdclient_cmd_pause(mpdclient_t *c, gint value)
309         if (MPD_ERROR(c))
310                 return -1;
312         mpd_sendPauseCommand(c->connection, value);
313         return mpdclient_finish_command(c);
316 gint
317 mpdclient_cmd_crop(mpdclient_t *c)
319         gint error;
320         mpd_Status *status;
321         bool playing;
322         int length, current;
324         if (MPD_ERROR(c))
325                 return -1;
327         mpd_sendStatusCommand(c->connection);
328         status = mpd_getStatus(c->connection);
329         error = mpdclient_finish_command(c);
330         if (error)
331                 return error;
333         playing = status->state == MPD_STATUS_STATE_PLAY ||
334                 status->state == MPD_STATUS_STATE_PAUSE;
335         length = status->playlistLength;
336         current = status->song;
338         mpd_freeStatus(status);
340         if (!playing || length < 2)
341                 return 0;
343         mpd_sendCommandListBegin( c->connection );
345         while (--length >= 0)
346                 if (length != current)
347                         mpd_sendDeleteCommand(c->connection, length);
349         mpd_sendCommandListEnd(c->connection);
351         return mpdclient_finish_command(c);
354 gint
355 mpdclient_cmd_stop(mpdclient_t *c)
357         if (MPD_ERROR(c))
358                 return -1;
360         mpd_sendStopCommand(c->connection);
361         return mpdclient_finish_command(c);
364 gint
365 mpdclient_cmd_next(mpdclient_t *c)
367         if (MPD_ERROR(c))
368                 return -1;
370         mpd_sendNextCommand(c->connection);
371         c->need_update = TRUE;
372         return mpdclient_finish_command(c);
375 gint
376 mpdclient_cmd_prev(mpdclient_t *c)
378         if (MPD_ERROR(c))
379                 return -1;
381         mpd_sendPrevCommand(c->connection);
382         c->need_update = TRUE;
383         return mpdclient_finish_command(c);
386 gint
387 mpdclient_cmd_seek(mpdclient_t *c, gint id, gint pos)
389         if (MPD_ERROR(c))
390                 return -1;
392         mpd_sendSeekIdCommand(c->connection, id, pos);
393         return mpdclient_finish_command(c);
396 gint
397 mpdclient_cmd_shuffle(mpdclient_t *c)
399         if (MPD_ERROR(c))
400                 return -1;
402         mpd_sendShuffleCommand(c->connection);
403         c->need_update = TRUE;
404         return mpdclient_finish_command(c);
407 gint
408 mpdclient_cmd_shuffle_range(mpdclient_t *c, guint start, guint end)
410         mpd_sendShuffleRangeCommand(c->connection, start, end);
411         c->need_update = TRUE;
412         return mpdclient_finish_command(c);
415 gint
416 mpdclient_cmd_clear(mpdclient_t *c)
418         gint retval = 0;
420         if (MPD_ERROR(c))
421                 return -1;
423         mpd_sendClearCommand(c->connection);
424         retval = mpdclient_finish_command(c);
425         /* call playlist updated callback */
426         mpdclient_playlist_callback(c, PLAYLIST_EVENT_CLEAR, NULL);
427         c->need_update = TRUE;
428         return retval;
431 gint
432 mpdclient_cmd_repeat(mpdclient_t *c, gint value)
434         if (MPD_ERROR(c))
435                 return -1;
437         mpd_sendRepeatCommand(c->connection, value);
438         return mpdclient_finish_command(c);
441 gint
442 mpdclient_cmd_random(mpdclient_t *c, gint value)
444         if (MPD_ERROR(c))
445                 return -1;
447         mpd_sendRandomCommand(c->connection, value);
448         return mpdclient_finish_command(c);
451 gint
452 mpdclient_cmd_single(mpdclient_t *c, gint value)
454         if (MPD_ERROR(c))
455                 return -1;
457         mpd_sendSingleCommand(c->connection, value);
458         return mpdclient_finish_command(c);
461 gint
462 mpdclient_cmd_consume(mpdclient_t *c, gint value)
464         if (MPD_ERROR(c))
465                 return -1;
467         mpd_sendConsumeCommand(c->connection, value);
468         return mpdclient_finish_command(c);
471 gint
472 mpdclient_cmd_crossfade(mpdclient_t *c, gint value)
474         if (MPD_ERROR(c))
475                 return -1;
477         mpd_sendCrossfadeCommand(c->connection, value);
478         return mpdclient_finish_command(c);
481 gint
482 mpdclient_cmd_db_update(mpdclient_t *c, const gchar *path)
484         gint ret;
486         if (MPD_ERROR(c))
487                 return -1;
489         mpd_sendUpdateCommand(c->connection, path ? path : "");
490         ret = mpdclient_finish_command(c);
492         if (ret == 0)
493                 /* set updatingDb to make sure the browse callback
494                    gets called even if the update has finished before
495                    status is updated */
496                 c->updatingdb = 1;
498         return ret;
501 gint
502 mpdclient_cmd_volume(mpdclient_t *c, gint value)
504         if (MPD_ERROR(c))
505                 return -1;
507         mpd_sendSetvolCommand(c->connection, value);
508         return mpdclient_finish_command(c);
511 gint mpdclient_cmd_volume_up(struct mpdclient *c)
513         if (MPD_ERROR(c))
514                 return -1;
516         if (c->status == NULL || c->status->volume == MPD_STATUS_NO_VOLUME)
517                 return 0;
519         if (c->volume == MPD_STATUS_NO_VOLUME)
520                 c->volume = c->status->volume;
522         if (c->volume >= 100)
523                 return 0;
525         return mpdclient_cmd_volume(c, ++c->volume);
528 gint mpdclient_cmd_volume_down(struct mpdclient *c)
530         if (MPD_ERROR(c))
531                 return -1;
533         if (c->status == NULL || c->status->volume == MPD_STATUS_NO_VOLUME)
534                 return 0;
536         if (c->volume == MPD_STATUS_NO_VOLUME)
537                 c->volume = c->status->volume;
539         if (c->volume <= 0)
540                 return 0;
542         return mpdclient_cmd_volume(c, --c->volume);
545 gint
546 mpdclient_cmd_add_path(mpdclient_t *c, const gchar *path_utf8)
548         if (MPD_ERROR(c))
549                 return -1;
551         mpd_sendAddCommand(c->connection, path_utf8);
552         return mpdclient_finish_command(c);
555 gint
556 mpdclient_cmd_add(mpdclient_t *c, const struct mpd_song *song)
558         gint retval = 0;
560         if (MPD_ERROR(c))
561                 return -1;
563         if( !song || !song->file )
564                 return -1;
566         /* send the add command to mpd */
567         mpd_sendAddCommand(c->connection, song->file);
568         if( (retval=mpdclient_finish_command(c)) )
569                 return retval;
571 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD
572         /* add the song to playlist */
573         playlist_append(&c->playlist, song);
575         /* increment the playlist id, so we don't retrieve a new playlist */
576         c->playlist.id++;
578         /* call playlist updated callback */
579         mpdclient_playlist_callback(c, PLAYLIST_EVENT_ADD, (gpointer) song);
580 #else
581         c->need_update = TRUE;
582 #endif
584         return 0;
587 gint
588 mpdclient_cmd_delete(mpdclient_t *c, gint idx)
590         gint retval = 0;
591         struct mpd_song *song;
593         if (MPD_ERROR(c))
594                 return -1;
596         if (idx < 0 || (guint)idx >= playlist_length(&c->playlist))
597                 return -1;
599         song = playlist_get(&c->playlist, idx);
601         /* send the delete command to mpd */
602 #ifdef ENABLE_SONG_ID
603         mpd_sendDeleteIdCommand(c->connection, song->id);
604 #else
605         mpd_sendDeleteCommand(c->connection, idx);
606 #endif
607         if( (retval=mpdclient_finish_command(c)) )
608                 return retval;
610 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
611         /* increment the playlist id, so we don't retrieve a new playlist */
612         c->playlist.id++;
614         /* remove the song from the playlist */
615         playlist_remove_reuse(&c->playlist, idx);
617         /* call playlist updated callback */
618         mpdclient_playlist_callback(c, PLAYLIST_EVENT_DELETE, (gpointer) song);
620         /* remove references to the song */
621         if (c->song == song) {
622                 c->song = NULL;
623                 c->need_update = TRUE;
624         }
626         mpd_freeSong(song);
628 #else
629         c->need_update = TRUE;
630 #endif
632         return 0;
635 gint
636 mpdclient_cmd_move(mpdclient_t *c, gint old_index, gint new_index)
638         gint n;
639         struct mpd_song *song1, *song2;
641         if (MPD_ERROR(c))
642                 return -1;
644         if (old_index == new_index || new_index < 0 ||
645             (guint)new_index >= c->playlist.list->len)
646                 return -1;
648         song1 = playlist_get(&c->playlist, old_index);
649         song2 = playlist_get(&c->playlist, new_index);
651         /* send the move command to mpd */
652 #ifdef ENABLE_SONG_ID
653         mpd_sendSwapIdCommand(c->connection, song1->id, song2->id);
654 #else
655         mpd_sendMoveCommand(c->connection, old_index, new_index);
656 #endif
657         if( (n=mpdclient_finish_command(c)) )
658                 return n;
660 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
661         /* update the playlist */
662         playlist_swap(&c->playlist, old_index, new_index);
664         /* increment the playlist id, so we don't retrieve a new playlist */
665         c->playlist.id++;
667 #else
668         c->need_update = TRUE;
669 #endif
671         /* call playlist updated callback */
672         mpdclient_playlist_callback(c, PLAYLIST_EVENT_MOVE, (gpointer) &new_index);
674         return 0;
677 gint
678 mpdclient_cmd_save_playlist(mpdclient_t *c, const gchar *filename_utf8)
680         gint retval = 0;
682         if (MPD_ERROR(c))
683                 return -1;
685         mpd_sendSaveCommand(c->connection, filename_utf8);
686         if ((retval = mpdclient_finish_command(c)) == 0)
687                 mpdclient_browse_callback(c, BROWSE_PLAYLIST_SAVED, NULL);
688         return retval;
691 gint
692 mpdclient_cmd_load_playlist(mpdclient_t *c, const gchar *filename_utf8)
694         if (MPD_ERROR(c))
695                 return -1;
697         mpd_sendLoadCommand(c->connection, filename_utf8);
698         c->need_update = TRUE;
699         return mpdclient_finish_command(c);
702 gint
703 mpdclient_cmd_delete_playlist(mpdclient_t *c, const gchar *filename_utf8)
705         gint retval = 0;
707         if (MPD_ERROR(c))
708                 return -1;
710         mpd_sendRmCommand(c->connection, filename_utf8);
711         if ((retval = mpdclient_finish_command(c)) == 0)
712                 mpdclient_browse_callback(c, BROWSE_PLAYLIST_DELETED, NULL);
713         return retval;
717 /****************************************************************************/
718 /*** Callback management functions ******************************************/
719 /****************************************************************************/
721 static void
722 do_list_callbacks(mpdclient_t *c, GList *list, gint event, gpointer data)
724         while (list) {
725                 mpdc_list_cb_t fn = list->data;
727                 fn(c, event, data);
728                 list = list->next;
729         }
732 void
733 mpdclient_playlist_callback(mpdclient_t *c, int event, gpointer data)
735         do_list_callbacks(c, c->playlist_callbacks, event, data);
738 void
739 mpdclient_install_playlist_callback(mpdclient_t *c,mpdc_list_cb_t cb)
741         c->playlist_callbacks = g_list_append(c->playlist_callbacks, cb);
744 void
745 mpdclient_remove_playlist_callback(mpdclient_t *c, mpdc_list_cb_t cb)
747         c->playlist_callbacks = g_list_remove(c->playlist_callbacks, cb);
750 void
751 mpdclient_browse_callback(mpdclient_t *c, int event, gpointer data)
753         do_list_callbacks(c, c->browse_callbacks, event, data);
757 void
758 mpdclient_install_browse_callback(mpdclient_t *c,mpdc_list_cb_t cb)
760         c->browse_callbacks = g_list_append(c->browse_callbacks, cb);
763 void
764 mpdclient_remove_browse_callback(mpdclient_t *c, mpdc_list_cb_t cb)
766         c->browse_callbacks = g_list_remove(c->browse_callbacks, cb);
769 void
770 mpdclient_install_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
772         c->error_callbacks = g_list_append(c->error_callbacks, cb);
775 void
776 mpdclient_remove_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
778         c->error_callbacks = g_list_remove(c->error_callbacks, cb);
782 /****************************************************************************/
783 /*** Playlist management functions ******************************************/
784 /****************************************************************************/
786 /* update playlist */
787 gint
788 mpdclient_playlist_update(mpdclient_t *c)
790         mpd_InfoEntity *entity;
792         if (MPD_ERROR(c))
793                 return -1;
795         playlist_clear(&c->playlist);
797         mpd_sendPlaylistInfoCommand(c->connection,-1);
798         while ((entity = mpd_getNextInfoEntity(c->connection))) {
799                 if (entity->type == MPD_INFO_ENTITY_TYPE_SONG)
800                         playlist_append(&c->playlist, entity->info.song);
802                 mpd_freeInfoEntity(entity);
803         }
805         c->playlist.id = c->status->playlist;
806         c->song = NULL;
808         /* call playlist updated callbacks */
809         mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
811         return mpdclient_finish_command(c);
814 #ifdef ENABLE_PLCHANGES
816 /* update playlist (plchanges) */
817 gint
818 mpdclient_playlist_update_changes(mpdclient_t *c)
820         mpd_InfoEntity *entity;
822         if (MPD_ERROR(c))
823                 return -1;
825         mpd_sendPlChangesCommand(c->connection, c->playlist.id);
827         while ((entity = mpd_getNextInfoEntity(c->connection)) != NULL) {
828                 struct mpd_song *song = entity->info.song;
830                 if (song->pos >= 0 && (guint)song->pos < c->playlist.list->len) {
831                         /* update song */
832                         playlist_replace(&c->playlist, song->pos, song);
833                 } else {
834                         /* add a new song */
835                         playlist_append(&c->playlist, song);
836                 }
838                 mpd_freeInfoEntity(entity);
839         }
841         /* remove trailing songs */
842         while ((guint)c->status->playlistLength < c->playlist.list->len) {
843                 guint pos = c->playlist.list->len - 1;
845                 /* Remove the last playlist entry */
846                 playlist_remove(&c->playlist, pos);
847         }
849         c->song = NULL;
850         c->playlist.id = c->status->playlist;
852         mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
854         return 0;
857 #else
858 gint
859 mpdclient_playlist_update_changes(mpdclient_t *c)
861         return mpdclient_playlist_update(c);
863 #endif
866 /****************************************************************************/
867 /*** Filelist functions *****************************************************/
868 /****************************************************************************/
870 mpdclient_filelist_t *
871 mpdclient_filelist_get(mpdclient_t *c, const gchar *path)
873         mpdclient_filelist_t *filelist;
874         mpd_InfoEntity *entity;
876         if (MPD_ERROR(c))
877                 return NULL;
879         mpd_sendLsInfoCommand(c->connection, path);
880         filelist = filelist_new();
881         if (path && path[0] && strcmp(path, "/"))
882                 /* add a dummy entry for ./.. */
883                 filelist_append(filelist, NULL);
885         while ((entity=mpd_getNextInfoEntity(c->connection))) {
886                 filelist_append(filelist, entity);
887         }
889         /* If there's an error, ignore it.  We'll return an empty filelist. */
890         mpdclient_finish_command(c);
892         filelist_sort_dir_play(filelist, compare_filelistentry);
894         return filelist;
897 mpdclient_filelist_t *
898 mpdclient_filelist_search(mpdclient_t *c,
899                           int exact_match,
900                           int table,
901                           gchar *filter_utf8)
903         mpdclient_filelist_t *filelist;
904         mpd_InfoEntity *entity;
906         if (MPD_ERROR(c))
907                 return NULL;
909         if (exact_match)
910                 mpd_sendFindCommand(c->connection, table, filter_utf8);
911         else
912                 mpd_sendSearchCommand(c->connection, table, filter_utf8);
913         filelist = filelist_new();
915         while ((entity=mpd_getNextInfoEntity(c->connection)))
916                 filelist_append(filelist, entity);
918         if (mpdclient_finish_command(c)) {
919                 filelist_free(filelist);
920                 return NULL;
921         }
923         return filelist;
926 int
927 mpdclient_filelist_add_all(mpdclient_t *c, mpdclient_filelist_t *fl)
929         guint i;
931         if (MPD_ERROR(c))
932                 return -1;
934         if (filelist_is_empty(fl))
935                 return 0;
937         mpd_sendCommandListBegin(c->connection);
939         for (i = 0; i < filelist_length(fl); ++i) {
940                 filelist_entry_t *entry = filelist_get(fl, i);
941                 mpd_InfoEntity *entity  = entry->entity;
943                 if (entity && entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
944                         struct mpd_song *song = entity->info.song;
946                         mpd_sendAddCommand(c->connection, song->file);
947                 }
948         }
950         mpd_sendCommandListEnd(c->connection);
951         return mpdclient_finish_command(c);
954 GList *
955 mpdclient_get_artists(mpdclient_t *c)
957         gchar *str = NULL;
958         GList *list = NULL;
960         if (MPD_ERROR(c))
961                return NULL;
963         mpd_sendListCommand(c->connection, MPD_TABLE_ARTIST, NULL);
964         while ((str = mpd_getNextArtist(c->connection)))
965                 list = g_list_append(list, (gpointer) str);
967         if (mpdclient_finish_command(c))
968                 return string_list_free(list);
970         return list;
973 GList *
974 mpdclient_get_albums(mpdclient_t *c, const gchar *artist_utf8)
976         gchar *str = NULL;
977         GList *list = NULL;
979         if (MPD_ERROR(c))
980                return NULL;
982         mpd_sendListCommand(c->connection, MPD_TABLE_ALBUM, artist_utf8);
983         while ((str = mpd_getNextAlbum(c->connection)))
984                 list = g_list_append(list, (gpointer) str);
986         if (mpdclient_finish_command(c))
987                 return string_list_free(list);
989         return list;