2 (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
3 This project's homepage is: http://www.musicpd.org
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
9 - Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 - Neither the name of the Music Player Daemon nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
24 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "libmpdclient.h"
37 #include <sys/types.h>
39 #include <sys/param.h>
46 # include <ws2tcpip.h>
49 # include <netinet/in.h>
50 # include <arpa/inet.h>
51 # include <sys/socket.h>
56 # define MSG_DONTWAIT 0
65 #define COMMAND_LIST 1
66 #define COMMAND_LIST_OK 2
69 # define SELECT_ERRNO_IGNORE (errno == WSAEINTR || errno == WSAEINPROGRESS)
70 # define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
72 # define SELECT_ERRNO_IGNORE (errno == EINTR)
73 # define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
74 # define winsock_dll_error(c) 0
75 # define closesocket(s) close(s)
76 # define WSACleanup() do { /* nothing */ } while (0)
80 static int winsock_dll_error(mpd_Connection
*connection
)
83 if ((WSAStartup(MAKEWORD(2, 2), &wsaData
)) != 0 ||
84 LOBYTE(wsaData
.wVersion
) != 2 ||
85 HIBYTE(wsaData
.wVersion
) != 2 ) {
86 strcpy(connection
->errorStr
,
87 "Could not find usable WinSock DLL.");
88 connection
->error
= MPD_ERROR_SYSTEM
;
94 static int do_connect_fail(mpd_Connection
*connection
,
95 const struct sockaddr
*serv_addr
, int addrlen
)
97 int iMode
= 1; /* 0 = blocking, else non-blocking */
98 ioctlsocket(connection
->sock
, FIONBIO
, (u_long FAR
*) &iMode
);
99 return (connect(connection
->sock
,serv_addr
,addrlen
) == SOCKET_ERROR
100 && WSAGetLastError() != WSAEWOULDBLOCK
);
102 #else /* !WIN32 (sane operating systems) */
103 static int do_connect_fail(mpd_Connection
*connection
,
104 const struct sockaddr
*serv_addr
, int addrlen
)
106 int flags
= fcntl(connection
->sock
, F_GETFL
, 0);
107 fcntl(connection
->sock
, F_SETFL
, flags
| O_NONBLOCK
);
108 return (connect(connection
->sock
,serv_addr
,addrlen
)<0 &&
114 static int mpd_connect(mpd_Connection
* connection
, const char * host
, int port
,
119 struct addrinfo hints
;
120 struct addrinfo
*res
= NULL
;
121 struct addrinfo
*addrinfo
= NULL
;
126 hints
.ai_flags
= AI_ADDRCONFIG
;
127 hints
.ai_family
= PF_UNSPEC
;
128 hints
.ai_socktype
= SOCK_STREAM
;
129 hints
.ai_protocol
= IPPROTO_TCP
;
130 hints
.ai_addrlen
= 0;
131 hints
.ai_addr
= NULL
;
132 hints
.ai_canonname
= NULL
;
133 hints
.ai_next
= NULL
;
135 snprintf(service
, sizeof(service
), "%d", port
);
137 error
= getaddrinfo(host
, service
, &hints
, &addrinfo
);
140 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
141 "host \"%s\" not found: %s",host
, gai_strerror(error
));
142 connection
->error
= MPD_ERROR_UNKHOST
;
146 for (res
= addrinfo
; res
; res
= res
->ai_next
) {
148 connection
->sock
= socket(res
->ai_family
, SOCK_STREAM
, res
->ai_protocol
);
149 if (connection
->sock
< 0) {
150 snprintf(connection
->errorStr
, MPD_ERRORSTR_MAX_LENGTH
,
151 "problems creating socket: %s",
153 connection
->error
= MPD_ERROR_SYSTEM
;
154 freeaddrinfo(addrinfo
);
158 mpd_setConnectionTimeout(connection
,timeout
);
161 if (do_connect_fail(connection
, res
->ai_addr
, res
->ai_addrlen
)) {
162 /* try the next address family */
163 closesocket(connection
->sock
);
164 connection
->sock
= -1;
168 freeaddrinfo(addrinfo
);
170 if (connection
->sock
< 0) {
171 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
172 "problems connecting to \"%s\" on port"
173 " %i: %s",host
,port
, strerror(errno
));
174 connection
->error
= MPD_ERROR_CONNPORT
;
181 #else /* !MPD_HAVE_GAI */
182 static int mpd_connect(mpd_Connection
* connection
, const char * host
, int port
,
186 struct sockaddr
* dest
;
188 struct sockaddr_in sin
;
190 if(!(he
=gethostbyname(host
))) {
191 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
192 "host \"%s\" not found",host
);
193 connection
->error
= MPD_ERROR_UNKHOST
;
197 memset(&sin
,0,sizeof(struct sockaddr_in
));
198 /*dest.sin_family = he->h_addrtype;*/
199 sin
.sin_family
= AF_INET
;
200 sin
.sin_port
= htons(port
);
202 switch(he
->h_addrtype
) {
204 memcpy((char *)&sin
.sin_addr
.s_addr
,(char *)he
->h_addr
,
206 dest
= (struct sockaddr
*)&sin
;
207 destlen
= sizeof(struct sockaddr_in
);
210 strcpy(connection
->errorStr
,"address type is not IPv4");
211 connection
->error
= MPD_ERROR_SYSTEM
;
216 if((connection
->sock
= socket(dest
->sa_family
,SOCK_STREAM
,0))<0) {
217 strcpy(connection
->errorStr
,"problems creating socket");
218 connection
->error
= MPD_ERROR_SYSTEM
;
222 mpd_setConnectionTimeout(connection
,timeout
);
225 if (do_connect_fail(connection
, dest
, destlen
)) {
226 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
227 "problems connecting to \"%s\" on port"
229 connection
->error
= MPD_ERROR_CONNPORT
;
235 #endif /* !MPD_HAVE_GAI */
237 char * mpdTagItemKeys
[MPD_TAG_NUM_OF_ITEM_TYPES
] =
254 static char * mpd_sanitizeArg(const char * arg
) {
257 register const char *c
;
260 /* instead of counting in that loop above, just
261 * use a bit more memory and half running time
263 ret
= malloc(strlen(arg
) * 2 + 1);
267 for(i
= strlen(arg
)+1; i
!= 0; --i
) {
268 if(*c
=='"' || *c
=='\\')
276 static mpd_ReturnElement
* mpd_newReturnElement(const char * name
, const char * value
)
278 mpd_ReturnElement
* ret
= malloc(sizeof(mpd_ReturnElement
));
280 ret
->name
= strdup(name
);
281 ret
->value
= strdup(value
);
286 static void mpd_freeReturnElement(mpd_ReturnElement
* re
) {
292 void mpd_setConnectionTimeout(mpd_Connection
* connection
, float timeout
) {
293 connection
->timeout
.tv_sec
= (int)timeout
;
294 connection
->timeout
.tv_usec
= (int)(timeout
*1e6
-
295 connection
->timeout
.tv_sec
*1000000 +
299 static int mpd_parseWelcome(mpd_Connection
* connection
, const char * host
, int port
,
300 char * rt
, char * output
) {
305 if(strncmp(output
,MPD_WELCOME_MESSAGE
,strlen(MPD_WELCOME_MESSAGE
))) {
306 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
307 "mpd not running on port %i on host \"%s\"",
309 connection
->error
= MPD_ERROR_NOTMPD
;
313 tmp
= &output
[strlen(MPD_WELCOME_MESSAGE
)];
316 if(tmp
) connection
->version
[i
] = strtol(tmp
,&test
,10);
318 if (!tmp
|| (test
[0] != '.' && test
[0] != '\0')) {
319 snprintf(connection
->errorStr
,
320 MPD_ERRORSTR_MAX_LENGTH
,
321 "error parsing version number at "
323 &output
[strlen(MPD_WELCOME_MESSAGE
)]);
324 connection
->error
= MPD_ERROR_NOTMPD
;
333 mpd_Connection
* mpd_newConnection(const char * host
, int port
, float timeout
) {
336 char * output
= NULL
;
337 mpd_Connection
* connection
= malloc(sizeof(mpd_Connection
));
340 strcpy(connection
->buffer
,"");
341 connection
->buflen
= 0;
342 connection
->bufstart
= 0;
343 strcpy(connection
->errorStr
,"");
344 connection
->error
= 0;
345 connection
->doneProcessing
= 0;
346 connection
->commandList
= 0;
347 connection
->listOks
= 0;
348 connection
->doneListOk
= 0;
349 connection
->returnElement
= NULL
;
350 connection
->request
= NULL
;
352 if (winsock_dll_error(connection
))
355 if (mpd_connect(connection
, host
, port
, timeout
) < 0)
358 while(!(rt
= strstr(connection
->buffer
,"\n"))) {
359 tv
.tv_sec
= connection
->timeout
.tv_sec
;
360 tv
.tv_usec
= connection
->timeout
.tv_usec
;
362 FD_SET(connection
->sock
,&fds
);
363 if((err
= select(connection
->sock
+1,&fds
,NULL
,NULL
,&tv
)) == 1) {
365 readed
= recv(connection
->sock
,
366 &(connection
->buffer
[connection
->buflen
]),
367 MPD_BUFFER_MAX_LENGTH
-connection
->buflen
,0);
369 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
370 "problems getting a response from"
371 " \"%s\" on port %i : %s",host
,
372 port
, strerror(errno
));
373 connection
->error
= MPD_ERROR_NORESPONSE
;
376 connection
->buflen
+=readed
;
377 connection
->buffer
[connection
->buflen
] = '\0';
380 if (SELECT_ERRNO_IGNORE
)
382 snprintf(connection
->errorStr
,
383 MPD_ERRORSTR_MAX_LENGTH
,
384 "problems connecting to \"%s\" on port"
386 connection
->error
= MPD_ERROR_CONNPORT
;
390 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
391 "timeout in attempting to get a response from"
392 " \"%s\" on port %i",host
,port
);
393 connection
->error
= MPD_ERROR_NORESPONSE
;
399 output
= strdup(connection
->buffer
);
400 strcpy(connection
->buffer
,rt
+1);
401 connection
->buflen
= strlen(connection
->buffer
);
403 if(mpd_parseWelcome(connection
,host
,port
,rt
,output
) == 0) connection
->doneProcessing
= 1;
410 void mpd_clearError(mpd_Connection
* connection
) {
411 connection
->error
= 0;
412 connection
->errorStr
[0] = '\0';
415 void mpd_closeConnection(mpd_Connection
* connection
) {
416 closesocket(connection
->sock
);
417 if(connection
->returnElement
) free(connection
->returnElement
);
418 if(connection
->request
) free(connection
->request
);
423 static void mpd_executeCommand(mpd_Connection
* connection
, char * command
) {
427 char * commandPtr
= command
;
428 int commandLen
= strlen(command
);
430 if(!connection
->doneProcessing
&& !connection
->commandList
) {
431 strcpy(connection
->errorStr
,"not done processing current command");
432 connection
->error
= 1;
436 mpd_clearError(connection
);
439 FD_SET(connection
->sock
,&fds
);
440 tv
.tv_sec
= connection
->timeout
.tv_sec
;
441 tv
.tv_usec
= connection
->timeout
.tv_usec
;
443 while((ret
= select(connection
->sock
+1,NULL
,&fds
,NULL
,&tv
)==1) ||
444 (ret
==-1 && SELECT_ERRNO_IGNORE
)) {
445 ret
= send(connection
->sock
,commandPtr
,commandLen
,MSG_DONTWAIT
);
448 if (SENDRECV_ERRNO_IGNORE
) continue;
449 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
450 "problems giving command \"%s\"",command
);
451 connection
->error
= MPD_ERROR_SENDING
;
459 if(commandLen
<=0) break;
464 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
465 "timeout sending command \"%s\"",command
);
466 connection
->error
= MPD_ERROR_TIMEOUT
;
470 if(!connection
->commandList
) connection
->doneProcessing
= 0;
471 else if(connection
->commandList
== COMMAND_LIST_OK
) {
472 connection
->listOks
++;
476 static void mpd_getNextReturnElement(mpd_Connection
* connection
) {
477 char * output
= NULL
;
485 char * bufferCheck
= NULL
;
489 if(connection
->returnElement
) mpd_freeReturnElement(connection
->returnElement
);
490 connection
->returnElement
= NULL
;
492 if(connection
->doneProcessing
|| (connection
->listOks
&&
493 connection
->doneListOk
))
495 strcpy(connection
->errorStr
,"already done processing current command");
496 connection
->error
= 1;
500 bufferCheck
= connection
->buffer
+connection
->bufstart
;
501 while(connection
->bufstart
>=connection
->buflen
||
502 !(rt
= strchr(bufferCheck
,'\n'))) {
503 if(connection
->buflen
>=MPD_BUFFER_MAX_LENGTH
) {
504 memmove(connection
->buffer
,
506 connection
->bufstart
,
508 connection
->bufstart
+1);
509 connection
->buflen
-=connection
->bufstart
;
510 connection
->bufstart
= 0;
512 if(connection
->buflen
>=MPD_BUFFER_MAX_LENGTH
) {
513 strcpy(connection
->errorStr
,"buffer overrun");
514 connection
->error
= MPD_ERROR_BUFFEROVERRUN
;
515 connection
->doneProcessing
= 1;
516 connection
->doneListOk
= 0;
519 bufferCheck
= connection
->buffer
+connection
->buflen
;
520 tv
.tv_sec
= connection
->timeout
.tv_sec
;
521 tv
.tv_usec
= connection
->timeout
.tv_usec
;
523 FD_SET(connection
->sock
,&fds
);
524 if((err
= select(connection
->sock
+1,&fds
,NULL
,NULL
,&tv
) == 1)) {
525 readed
= recv(connection
->sock
,
526 connection
->buffer
+connection
->buflen
,
527 MPD_BUFFER_MAX_LENGTH
-connection
->buflen
,
529 if(readed
<0 && SENDRECV_ERRNO_IGNORE
) {
533 strcpy(connection
->errorStr
,"connection"
535 connection
->error
= MPD_ERROR_CONNCLOSED
;
536 connection
->doneProcessing
= 1;
537 connection
->doneListOk
= 0;
540 connection
->buflen
+=readed
;
541 connection
->buffer
[connection
->buflen
] = '\0';
543 else if(err
<0 && SELECT_ERRNO_IGNORE
) continue;
545 strcpy(connection
->errorStr
,"connection timeout");
546 connection
->error
= MPD_ERROR_TIMEOUT
;
547 connection
->doneProcessing
= 1;
548 connection
->doneListOk
= 0;
554 output
= connection
->buffer
+connection
->bufstart
;
555 connection
->bufstart
= rt
- connection
->buffer
+ 1;
557 if(strcmp(output
,"OK")==0) {
558 if(connection
->listOks
> 0) {
559 strcpy(connection
->errorStr
, "expected more list_OK's");
560 connection
->error
= 1;
562 connection
->listOks
= 0;
563 connection
->doneProcessing
= 1;
564 connection
->doneListOk
= 0;
568 if(strcmp(output
, "list_OK") == 0) {
569 if(!connection
->listOks
) {
570 strcpy(connection
->errorStr
,
571 "got an unexpected list_OK");
572 connection
->error
= 1;
575 connection
->doneListOk
= 1;
576 connection
->listOks
--;
581 if(strncmp(output
,"ACK",strlen("ACK"))==0) {
586 strcpy(connection
->errorStr
, output
);
587 connection
->error
= MPD_ERROR_ACK
;
588 connection
->errorCode
= MPD_ACK_ERROR_UNK
;
589 connection
->errorAt
= MPD_ERROR_AT_UNK
;
590 connection
->doneProcessing
= 1;
591 connection
->doneListOk
= 0;
593 needle
= strchr(output
, '[');
595 val
= strtol(needle
+1, &test
, 10);
596 if(*test
!= '@') return;
597 connection
->errorCode
= val
;
598 val
= strtol(test
+1, &test
, 10);
599 if(*test
!= ']') return;
600 connection
->errorAt
= val
;
604 tok
= strchr(output
, ':');
612 connection
->returnElement
= mpd_newReturnElement(name
,&(value
[1]));
615 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
616 "error parsing: %s:%s",name
,value
);
617 connection
->error
= 1;
621 void mpd_finishCommand(mpd_Connection
* connection
) {
622 while(!connection
->doneProcessing
) {
623 if(connection
->doneListOk
) connection
->doneListOk
= 0;
624 mpd_getNextReturnElement(connection
);
628 static void mpd_finishListOkCommand(mpd_Connection
* connection
) {
629 while(!connection
->doneProcessing
&& connection
->listOks
&&
630 !connection
->doneListOk
)
632 mpd_getNextReturnElement(connection
);
636 int mpd_nextListOkCommand(mpd_Connection
* connection
) {
637 mpd_finishListOkCommand(connection
);
638 if(!connection
->doneProcessing
) connection
->doneListOk
= 0;
639 if(connection
->listOks
== 0 || connection
->doneProcessing
) return -1;
643 void mpd_sendStatusCommand(mpd_Connection
* connection
) {
644 mpd_executeCommand(connection
,"status\n");
647 mpd_Status
* mpd_getStatus(mpd_Connection
* connection
) {
650 /*mpd_executeCommand(connection,"status\n");
652 if(connection->error) return NULL;*/
654 if(connection
->doneProcessing
|| (connection
->listOks
&&
655 connection
->doneListOk
))
660 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
662 status
= malloc(sizeof(mpd_Status
));
666 status
->playlist
= -1;
667 status
->playlistLength
= -1;
671 status
->elapsedTime
= 0;
672 status
->totalTime
= 0;
674 status
->sampleRate
= 0;
676 status
->channels
= 0;
677 status
->crossfade
= -1;
678 status
->error
= NULL
;
679 status
->updatingDb
= 0;
681 if(connection
->error
) {
685 while(connection
->returnElement
) {
686 mpd_ReturnElement
* re
= connection
->returnElement
;
687 if(strcmp(re
->name
,"volume")==0) {
688 status
->volume
= atoi(re
->value
);
690 else if(strcmp(re
->name
,"repeat")==0) {
691 status
->repeat
= atoi(re
->value
);
693 else if(strcmp(re
->name
,"random")==0) {
694 status
->random
= atoi(re
->value
);
696 else if(strcmp(re
->name
,"playlist")==0) {
697 status
->playlist
= strtol(re
->value
,NULL
,10);
699 else if(strcmp(re
->name
,"playlistlength")==0) {
700 status
->playlistLength
= atoi(re
->value
);
702 else if(strcmp(re
->name
,"bitrate")==0) {
703 status
->bitRate
= atoi(re
->value
);
705 else if(strcmp(re
->name
,"state")==0) {
706 if(strcmp(re
->value
,"play")==0) {
707 status
->state
= MPD_STATUS_STATE_PLAY
;
709 else if(strcmp(re
->value
,"stop")==0) {
710 status
->state
= MPD_STATUS_STATE_STOP
;
712 else if(strcmp(re
->value
,"pause")==0) {
713 status
->state
= MPD_STATUS_STATE_PAUSE
;
716 status
->state
= MPD_STATUS_STATE_UNKNOWN
;
719 else if(strcmp(re
->name
,"song")==0) {
720 status
->song
= atoi(re
->value
);
722 else if(strcmp(re
->name
,"songid")==0) {
723 status
->songid
= atoi(re
->value
);
725 else if(strcmp(re
->name
,"time")==0) {
726 char * tok
= strchr(re
->value
,':');
727 /* the second strchr below is a safety check */
728 if (tok
&& (strchr(tok
,0) > (tok
+1))) {
729 /* atoi stops at the first non-[0-9] char: */
730 status
->elapsedTime
= atoi(re
->value
);
731 status
->totalTime
= atoi(tok
+1);
734 else if(strcmp(re
->name
,"error")==0) {
735 status
->error
= strdup(re
->value
);
737 else if(strcmp(re
->name
,"xfade")==0) {
738 status
->crossfade
= atoi(re
->value
);
740 else if(strcmp(re
->name
,"updating_db")==0) {
741 status
->updatingDb
= atoi(re
->value
);
743 else if(strcmp(re
->name
,"audio")==0) {
744 char * tok
= strchr(re
->value
,':');
745 if (tok
&& (strchr(tok
,0) > (tok
+1))) {
746 status
->sampleRate
= atoi(re
->value
);
747 status
->bits
= atoi(++tok
);
748 tok
= strchr(tok
,':');
749 if (tok
&& (strchr(tok
,0) > (tok
+1)))
750 status
->channels
= atoi(tok
+1);
754 mpd_getNextReturnElement(connection
);
755 if(connection
->error
) {
761 if(connection
->error
) {
765 else if(status
->state
<0) {
766 strcpy(connection
->errorStr
,"state not found");
767 connection
->error
= 1;
775 void mpd_freeStatus(mpd_Status
* status
) {
776 if(status
->error
) free(status
->error
);
780 void mpd_sendStatsCommand(mpd_Connection
* connection
) {
781 mpd_executeCommand(connection
,"stats\n");
784 mpd_Stats
* mpd_getStats(mpd_Connection
* connection
) {
787 /*mpd_executeCommand(connection,"stats\n");
789 if(connection->error) return NULL;*/
791 if(connection
->doneProcessing
|| (connection
->listOks
&&
792 connection
->doneListOk
))
797 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
799 stats
= malloc(sizeof(mpd_Stats
));
800 stats
->numberOfArtists
= 0;
801 stats
->numberOfAlbums
= 0;
802 stats
->numberOfSongs
= 0;
804 stats
->dbUpdateTime
= 0;
806 stats
->dbPlayTime
= 0;
808 if(connection
->error
) {
812 while(connection
->returnElement
) {
813 mpd_ReturnElement
* re
= connection
->returnElement
;
814 if(strcmp(re
->name
,"artists")==0) {
815 stats
->numberOfArtists
= atoi(re
->value
);
817 else if(strcmp(re
->name
,"albums")==0) {
818 stats
->numberOfAlbums
= atoi(re
->value
);
820 else if(strcmp(re
->name
,"songs")==0) {
821 stats
->numberOfSongs
= atoi(re
->value
);
823 else if(strcmp(re
->name
,"uptime")==0) {
824 stats
->uptime
= strtol(re
->value
,NULL
,10);
826 else if(strcmp(re
->name
,"db_update")==0) {
827 stats
->dbUpdateTime
= strtol(re
->value
,NULL
,10);
829 else if(strcmp(re
->name
,"playtime")==0) {
830 stats
->playTime
= strtol(re
->value
,NULL
,10);
832 else if(strcmp(re
->name
,"db_playtime")==0) {
833 stats
->dbPlayTime
= strtol(re
->value
,NULL
,10);
836 mpd_getNextReturnElement(connection
);
837 if(connection
->error
) {
843 if(connection
->error
) {
851 void mpd_freeStats(mpd_Stats
* stats
) {
855 static void mpd_initSong(mpd_Song
* song
) {
865 song
->composer
= NULL
;
867 song
->comment
= NULL
;
869 song
->time
= MPD_SONG_NO_TIME
;
870 song
->pos
= MPD_SONG_NO_NUM
;
871 song
->id
= MPD_SONG_NO_ID
;
874 static void mpd_finishSong(mpd_Song
* song
) {
875 if(song
->file
) free(song
->file
);
876 if(song
->artist
) free(song
->artist
);
877 if(song
->album
) free(song
->album
);
878 if(song
->title
) free(song
->title
);
879 if(song
->track
) free(song
->track
);
880 if(song
->name
) free(song
->name
);
881 if(song
->date
) free(song
->date
);
882 if(song
->genre
) free(song
->genre
);
883 if(song
->composer
) free(song
->composer
);
884 if(song
->disc
) free(song
->disc
);
885 if(song
->comment
) free(song
->comment
);
888 mpd_Song
* mpd_newSong(void) {
889 mpd_Song
* ret
= malloc(sizeof(mpd_Song
));
896 void mpd_freeSong(mpd_Song
* song
) {
897 mpd_finishSong(song
);
901 mpd_Song
* mpd_songDup(mpd_Song
* song
) {
902 mpd_Song
* ret
= mpd_newSong();
904 if(song
->file
) ret
->file
= strdup(song
->file
);
905 if(song
->artist
) ret
->artist
= strdup(song
->artist
);
906 if(song
->album
) ret
->album
= strdup(song
->album
);
907 if(song
->title
) ret
->title
= strdup(song
->title
);
908 if(song
->track
) ret
->track
= strdup(song
->track
);
909 if(song
->name
) ret
->name
= strdup(song
->name
);
910 if(song
->date
) ret
->date
= strdup(song
->date
);
911 if(song
->genre
) ret
->genre
= strdup(song
->genre
);
912 if(song
->composer
) ret
->composer
= strdup(song
->composer
);
913 if(song
->disc
) ret
->disc
= strdup(song
->disc
);
914 if(song
->comment
) ret
->comment
= strdup(song
->comment
);
915 ret
->time
= song
->time
;
916 ret
->pos
= song
->pos
;
922 static void mpd_initDirectory(mpd_Directory
* directory
) {
923 directory
->path
= NULL
;
926 static void mpd_finishDirectory(mpd_Directory
* directory
) {
927 if(directory
->path
) free(directory
->path
);
930 mpd_Directory
* mpd_newDirectory(void) {
931 mpd_Directory
* directory
= malloc(sizeof(mpd_Directory
));;
933 mpd_initDirectory(directory
);
938 void mpd_freeDirectory(mpd_Directory
* directory
) {
939 mpd_finishDirectory(directory
);
944 mpd_Directory
* mpd_directoryDup(mpd_Directory
* directory
) {
945 mpd_Directory
* ret
= mpd_newDirectory();
947 if(directory
->path
) ret
->path
= strdup(directory
->path
);
952 static void mpd_initPlaylistFile(mpd_PlaylistFile
* playlist
) {
953 playlist
->path
= NULL
;
956 static void mpd_finishPlaylistFile(mpd_PlaylistFile
* playlist
) {
957 if(playlist
->path
) free(playlist
->path
);
960 mpd_PlaylistFile
* mpd_newPlaylistFile(void) {
961 mpd_PlaylistFile
* playlist
= malloc(sizeof(mpd_PlaylistFile
));
963 mpd_initPlaylistFile(playlist
);
968 void mpd_freePlaylistFile(mpd_PlaylistFile
* playlist
) {
969 mpd_finishPlaylistFile(playlist
);
973 mpd_PlaylistFile
* mpd_playlistFileDup(mpd_PlaylistFile
* playlist
) {
974 mpd_PlaylistFile
* ret
= mpd_newPlaylistFile();
976 if(playlist
->path
) ret
->path
= strdup(playlist
->path
);
981 static void mpd_initInfoEntity(mpd_InfoEntity
* entity
) {
982 entity
->info
.directory
= NULL
;
985 static void mpd_finishInfoEntity(mpd_InfoEntity
* entity
) {
986 if(entity
->info
.directory
) {
987 if(entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
988 mpd_freeDirectory(entity
->info
.directory
);
990 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
) {
991 mpd_freeSong(entity
->info
.song
);
993 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
994 mpd_freePlaylistFile(entity
->info
.playlistFile
);
999 mpd_InfoEntity
* mpd_newInfoEntity(void) {
1000 mpd_InfoEntity
* entity
= malloc(sizeof(mpd_InfoEntity
));
1002 mpd_initInfoEntity(entity
);
1007 void mpd_freeInfoEntity(mpd_InfoEntity
* entity
) {
1008 mpd_finishInfoEntity(entity
);
1012 static void mpd_sendInfoCommand(mpd_Connection
* connection
, char * command
) {
1013 mpd_executeCommand(connection
,command
);
1016 mpd_InfoEntity
* mpd_getNextInfoEntity(mpd_Connection
* connection
) {
1017 mpd_InfoEntity
* entity
= NULL
;
1019 if(connection
->doneProcessing
|| (connection
->listOks
&&
1020 connection
->doneListOk
))
1025 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
1027 if(connection
->returnElement
) {
1028 if(strcmp(connection
->returnElement
->name
,"file")==0) {
1029 entity
= mpd_newInfoEntity();
1030 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1031 entity
->info
.song
= mpd_newSong();
1032 entity
->info
.song
->file
=
1033 strdup(connection
->returnElement
->value
);
1035 else if(strcmp(connection
->returnElement
->name
,
1037 entity
= mpd_newInfoEntity();
1038 entity
->type
= MPD_INFO_ENTITY_TYPE_DIRECTORY
;
1039 entity
->info
.directory
= mpd_newDirectory();
1040 entity
->info
.directory
->path
=
1041 strdup(connection
->returnElement
->value
);
1043 else if(strcmp(connection
->returnElement
->name
,"playlist")==0) {
1044 entity
= mpd_newInfoEntity();
1045 entity
->type
= MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
;
1046 entity
->info
.playlistFile
= mpd_newPlaylistFile();
1047 entity
->info
.playlistFile
->path
=
1048 strdup(connection
->returnElement
->value
);
1050 else if(strcmp(connection
->returnElement
->name
, "cpos") == 0){
1051 entity
= mpd_newInfoEntity();
1052 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1053 entity
->info
.song
= mpd_newSong();
1054 entity
->info
.song
->pos
= atoi(connection
->returnElement
->value
);
1057 connection
->error
= 1;
1058 strcpy(connection
->errorStr
,"problem parsing song info");
1064 mpd_getNextReturnElement(connection
);
1065 while(connection
->returnElement
) {
1066 mpd_ReturnElement
* re
= connection
->returnElement
;
1068 if(strcmp(re
->name
,"file")==0) return entity
;
1069 else if(strcmp(re
->name
,"directory")==0) return entity
;
1070 else if(strcmp(re
->name
,"playlist")==0) return entity
;
1071 else if(strcmp(re
->name
,"cpos")==0) return entity
;
1073 if(entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
&&
1074 strlen(re
->value
)) {
1075 if(!entity
->info
.song
->artist
&&
1076 strcmp(re
->name
,"Artist")==0) {
1077 entity
->info
.song
->artist
= strdup(re
->value
);
1079 else if(!entity
->info
.song
->album
&&
1080 strcmp(re
->name
,"Album")==0) {
1081 entity
->info
.song
->album
= strdup(re
->value
);
1083 else if(!entity
->info
.song
->title
&&
1084 strcmp(re
->name
,"Title")==0) {
1085 entity
->info
.song
->title
= strdup(re
->value
);
1087 else if(!entity
->info
.song
->track
&&
1088 strcmp(re
->name
,"Track")==0) {
1089 entity
->info
.song
->track
= strdup(re
->value
);
1091 else if(!entity
->info
.song
->name
&&
1092 strcmp(re
->name
,"Name")==0) {
1093 entity
->info
.song
->name
= strdup(re
->value
);
1095 else if(entity
->info
.song
->time
==MPD_SONG_NO_TIME
&&
1096 strcmp(re
->name
,"Time")==0) {
1097 entity
->info
.song
->time
= atoi(re
->value
);
1099 else if(entity
->info
.song
->pos
==MPD_SONG_NO_NUM
&&
1100 strcmp(re
->name
,"Pos")==0) {
1101 entity
->info
.song
->pos
= atoi(re
->value
);
1103 else if(entity
->info
.song
->id
==MPD_SONG_NO_ID
&&
1104 strcmp(re
->name
,"Id")==0) {
1105 entity
->info
.song
->id
= atoi(re
->value
);
1107 else if(!entity
->info
.song
->date
&&
1108 strcmp(re
->name
, "Date") == 0) {
1109 entity
->info
.song
->date
= strdup(re
->value
);
1111 else if(!entity
->info
.song
->genre
&&
1112 strcmp(re
->name
, "Genre") == 0) {
1113 entity
->info
.song
->genre
= strdup(re
->value
);
1115 else if(!entity
->info
.song
->composer
&&
1116 strcmp(re
->name
, "Composer") == 0) {
1117 entity
->info
.song
->composer
= strdup(re
->value
);
1119 else if(!entity
->info
.song
->disc
&&
1120 strcmp(re
->name
, "Disc") == 0) {
1121 entity
->info
.song
->disc
= strdup(re
->value
);
1123 else if(!entity
->info
.song
->comment
&&
1124 strcmp(re
->name
, "Comment") == 0) {
1125 entity
->info
.song
->comment
= strdup(re
->value
);
1128 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1130 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1133 mpd_getNextReturnElement(connection
);
1139 static char * mpd_getNextReturnElementNamed(mpd_Connection
* connection
,
1142 if(connection
->doneProcessing
|| (connection
->listOks
&&
1143 connection
->doneListOk
))
1148 mpd_getNextReturnElement(connection
);
1149 while(connection
->returnElement
) {
1150 mpd_ReturnElement
* re
= connection
->returnElement
;
1152 if(strcmp(re
->name
,name
)==0) return strdup(re
->value
);
1153 mpd_getNextReturnElement(connection
);
1159 char *mpd_getNextTag(mpd_Connection
*connection
, int type
)
1161 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
||
1162 type
== MPD_TAG_ITEM_ANY
)
1164 if (type
== MPD_TAG_ITEM_FILENAME
)
1165 return mpd_getNextReturnElementNamed(connection
, "file");
1166 return mpd_getNextReturnElementNamed(connection
, mpdTagItemKeys
[type
]);
1169 char * mpd_getNextArtist(mpd_Connection
* connection
) {
1170 return mpd_getNextReturnElementNamed(connection
,"Artist");
1173 char * mpd_getNextAlbum(mpd_Connection
* connection
) {
1174 return mpd_getNextReturnElementNamed(connection
,"Album");
1177 void mpd_sendPlaylistInfoCommand(mpd_Connection
* connection
, int songPos
) {
1178 char * string
= malloc(strlen("playlistinfo")+25);
1179 sprintf(string
,"playlistinfo \"%i\"\n",songPos
);
1180 mpd_sendInfoCommand(connection
,string
);
1184 void mpd_sendPlaylistIdCommand(mpd_Connection
* connection
, int id
) {
1185 char * string
= malloc(strlen("playlistid")+25);
1186 sprintf(string
, "playlistid \"%i\"\n", id
);
1187 mpd_sendInfoCommand(connection
, string
);
1191 void mpd_sendPlChangesCommand(mpd_Connection
* connection
, long long playlist
) {
1192 char * string
= malloc(strlen("plchanges")+25);
1193 sprintf(string
,"plchanges \"%lld\"\n",playlist
);
1194 mpd_sendInfoCommand(connection
,string
);
1198 void mpd_sendPlChangesPosIdCommand(mpd_Connection
* connection
, long long playlist
) {
1199 char * string
= malloc(strlen("plchangesposid")+25);
1200 sprintf(string
,"plchangesposid \"%lld\"\n",playlist
);
1201 mpd_sendInfoCommand(connection
,string
);
1205 void mpd_sendListallCommand(mpd_Connection
* connection
, const char * dir
) {
1206 char * sDir
= mpd_sanitizeArg(dir
);
1207 char * string
= malloc(strlen("listall")+strlen(sDir
)+5);
1208 sprintf(string
,"listall \"%s\"\n",sDir
);
1209 mpd_sendInfoCommand(connection
,string
);
1214 void mpd_sendListallInfoCommand(mpd_Connection
* connection
, const char * dir
) {
1215 char * sDir
= mpd_sanitizeArg(dir
);
1216 char * string
= malloc(strlen("listallinfo")+strlen(sDir
)+5);
1217 sprintf(string
,"listallinfo \"%s\"\n",sDir
);
1218 mpd_sendInfoCommand(connection
,string
);
1223 void mpd_sendLsInfoCommand(mpd_Connection
* connection
, const char * dir
) {
1224 char * sDir
= mpd_sanitizeArg(dir
);
1225 char * string
= malloc(strlen("lsinfo")+strlen(sDir
)+5);
1226 sprintf(string
,"lsinfo \"%s\"\n",sDir
);
1227 mpd_sendInfoCommand(connection
,string
);
1232 void mpd_sendCurrentSongCommand(mpd_Connection
* connection
) {
1233 mpd_executeCommand(connection
,"currentsong\n");
1236 void mpd_sendSearchCommand(mpd_Connection
* connection
, int table
,
1241 char * sanitStr
= mpd_sanitizeArg(str
);
1242 if(table
== MPD_TABLE_ARTIST
) strcpy(st
,"artist");
1243 else if(table
== MPD_TABLE_ALBUM
) strcpy(st
,"album");
1244 else if(table
== MPD_TABLE_TITLE
) strcpy(st
,"title");
1245 else if(table
== MPD_TABLE_FILENAME
) strcpy(st
,"filename");
1247 connection
->error
= 1;
1248 strcpy(connection
->errorStr
,"unknown table for search");
1251 string
= malloc(strlen("search")+strlen(sanitStr
)+strlen(st
)+6);
1252 sprintf(string
,"search %s \"%s\"\n",st
,sanitStr
);
1253 mpd_sendInfoCommand(connection
,string
);
1258 void mpd_sendFindCommand(mpd_Connection
* connection
, int table
,
1263 char * sanitStr
= mpd_sanitizeArg(str
);
1264 if(table
== MPD_TABLE_ARTIST
) strcpy(st
,"artist");
1265 else if(table
== MPD_TABLE_ALBUM
) strcpy(st
,"album");
1266 else if(table
== MPD_TABLE_TITLE
) strcpy(st
,"title");
1268 connection
->error
= 1;
1269 strcpy(connection
->errorStr
,"unknown table for find");
1272 string
= malloc(strlen("find")+strlen(sanitStr
)+strlen(st
)+6);
1273 sprintf(string
,"find %s \"%s\"\n",st
,sanitStr
);
1274 mpd_sendInfoCommand(connection
,string
);
1279 void mpd_sendListCommand(mpd_Connection
* connection
, int table
,
1284 if(table
== MPD_TABLE_ARTIST
) strcpy(st
,"artist");
1285 else if(table
== MPD_TABLE_ALBUM
) strcpy(st
,"album");
1287 connection
->error
= 1;
1288 strcpy(connection
->errorStr
,"unknown table for list");
1292 char * sanitArg1
= mpd_sanitizeArg(arg1
);
1293 string
= malloc(strlen("list")+strlen(sanitArg1
)+strlen(st
)+6);
1294 sprintf(string
,"list %s \"%s\"\n",st
,sanitArg1
);
1298 string
= malloc(strlen("list")+strlen(st
)+3);
1299 sprintf(string
,"list %s\n",st
);
1301 mpd_sendInfoCommand(connection
,string
);
1305 void mpd_sendAddCommand(mpd_Connection
* connection
, const char * file
) {
1306 char * sFile
= mpd_sanitizeArg(file
);
1307 char * string
= malloc(strlen("add")+strlen(sFile
)+5);
1308 sprintf(string
,"add \"%s\"\n",sFile
);
1309 mpd_executeCommand(connection
,string
);
1314 int mpd_sendAddIdCommand(mpd_Connection
*connection
, const char *file
)
1317 char *sFile
= mpd_sanitizeArg(file
);
1318 char *string
= malloc(strlen("addid")+strlen(sFile
)+5);
1320 sprintf(string
, "addid \"%s\"\n", sFile
);
1321 mpd_sendInfoCommand(connection
, string
);
1325 string
= mpd_getNextReturnElementNamed(connection
, "Id");
1327 retval
= atoi(string
);
1334 void mpd_sendDeleteCommand(mpd_Connection
* connection
, int songPos
) {
1335 char * string
= malloc(strlen("delete")+25);
1336 sprintf(string
,"delete \"%i\"\n",songPos
);
1337 mpd_sendInfoCommand(connection
,string
);
1341 void mpd_sendDeleteIdCommand(mpd_Connection
* connection
, int id
) {
1342 char * string
= malloc(strlen("deleteid")+25);
1343 sprintf(string
, "deleteid \"%i\"\n", id
);
1344 mpd_sendInfoCommand(connection
,string
);
1348 void mpd_sendSaveCommand(mpd_Connection
* connection
, const char * name
) {
1349 char * sName
= mpd_sanitizeArg(name
);
1350 char * string
= malloc(strlen("save")+strlen(sName
)+5);
1351 sprintf(string
,"save \"%s\"\n",sName
);
1352 mpd_executeCommand(connection
,string
);
1357 void mpd_sendLoadCommand(mpd_Connection
* connection
, const char * name
) {
1358 char * sName
= mpd_sanitizeArg(name
);
1359 char * string
= malloc(strlen("load")+strlen(sName
)+5);
1360 sprintf(string
,"load \"%s\"\n",sName
);
1361 mpd_executeCommand(connection
,string
);
1366 void mpd_sendRmCommand(mpd_Connection
* connection
, const char * name
) {
1367 char * sName
= mpd_sanitizeArg(name
);
1368 char * string
= malloc(strlen("rm")+strlen(sName
)+5);
1369 sprintf(string
,"rm \"%s\"\n",sName
);
1370 mpd_executeCommand(connection
,string
);
1375 void mpd_sendShuffleCommand(mpd_Connection
* connection
) {
1376 mpd_executeCommand(connection
,"shuffle\n");
1379 void mpd_sendClearCommand(mpd_Connection
* connection
) {
1380 mpd_executeCommand(connection
,"clear\n");
1383 void mpd_sendPlayCommand(mpd_Connection
* connection
, int songPos
) {
1384 char * string
= malloc(strlen("play")+25);
1385 sprintf(string
,"play \"%i\"\n",songPos
);
1386 mpd_sendInfoCommand(connection
,string
);
1390 void mpd_sendPlayIdCommand(mpd_Connection
* connection
, int id
) {
1391 char * string
= malloc(strlen("playid")+25);
1392 sprintf(string
,"playid \"%i\"\n",id
);
1393 mpd_sendInfoCommand(connection
,string
);
1397 void mpd_sendStopCommand(mpd_Connection
* connection
) {
1398 mpd_executeCommand(connection
,"stop\n");
1401 void mpd_sendPauseCommand(mpd_Connection
* connection
, int pauseMode
) {
1402 char * string
= malloc(strlen("pause")+25);
1403 sprintf(string
,"pause \"%i\"\n",pauseMode
);
1404 mpd_executeCommand(connection
,string
);
1408 void mpd_sendNextCommand(mpd_Connection
* connection
) {
1409 mpd_executeCommand(connection
,"next\n");
1412 void mpd_sendMoveCommand(mpd_Connection
* connection
, int from
, int to
) {
1413 char * string
= malloc(strlen("move")+25);
1414 sprintf(string
,"move \"%i\" \"%i\"\n",from
,to
);
1415 mpd_sendInfoCommand(connection
,string
);
1419 void mpd_sendMoveIdCommand(mpd_Connection
* connection
, int id
, int to
) {
1420 char * string
= malloc(strlen("moveid")+25);
1421 sprintf(string
, "moveid \"%i\" \"%i\"\n", id
, to
);
1422 mpd_sendInfoCommand(connection
,string
);
1426 void mpd_sendSwapCommand(mpd_Connection
* connection
, int song1
, int song2
) {
1427 char * string
= malloc(strlen("swap")+25);
1428 sprintf(string
,"swap \"%i\" \"%i\"\n",song1
,song2
);
1429 mpd_sendInfoCommand(connection
,string
);
1433 void mpd_sendSwapIdCommand(mpd_Connection
* connection
, int id1
, int id2
) {
1434 char * string
= malloc(strlen("swapid")+25);
1435 sprintf(string
, "swapid \"%i\" \"%i\"\n", id1
, id2
);
1436 mpd_sendInfoCommand(connection
,string
);
1440 void mpd_sendSeekCommand(mpd_Connection
* connection
, int song
, int time
) {
1441 char * string
= malloc(strlen("seek")+25);
1442 sprintf(string
,"seek \"%i\" \"%i\"\n",song
,time
);
1443 mpd_sendInfoCommand(connection
,string
);
1447 void mpd_sendSeekIdCommand(mpd_Connection
* connection
, int id
, int time
) {
1448 char * string
= malloc(strlen("seekid")+25);
1449 sprintf(string
,"seekid \"%i\" \"%i\"\n",id
,time
);
1450 mpd_sendInfoCommand(connection
,string
);
1454 void mpd_sendUpdateCommand(mpd_Connection
* connection
, char * path
) {
1455 char * sPath
= mpd_sanitizeArg(path
);
1456 char * string
= malloc(strlen("update")+strlen(sPath
)+5);
1457 sprintf(string
,"update \"%s\"\n",sPath
);
1458 mpd_sendInfoCommand(connection
,string
);
1463 int mpd_getUpdateId(mpd_Connection
* connection
) {
1467 jobid
= mpd_getNextReturnElementNamed(connection
,"updating_db");
1476 void mpd_sendPrevCommand(mpd_Connection
* connection
) {
1477 mpd_executeCommand(connection
,"previous\n");
1480 void mpd_sendRepeatCommand(mpd_Connection
* connection
, int repeatMode
) {
1481 char * string
= malloc(strlen("repeat")+25);
1482 sprintf(string
,"repeat \"%i\"\n",repeatMode
);
1483 mpd_executeCommand(connection
,string
);
1487 void mpd_sendRandomCommand(mpd_Connection
* connection
, int randomMode
) {
1488 char * string
= malloc(strlen("random")+25);
1489 sprintf(string
,"random \"%i\"\n",randomMode
);
1490 mpd_executeCommand(connection
,string
);
1494 void mpd_sendSetvolCommand(mpd_Connection
* connection
, int volumeChange
) {
1495 char * string
= malloc(strlen("setvol")+25);
1496 sprintf(string
,"setvol \"%i\"\n",volumeChange
);
1497 mpd_executeCommand(connection
,string
);
1501 void mpd_sendVolumeCommand(mpd_Connection
* connection
, int volumeChange
) {
1502 char * string
= malloc(strlen("volume")+25);
1503 sprintf(string
,"volume \"%i\"\n",volumeChange
);
1504 mpd_executeCommand(connection
,string
);
1508 void mpd_sendCrossfadeCommand(mpd_Connection
* connection
, int seconds
) {
1509 char * string
= malloc(strlen("crossfade")+25);
1510 sprintf(string
,"crossfade \"%i\"\n",seconds
);
1511 mpd_executeCommand(connection
,string
);
1515 void mpd_sendPasswordCommand(mpd_Connection
* connection
, const char * pass
) {
1516 char * sPass
= mpd_sanitizeArg(pass
);
1517 char * string
= malloc(strlen("password")+strlen(sPass
)+5);
1518 sprintf(string
,"password \"%s\"\n",sPass
);
1519 mpd_executeCommand(connection
,string
);
1524 void mpd_sendCommandListBegin(mpd_Connection
* connection
) {
1525 if(connection
->commandList
) {
1526 strcpy(connection
->errorStr
,"already in command list mode");
1527 connection
->error
= 1;
1530 connection
->commandList
= COMMAND_LIST
;
1531 mpd_executeCommand(connection
,"command_list_begin\n");
1534 void mpd_sendCommandListOkBegin(mpd_Connection
* connection
) {
1535 if(connection
->commandList
) {
1536 strcpy(connection
->errorStr
,"already in command list mode");
1537 connection
->error
= 1;
1540 connection
->commandList
= COMMAND_LIST_OK
;
1541 mpd_executeCommand(connection
,"command_list_ok_begin\n");
1542 connection
->listOks
= 0;
1545 void mpd_sendCommandListEnd(mpd_Connection
* connection
) {
1546 if(!connection
->commandList
) {
1547 strcpy(connection
->errorStr
,"not in command list mode");
1548 connection
->error
= 1;
1551 connection
->commandList
= 0;
1552 mpd_executeCommand(connection
,"command_list_end\n");
1555 void mpd_sendOutputsCommand(mpd_Connection
* connection
) {
1556 mpd_executeCommand(connection
,"outputs\n");
1559 mpd_OutputEntity
* mpd_getNextOutput(mpd_Connection
* connection
) {
1560 mpd_OutputEntity
* output
= NULL
;
1562 if(connection
->doneProcessing
|| (connection
->listOks
&&
1563 connection
->doneListOk
))
1568 if(connection
->error
) return NULL
;
1570 output
= malloc(sizeof(mpd_OutputEntity
));
1572 output
->name
= NULL
;
1573 output
->enabled
= 0;
1575 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
1577 while(connection
->returnElement
) {
1578 mpd_ReturnElement
* re
= connection
->returnElement
;
1579 if(strcmp(re
->name
,"outputid")==0) {
1580 if(output
!=NULL
&& output
->id
>=0) return output
;
1581 output
->id
= atoi(re
->value
);
1583 else if(strcmp(re
->name
,"outputname")==0) {
1584 output
->name
= strdup(re
->value
);
1586 else if(strcmp(re
->name
,"outputenabled")==0) {
1587 output
->enabled
= atoi(re
->value
);
1590 mpd_getNextReturnElement(connection
);
1591 if(connection
->error
) {
1601 void mpd_sendEnableOutputCommand(mpd_Connection
* connection
, int outputId
) {
1602 char * string
= malloc(strlen("enableoutput")+25);
1603 sprintf(string
,"enableoutput \"%i\"\n",outputId
);
1604 mpd_executeCommand(connection
,string
);
1608 void mpd_sendDisableOutputCommand(mpd_Connection
* connection
, int outputId
) {
1609 char * string
= malloc(strlen("disableoutput")+25);
1610 sprintf(string
,"disableoutput \"%i\"\n",outputId
);
1611 mpd_executeCommand(connection
,string
);
1615 void mpd_freeOutputElement(mpd_OutputEntity
* output
) {
1621 * mpd_sendNotCommandsCommand
1622 * odd naming, but it gets the not allowed commands
1625 void mpd_sendNotCommandsCommand(mpd_Connection
* connection
) {
1626 mpd_executeCommand(connection
,"notcommands\n");
1630 * mpd_sendCommandsCommand
1631 * odd naming, but it gets the allowed commands
1634 void mpd_sendCommandsCommand(mpd_Connection
* connection
) {
1635 mpd_executeCommand(connection
,"commands\n");
1638 * Get the next returned command
1640 char * mpd_getNextCommand(mpd_Connection
* connection
) {
1641 return mpd_getNextReturnElementNamed(connection
,"command");
1644 void mpd_startSearch(mpd_Connection
*connection
, int exact
)
1646 if (connection
->request
) {
1647 strcpy(connection
->errorStr
, "search already in progress");
1648 connection
->error
= 1;
1652 if (exact
) connection
->request
= strdup("find");
1653 else connection
->request
= strdup("search");
1656 void mpd_startFieldSearch(mpd_Connection
*connection
, int type
)
1660 if (connection
->request
) {
1661 strcpy(connection
->errorStr
, "search already in progress");
1662 connection
->error
= 1;
1666 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1667 strcpy(connection
->errorStr
, "invalid type specified");
1668 connection
->error
= 1;
1672 strtype
= mpdTagItemKeys
[type
];
1674 connection
->request
= malloc(strlen(strtype
)+6 /* "list"+space+\0 */);
1676 sprintf(connection
->request
, "list %c%s",
1677 tolower(strtype
[0]), strtype
+1);
1680 void mpd_addConstraintSearch(mpd_Connection
*connection
, int type
, char *name
)
1685 if (!connection
->request
) {
1686 strcpy(connection
->errorStr
, "no search in progress");
1687 connection
->error
= 1;
1691 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1692 strcpy(connection
->errorStr
, "invalid type specified");
1693 connection
->error
= 1;
1698 strcpy(connection
->errorStr
, "no name specified");
1699 connection
->error
= 1;
1703 strtype
= mpdTagItemKeys
[type
];
1704 arg
= mpd_sanitizeArg(name
);
1706 connection
->request
= realloc(connection
->request
,
1707 strlen(connection
->request
)+
1708 strlen(strtype
)+strlen(arg
)+
1709 5 /* two spaces+two quotes+\0 */);
1711 sprintf(connection
->request
, "%s %c%s \"%s\"", connection
->request
,
1712 tolower(strtype
[0]), strtype
+1, arg
);
1717 void mpd_commitSearch(mpd_Connection
*connection
)
1721 if (!connection
->request
) {
1722 strcpy(connection
->errorStr
, "no search in progress");
1723 connection
->error
= 1;
1727 length
= strlen(connection
->request
);
1728 connection
->request
= realloc(connection
->request
,
1729 length
+2 /* old length+\n+\0 */);
1730 connection
->request
[length
] = '\n';
1731 connection
->request
[length
+1] = '\0';
1732 mpd_sendInfoCommand(connection
, connection
->request
);
1734 free(connection
->request
);
1735 connection
->request
= NULL
;
1739 * @param connection a MpdConnection
1740 * @param path the path to the playlist.
1742 * List the content, with full metadata, of a stored playlist.
1745 void mpd_sendListPlaylistInfoCommand(mpd_Connection
*connection
, char *path
)
1747 char *arg
= mpd_sanitizeArg(path
);
1748 char *query
= malloc(strlen("listplaylistinfo")+strlen(arg
)+5);
1749 sprintf(query
, "listplaylistinfo \"%s\"\n",arg
);
1750 mpd_sendInfoCommand(connection
, query
);
1756 * @param connection a MpdConnection
1757 * @param path the path to the playlist.
1759 * List the content of a stored playlist.
1762 void mpd_sendListPlaylistCommand(mpd_Connection
*connection
, char *path
)
1764 char *arg
= mpd_sanitizeArg(path
);
1765 char *query
= malloc(strlen("listplaylist")+strlen(arg
)+5);
1766 sprintf(query
, "listplaylist \"%s\"\n",arg
);
1767 mpd_sendInfoCommand(connection
, query
);