bb6c90fa9e4fc5de84fef192c19bbe5a78f48030
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)
43 /* Error callbacks */
44 static gint
45 error_cb(mpdclient_t *c, gint error, gchar *msg)
46 {
47 GList *list = c->error_callbacks;
49 if( list==NULL )
50 fprintf(stderr, "error [%d]: %s\n", (error & 0xFF), msg);
52 while(list)
53 {
54 mpdc_error_cb_t cb = list->data;
55 if( cb )
56 cb(c, error, msg);
57 list=list->next;
58 }
59 mpd_clearError(c->connection);
60 return error;
61 }
63 #ifdef DEBUG
64 #include "strfsong.h"
66 static gchar *
67 get_song_name(mpd_Song *song)
68 {
69 static gchar name[256];
71 strfsong(name, 256, "[%artist% - ]%title%|%file%", song);
72 return name;
73 }
75 #endif
77 /****************************************************************************/
78 /*** mpdclient functions ****************************************************/
79 /****************************************************************************/
81 gint
82 mpdclient_finish_command(mpdclient_t *c)
83 {
84 mpd_finishCommand(c->connection);
86 if( c->connection->error )
87 {
88 gchar *msg = locale_to_utf8(c->connection->errorStr);
89 gint error = c->connection->error;
91 if( error == MPD_ERROR_ACK )
92 error = error | (c->connection->errorCode << 8);
94 error_cb(c, error, msg);
95 g_free(msg);
96 return error;
97 }
99 return 0;
100 }
102 mpdclient_t *
103 mpdclient_new(void)
104 {
105 mpdclient_t *c;
107 c = g_malloc0(sizeof(mpdclient_t));
109 return c;
110 }
112 mpdclient_t *
113 mpdclient_free(mpdclient_t *c)
114 {
115 mpdclient_disconnect(c);
116 g_list_free(c->error_callbacks);
117 g_list_free(c->playlist_callbacks);
118 g_list_free(c->browse_callbacks);
119 g_free(c);
121 return NULL;
122 }
124 gint
125 mpdclient_disconnect(mpdclient_t *c)
126 {
127 if( c->connection )
128 mpd_closeConnection(c->connection);
129 c->connection = NULL;
131 if( c->status )
132 mpd_freeStatus(c->status);
133 c->status = NULL;
135 if( c->playlist.list )
136 mpdclient_playlist_free(&c->playlist);
138 if( c->song )
139 c->song = NULL;
141 return 0;
142 }
144 gint
145 mpdclient_connect(mpdclient_t *c,
146 gchar *host,
147 gint port,
148 gfloat timeout,
149 gchar *password)
150 {
151 gint retval = 0;
153 /* close any open connection */
154 if( c->connection )
155 mpdclient_disconnect(c);
157 /* connect to MPD */
158 c->connection = mpd_newConnection(host, port, timeout);
159 if( c->connection->error )
160 return error_cb(c, c->connection->error, c->connection->errorStr);
162 /* send password */
163 if( password )
164 {
165 mpd_sendPasswordCommand(c->connection, password);
166 retval = mpdclient_finish_command(c);
167 }
168 c->need_update = TRUE;
170 return retval;
171 }
173 gint
174 mpdclient_update(mpdclient_t *c)
175 {
176 gint retval = 0;
178 if( MPD_ERROR(c) )
179 return -1;
181 /* free the old status */
182 if( c->status )
183 mpd_freeStatus(c->status);
185 /* retreive new status */
186 mpd_sendStatusCommand(c->connection);
187 c->status = mpd_getStatus(c->connection);
188 if( (retval=mpdclient_finish_command(c)) )
189 return retval;
190 #ifdef DEBUG
191 if( c->status->error )
192 D("status> %s\n", c->status->error);
193 #endif
195 /* check if the playlist needs an update */
196 if( c->playlist.id != c->status->playlist )
197 {
198 if( c->playlist.list )
199 retval = mpdclient_playlist_update_changes(c);
200 else
201 retval = mpdclient_playlist_update(c);
202 }
204 /* update the current song */
205 if( !c->song || c->status->songid != c->song->id )
206 {
207 c->song = playlist_get_song(c, c->status->song);
208 }
210 c->need_update = FALSE;
212 return retval;
213 }
216 /****************************************************************************/
217 /*** MPD Commands **********************************************************/
218 /****************************************************************************/
220 gint
221 mpdclient_cmd_play(mpdclient_t *c, gint index)
222 {
223 #ifdef ENABLE_SONG_ID
224 mpd_Song *song = playlist_get_song(c, index);
226 D("Play id:%d\n", song ? song->id : -1);
227 if( song )
228 mpd_sendPlayIdCommand(c->connection, song->id);
229 else
230 mpd_sendPlayIdCommand(c->connection, MPD_PLAY_AT_BEGINNING);
231 #else
232 mpd_sendPlayCommand(c->connection, index);
233 #endif
234 c->need_update = TRUE;
235 return mpdclient_finish_command(c);
236 }
238 gint
239 mpdclient_cmd_pause(mpdclient_t *c, gint value)
240 {
241 mpd_sendPauseCommand(c->connection, value);
242 return mpdclient_finish_command(c);
243 }
245 gint
246 mpdclient_cmd_stop(mpdclient_t *c)
247 {
248 mpd_sendStopCommand(c->connection);
249 return mpdclient_finish_command(c);
250 }
252 gint
253 mpdclient_cmd_next(mpdclient_t *c)
254 {
255 mpd_sendNextCommand(c->connection);
256 c->need_update = TRUE;
257 return mpdclient_finish_command(c);
258 }
260 gint
261 mpdclient_cmd_prev(mpdclient_t *c)
262 {
263 mpd_sendPrevCommand(c->connection);
264 c->need_update = TRUE;
265 return mpdclient_finish_command(c);
266 }
268 gint
269 mpdclient_cmd_seek(mpdclient_t *c, gint id, gint pos)
270 {
271 D("Seek id:%d\n", id);
272 mpd_sendSeekIdCommand(c->connection, id, pos);
273 return mpdclient_finish_command(c);
274 }
276 gint
277 mpdclient_cmd_shuffle(mpdclient_t *c)
278 {
279 mpd_sendShuffleCommand(c->connection);
280 c->need_update = TRUE;
281 return mpdclient_finish_command(c);
282 }
284 gint
285 mpdclient_cmd_clear(mpdclient_t *c)
286 {
287 gint retval = 0;
289 mpd_sendClearCommand(c->connection);
290 retval = mpdclient_finish_command(c);
291 /* call playlist updated callback */
292 mpdclient_playlist_callback(c, PLAYLIST_EVENT_CLEAR, NULL);
293 c->need_update = TRUE;
294 return retval;
295 }
297 gint
298 mpdclient_cmd_repeat(mpdclient_t *c, gint value)
299 {
300 mpd_sendRepeatCommand(c->connection, value);
301 return mpdclient_finish_command(c);
302 }
304 gint
305 mpdclient_cmd_random(mpdclient_t *c, gint value)
306 {
307 mpd_sendRandomCommand(c->connection, value);
308 return mpdclient_finish_command(c);
309 }
311 gint
312 mpdclient_cmd_crossfade(mpdclient_t *c, gint value)
313 {
314 mpd_sendCrossfadeCommand(c->connection, value);
315 return mpdclient_finish_command(c);
316 }
318 gint
319 mpdclient_cmd_db_update(mpdclient_t *c, gchar *path)
320 {
321 mpd_sendUpdateCommand(c->connection, path ? path : "");
322 return mpdclient_finish_command(c);
323 }
325 gint
326 mpdclient_cmd_volume(mpdclient_t *c, gint value)
327 {
328 mpd_sendSetvolCommand(c->connection, value);
329 return mpdclient_finish_command(c);
330 }
332 gint
333 mpdclient_cmd_add(mpdclient_t *c, mpd_Song *song)
334 {
335 gint retval = 0;
337 if( !song || !song->file )
338 return -1;
340 /* send the add command to mpd */
341 mpd_sendAddCommand(c->connection, song->file);
342 if( (retval=mpdclient_finish_command(c)) )
343 return retval;
345 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_ADD
346 /* add the song to playlist */
347 c->playlist.list = g_list_append(c->playlist.list, mpd_songDup(song));
348 c->playlist.length++;
350 /* increment the playlist id, so we dont retrives a new playlist */
351 c->playlist.id++;
353 /* call playlist updated callback */
354 mpdclient_playlist_callback(c, PLAYLIST_EVENT_ADD, (gpointer) song);
355 #else
356 c->need_update = TRUE;
357 #endif
359 return 0;
360 }
362 gint
363 mpdclient_cmd_delete(mpdclient_t *c, gint index)
364 {
365 gint retval = 0;
366 mpd_Song *song = playlist_get_song(c, index);
368 if( !song )
369 return -1;
371 /* send the delete command to mpd */
372 #ifdef ENABLE_SONG_ID
373 D("Delete id:%d\n", song->id);
374 mpd_sendDeleteIdCommand(c->connection, song->id);
375 #else
376 mpd_sendDeleteCommand(c->connection, index);
377 #endif
378 if( (retval=mpdclient_finish_command(c)) )
379 return retval;
381 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_DELETE
382 /* increment the playlist id, so we dont retrive a new playlist */
383 c->playlist.id++;
385 /* remove the song from the playlist */
386 c->playlist.list = g_list_remove(c->playlist.list, (gpointer) song);
387 c->playlist.length = g_list_length(c->playlist.list);
389 /* call playlist updated callback */
390 mpdclient_playlist_callback(c, PLAYLIST_EVENT_DELETE, (gpointer) song);
392 /* remove references to the song */
393 if( c->song == song )
394 {
395 c->song = NULL;
396 c->need_update = TRUE;
397 }
399 /* free song */
400 mpd_freeSong(song);
402 #else
403 c->need_update = TRUE;
404 #endif
406 return 0;
407 }
409 gint
410 mpdclient_cmd_move(mpdclient_t *c, gint old_index, gint new_index)
411 {
412 gint n, index1, index2;
413 GList *item1, *item2;
414 gpointer data1, data2;
415 mpd_Song *song1, *song2;
417 if( old_index==new_index || new_index<0 || new_index>=c->playlist.length )
418 return -1;
420 song1 = playlist_get_song(c, old_index);
421 song2 = playlist_get_song(c, new_index);
423 /* send the move command to mpd */
424 #ifdef ENABLE_SONG_ID
425 D("Swaping id:%d with id:%d\n", song1->id, song2->id);
426 mpd_sendSwapIdCommand(c->connection, song1->id, song2->id);
427 #else
428 D("Moving index %d to id:%d\n", old_index, new_index);
429 mpd_sendMoveCommand(c->connection, old_index, new_index);
430 #endif
431 if( (n=mpdclient_finish_command(c)) )
432 return n;
434 #ifdef ENABLE_FANCY_PLAYLIST_MANAGMENT_CMD_MOVE
435 /* update the songs position field */
436 n = song1->pos;
437 song1->pos = song2->pos;
438 song2->pos = n;
439 index1 = MIN(old_index, new_index);
440 index2 = MAX(old_index, new_index);
441 /* retreive the list items */
442 item1 = g_list_nth(c->playlist.list, index1);
443 item2 = g_list_nth(c->playlist.list, index2);
444 /* retrieve the songs */
445 data1 = item1->data;
446 data2 = item2->data;
448 /* move the second item */
449 c->playlist.list = g_list_remove(c->playlist.list, data2);
450 c->playlist.list = g_list_insert_before(c->playlist.list, item1, data2);
452 /* move the first item */
453 if( index2-index1 >1 )
454 {
455 item2 = g_list_nth(c->playlist.list, index2);
456 c->playlist.list = g_list_remove(c->playlist.list, data1);
457 c->playlist.list = g_list_insert_before(c->playlist.list, item2, data1);
458 }
460 /* increment the playlist id, so we dont retrives a new playlist */
461 c->playlist.id++;
463 #else
464 c->need_update = TRUE;
465 #endif
467 /* call playlist updated callback */
468 mpdclient_playlist_callback(c, PLAYLIST_EVENT_MOVE, (gpointer) &new_index);
470 return 0;
471 }
473 gint
474 mpdclient_cmd_save_playlist(mpdclient_t *c, gchar *filename)
475 {
476 gint retval = 0;
477 gchar *filename_utf8 = locale_to_utf8(filename);
479 mpd_sendSaveCommand(c->connection, filename_utf8);
480 if( (retval=mpdclient_finish_command(c)) == 0 )
481 mpdclient_browse_callback(c, BROWSE_PLAYLIST_SAVED, NULL);
482 g_free(filename_utf8);
483 return retval;
484 }
486 gint
487 mpdclient_cmd_load_playlist(mpdclient_t *c, gchar *filename_utf8)
488 {
489 mpd_sendLoadCommand(c->connection, filename_utf8);
490 c->need_update = TRUE;
491 return mpdclient_finish_command(c);
492 }
494 gint
495 mpdclient_cmd_delete_playlist(mpdclient_t *c, gchar *filename_utf8)
496 {
497 gint retval = 0;
499 mpd_sendRmCommand(c->connection, filename_utf8);
500 if( (retval=mpdclient_finish_command(c)) == 0 )
501 mpdclient_browse_callback(c, BROWSE_PLAYLIST_DELETED, NULL);
502 return retval;
503 }
506 /****************************************************************************/
507 /*** Callback managment functions *******************************************/
508 /****************************************************************************/
509 static void
510 do_list_callbacks(mpdclient_t *c, GList *list, gint event, gpointer data)
511 {
512 while(list)
513 {
514 mpdc_list_cb_t fn = list->data;
516 fn(c, event, data);
517 list=list->next;
518 }
519 }
521 void
522 mpdclient_playlist_callback(mpdclient_t *c, int event, gpointer data)
523 {
524 do_list_callbacks(c, c->playlist_callbacks, event, data);
525 }
527 void
528 mpdclient_install_playlist_callback(mpdclient_t *c,mpdc_list_cb_t cb)
529 {
530 c->playlist_callbacks = g_list_append(c->playlist_callbacks, cb);
531 }
533 void
534 mpdclient_remove_playlist_callback(mpdclient_t *c, mpdc_list_cb_t cb)
535 {
536 c->playlist_callbacks = g_list_remove(c->playlist_callbacks, cb);
537 }
539 void
540 mpdclient_browse_callback(mpdclient_t *c, int event, gpointer data)
541 {
542 do_list_callbacks(c, c->browse_callbacks, event, data);
543 }
546 void
547 mpdclient_install_browse_callback(mpdclient_t *c,mpdc_list_cb_t cb)
548 {
549 c->browse_callbacks = g_list_append(c->browse_callbacks, cb);
550 }
552 void
553 mpdclient_remove_browse_callback(mpdclient_t *c, mpdc_list_cb_t cb)
554 {
555 c->browse_callbacks = g_list_remove(c->browse_callbacks, cb);
556 }
558 void
559 mpdclient_install_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
560 {
561 c->error_callbacks = g_list_append(c->error_callbacks, cb);
562 }
564 void
565 mpdclient_remove_error_callback(mpdclient_t *c, mpdc_error_cb_t cb)
566 {
567 c->error_callbacks = g_list_remove(c->error_callbacks, cb);
568 }
570 /****************************************************************************/
571 /*** Playlist managment functions *******************************************/
572 /****************************************************************************/
574 gint
575 mpdclient_playlist_free(mpdclient_playlist_t *playlist)
576 {
577 GList *list = g_list_first(playlist->list);
579 while(list)
580 {
581 mpd_Song *song = (mpd_Song *) list->data;
582 mpd_freeSong(song);
583 list=list->next;
584 }
585 g_list_free(playlist->list);
586 memset(playlist, 0, sizeof(mpdclient_playlist_t));
587 return 0;
588 }
590 /* update playlist */
591 gint
592 mpdclient_playlist_update(mpdclient_t *c)
593 {
594 mpd_InfoEntity *entity;
596 D("mpdclient_playlist_update() [%lld]\n", c->status->playlist);
598 if( MPD_ERROR(c) )
599 return -1;
601 if( c->playlist.list )
602 mpdclient_playlist_free(&c->playlist);
604 mpd_sendPlaylistInfoCommand(c->connection,-1);
605 while( (entity=mpd_getNextInfoEntity(c->connection)) )
606 {
607 if(entity->type==MPD_INFO_ENTITY_TYPE_SONG)
608 {
609 mpd_Song *song = mpd_songDup(entity->info.song);
611 c->playlist.list = g_list_append(c->playlist.list, (gpointer) song);
612 c->playlist.length++;
613 }
614 mpd_freeInfoEntity(entity);
615 }
616 c->playlist.id = c->status->playlist;
617 c->song = NULL;
618 c->playlist.updated = TRUE;
620 /* call playlist updated callbacks */
621 mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
623 return mpdclient_finish_command(c);
624 }
626 #ifdef ENABLE_PLCHANGES
628 gint
629 mpdclient_compare_songs(gconstpointer a, gconstpointer b)
630 {
631 mpd_Song *song1 = (mpd_Song *) a;
632 mpd_Song *song2 = (mpd_Song *) b;
634 return song1->pos - song2->pos;
635 }
639 /* update playlist (plchanges) */
641 gint
642 mpdclient_playlist_update_changes(mpdclient_t *c)
643 {
644 mpd_InfoEntity *entity;
646 D("mpdclient_playlist_update_changes() [%lld -> %lld]\n",
647 c->status->playlist, c->playlist.id);
649 if( MPD_ERROR(c) )
650 return -1;
652 mpd_sendPlChangesCommand(c->connection, c->playlist.id);
654 while( (entity=mpd_getNextInfoEntity(c->connection)) != NULL )
655 {
657 if(entity->type==MPD_INFO_ENTITY_TYPE_SONG)
658 {
659 mpd_Song *song = entity->info.song;
660 GList *item;
662 item = playlist_lookup(c, song->id);
664 #ifdef DEBUG
665 if( item )
666 D("Changing index:%d, pos:%d, id:%d => %s\n",
667 g_list_position(c->playlist.list, item),
668 song->pos, song->id, get_song_name(song));
669 else
670 D("Unable to find pos:%d, id:%d => %s\n",
671 song->pos, song->id, get_song_name(song));
672 #endif
674 if( item && item->data)
675 {
676 GList *old;
677 gint index = g_list_position(c->playlist.list, item);
679 /* remove previous song at song->pos */
680 while( song->pos != (index=g_list_position(c->playlist.list, item))
681 &&
682 (old=g_list_nth(c->playlist.list, song->pos)) )
683 {
684 D("Removing item with index %d id:%d (%d)\n",
685 song->pos, old ? ((mpd_Song *) old->data)->id : -1, index);
686 if( item->data == c->song )
687 c->song = NULL;
688 mpd_freeSong((mpd_Song *) old->data);
689 old->data = NULL;
690 c->playlist.list = g_list_delete_link(c->playlist.list, old);
691 c->playlist.length = g_list_length(c->playlist.list);
692 }
694 /* Update playlist entry */
695 mpd_freeSong((mpd_Song *) item->data);
696 item->data = mpd_songDup(song);
697 if( c->song && c->song->id == song->id )
698 c->song = item->data;
700 }
701 else
702 {
703 /* Add a new playlist entry */
704 D("Adding pos:%d, id;%d - %s\n",
705 song->pos, song->id, get_song_name(song));
706 c->playlist.list = g_list_append(c->playlist.list,
707 (gpointer) mpd_songDup(song));
708 c->playlist.length++;
709 }
710 }
711 mpd_freeInfoEntity(entity);
712 }
713 mpd_finishCommand(c->connection);
715 while( g_list_length(c->playlist.list) > c->status->playlistLength )
716 {
717 GList *item = g_list_last(c->playlist.list);
719 /* Remove the last playlist entry */
720 mpd_freeSong((mpd_Song *) item->data);
721 c->playlist.list = g_list_delete_link(c->playlist.list, item);
722 c->playlist.length--;
723 D("Removed the last playlist entry\n");
724 }
726 c->playlist.id = c->status->playlist;
727 c->playlist.updated = TRUE;
729 mpdclient_playlist_callback(c, PLAYLIST_EVENT_UPDATED, NULL);
731 return 0;
732 }
733 #else
734 gint
735 mpdclient_playlist_update_changes(mpdclient_t *c)
736 {
737 return mpdclient_playlist_update(c);
738 }
739 #endif
741 mpd_Song *
742 playlist_get_song(mpdclient_t *c, gint index)
743 {
744 return (mpd_Song *) g_list_nth_data(c->playlist.list, index);
745 }
747 GList *
748 playlist_lookup(mpdclient_t *c, int id)
749 {
750 GList *list = g_list_first(c->playlist.list);
752 while( list )
753 {
754 mpd_Song *song = (mpd_Song *) list->data;
755 if( song->id == id )
756 return list;
757 list=list->next;
758 }
759 return NULL;
760 }
762 mpd_Song *
763 playlist_lookup_song(mpdclient_t *c, gint id)
764 {
765 GList *list = c->playlist.list;
767 while( list )
768 {
769 mpd_Song *song = (mpd_Song *) list->data;
770 if( song->id == id )
771 return song;
772 list=list->next;
773 }
774 return NULL;
775 }
777 gint
778 playlist_get_index(mpdclient_t *c, mpd_Song *song)
779 {
780 return g_list_index(c->playlist.list, song);
781 }
783 gint
784 playlist_get_index_from_id(mpdclient_t *c, gint id)
785 {
786 return g_list_index(c->playlist.list, playlist_lookup_song(c, id));
787 }
789 gint
790 playlist_get_index_from_file(mpdclient_t *c, gchar *filename)
791 {
792 GList *list = c->playlist.list;
793 gint i=0;
795 while( list )
796 {
797 mpd_Song *song = (mpd_Song *) list->data;
798 if( strcmp(song->file, filename ) == 0 )
799 return i;
800 list=list->next;
801 i++;
802 }
803 return -1;
804 }
807 /****************************************************************************/
808 /*** Filelist functions *****************************************************/
809 /****************************************************************************/
811 mpdclient_filelist_t *
812 mpdclient_filelist_free(mpdclient_filelist_t *filelist)
813 {
814 GList *list = g_list_first(filelist->list);
816 D("mpdclient_filelist_free()\n");
817 while( list!=NULL )
818 {
819 filelist_entry_t *entry = list->data;
821 if( entry->entity )
822 mpd_freeInfoEntity(entry->entity);
823 g_free(entry);
824 list=list->next;
825 }
826 g_list_free(filelist->list);
827 g_free(filelist->path);
828 filelist->path = NULL;
829 filelist->list = NULL;
830 filelist->length = 0;
831 g_free(filelist);
833 return NULL;
834 }
837 mpdclient_filelist_t *
838 mpdclient_filelist_get(mpdclient_t *c, gchar *path)
839 {
840 mpdclient_filelist_t *filelist;
841 mpd_InfoEntity *entity;
842 gchar *path_utf8 = locale_to_utf8(path);
844 D("mpdclient_filelist_get(%s)\n", path);
845 mpd_sendLsInfoCommand(c->connection, path_utf8);
846 filelist = g_malloc0(sizeof(mpdclient_filelist_t));
847 if( path && path[0] && strcmp(path, "/") )
848 {
849 /* add a dummy entry for ./.. */
850 filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
851 entry->entity = NULL;
852 filelist->list = g_list_append(filelist->list, (gpointer) entry);
853 filelist->length++;
854 }
856 while( (entity=mpd_getNextInfoEntity(c->connection)) )
857 {
858 filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
860 entry->entity = entity;
861 filelist->list = g_list_append(filelist->list, (gpointer) entry);
862 filelist->length++;
863 }
865 if( mpdclient_finish_command(c) )
866 {
867 g_free(path_utf8);
868 return mpdclient_filelist_free(filelist);
869 }
871 g_free(path_utf8);
872 filelist->path = g_strdup(path);
873 filelist->updated = TRUE;
875 return filelist;
876 }
878 mpdclient_filelist_t *
879 mpdclient_filelist_update(mpdclient_t *c, mpdclient_filelist_t *filelist)
880 {
881 if( filelist != NULL )
882 {
883 gchar *path = g_strdup(filelist->path);
885 filelist = mpdclient_filelist_free(filelist);
886 filelist = mpdclient_filelist_get(c, path);
887 g_free(path);
888 return filelist;
889 }
890 return NULL;
891 }
893 filelist_entry_t *
894 mpdclient_filelist_find_song(mpdclient_filelist_t *fl, mpd_Song *song)
895 {
896 GList *list = g_list_first(fl->list);
898 while( list && song)
899 {
900 filelist_entry_t *entry = list->data;
901 mpd_InfoEntity *entity = entry->entity;
903 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG )
904 {
905 mpd_Song *song2 = entity->info.song;
907 if( strcmp(song->file, song2->file) == 0 )
908 {
909 return entry;
910 }
911 }
912 list = list->next;
913 }
914 return NULL;
915 }