Code

5697bd85d594134e7e8d2aa51df2d1d145f86827
[ncmpc.git] / src / mpdclient.c
1 /* 
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <time.h>
25 #include <string.h>
26 #include <glib.h>
28 #include "config.h"
29 #include "ncmpc.h"
30 #include "support.h"
31 #include "mpdclient.h"
32 #include "options.h"
34 #undef  ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD /* broken with song id's */
35 #define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
36 #define ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
37 #define ENABLE_SONG_ID
38 #define ENABLE_PLCHANGES 
40 #define MPD_ERROR(c) (c==NULL || c->connection==NULL || c->connection->error)
42 /* from utils.c */
43 extern GList *string_list_free(GList *string_list);
45 /* Error callbacks */
46 static gint
47 error_cb(mpdclient_t *c, gint error, gchar *msg)
48 {
49   GList *list = c->error_callbacks;
50   
51   if( list==NULL )
52     fprintf(stderr, "error [%d]: %s\n", (error & 0xFF), msg);
54   while(list)
55     {
56       mpdc_error_cb_t cb = list->data;
57       if( cb )
58         cb(c, error, msg);
59       list=list->next;
60     }
61   mpd_clearError(c->connection);
62   return error;
63 }
65 #ifdef DEBUG
66 // Unused ath the moment
67 /*
68 #include "strfsong.h"
70 static gchar *
71 get_song_name(mpd_Song *song)
72 {
73   static gchar name[256];
75   strfsong(name, 256, "[%artist% - ]%title%|%file%", song);
76   return name;
77 }
78 */
79 #endif
81 /****************************************************************************/
82 /*** mpdclient functions ****************************************************/
83 /****************************************************************************/
85 gint
86 mpdclient_finish_command(mpdclient_t *c) 
87 {
88   mpd_finishCommand(c->connection);
90   if( c->connection->error )
91     {
92       gchar *msg = locale_to_utf8(c->connection->errorStr);
93       gint error = c->connection->error;
94       
95       if( error == MPD_ERROR_ACK )
96         error = error | (c->connection->errorCode << 8);
98       error_cb(c, error, msg);
99       g_free(msg);
100       return error;
101     }
103   return 0;
106 mpdclient_t *
107 mpdclient_new(void)
109   mpdclient_t *c;
111   c = g_malloc0(sizeof(mpdclient_t));
113   return c;
116 mpdclient_t *
117 mpdclient_free(mpdclient_t *c)
119   mpdclient_disconnect(c);
120   g_list_free(c->error_callbacks);
121   g_list_free(c->playlist_callbacks);
122   g_list_free(c->browse_callbacks);
123   g_free(c);
125   return NULL;
128 gint
129 mpdclient_disconnect(mpdclient_t *c)
131   if( c->connection )
132     mpd_closeConnection(c->connection);
133   c->connection = NULL;
135   if( c->status )
136     mpd_freeStatus(c->status);
137   c->status = NULL;
139   if( c->playlist.list )
140     mpdclient_playlist_free(&c->playlist);
142   if( c->song )
143     c->song = NULL;
144   
145   return 0;
148 gint
149 mpdclient_connect(mpdclient_t *c, 
150                   gchar *host, 
151                   gint port, 
152                   gfloat timeout,
153                   gchar *password)
155   gint retval = 0;
156   
157   /* close any open connection */
158   if( c->connection )
159     mpdclient_disconnect(c);
161   /* connect to MPD */
162   c->connection = mpd_newConnection(host, port, timeout);
163   if( c->connection->error )
164     return error_cb(c, c->connection->error, c->connection->errorStr);
166   /* send password */
167   if( password )
168     {
169       mpd_sendPasswordCommand(c->connection, password);
170       retval = mpdclient_finish_command(c);
171     }
172   c->need_update = TRUE;
174   return retval;
177 gint
178 mpdclient_update(mpdclient_t *c)
180   gint retval = 0;
182   if( MPD_ERROR(c) )
183     return -1;
185   /* free the old status */
186   if( c->status )
187     mpd_freeStatus(c->status);
188   
189   /* retreive new status */
190   mpd_sendStatusCommand(c->connection);
191   c->status = mpd_getStatus(c->connection);
192   if( (retval=mpdclient_finish_command(c)) )
193     return retval;
194 #ifdef DEBUG
195   if( c->status->error )
196     D("status> %s\n", c->status->error);
197 #endif
199   /* check if the playlist needs an update */
200   if( c->playlist.id != c->status->playlist )
201     {
202       if( c->playlist.list )
203         retval = mpdclient_playlist_update_changes(c);
204       else
205         retval = mpdclient_playlist_update(c);
206     }
208   /* update the current song */
209   if( !c->song || c->status->songid != c->song->id )
210     {
211       c->song = playlist_get_song(c, c->status->song);
212     }
214   c->need_update = FALSE;
216   return retval;
220 /****************************************************************************/
221 /*** MPD Commands  **********************************************************/
222 /****************************************************************************/
224 gint 
225 mpdclient_cmd_play(mpdclient_t *c, gint index)
227 #ifdef ENABLE_SONG_ID
228   mpd_Song *song = playlist_get_song(c, index);
230   D("Play id:%d\n", song ? song->id : -1);
231   if( song )
232     mpd_sendPlayIdCommand(c->connection, song->id);
233   else
234     mpd_sendPlayIdCommand(c->connection, MPD_PLAY_AT_BEGINNING);
235 #else
236   mpd_sendPlayCommand(c->connection, index);
237 #endif
238   c->need_update = TRUE;
239   return mpdclient_finish_command(c);
242 gint 
243 mpdclient_cmd_pause(mpdclient_t *c, gint value)
245   mpd_sendPauseCommand(c->connection, value);
246   return mpdclient_finish_command(c);
249 gint 
250 mpdclient_cmd_stop(mpdclient_t *c)
252   mpd_sendStopCommand(c->connection);
253   return mpdclient_finish_command(c);
256 gint 
257 mpdclient_cmd_next(mpdclient_t *c)
259   mpd_sendNextCommand(c->connection);
260   c->need_update = TRUE;
261   return mpdclient_finish_command(c);
264 gint 
265 mpdclient_cmd_prev(mpdclient_t *c)
267   mpd_sendPrevCommand(c->connection);
268   c->need_update = TRUE;
269   return mpdclient_finish_command(c);
272 gint 
273 mpdclient_cmd_seek(mpdclient_t *c, gint id, gint pos)
275   D("Seek id:%d\n", id);
276   mpd_sendSeekIdCommand(c->connection, id, pos);
277   return mpdclient_finish_command(c);
280 gint 
281 mpdclient_cmd_shuffle(mpdclient_t *c)
283   mpd_sendShuffleCommand(c->connection);
284   c->need_update = TRUE;
285   return mpdclient_finish_command(c);
288 gint 
289 mpdclient_cmd_clear(mpdclient_t *c)
291   gint retval = 0;
293   mpd_sendClearCommand(c->connection);
294   retval = mpdclient_finish_command(c);
295   /* call playlist updated callback */
296   mpdclient_playlist_callback(c, PLAYLIST_EVENT_CLEAR, NULL);
297   c->need_update = TRUE;
298   return retval;
301 gint 
302 mpdclient_cmd_repeat(mpdclient_t *c, gint value)
304   mpd_sendRepeatCommand(c->connection, value);
305   return mpdclient_finish_command(c);
308 gint 
309 mpdclient_cmd_random(mpdclient_t *c, gint value)
311   mpd_sendRandomCommand(c->connection, value);
312   return mpdclient_finish_command(c);
315 gint 
316 mpdclient_cmd_crossfade(mpdclient_t *c, gint value)
318   mpd_sendCrossfadeCommand(c->connection, value);
319   return mpdclient_finish_command(c);
322 gint 
323 mpdclient_cmd_db_update_utf8(mpdclient_t *c, gchar *path)
325   mpd_sendUpdateCommand(c->connection, path ? path : "");
326   return mpdclient_finish_command(c);
329 gint 
330 mpdclient_cmd_volume(mpdclient_t *c, gint value)
332   mpd_sendSetvolCommand(c->connection, value);
333   return mpdclient_finish_command(c);
336 gint 
337 mpdclient_cmd_add_path_utf8(mpdclient_t *c, gchar *path_utf8)
339   mpd_sendAddCommand(c->connection, path_utf8);
340   return mpdclient_finish_command(c);
343 gint 
344 mpdclient_cmd_add_path(mpdclient_t *c, gchar *path)
346   gint retval;
347   gchar *path_utf8 = locale_to_utf8(path);
349   retval=mpdclient_cmd_add_path_utf8(c, path_utf8);
350   g_free(path_utf8);
351   return retval;
354 gint 
355 mpdclient_cmd_add(mpdclient_t *c, mpd_Song *song)
356
357   gint retval = 0;
359   if( !song || !song->file )
360     return -1;
362   /* send the add command to mpd */
363   mpd_sendAddCommand(c->connection, song->file);
364   if( (retval=mpdclient_finish_command(c)) )
365     return retval;
367 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD
368   /* add the song to playlist */
369   c->playlist.list = g_list_append(c->playlist.list, mpd_songDup(song));
370   c->playlist.length++;
372   /* increment the playlist id, so we dont retrives a new playlist */
373   c->playlist.id++;
375   /* call playlist updated callback */
376   mpdclient_playlist_callback(c, PLAYLIST_EVENT_ADD, (gpointer) song);
377 #else
378   c->need_update = TRUE;
379 #endif
381   return 0;
384 gint
385 mpdclient_cmd_delete(mpdclient_t *c, gint index)
387   gint retval = 0;
388   mpd_Song *song = playlist_get_song(c, index);
390   if( !song )
391     return -1;
393   /* send the delete command to mpd */
394 #ifdef ENABLE_SONG_ID
395   D("Delete id:%d\n", song->id);
396   mpd_sendDeleteIdCommand(c->connection, song->id);
397 #else
398   mpd_sendDeleteCommand(c->connection, index);
399 #endif
400   if( (retval=mpdclient_finish_command(c)) )
401     return retval;
403 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
404   /* increment the playlist id, so we dont retrive a new playlist */
405   c->playlist.id++;
407   /* remove the song from the playlist */
408   c->playlist.list = g_list_remove(c->playlist.list, (gpointer) song);
409   c->playlist.length = g_list_length(c->playlist.list);
411   /* call playlist updated callback */
412   mpdclient_playlist_callback(c, PLAYLIST_EVENT_DELETE, (gpointer) song);
414   /* remove references to the song */
415   if( c->song == song )
416     {
417       c->song = NULL;   
418       c->need_update = TRUE;
419     }
421   /* free song */
422   mpd_freeSong(song);  
424 #else
425   c->need_update = TRUE;
426 #endif
428   return 0;
431 gint
432 mpdclient_cmd_move(mpdclient_t *c, gint old_index, gint new_index)
434   gint n, index1, index2;
435   GList *item1, *item2;
436   gpointer data1, data2;
437   mpd_Song *song1, *song2;
439   if( old_index==new_index || new_index<0 || new_index>=c->playlist.length )
440     return -1;
442   song1 = playlist_get_song(c, old_index);
443   song2 = playlist_get_song(c, new_index);
445   /* send the move command to mpd */  
446 #ifdef ENABLE_SONG_ID
447   D("Swaping id:%d with id:%d\n", song1->id, song2->id);
448   mpd_sendSwapIdCommand(c->connection, song1->id, song2->id);
449 #else
450   D("Moving index %d to id:%d\n", old_index, new_index);
451   mpd_sendMoveCommand(c->connection, old_index, new_index);
452 #endif
453   if( (n=mpdclient_finish_command(c)) )
454     return n;
456 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
457   /* update the songs position field */
458   n = song1->pos;
459   song1->pos = song2->pos;
460   song2->pos = n;
461   index1 = MIN(old_index, new_index);
462   index2 = MAX(old_index, new_index);
463   /* retreive the list items */
464   item1 = g_list_nth(c->playlist.list, index1);
465   item2 = g_list_nth(c->playlist.list, index2);
466   /* retrieve the songs */
467   data1 = item1->data;
468   data2 = item2->data;
470   /* move the second item */
471   c->playlist.list = g_list_remove(c->playlist.list, data2);
472   c->playlist.list = g_list_insert_before(c->playlist.list, item1, data2);
474   /* move the first item */
475   if( index2-index1 >1 )
476     {
477       item2 = g_list_nth(c->playlist.list, index2);
478       c->playlist.list = g_list_remove(c->playlist.list, data1);
479       c->playlist.list = g_list_insert_before(c->playlist.list, item2, data1);
480     }
482   /* increment the playlist id, so we dont retrives a new playlist */
483   c->playlist.id++;
485 #else
486   c->need_update = TRUE;
487 #endif 
489   /* call playlist updated callback */
490   D("move> new_index=%d, old_index=%d\n", new_index, old_index);
491   mpdclient_playlist_callback(c, PLAYLIST_EVENT_MOVE, (gpointer) &new_index);
493   return 0;
496 gint 
497 mpdclient_cmd_save_playlist_utf8(mpdclient_t *c, gchar *filename_utf8)
499   gint retval = 0;
501   mpd_sendSaveCommand(c->connection, filename_utf8);
502   if( (retval=mpdclient_finish_command(c)) == 0 )
503     mpdclient_browse_callback(c, BROWSE_PLAYLIST_SAVED, NULL);
504   return retval;
507 gint 
508 mpdclient_cmd_save_playlist(mpdclient_t *c, gchar *filename)
510   gint retval = 0;
511   gchar *filename_utf8 = locale_to_utf8(filename);
512   
513   retval = mpdclient_cmd_save_playlist_utf8(c, filename);
514   g_free(filename_utf8);
515   return retval;
518 gint 
519 mpdclient_cmd_load_playlist_utf8(mpdclient_t *c, gchar *filename_utf8)
521   mpd_sendLoadCommand(c->connection, filename_utf8);
522   c->need_update = TRUE;
523   return mpdclient_finish_command(c);
526 gint 
527 mpdclient_cmd_delete_playlist_utf8(mpdclient_t *c, gchar *filename_utf8)
529   gint retval = 0;
531   mpd_sendRmCommand(c->connection, filename_utf8);
532   if( (retval=mpdclient_finish_command(c)) == 0 )
533     mpdclient_browse_callback(c, BROWSE_PLAYLIST_DELETED, NULL);
534   return retval;
537 gint 
538 mpdclient_cmd_delete_playlist(mpdclient_t *c, gchar *filename)
540   gint retval = 0;
541   gchar *filename_utf8 = locale_to_utf8(filename);
543   retval = mpdclient_cmd_delete_playlist_utf8(c, filename_utf8);
544   g_free(filename_utf8);
545   return retval;
549 /****************************************************************************/
550 /*** Callback managment functions *******************************************/
551 /****************************************************************************/
552 static void
553 do_list_callbacks(mpdclient_t *c, GList *list, gint event, gpointer data)
555   while(list)
556     {
557       mpdc_list_cb_t fn = list->data;
559       fn(c, event, data);
560       list=list->next;
561     }
564 void
565 mpdclient_playlist_callback(mpdclient_t *c, int event, gpointer data)
567   do_list_callbacks(c, c->playlist_callbacks, event, data);
570 void
571 mpdclient_install_playlist_callback(mpdclient_t *c,mpdc_list_cb_t cb)
573   c->playlist_callbacks = g_list_append(c->playlist_callbacks, cb);
576 void
577 mpdclient_remove_playlist_callback(mpdclient_t *c, mpdc_list_cb_t cb)
579   c->playlist_callbacks = g_list_remove(c->playlist_callbacks, cb);
582 void
583 mpdclient_browse_callback(mpdclient_t *c, int event, gpointer data)
585   do_list_callbacks(c, c->browse_callbacks, event, data);
589 void
590 mpdclient_install_browse_callback(mpdclient_t *c,mpdc_list_cb_t cb)
592   c->browse_callbacks = g_list_append(c->browse_callbacks, cb);
595 void
596 mpdclient_remove_browse_callback(mpdclient_t *c, mpdc_list_cb_t cb)
598   c->browse_callbacks = g_list_remove(c->browse_callbacks, cb);
601 void
602 mpdclient_install_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
604   c->error_callbacks = g_list_append(c->error_callbacks, cb);
607 void
608 mpdclient_remove_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
610   c->error_callbacks = g_list_remove(c->error_callbacks, cb);
613 /****************************************************************************/
614 /*** Playlist managment functions *******************************************/
615 /****************************************************************************/
617 gint
618 mpdclient_playlist_free(mpdclient_playlist_t *playlist)
620   GList *list = g_list_first(playlist->list);
622   while(list)
623     {
624       mpd_Song *song = (mpd_Song *) list->data;
625       mpd_freeSong(song);
626       list=list->next;
627     }
628   g_list_free(playlist->list);
629   memset(playlist, 0, sizeof(mpdclient_playlist_t));
630   return 0;
633 /* update playlist */
634 gint 
635 mpdclient_playlist_update(mpdclient_t *c)
637   mpd_InfoEntity *entity;
639   D("mpdclient_playlist_update() [%lld]\n", c->status->playlist);
641   if( MPD_ERROR(c) )
642     return -1;
644   if( c->playlist.list )
645     mpdclient_playlist_free(&c->playlist);
647   mpd_sendPlaylistInfoCommand(c->connection,-1);
648   while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
649     {
650       if(entity->type==MPD_INFO_ENTITY_TYPE_SONG) 
651         {
652           mpd_Song *song = mpd_songDup(entity->info.song);
654           c->playlist.list = g_list_append(c->playlist.list, (gpointer) song);
655           c->playlist.length++;
656         }
657       mpd_freeInfoEntity(entity);
658     }
659   c->playlist.id = c->status->playlist;
660   c->song = NULL;
661   c->playlist.updated = TRUE;
663   /* call playlist updated callbacks */
664   mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
666   return mpdclient_finish_command(c);
669 #ifdef ENABLE_PLCHANGES
671 gint 
672 mpdclient_compare_songs(gconstpointer a, gconstpointer b)
674   mpd_Song *song1 = (mpd_Song *) a; 
675   mpd_Song *song2 = (mpd_Song *) b; 
677   return song1->pos - song2->pos;
682 /* update playlist (plchanges) */
683 gint 
684 mpdclient_playlist_update_changes(mpdclient_t *c)
686   mpd_InfoEntity *entity;
688   D("mpdclient_playlist_update_changes() [%lld -> %lld]\n", 
689     c->status->playlist, c->playlist.id);
691   if( MPD_ERROR(c) )
692     return -1;
694   mpd_sendPlChangesCommand(c->connection, c->playlist.id); 
696   while( (entity=mpd_getNextInfoEntity(c->connection)) != NULL   ) 
697     {
698       mpd_Song *song = entity->info.song;
700       if( song->pos < c->playlist.length )
701         {
702           GList *item = g_list_nth(c->playlist.list, song->pos);
704           /* update song */
705           D("updating pos:%d, id=%d [%p] - %s\n", 
706             song->pos, song->id, item, song->file);
707           mpd_freeSong((mpd_Song *) item->data);                     
708           item->data = mpd_songDup(song);
709         }
710       else
711         {
712           /* add a new song */
713           D("adding song at pos %d\n", song->pos);
714           c->playlist.list = g_list_append(c->playlist.list, 
715                                            (gpointer) mpd_songDup(song));
716         }
717       
718     }
720   /* remove trailing songs */
721   while( c->status->playlistLength < c->playlist.length )
722     {
723       GList *item = g_list_last(c->playlist.list);
725       /* Remove the last playlist entry */
726       D("removing song at pos %d\n", ((mpd_Song *) item->data)->pos);
727       mpd_freeSong((mpd_Song *) item->data);
728       c->playlist.list = g_list_delete_link(c->playlist.list, item);
729       c->playlist.length = g_list_length(c->playlist.list);   
730     }
732   c->song = NULL;
733   c->playlist.id = c->status->playlist;
734   c->playlist.updated = TRUE;
735   c->playlist.length = g_list_length(c->playlist.list);
737   mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
739   return 0;
742 #else
743 gint 
744 mpdclient_playlist_update_changes(mpdclient_t *c)
746   return mpdclient_playlist_update(c);
748 #endif
750 mpd_Song *
751 playlist_get_song(mpdclient_t *c, gint index)
753   return (mpd_Song *) g_list_nth_data(c->playlist.list, index);
756 GList *
757 playlist_lookup(mpdclient_t *c, int id)
759   GList *list = g_list_first(c->playlist.list);
761   while( list )
762     {
763       mpd_Song *song = (mpd_Song *) list->data;
764       if( song->id == id )
765         return list;
766       list=list->next;
767     }
768   return NULL;
771 mpd_Song *
772 playlist_lookup_song(mpdclient_t *c, gint id)
774   GList *list = c->playlist.list;
776   while( list )
777     {
778       mpd_Song *song = (mpd_Song *) list->data;
779       if( song->id == id )
780         return song;
781       list=list->next;
782     }
783   return NULL;
786 gint 
787 playlist_get_index(mpdclient_t *c, mpd_Song *song)
789   return g_list_index(c->playlist.list, song);
792 gint 
793 playlist_get_index_from_id(mpdclient_t *c, gint id)
795   return g_list_index(c->playlist.list, playlist_lookup_song(c, id));
798 gint
799 playlist_get_index_from_file(mpdclient_t *c, gchar *filename)
801   GList *list = c->playlist.list;
802   gint i=0;
804   while( list )
805     {
806       mpd_Song *song = (mpd_Song *) list->data;
807       if( strcmp(song->file, filename ) == 0 )  
808         return i;
809       list=list->next;
810       i++;
811     }
812   return -1;
816 /****************************************************************************/
817 /*** Filelist functions *****************************************************/
818 /****************************************************************************/
820 mpdclient_filelist_t *
821 mpdclient_filelist_free(mpdclient_filelist_t *filelist)
823   GList *list = g_list_first(filelist->list);
825   D("mpdclient_filelist_free()\n");
826   if( list == NULL )
827     return NULL;
828   while( list!=NULL )
829     {
830       filelist_entry_t *entry = list->data;
832       if( entry->entity )
833         mpd_freeInfoEntity(entry->entity);
834       g_free(entry);
835       list=list->next;
836     }
837   g_list_free(filelist->list);
838   g_free(filelist->path);
839   filelist->path = NULL;
840   filelist->list = NULL;
841   filelist->length = 0;
842   g_free(filelist);
844   return NULL;
848 mpdclient_filelist_t *
849 mpdclient_filelist_get(mpdclient_t *c, gchar *path)
851   mpdclient_filelist_t *filelist;
852   mpd_InfoEntity *entity;
853   gchar *path_utf8 = locale_to_utf8(path);
855   D("mpdclient_filelist_get(%s)\n", path);
856   mpd_sendLsInfoCommand(c->connection, path_utf8);
857   filelist = g_malloc0(sizeof(mpdclient_filelist_t));
858   if( path && path[0] && strcmp(path, "/") )
859     {
860       /* add a dummy entry for ./.. */
861       filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
862       entry->entity = NULL;
863       filelist->list = g_list_append(filelist->list, (gpointer) entry);
864       filelist->length++;
865     }
867   while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
868     {
869       filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
870       
871       entry->entity = entity;
872       filelist->list = g_list_append(filelist->list, (gpointer) entry);
873       filelist->length++;
874     }
875   
876    /* If there's an error, ignore it.  We'll return an empty filelist. */
877    mpdclient_finish_command(c);
878   
879   g_free(path_utf8);
880   filelist->path = g_strdup(path);
881   filelist->updated = TRUE;
883   return filelist;
886 mpdclient_filelist_t *
887 mpdclient_filelist_search_utf8(mpdclient_t *c, 
888                                int exact_match,
889                                int table, 
890                                gchar *filter_utf8)
892   mpdclient_filelist_t *filelist;
893   mpd_InfoEntity *entity;
895   D("mpdclient_filelist_search(%s)\n", filter_utf8);
896   if( exact_match )
897     mpd_sendFindCommand(c->connection, table, filter_utf8);
898   else
899     mpd_sendSearchCommand(c->connection, table, filter_utf8);
900   filelist = g_malloc0(sizeof(mpdclient_filelist_t));
902   while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
903     {
904       filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
905       
906       entry->entity = entity;
907       filelist->list = g_list_append(filelist->list, (gpointer) entry);
908       filelist->length++;
909     }
910   
911   if( mpdclient_finish_command(c) )
912     return mpdclient_filelist_free(filelist);
914   filelist->updated = TRUE;
916   return filelist;
920 mpdclient_filelist_t *
921 mpdclient_filelist_search(mpdclient_t *c,
922                           int exact_match, 
923                           int table, 
924                           gchar *filter)
926   mpdclient_filelist_t *filelist;
927   gchar *filter_utf8 = locale_to_utf8(filter);
929   D("mpdclient_filelist_search(%s)\n", filter);
930   filelist = mpdclient_filelist_search_utf8(c,exact_match,table,filter_utf8);
931   g_free(filter_utf8);
933   return filelist;
936 mpdclient_filelist_t *
937 mpdclient_filelist_update(mpdclient_t *c, mpdclient_filelist_t *filelist)
939   if( filelist != NULL )
940     {    
941       gchar *path = g_strdup(filelist->path);
943       filelist = mpdclient_filelist_free(filelist);
944       filelist = mpdclient_filelist_get(c, path);
945       g_free(path);
946       return filelist;
947     }
948   return NULL;
951 filelist_entry_t *
952 mpdclient_filelist_find_song(mpdclient_filelist_t *fl, mpd_Song *song)
954   GList *list = g_list_first(fl->list);
956   while( list && song)
957     {
958       filelist_entry_t *entry = list->data;
959       mpd_InfoEntity *entity  = entry->entity;
961       if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
962         {
963           mpd_Song *song2 = entity->info.song;
965           if( strcmp(song->file, song2->file) == 0 )
966             {
967               return entry;
968             }
969         }
970       list = list->next;
971     }
972   return NULL;
975 int
976 mpdclient_filelist_add_all(mpdclient_t *c, mpdclient_filelist_t *fl)
978   GList *list = g_list_first(fl->list);
980   if( fl->list==NULL || fl->length<1 )
981     return 0;
983   mpd_sendCommandListBegin(c->connection);
984   while( list )
985     {
986       filelist_entry_t *entry = list->data;
987       mpd_InfoEntity *entity  = entry->entity;
989       if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
990         {
991           mpd_Song *song = entity->info.song;
993           mpd_sendAddCommand(c->connection, song->file);
994         }
995       list = list->next;
996     }
997   mpd_sendCommandListEnd(c->connection);
998   return mpdclient_finish_command(c);
1008 GList *
1009 mpdclient_get_artists_utf8(mpdclient_t *c)
1011   gchar *str = NULL; 
1012   GList *list = NULL;
1014   D("mpdclient_get_artists()\n");
1015   mpd_sendListCommand(c->connection, MPD_TABLE_ARTIST, NULL);
1016   while( (str=mpd_getNextArtist(c->connection)) )
1017     {
1018       list = g_list_append(list, (gpointer) str);
1019     }
1020   if( mpdclient_finish_command(c) )
1021     {
1022       return string_list_free(list);
1023     }  
1025   return list;
1028 GList *
1029 mpdclient_get_albums_utf8(mpdclient_t *c, gchar *artist_utf8)
1031   gchar *str = NULL; 
1032   GList *list = NULL;
1034   D("mpdclient_get_albums(%s)\n", artist_utf8);
1035   mpd_sendListCommand(c->connection, MPD_TABLE_ALBUM, artist_utf8);
1036   while( (str=mpd_getNextAlbum(c->connection)) )
1037     {
1038       list = g_list_append(list, (gpointer) str);
1039     }
1040   if( mpdclient_finish_command(c) )
1041     {
1042       return string_list_free(list);
1043     }  
1044   
1045   return list;