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>
47 # include <ws2tcpip.h>
50 # include <netinet/in.h>
51 # include <arpa/inet.h>
52 # include <sys/socket.h>
56 /* (bits+1)/3 (plus the sign character) */
57 #define INTLEN ((sizeof(int) * CHAR_BIT + 1) / 3 + 1)
58 #define LONGLONGLEN ((sizeof(long long) * CHAR_BIT + 1) / 3 + 1)
60 #define COMMAND_LIST 1
61 #define COMMAND_LIST_OK 2
74 # define MSG_DONTWAIT 0
78 # define SELECT_ERRNO_IGNORE (errno == WSAEINTR || errno == WSAEINPROGRESS)
79 # define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
81 # define SELECT_ERRNO_IGNORE (errno == EINTR)
82 # define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
83 # define winsock_dll_error(c) 0
84 # define closesocket(s) close(s)
85 # define WSACleanup() do { /* nothing */ } while (0)
89 static int winsock_dll_error(mpd_Connection
*connection
)
92 if ((WSAStartup(MAKEWORD(2, 2), &wsaData
)) != 0 ||
93 LOBYTE(wsaData
.wVersion
) != 2 ||
94 HIBYTE(wsaData
.wVersion
) != 2 ) {
95 strcpy(connection
->errorStr
,
96 "Could not find usable WinSock DLL.");
97 connection
->error
= MPD_ERROR_SYSTEM
;
103 static int do_connect_fail(mpd_Connection
*connection
,
104 const struct sockaddr
*serv_addr
, int addrlen
)
106 int iMode
= 1; /* 0 = blocking, else non-blocking */
107 if (connect(connection
->sock
, serv_addr
, addrlen
) == SOCKET_ERROR
)
109 ioctlsocket(connection
->sock
, FIONBIO
, (u_long FAR
*) &iMode
);
112 #else /* !WIN32 (sane operating systems) */
113 static int do_connect_fail(mpd_Connection
*connection
,
114 const struct sockaddr
*serv_addr
, int addrlen
)
117 if (connect(connection
->sock
, serv_addr
, addrlen
) < 0)
119 flags
= fcntl(connection
->sock
, F_GETFL
, 0);
120 fcntl(connection
->sock
, F_SETFL
, flags
| O_NONBLOCK
);
126 static int mpd_connect(mpd_Connection
* connection
, const char * host
, int port
,
130 char service
[INTLEN
+1];
131 struct addrinfo hints
;
132 struct addrinfo
*res
= NULL
;
133 struct addrinfo
*addrinfo
= NULL
;
138 hints
.ai_flags
= AI_ADDRCONFIG
;
139 hints
.ai_family
= AF_UNSPEC
;
140 hints
.ai_socktype
= SOCK_STREAM
;
141 hints
.ai_protocol
= IPPROTO_TCP
;
142 hints
.ai_addrlen
= 0;
143 hints
.ai_addr
= NULL
;
144 hints
.ai_canonname
= NULL
;
145 hints
.ai_next
= NULL
;
147 snprintf(service
, sizeof(service
), "%i", port
);
149 error
= getaddrinfo(host
, service
, &hints
, &addrinfo
);
152 snprintf(connection
->errorStr
, MPD_ERRORSTR_MAX_LENGTH
,
153 "host \"%s\" not found: %s",
154 host
, gai_strerror(error
));
155 connection
->error
= MPD_ERROR_UNKHOST
;
159 for (res
= addrinfo
; res
; res
= res
->ai_next
) {
161 if (connection
->sock
>= 0)
162 closesocket(connection
->sock
);
163 connection
->sock
= socket(res
->ai_family
, SOCK_STREAM
,
165 if (connection
->sock
< 0) {
166 snprintf(connection
->errorStr
, MPD_ERRORSTR_MAX_LENGTH
,
167 "problems creating socket: %s",
169 connection
->error
= MPD_ERROR_SYSTEM
;
170 freeaddrinfo(addrinfo
);
174 mpd_setConnectionTimeout(connection
, timeout
);
177 if (do_connect_fail(connection
,
178 res
->ai_addr
, res
->ai_addrlen
)) {
179 /* try the next address */
180 closesocket(connection
->sock
);
181 connection
->sock
= -1;
188 freeaddrinfo(addrinfo
);
190 if (connection
->sock
< 0) {
191 snprintf(connection
->errorStr
, MPD_ERRORSTR_MAX_LENGTH
,
192 "problems connecting to \"%s\" on port %i: %s",
193 host
, port
, strerror(errno
));
194 connection
->error
= MPD_ERROR_CONNPORT
;
201 #else /* !MPD_HAVE_GAI */
202 static int mpd_connect(mpd_Connection
* connection
, const char * host
, int port
,
206 struct sockaddr
* dest
;
208 struct sockaddr_in sin
;
210 if(!(he
=gethostbyname(host
))) {
211 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
212 "host \"%s\" not found",host
);
213 connection
->error
= MPD_ERROR_UNKHOST
;
217 memset(&sin
,0,sizeof(struct sockaddr_in
));
218 /*dest.sin_family = he->h_addrtype;*/
219 sin
.sin_family
= AF_INET
;
220 sin
.sin_port
= htons(port
);
222 switch(he
->h_addrtype
) {
224 memcpy((char *)&sin
.sin_addr
.s_addr
,(char *)he
->h_addr
,
226 dest
= (struct sockaddr
*)&sin
;
227 destlen
= sizeof(struct sockaddr_in
);
230 strcpy(connection
->errorStr
,"address type is not IPv4");
231 connection
->error
= MPD_ERROR_SYSTEM
;
236 if (connection
->sock
>= 0)
237 closesocket(connection
->sock
);
238 if((connection
->sock
= socket(dest
->sa_family
,SOCK_STREAM
,0))<0) {
239 strcpy(connection
->errorStr
,"problems creating socket");
240 connection
->error
= MPD_ERROR_SYSTEM
;
244 mpd_setConnectionTimeout(connection
,timeout
);
247 if (do_connect_fail(connection
, dest
, destlen
)) {
248 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
249 "problems connecting to \"%s\" on port"
251 connection
->error
= MPD_ERROR_CONNPORT
;
257 #endif /* !MPD_HAVE_GAI */
259 char * mpdTagItemKeys
[MPD_TAG_NUM_OF_ITEM_TYPES
] =
276 static char * mpd_sanitizeArg(const char * arg
) {
279 register const char *c
;
282 /* instead of counting in that loop above, just
283 * use a bit more memory and half running time
285 ret
= malloc(strlen(arg
) * 2 + 1);
289 for(i
= strlen(arg
)+1; i
!= 0; --i
) {
290 if(*c
=='"' || *c
=='\\')
298 static mpd_ReturnElement
* mpd_newReturnElement(const char * name
, const char * value
)
300 mpd_ReturnElement
* ret
= malloc(sizeof(mpd_ReturnElement
));
302 ret
->name
= strdup(name
);
303 ret
->value
= strdup(value
);
308 static void mpd_freeReturnElement(mpd_ReturnElement
* re
) {
314 void mpd_setConnectionTimeout(mpd_Connection
* connection
, float timeout
) {
315 connection
->timeout
.tv_sec
= (int)timeout
;
316 connection
->timeout
.tv_usec
= (int)(timeout
*1e6
-
317 connection
->timeout
.tv_sec
*1000000 +
321 static int mpd_parseWelcome(mpd_Connection
* connection
, const char * host
, int port
,
327 if(strncmp(output
,MPD_WELCOME_MESSAGE
,strlen(MPD_WELCOME_MESSAGE
))) {
328 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
329 "mpd not running on port %i on host \"%s\"",
331 connection
->error
= MPD_ERROR_NOTMPD
;
335 tmp
= &output
[strlen(MPD_WELCOME_MESSAGE
)];
338 if(tmp
) connection
->version
[i
] = strtol(tmp
,&test
,10);
340 if (!tmp
|| (test
[0] != '.' && test
[0] != '\0')) {
341 snprintf(connection
->errorStr
,
342 MPD_ERRORSTR_MAX_LENGTH
,
343 "error parsing version number at "
345 &output
[strlen(MPD_WELCOME_MESSAGE
)]);
346 connection
->error
= MPD_ERROR_NOTMPD
;
356 static int mpd_connect_un(mpd_Connection
* connection
,
357 const char * host
, float timeout
)
361 struct sockaddr_un sun
;
363 path_length
= strlen(host
);
364 if (path_length
>= sizeof(sun
.sun_path
)) {
365 strcpy(connection
->errorStr
, "unix socket path is too long");
366 connection
->error
= MPD_ERROR_UNKHOST
;
370 sun
.sun_family
= AF_UNIX
;
371 memcpy(sun
.sun_path
, host
, path_length
+ 1);
373 connection
->sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
374 if (connection
->sock
< 0) {
375 strcpy(connection
->errorStr
, "problems creating socket");
376 connection
->error
= MPD_ERROR_SYSTEM
;
380 mpd_setConnectionTimeout(connection
, timeout
);
382 flags
= fcntl(connection
->sock
, F_GETFL
, 0);
383 fcntl(connection
->sock
, F_SETFL
, flags
| O_NONBLOCK
);
385 error
= connect(connection
->sock
, (struct sockaddr
*)&sun
, sizeof(sun
));
387 /* try the next address family */
388 close(connection
->sock
);
389 connection
->sock
= 0;
391 snprintf(connection
->errorStr
,MPD_BUFFER_MAX_LENGTH
,
392 "problems connecting to \"%s\": %s",
393 host
, strerror(errno
));
394 connection
->error
= MPD_ERROR_CONNPORT
;
402 mpd_Connection
* mpd_newConnection(const char * host
, int port
, float timeout
) {
405 char * output
= NULL
;
406 mpd_Connection
* connection
= malloc(sizeof(mpd_Connection
));
409 strcpy(connection
->buffer
,"");
410 connection
->sock
= -1;
411 connection
->buflen
= 0;
412 connection
->bufstart
= 0;
413 strcpy(connection
->errorStr
,"");
414 connection
->error
= 0;
415 connection
->doneProcessing
= 0;
416 connection
->commandList
= 0;
417 connection
->listOks
= 0;
418 connection
->doneListOk
= 0;
419 connection
->returnElement
= NULL
;
420 connection
->request
= NULL
;
422 if (winsock_dll_error(connection
))
427 err
= mpd_connect_un(connection
, host
, timeout
);
430 err
= mpd_connect(connection
, host
, port
, timeout
);
434 while(!(rt
= strstr(connection
->buffer
,"\n"))) {
435 tv
.tv_sec
= connection
->timeout
.tv_sec
;
436 tv
.tv_usec
= connection
->timeout
.tv_usec
;
438 FD_SET(connection
->sock
,&fds
);
439 if((err
= select(connection
->sock
+1,&fds
,NULL
,NULL
,&tv
)) == 1) {
441 readed
= recv(connection
->sock
,
442 &(connection
->buffer
[connection
->buflen
]),
443 MPD_BUFFER_MAX_LENGTH
-connection
->buflen
,0);
445 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
446 "problems getting a response from"
447 " \"%s\" on port %i : %s",host
,
448 port
, strerror(errno
));
449 connection
->error
= MPD_ERROR_NORESPONSE
;
452 connection
->buflen
+=readed
;
453 connection
->buffer
[connection
->buflen
] = '\0';
456 if (SELECT_ERRNO_IGNORE
)
458 snprintf(connection
->errorStr
,
459 MPD_ERRORSTR_MAX_LENGTH
,
460 "problems connecting to \"%s\" on port"
462 connection
->error
= MPD_ERROR_CONNPORT
;
466 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
467 "timeout in attempting to get a response from"
468 " \"%s\" on port %i",host
,port
);
469 connection
->error
= MPD_ERROR_NORESPONSE
;
475 output
= strdup(connection
->buffer
);
476 strcpy(connection
->buffer
,rt
+1);
477 connection
->buflen
= strlen(connection
->buffer
);
479 if(mpd_parseWelcome(connection
,host
,port
,output
) == 0) connection
->doneProcessing
= 1;
486 void mpd_clearError(mpd_Connection
* connection
) {
487 connection
->error
= 0;
488 connection
->errorStr
[0] = '\0';
491 void mpd_closeConnection(mpd_Connection
* connection
) {
492 closesocket(connection
->sock
);
493 if(connection
->returnElement
) free(connection
->returnElement
);
494 if(connection
->request
) free(connection
->request
);
499 static void mpd_executeCommand(mpd_Connection
* connection
, char * command
) {
503 char * commandPtr
= command
;
504 int commandLen
= strlen(command
);
506 if(!connection
->doneProcessing
&& !connection
->commandList
) {
507 strcpy(connection
->errorStr
,"not done processing current command");
508 connection
->error
= 1;
512 mpd_clearError(connection
);
515 FD_SET(connection
->sock
,&fds
);
516 tv
.tv_sec
= connection
->timeout
.tv_sec
;
517 tv
.tv_usec
= connection
->timeout
.tv_usec
;
519 while((ret
= select(connection
->sock
+1,NULL
,&fds
,NULL
,&tv
)==1) ||
520 (ret
==-1 && SELECT_ERRNO_IGNORE
)) {
521 ret
= send(connection
->sock
,commandPtr
,commandLen
,MSG_DONTWAIT
);
524 if (SENDRECV_ERRNO_IGNORE
) continue;
525 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
526 "problems giving command \"%s\"",command
);
527 connection
->error
= MPD_ERROR_SENDING
;
535 if(commandLen
<=0) break;
540 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
541 "timeout sending command \"%s\"",command
);
542 connection
->error
= MPD_ERROR_TIMEOUT
;
546 if(!connection
->commandList
) connection
->doneProcessing
= 0;
547 else if(connection
->commandList
== COMMAND_LIST_OK
) {
548 connection
->listOks
++;
552 static void mpd_getNextReturnElement(mpd_Connection
* connection
) {
553 char * output
= NULL
;
561 char * bufferCheck
= NULL
;
565 if(connection
->returnElement
) mpd_freeReturnElement(connection
->returnElement
);
566 connection
->returnElement
= NULL
;
568 if(connection
->doneProcessing
|| (connection
->listOks
&&
569 connection
->doneListOk
))
571 strcpy(connection
->errorStr
,"already done processing current command");
572 connection
->error
= 1;
576 bufferCheck
= connection
->buffer
+connection
->bufstart
;
577 while(connection
->bufstart
>=connection
->buflen
||
578 !(rt
= strchr(bufferCheck
,'\n'))) {
579 if(connection
->buflen
>=MPD_BUFFER_MAX_LENGTH
) {
580 memmove(connection
->buffer
,
582 connection
->bufstart
,
584 connection
->bufstart
+1);
585 connection
->buflen
-=connection
->bufstart
;
586 connection
->bufstart
= 0;
588 if(connection
->buflen
>=MPD_BUFFER_MAX_LENGTH
) {
589 strcpy(connection
->errorStr
,"buffer overrun");
590 connection
->error
= MPD_ERROR_BUFFEROVERRUN
;
591 connection
->doneProcessing
= 1;
592 connection
->doneListOk
= 0;
595 bufferCheck
= connection
->buffer
+connection
->buflen
;
596 tv
.tv_sec
= connection
->timeout
.tv_sec
;
597 tv
.tv_usec
= connection
->timeout
.tv_usec
;
599 FD_SET(connection
->sock
,&fds
);
600 if((err
= select(connection
->sock
+1,&fds
,NULL
,NULL
,&tv
) == 1)) {
601 readed
= recv(connection
->sock
,
602 connection
->buffer
+connection
->buflen
,
603 MPD_BUFFER_MAX_LENGTH
-connection
->buflen
,
605 if(readed
<0 && SENDRECV_ERRNO_IGNORE
) {
609 strcpy(connection
->errorStr
,"connection"
611 connection
->error
= MPD_ERROR_CONNCLOSED
;
612 connection
->doneProcessing
= 1;
613 connection
->doneListOk
= 0;
616 connection
->buflen
+=readed
;
617 connection
->buffer
[connection
->buflen
] = '\0';
619 else if(err
<0 && SELECT_ERRNO_IGNORE
) continue;
621 strcpy(connection
->errorStr
,"connection timeout");
622 connection
->error
= MPD_ERROR_TIMEOUT
;
623 connection
->doneProcessing
= 1;
624 connection
->doneListOk
= 0;
630 output
= connection
->buffer
+connection
->bufstart
;
631 connection
->bufstart
= rt
- connection
->buffer
+ 1;
633 if(strcmp(output
,"OK")==0) {
634 if(connection
->listOks
> 0) {
635 strcpy(connection
->errorStr
, "expected more list_OK's");
636 connection
->error
= 1;
638 connection
->listOks
= 0;
639 connection
->doneProcessing
= 1;
640 connection
->doneListOk
= 0;
644 if(strcmp(output
, "list_OK") == 0) {
645 if(!connection
->listOks
) {
646 strcpy(connection
->errorStr
,
647 "got an unexpected list_OK");
648 connection
->error
= 1;
651 connection
->doneListOk
= 1;
652 connection
->listOks
--;
657 if(strncmp(output
,"ACK",strlen("ACK"))==0) {
662 strcpy(connection
->errorStr
, output
);
663 connection
->error
= MPD_ERROR_ACK
;
664 connection
->errorCode
= MPD_ACK_ERROR_UNK
;
665 connection
->errorAt
= MPD_ERROR_AT_UNK
;
666 connection
->doneProcessing
= 1;
667 connection
->doneListOk
= 0;
669 needle
= strchr(output
, '[');
671 val
= strtol(needle
+1, &test
, 10);
672 if(*test
!= '@') return;
673 connection
->errorCode
= val
;
674 val
= strtol(test
+1, &test
, 10);
675 if(*test
!= ']') return;
676 connection
->errorAt
= val
;
680 tok
= strchr(output
, ':');
688 connection
->returnElement
= mpd_newReturnElement(name
,&(value
[1]));
691 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
692 "error parsing: %s:%s",name
,value
);
693 connection
->error
= 1;
697 void mpd_finishCommand(mpd_Connection
* connection
) {
698 while(!connection
->doneProcessing
) {
699 if(connection
->doneListOk
) connection
->doneListOk
= 0;
700 mpd_getNextReturnElement(connection
);
704 static void mpd_finishListOkCommand(mpd_Connection
* connection
) {
705 while(!connection
->doneProcessing
&& connection
->listOks
&&
706 !connection
->doneListOk
)
708 mpd_getNextReturnElement(connection
);
712 int mpd_nextListOkCommand(mpd_Connection
* connection
) {
713 mpd_finishListOkCommand(connection
);
714 if(!connection
->doneProcessing
) connection
->doneListOk
= 0;
715 if(connection
->listOks
== 0 || connection
->doneProcessing
) return -1;
719 void mpd_sendStatusCommand(mpd_Connection
* connection
) {
720 mpd_executeCommand(connection
,"status\n");
723 mpd_Status
* mpd_getStatus(mpd_Connection
* connection
) {
726 /*mpd_executeCommand(connection,"status\n");
728 if(connection->error) return NULL;*/
730 if(connection
->doneProcessing
|| (connection
->listOks
&&
731 connection
->doneListOk
))
736 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
738 status
= malloc(sizeof(mpd_Status
));
742 status
->playlist
= -1;
743 status
->playlistLength
= -1;
747 status
->elapsedTime
= 0;
748 status
->totalTime
= 0;
750 status
->sampleRate
= 0;
752 status
->channels
= 0;
753 status
->crossfade
= -1;
754 status
->error
= NULL
;
755 status
->updatingDb
= 0;
757 if(connection
->error
) {
761 while(connection
->returnElement
) {
762 mpd_ReturnElement
* re
= connection
->returnElement
;
763 if(strcmp(re
->name
,"volume")==0) {
764 status
->volume
= atoi(re
->value
);
766 else if(strcmp(re
->name
,"repeat")==0) {
767 status
->repeat
= atoi(re
->value
);
769 else if(strcmp(re
->name
,"random")==0) {
770 status
->random
= atoi(re
->value
);
772 else if(strcmp(re
->name
,"playlist")==0) {
773 status
->playlist
= strtol(re
->value
,NULL
,10);
775 else if(strcmp(re
->name
,"playlistlength")==0) {
776 status
->playlistLength
= atoi(re
->value
);
778 else if(strcmp(re
->name
,"bitrate")==0) {
779 status
->bitRate
= atoi(re
->value
);
781 else if(strcmp(re
->name
,"state")==0) {
782 if(strcmp(re
->value
,"play")==0) {
783 status
->state
= MPD_STATUS_STATE_PLAY
;
785 else if(strcmp(re
->value
,"stop")==0) {
786 status
->state
= MPD_STATUS_STATE_STOP
;
788 else if(strcmp(re
->value
,"pause")==0) {
789 status
->state
= MPD_STATUS_STATE_PAUSE
;
792 status
->state
= MPD_STATUS_STATE_UNKNOWN
;
795 else if(strcmp(re
->name
,"song")==0) {
796 status
->song
= atoi(re
->value
);
798 else if(strcmp(re
->name
,"songid")==0) {
799 status
->songid
= atoi(re
->value
);
801 else if(strcmp(re
->name
,"time")==0) {
802 char * tok
= strchr(re
->value
,':');
803 /* the second strchr below is a safety check */
804 if (tok
&& (strchr(tok
,0) > (tok
+1))) {
805 /* atoi stops at the first non-[0-9] char: */
806 status
->elapsedTime
= atoi(re
->value
);
807 status
->totalTime
= atoi(tok
+1);
810 else if(strcmp(re
->name
,"error")==0) {
811 status
->error
= strdup(re
->value
);
813 else if(strcmp(re
->name
,"xfade")==0) {
814 status
->crossfade
= atoi(re
->value
);
816 else if(strcmp(re
->name
,"updating_db")==0) {
817 status
->updatingDb
= atoi(re
->value
);
819 else if(strcmp(re
->name
,"audio")==0) {
820 char * tok
= strchr(re
->value
,':');
821 if (tok
&& (strchr(tok
,0) > (tok
+1))) {
822 status
->sampleRate
= atoi(re
->value
);
823 status
->bits
= atoi(++tok
);
824 tok
= strchr(tok
,':');
825 if (tok
&& (strchr(tok
,0) > (tok
+1)))
826 status
->channels
= atoi(tok
+1);
830 mpd_getNextReturnElement(connection
);
831 if(connection
->error
) {
837 if(connection
->error
) {
841 else if(status
->state
<0) {
842 strcpy(connection
->errorStr
,"state not found");
843 connection
->error
= 1;
851 void mpd_freeStatus(mpd_Status
* status
) {
852 if(status
->error
) free(status
->error
);
856 void mpd_sendStatsCommand(mpd_Connection
* connection
) {
857 mpd_executeCommand(connection
,"stats\n");
860 mpd_Stats
* mpd_getStats(mpd_Connection
* connection
) {
863 /*mpd_executeCommand(connection,"stats\n");
865 if(connection->error) return NULL;*/
867 if(connection
->doneProcessing
|| (connection
->listOks
&&
868 connection
->doneListOk
))
873 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
875 stats
= malloc(sizeof(mpd_Stats
));
876 stats
->numberOfArtists
= 0;
877 stats
->numberOfAlbums
= 0;
878 stats
->numberOfSongs
= 0;
880 stats
->dbUpdateTime
= 0;
882 stats
->dbPlayTime
= 0;
884 if(connection
->error
) {
888 while(connection
->returnElement
) {
889 mpd_ReturnElement
* re
= connection
->returnElement
;
890 if(strcmp(re
->name
,"artists")==0) {
891 stats
->numberOfArtists
= atoi(re
->value
);
893 else if(strcmp(re
->name
,"albums")==0) {
894 stats
->numberOfAlbums
= atoi(re
->value
);
896 else if(strcmp(re
->name
,"songs")==0) {
897 stats
->numberOfSongs
= atoi(re
->value
);
899 else if(strcmp(re
->name
,"uptime")==0) {
900 stats
->uptime
= strtol(re
->value
,NULL
,10);
902 else if(strcmp(re
->name
,"db_update")==0) {
903 stats
->dbUpdateTime
= strtol(re
->value
,NULL
,10);
905 else if(strcmp(re
->name
,"playtime")==0) {
906 stats
->playTime
= strtol(re
->value
,NULL
,10);
908 else if(strcmp(re
->name
,"db_playtime")==0) {
909 stats
->dbPlayTime
= strtol(re
->value
,NULL
,10);
912 mpd_getNextReturnElement(connection
);
913 if(connection
->error
) {
919 if(connection
->error
) {
927 void mpd_freeStats(mpd_Stats
* stats
) {
931 mpd_SearchStats
* mpd_getSearchStats(mpd_Connection
* connection
)
933 mpd_SearchStats
* stats
;
934 mpd_ReturnElement
* re
;
936 if (connection
->doneProcessing
||
937 (connection
->listOks
&& connection
->doneListOk
)) {
941 if (!connection
->returnElement
) mpd_getNextReturnElement(connection
);
943 if (connection
->error
)
946 stats
= malloc(sizeof(mpd_SearchStats
));
947 stats
->numberOfSongs
= 0;
950 while (connection
->returnElement
) {
951 re
= connection
->returnElement
;
953 if (strcmp(re
->name
, "songs") == 0) {
954 stats
->numberOfSongs
= atoi(re
->value
);
955 } else if (strcmp(re
->name
, "playtime") == 0) {
956 stats
->playTime
= strtol(re
->value
, NULL
, 10);
959 mpd_getNextReturnElement(connection
);
960 if (connection
->error
) {
966 if (connection
->error
) {
974 void mpd_freeSearchStats(mpd_SearchStats
* stats
)
979 static void mpd_initSong(mpd_Song
* song
) {
989 song
->composer
= NULL
;
990 song
->performer
= NULL
;
992 song
->comment
= NULL
;
994 song
->time
= MPD_SONG_NO_TIME
;
995 song
->pos
= MPD_SONG_NO_NUM
;
996 song
->id
= MPD_SONG_NO_ID
;
999 static void mpd_finishSong(mpd_Song
* song
) {
1000 if(song
->file
) free(song
->file
);
1001 if(song
->artist
) free(song
->artist
);
1002 if(song
->album
) free(song
->album
);
1003 if(song
->title
) free(song
->title
);
1004 if(song
->track
) free(song
->track
);
1005 if(song
->name
) free(song
->name
);
1006 if(song
->date
) free(song
->date
);
1007 if(song
->genre
) free(song
->genre
);
1008 if(song
->composer
) free(song
->composer
);
1009 if(song
->performer
) free(song
->performer
);
1010 if(song
->disc
) free(song
->disc
);
1011 if(song
->comment
) free(song
->comment
);
1014 mpd_Song
* mpd_newSong(void) {
1015 mpd_Song
* ret
= malloc(sizeof(mpd_Song
));
1022 void mpd_freeSong(mpd_Song
* song
) {
1024 mpd_finishSong(song
);
1028 mpd_Song
* mpd_songDup(mpd_Song
* song
) {
1029 mpd_Song
* ret
= mpd_newSong();
1031 if(song
->file
) ret
->file
= strdup(song
->file
);
1032 if(song
->artist
) ret
->artist
= strdup(song
->artist
);
1033 if(song
->album
) ret
->album
= strdup(song
->album
);
1034 if(song
->title
) ret
->title
= strdup(song
->title
);
1035 if(song
->track
) ret
->track
= strdup(song
->track
);
1036 if(song
->name
) ret
->name
= strdup(song
->name
);
1037 if(song
->date
) ret
->date
= strdup(song
->date
);
1038 if(song
->genre
) ret
->genre
= strdup(song
->genre
);
1039 if(song
->composer
) ret
->composer
= strdup(song
->composer
);
1040 if(song
->performer
) ret
->performer
= strdup(song
->performer
);
1041 if(song
->disc
) ret
->disc
= strdup(song
->disc
);
1042 if(song
->comment
) ret
->comment
= strdup(song
->comment
);
1043 ret
->time
= song
->time
;
1044 ret
->pos
= song
->pos
;
1050 static void mpd_initDirectory(mpd_Directory
* directory
) {
1051 directory
->path
= NULL
;
1054 static void mpd_finishDirectory(mpd_Directory
* directory
) {
1055 if(directory
->path
) free(directory
->path
);
1058 mpd_Directory
* mpd_newDirectory(void) {
1059 mpd_Directory
* directory
= malloc(sizeof(mpd_Directory
));;
1061 mpd_initDirectory(directory
);
1066 void mpd_freeDirectory(mpd_Directory
* directory
) {
1067 mpd_finishDirectory(directory
);
1072 mpd_Directory
* mpd_directoryDup(mpd_Directory
* directory
) {
1073 mpd_Directory
* ret
= mpd_newDirectory();
1075 if(directory
->path
) ret
->path
= strdup(directory
->path
);
1080 static void mpd_initPlaylistFile(mpd_PlaylistFile
* playlist
) {
1081 playlist
->path
= NULL
;
1084 static void mpd_finishPlaylistFile(mpd_PlaylistFile
* playlist
) {
1085 if(playlist
->path
) free(playlist
->path
);
1088 mpd_PlaylistFile
* mpd_newPlaylistFile(void) {
1089 mpd_PlaylistFile
* playlist
= malloc(sizeof(mpd_PlaylistFile
));
1091 mpd_initPlaylistFile(playlist
);
1096 void mpd_freePlaylistFile(mpd_PlaylistFile
* playlist
) {
1097 mpd_finishPlaylistFile(playlist
);
1101 mpd_PlaylistFile
* mpd_playlistFileDup(mpd_PlaylistFile
* playlist
) {
1102 mpd_PlaylistFile
* ret
= mpd_newPlaylistFile();
1104 if(playlist
->path
) ret
->path
= strdup(playlist
->path
);
1109 static void mpd_initInfoEntity(mpd_InfoEntity
* entity
) {
1110 entity
->info
.directory
= NULL
;
1113 static void mpd_finishInfoEntity(mpd_InfoEntity
* entity
) {
1114 if(entity
->info
.directory
) {
1115 if(entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1116 mpd_freeDirectory(entity
->info
.directory
);
1118 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
) {
1119 mpd_freeSong(entity
->info
.song
);
1121 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1122 mpd_freePlaylistFile(entity
->info
.playlistFile
);
1127 mpd_InfoEntity
* mpd_newInfoEntity(void) {
1128 mpd_InfoEntity
* entity
= malloc(sizeof(mpd_InfoEntity
));
1130 mpd_initInfoEntity(entity
);
1135 void mpd_freeInfoEntity(mpd_InfoEntity
* entity
) {
1136 mpd_finishInfoEntity(entity
);
1140 static void mpd_sendInfoCommand(mpd_Connection
* connection
, char * command
) {
1141 mpd_executeCommand(connection
,command
);
1144 mpd_InfoEntity
* mpd_getNextInfoEntity(mpd_Connection
* connection
) {
1145 mpd_InfoEntity
* entity
= NULL
;
1147 if(connection
->doneProcessing
|| (connection
->listOks
&&
1148 connection
->doneListOk
))
1153 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
1155 if(connection
->returnElement
) {
1156 if(strcmp(connection
->returnElement
->name
,"file")==0) {
1157 entity
= mpd_newInfoEntity();
1158 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1159 entity
->info
.song
= mpd_newSong();
1160 entity
->info
.song
->file
=
1161 strdup(connection
->returnElement
->value
);
1163 else if(strcmp(connection
->returnElement
->name
,
1165 entity
= mpd_newInfoEntity();
1166 entity
->type
= MPD_INFO_ENTITY_TYPE_DIRECTORY
;
1167 entity
->info
.directory
= mpd_newDirectory();
1168 entity
->info
.directory
->path
=
1169 strdup(connection
->returnElement
->value
);
1171 else if(strcmp(connection
->returnElement
->name
,"playlist")==0) {
1172 entity
= mpd_newInfoEntity();
1173 entity
->type
= MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
;
1174 entity
->info
.playlistFile
= mpd_newPlaylistFile();
1175 entity
->info
.playlistFile
->path
=
1176 strdup(connection
->returnElement
->value
);
1178 else if(strcmp(connection
->returnElement
->name
, "cpos") == 0){
1179 entity
= mpd_newInfoEntity();
1180 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1181 entity
->info
.song
= mpd_newSong();
1182 entity
->info
.song
->pos
= atoi(connection
->returnElement
->value
);
1185 connection
->error
= 1;
1186 strcpy(connection
->errorStr
,"problem parsing song info");
1192 mpd_getNextReturnElement(connection
);
1193 while(connection
->returnElement
) {
1194 mpd_ReturnElement
* re
= connection
->returnElement
;
1196 if(strcmp(re
->name
,"file")==0) return entity
;
1197 else if(strcmp(re
->name
,"directory")==0) return entity
;
1198 else if(strcmp(re
->name
,"playlist")==0) return entity
;
1199 else if(strcmp(re
->name
,"cpos")==0) return entity
;
1201 if(entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
&&
1202 strlen(re
->value
)) {
1203 if(!entity
->info
.song
->artist
&&
1204 strcmp(re
->name
,"Artist")==0) {
1205 entity
->info
.song
->artist
= strdup(re
->value
);
1207 else if(!entity
->info
.song
->album
&&
1208 strcmp(re
->name
,"Album")==0) {
1209 entity
->info
.song
->album
= strdup(re
->value
);
1211 else if(!entity
->info
.song
->title
&&
1212 strcmp(re
->name
,"Title")==0) {
1213 entity
->info
.song
->title
= strdup(re
->value
);
1215 else if(!entity
->info
.song
->track
&&
1216 strcmp(re
->name
,"Track")==0) {
1217 entity
->info
.song
->track
= strdup(re
->value
);
1219 else if(!entity
->info
.song
->name
&&
1220 strcmp(re
->name
,"Name")==0) {
1221 entity
->info
.song
->name
= strdup(re
->value
);
1223 else if(entity
->info
.song
->time
==MPD_SONG_NO_TIME
&&
1224 strcmp(re
->name
,"Time")==0) {
1225 entity
->info
.song
->time
= atoi(re
->value
);
1227 else if(entity
->info
.song
->pos
==MPD_SONG_NO_NUM
&&
1228 strcmp(re
->name
,"Pos")==0) {
1229 entity
->info
.song
->pos
= atoi(re
->value
);
1231 else if(entity
->info
.song
->id
==MPD_SONG_NO_ID
&&
1232 strcmp(re
->name
,"Id")==0) {
1233 entity
->info
.song
->id
= atoi(re
->value
);
1235 else if(!entity
->info
.song
->date
&&
1236 strcmp(re
->name
, "Date") == 0) {
1237 entity
->info
.song
->date
= strdup(re
->value
);
1239 else if(!entity
->info
.song
->genre
&&
1240 strcmp(re
->name
, "Genre") == 0) {
1241 entity
->info
.song
->genre
= strdup(re
->value
);
1243 else if(!entity
->info
.song
->composer
&&
1244 strcmp(re
->name
, "Composer") == 0) {
1245 entity
->info
.song
->composer
= strdup(re
->value
);
1247 else if(!entity
->info
.song
->performer
&&
1248 strcmp(re
->name
, "Performer") == 0) {
1249 entity
->info
.song
->performer
= strdup(re
->value
);
1251 else if(!entity
->info
.song
->disc
&&
1252 strcmp(re
->name
, "Disc") == 0) {
1253 entity
->info
.song
->disc
= strdup(re
->value
);
1255 else if(!entity
->info
.song
->comment
&&
1256 strcmp(re
->name
, "Comment") == 0) {
1257 entity
->info
.song
->comment
= strdup(re
->value
);
1260 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1262 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1265 mpd_getNextReturnElement(connection
);
1271 static char * mpd_getNextReturnElementNamed(mpd_Connection
* connection
,
1274 if(connection
->doneProcessing
|| (connection
->listOks
&&
1275 connection
->doneListOk
))
1280 mpd_getNextReturnElement(connection
);
1281 while(connection
->returnElement
) {
1282 mpd_ReturnElement
* re
= connection
->returnElement
;
1284 if(strcmp(re
->name
,name
)==0) return strdup(re
->value
);
1285 mpd_getNextReturnElement(connection
);
1291 char *mpd_getNextTag(mpd_Connection
*connection
, int type
)
1293 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
||
1294 type
== MPD_TAG_ITEM_ANY
)
1296 if (type
== MPD_TAG_ITEM_FILENAME
)
1297 return mpd_getNextReturnElementNamed(connection
, "file");
1298 return mpd_getNextReturnElementNamed(connection
, mpdTagItemKeys
[type
]);
1301 char * mpd_getNextArtist(mpd_Connection
* connection
) {
1302 return mpd_getNextReturnElementNamed(connection
,"Artist");
1305 char * mpd_getNextAlbum(mpd_Connection
* connection
) {
1306 return mpd_getNextReturnElementNamed(connection
,"Album");
1309 void mpd_sendPlaylistInfoCommand(mpd_Connection
* connection
, int songPos
) {
1310 int len
= strlen("playlistinfo")+2+INTLEN
+3;
1311 char *string
= malloc(len
);
1312 snprintf(string
, len
, "playlistinfo \"%i\"\n", songPos
);
1313 mpd_sendInfoCommand(connection
,string
);
1317 void mpd_sendPlaylistIdCommand(mpd_Connection
* connection
, int id
) {
1318 int len
= strlen("playlistid")+2+INTLEN
+3;
1319 char *string
= malloc(len
);
1320 snprintf(string
, len
, "playlistid \"%i\"\n", id
);
1321 mpd_sendInfoCommand(connection
, string
);
1325 void mpd_sendPlChangesCommand(mpd_Connection
* connection
, long long playlist
) {
1326 int len
= strlen("plchanges")+2+LONGLONGLEN
+3;
1327 char *string
= malloc(len
);
1328 snprintf(string
, len
, "plchanges \"%lld\"\n", playlist
);
1329 mpd_sendInfoCommand(connection
,string
);
1333 void mpd_sendPlChangesPosIdCommand(mpd_Connection
* connection
, long long playlist
) {
1334 int len
= strlen("plchangesposid")+2+LONGLONGLEN
+3;
1335 char *string
= malloc(len
);
1336 snprintf(string
, len
, "plchangesposid \"%lld\"\n", playlist
);
1337 mpd_sendInfoCommand(connection
,string
);
1341 void mpd_sendListallCommand(mpd_Connection
* connection
, const char * dir
) {
1342 char * sDir
= mpd_sanitizeArg(dir
);
1343 int len
= strlen("listall")+2+strlen(sDir
)+3;
1344 char *string
= malloc(len
);
1345 snprintf(string
, len
, "listall \"%s\"\n", sDir
);
1346 mpd_sendInfoCommand(connection
,string
);
1351 void mpd_sendListallInfoCommand(mpd_Connection
* connection
, const char * dir
) {
1352 char * sDir
= mpd_sanitizeArg(dir
);
1353 int len
= strlen("listallinfo")+2+strlen(sDir
)+3;
1354 char *string
= malloc(len
);
1355 snprintf(string
, len
, "listallinfo \"%s\"\n", sDir
);
1356 mpd_sendInfoCommand(connection
,string
);
1361 void mpd_sendLsInfoCommand(mpd_Connection
* connection
, const char * dir
) {
1362 char * sDir
= mpd_sanitizeArg(dir
);
1363 int len
= strlen("lsinfo")+2+strlen(sDir
)+3;
1364 char *string
= malloc(len
);
1365 snprintf(string
, len
, "lsinfo \"%s\"\n", sDir
);
1366 mpd_sendInfoCommand(connection
,string
);
1371 void mpd_sendCurrentSongCommand(mpd_Connection
* connection
) {
1372 mpd_executeCommand(connection
,"currentsong\n");
1375 void mpd_sendSearchCommand(mpd_Connection
* connection
, int table
,
1378 mpd_startSearch(connection
, 0);
1379 mpd_addConstraintSearch(connection
, table
, str
);
1380 mpd_commitSearch(connection
);
1383 void mpd_sendFindCommand(mpd_Connection
* connection
, int table
,
1386 mpd_startSearch(connection
, 1);
1387 mpd_addConstraintSearch(connection
, table
, str
);
1388 mpd_commitSearch(connection
);
1391 void mpd_sendListCommand(mpd_Connection
* connection
, int table
,
1397 if(table
== MPD_TABLE_ARTIST
) strcpy(st
,"artist");
1398 else if(table
== MPD_TABLE_ALBUM
) strcpy(st
,"album");
1400 connection
->error
= 1;
1401 strcpy(connection
->errorStr
,"unknown table for list");
1405 char * sanitArg1
= mpd_sanitizeArg(arg1
);
1406 len
= strlen("list")+1+strlen(sanitArg1
)+2+strlen(st
)+3;
1407 string
= malloc(len
);
1408 snprintf(string
, len
, "list %s \"%s\"\n", st
, sanitArg1
);
1412 len
= strlen("list")+1+strlen(st
)+2;
1413 string
= malloc(len
);
1414 snprintf(string
, len
, "list %s\n", st
);
1416 mpd_sendInfoCommand(connection
,string
);
1420 void mpd_sendAddCommand(mpd_Connection
* connection
, const char * file
) {
1421 char * sFile
= mpd_sanitizeArg(file
);
1422 int len
= strlen("add")+2+strlen(sFile
)+3;
1423 char *string
= malloc(len
);
1424 snprintf(string
, len
, "add \"%s\"\n", sFile
);
1425 mpd_executeCommand(connection
,string
);
1430 int mpd_sendAddIdCommand(mpd_Connection
*connection
, const char *file
)
1433 char *sFile
= mpd_sanitizeArg(file
);
1434 int len
= strlen("addid")+2+strlen(sFile
)+3;
1435 char *string
= malloc(len
);
1437 snprintf(string
, len
, "addid \"%s\"\n", sFile
);
1438 mpd_sendInfoCommand(connection
, string
);
1442 string
= mpd_getNextReturnElementNamed(connection
, "Id");
1444 retval
= atoi(string
);
1451 void mpd_sendDeleteCommand(mpd_Connection
* connection
, int songPos
) {
1452 int len
= strlen("delete")+2+INTLEN
+3;
1453 char *string
= malloc(len
);
1454 snprintf(string
, len
, "delete \"%i\"\n", songPos
);
1455 mpd_sendInfoCommand(connection
,string
);
1459 void mpd_sendDeleteIdCommand(mpd_Connection
* connection
, int id
) {
1460 int len
= strlen("deleteid")+2+INTLEN
+3;
1461 char *string
= malloc(len
);
1462 snprintf(string
, len
, "deleteid \"%i\"\n", id
);
1463 mpd_sendInfoCommand(connection
,string
);
1467 void mpd_sendSaveCommand(mpd_Connection
* connection
, const char * name
) {
1468 char * sName
= mpd_sanitizeArg(name
);
1469 int len
= strlen("save")+2+strlen(sName
)+3;
1470 char *string
= malloc(len
);
1471 snprintf(string
, len
, "save \"%s\"\n", sName
);
1472 mpd_executeCommand(connection
,string
);
1477 void mpd_sendLoadCommand(mpd_Connection
* connection
, const char * name
) {
1478 char * sName
= mpd_sanitizeArg(name
);
1479 int len
= strlen("load")+2+strlen(sName
)+3;
1480 char *string
= malloc(len
);
1481 snprintf(string
, len
, "load \"%s\"\n", sName
);
1482 mpd_executeCommand(connection
,string
);
1487 void mpd_sendRmCommand(mpd_Connection
* connection
, const char * name
) {
1488 char * sName
= mpd_sanitizeArg(name
);
1489 int len
= strlen("rm")+2+strlen(sName
)+3;
1490 char *string
= malloc(len
);
1491 snprintf(string
, len
, "rm \"%s\"\n", sName
);
1492 mpd_executeCommand(connection
,string
);
1497 void mpd_sendRenameCommand(mpd_Connection
*connection
, const char *from
,
1500 char *sFrom
= mpd_sanitizeArg(from
);
1501 char *sTo
= mpd_sanitizeArg(to
);
1502 int len
= strlen("rename")+2+strlen(sFrom
)+3+strlen(sTo
)+3;
1503 char *string
= malloc(len
);
1504 snprintf(string
, len
, "rename \"%s\" \"%s\"\n", sFrom
, sTo
);
1505 mpd_executeCommand(connection
, string
);
1511 void mpd_sendShuffleCommand(mpd_Connection
* connection
) {
1512 mpd_executeCommand(connection
,"shuffle\n");
1515 void mpd_sendClearCommand(mpd_Connection
* connection
) {
1516 mpd_executeCommand(connection
,"clear\n");
1519 void mpd_sendPlayCommand(mpd_Connection
* connection
, int songPos
) {
1520 int len
= strlen("play")+2+INTLEN
+3;
1521 char *string
= malloc(len
);
1522 snprintf(string
, len
, "play \"%i\"\n", songPos
);
1523 mpd_sendInfoCommand(connection
,string
);
1527 void mpd_sendPlayIdCommand(mpd_Connection
* connection
, int id
) {
1528 int len
= strlen("playid")+2+INTLEN
+3;
1529 char *string
= malloc(len
);
1530 snprintf(string
, len
, "playid \"%i\"\n", id
);
1531 mpd_sendInfoCommand(connection
,string
);
1535 void mpd_sendStopCommand(mpd_Connection
* connection
) {
1536 mpd_executeCommand(connection
,"stop\n");
1539 void mpd_sendPauseCommand(mpd_Connection
* connection
, int pauseMode
) {
1540 int len
= strlen("pause")+2+INTLEN
+3;
1541 char *string
= malloc(len
);
1542 snprintf(string
, len
, "pause \"%i\"\n", pauseMode
);
1543 mpd_executeCommand(connection
,string
);
1547 void mpd_sendNextCommand(mpd_Connection
* connection
) {
1548 mpd_executeCommand(connection
,"next\n");
1551 void mpd_sendMoveCommand(mpd_Connection
* connection
, int from
, int to
) {
1552 int len
= strlen("move")+2+INTLEN
+3+INTLEN
+3;
1553 char *string
= malloc(len
);
1554 snprintf(string
, len
, "move \"%i\" \"%i\"\n", from
, to
);
1555 mpd_sendInfoCommand(connection
,string
);
1559 void mpd_sendMoveIdCommand(mpd_Connection
* connection
, int id
, int to
) {
1560 int len
= strlen("moveid")+2+INTLEN
+3+INTLEN
+3;
1561 char *string
= malloc(len
);
1562 snprintf(string
, len
, "moveid \"%i\" \"%i\"\n", id
, to
);
1563 mpd_sendInfoCommand(connection
,string
);
1567 void mpd_sendSwapCommand(mpd_Connection
* connection
, int song1
, int song2
) {
1568 int len
= strlen("swap")+2+INTLEN
+3+INTLEN
+3;
1569 char *string
= malloc(len
);
1570 snprintf(string
, len
, "swap \"%i\" \"%i\"\n", song1
, song2
);
1571 mpd_sendInfoCommand(connection
,string
);
1575 void mpd_sendSwapIdCommand(mpd_Connection
* connection
, int id1
, int id2
) {
1576 int len
= strlen("swapid")+2+INTLEN
+3+INTLEN
+3;
1577 char *string
= malloc(len
);
1578 snprintf(string
, len
, "swapid \"%i\" \"%i\"\n", id1
, id2
);
1579 mpd_sendInfoCommand(connection
,string
);
1583 void mpd_sendSeekCommand(mpd_Connection
* connection
, int song
, int time
) {
1584 int len
= strlen("seek")+2+INTLEN
+3+INTLEN
+3;
1585 char *string
= malloc(len
);
1586 snprintf(string
, len
, "seek \"%i\" \"%i\"\n", song
, time
);
1587 mpd_sendInfoCommand(connection
,string
);
1591 void mpd_sendSeekIdCommand(mpd_Connection
* connection
, int id
, int time
) {
1592 int len
= strlen("seekid")+2+INTLEN
+3+INTLEN
+3;
1593 char *string
= malloc(len
);
1594 snprintf(string
, len
, "seekid \"%i\" \"%i\"\n", id
, time
);
1595 mpd_sendInfoCommand(connection
,string
);
1599 void mpd_sendUpdateCommand(mpd_Connection
* connection
, char * path
) {
1600 char * sPath
= mpd_sanitizeArg(path
);
1601 int len
= strlen("update")+2+strlen(sPath
)+3;
1602 char *string
= malloc(len
);
1603 snprintf(string
, len
, "update \"%s\"\n", sPath
);
1604 mpd_sendInfoCommand(connection
,string
);
1609 int mpd_getUpdateId(mpd_Connection
* connection
) {
1613 jobid
= mpd_getNextReturnElementNamed(connection
,"updating_db");
1622 void mpd_sendPrevCommand(mpd_Connection
* connection
) {
1623 mpd_executeCommand(connection
,"previous\n");
1626 void mpd_sendRepeatCommand(mpd_Connection
* connection
, int repeatMode
) {
1627 int len
= strlen("repeat")+2+INTLEN
+3;
1628 char *string
= malloc(len
);
1629 snprintf(string
, len
, "repeat \"%i\"\n", repeatMode
);
1630 mpd_executeCommand(connection
,string
);
1634 void mpd_sendRandomCommand(mpd_Connection
* connection
, int randomMode
) {
1635 int len
= strlen("random")+2+INTLEN
+3;
1636 char *string
= malloc(len
);
1637 snprintf(string
, len
, "random \"%i\"\n", randomMode
);
1638 mpd_executeCommand(connection
,string
);
1642 void mpd_sendSetvolCommand(mpd_Connection
* connection
, int volumeChange
) {
1643 int len
= strlen("setvol")+2+INTLEN
+3;
1644 char *string
= malloc(len
);
1645 snprintf(string
, len
, "setvol \"%i\"\n", volumeChange
);
1646 mpd_executeCommand(connection
,string
);
1650 void mpd_sendVolumeCommand(mpd_Connection
* connection
, int volumeChange
) {
1651 int len
= strlen("volume")+2+INTLEN
+3;
1652 char *string
= malloc(len
);
1653 snprintf(string
, len
, "volume \"%i\"\n", volumeChange
);
1654 mpd_executeCommand(connection
,string
);
1658 void mpd_sendCrossfadeCommand(mpd_Connection
* connection
, int seconds
) {
1659 int len
= strlen("crossfade")+2+INTLEN
+3;
1660 char *string
= malloc(len
);
1661 snprintf(string
, len
, "crossfade \"%i\"\n", seconds
);
1662 mpd_executeCommand(connection
,string
);
1666 void mpd_sendPasswordCommand(mpd_Connection
* connection
, const char * pass
) {
1667 char * sPass
= mpd_sanitizeArg(pass
);
1668 int len
= strlen("password")+2+strlen(sPass
)+3;
1669 char *string
= malloc(len
);
1670 snprintf(string
, len
, "password \"%s\"\n", sPass
);
1671 mpd_executeCommand(connection
,string
);
1676 void mpd_sendCommandListBegin(mpd_Connection
* connection
) {
1677 if(connection
->commandList
) {
1678 strcpy(connection
->errorStr
,"already in command list mode");
1679 connection
->error
= 1;
1682 connection
->commandList
= COMMAND_LIST
;
1683 mpd_executeCommand(connection
,"command_list_begin\n");
1686 void mpd_sendCommandListOkBegin(mpd_Connection
* connection
) {
1687 if(connection
->commandList
) {
1688 strcpy(connection
->errorStr
,"already in command list mode");
1689 connection
->error
= 1;
1692 connection
->commandList
= COMMAND_LIST_OK
;
1693 mpd_executeCommand(connection
,"command_list_ok_begin\n");
1694 connection
->listOks
= 0;
1697 void mpd_sendCommandListEnd(mpd_Connection
* connection
) {
1698 if(!connection
->commandList
) {
1699 strcpy(connection
->errorStr
,"not in command list mode");
1700 connection
->error
= 1;
1703 connection
->commandList
= 0;
1704 mpd_executeCommand(connection
,"command_list_end\n");
1707 void mpd_sendOutputsCommand(mpd_Connection
* connection
) {
1708 mpd_executeCommand(connection
,"outputs\n");
1711 mpd_OutputEntity
* mpd_getNextOutput(mpd_Connection
* connection
) {
1712 mpd_OutputEntity
* output
= NULL
;
1714 if(connection
->doneProcessing
|| (connection
->listOks
&&
1715 connection
->doneListOk
))
1720 if(connection
->error
) return NULL
;
1722 output
= malloc(sizeof(mpd_OutputEntity
));
1724 output
->name
= NULL
;
1725 output
->enabled
= 0;
1727 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
1729 while(connection
->returnElement
) {
1730 mpd_ReturnElement
* re
= connection
->returnElement
;
1731 if(strcmp(re
->name
,"outputid")==0) {
1732 if(output
!=NULL
&& output
->id
>=0) return output
;
1733 output
->id
= atoi(re
->value
);
1735 else if(strcmp(re
->name
,"outputname")==0) {
1736 output
->name
= strdup(re
->value
);
1738 else if(strcmp(re
->name
,"outputenabled")==0) {
1739 output
->enabled
= atoi(re
->value
);
1742 mpd_getNextReturnElement(connection
);
1743 if(connection
->error
) {
1753 void mpd_sendEnableOutputCommand(mpd_Connection
* connection
, int outputId
) {
1754 int len
= strlen("enableoutput")+2+INTLEN
+3;
1755 char *string
= malloc(len
);
1756 snprintf(string
, len
, "enableoutput \"%i\"\n", outputId
);
1757 mpd_executeCommand(connection
,string
);
1761 void mpd_sendDisableOutputCommand(mpd_Connection
* connection
, int outputId
) {
1762 int len
= strlen("disableoutput")+2+INTLEN
+3;
1763 char *string
= malloc(len
);
1764 snprintf(string
, len
, "disableoutput \"%i\"\n", outputId
);
1765 mpd_executeCommand(connection
,string
);
1769 void mpd_freeOutputElement(mpd_OutputEntity
* output
) {
1775 * mpd_sendNotCommandsCommand
1776 * odd naming, but it gets the not allowed commands
1779 void mpd_sendNotCommandsCommand(mpd_Connection
* connection
)
1781 mpd_executeCommand(connection
, "notcommands\n");
1785 * mpd_sendCommandsCommand
1786 * odd naming, but it gets the allowed commands
1788 void mpd_sendCommandsCommand(mpd_Connection
* connection
)
1790 mpd_executeCommand(connection
, "commands\n");
1794 * Get the next returned command
1796 char * mpd_getNextCommand(mpd_Connection
* connection
)
1798 return mpd_getNextReturnElementNamed(connection
, "command");
1801 void mpd_sendUrlHandlersCommand(mpd_Connection
* connection
)
1803 mpd_executeCommand(connection
, "urlhandlers\n");
1806 char * mpd_getNextHandler(mpd_Connection
* connection
)
1808 return mpd_getNextReturnElementNamed(connection
, "handler");
1811 void mpd_sendTagTypesCommand(mpd_Connection
* connection
)
1813 mpd_executeCommand(connection
, "tagtypes\n");
1816 char * mpd_getNextTagType(mpd_Connection
* connection
)
1818 return mpd_getNextReturnElementNamed(connection
, "tagtype");
1821 void mpd_startSearch(mpd_Connection
*connection
, int exact
)
1823 if (connection
->request
) {
1824 strcpy(connection
->errorStr
, "search already in progress");
1825 connection
->error
= 1;
1829 if (exact
) connection
->request
= strdup("find");
1830 else connection
->request
= strdup("search");
1833 void mpd_startStatsSearch(mpd_Connection
*connection
)
1835 if (connection
->request
) {
1836 strcpy(connection
->errorStr
, "search already in progress");
1837 connection
->error
= 1;
1841 connection
->request
= strdup("count");
1844 void mpd_startPlaylistSearch(mpd_Connection
*connection
, int exact
)
1846 if (connection
->request
) {
1847 strcpy(connection
->errorStr
, "search already in progress");
1848 connection
->error
= 1;
1852 if (exact
) connection
->request
= strdup("playlistfind");
1853 else connection
->request
= strdup("playlistsearch");
1856 void mpd_startFieldSearch(mpd_Connection
*connection
, int type
)
1861 if (connection
->request
) {
1862 strcpy(connection
->errorStr
, "search already in progress");
1863 connection
->error
= 1;
1867 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1868 strcpy(connection
->errorStr
, "invalid type specified");
1869 connection
->error
= 1;
1873 strtype
= mpdTagItemKeys
[type
];
1875 len
= 5+strlen(strtype
)+1;
1876 connection
->request
= malloc(len
);
1878 snprintf(connection
->request
, len
, "list %c%s",
1879 tolower(strtype
[0]), strtype
+1);
1882 void mpd_addConstraintSearch(mpd_Connection
*connection
, int type
, const char *name
)
1889 if (!connection
->request
) {
1890 strcpy(connection
->errorStr
, "no search in progress");
1891 connection
->error
= 1;
1895 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1896 strcpy(connection
->errorStr
, "invalid type specified");
1897 connection
->error
= 1;
1902 strcpy(connection
->errorStr
, "no name specified");
1903 connection
->error
= 1;
1907 string
= strdup(connection
->request
);
1908 strtype
= mpdTagItemKeys
[type
];
1909 arg
= mpd_sanitizeArg(name
);
1911 len
= strlen(string
)+1+strlen(strtype
)+2+strlen(arg
)+2;
1912 connection
->request
= realloc(connection
->request
, len
);
1913 snprintf(connection
->request
, len
, "%s %c%s \"%s\"",
1914 string
, tolower(strtype
[0]), strtype
+1, arg
);
1920 void mpd_commitSearch(mpd_Connection
*connection
)
1924 if (!connection
->request
) {
1925 strcpy(connection
->errorStr
, "no search in progress");
1926 connection
->error
= 1;
1930 len
= strlen(connection
->request
)+2;
1931 connection
->request
= realloc(connection
->request
, len
);
1932 connection
->request
[len
-2] = '\n';
1933 connection
->request
[len
-1] = '\0';
1934 mpd_sendInfoCommand(connection
, connection
->request
);
1936 free(connection
->request
);
1937 connection
->request
= NULL
;
1941 * @param connection a MpdConnection
1942 * @param path the path to the playlist.
1944 * List the content, with full metadata, of a stored playlist.
1947 void mpd_sendListPlaylistInfoCommand(mpd_Connection
*connection
, char *path
)
1949 char *arg
= mpd_sanitizeArg(path
);
1950 int len
= strlen("listplaylistinfo")+2+strlen(arg
)+3;
1951 char *query
= malloc(len
);
1952 snprintf(query
, len
, "listplaylistinfo \"%s\"\n", arg
);
1953 mpd_sendInfoCommand(connection
, query
);
1959 * @param connection a MpdConnection
1960 * @param path the path to the playlist.
1962 * List the content of a stored playlist.
1965 void mpd_sendListPlaylistCommand(mpd_Connection
*connection
, char *path
)
1967 char *arg
= mpd_sanitizeArg(path
);
1968 int len
= strlen("listplaylist")+2+strlen(arg
)+3;
1969 char *query
= malloc(len
);
1970 snprintf(query
, len
, "listplaylist \"%s\"\n", arg
);
1971 mpd_sendInfoCommand(connection
, query
);
1976 void mpd_sendPlaylistClearCommand(mpd_Connection
*connection
, char *path
)
1978 char *sPath
= mpd_sanitizeArg(path
);
1979 int len
= strlen("playlistclear")+2+strlen(sPath
)+3;
1980 char *string
= malloc(len
);
1981 snprintf(string
, len
, "playlistclear \"%s\"\n", sPath
);
1982 mpd_executeCommand(connection
, string
);
1987 void mpd_sendPlaylistAddCommand(mpd_Connection
*connection
,
1988 char *playlist
, char *path
)
1990 char *sPlaylist
= mpd_sanitizeArg(playlist
);
1991 char *sPath
= mpd_sanitizeArg(path
);
1992 int len
= strlen("playlistadd")+2+strlen(sPlaylist
)+3+strlen(sPath
)+3;
1993 char *string
= malloc(len
);
1994 snprintf(string
, len
, "playlistadd \"%s\" \"%s\"\n", sPlaylist
, sPath
);
1995 mpd_executeCommand(connection
, string
);
2001 void mpd_sendPlaylistMoveCommand(mpd_Connection
*connection
,
2002 char *playlist
, int from
, int to
)
2004 char *sPlaylist
= mpd_sanitizeArg(playlist
);
2005 int len
= strlen("playlistmove")+
2006 2+strlen(sPlaylist
)+3+INTLEN
+3+INTLEN
+3;
2007 char *string
= malloc(len
);
2008 snprintf(string
, len
, "playlistmove \"%s\" \"%i\" \"%i\"\n",
2009 sPlaylist
, from
, to
);
2010 mpd_executeCommand(connection
, string
);
2015 void mpd_sendPlaylistDeleteCommand(mpd_Connection
*connection
,
2016 char *playlist
, int pos
)
2018 char *sPlaylist
= mpd_sanitizeArg(playlist
);
2019 int len
= strlen("playlistdelete")+2+strlen(sPlaylist
)+3+INTLEN
+3;
2020 char *string
= malloc(len
);
2021 snprintf(string
, len
, "playlistdelete \"%s\" \"%i\"\n", sPlaylist
, pos
);
2022 mpd_executeCommand(connection
, string
);