Code

due to bensonk's demand i added a splash screen.
[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       if( error == MPD_ERROR_ACK )
95         error = error | (c->connection->errorCode << 8);
96       if(  c->connection->errorCode == MPD_ACK_ERROR_PERMISSION )
97         {
98           if(screen_auth(c) == 0) return 0;
99         }
100       error_cb(c, error, msg);
101       g_free(msg);
102       return error;
103     }
105   return 0;
108 mpdclient_t *
109 mpdclient_new(void)
111   mpdclient_t *c;
113   c = g_malloc0(sizeof(mpdclient_t));
115   return c;
118 mpdclient_t *
119 mpdclient_free(mpdclient_t *c)
121   mpdclient_disconnect(c);
122   g_list_free(c->error_callbacks);
123   g_list_free(c->playlist_callbacks);
124   g_list_free(c->browse_callbacks);
125   g_free(c);
127   return NULL;
130 gint
131 mpdclient_disconnect(mpdclient_t *c)
133   if( c->connection )
134     mpd_closeConnection(c->connection);
135   c->connection = NULL;
137   if( c->status )
138     mpd_freeStatus(c->status);
139   c->status = NULL;
141   if( c->playlist.list )
142     mpdclient_playlist_free(&c->playlist);
144   if( c->song )
145     c->song = NULL;
146   
147   return 0;
150 gint
151 mpdclient_connect(mpdclient_t *c, 
152                   gchar *host, 
153                   gint port, 
154                   gfloat timeout,
155                   gchar *password)
157   gint retval = 0;
158   
159   /* close any open connection */
160   if( c->connection )
161     mpdclient_disconnect(c);
163   /* connect to MPD */
164   c->connection = mpd_newConnection(host, port, timeout);
165   if( c->connection->error )
166     return error_cb(c, c->connection->error, c->connection->errorStr);
168   /* send password */
169   if( password )
170     {
171       mpd_sendPasswordCommand(c->connection, password);
172       retval = mpdclient_finish_command(c);
173     }
174   c->need_update = TRUE;
176   return retval;
179 gint
180 mpdclient_update(mpdclient_t *c)
182   gint retval = 0;
184   if( MPD_ERROR(c) )
185     return -1;
187   /* free the old status */
188   if( c->status )
189     mpd_freeStatus(c->status);
190   
191   /* retreive new status */
192   mpd_sendStatusCommand(c->connection);
193   c->status = mpd_getStatus(c->connection);
194   if( (retval=mpdclient_finish_command(c)) )
195     return retval;
196 #ifdef DEBUG
197   if( c->status->error )
198     D("status> %s\n", c->status->error);
199 #endif
201   /* check if the playlist needs an update */
202   if( c->playlist.id != c->status->playlist )
203     {
204       if( c->playlist.list )
205         retval = mpdclient_playlist_update_changes(c);
206       else
207         retval = mpdclient_playlist_update(c);
208     }
210   /* update the current song */
211   if( !c->song || c->status->songid != c->song->id )
212     {
213       c->song = playlist_get_song(c, c->status->song);
214     }
216   c->need_update = FALSE;
218   return retval;
222 /****************************************************************************/
223 /*** MPD Commands  **********************************************************/
224 /****************************************************************************/
226 gint 
227 mpdclient_cmd_play(mpdclient_t *c, gint index)
229 #ifdef ENABLE_SONG_ID
230   mpd_Song *song = playlist_get_song(c, index);
232   D("Play id:%d\n", song ? song->id : -1);
233   if( song )
234     mpd_sendPlayIdCommand(c->connection, song->id);
235   else
236     mpd_sendPlayIdCommand(c->connection, MPD_PLAY_AT_BEGINNING);
237 #else
238   mpd_sendPlayCommand(c->connection, index);
239 #endif
240   c->need_update = TRUE;
241   return mpdclient_finish_command(c);
244 gint 
245 mpdclient_cmd_pause(mpdclient_t *c, gint value)
247   mpd_sendPauseCommand(c->connection, value);
248   return mpdclient_finish_command(c);
251 gint 
252 mpdclient_cmd_stop(mpdclient_t *c)
254   mpd_sendStopCommand(c->connection);
255   return mpdclient_finish_command(c);
258 gint 
259 mpdclient_cmd_next(mpdclient_t *c)
261   mpd_sendNextCommand(c->connection);
262   c->need_update = TRUE;
263   return mpdclient_finish_command(c);
266 gint 
267 mpdclient_cmd_prev(mpdclient_t *c)
269   mpd_sendPrevCommand(c->connection);
270   c->need_update = TRUE;
271   return mpdclient_finish_command(c);
274 gint 
275 mpdclient_cmd_seek(mpdclient_t *c, gint id, gint pos)
277   D("Seek id:%d\n", id);
278   mpd_sendSeekIdCommand(c->connection, id, pos);
279   return mpdclient_finish_command(c);
282 gint 
283 mpdclient_cmd_shuffle(mpdclient_t *c)
285   mpd_sendShuffleCommand(c->connection);
286   c->need_update = TRUE;
287   return mpdclient_finish_command(c);
290 gint 
291 mpdclient_cmd_clear(mpdclient_t *c)
293   gint retval = 0;
295   mpd_sendClearCommand(c->connection);
296   retval = mpdclient_finish_command(c);
297   /* call playlist updated callback */
298   mpdclient_playlist_callback(c, PLAYLIST_EVENT_CLEAR, NULL);
299   c->need_update = TRUE;
300   return retval;
303 gint 
304 mpdclient_cmd_repeat(mpdclient_t *c, gint value)
306   mpd_sendRepeatCommand(c->connection, value);
307   return mpdclient_finish_command(c);
310 gint 
311 mpdclient_cmd_random(mpdclient_t *c, gint value)
313   mpd_sendRandomCommand(c->connection, value);
314   return mpdclient_finish_command(c);
317 gint 
318 mpdclient_cmd_crossfade(mpdclient_t *c, gint value)
320   mpd_sendCrossfadeCommand(c->connection, value);
321   return mpdclient_finish_command(c);
324 gint 
325 mpdclient_cmd_db_update_utf8(mpdclient_t *c, gchar *path)
327   mpd_sendUpdateCommand(c->connection, path ? path : "");
328   return mpdclient_finish_command(c);
331 gint 
332 mpdclient_cmd_volume(mpdclient_t *c, gint value)
334   mpd_sendSetvolCommand(c->connection, value);
335   return mpdclient_finish_command(c);
338 gint 
339 mpdclient_cmd_add_path_utf8(mpdclient_t *c, gchar *path_utf8)
341   mpd_sendAddCommand(c->connection, path_utf8);
342   return mpdclient_finish_command(c);
345 gint 
346 mpdclient_cmd_add_path(mpdclient_t *c, gchar *path)
348   gint retval;
349   gchar *path_utf8 = locale_to_utf8(path);
351   retval=mpdclient_cmd_add_path_utf8(c, path_utf8);
352   g_free(path_utf8);
353   return retval;
356 gint 
357 mpdclient_cmd_add(mpdclient_t *c, mpd_Song *song)
358
359   gint retval = 0;
361   if( !song || !song->file )
362     return -1;
364   /* send the add command to mpd */
365   mpd_sendAddCommand(c->connection, song->file);
366   if( (retval=mpdclient_finish_command(c)) )
367     return retval;
369 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD
370   /* add the song to playlist */
371   c->playlist.list = g_list_append(c->playlist.list, mpd_songDup(song));
372   c->playlist.length++;
374   /* increment the playlist id, so we dont retrives a new playlist */
375   c->playlist.id++;
377   /* call playlist updated callback */
378   mpdclient_playlist_callback(c, PLAYLIST_EVENT_ADD, (gpointer) song);
379 #else
380   c->need_update = TRUE;
381 #endif
383   return 0;
386 gint
387 mpdclient_cmd_delete(mpdclient_t *c, gint index)
389   gint retval = 0;
390   mpd_Song *song = playlist_get_song(c, index);
392   if( !song )
393     return -1;
395   /* send the delete command to mpd */
396 #ifdef ENABLE_SONG_ID
397   D("Delete id:%d\n", song->id);
398   mpd_sendDeleteIdCommand(c->connection, song->id);
399 #else
400   mpd_sendDeleteCommand(c->connection, index);
401 #endif
402   if( (retval=mpdclient_finish_command(c)) )
403     return retval;
405 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
406   /* increment the playlist id, so we dont retrive a new playlist */
407   c->playlist.id++;
409   /* remove the song from the playlist */
410   c->playlist.list = g_list_remove(c->playlist.list, (gpointer) song);
411   c->playlist.length = g_list_length(c->playlist.list);
413   /* call playlist updated callback */
414   mpdclient_playlist_callback(c, PLAYLIST_EVENT_DELETE, (gpointer) song);
416   /* remove references to the song */
417   if( c->song == song )
418     {
419       c->song = NULL;   
420       c->need_update = TRUE;
421     }
423   /* free song */
424   mpd_freeSong(song);  
426 #else
427   c->need_update = TRUE;
428 #endif
430   return 0;
433 gint
434 mpdclient_cmd_move(mpdclient_t *c, gint old_index, gint new_index)
436   gint n, index1, index2;
437   GList *item1, *item2;
438   gpointer data1, data2;
439   mpd_Song *song1, *song2;
441   if( old_index==new_index || new_index<0 || new_index>=c->playlist.length )
442     return -1;
444   song1 = playlist_get_song(c, old_index);
445   song2 = playlist_get_song(c, new_index);
447   /* send the move command to mpd */  
448 #ifdef ENABLE_SONG_ID
449   D("Swapping id:%d with id:%d\n", song1->id, song2->id);
450   mpd_sendSwapIdCommand(c->connection, song1->id, song2->id);
451 #else
452   D("Moving index %d to id:%d\n", old_index, new_index);
453   mpd_sendMoveCommand(c->connection, old_index, new_index);
454 #endif
455   if( (n=mpdclient_finish_command(c)) )
456     return n;
458 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
459   /* update the songs position field */
460   n = song1->pos;
461   song1->pos = song2->pos;
462   song2->pos = n;
463   index1 = MIN(old_index, new_index);
464   index2 = MAX(old_index, new_index);
465   /* retreive the list items */
466   item1 = g_list_nth(c->playlist.list, index1);
467   item2 = g_list_nth(c->playlist.list, index2);
468   /* retrieve the songs */
469   data1 = item1->data;
470   data2 = item2->data;
472   /* move the second item */
473   c->playlist.list = g_list_remove(c->playlist.list, data2);
474   c->playlist.list = g_list_insert_before(c->playlist.list, item1, data2);
476   /* move the first item */
477   if( index2-index1 >1 )
478     {
479       item2 = g_list_nth(c->playlist.list, index2);
480       c->playlist.list = g_list_remove(c->playlist.list, data1);
481       c->playlist.list = g_list_insert_before(c->playlist.list, item2, data1);
482     }
484   /* increment the playlist id, so we dont retrives a new playlist */
485   c->playlist.id++;
487 #else
488   c->need_update = TRUE;
489 #endif 
491   /* call playlist updated callback */
492   D("move> new_index=%d, old_index=%d\n", new_index, old_index);
493   mpdclient_playlist_callback(c, PLAYLIST_EVENT_MOVE, (gpointer) &new_index);
495   return 0;
498 gint 
499 mpdclient_cmd_save_playlist_utf8(mpdclient_t *c, gchar *filename_utf8)
501   gint retval = 0;
503   mpd_sendSaveCommand(c->connection, filename_utf8);
504   if( (retval=mpdclient_finish_command(c)) == 0 )
505     mpdclient_browse_callback(c, BROWSE_PLAYLIST_SAVED, NULL);
506   return retval;
509 gint 
510 mpdclient_cmd_save_playlist(mpdclient_t *c, gchar *filename)
512   gint retval = 0;
513   gchar *filename_utf8 = locale_to_utf8(filename);
514   
515   retval = mpdclient_cmd_save_playlist_utf8(c, filename);
516   g_free(filename_utf8);
517   return retval;
520 gint 
521 mpdclient_cmd_load_playlist_utf8(mpdclient_t *c, gchar *filename_utf8)
523   mpd_sendLoadCommand(c->connection, filename_utf8);
524   c->need_update = TRUE;
525   return mpdclient_finish_command(c);
528 gint 
529 mpdclient_cmd_delete_playlist_utf8(mpdclient_t *c, gchar *filename_utf8)
531   gint retval = 0;
533   mpd_sendRmCommand(c->connection, filename_utf8);
534   if( (retval=mpdclient_finish_command(c)) == 0 )
535     mpdclient_browse_callback(c, BROWSE_PLAYLIST_DELETED, NULL);
536   return retval;
539 gint 
540 mpdclient_cmd_delete_playlist(mpdclient_t *c, gchar *filename)
542   gint retval = 0;
543   gchar *filename_utf8 = locale_to_utf8(filename);
545   retval = mpdclient_cmd_delete_playlist_utf8(c, filename_utf8);
546   g_free(filename_utf8);
547   return retval;
551 /****************************************************************************/
552 /*** Callback managment functions *******************************************/
553 /****************************************************************************/
554 static void
555 do_list_callbacks(mpdclient_t *c, GList *list, gint event, gpointer data)
557   while(list)
558     {
559       mpdc_list_cb_t fn = list->data;
561       fn(c, event, data);
562       list=list->next;
563     }
566 void
567 mpdclient_playlist_callback(mpdclient_t *c, int event, gpointer data)
569   do_list_callbacks(c, c->playlist_callbacks, event, data);
572 void
573 mpdclient_install_playlist_callback(mpdclient_t *c,mpdc_list_cb_t cb)
575   c->playlist_callbacks = g_list_append(c->playlist_callbacks, cb);
578 void
579 mpdclient_remove_playlist_callback(mpdclient_t *c, mpdc_list_cb_t cb)
581   c->playlist_callbacks = g_list_remove(c->playlist_callbacks, cb);
584 void
585 mpdclient_browse_callback(mpdclient_t *c, int event, gpointer data)
587   do_list_callbacks(c, c->browse_callbacks, event, data);
591 void
592 mpdclient_install_browse_callback(mpdclient_t *c,mpdc_list_cb_t cb)
594   c->browse_callbacks = g_list_append(c->browse_callbacks, cb);
597 void
598 mpdclient_remove_browse_callback(mpdclient_t *c, mpdc_list_cb_t cb)
600   c->browse_callbacks = g_list_remove(c->browse_callbacks, cb);
603 void
604 mpdclient_install_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
606   c->error_callbacks = g_list_append(c->error_callbacks, cb);
609 void
610 mpdclient_remove_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
612   c->error_callbacks = g_list_remove(c->error_callbacks, cb);
615 /****************************************************************************/
616 /*** Playlist managment functions *******************************************/
617 /****************************************************************************/
619 gint
620 mpdclient_playlist_free(mpdclient_playlist_t *playlist)
622   GList *list = g_list_first(playlist->list);
624   while(list)
625     {
626       mpd_Song *song = (mpd_Song *) list->data;
627       mpd_freeSong(song);
628       list=list->next;
629     }
630   g_list_free(playlist->list);
631   memset(playlist, 0, sizeof(mpdclient_playlist_t));
632   return 0;
635 /* update playlist */
636 gint 
637 mpdclient_playlist_update(mpdclient_t *c)
639   mpd_InfoEntity *entity;
641   D("mpdclient_playlist_update() [%lld]\n", c->status->playlist);
643   if( MPD_ERROR(c) )
644     return -1;
646   if( c->playlist.list )
647     mpdclient_playlist_free(&c->playlist);
649   mpd_sendPlaylistInfoCommand(c->connection,-1);
650   while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
651     {
652       if(entity->type==MPD_INFO_ENTITY_TYPE_SONG) 
653         {
654           mpd_Song *song = mpd_songDup(entity->info.song);
656           c->playlist.list = g_list_append(c->playlist.list, (gpointer) song);
657           c->playlist.length++;
658         }
659       mpd_freeInfoEntity(entity);
660     }
661   c->playlist.id = c->status->playlist;
662   c->song = NULL;
663   c->playlist.updated = TRUE;
665   /* call playlist updated callbacks */
666   mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
668   return mpdclient_finish_command(c);
671 #ifdef ENABLE_PLCHANGES
673 gint 
674 mpdclient_compare_songs(gconstpointer a, gconstpointer b)
676   mpd_Song *song1 = (mpd_Song *) a; 
677   mpd_Song *song2 = (mpd_Song *) b; 
679   return song1->pos - song2->pos;
684 /* update playlist (plchanges) */
685 gint 
686 mpdclient_playlist_update_changes(mpdclient_t *c)
688   mpd_InfoEntity *entity;
690   D("mpdclient_playlist_update_changes() [%lld -> %lld]\n", 
691     c->status->playlist, c->playlist.id);
693   if( MPD_ERROR(c) )
694     return -1;
696   mpd_sendPlChangesCommand(c->connection, c->playlist.id); 
698   while( (entity=mpd_getNextInfoEntity(c->connection)) != NULL   ) 
699     {
700       mpd_Song *song = entity->info.song;
702       if( song->pos < c->playlist.length )
703         {
704           GList *item = g_list_nth(c->playlist.list, song->pos);
706           /* update song */
707           D("updating pos:%d, id=%d [%p] - %s\n", 
708             song->pos, song->id, item, song->file);
709           mpd_freeSong((mpd_Song *) item->data);                     
710           item->data = mpd_songDup(song);
711         }
712       else
713         {
714           /* add a new song */
715           D("adding song at pos %d\n", song->pos);
716           c->playlist.list = g_list_append(c->playlist.list, 
717                                            (gpointer) mpd_songDup(song));
718         }
719       
720     }
722   /* remove trailing songs */
723   while( c->status->playlistLength < c->playlist.length )
724     {
725       GList *item = g_list_last(c->playlist.list);
727       /* Remove the last playlist entry */
728       D("removing song at pos %d\n", ((mpd_Song *) item->data)->pos);
729       mpd_freeSong((mpd_Song *) item->data);
730       c->playlist.list = g_list_delete_link(c->playlist.list, item);
731       c->playlist.length = g_list_length(c->playlist.list);   
732     }
734   c->song = NULL;
735   c->playlist.id = c->status->playlist;
736   c->playlist.updated = TRUE;
737   c->playlist.length = g_list_length(c->playlist.list);
739   mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
741   return 0;
744 #else
745 gint 
746 mpdclient_playlist_update_changes(mpdclient_t *c)
748   return mpdclient_playlist_update(c);
750 #endif
752 mpd_Song *
753 playlist_get_song(mpdclient_t *c, gint index)
755   return (mpd_Song *) g_list_nth_data(c->playlist.list, index);
758 GList *
759 playlist_lookup(mpdclient_t *c, int id)
761   GList *list = g_list_first(c->playlist.list);
763   while( list )
764     {
765       mpd_Song *song = (mpd_Song *) list->data;
766       if( song->id == id )
767         return list;
768       list=list->next;
769     }
770   return NULL;
773 mpd_Song *
774 playlist_lookup_song(mpdclient_t *c, gint id)
776   GList *list = c->playlist.list;
778   while( list )
779     {
780       mpd_Song *song = (mpd_Song *) list->data;
781       if( song->id == id )
782         return song;
783       list=list->next;
784     }
785   return NULL;
788 gint 
789 playlist_get_index(mpdclient_t *c, mpd_Song *song)
791   return g_list_index(c->playlist.list, song);
794 gint 
795 playlist_get_index_from_id(mpdclient_t *c, gint id)
797   return g_list_index(c->playlist.list, playlist_lookup_song(c, id));
800 gint
801 playlist_get_index_from_file(mpdclient_t *c, gchar *filename)
803   GList *list = c->playlist.list;
804   gint i=0;
806   while( list )
807     {
808       mpd_Song *song = (mpd_Song *) list->data;
809       if( strcmp(song->file, filename ) == 0 )  
810         return i;
811       list=list->next;
812       i++;
813     }
814   return -1;
818 /****************************************************************************/
819 /*** Filelist functions *****************************************************/
820 /****************************************************************************/
822 mpdclient_filelist_t *
823 mpdclient_filelist_free(mpdclient_filelist_t *filelist)
825   GList *list = g_list_first(filelist->list);
827   D("mpdclient_filelist_free()\n");
828   if( list == NULL )
829     return NULL;
830   while( list!=NULL )
831     {
832       filelist_entry_t *entry = list->data;
834       if( entry->entity )
835         mpd_freeInfoEntity(entry->entity);
836       g_free(entry);
837       list=list->next;
838     }
839   g_list_free(filelist->list);
840   g_free(filelist->path);
841   filelist->path = NULL;
842   filelist->list = NULL;
843   filelist->length = 0;
844   g_free(filelist);
846   return NULL;
850 mpdclient_filelist_t *
851 mpdclient_filelist_get(mpdclient_t *c, gchar *path)
853   mpdclient_filelist_t *filelist;
854   mpd_InfoEntity *entity;
855   gchar *path_utf8 = locale_to_utf8(path);
857   D("mpdclient_filelist_get(%s)\n", path);
858   mpd_sendLsInfoCommand(c->connection, path_utf8);
859   filelist = g_malloc0(sizeof(mpdclient_filelist_t));
860   if( path && path[0] && strcmp(path, "/") )
861     {
862       /* add a dummy entry for ./.. */
863       filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
864       entry->entity = NULL;
865       filelist->list = g_list_append(filelist->list, (gpointer) entry);
866       filelist->length++;
867     }
869   while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
870     {
871       filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
872       
873       entry->entity = entity;
874       filelist->list = g_list_append(filelist->list, (gpointer) entry);
875       filelist->length++;
876     }
877   
878    /* If there's an error, ignore it.  We'll return an empty filelist. */
879    mpdclient_finish_command(c);
880   
881   g_free(path_utf8);
882   filelist->path = g_strdup(path);
883   filelist->updated = TRUE;
885   return filelist;
888 mpdclient_filelist_t *
889 mpdclient_filelist_search_utf8(mpdclient_t *c, 
890                                int exact_match,
891                                int table, 
892                                gchar *filter_utf8)
894   mpdclient_filelist_t *filelist;
895   mpd_InfoEntity *entity;
897   D("mpdclient_filelist_search(%s)\n", filter_utf8);
898   if( exact_match )
899     mpd_sendFindCommand(c->connection, table, filter_utf8);
900   else
901     mpd_sendSearchCommand(c->connection, table, filter_utf8);
902   filelist = g_malloc0(sizeof(mpdclient_filelist_t));
904   while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
905     {
906       filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
907       
908       entry->entity = entity;
909       filelist->list = g_list_append(filelist->list, (gpointer) entry);
910       filelist->length++;
911     }
912   
913   if( mpdclient_finish_command(c) )
914     return mpdclient_filelist_free(filelist);
916   filelist->updated = TRUE;
918   return filelist;
922 mpdclient_filelist_t *
923 mpdclient_filelist_search(mpdclient_t *c,
924                           int exact_match, 
925                           int table, 
926                           gchar *filter)
928   mpdclient_filelist_t *filelist;
929   gchar *filter_utf8 = locale_to_utf8(filter);
931   D("mpdclient_filelist_search(%s)\n", filter);
932   filelist = mpdclient_filelist_search_utf8(c,exact_match,table,filter_utf8);
933   g_free(filter_utf8);
935   return filelist;
938 mpdclient_filelist_t *
939 mpdclient_filelist_update(mpdclient_t *c, mpdclient_filelist_t *filelist)
941   if( filelist != NULL )
942     {    
943       gchar *path = g_strdup(filelist->path);
945       filelist = mpdclient_filelist_free(filelist);
946       filelist = mpdclient_filelist_get(c, path);
947       g_free(path);
948       return filelist;
949     }
950   return NULL;
953 filelist_entry_t *
954 mpdclient_filelist_find_song(mpdclient_filelist_t *fl, mpd_Song *song)
956   GList *list = g_list_first(fl->list);
958   while( list && song)
959     {
960       filelist_entry_t *entry = list->data;
961       mpd_InfoEntity *entity  = entry->entity;
963       if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
964         {
965           mpd_Song *song2 = entity->info.song;
967           if( strcmp(song->file, song2->file) == 0 )
968             {
969               return entry;
970             }
971         }
972       list = list->next;
973     }
974   return NULL;
977 int
978 mpdclient_filelist_add_all(mpdclient_t *c, mpdclient_filelist_t *fl)
980   GList *list = g_list_first(fl->list);
982   if( fl->list==NULL || fl->length<1 )
983     return 0;
985   mpd_sendCommandListBegin(c->connection);
986   while( list )
987     {
988       filelist_entry_t *entry = list->data;
989       mpd_InfoEntity *entity  = entry->entity;
991       if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
992         {
993           mpd_Song *song = entity->info.song;
995           mpd_sendAddCommand(c->connection, song->file);
996         }
997       list = list->next;
998     }
999   mpd_sendCommandListEnd(c->connection);
1000   return mpdclient_finish_command(c);
1010 GList *
1011 mpdclient_get_artists_utf8(mpdclient_t *c)
1013   gchar *str = NULL; 
1014   GList *list = NULL;
1016   D("mpdclient_get_artists()\n");
1017   mpd_sendListCommand(c->connection, MPD_TABLE_ARTIST, NULL);
1018   while( (str=mpd_getNextArtist(c->connection)) )
1019     {
1020       list = g_list_append(list, (gpointer) str);
1021     }
1022   if( mpdclient_finish_command(c) )
1023     {
1024       return string_list_free(list);
1025     }  
1027   return list;
1030 GList *
1031 mpdclient_get_albums_utf8(mpdclient_t *c, gchar *artist_utf8)
1033   gchar *str = NULL; 
1034   GList *list = NULL;
1036   D("mpdclient_get_albums(%s)\n", artist_utf8);
1037   mpd_sendListCommand(c->connection, MPD_TABLE_ALBUM, artist_utf8);
1038   while( (str=mpd_getNextAlbum(c->connection)) )
1039     {
1040       list = g_list_append(list, (gpointer) str);
1041     }
1042   if( mpdclient_finish_command(c) )
1043     {
1044       return string_list_free(list);
1045     }  
1046   
1047   return list;