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.
28 #include "debug_printf.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
;
40 * Not every platfarm has strndup, so here we have a nice little custom implementation
42 char * strndup(const char *s
, size_t n
)
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
))) {
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;
73 state
->dbUpdateTime
= 0;
74 state
->updatingDb
= 0;
80 state
->elapsedtime
= 0;
82 state
->samplerate
= 0;
85 state
->playlistLength
= 0;
86 state
->error
[0] = '\0';
91 static MpdObj
* mpd_create()
93 MpdObj
* mi
= malloc(sizeof(*mi
));
96 /* should never happen on linux */
101 /* set default values */
102 /* we start not connected */
103 mi
->connected
= FALSE
;
104 /* port 6600 is the default mpd port */
107 mi
->hostname
= strdup("localhost");
110 /* 1 second timeout */
111 mi
->connection_timeout
= 1.0;
112 /* we have no connection pointer */
113 mi
->connection
= NULL
;
119 mi
->error_mpd_code
= 0;
120 mi
->error_msg
= NULL
;
121 mi
->CurrentSong
= NULL
;
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
;
134 mi
->the_status_changed_callback
= NULL
;
135 mi
->the_status_changed_signal_userdata
= NULL
;
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 */
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
;
152 mi
->output_states
= NULL
;
159 void mpd_free(MpdObj
*mi
)
161 debug_printf(DEBUG_INFO
, "destroying MpdObj object\n");
165 debug_printf(DEBUG_WARNING
, "Connection still running, disconnecting\n");
183 mpd_closeConnection(mi
->connection
);
187 mpd_freeStatus(mi
->status
);
191 mpd_freeStats(mi
->stats
);
195 mpd_freeSong(mi
->CurrentSong
);
197 mpd_free_queue_ob(mi
);
198 mpd_server_free_commands(mi
);
202 int mpd_check_error(MpdObj
*mi
)
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");
240 mi
->error_msg
= NULL
;
242 return MPD_SERVER_ERROR
;
246 mi
->error_msg
= NULL
;
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
);
261 mi
->error_msg
= NULL
;
263 return MPD_SERVER_ERROR
;
266 mi
->error_msg
= NULL
;
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
;
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");
303 MpdObj
*mpd_new(char *hostname
, int port
, char *password
)
305 MpdObj
*mi
= mpd_create();
312 mpd_set_hostname(mi
, hostname
);
316 mpd_set_port(mi
, port
);
320 mpd_set_password(mi
, password
);
326 const char * mpd_get_hostname(MpdObj
*mi
)
335 int mpd_set_hostname(MpdObj
*mi
, char *hostname
)
339 debug_printf(DEBUG_ERROR
, "mi == NULL\n");
340 return MPD_ARGS_ERROR
;
343 if(mi
->hostname
!= NULL
)
347 /* possible location todo some post processing of hostname */
348 mi
->hostname
= strdup(hostname
);
352 int mpd_set_password(MpdObj
*mi
, char *password
)
356 debug_printf(DEBUG_ERROR
, "mi == NULL\n");
357 return MPD_ARGS_ERROR
;
360 if(mi
->password
!= NULL
)
364 /* possible location todo some post processing of password */
365 mi
->password
= strdup(password
);
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
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
);
401 int mpd_set_port(MpdObj
*mi
, int port
)
405 debug_printf(DEBUG_ERROR
, "mi == NULL\n");
406 return MPD_ARGS_ERROR
;
412 int mpd_set_connection_timeout(MpdObj
*mi
, float timeout
)
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
);
437 static void mpd_server_free_commands(MpdObj
*mi
)
442 while(mi
->commands
[i
].command_name
)
444 free(mi
->commands
[i
].command_name
);
452 char *mpd_server_get_version(MpdObj
*mi
)
455 if(!mi
|| !mpd_check_connected(mi
))
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 */
464 int mpd_server_get_allowed_commands(MpdObj
*mi
)
467 int num_commands
= 0;
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
)))
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) {
501 mpd_finishCommand(mi
->connection
);
502 mpd_sendNotCommandsCommand(mi
->connection
);
503 while((temp
= mpd_getNextCommand(mi
->connection
)))
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
;
523 int mpd_disconnect(MpdObj
*mi
)
528 debug_printf(DEBUG_INFO
, "disconnecting\n");
532 mpd_closeConnection(mi
->connection
);
533 mi
->connection
= NULL
;
537 mpd_freeStatus(mi
->status
);
542 mpd_freeStats(mi
->stats
);
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';
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
;
575 if(mi
->output_states
)
576 g_free(mi
->output_states
);
577 mi
->output_states
= NULL
;
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 */
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");
599 int mpd_connect(MpdObj
*mi
)
601 return mpd_connect_real(mi
,NULL
);
603 int mpd_connect_real(MpdObj
*mi
,mpd_Connection
*connection
)
608 /* should return some spiffy error here */
609 debug_printf(DEBUG_ERROR
, "mi != NULL failed");
610 return MPD_ARGS_ERROR
;
614 mi
->error_mpd_code
= 0;
615 if(mi
->error_msg
!= NULL
)
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
));
632 if(mi
->hostname
== NULL
)
634 mpd_set_hostname(mi
, "localhost");
636 /* make sure this is locked */
637 if(!mi
->connection_lock
)
642 mi
->connection
= connection
;
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
);
673 retv = mpd_server_update_outputs(mi);
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
);
688 debug_printf(DEBUG_INFO
, "Connected to mpd");
692 int mpd_check_connected(MpdObj
*mi
)
698 return mi
->connected
;
703 void mpd_signal_connect_status_changed (MpdObj
*mi
, StatusChangedCallback status_changed
, void *userdata
)
707 debug_printf(DEBUG_ERROR
, "mi != NULL failed");
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
)
719 debug_printf(DEBUG_ERROR
, "mi != NULL failed");
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
)
730 debug_printf(DEBUG_ERROR
, "mi != NULL failed");
733 mi
->the_connection_changed_callback
= connection_changed
;
734 mi
->the_connection_changed_signal_userdata
= userdata
;
740 MpdData
*mpd_new_data_struct(void)
743 data
= g_slice_new(MpdData_real
);
749 data
->directory
= NULL
;
750 data
->playlist
= NULL
;
751 data
->output_dev
= 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
;
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
;
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
;
807 if (kill_list
) mpd_data_free((MpdData
*)data_real
);
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
)
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
;
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 */
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
;
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 */
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 */
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
;
893 for(;node
->prev
;node
= node
->prev
);
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
;
905 mpd_data_free((MpdData
*)data_real
);
907 return (MpdData
*)temp
;
910 void mpd_data_free(MpdData
*data
)
912 MpdData_real
*data_real
,*temp
;
915 debug_printf(DEBUG_ERROR
, "data != NULL Failed");
918 data_real
= (MpdData_real
*)mpd_data_get_first(data
);
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
);
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
;
948 debug_printf(DEBUG_ERROR
, "mi != NULL failed");
951 if(mi
->queue
== NULL
)
953 debug_printf(DEBUG_INFO
, "mi->queue != NULL failed, nothing to clean.");
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
);
973 MpdQueue
*mpd_new_queue_struct()
975 MpdQueue
* queue
= malloc(sizeof(MpdQueue
));
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
);
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");
1023 /* TODO: Check version */
1024 if(mpd_lock_conn(mi
))
1026 debug_printf(DEBUG_ERROR
,"lock failed\n");
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
);
1040 mpd_unlock_conn(mi
);
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
;
1062 mpd_sendEnableOutputCommand(mi
->connection
, device_id
);
1066 mpd_sendDisableOutputCommand(mi
->connection
, device_id
);
1068 mpd_finishCommand(mi
->connection
);
1070 mpd_unlock_conn(mi
);
1071 mpd_status_queue_update(mi
);
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");
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
;
1091 int mpd_server_check_command_allowed(MpdObj
*mi
, const char *command
)
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
)
1119 if(!mpd_check_connected(mi
))
1121 debug_printf(DEBUG_WARNING
,"not connected\n");
1124 if(mpd_lock_conn(mi
))
1126 debug_printf(DEBUG_ERROR
,"lock failed\n");
1129 mpd_sendUrlHandlersCommand(mi
->connection
);
1130 while((temp
= mpd_getNextHandler(mi
->connection
)) != NULL
)
1132 retv
= realloc(retv
,(i
+2)*sizeof(*retv
));
1137 mpd_finishCommand(mi
->connection
);
1140 mpd_unlock_conn(mi
);
1143 char ** mpd_server_get_tag_types(MpdObj
*mi
)
1148 if(!mpd_check_connected(mi
))
1150 debug_printf(DEBUG_WARNING
,"not connected\n");
1153 if(mpd_lock_conn(mi
))
1155 debug_printf(DEBUG_ERROR
,"lock failed\n");
1158 mpd_sendTagTypesCommand(mi
->connection
);
1159 while((temp
= mpd_getNextTagType(mi
->connection
)) != NULL
)
1161 retv
= realloc(retv
,(i
+2)*sizeof(*retv
));
1166 mpd_finishCommand(mi
->connection
);
1169 mpd_unlock_conn(mi
);
1173 int mpd_misc_get_tag_by_name(char *name
)
1178 return MPD_ARGS_ERROR
;
1180 for(i
=0; i
< MPD_TAG_NUM_OF_ITEM_TYPES
; i
++)
1182 if(!strcasecmp(mpdTagItemKeys
[i
], name
))
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
)
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
);