Adding some support for using "idle" to get changed events.
[libmpd.git] / src / libmpd.c
blob5d16717ed82bd20407ae7466ca4d025eb8debd36
1 /*
2 *Copyright (C) 2004-2007 Qball Cow <Qball@qballcow.nl>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include <stdio.h>
21 #include <stdlib.h>
22 #define __USE_GNU
24 #include <string.h>
25 #include <stdarg.h>
26 #include <config.h>
27 #include <glib.h>
28 #include "debug_printf.h"
30 #include "libmpd.h"
31 #include "libmpd-internal.h"
33 static void mpd_free_queue_ob(MpdObj *mi);
34 static void mpd_server_free_commands(MpdObj *mi);
37 char *libmpd_version = LIBMPD_VERSION;
38 #ifndef HAVE_STRNDUP
39 /**
40 * Not every platfarm has strndup, so here we have a nice little custom implementation
42 char * strndup(const char *s, size_t n)
44 size_t nAvail;
45 char *p;
47 if(!s) {
48 return NULL;
51 /* nAvail = min( strlen(s)+1, n+1 ); */
52 nAvail=((strlen(s)+1) > (n+1)) ? n+1 : strlen(s)+1;
53 if(!(p=malloc(nAvail))) {
54 return NULL;
56 memcpy(p, s, nAvail);
57 p[nAvail - 1] = 0;
58 return p;
60 #endif
61 /**
62 * @param state a #MpdServerState to initialize
64 * Initialize #MpdServerState. To stop duplicating code.
66 static void mpd_init_MpdServerState(MpdServerState *state)
68 state->playlistid = -1;
69 state->storedplaylistid = -1;
70 state->state = -1;
71 state->songid = -1;
72 state->songpos = -1;
73 state->dbUpdateTime = 0;
74 state->updatingDb = 0;
75 state->repeat = -1;
76 state->random = -1;
77 state->volume = -2;
78 state->xfade = -1;
79 state->totaltime = 0;
80 state->elapsedtime = 0;
81 state->bitrate = 0;
82 state->samplerate = 0;
83 state->channels = 0;
84 state->bits = 0;
85 state->playlistLength = 0;
86 state->error[0] = '\0';
91 static MpdObj * mpd_create()
93 MpdObj * mi = malloc(sizeof(*mi));
94 if( mi == NULL )
96 /* should never happen on linux */
97 return NULL;
101 /* set default values */
102 /* we start not connected */
103 mi->connected = FALSE;
104 /* port 6600 is the default mpd port */
105 mi->port = 6600;
106 /* localhost */
107 mi->hostname = strdup("localhost");
108 /* no password */
109 mi->password = NULL;
110 /* 1 second timeout */
111 mi->connection_timeout = 1.0;
112 /* we have no connection pointer */
113 mi->connection = NULL;
114 /* no status */
115 mi->status = NULL;
116 /* no stats */
117 mi->stats = NULL;
118 mi->error = 0;
119 mi->error_mpd_code = 0;
120 mi->error_msg = NULL;
121 mi->CurrentSong = NULL;
122 /* info */
123 mpd_init_MpdServerState(&(mi->CurrentState));
124 mpd_init_MpdServerState(&(mi->OldState));
127 * Set signals to NULL
129 /* connection changed signal */
130 mi->the_connection_changed_callback = NULL;
131 mi->the_connection_changed_signal_userdata = NULL;
133 /* status changed */
134 mi->the_status_changed_callback = NULL;
135 mi->the_status_changed_signal_userdata = NULL;
137 /* error callback */
138 mi->the_error_callback = NULL;
139 mi->the_error_signal_userdata = NULL;
140 /* connection is locked because where not connected */
141 mi->connection_lock = TRUE;
143 /* set queue to NULL */
144 mi->queue = NULL;
145 /* search stuff */
146 mi->search_type = MPD_SEARCH_TYPE_NONE;
147 /* no need to initialize, but set it to anything anyway*/
148 mi->search_field = MPD_TAG_ITEM_ARTIST;
150 /* outputs */
151 mi->num_outputs = 0;
152 mi->output_states = NULL;
153 mi->has_idle = 0;
154 /* commands */
155 mi->commands = NULL;
156 return mi;
159 void mpd_free(MpdObj *mi)
161 debug_printf(DEBUG_INFO, "destroying MpdObj object\n");
162 if(mi->connected)
164 /* disconnect */
165 debug_printf(DEBUG_WARNING, "Connection still running, disconnecting\n");
166 mpd_disconnect(mi);
168 if(mi->hostname)
170 free(mi->hostname);
172 if(mi->password)
174 free(mi->password);
176 if(mi->error_msg)
178 free(mi->error_msg);
180 if(mi->connection)
182 /* obsolete */
183 mpd_closeConnection(mi->connection);
185 if(mi->status)
187 mpd_freeStatus(mi->status);
189 if(mi->stats)
191 mpd_freeStats(mi->stats);
193 if(mi->CurrentSong)
195 mpd_freeSong(mi->CurrentSong);
197 mpd_free_queue_ob(mi);
198 mpd_server_free_commands(mi);
199 free(mi);
202 int mpd_check_error(MpdObj *mi)
204 if(mi == NULL)
206 debug_printf(DEBUG_ERROR, "mi == NULL?");
207 return MPD_ARGS_ERROR;
210 /* this shouldn't happen, ever */
211 if(mi->connection == NULL)
213 debug_printf(DEBUG_ERROR, "mi->connection == NULL?");
214 return MPD_FATAL_ERROR;
217 /* TODO: map these errors in the future */
218 mi->error = mi->connection->error;
219 mi->error_mpd_code = mi->connection->errorCode;
220 /*TODO: do I need to strdup this? */
221 mi->error_msg = strdup(mi->connection->errorStr);
223 /* Check for permission */
224 /* First check for an error reported by MPD
225 * Then check what type of error mpd reported
227 if(mi->error == MPD_ERROR_ACK)
230 debug_printf(DEBUG_ERROR,"clearing errors in mpd_Connection: %i-%s", mi->connection->errorCode, mi->connection->errorStr);
231 mpd_clearError(mi->connection);
232 if (mi->the_error_callback)
234 debug_printf(DEBUG_ERROR, "Error callback 1 (ACK)");
235 if(mi->the_error_callback(mi, mi->error_mpd_code, mi->error_msg, mi->the_error_signal_userdata ))
237 debug_printf(DEBUG_ERROR, "Error callback told me to disconnenct");
238 mpd_disconnect(mi);
239 free(mi->error_msg);
240 mi->error_msg = NULL;
242 return MPD_SERVER_ERROR;
245 free(mi->error_msg);
246 mi->error_msg = NULL;
247 return TRUE;
249 if(mi->error)
252 debug_printf(DEBUG_ERROR, "Following error occured: %i: code: %i msg: %s", mi->error,mi->connection->errorCode, mi->error_msg);
254 if (mi->the_error_callback)
256 debug_printf(DEBUG_ERROR, "Error callback 2");
257 mi->the_error_callback(mi, mi->error, mi->error_msg, mi->the_error_signal_userdata );
259 mpd_disconnect(mi);
260 free(mi->error_msg);
261 mi->error_msg = NULL;
263 return MPD_SERVER_ERROR;
265 free(mi->error_msg);
266 mi->error_msg = NULL;
267 return MPD_OK;
272 int mpd_lock_conn(MpdObj *mi)
275 if(mi->connection_lock)
277 debug_printf(DEBUG_WARNING, "Failed to lock connection, already locked\n");
278 return MPD_LOCK_FAILED;
280 mi->connection_lock = TRUE;
281 return MPD_OK;
284 int mpd_unlock_conn(MpdObj *mi)
286 if(!mi->connection_lock)
288 debug_printf(DEBUG_ERROR, "Failed to unlock connection, already unlocked\n");
289 return MPD_LOCK_FAILED;
292 mi->connection_lock = FALSE;
294 return mpd_check_error(mi);
297 MpdObj * mpd_new_default()
299 debug_printf(DEBUG_INFO, "creating a new mpdInt object\n");
300 return mpd_create();
303 MpdObj *mpd_new(char *hostname, int port, char *password)
305 MpdObj *mi = mpd_create();
306 if(mi == NULL)
308 return NULL;
310 if(hostname != NULL)
312 mpd_set_hostname(mi, hostname);
314 if(port != 0)
316 mpd_set_port(mi, port);
318 if(password != NULL)
320 mpd_set_password(mi, password);
322 return mi;
326 const char * mpd_get_hostname(MpdObj *mi)
328 if(mi == NULL)
330 return NULL;
332 return mi->hostname;
335 int mpd_set_hostname(MpdObj *mi, char *hostname)
337 if(mi == NULL)
339 debug_printf(DEBUG_ERROR, "mi == NULL\n");
340 return MPD_ARGS_ERROR;
343 if(mi->hostname != NULL)
345 free(mi->hostname);
347 /* possible location todo some post processing of hostname */
348 mi->hostname = strdup(hostname);
349 return MPD_OK;
352 int mpd_set_password(MpdObj *mi, char *password)
354 if(mi == NULL)
356 debug_printf(DEBUG_ERROR, "mi == NULL\n");
357 return MPD_ARGS_ERROR;
360 if(mi->password != NULL)
362 free(mi->password);
364 /* possible location todo some post processing of password */
365 mi->password = strdup(password);
366 return MPD_OK;
370 int mpd_send_password(MpdObj *mi)
372 if(!mi) return MPD_ARGS_ERROR;
373 if(mi->password && mpd_check_connected(mi) && strlen(mi->password))
375 if(mpd_lock_conn(mi))
377 debug_printf(DEBUG_WARNING, "failed to lock connection");
378 return MPD_LOCK_FAILED;
380 mpd_sendPasswordCommand(mi->connection, mi->password);
381 mpd_finishCommand(mi->connection);
382 if(mpd_unlock_conn(mi))
384 debug_printf(DEBUG_ERROR, "Failed to unlock connection\n");
385 return MPD_LOCK_FAILED;
387 mpd_server_get_allowed_commands(mi);
388 /*TODO: should I do it here, or in the
389 * mpd_server_get_allowed_command, so it also get's executed on
390 * connect
392 if((mi->the_status_changed_callback != NULL))
394 mi->the_status_changed_callback( mi,
395 MPD_CST_PERMISSION, mi->the_status_changed_signal_userdata );
398 return MPD_OK;
401 int mpd_set_port(MpdObj *mi, int port)
403 if(mi == NULL)
405 debug_printf(DEBUG_ERROR, "mi == NULL\n");
406 return MPD_ARGS_ERROR;
408 mi->port = port;
409 return MPD_OK;
412 int mpd_set_connection_timeout(MpdObj *mi, float timeout)
414 if(mi == NULL)
416 debug_printf(DEBUG_ERROR, "mi == NULL\n");
417 return MPD_ARGS_ERROR;
419 mi->connection_timeout = timeout;
420 if(mpd_check_connected(mi))
422 /*TODO: set timeout */
423 if(mpd_lock_conn(mi))
425 debug_printf(DEBUG_ERROR,"lock failed\n");
426 return MPD_LOCK_FAILED;
428 mpd_setConnectionTimeout(mi->connection, timeout);
429 mpd_finishCommand(mi->connection);
431 mpd_unlock_conn(mi);
434 return MPD_OK;
437 static void mpd_server_free_commands(MpdObj *mi)
439 if(mi->commands)
441 int i=0;
442 while(mi->commands[i].command_name)
444 free(mi->commands[i].command_name);
445 i++;
447 free(mi->commands);
448 mi->commands = NULL;
452 char *mpd_server_get_version(MpdObj *mi)
454 char *retval = NULL;
455 if(!mi || !mpd_check_connected(mi))
456 return NULL;
457 retval = malloc(10*sizeof(char));
458 snprintf(retval,10,"%i.%i.%i", mi->connection->version[0], mi->connection->version[1], mi->connection->version[2]);
459 /* always make sure the string is terminated */
460 retval[9] = '\0';
461 return retval;
464 int mpd_server_get_allowed_commands(MpdObj *mi)
466 char *temp = NULL;
467 int num_commands = 0;
468 if(!mi){
469 debug_printf(DEBUG_ERROR, "mi != NULL failed\n");
470 return MPD_ARGS_ERROR;
472 if(!mpd_check_connected(mi)) {
473 debug_printf(DEBUG_WARNING, "Not Connected");
474 return MPD_NOT_CONNECTED;
476 if(!mpd_server_check_version(mi,0,12,0)){
477 debug_printf(DEBUG_INFO, "Not supported by mpd");
478 return MPD_SERVER_NOT_SUPPORTED;
481 mpd_server_free_commands(mi);
483 if(mpd_lock_conn(mi))
485 debug_printf(DEBUG_ERROR, "lock failed");
486 return MPD_LOCK_FAILED;
488 mpd_sendCommandsCommand(mi->connection);
489 while((temp = mpd_getNextCommand(mi->connection)))
491 num_commands++;
492 mi->commands = realloc(mi->commands, (num_commands+1)*sizeof(MpdCommand));
493 mi->commands[num_commands-1].command_name = temp;
494 mi->commands[num_commands-1].enabled = TRUE;
495 mi->commands[num_commands].command_name = NULL;
496 mi->commands[num_commands].enabled = FALSE;
497 if(strcmp(mi->commands[num_commands-1].command_name, "idle") == 0) {
498 mi->has_idle = TRUE;
501 mpd_finishCommand(mi->connection);
502 mpd_sendNotCommandsCommand(mi->connection);
503 while((temp = mpd_getNextCommand(mi->connection)))
505 num_commands++;
506 mi->commands = realloc(mi->commands, (num_commands+1)*sizeof(MpdCommand));
507 mi->commands[num_commands-1].command_name = temp;
508 mi->commands[num_commands-1].enabled = FALSE;
509 mi->commands[num_commands].command_name = NULL;
510 mi->commands[num_commands].enabled = FALSE;
512 mpd_finishCommand(mi->connection);
514 if(mpd_unlock_conn(mi))
516 return MPD_LOCK_FAILED;
518 return MPD_OK;
523 int mpd_disconnect(MpdObj *mi)
526 /* lock */
527 mpd_lock_conn(mi);
528 debug_printf(DEBUG_INFO, "disconnecting\n");
530 if(mi->connection)
532 mpd_closeConnection(mi->connection);
533 mi->connection = NULL;
535 if(mi->status)
537 mpd_freeStatus(mi->status);
538 mi->status = NULL;
540 if(mi->stats)
542 mpd_freeStats(mi->stats);
543 mi->stats = NULL;
545 if(mi->CurrentSong)
547 mpd_freeSong(mi->CurrentSong);
548 mi->CurrentSong = NULL;
550 mi->CurrentState.playlistid = -1;
551 mi->CurrentState.storedplaylistid = -1;
552 mi->CurrentState.state = -1;
553 mi->CurrentState.songid = -1;
554 mi->CurrentState.songpos = -1;
555 mi->CurrentState.dbUpdateTime = 0;
556 mi->CurrentState.updatingDb = 0;
557 mi->CurrentState.repeat = -1;
558 mi->CurrentState.random = -1;
559 mi->CurrentState.volume = -2;
560 mi->CurrentState.xfade = -1;
561 mi->CurrentState.totaltime = 0;
562 mi->CurrentState.elapsedtime = 0;
563 mi->CurrentState.bitrate = 0;
564 mi->CurrentState.samplerate = 0;
565 mi->CurrentState.channels = 0;
566 mi->CurrentState.bits = 0;
567 mi->CurrentState.playlistLength = 0;
568 mi->CurrentState.error[0] = '\0';
569 /* search stuff */
570 mi->search_type = MPD_SEARCH_TYPE_NONE;
571 /* no need to initialize, but set it to anything anyway*/
572 mi->search_field = MPD_TAG_ITEM_ARTIST;
573 /* outputs */
574 mi->num_outputs = 0;
575 if(mi->output_states)
576 g_free(mi->output_states);
577 mi->output_states = NULL;
578 mi->has_idle = 0;
580 memcpy(&(mi->OldState), &(mi->CurrentState) , sizeof(MpdServerState));
582 mpd_free_queue_ob(mi);
583 mpd_server_free_commands(mi);
584 /*don't reset errors */
585 /* Remove this signal, we don't actually disconnect */
586 if(mi->connected)
588 /* set disconnect flag */
589 mi->connected = FALSE;
591 if(mi->the_connection_changed_callback != NULL)
593 mi->the_connection_changed_callback( mi, FALSE, mi->the_connection_changed_signal_userdata );
596 debug_printf(DEBUG_INFO, "Disconnect completed\n");
597 return MPD_OK;
599 int mpd_connect(MpdObj *mi)
601 return mpd_connect_real(mi,NULL);
603 int mpd_connect_real(MpdObj *mi,mpd_Connection *connection)
605 int retv;
606 if(mi == NULL)
608 /* should return some spiffy error here */
609 debug_printf(DEBUG_ERROR, "mi != NULL failed");
610 return MPD_ARGS_ERROR;
612 /* reset errors */
613 mi->error = 0;
614 mi->error_mpd_code = 0;
615 if(mi->error_msg != NULL)
617 free(mi->error_msg);
619 mi->error_msg = NULL;
621 debug_printf(DEBUG_INFO, "connecting\n");
622 mpd_init_MpdServerState(&(mi->CurrentState));
624 memcpy(&(mi->OldState), &(mi->CurrentState), sizeof(MpdServerState));
626 if(mi->connected)
628 /* disconnect */
629 mpd_disconnect(mi);
632 if(mi->hostname == NULL)
634 mpd_set_hostname(mi, "localhost");
636 /* make sure this is locked */
637 if(!mi->connection_lock)
639 mpd_lock_conn(mi);
641 if(connection) {
642 mi->connection = connection;
643 } else {
644 /* make timeout configurable */
645 mi->connection = mpd_newConnection(mi->hostname,mi->port,mi->connection_timeout);
647 if(mi->connection == NULL)
649 /* TODO: make seperate error message? */
650 return MPD_NOT_CONNECTED;
652 if(mpd_check_error(mi) != MPD_OK)
654 /* TODO: make seperate error message? */
655 return MPD_NOT_CONNECTED;
658 /* set connected state */
659 mi->connected = TRUE;
660 if(mpd_unlock_conn(mi))
662 return MPD_LOCK_FAILED;
665 /* get the commands we are allowed to use */
666 retv = mpd_server_get_allowed_commands(mi);
667 if(retv!= MPD_OK)
669 return retv;
673 retv = mpd_server_update_outputs(mi);
674 if(retv != MPD_OK)
675 return retv;
677 debug_printf(DEBUG_INFO, "Propagating connection changed");
679 if(mi->the_connection_changed_callback != NULL)
681 mi->the_connection_changed_callback( mi, TRUE, mi->the_connection_changed_signal_userdata );
683 retv = mpd_server_update_outputs(mi);
685 if(retv != MPD_OK)
686 return retv;
688 debug_printf(DEBUG_INFO, "Connected to mpd");
689 return MPD_OK;
692 int mpd_check_connected(MpdObj *mi)
694 if(mi == NULL)
696 return FALSE;
698 return mi->connected;
702 /* SIGNALS */
703 void mpd_signal_connect_status_changed (MpdObj *mi, StatusChangedCallback status_changed, void *userdata)
705 if(mi == NULL)
707 debug_printf(DEBUG_ERROR, "mi != NULL failed");
708 return;
710 mi->the_status_changed_callback = status_changed;
711 mi->the_status_changed_signal_userdata = userdata;
715 void mpd_signal_connect_error(MpdObj *mi, ErrorCallback error_callback, void *userdata)
717 if(mi == NULL)
719 debug_printf(DEBUG_ERROR, "mi != NULL failed");
720 return;
722 mi->the_error_callback = error_callback;
723 mi->the_error_signal_userdata = userdata;
726 void mpd_signal_connect_connection_changed(MpdObj *mi, ConnectionChangedCallback connection_changed, void *userdata)
728 if(mi == NULL)
730 debug_printf(DEBUG_ERROR, "mi != NULL failed");
731 return;
733 mi->the_connection_changed_callback = connection_changed;
734 mi->the_connection_changed_signal_userdata = userdata;
738 /* more playlist */
739 /* MpdData Part */
740 MpdData *mpd_new_data_struct(void)
742 MpdData_real* data;
743 data = g_slice_new(MpdData_real);
744 data->type = 0;
746 data->tag_type = 0;
747 data->tag = NULL;
748 data->song = NULL;
749 data->directory = NULL;
750 data->playlist = NULL;
751 data->output_dev = NULL;
752 data->next = NULL;
753 data->prev = NULL;
754 data->first = NULL;
756 data->userdata = NULL;
757 data->freefunc = NULL;
758 return (MpdData*)data;
761 MpdData *mpd_new_data_struct_append(MpdData * data)
763 MpdData_real *data_real = (MpdData_real*)data;
764 if(data_real == NULL)
766 data_real = (MpdData_real*)mpd_new_data_struct();
767 data_real->first = data_real;
769 else
771 data_real->next = (MpdData_real*)mpd_new_data_struct();
772 data_real->next->prev = data_real;
773 data_real = data_real->next;
774 data_real->next = NULL;
775 data_real->first = data_real->prev->first;
777 return (MpdData*)data_real;
780 MpdData * mpd_data_get_first(MpdData const * const data)
782 MpdData_real const * const data_real = (MpdData_real const * const)data;
783 if(data_real != NULL)
785 return (MpdData*)data_real->first;
787 return NULL;
791 MpdData * mpd_data_get_next(MpdData * const data)
793 return mpd_data_get_next_real(data, TRUE);
796 MpdData * mpd_data_get_next_real(MpdData * const data, int kill_list)
798 MpdData_real *data_real = (MpdData_real*)data;
799 if (data_real != NULL)
801 if (data_real->next != NULL )
803 return (MpdData*)data_real->next;
805 else
807 if (kill_list) mpd_data_free((MpdData*)data_real);
808 return NULL;
811 return (MpdData*)data_real;
814 int mpd_data_is_last(MpdData const * const data)
816 MpdData_real const * const data_real = (MpdData_real const * const)data;
817 if(data_real != NULL)
819 if (data_real->next == NULL)
821 return TRUE;
824 return FALSE;
827 MpdData_head *mpd_data_get_head(MpdData const * const data) {
828 return ((MpdData_real*)data)->head;
831 MpdData* mpd_data_concatenate( MpdData * const first, MpdData * const second)
833 MpdData_real *first_real = (MpdData_real*)first;
834 MpdData_real *second_real = (MpdData_real*)second;
835 MpdData_real *first_head = NULL;
837 if ( first == NULL ) {
838 if ( second != NULL )
839 return (MpdData*)second_real;
840 else
841 return NULL;
842 } else {
843 if ( second == NULL )
844 return (MpdData*)first_real;
847 first_head = (MpdData_real *)mpd_data_get_first(first);
849 /* find last element in first data list */
850 while (!mpd_data_is_last((MpdData*)first_real)) first_real = (MpdData_real*)mpd_data_get_next_real((MpdData*)first_real, FALSE);
851 second_real =(MpdData_real*) mpd_data_get_first((MpdData*)second_real);
853 first_real->next = second_real;
854 second_real->prev = first_real;
856 /* I need to set all the -> first correct */
857 while (second_real)
859 second_real->first = first_head;
860 second_real = (MpdData_real*)mpd_data_get_next_real((MpdData*)second_real, FALSE);
863 return (MpdData*)first_head;
865 /**
866 * Deletes an item from the list. It returns the next item in the list.
867 * if that is not available, it will return the last item
869 MpdData * mpd_data_delete_item(MpdData *data)
871 MpdData_real *temp = NULL, *data_real = (MpdData_real*)data;
872 if(data_real == NULL) return NULL;
873 /* if there is a next item, fix the prev pointer of the next item */
874 if (data_real->next)
876 data_real->next->prev = data_real->prev;
877 temp = data_real->next;
879 /* if there is a previous item, fix the next pointer of the previous item */
880 if (data_real->prev)
882 /* the next item of the previous is the next item of the current */
883 data_real->prev->next = data_real->next;
884 /* temp is the previous item */
885 temp = data_real->prev;
888 /* fix first, if removed item is the first */
889 if(temp && temp->first == data_real)
891 MpdData_real *first,*node = temp;
892 /* get first */
893 for(;node->prev;node = node->prev);
894 first = node;
895 while(node){
896 node->first = first;
897 node = node->next;
900 /* make the removed row a valid list, so I can use the default free function to free it */
901 data_real->next = NULL;
902 data_real->prev = NULL;
903 data_real->first = data_real;
904 /* free it */
905 mpd_data_free((MpdData *)data_real);
907 return (MpdData *)temp;
910 void mpd_data_free(MpdData *data)
912 MpdData_real *data_real,*temp;
913 if(data == NULL)
915 debug_printf(DEBUG_ERROR, "data != NULL Failed");
916 return;
918 data_real = (MpdData_real *)mpd_data_get_first(data);
919 while(data_real){
920 temp = data_real;
921 if (data_real->type == MPD_DATA_TYPE_SONG) {
922 if(data_real->song) mpd_freeSong(data_real->song);
923 } else if (data_real->type == MPD_DATA_TYPE_OUTPUT_DEV) {
924 mpd_freeOutputElement(data_real->output_dev);
925 } else if(data_real->type == MPD_DATA_TYPE_DIRECTORY) {
926 if(data_real->directory)free(data_real->directory);
927 } else if(data_real->type == MPD_DATA_TYPE_PLAYLIST) {
928 if(data_real->playlist)free(data_real->playlist);
929 } else {
930 free((void*)(data_real->tag));
932 if(data_real->freefunc)
934 if(data_real->userdata)
935 data_real->freefunc(data_real->userdata);
937 data_real = data_real->next;
938 g_slice_free1(sizeof(*temp), temp);
942 /* clean this up.. make one while loop */
943 static void mpd_free_queue_ob(MpdObj *mi)
945 MpdQueue *temp = NULL;
946 if(mi == NULL)
948 debug_printf(DEBUG_ERROR, "mi != NULL failed");
949 return;
951 if(mi->queue == NULL)
953 debug_printf(DEBUG_INFO, "mi->queue != NULL failed, nothing to clean.");
954 return;
956 mi->queue = mi->queue->first;
957 while(mi->queue != NULL)
959 temp = mi->queue->next;
961 if(mi->queue->path != NULL)
963 free(mi->queue->path);
966 free(mi->queue);
967 mi->queue = temp;
969 mi->queue = NULL;
973 MpdQueue *mpd_new_queue_struct()
975 MpdQueue* queue = malloc(sizeof(MpdQueue));
977 queue->type = 0;
978 queue->path = NULL;
979 queue->id = 0;
981 return queue;
985 void mpd_queue_get_next(MpdObj *mi)
987 if(mi->queue != NULL && mi->queue->next != NULL)
989 mi->queue = mi->queue->next;
991 else if(mi->queue->next == NULL)
993 mpd_free_queue_ob(mi);
994 mi->queue = NULL;
998 long unsigned mpd_server_get_database_update_time(MpdObj *mi)
1000 if(!mpd_check_connected(mi))
1002 debug_printf(DEBUG_WARNING,"not connected\n");
1003 return MPD_NOT_CONNECTED;
1005 if(mpd_stats_check(mi) != MPD_OK)
1007 debug_printf(DEBUG_WARNING,"Failed grabbing status\n");
1008 return MPD_STATS_FAILED;
1010 return mi->stats->dbUpdateTime;
1014 MpdData * mpd_server_get_output_devices(MpdObj *mi)
1016 mpd_OutputEntity *output = NULL;
1017 MpdData *data = NULL;
1018 if(!mpd_check_connected(mi))
1020 debug_printf(DEBUG_WARNING,"not connected\n");
1021 return NULL;
1023 /* TODO: Check version */
1024 if(mpd_lock_conn(mi))
1026 debug_printf(DEBUG_ERROR,"lock failed\n");
1027 return NULL;
1030 mpd_sendOutputsCommand(mi->connection);
1031 while (( output = mpd_getNextOutput(mi->connection)) != NULL)
1033 data = mpd_new_data_struct_append(data);
1034 data->type = MPD_DATA_TYPE_OUTPUT_DEV;
1035 data->output_dev = output;
1037 mpd_finishCommand(mi->connection);
1039 /* unlock */
1040 mpd_unlock_conn(mi);
1041 if(data == NULL)
1043 return NULL;
1045 return mpd_data_get_first(data);
1048 int mpd_server_set_output_device(MpdObj *mi,int device_id,int state)
1050 if(!mpd_check_connected(mi))
1052 debug_printf(DEBUG_WARNING,"not connected\n");
1053 return MPD_NOT_CONNECTED;
1055 if(mpd_lock_conn(mi))
1057 debug_printf(DEBUG_ERROR,"lock failed\n");
1058 return MPD_LOCK_FAILED;
1060 if(state)
1062 mpd_sendEnableOutputCommand(mi->connection, device_id);
1064 else
1066 mpd_sendDisableOutputCommand(mi->connection, device_id);
1068 mpd_finishCommand(mi->connection);
1070 mpd_unlock_conn(mi);
1071 mpd_status_queue_update(mi);
1072 return FALSE;
1075 int mpd_server_check_version(MpdObj *mi, int major, int minor, int micro)
1077 if(!mpd_check_connected(mi))
1079 debug_printf(DEBUG_WARNING,"not connected\n");
1080 return FALSE;
1082 if(major > mi->connection->version[0]) return FALSE;
1083 if(mi->connection->version[0] > major) return TRUE;
1084 if(minor > mi->connection->version[1]) return FALSE;
1085 if(mi->connection->version[1] > minor) return TRUE;
1086 if(micro > mi->connection->version[2]) return FALSE;
1087 if(mi->connection->version[2] > micro) return TRUE;
1088 return TRUE;
1091 int mpd_server_check_command_allowed(MpdObj *mi, const char *command)
1093 int i;
1094 if(!mi || !command) return MPD_SERVER_COMMAND_ERROR;
1095 /* when we are connected to a mpd server that doesn't support commands and not commands
1096 * feature. (like mpd 0.11.5) allow everything
1098 if(!mpd_server_check_version(mi, 0,12,0)) return MPD_SERVER_COMMAND_ALLOWED;
1100 * Also when somehow we failted to get commands
1102 if(mi->commands == NULL) return MPD_SERVER_COMMAND_ALLOWED;
1106 for(i=0;mi->commands[i].command_name;i++)
1108 if(!strcasecmp(mi->commands[i].command_name, command))
1109 return mi->commands[i].enabled;
1111 return MPD_SERVER_COMMAND_NOT_SUPPORTED;
1114 char ** mpd_server_get_url_handlers(MpdObj *mi)
1116 char *temp = NULL;
1117 int i=0;
1118 char **retv = NULL;
1119 if(!mpd_check_connected(mi))
1121 debug_printf(DEBUG_WARNING,"not connected\n");
1122 return FALSE;
1124 if(mpd_lock_conn(mi))
1126 debug_printf(DEBUG_ERROR,"lock failed\n");
1127 return NULL;
1129 mpd_sendUrlHandlersCommand(mi->connection);
1130 while((temp = mpd_getNextHandler(mi->connection)) != NULL)
1132 retv = realloc(retv,(i+2)*sizeof(*retv));
1133 retv[i] = temp;
1134 retv[i+1] = NULL;
1135 i++;
1137 mpd_finishCommand(mi->connection);
1140 mpd_unlock_conn(mi);
1141 return retv;
1143 char ** mpd_server_get_tag_types(MpdObj *mi)
1145 char *temp = NULL;
1146 int i=0;
1147 char **retv = NULL;
1148 if(!mpd_check_connected(mi))
1150 debug_printf(DEBUG_WARNING,"not connected\n");
1151 return FALSE;
1153 if(mpd_lock_conn(mi))
1155 debug_printf(DEBUG_ERROR,"lock failed\n");
1156 return NULL;
1158 mpd_sendTagTypesCommand(mi->connection);
1159 while((temp = mpd_getNextTagType(mi->connection)) != NULL)
1161 retv = realloc(retv,(i+2)*sizeof(*retv));
1162 retv[i] = temp;
1163 retv[i+1] = NULL;
1164 i++;
1166 mpd_finishCommand(mi->connection);
1169 mpd_unlock_conn(mi);
1170 return retv;
1173 int mpd_misc_get_tag_by_name(char *name)
1175 int i;
1176 if(name == NULL)
1178 return MPD_ARGS_ERROR;
1180 for(i=0; i < MPD_TAG_NUM_OF_ITEM_TYPES; i++)
1182 if(!strcasecmp(mpdTagItemKeys[i], name))
1184 return i;
1187 return MPD_TAG_NOT_FOUND;
1190 int mpd_server_update_outputs(MpdObj *mi)
1192 mpd_OutputEntity *output = NULL;
1193 if(!mpd_check_connected(mi))
1195 debug_printf(DEBUG_WARNING,"not connected\n");
1196 return MPD_NOT_CONNECTED;
1198 if(mpd_lock_conn(mi))
1200 debug_printf(DEBUG_ERROR,"lock failed\n");
1201 return MPD_LOCK_FAILED;
1203 mpd_sendOutputsCommand(mi->connection);
1204 while (( output = mpd_getNextOutput(mi->connection)) != NULL)
1206 mi->num_outputs++;
1207 mi->output_states = g_realloc(mi->output_states,mi->num_outputs*sizeof(int));
1208 mi->output_states[mi->num_outputs-1] = FALSE;/*output->enabled;*/
1209 mpd_freeOutputElement(output);
1211 mpd_finishCommand(mi->connection);
1212 return mpd_unlock_conn(mi);