Fix compiler warning
[libmpd.git] / src / libmpd.c
blob7a5e7b1d2b453ebe12bd81c20aa108deefac5ead
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 <regex.h>
26 #include <stdarg.h>
27 #include <config.h>
28 #include <glib.h>
29 #include "debug_printf.h"
31 #include "libmpd.h"
32 #include "libmpd-internal.h"
34 static void mpd_free_queue_ob(MpdObj *mi);
35 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->queueid = -2;
70 state->storedplaylistid = -1;
71 state->state = -1;
72 state->songid = -1;
73 state->songpos = -1;
74 state->dbUpdateTime = 0;
75 state->updatingDb = 0;
76 state->repeat = -1;
77 state->random = -1;
78 state->volume = -2;
79 state->xfade = -1;
80 state->totaltime = 0;
81 state->elapsedtime = 0;
82 state->bitrate = 0;
83 state->samplerate = 0;
84 state->channels = 0;
85 state->bits = 0;
86 state->playlistLength = 0;
87 state->error[0] = '\0';
92 static MpdObj * mpd_create()
94 MpdObj * mi = malloc(sizeof(*mi));
95 if( mi == NULL )
97 /* should never happen on linux */
98 return NULL;
102 /* set default values */
103 /* we start not connected */
104 mi->connected = FALSE;
105 /* port 6600 is the default mpd port */
106 mi->port = 6600;
107 /* localhost */
108 mi->hostname = strdup("localhost");
109 /* no password */
110 mi->password = NULL;
111 /* 1 second timeout */
112 mi->connection_timeout = 1.0;
113 /* we have no connection pointer */
114 mi->connection = NULL;
115 /* no status */
116 mi->status = NULL;
117 /* no stats */
118 mi->stats = NULL;
119 mi->error = 0;
120 mi->error_mpd_code = 0;
121 mi->error_msg = NULL;
122 mi->CurrentSong = NULL;
123 /* info */
124 mpd_init_MpdServerState(&(mi->CurrentState));
125 mpd_init_MpdServerState(&(mi->OldState));
128 * Set signals to NULL
130 /* connection changed signal */
131 mi->the_connection_changed_callback = NULL;
132 mi->the_connection_changed_signal_userdata = NULL;
134 /* status changed */
135 mi->the_status_changed_callback = NULL;
136 mi->the_status_changed_signal_userdata = NULL;
138 /* error callback */
139 mi->the_error_callback = NULL;
140 mi->the_error_signal_userdata = NULL;
141 /* connection is locked because where not connected */
142 mi->connection_lock = TRUE;
144 /* set queue to NULL */
145 mi->queue = NULL;
146 /* search stuff */
147 mi->search_type = MPD_SEARCH_TYPE_NONE;
148 /* no need to initialize, but set it to anything anyway*/
149 mi->search_field = MPD_TAG_ITEM_ARTIST;
151 /* commands */
152 mi->commands = NULL;
153 return mi;
156 void mpd_free(MpdObj *mi)
158 debug_printf(DEBUG_INFO, "destroying MpdObj object\n");
159 if(mi->connected)
161 /* disconnect */
162 debug_printf(DEBUG_WARNING, "Connection still running, disconnecting\n");
163 mpd_disconnect(mi);
165 if(mi->hostname)
167 free(mi->hostname);
169 if(mi->password)
171 free(mi->password);
173 if(mi->error_msg)
175 free(mi->error_msg);
177 if(mi->connection)
179 /* obsolete */
180 mpd_closeConnection(mi->connection);
182 if(mi->status)
184 mpd_freeStatus(mi->status);
186 if(mi->stats)
188 mpd_freeStats(mi->stats);
190 if(mi->CurrentSong)
192 mpd_freeSong(mi->CurrentSong);
194 mpd_free_queue_ob(mi);
195 mpd_server_free_commands(mi);
196 free(mi);
199 int mpd_check_error(MpdObj *mi)
201 if(mi == NULL)
203 debug_printf(DEBUG_ERROR, "mi == NULL?");
204 return MPD_ARGS_ERROR;
207 /* this shouldn't happen, ever */
208 if(mi->connection == NULL)
210 debug_printf(DEBUG_ERROR, "mi->connection == NULL?");
211 return MPD_FATAL_ERROR;
214 /* TODO: map these errors in the future */
215 mi->error = mi->connection->error;
216 mi->error_mpd_code = mi->connection->errorCode;
217 /*TODO: do I need to strdup this? */
218 mi->error_msg = strdup(mi->connection->errorStr);
220 /* Check for permission */
221 /* First check for an error reported by MPD
222 * Then check what type of error mpd reported
224 if(mi->error == MPD_ERROR_ACK)
227 debug_printf(DEBUG_ERROR,"clearing errors in mpd_Connection: %i-%s", mi->connection->errorCode, mi->connection->errorStr);
228 mpd_clearError(mi->connection);
229 if (mi->the_error_callback)
231 debug_printf(DEBUG_ERROR, "Error callback 1 (ACK)");
232 mi->the_error_callback(mi, mi->error_mpd_code, mi->error_msg, mi->the_error_signal_userdata );
234 free(mi->error_msg);
235 mi->error_msg = NULL;
236 return TRUE;
238 if(mi->error)
241 debug_printf(DEBUG_ERROR, "Following error occured: %i: code: %i msg: %s", mi->error,mi->connection->errorCode, mi->error_msg);
243 if (mi->the_error_callback)
245 debug_printf(DEBUG_ERROR, "Error callback 2");
246 mi->the_error_callback(mi, mi->error, mi->error_msg, mi->the_error_signal_userdata );
248 mpd_disconnect(mi);
249 free(mi->error_msg);
250 mi->error_msg = NULL;
252 return MPD_SERVER_ERROR;
254 free(mi->error_msg);
255 mi->error_msg = NULL;
256 return MPD_OK;
261 int mpd_lock_conn(MpdObj *mi)
264 if(mi->connection_lock)
266 debug_printf(DEBUG_WARNING, "Failed to lock connection, already locked\n");
267 return MPD_LOCK_FAILED;
269 mi->connection_lock = TRUE;
270 return MPD_OK;
273 int mpd_unlock_conn(MpdObj *mi)
275 if(!mi->connection_lock)
277 debug_printf(DEBUG_ERROR, "Failed to unlock connection, already unlocked\n");
278 return MPD_LOCK_FAILED;
281 mi->connection_lock = FALSE;
283 return mpd_check_error(mi);
286 MpdObj * mpd_new_default()
288 debug_printf(DEBUG_INFO, "creating a new mpdInt object\n");
289 return mpd_create();
292 MpdObj *mpd_new(char *hostname, int port, char *password)
294 MpdObj *mi = mpd_create();
295 if(mi == NULL)
297 return NULL;
299 if(hostname != NULL)
301 mpd_set_hostname(mi, hostname);
303 if(port != 0)
305 mpd_set_port(mi, port);
307 if(password != NULL)
309 mpd_set_password(mi, password);
311 return mi;
315 const char * mpd_get_hostname(MpdObj *mi)
317 if(mi == NULL)
319 return NULL;
321 return mi->hostname;
324 int mpd_set_hostname(MpdObj *mi, char *hostname)
326 if(mi == NULL)
328 debug_printf(DEBUG_ERROR, "mi == NULL\n");
329 return MPD_ARGS_ERROR;
332 if(mi->hostname != NULL)
334 free(mi->hostname);
336 /* possible location todo some post processing of hostname */
337 mi->hostname = strdup(hostname);
338 return MPD_OK;
341 int mpd_set_password(MpdObj *mi, char *password)
343 if(mi == NULL)
345 debug_printf(DEBUG_ERROR, "mi == NULL\n");
346 return MPD_ARGS_ERROR;
349 if(mi->password != NULL)
351 free(mi->password);
353 /* possible location todo some post processing of password */
354 mi->password = strdup(password);
355 return MPD_OK;
359 int mpd_send_password(MpdObj *mi)
361 if(!mi) return MPD_ARGS_ERROR;
362 if(mi->password && mpd_check_connected(mi) && strlen(mi->password))
364 if(mpd_lock_conn(mi))
366 debug_printf(DEBUG_WARNING, "failed to lock connection");
367 return MPD_LOCK_FAILED;
369 mpd_sendPasswordCommand(mi->connection, mi->password);
370 mpd_finishCommand(mi->connection);
371 if(mpd_unlock_conn(mi))
373 debug_printf(DEBUG_ERROR, "Failed to unlock connection\n");
374 return MPD_LOCK_FAILED;
376 mpd_server_get_allowed_commands(mi);
377 /*TODO: should I do it here, or in the
378 * mpd_server_get_allowed_command, so it also get's executed on
379 * connect
381 if((mi->the_status_changed_callback != NULL))
383 mi->the_status_changed_callback( mi,
384 MPD_CST_PERMISSION, mi->the_status_changed_signal_userdata );
387 return MPD_OK;
390 int mpd_set_port(MpdObj *mi, int port)
392 if(mi == NULL)
394 debug_printf(DEBUG_ERROR, "mi == NULL\n");
395 return MPD_ARGS_ERROR;
397 mi->port = port;
398 return MPD_OK;
401 int mpd_set_connection_timeout(MpdObj *mi, float timeout)
403 if(mi == NULL)
405 debug_printf(DEBUG_ERROR, "mi == NULL\n");
406 return MPD_ARGS_ERROR;
408 mi->connection_timeout = timeout;
409 if(mpd_check_connected(mi))
411 /*TODO: set timeout */
412 if(mpd_lock_conn(mi))
414 debug_printf(DEBUG_ERROR,"lock failed\n");
415 return MPD_LOCK_FAILED;
417 mpd_setConnectionTimeout(mi->connection, timeout);
418 mpd_finishCommand(mi->connection);
420 mpd_unlock_conn(mi);
423 return MPD_OK;
426 static void mpd_server_free_commands(MpdObj *mi)
428 if(mi->commands)
430 int i=0;
431 while(mi->commands[i].command_name)
433 free(mi->commands[i].command_name);
434 i++;
436 free(mi->commands);
437 mi->commands = NULL;
441 char *mpd_server_get_version(MpdObj *mi)
443 char *retval = NULL;
444 if(!mi || !mpd_check_connected(mi))
445 return NULL;
446 retval = malloc(10*sizeof(char));
447 snprintf(retval,10,"%i.%i.%i", mi->connection->version[0], mi->connection->version[1], mi->connection->version[2]);
448 /* always make sure the string is terminated */
449 retval[9] = '\0';
450 return retval;
453 int mpd_server_get_allowed_commands(MpdObj *mi)
455 char *temp = NULL;
456 int num_commands = 0;
457 if(!mi){
458 debug_printf(DEBUG_ERROR, "mi != NULL failed\n");
459 return MPD_ARGS_ERROR;
461 if(!mpd_check_connected(mi)) {
462 debug_printf(DEBUG_WARNING, "Not Connected");
463 return MPD_NOT_CONNECTED;
465 if(!mpd_server_check_version(mi,0,12,0)){
466 debug_printf(DEBUG_INFO, "Not supported by mpd");
467 return MPD_SERVER_NOT_SUPPORTED;
470 mpd_server_free_commands(mi);
472 if(mpd_lock_conn(mi))
474 debug_printf(DEBUG_ERROR, "lock failed");
475 return MPD_LOCK_FAILED;
477 mpd_sendCommandsCommand(mi->connection);
478 while((temp = mpd_getNextCommand(mi->connection)))
480 num_commands++;
481 mi->commands = realloc(mi->commands, (num_commands+1)*sizeof(MpdCommand));
482 mi->commands[num_commands-1].command_name = temp;
483 mi->commands[num_commands-1].enabled = TRUE;
484 mi->commands[num_commands].command_name = NULL;
485 mi->commands[num_commands].enabled = FALSE;
487 mpd_finishCommand(mi->connection);
488 mpd_sendNotCommandsCommand(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 = FALSE;
495 mi->commands[num_commands].command_name = NULL;
496 mi->commands[num_commands].enabled = FALSE;
498 mpd_finishCommand(mi->connection);
500 mpd_unlock_conn(mi);
501 return MPD_OK;
506 int mpd_disconnect(MpdObj *mi)
509 /* lock */
510 mpd_lock_conn(mi);
511 debug_printf(DEBUG_INFO, "disconnecting\n");
513 if(mi->connection)
515 mpd_closeConnection(mi->connection);
516 mi->connection = NULL;
518 if(mi->status)
520 mpd_freeStatus(mi->status);
521 mi->status = NULL;
523 if(mi->stats)
525 mpd_freeStats(mi->stats);
526 mi->stats = NULL;
528 if(mi->CurrentSong)
530 mpd_freeSong(mi->CurrentSong);
531 mi->CurrentSong = NULL;
533 mi->CurrentState.playlistid = -1;
534 mi->CurrentState.queueid = -2;
535 mi->CurrentState.storedplaylistid = -1;
536 mi->CurrentState.state = -1;
537 mi->CurrentState.songid = -1;
538 mi->CurrentState.songpos = -1;
539 mi->CurrentState.dbUpdateTime = 0;
540 mi->CurrentState.updatingDb = 0;
541 mi->CurrentState.repeat = -1;
542 mi->CurrentState.random = -1;
543 mi->CurrentState.volume = -2;
544 mi->CurrentState.xfade = -1;
545 mi->CurrentState.totaltime = 0;
546 mi->CurrentState.elapsedtime = 0;
547 mi->CurrentState.bitrate = 0;
548 mi->CurrentState.samplerate = 0;
549 mi->CurrentState.channels = 0;
550 mi->CurrentState.bits = 0;
551 mi->CurrentState.playlistLength = 0;
552 mi->CurrentState.error[0] = '\0';
553 /* search stuff */
554 mi->search_type = MPD_SEARCH_TYPE_NONE;
555 /* no need to initialize, but set it to anything anyway*/
556 mi->search_field = MPD_TAG_ITEM_ARTIST;
561 memcpy(&(mi->OldState), &(mi->CurrentState) , sizeof(MpdServerState));
563 mpd_free_queue_ob(mi);
564 mpd_server_free_commands(mi);
565 /*don't reset errors */
566 /* Remove this signal, we don't actually disconnect */
567 if(mi->connected)
569 /* set disconnect flag */
570 mi->connected = FALSE;
572 if(mi->the_connection_changed_callback != NULL)
574 mi->the_connection_changed_callback( mi, FALSE, mi->the_connection_changed_signal_userdata );
577 debug_printf(DEBUG_INFO, "Disconnect completed\n");
578 return MPD_OK;
580 int mpd_connect(MpdObj *mi)
582 return mpd_connect_real(mi,NULL);
584 int mpd_connect_real(MpdObj *mi,mpd_Connection *connection)
586 if(mi == NULL)
588 /* should return some spiffy error here */
589 debug_printf(DEBUG_ERROR, "mi != NULL failed");
590 return MPD_ARGS_ERROR;
592 /* reset errors */
593 mi->error = 0;
594 mi->error_mpd_code = 0;
595 if(mi->error_msg != NULL)
597 free(mi->error_msg);
599 mi->error_msg = NULL;
601 debug_printf(DEBUG_INFO, "connecting\n");
602 mpd_init_MpdServerState(&(mi->CurrentState));
604 memcpy(&(mi->OldState), &(mi->CurrentState), sizeof(MpdServerState));
606 if(mi->connected)
608 /* disconnect */
609 mpd_disconnect(mi);
612 if(mi->hostname == NULL)
614 mpd_set_hostname(mi, "localhost");
616 /* make sure this is locked */
617 if(!mi->connection_lock)
619 mpd_lock_conn(mi);
621 if(connection) {
622 mi->connection = connection;
623 } else {
624 /* make timeout configurable */
625 mi->connection = mpd_newConnection(mi->hostname,mi->port,mi->connection_timeout);
627 if(mi->connection == NULL)
629 /* TODO: make seperate error message? */
630 return MPD_NOT_CONNECTED;
632 if(mpd_check_error(mi) != MPD_OK)
634 /* TODO: make seperate error message? */
635 return MPD_NOT_CONNECTED;
638 /* set connected state */
639 mi->connected = TRUE;
640 if(mpd_unlock_conn(mi))
642 return MPD_LOCK_FAILED;
645 /* get the commands we are allowed to use */
646 mpd_server_get_allowed_commands(mi);
649 if(mi->the_connection_changed_callback != NULL)
651 mi->the_connection_changed_callback( mi, TRUE, mi->the_connection_changed_signal_userdata );
654 debug_printf(DEBUG_INFO, "Connected to mpd");
655 return MPD_OK;
658 int mpd_check_connected(MpdObj *mi)
660 if(mi == NULL)
662 return FALSE;
664 return mi->connected;
668 /* SIGNALS */
669 void mpd_signal_connect_status_changed (MpdObj *mi, StatusChangedCallback status_changed, void *userdata)
671 if(mi == NULL)
673 debug_printf(DEBUG_ERROR, "mi != NULL failed");
674 return;
676 mi->the_status_changed_callback = status_changed;
677 mi->the_status_changed_signal_userdata = userdata;
681 void mpd_signal_connect_error(MpdObj *mi, ErrorCallback error_callback, void *userdata)
683 if(mi == NULL)
685 debug_printf(DEBUG_ERROR, "mi != NULL failed");
686 return;
688 mi->the_error_callback = error_callback;
689 mi->the_error_signal_userdata = userdata;
692 void mpd_signal_connect_connection_changed(MpdObj *mi, ConnectionChangedCallback connection_changed, void *userdata)
694 if(mi == NULL)
696 debug_printf(DEBUG_ERROR, "mi != NULL failed");
697 return;
699 mi->the_connection_changed_callback = connection_changed;
700 mi->the_connection_changed_signal_userdata = userdata;
704 /* more playlist */
705 /* MpdData Part */
706 MpdData *mpd_new_data_struct(void)
708 MpdData_real* data;
709 data = g_slice_new(MpdData_real);
710 data->type = 0;
712 data->tag_type = 0;
713 data->tag = NULL;
714 data->song = NULL;
715 data->directory = NULL;
716 data->playlist = NULL;
717 data->output_dev = NULL;
718 data->next = NULL;
719 data->prev = NULL;
720 data->first = NULL;
721 return (MpdData*)data;
724 MpdData *mpd_new_data_struct_append(MpdData * data)
726 MpdData_real *data_real = (MpdData_real*)data;
727 if(data_real == NULL)
729 data_real = (MpdData_real*)mpd_new_data_struct();
730 data_real->first = data_real;
732 else
734 data_real->next = (MpdData_real*)mpd_new_data_struct();
735 data_real->next->prev = data_real;
736 data_real = data_real->next;
737 data_real->next = NULL;
738 data_real->first = data_real->prev->first;
740 return (MpdData*)data_real;
743 MpdData * mpd_data_get_first(MpdData const * const data)
745 MpdData_real const * const data_real = (MpdData_real const * const)data;
746 if(data_real != NULL)
748 return (MpdData*)data_real->first;
750 return NULL;
754 MpdData * mpd_data_get_next(MpdData * const data)
756 return mpd_data_get_next_real(data, TRUE);
759 MpdData * mpd_data_get_next_real(MpdData * const data, int kill_list)
761 MpdData_real *data_real = (MpdData_real*)data;
762 if (data_real != NULL)
764 if (data_real->next != NULL )
766 return (MpdData*)data_real->next;
768 else
770 if (kill_list) mpd_data_free((MpdData*)data_real);
771 return NULL;
774 return (MpdData*)data_real;
777 int mpd_data_is_last(MpdData const * const data)
779 MpdData_real const * const data_real = (MpdData_real const * const)data;
780 if(data_real != NULL)
782 if (data_real->next == NULL)
784 return TRUE;
787 return FALSE;
790 MpdData_head *mpd_data_get_head(MpdData const * const data) {
791 return ((MpdData_real*)data)->head;
794 MpdData* mpd_data_concatenate( MpdData * const first, MpdData * const second)
796 MpdData_real *first_real = (MpdData_real*)first;
797 MpdData_real *second_real = (MpdData_real*)second;
798 MpdData_real *first_head = NULL;
800 if ( first == NULL ) {
801 if ( second != NULL )
802 return (MpdData*)second_real;
803 else
804 return NULL;
805 } else {
806 if ( second == NULL )
807 return (MpdData*)first_real;
810 first_head = (MpdData_real *)mpd_data_get_first(first);
812 /* find last element in first data list */
813 while (!mpd_data_is_last((MpdData*)first_real)) first_real = (MpdData_real*)mpd_data_get_next_real((MpdData*)first_real, FALSE);
814 second_real =(MpdData_real*) mpd_data_get_first((MpdData*)second_real);
816 first_real->next = second_real;
817 second_real->prev = first_real;
819 /* I need to set all the -> first correct */
820 while (second_real)
822 second_real->first = first_head;
823 second_real = (MpdData_real*)mpd_data_get_next_real((MpdData*)second_real, FALSE);
826 return (MpdData*)first_head;
828 /**
829 * Deletes an item from the list. It returns the next item in the list.
830 * if that is not available, it will return the last item
832 MpdData * mpd_data_delete_item(MpdData *data)
834 MpdData_real *temp = NULL, *data_real = (MpdData_real*)data;
835 if(data_real == NULL) return NULL;
836 /* if there is a next item, fix the prev pointer of the next item */
837 if (data_real->next)
839 data_real->next->prev = data_real->prev;
840 temp = data_real->next;
842 /* if there is a previous item, fix the next pointer of the previous item */
843 if (data_real->prev)
845 /* the next item of the previous is the next item of the current */
846 data_real->prev->next = data_real->next;
847 /* temp is the previous item */
848 temp = data_real->prev;
851 /* fix first, if removed item is the first */
852 if(temp && temp->first == data_real)
854 MpdData_real *first,*node = temp;
855 /* get first */
856 for(;node->prev;node = node->prev);
857 first = node;
858 while(node){
859 node->first = first;
860 node = node->next;
863 /* make the removed row a valid list, so I can use the default free function to free it */
864 data_real->next = NULL;
865 data_real->prev = NULL;
866 data_real->first = data_real;
867 /* free it */
868 mpd_data_free((MpdData *)data_real);
870 return (MpdData *)temp;
873 void mpd_data_free(MpdData *data)
875 MpdData_real *data_real,*temp;
876 if(data == NULL)
878 debug_printf(DEBUG_ERROR, "data != NULL Failed");
879 return;
881 data_real = (MpdData_real *)mpd_data_get_first(data);
882 while(data_real){
883 temp = data_real;
884 if (data_real->type == MPD_DATA_TYPE_SONG) {
885 if(data_real->song) mpd_freeSong(data_real->song);
886 } else if (data_real->type == MPD_DATA_TYPE_OUTPUT_DEV) {
887 mpd_freeOutputElement(data_real->output_dev);
888 } else if(data_real->type == MPD_DATA_TYPE_DIRECTORY) {
889 if(data_real->directory)free(data_real->directory);
890 } else if(data_real->type == MPD_DATA_TYPE_PLAYLIST) {
891 if(data_real->playlist)free(data_real->playlist);
892 } else {
893 free((void*)(data_real->tag));
895 data_real = data_real->next;
896 g_slice_free1(sizeof(*temp), temp);
900 /* clean this up.. make one while loop */
901 static void mpd_free_queue_ob(MpdObj *mi)
903 MpdQueue *temp = NULL;
904 if(mi == NULL)
906 debug_printf(DEBUG_ERROR, "mi != NULL failed");
907 return;
909 if(mi->queue == NULL)
911 debug_printf(DEBUG_INFO, "mi->queue != NULL failed, nothing to clean.");
912 return;
914 mi->queue = mi->queue->first;
915 while(mi->queue != NULL)
917 temp = mi->queue->next;
919 if(mi->queue->path != NULL)
921 free(mi->queue->path);
924 free(mi->queue);
925 mi->queue = temp;
927 mi->queue = NULL;
931 MpdQueue *mpd_new_queue_struct()
933 MpdQueue* queue = malloc(sizeof(MpdQueue));
935 queue->type = 0;
936 queue->path = NULL;
937 queue->id = 0;
939 return queue;
943 void mpd_queue_get_next(MpdObj *mi)
945 if(mi->queue != NULL && mi->queue->next != NULL)
947 mi->queue = mi->queue->next;
949 else if(mi->queue->next == NULL)
951 mpd_free_queue_ob(mi);
952 mi->queue = NULL;
956 long unsigned mpd_server_get_database_update_time(MpdObj *mi)
958 if(!mpd_check_connected(mi))
960 debug_printf(DEBUG_WARNING,"not connected\n");
961 return MPD_NOT_CONNECTED;
963 if(mpd_stats_check(mi) != MPD_OK)
965 debug_printf(DEBUG_WARNING,"Failed grabbing status\n");
966 return MPD_STATS_FAILED;
968 return mi->stats->dbUpdateTime;
972 MpdData * mpd_server_get_output_devices(MpdObj *mi)
974 mpd_OutputEntity *output = NULL;
975 MpdData *data = NULL;
976 if(!mpd_check_connected(mi))
978 debug_printf(DEBUG_WARNING,"not connected\n");
979 return NULL;
981 /* TODO: Check version */
982 if(mpd_lock_conn(mi))
984 debug_printf(DEBUG_ERROR,"lock failed\n");
985 return NULL;
988 mpd_sendOutputsCommand(mi->connection);
989 while (( output = mpd_getNextOutput(mi->connection)) != NULL)
991 data = mpd_new_data_struct_append(data);
992 data->type = MPD_DATA_TYPE_OUTPUT_DEV;
993 data->output_dev = output;
995 mpd_finishCommand(mi->connection);
997 /* unlock */
998 mpd_unlock_conn(mi);
999 if(data == NULL)
1001 return NULL;
1003 return mpd_data_get_first(data);
1006 int mpd_server_set_output_device(MpdObj *mi,int device_id,int state)
1008 if(!mpd_check_connected(mi))
1010 debug_printf(DEBUG_WARNING,"not connected\n");
1011 return MPD_NOT_CONNECTED;
1013 if(mpd_lock_conn(mi))
1015 debug_printf(DEBUG_ERROR,"lock failed\n");
1016 return MPD_LOCK_FAILED;
1018 if(state)
1020 mpd_sendEnableOutputCommand(mi->connection, device_id);
1022 else
1024 mpd_sendDisableOutputCommand(mi->connection, device_id);
1026 mpd_finishCommand(mi->connection);
1028 mpd_unlock_conn(mi);
1029 mpd_status_queue_update(mi);
1030 return FALSE;
1033 int mpd_server_check_version(MpdObj *mi, int major, int minor, int micro)
1035 if(!mpd_check_connected(mi))
1037 debug_printf(DEBUG_WARNING,"not connected\n");
1038 return FALSE;
1040 if(major > mi->connection->version[0]) return FALSE;
1041 if(mi->connection->version[0] > major) return TRUE;
1042 if(minor > mi->connection->version[1]) return FALSE;
1043 if(mi->connection->version[1] > minor) return TRUE;
1044 if(micro > mi->connection->version[2]) return FALSE;
1045 if(mi->connection->version[2] > micro) return TRUE;
1046 return TRUE;
1049 int mpd_server_check_command_allowed(MpdObj *mi, const char *command)
1051 int i;
1052 if(!mi || !command) return MPD_SERVER_COMMAND_ERROR;
1053 /* when we are connected to a mpd server that doesn't support commands and not commands
1054 * feature. (like mpd 0.11.5) allow everything
1056 if(!mpd_server_check_version(mi, 0,12,0)) return MPD_SERVER_COMMAND_ALLOWED;
1058 * Also when somehow we failted to get commands
1060 if(mi->commands == NULL) return MPD_SERVER_COMMAND_ALLOWED;
1064 for(i=0;mi->commands[i].command_name;i++)
1066 if(!strcasecmp(mi->commands[i].command_name, command))
1067 return mi->commands[i].enabled;
1069 return MPD_SERVER_COMMAND_NOT_SUPPORTED;
1072 char ** mpd_server_get_url_handlers(MpdObj *mi)
1074 char *temp = NULL;
1075 int i=0;
1076 char **retv = NULL;
1077 if(!mpd_check_connected(mi))
1079 debug_printf(DEBUG_WARNING,"not connected\n");
1080 return FALSE;
1082 if(mpd_lock_conn(mi))
1084 debug_printf(DEBUG_ERROR,"lock failed\n");
1085 return NULL;
1087 mpd_sendUrlHandlersCommand(mi->connection);
1088 while((temp = mpd_getNextHandler(mi->connection)) != NULL)
1090 retv = realloc(retv,(i+2)*sizeof(*retv));
1091 retv[i] = temp;
1092 retv[i+1] = NULL;
1093 i++;
1095 mpd_finishCommand(mi->connection);
1098 mpd_unlock_conn(mi);
1099 return retv;
1103 /** MISC **/
1105 regex_t ** mpd_misc_tokenize(char *string)
1107 regex_t ** result = NULL; /* the result with tokens */
1108 int i = 0; /* position in string */
1109 int br = 0; /* number for open ()[]'s */
1110 int bpos = 0; /* begin position of the cur. token */
1112 int tokens=0;
1113 if(string == NULL) return NULL;
1114 for(i=0; i < strlen(string)+1;i++)
1116 /* check for opening [( */
1117 if(string[i] == '(' || string[i] == '[' || string[i] == '{') br++;
1118 /* check closing */
1119 else if(string[i] == ')' || string[i] == ']' || string[i] == '}') br--;
1120 /* if multiple spaces at begin of token skip them */
1121 else if(string[i] == ' ' && !(i-bpos))bpos++;
1122 /* if token end or string end add token to list */
1123 else if((string[i] == ' ' && !br) || string[i] == '\0')
1125 char * temp=NULL;
1126 result = (regex_t **)realloc(result,(tokens+2)*sizeof(regex_t *));
1127 result[tokens] = malloc(sizeof(regex_t));
1128 temp = (char *)strndup((const char *)&string[bpos], i-bpos);
1129 if(regcomp(result[tokens], temp, REG_EXTENDED|REG_ICASE|REG_NOSUB))
1131 result[tokens+1] = NULL;
1132 mpd_misc_tokens_free(result);
1133 return NULL;
1135 free(temp);
1136 result[tokens+1] = NULL;
1137 bpos = i+1;
1138 tokens++;
1142 return result;
1145 void mpd_misc_tokens_free(regex_t ** tokens)
1147 int i=0;
1148 if(tokens == NULL) return;
1149 for(i=0;tokens[i] != NULL;i++)
1151 regfree(tokens[i]);
1152 free(tokens[i]);
1154 free(tokens);
1157 int mpd_misc_get_tag_by_name(char *name)
1159 int i;
1160 if(name == NULL)
1162 return MPD_ARGS_ERROR;
1164 for(i=0; i < MPD_TAG_NUM_OF_ITEM_TYPES; i++)
1166 if(!strcasecmp(mpdTagItemKeys[i], name))
1168 return i;
1171 return MPD_TAG_NOT_FOUND;