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
] =
277 static char * mpd_sanitizeArg(const char * arg
) {
280 register const char *c
;
283 /* instead of counting in that loop above, just
284 * use a bit more memory and half running time
286 ret
= malloc(strlen(arg
) * 2 + 1);
290 for(i
= strlen(arg
)+1; i
!= 0; --i
) {
291 if(*c
=='"' || *c
=='\\')
299 static mpd_ReturnElement
* mpd_newReturnElement(const char * name
, const char * value
)
301 mpd_ReturnElement
* ret
= malloc(sizeof(mpd_ReturnElement
));
303 ret
->name
= strdup(name
);
304 ret
->value
= strdup(value
);
309 static void mpd_freeReturnElement(mpd_ReturnElement
* re
) {
315 void mpd_setConnectionTimeout(mpd_Connection
* connection
, float timeout
) {
316 connection
->timeout
.tv_sec
= (int)timeout
;
317 connection
->timeout
.tv_usec
= (int)(timeout
*1e6
-
318 connection
->timeout
.tv_sec
*1000000 +
322 static int mpd_parseWelcome(mpd_Connection
* connection
, const char * host
, int port
,
328 if(strncmp(output
,MPD_WELCOME_MESSAGE
,strlen(MPD_WELCOME_MESSAGE
))) {
329 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
330 "mpd not running on port %i on host \"%s\"",
332 connection
->error
= MPD_ERROR_NOTMPD
;
336 tmp
= &output
[strlen(MPD_WELCOME_MESSAGE
)];
339 if(tmp
) connection
->version
[i
] = strtol(tmp
,&test
,10);
341 if (!tmp
|| (test
[0] != '.' && test
[0] != '\0')) {
342 snprintf(connection
->errorStr
,
343 MPD_ERRORSTR_MAX_LENGTH
,
344 "error parsing version number at "
346 &output
[strlen(MPD_WELCOME_MESSAGE
)]);
347 connection
->error
= MPD_ERROR_NOTMPD
;
357 static int mpd_connect_un(mpd_Connection
* connection
,
358 const char * host
, float timeout
)
362 struct sockaddr_un saun
;
364 path_length
= strlen(host
);
365 if (path_length
>= sizeof(saun
.sun_path
)) {
366 strcpy(connection
->errorStr
, "unix socket path is too long");
367 connection
->error
= MPD_ERROR_UNKHOST
;
371 saun
.sun_family
= AF_UNIX
;
372 memcpy(saun
.sun_path
, host
, path_length
+ 1);
374 connection
->sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
375 if (connection
->sock
< 0) {
376 strcpy(connection
->errorStr
, "problems creating socket");
377 connection
->error
= MPD_ERROR_SYSTEM
;
381 mpd_setConnectionTimeout(connection
, timeout
);
383 flags
= fcntl(connection
->sock
, F_GETFL
, 0);
384 fcntl(connection
->sock
, F_SETFL
, flags
| O_NONBLOCK
);
386 error
= connect(connection
->sock
, (struct sockaddr
*)&saun
, sizeof(saun
));
388 /* try the next address family */
389 close(connection
->sock
);
390 connection
->sock
= 0;
392 snprintf(connection
->errorStr
,MPD_BUFFER_MAX_LENGTH
,
393 "problems connecting to \"%s\": %s",
394 host
, strerror(errno
));
395 connection
->error
= MPD_ERROR_CONNPORT
;
403 mpd_Connection
* mpd_newConnection(const char * host
, int port
, float timeout
) {
406 char * output
= NULL
;
407 mpd_Connection
* connection
= malloc(sizeof(mpd_Connection
));
410 strcpy(connection
->buffer
,"");
411 connection
->sock
= -1;
412 connection
->buflen
= 0;
413 connection
->bufstart
= 0;
414 strcpy(connection
->errorStr
,"");
415 connection
->error
= 0;
416 connection
->doneProcessing
= 0;
417 connection
->commandList
= 0;
418 connection
->listOks
= 0;
419 connection
->doneListOk
= 0;
420 connection
->returnElement
= NULL
;
421 connection
->request
= NULL
;
423 if (winsock_dll_error(connection
))
428 err
= mpd_connect_un(connection
, host
, timeout
);
431 err
= mpd_connect(connection
, host
, port
, timeout
);
435 while(!(rt
= strstr(connection
->buffer
,"\n"))) {
436 tv
.tv_sec
= connection
->timeout
.tv_sec
;
437 tv
.tv_usec
= connection
->timeout
.tv_usec
;
439 FD_SET(connection
->sock
,&fds
);
440 if((err
= select(connection
->sock
+1,&fds
,NULL
,NULL
,&tv
)) == 1) {
442 readed
= recv(connection
->sock
,
443 &(connection
->buffer
[connection
->buflen
]),
444 MPD_BUFFER_MAX_LENGTH
-connection
->buflen
,0);
446 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
447 "problems getting a response from"
448 " \"%s\" on port %i : %s",host
,
449 port
, strerror(errno
));
450 connection
->error
= MPD_ERROR_NORESPONSE
;
453 connection
->buflen
+=readed
;
454 connection
->buffer
[connection
->buflen
] = '\0';
457 if (SELECT_ERRNO_IGNORE
)
459 snprintf(connection
->errorStr
,
460 MPD_ERRORSTR_MAX_LENGTH
,
461 "problems connecting to \"%s\" on port"
463 connection
->error
= MPD_ERROR_CONNPORT
;
467 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
468 "timeout in attempting to get a response from"
469 " \"%s\" on port %i",host
,port
);
470 connection
->error
= MPD_ERROR_NORESPONSE
;
476 output
= strdup(connection
->buffer
);
477 strcpy(connection
->buffer
,rt
+1);
478 connection
->buflen
= strlen(connection
->buffer
);
480 if(mpd_parseWelcome(connection
,host
,port
,output
) == 0) connection
->doneProcessing
= 1;
487 void mpd_clearError(mpd_Connection
* connection
) {
488 connection
->error
= 0;
489 connection
->errorStr
[0] = '\0';
492 void mpd_closeConnection(mpd_Connection
* connection
) {
493 closesocket(connection
->sock
);
494 if(connection
->returnElement
) free(connection
->returnElement
);
495 if(connection
->request
) free(connection
->request
);
500 static void mpd_executeCommand(mpd_Connection
* connection
,const char * command
) {
504 const char * commandPtr
= command
;
505 int commandLen
= strlen(command
);
507 if(!connection
->doneProcessing
&& !connection
->commandList
) {
508 strcpy(connection
->errorStr
,"not done processing current command");
509 connection
->error
= 1;
513 mpd_clearError(connection
);
516 FD_SET(connection
->sock
,&fds
);
517 tv
.tv_sec
= connection
->timeout
.tv_sec
;
518 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
)) {
522 ret
= send(connection
->sock
,commandPtr
,commandLen
,MSG_DONTWAIT
);
525 if (SENDRECV_ERRNO_IGNORE
) continue;
526 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
527 "problems giving command \"%s\"",command
);
528 connection
->error
= MPD_ERROR_SENDING
;
536 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
->storedplaylist
= -1;
744 status
->playlistLength
= -1;
748 status
->nextsong
= -1;
749 status
->nextsongid
= -1;
750 status
->elapsedTime
= 0;
751 status
->totalTime
= 0;
753 status
->sampleRate
= 0;
755 status
->channels
= 0;
756 status
->crossfade
= -1;
757 status
->error
= NULL
;
758 status
->updatingDb
= 0;
760 if(connection
->error
) {
764 while(connection
->returnElement
) {
765 mpd_ReturnElement
* re
= connection
->returnElement
;
766 if(strcmp(re
->name
,"volume")==0) {
767 status
->volume
= atoi(re
->value
);
769 else if(strcmp(re
->name
,"repeat")==0) {
770 status
->repeat
= atoi(re
->value
);
772 else if(strcmp(re
->name
,"random")==0) {
773 status
->random
= atoi(re
->value
);
775 else if(strcmp(re
->name
,"playlist")==0) {
776 status
->playlist
= strtol(re
->value
,NULL
,10);
778 else if(strcmp(re
->name
,"playlistlength")==0) {
779 status
->playlistLength
= atoi(re
->value
);
781 else if(strcmp(re
->name
,"bitrate")==0) {
782 status
->bitRate
= atoi(re
->value
);
784 else if(strcmp(re
->name
,"state")==0) {
785 if(strcmp(re
->value
,"play")==0) {
786 status
->state
= MPD_STATUS_STATE_PLAY
;
788 else if(strcmp(re
->value
,"stop")==0) {
789 status
->state
= MPD_STATUS_STATE_STOP
;
791 else if(strcmp(re
->value
,"pause")==0) {
792 status
->state
= MPD_STATUS_STATE_PAUSE
;
795 status
->state
= MPD_STATUS_STATE_UNKNOWN
;
798 else if(strcmp(re
->name
,"song")==0) {
799 status
->song
= atoi(re
->value
);
801 else if(strcmp(re
->name
,"songid")==0) {
802 status
->songid
= atoi(re
->value
);
804 else if(strcmp(re
->name
,"nextsong")==0) {
805 status
->nextsong
= atoi(re
->value
);
807 else if(strcmp(re
->name
,"nextsongid")==0) {
808 status
->nextsongid
= atoi(re
->value
);
810 else if(strcmp(re
->name
,"time")==0) {
811 char * tok
= strchr(re
->value
,':');
812 /* the second strchr below is a safety check */
813 if (tok
&& (strchr(tok
,0) > (tok
+1))) {
814 /* atoi stops at the first non-[0-9] char: */
815 status
->elapsedTime
= atoi(re
->value
);
816 status
->totalTime
= atoi(tok
+1);
819 else if(strcmp(re
->name
,"error")==0) {
820 status
->error
= strdup(re
->value
);
822 else if(strcmp(re
->name
,"xfade")==0) {
823 status
->crossfade
= atoi(re
->value
);
825 else if(strcmp(re
->name
,"updating_db")==0) {
826 status
->updatingDb
= atoi(re
->value
);
828 else if(strcmp(re
->name
,"audio")==0) {
829 char * tok
= strchr(re
->value
,':');
830 if (tok
&& (strchr(tok
,0) > (tok
+1))) {
831 status
->sampleRate
= atoi(re
->value
);
832 status
->bits
= atoi(++tok
);
833 tok
= strchr(tok
,':');
834 if (tok
&& (strchr(tok
,0) > (tok
+1)))
835 status
->channels
= atoi(tok
+1);
839 mpd_getNextReturnElement(connection
);
840 if(connection
->error
) {
846 if(connection
->error
) {
850 else if(status
->state
<0) {
851 strcpy(connection
->errorStr
,"state not found");
852 connection
->error
= 1;
860 void mpd_freeStatus(mpd_Status
* status
) {
861 if(status
->error
) free(status
->error
);
865 void mpd_sendStatsCommand(mpd_Connection
* connection
) {
866 mpd_executeCommand(connection
,"stats\n");
869 mpd_Stats
* mpd_getStats(mpd_Connection
* connection
) {
872 /*mpd_executeCommand(connection,"stats\n");
874 if(connection->error) return NULL;*/
876 if(connection
->doneProcessing
|| (connection
->listOks
&&
877 connection
->doneListOk
))
882 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
884 stats
= malloc(sizeof(mpd_Stats
));
885 stats
->numberOfArtists
= 0;
886 stats
->numberOfAlbums
= 0;
887 stats
->numberOfSongs
= 0;
889 stats
->dbUpdateTime
= 0;
891 stats
->dbPlayTime
= 0;
893 if(connection
->error
) {
897 while(connection
->returnElement
) {
898 mpd_ReturnElement
* re
= connection
->returnElement
;
899 if(strcmp(re
->name
,"artists")==0) {
900 stats
->numberOfArtists
= atoi(re
->value
);
902 else if(strcmp(re
->name
,"albums")==0) {
903 stats
->numberOfAlbums
= atoi(re
->value
);
905 else if(strcmp(re
->name
,"songs")==0) {
906 stats
->numberOfSongs
= atoi(re
->value
);
908 else if(strcmp(re
->name
,"uptime")==0) {
909 stats
->uptime
= strtol(re
->value
,NULL
,10);
911 else if(strcmp(re
->name
,"db_update")==0) {
912 stats
->dbUpdateTime
= strtol(re
->value
,NULL
,10);
914 else if(strcmp(re
->name
,"playtime")==0) {
915 stats
->playTime
= strtol(re
->value
,NULL
,10);
917 else if(strcmp(re
->name
,"db_playtime")==0) {
918 stats
->dbPlayTime
= strtol(re
->value
,NULL
,10);
921 mpd_getNextReturnElement(connection
);
922 if(connection
->error
) {
928 if(connection
->error
) {
936 void mpd_freeStats(mpd_Stats
* stats
) {
940 mpd_SearchStats
* mpd_getSearchStats(mpd_Connection
* connection
)
942 mpd_SearchStats
* stats
;
943 mpd_ReturnElement
* re
;
945 if (connection
->doneProcessing
||
946 (connection
->listOks
&& connection
->doneListOk
)) {
950 if (!connection
->returnElement
) mpd_getNextReturnElement(connection
);
952 if (connection
->error
)
955 stats
= malloc(sizeof(mpd_SearchStats
));
956 stats
->numberOfSongs
= 0;
959 while (connection
->returnElement
) {
960 re
= connection
->returnElement
;
962 if (strcmp(re
->name
, "songs") == 0) {
963 stats
->numberOfSongs
= atoi(re
->value
);
964 } else if (strcmp(re
->name
, "playtime") == 0) {
965 stats
->playTime
= strtol(re
->value
, NULL
, 10);
968 mpd_getNextReturnElement(connection
);
969 if (connection
->error
) {
975 if (connection
->error
) {
983 void mpd_freeSearchStats(mpd_SearchStats
* stats
)
988 static void mpd_initSong(mpd_Song
* song
) {
998 song
->composer
= NULL
;
999 song
->performer
= NULL
;
1001 song
->comment
= NULL
;
1002 song
->albumartist
= NULL
;
1004 song
->time
= MPD_SONG_NO_TIME
;
1005 song
->pos
= MPD_SONG_NO_NUM
;
1006 song
->id
= MPD_SONG_NO_ID
;
1009 static void mpd_finishSong(mpd_Song
* song
) {
1010 if(song
->file
) free(song
->file
);
1011 if(song
->artist
) free(song
->artist
);
1012 if(song
->album
) free(song
->album
);
1013 if(song
->title
) free(song
->title
);
1014 if(song
->track
) free(song
->track
);
1015 if(song
->name
) free(song
->name
);
1016 if(song
->date
) free(song
->date
);
1017 if(song
->genre
) free(song
->genre
);
1018 if(song
->composer
) free(song
->composer
);
1019 if(song
->performer
) free(song
->performer
);
1020 if(song
->disc
) free(song
->disc
);
1021 if(song
->comment
) free(song
->comment
);
1022 if(song
->albumartist
) free(song
->albumartist
);
1025 mpd_Song
* mpd_newSong(void) {
1026 mpd_Song
* ret
= malloc(sizeof(mpd_Song
));
1033 void mpd_freeSong(mpd_Song
* song
) {
1034 mpd_finishSong(song
);
1038 mpd_Song
* mpd_songDup(const mpd_Song
* song
) {
1039 mpd_Song
* ret
= mpd_newSong();
1041 if(song
->file
) ret
->file
= strdup(song
->file
);
1042 if(song
->artist
) ret
->artist
= strdup(song
->artist
);
1043 if(song
->album
) ret
->album
= strdup(song
->album
);
1044 if(song
->title
) ret
->title
= strdup(song
->title
);
1045 if(song
->track
) ret
->track
= strdup(song
->track
);
1046 if(song
->name
) ret
->name
= strdup(song
->name
);
1047 if(song
->date
) ret
->date
= strdup(song
->date
);
1048 if(song
->genre
) ret
->genre
= strdup(song
->genre
);
1049 if(song
->composer
) ret
->composer
= strdup(song
->composer
);
1050 if(song
->performer
) ret
->performer
= strdup(song
->performer
);
1051 if(song
->disc
) ret
->disc
= strdup(song
->disc
);
1052 if(song
->comment
) ret
->comment
= strdup(song
->comment
);
1053 if(song
->albumartist
) ret
->albumartist
= strdup(song
->albumartist
);
1054 ret
->time
= song
->time
;
1055 ret
->pos
= song
->pos
;
1061 static void mpd_initDirectory(mpd_Directory
* directory
) {
1062 directory
->path
= NULL
;
1065 static void mpd_finishDirectory(mpd_Directory
* directory
) {
1066 if(directory
->path
) free(directory
->path
);
1069 mpd_Directory
* mpd_newDirectory(void) {
1070 mpd_Directory
* directory
= malloc(sizeof(mpd_Directory
));;
1072 mpd_initDirectory(directory
);
1077 void mpd_freeDirectory(mpd_Directory
* directory
) {
1078 mpd_finishDirectory(directory
);
1083 mpd_Directory
* mpd_directoryDup(mpd_Directory
* directory
) {
1084 mpd_Directory
* ret
= mpd_newDirectory();
1086 if(directory
->path
) ret
->path
= strdup(directory
->path
);
1091 static void mpd_initPlaylistFile(mpd_PlaylistFile
* playlist
) {
1092 playlist
->path
= NULL
;
1093 playlist
->mtime
= NULL
;
1096 static void mpd_finishPlaylistFile(mpd_PlaylistFile
* playlist
) {
1097 if(playlist
->path
) free(playlist
->path
);
1098 if(playlist
->mtime
) free(playlist
->mtime
);
1101 mpd_PlaylistFile
* mpd_newPlaylistFile(void) {
1102 mpd_PlaylistFile
* playlist
= malloc(sizeof(mpd_PlaylistFile
));
1104 mpd_initPlaylistFile(playlist
);
1109 void mpd_freePlaylistFile(mpd_PlaylistFile
* playlist
) {
1110 mpd_finishPlaylistFile(playlist
);
1114 mpd_PlaylistFile
* mpd_playlistFileDup(mpd_PlaylistFile
* playlist
) {
1115 mpd_PlaylistFile
* ret
= mpd_newPlaylistFile();
1117 if(playlist
->path
) ret
->path
= strdup(playlist
->path
);
1118 if(playlist
->mtime
) ret
->mtime
= strdup(playlist
->mtime
);
1123 static void mpd_initInfoEntity(mpd_InfoEntity
* entity
) {
1124 entity
->info
.directory
= NULL
;
1127 static void mpd_finishInfoEntity(mpd_InfoEntity
* entity
) {
1128 if(entity
->info
.directory
) {
1129 if(entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1130 mpd_freeDirectory(entity
->info
.directory
);
1132 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
) {
1133 mpd_freeSong(entity
->info
.song
);
1135 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1136 mpd_freePlaylistFile(entity
->info
.playlistFile
);
1141 mpd_InfoEntity
* mpd_newInfoEntity(void) {
1142 mpd_InfoEntity
* entity
= malloc(sizeof(mpd_InfoEntity
));
1144 mpd_initInfoEntity(entity
);
1149 void mpd_freeInfoEntity(mpd_InfoEntity
* entity
) {
1150 mpd_finishInfoEntity(entity
);
1154 static void mpd_sendInfoCommand(mpd_Connection
* connection
,const char * command
) {
1155 mpd_executeCommand(connection
,command
);
1158 mpd_InfoEntity
* mpd_getNextInfoEntity(mpd_Connection
* connection
) {
1159 mpd_InfoEntity
* entity
= NULL
;
1161 if(connection
->doneProcessing
|| (connection
->listOks
&&
1162 connection
->doneListOk
))
1167 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
1169 if(connection
->returnElement
) {
1170 if(strcmp(connection
->returnElement
->name
,"file")==0) {
1171 entity
= mpd_newInfoEntity();
1172 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1173 entity
->info
.song
= mpd_newSong();
1174 entity
->info
.song
->file
=
1175 strdup(connection
->returnElement
->value
);
1177 else if(strcmp(connection
->returnElement
->name
,
1179 entity
= mpd_newInfoEntity();
1180 entity
->type
= MPD_INFO_ENTITY_TYPE_DIRECTORY
;
1181 entity
->info
.directory
= mpd_newDirectory();
1182 entity
->info
.directory
->path
=
1183 strdup(connection
->returnElement
->value
);
1185 else if(strcmp(connection
->returnElement
->name
,"playlist")==0) {
1186 entity
= mpd_newInfoEntity();
1187 entity
->type
= MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
;
1188 entity
->info
.playlistFile
= mpd_newPlaylistFile();
1189 entity
->info
.playlistFile
->path
=
1190 strdup(connection
->returnElement
->value
);
1192 else if(strcmp(connection
->returnElement
->name
, "cpos") == 0){
1193 entity
= mpd_newInfoEntity();
1194 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1195 entity
->info
.song
= mpd_newSong();
1196 entity
->info
.song
->pos
= atoi(connection
->returnElement
->value
);
1199 connection
->error
= 1;
1200 strcpy(connection
->errorStr
,"problem parsing song info");
1206 mpd_getNextReturnElement(connection
);
1207 while(connection
->returnElement
) {
1208 mpd_ReturnElement
* re
= connection
->returnElement
;
1210 if(strcmp(re
->name
,"file")==0) return entity
;
1211 else if(strcmp(re
->name
,"directory")==0) return entity
;
1212 else if(strcmp(re
->name
,"playlist")==0) return entity
;
1213 else if(strcmp(re
->name
,"cpos")==0) return entity
;
1215 if(entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
&&
1216 strlen(re
->value
)) {
1217 if(strcmp(re
->name
,"Artist")==0) {
1218 if(entity
->info
.song
->artist
) {
1219 int length
= strlen(entity
->info
.song
->artist
);
1220 entity
->info
.song
->artist
= realloc(entity
->info
.song
->artist
,
1221 length
+ strlen(re
->value
) + 3);
1222 strcpy(&((entity
->info
.song
->artist
)[length
]), ", ");
1223 strcpy(&((entity
->info
.song
->artist
)[length
+ 2]), re
->value
);
1226 entity
->info
.song
->artist
= strdup(re
->value
);
1229 else if(!entity
->info
.song
->album
&&
1230 strcmp(re
->name
,"Album")==0) {
1231 entity
->info
.song
->album
= strdup(re
->value
);
1233 else if(!entity
->info
.song
->title
&&
1234 strcmp(re
->name
,"Title")==0) {
1235 entity
->info
.song
->title
= strdup(re
->value
);
1237 else if(!entity
->info
.song
->track
&&
1238 strcmp(re
->name
,"Track")==0) {
1239 entity
->info
.song
->track
= strdup(re
->value
);
1241 else if(!entity
->info
.song
->name
&&
1242 strcmp(re
->name
,"Name")==0) {
1243 entity
->info
.song
->name
= strdup(re
->value
);
1245 else if(entity
->info
.song
->time
==MPD_SONG_NO_TIME
&&
1246 strcmp(re
->name
,"Time")==0) {
1247 entity
->info
.song
->time
= atoi(re
->value
);
1249 else if(entity
->info
.song
->pos
==MPD_SONG_NO_NUM
&&
1250 strcmp(re
->name
,"Pos")==0) {
1251 entity
->info
.song
->pos
= atoi(re
->value
);
1253 else if(entity
->info
.song
->id
==MPD_SONG_NO_ID
&&
1254 strcmp(re
->name
,"Id")==0) {
1255 entity
->info
.song
->id
= atoi(re
->value
);
1257 else if(!entity
->info
.song
->date
&&
1258 strcmp(re
->name
, "Date") == 0) {
1259 entity
->info
.song
->date
= strdup(re
->value
);
1261 else if(!entity
->info
.song
->genre
&&
1262 strcmp(re
->name
, "Genre") == 0) {
1263 if(entity
->info
.song
->genre
) {
1264 int length
= strlen(entity
->info
.song
->genre
);
1265 entity
->info
.song
->genre
= realloc(entity
->info
.song
->genre
,
1266 length
+ strlen(re
->value
) + 4);
1267 strcpy(&((entity
->info
.song
->genre
)[length
]), ", ");
1268 strcpy(&((entity
->info
.song
->genre
)[length
+ 3]), re
->value
);
1271 entity
->info
.song
->genre
= strdup(re
->value
);
1274 else if(strcmp(re
->name
, "Composer") == 0) {
1275 if(entity
->info
.song
->composer
) {
1276 int length
= strlen(entity
->info
.song
->composer
);
1277 entity
->info
.song
->composer
= realloc(entity
->info
.song
->composer
,
1278 length
+ strlen(re
->value
) + 3);
1279 strcpy(&((entity
->info
.song
->composer
)[length
]), ", ");
1280 strcpy(&((entity
->info
.song
->composer
)[length
+ 2]), re
->value
);
1283 entity
->info
.song
->composer
= strdup(re
->value
);
1286 else if(strcmp(re
->name
, "Performer") == 0) {
1287 if(entity
->info
.song
->performer
) {
1288 int length
= strlen(entity
->info
.song
->performer
);
1289 entity
->info
.song
->performer
= realloc(entity
->info
.song
->performer
,
1290 length
+ strlen(re
->value
) + 3);
1291 strcpy(&((entity
->info
.song
->performer
)[length
]), ", ");
1292 strcpy(&((entity
->info
.song
->performer
)[length
+ 2]), re
->value
);
1295 entity
->info
.song
->performer
= strdup(re
->value
);
1298 else if(!entity
->info
.song
->disc
&&
1299 strcmp(re
->name
, "Disc") == 0) {
1300 entity
->info
.song
->disc
= strdup(re
->value
);
1302 else if(!entity
->info
.song
->comment
&&
1303 strcmp(re
->name
, "Comment") == 0) {
1304 entity
->info
.song
->comment
= strdup(re
->value
);
1307 else if(!entity
->info
.song
->albumartist
&&
1308 strcmp(re
->name
, "AlbumArtist") == 0) {
1309 entity
->info
.song
->albumartist
= strdup(re
->value
);
1312 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1314 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1315 if(!entity
->info
.playlistFile
->mtime
&&
1316 strcmp(re
->name
, "Last-Modified") == 0) {
1317 entity
->info
.playlistFile
->mtime
= strdup(re
->value
);
1321 mpd_getNextReturnElement(connection
);
1327 static char * mpd_getNextReturnElementNamed(mpd_Connection
* connection
,
1330 if(connection
->doneProcessing
|| (connection
->listOks
&&
1331 connection
->doneListOk
))
1336 mpd_getNextReturnElement(connection
);
1337 while(connection
->returnElement
) {
1338 mpd_ReturnElement
* re
= connection
->returnElement
;
1340 if(strcmp(re
->name
,name
)==0) return strdup(re
->value
);
1341 mpd_getNextReturnElement(connection
);
1347 char *mpd_getNextTag(mpd_Connection
*connection
, int type
)
1349 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
||
1350 type
== MPD_TAG_ITEM_ANY
)
1352 if (type
== MPD_TAG_ITEM_FILENAME
)
1353 return mpd_getNextReturnElementNamed(connection
, "file");
1354 return mpd_getNextReturnElementNamed(connection
, mpdTagItemKeys
[type
]);
1357 char * mpd_getNextArtist(mpd_Connection
* connection
) {
1358 return mpd_getNextReturnElementNamed(connection
,"Artist");
1361 char * mpd_getNextAlbum(mpd_Connection
* connection
) {
1362 return mpd_getNextReturnElementNamed(connection
,"Album");
1365 void mpd_sendPlaylistInfoCommand(mpd_Connection
* connection
, int songPos
) {
1366 int len
= strlen("playlistinfo")+2+INTLEN
+3;
1367 char *string
= malloc(len
);
1368 snprintf(string
, len
, "playlistinfo \"%i\"\n", songPos
);
1369 mpd_sendInfoCommand(connection
,string
);
1373 void mpd_sendPlaylistIdCommand(mpd_Connection
* connection
, int id
) {
1374 int len
= strlen("playlistid")+2+INTLEN
+3;
1375 char *string
= malloc(len
);
1376 snprintf(string
, len
, "playlistid \"%i\"\n", id
);
1377 mpd_sendInfoCommand(connection
, string
);
1381 void mpd_sendPlChangesCommand(mpd_Connection
* connection
, long long playlist
) {
1382 int len
= strlen("plchanges")+2+LONGLONGLEN
+3;
1383 char *string
= malloc(len
);
1384 snprintf(string
, len
, "plchanges \"%lld\"\n", playlist
);
1385 mpd_sendInfoCommand(connection
,string
);
1389 void mpd_sendPlChangesPosIdCommand(mpd_Connection
* connection
, long long playlist
) {
1390 int len
= strlen("plchangesposid")+2+LONGLONGLEN
+3;
1391 char *string
= malloc(len
);
1392 snprintf(string
, len
, "plchangesposid \"%lld\"\n", playlist
);
1393 mpd_sendInfoCommand(connection
,string
);
1397 void mpd_sendListallCommand(mpd_Connection
* connection
, const char * dir
) {
1398 char * sDir
= mpd_sanitizeArg(dir
);
1399 int len
= strlen("listall")+2+strlen(sDir
)+3;
1400 char *string
= malloc(len
);
1401 snprintf(string
, len
, "listall \"%s\"\n", sDir
);
1402 mpd_sendInfoCommand(connection
,string
);
1407 void mpd_sendListallInfoCommand(mpd_Connection
* connection
, const char * dir
) {
1408 char * sDir
= mpd_sanitizeArg(dir
);
1409 int len
= strlen("listallinfo")+2+strlen(sDir
)+3;
1410 char *string
= malloc(len
);
1411 snprintf(string
, len
, "listallinfo \"%s\"\n", sDir
);
1412 mpd_sendInfoCommand(connection
,string
);
1417 void mpd_sendLsInfoCommand(mpd_Connection
* connection
, const char * dir
) {
1418 char * sDir
= mpd_sanitizeArg(dir
);
1419 int len
= strlen("lsinfo")+2+strlen(sDir
)+3;
1420 char *string
= malloc(len
);
1421 snprintf(string
, len
, "lsinfo \"%s\"\n", sDir
);
1422 mpd_sendInfoCommand(connection
,string
);
1427 void mpd_sendCurrentSongCommand(mpd_Connection
* connection
) {
1428 mpd_executeCommand(connection
,"currentsong\n");
1431 void mpd_sendSearchCommand(mpd_Connection
* connection
, int table
,
1434 mpd_startSearch(connection
, 0);
1435 mpd_addConstraintSearch(connection
, table
, str
);
1436 mpd_commitSearch(connection
);
1439 void mpd_sendFindCommand(mpd_Connection
* connection
, int table
,
1442 mpd_startSearch(connection
, 1);
1443 mpd_addConstraintSearch(connection
, table
, str
);
1444 mpd_commitSearch(connection
);
1447 void mpd_sendListCommand(mpd_Connection
* connection
, int table
,
1453 if(table
== MPD_TABLE_ARTIST
) strcpy(st
,"artist");
1454 else if(table
== MPD_TABLE_ALBUM
) strcpy(st
,"album");
1456 connection
->error
= 1;
1457 strcpy(connection
->errorStr
,"unknown table for list");
1461 char * sanitArg1
= mpd_sanitizeArg(arg1
);
1462 len
= strlen("list")+1+strlen(sanitArg1
)+2+strlen(st
)+3;
1463 string
= malloc(len
);
1464 snprintf(string
, len
, "list %s \"%s\"\n", st
, sanitArg1
);
1468 len
= strlen("list")+1+strlen(st
)+2;
1469 string
= malloc(len
);
1470 snprintf(string
, len
, "list %s\n", st
);
1472 mpd_sendInfoCommand(connection
,string
);
1476 void mpd_sendAddCommand(mpd_Connection
* connection
, const char * file
) {
1477 char * sFile
= mpd_sanitizeArg(file
);
1478 int len
= strlen("add")+2+strlen(sFile
)+3;
1479 char *string
= malloc(len
);
1480 snprintf(string
, len
, "add \"%s\"\n", sFile
);
1481 mpd_executeCommand(connection
,string
);
1486 int mpd_sendAddIdCommand(mpd_Connection
*connection
, const char *file
)
1489 char *sFile
= mpd_sanitizeArg(file
);
1490 int len
= strlen("addid")+2+strlen(sFile
)+3;
1491 char *string
= malloc(len
);
1493 snprintf(string
, len
, "addid \"%s\"\n", sFile
);
1494 mpd_sendInfoCommand(connection
, string
);
1498 string
= mpd_getNextReturnElementNamed(connection
, "Id");
1500 retval
= atoi(string
);
1507 void mpd_sendDeleteCommand(mpd_Connection
* connection
, int songPos
) {
1508 int len
= strlen("delete")+2+INTLEN
+3;
1509 char *string
= malloc(len
);
1510 snprintf(string
, len
, "delete \"%i\"\n", songPos
);
1511 mpd_sendInfoCommand(connection
,string
);
1515 void mpd_sendDeleteIdCommand(mpd_Connection
* connection
, int id
) {
1516 int len
= strlen("deleteid")+2+INTLEN
+3;
1517 char *string
= malloc(len
);
1518 snprintf(string
, len
, "deleteid \"%i\"\n", id
);
1519 mpd_sendInfoCommand(connection
,string
);
1523 void mpd_sendSaveCommand(mpd_Connection
* connection
, const char * name
) {
1524 char * sName
= mpd_sanitizeArg(name
);
1525 int len
= strlen("save")+2+strlen(sName
)+3;
1526 char *string
= malloc(len
);
1527 snprintf(string
, len
, "save \"%s\"\n", sName
);
1528 mpd_executeCommand(connection
,string
);
1533 void mpd_sendLoadCommand(mpd_Connection
* connection
, const char * name
) {
1534 char * sName
= mpd_sanitizeArg(name
);
1535 int len
= strlen("load")+2+strlen(sName
)+3;
1536 char *string
= malloc(len
);
1537 snprintf(string
, len
, "load \"%s\"\n", sName
);
1538 mpd_executeCommand(connection
,string
);
1543 void mpd_sendRmCommand(mpd_Connection
* connection
, const char * name
) {
1544 char * sName
= mpd_sanitizeArg(name
);
1545 int len
= strlen("rm")+2+strlen(sName
)+3;
1546 char *string
= malloc(len
);
1547 snprintf(string
, len
, "rm \"%s\"\n", sName
);
1548 mpd_executeCommand(connection
,string
);
1553 void mpd_sendRenameCommand(mpd_Connection
*connection
, const char *from
,
1556 char *sFrom
= mpd_sanitizeArg(from
);
1557 char *sTo
= mpd_sanitizeArg(to
);
1558 int len
= strlen("rename")+2+strlen(sFrom
)+3+strlen(sTo
)+3;
1559 char *string
= malloc(len
);
1560 snprintf(string
, len
, "rename \"%s\" \"%s\"\n", sFrom
, sTo
);
1561 mpd_executeCommand(connection
, string
);
1567 void mpd_sendShuffleCommand(mpd_Connection
* connection
) {
1568 mpd_executeCommand(connection
,"shuffle\n");
1571 void mpd_sendClearCommand(mpd_Connection
* connection
) {
1572 mpd_executeCommand(connection
,"clear\n");
1575 void mpd_sendPlayCommand(mpd_Connection
* connection
, int songPos
) {
1576 int len
= strlen("play")+2+INTLEN
+3;
1577 char *string
= malloc(len
);
1578 snprintf(string
, len
, "play \"%i\"\n", songPos
);
1579 mpd_sendInfoCommand(connection
,string
);
1583 void mpd_sendPlayIdCommand(mpd_Connection
* connection
, int id
) {
1584 int len
= strlen("playid")+2+INTLEN
+3;
1585 char *string
= malloc(len
);
1586 snprintf(string
, len
, "playid \"%i\"\n", id
);
1587 mpd_sendInfoCommand(connection
,string
);
1591 void mpd_sendStopCommand(mpd_Connection
* connection
) {
1592 mpd_executeCommand(connection
,"stop\n");
1595 void mpd_sendPauseCommand(mpd_Connection
* connection
, int pauseMode
) {
1596 int len
= strlen("pause")+2+INTLEN
+3;
1597 char *string
= malloc(len
);
1598 snprintf(string
, len
, "pause \"%i\"\n", pauseMode
);
1599 mpd_executeCommand(connection
,string
);
1603 void mpd_sendNextCommand(mpd_Connection
* connection
) {
1604 mpd_executeCommand(connection
,"next\n");
1607 void mpd_sendMoveCommand(mpd_Connection
* connection
, int from
, int to
) {
1608 int len
= strlen("move")+2+INTLEN
+3+INTLEN
+3;
1609 char *string
= malloc(len
);
1610 snprintf(string
, len
, "move \"%i\" \"%i\"\n", from
, to
);
1611 mpd_sendInfoCommand(connection
,string
);
1615 void mpd_sendMoveIdCommand(mpd_Connection
* connection
, int id
, int to
) {
1616 int len
= strlen("moveid")+2+INTLEN
+3+INTLEN
+3;
1617 char *string
= malloc(len
);
1618 snprintf(string
, len
, "moveid \"%i\" \"%i\"\n", id
, to
);
1619 mpd_sendInfoCommand(connection
,string
);
1623 void mpd_sendSwapCommand(mpd_Connection
* connection
, int song1
, int song2
) {
1624 int len
= strlen("swap")+2+INTLEN
+3+INTLEN
+3;
1625 char *string
= malloc(len
);
1626 snprintf(string
, len
, "swap \"%i\" \"%i\"\n", song1
, song2
);
1627 mpd_sendInfoCommand(connection
,string
);
1631 void mpd_sendSwapIdCommand(mpd_Connection
* connection
, int id1
, int id2
) {
1632 int len
= strlen("swapid")+2+INTLEN
+3+INTLEN
+3;
1633 char *string
= malloc(len
);
1634 snprintf(string
, len
, "swapid \"%i\" \"%i\"\n", id1
, id2
);
1635 mpd_sendInfoCommand(connection
,string
);
1639 void mpd_sendSeekCommand(mpd_Connection
* connection
, int song
, int time
) {
1640 int len
= strlen("seek")+2+INTLEN
+3+INTLEN
+3;
1641 char *string
= malloc(len
);
1642 snprintf(string
, len
, "seek \"%i\" \"%i\"\n", song
, time
);
1643 mpd_sendInfoCommand(connection
,string
);
1647 void mpd_sendSeekIdCommand(mpd_Connection
* connection
, int id
, int time
) {
1648 int len
= strlen("seekid")+2+INTLEN
+3+INTLEN
+3;
1649 char *string
= malloc(len
);
1650 snprintf(string
, len
, "seekid \"%i\" \"%i\"\n", id
, time
);
1651 mpd_sendInfoCommand(connection
,string
);
1655 void mpd_sendUpdateCommand(mpd_Connection
* connection
,const char * path
) {
1656 char * sPath
= mpd_sanitizeArg(path
);
1657 int len
= strlen("update")+2+strlen(sPath
)+3;
1658 char *string
= malloc(len
);
1659 snprintf(string
, len
, "update \"%s\"\n", sPath
);
1660 mpd_sendInfoCommand(connection
,string
);
1665 int mpd_getUpdateId(mpd_Connection
* connection
) {
1669 jobid
= mpd_getNextReturnElementNamed(connection
,"updating_db");
1678 void mpd_sendPrevCommand(mpd_Connection
* connection
) {
1679 mpd_executeCommand(connection
,"previous\n");
1682 void mpd_sendRepeatCommand(mpd_Connection
* connection
, int repeatMode
) {
1683 int len
= strlen("repeat")+2+INTLEN
+3;
1684 char *string
= malloc(len
);
1685 snprintf(string
, len
, "repeat \"%i\"\n", repeatMode
);
1686 mpd_executeCommand(connection
,string
);
1690 void mpd_sendRandomCommand(mpd_Connection
* connection
, int randomMode
) {
1691 int len
= strlen("random")+2+INTLEN
+3;
1692 char *string
= malloc(len
);
1693 snprintf(string
, len
, "random \"%i\"\n", randomMode
);
1694 mpd_executeCommand(connection
,string
);
1698 void mpd_sendSetvolCommand(mpd_Connection
* connection
, int volumeChange
) {
1699 int len
= strlen("setvol")+2+INTLEN
+3;
1700 char *string
= malloc(len
);
1701 snprintf(string
, len
, "setvol \"%i\"\n", volumeChange
);
1702 mpd_executeCommand(connection
,string
);
1706 void mpd_sendVolumeCommand(mpd_Connection
* connection
, int volumeChange
) {
1707 int len
= strlen("volume")+2+INTLEN
+3;
1708 char *string
= malloc(len
);
1709 snprintf(string
, len
, "volume \"%i\"\n", volumeChange
);
1710 mpd_executeCommand(connection
,string
);
1714 void mpd_sendCrossfadeCommand(mpd_Connection
* connection
, int seconds
) {
1715 int len
= strlen("crossfade")+2+INTLEN
+3;
1716 char *string
= malloc(len
);
1717 snprintf(string
, len
, "crossfade \"%i\"\n", seconds
);
1718 mpd_executeCommand(connection
,string
);
1722 void mpd_sendPasswordCommand(mpd_Connection
* connection
, const char * pass
) {
1723 char * sPass
= mpd_sanitizeArg(pass
);
1724 int len
= strlen("password")+2+strlen(sPass
)+3;
1725 char *string
= malloc(len
);
1726 snprintf(string
, len
, "password \"%s\"\n", sPass
);
1727 mpd_executeCommand(connection
,string
);
1732 void mpd_sendCommandListBegin(mpd_Connection
* connection
) {
1733 if(connection
->commandList
) {
1734 strcpy(connection
->errorStr
,"already in command list mode");
1735 connection
->error
= 1;
1738 connection
->commandList
= COMMAND_LIST
;
1739 mpd_executeCommand(connection
,"command_list_begin\n");
1742 void mpd_sendCommandListOkBegin(mpd_Connection
* connection
) {
1743 if(connection
->commandList
) {
1744 strcpy(connection
->errorStr
,"already in command list mode");
1745 connection
->error
= 1;
1748 connection
->commandList
= COMMAND_LIST_OK
;
1749 mpd_executeCommand(connection
,"command_list_ok_begin\n");
1750 connection
->listOks
= 0;
1753 void mpd_sendCommandListEnd(mpd_Connection
* connection
) {
1754 if(!connection
->commandList
) {
1755 strcpy(connection
->errorStr
,"not in command list mode");
1756 connection
->error
= 1;
1759 connection
->commandList
= 0;
1760 mpd_executeCommand(connection
,"command_list_end\n");
1763 void mpd_sendOutputsCommand(mpd_Connection
* connection
) {
1764 mpd_executeCommand(connection
,"outputs\n");
1767 mpd_OutputEntity
* mpd_getNextOutput(mpd_Connection
* connection
) {
1768 mpd_OutputEntity
* output
= NULL
;
1770 if(connection
->doneProcessing
|| (connection
->listOks
&&
1771 connection
->doneListOk
))
1776 if(connection
->error
) return NULL
;
1778 output
= malloc(sizeof(mpd_OutputEntity
));
1780 output
->name
= NULL
;
1781 output
->enabled
= 0;
1783 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
1785 while(connection
->returnElement
) {
1786 mpd_ReturnElement
* re
= connection
->returnElement
;
1787 if(strcmp(re
->name
,"outputid")==0) {
1788 if(output
!=NULL
&& output
->id
>=0) return output
;
1789 output
->id
= atoi(re
->value
);
1791 else if(strcmp(re
->name
,"outputname")==0) {
1792 output
->name
= strdup(re
->value
);
1794 else if(strcmp(re
->name
,"outputenabled")==0) {
1795 output
->enabled
= atoi(re
->value
);
1798 mpd_getNextReturnElement(connection
);
1799 if(connection
->error
) {
1809 void mpd_sendEnableOutputCommand(mpd_Connection
* connection
, int outputId
) {
1810 int len
= strlen("enableoutput")+2+INTLEN
+3;
1811 char *string
= malloc(len
);
1812 snprintf(string
, len
, "enableoutput \"%i\"\n", outputId
);
1813 mpd_executeCommand(connection
,string
);
1817 void mpd_sendDisableOutputCommand(mpd_Connection
* connection
, int outputId
) {
1818 int len
= strlen("disableoutput")+2+INTLEN
+3;
1819 char *string
= malloc(len
);
1820 snprintf(string
, len
, "disableoutput \"%i\"\n", outputId
);
1821 mpd_executeCommand(connection
,string
);
1825 void mpd_freeOutputElement(mpd_OutputEntity
* output
) {
1831 * mpd_sendNotCommandsCommand
1832 * odd naming, but it gets the not allowed commands
1835 void mpd_sendNotCommandsCommand(mpd_Connection
* connection
)
1837 mpd_executeCommand(connection
, "notcommands\n");
1841 * mpd_sendCommandsCommand
1842 * odd naming, but it gets the allowed commands
1844 void mpd_sendCommandsCommand(mpd_Connection
* connection
)
1846 mpd_executeCommand(connection
, "commands\n");
1850 * Get the next returned command
1852 char * mpd_getNextCommand(mpd_Connection
* connection
)
1854 return mpd_getNextReturnElementNamed(connection
, "command");
1857 void mpd_sendUrlHandlersCommand(mpd_Connection
* connection
)
1859 mpd_executeCommand(connection
, "urlhandlers\n");
1862 char * mpd_getNextHandler(mpd_Connection
* connection
)
1864 return mpd_getNextReturnElementNamed(connection
, "handler");
1867 void mpd_sendTagTypesCommand(mpd_Connection
* connection
)
1869 mpd_executeCommand(connection
, "tagtypes\n");
1872 char * mpd_getNextTagType(mpd_Connection
* connection
)
1874 return mpd_getNextReturnElementNamed(connection
, "tagtype");
1877 void mpd_startSearch(mpd_Connection
*connection
, int exact
)
1879 if (connection
->request
) {
1880 strcpy(connection
->errorStr
, "search already in progress");
1881 connection
->error
= 1;
1885 if (exact
) connection
->request
= strdup("find");
1886 else connection
->request
= strdup("search");
1889 void mpd_startStatsSearch(mpd_Connection
*connection
)
1891 if (connection
->request
) {
1892 strcpy(connection
->errorStr
, "search already in progress");
1893 connection
->error
= 1;
1897 connection
->request
= strdup("count");
1900 void mpd_startPlaylistSearch(mpd_Connection
*connection
, int exact
)
1902 if (connection
->request
) {
1903 strcpy(connection
->errorStr
, "search already in progress");
1904 connection
->error
= 1;
1908 if (exact
) connection
->request
= strdup("playlistfind");
1909 else connection
->request
= strdup("playlistsearch");
1912 void mpd_startFieldSearch(mpd_Connection
*connection
, int type
)
1917 if (connection
->request
) {
1918 strcpy(connection
->errorStr
, "search already in progress");
1919 connection
->error
= 1;
1923 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1924 strcpy(connection
->errorStr
, "invalid type specified");
1925 connection
->error
= 1;
1929 strtype
= mpdTagItemKeys
[type
];
1931 len
= 5+strlen(strtype
)+1;
1932 connection
->request
= malloc(len
);
1934 snprintf(connection
->request
, len
, "list %c%s",
1935 tolower(strtype
[0]), strtype
+1);
1938 void mpd_addConstraintSearch(mpd_Connection
*connection
, int type
, const char *name
)
1945 if (!connection
->request
) {
1946 strcpy(connection
->errorStr
, "no search in progress");
1947 connection
->error
= 1;
1951 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1952 strcpy(connection
->errorStr
, "invalid type specified");
1953 connection
->error
= 1;
1958 strcpy(connection
->errorStr
, "no name specified");
1959 connection
->error
= 1;
1963 string
= strdup(connection
->request
);
1964 strtype
= mpdTagItemKeys
[type
];
1965 arg
= mpd_sanitizeArg(name
);
1967 len
= strlen(string
)+1+strlen(strtype
)+2+strlen(arg
)+2;
1968 connection
->request
= realloc(connection
->request
, len
);
1969 snprintf(connection
->request
, len
, "%s %c%s \"%s\"",
1970 string
, tolower(strtype
[0]), strtype
+1, arg
);
1976 void mpd_commitSearch(mpd_Connection
*connection
)
1980 if (!connection
->request
) {
1981 strcpy(connection
->errorStr
, "no search in progress");
1982 connection
->error
= 1;
1986 len
= strlen(connection
->request
)+2;
1987 connection
->request
= realloc(connection
->request
, len
);
1988 connection
->request
[len
-2] = '\n';
1989 connection
->request
[len
-1] = '\0';
1990 mpd_sendInfoCommand(connection
, connection
->request
);
1992 free(connection
->request
);
1993 connection
->request
= NULL
;
1997 * @param connection a MpdConnection
1998 * @param path the path to the playlist.
2000 * List the content, with full metadata, of a stored playlist.
2003 void mpd_sendListPlaylistInfoCommand(mpd_Connection
*connection
,const char *path
)
2005 char *arg
= mpd_sanitizeArg(path
);
2006 int len
= strlen("listplaylistinfo")+2+strlen(arg
)+3;
2007 char *query
= malloc(len
);
2008 snprintf(query
, len
, "listplaylistinfo \"%s\"\n", arg
);
2009 mpd_sendInfoCommand(connection
, query
);
2015 * @param connection a MpdConnection
2016 * @param path the path to the playlist.
2018 * List the content of a stored playlist.
2021 void mpd_sendListPlaylistCommand(mpd_Connection
*connection
,const char *path
)
2023 char *arg
= mpd_sanitizeArg(path
);
2024 int len
= strlen("listplaylist")+2+strlen(arg
)+3;
2025 char *query
= malloc(len
);
2026 snprintf(query
, len
, "listplaylist \"%s\"\n", arg
);
2027 mpd_sendInfoCommand(connection
, query
);
2032 void mpd_sendPlaylistClearCommand(mpd_Connection
*connection
,const char *path
)
2034 char *sPath
= mpd_sanitizeArg(path
);
2035 int len
= strlen("playlistclear")+2+strlen(sPath
)+3;
2036 char *string
= malloc(len
);
2037 snprintf(string
, len
, "playlistclear \"%s\"\n", sPath
);
2038 mpd_executeCommand(connection
, string
);
2043 void mpd_sendPlaylistAddCommand(mpd_Connection
*connection
,
2044 const char *playlist
,const char *path
)
2046 char *sPlaylist
= mpd_sanitizeArg(playlist
);
2047 char *sPath
= mpd_sanitizeArg(path
);
2048 int len
= strlen("playlistadd")+2+strlen(sPlaylist
)+3+strlen(sPath
)+3;
2049 char *string
= malloc(len
);
2050 snprintf(string
, len
, "playlistadd \"%s\" \"%s\"\n", sPlaylist
, sPath
);
2051 mpd_executeCommand(connection
, string
);
2057 void mpd_sendPlaylistMoveCommand(mpd_Connection
*connection
,
2058 const char *playlist
, int from
, int to
)
2060 char *sPlaylist
= mpd_sanitizeArg(playlist
);
2061 int len
= strlen("playlistmove")+
2062 2+strlen(sPlaylist
)+3+INTLEN
+3+INTLEN
+3;
2063 char *string
= malloc(len
);
2064 snprintf(string
, len
, "playlistmove \"%s\" \"%i\" \"%i\"\n",
2065 sPlaylist
, from
, to
);
2066 mpd_executeCommand(connection
, string
);
2071 void mpd_sendPlaylistDeleteCommand(mpd_Connection
*connection
,
2072 const char *playlist
, int pos
)
2074 char *sPlaylist
= mpd_sanitizeArg(playlist
);
2075 int len
= strlen("playlistdelete")+2+strlen(sPlaylist
)+3+INTLEN
+3;
2076 char *string
= malloc(len
);
2077 snprintf(string
, len
, "playlistdelete \"%s\" \"%i\"\n", sPlaylist
, pos
);
2078 mpd_executeCommand(connection
, string
);
2082 void mpd_sendClearErrorCommand(mpd_Connection
* connection
) {
2083 mpd_executeCommand(connection
,"clearerror\n");
2087 void mpd_sendGetEventsCommand(mpd_Connection
*connection
) {
2088 mpd_executeCommand(connection
, "idle\nnoidle\n");
2089 // mpd_executeCommand(connection, "noidle\n");
2092 char * mpd_getNextEvent(mpd_Connection
*connection
)
2094 return mpd_getNextReturnElementNamed(connection
, "changed");
2097 void mpd_sendListPlaylistsCommand(mpd_Connection
* connection
) {
2098 mpd_sendInfoCommand(connection
, "listplaylists\n");
2101 char * mpd_getNextSticker (mpd_Connection
* connection
)
2103 return mpd_getNextReturnElementNamed(connection
, "sticker");
2105 void mpd_sendGetSongSticker(mpd_Connection
*connection
, const char *song_path
, const char *sticker
)
2107 char *sSong
= mpd_sanitizeArg(song_path
);
2108 char *sSticker
= mpd_sanitizeArg(sticker
);
2109 int len
= strlen("sticker get song ")+strlen(sSong
)+3+strlen(sSticker
)+4;
2110 char *string
= malloc(len
);
2111 snprintf(string
, len
, "sticker get song \"%s\" \"%s\"\n", sSong
, sSticker
);
2112 mpd_executeCommand(connection
, string
);
2118 void mpd_sendSetSongSticker(mpd_Connection
*connection
, const char *song_path
, const char *sticker
, const char *value
)
2121 char *sSong
= mpd_sanitizeArg(song_path
);
2122 char *sSticker
= mpd_sanitizeArg(sticker
);
2123 char *sValue
= mpd_sanitizeArg(value
);
2124 int len
= strlen("sticker set song ")+strlen(sSong
)+3+strlen(sSticker
)+3+strlen(sValue
)+4;
2125 char *string
= malloc(len
);
2126 snprintf(string
, len
, "sticker set song \"%s\" \"%s\" \"%s\"\n", sSong
, sSticker
,sValue
);
2127 mpd_sendInfoCommand(connection
, string
);