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 saun
;
363 path_length
= strlen(host
);
364 if (path_length
>= sizeof(saun
.sun_path
)) {
365 strcpy(connection
->errorStr
, "unix socket path is too long");
366 connection
->error
= MPD_ERROR_UNKHOST
;
370 saun
.sun_family
= AF_UNIX
;
371 memcpy(saun
.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
*)&saun
, sizeof(saun
));
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
;
518 while((ret
= select(connection
->sock
+1,NULL
,&fds
,NULL
,&tv
)==1) ||
519 (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;
539 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
540 "timeout sending command \"%s\"",command
);
541 connection
->error
= MPD_ERROR_TIMEOUT
;
545 if(!connection
->commandList
) connection
->doneProcessing
= 0;
546 else if(connection
->commandList
== COMMAND_LIST_OK
) {
547 connection
->listOks
++;
551 static void mpd_getNextReturnElement(mpd_Connection
* connection
) {
552 char * output
= NULL
;
560 char * bufferCheck
= NULL
;
564 if(connection
->returnElement
) mpd_freeReturnElement(connection
->returnElement
);
565 connection
->returnElement
= NULL
;
567 if(connection
->doneProcessing
|| (connection
->listOks
&&
568 connection
->doneListOk
))
570 strcpy(connection
->errorStr
,"already done processing current command");
571 connection
->error
= 1;
575 bufferCheck
= connection
->buffer
+connection
->bufstart
;
576 while(connection
->bufstart
>=connection
->buflen
||
577 !(rt
= strchr(bufferCheck
,'\n'))) {
578 if(connection
->buflen
>=MPD_BUFFER_MAX_LENGTH
) {
579 memmove(connection
->buffer
,
581 connection
->bufstart
,
583 connection
->bufstart
+1);
584 connection
->buflen
-=connection
->bufstart
;
585 connection
->bufstart
= 0;
587 if(connection
->buflen
>=MPD_BUFFER_MAX_LENGTH
) {
588 strcpy(connection
->errorStr
,"buffer overrun");
589 connection
->error
= MPD_ERROR_BUFFEROVERRUN
;
590 connection
->doneProcessing
= 1;
591 connection
->doneListOk
= 0;
594 bufferCheck
= connection
->buffer
+connection
->buflen
;
595 tv
.tv_sec
= connection
->timeout
.tv_sec
;
596 tv
.tv_usec
= connection
->timeout
.tv_usec
;
598 FD_SET(connection
->sock
,&fds
);
599 if((err
= select(connection
->sock
+1,&fds
,NULL
,NULL
,&tv
) == 1)) {
600 readed
= recv(connection
->sock
,
601 connection
->buffer
+connection
->buflen
,
602 MPD_BUFFER_MAX_LENGTH
-connection
->buflen
,
604 if(readed
<0 && SENDRECV_ERRNO_IGNORE
) {
608 strcpy(connection
->errorStr
,"connection"
610 connection
->error
= MPD_ERROR_CONNCLOSED
;
611 connection
->doneProcessing
= 1;
612 connection
->doneListOk
= 0;
615 connection
->buflen
+=readed
;
616 connection
->buffer
[connection
->buflen
] = '\0';
618 else if(err
<0 && SELECT_ERRNO_IGNORE
) continue;
620 strcpy(connection
->errorStr
,"connection timeout");
621 connection
->error
= MPD_ERROR_TIMEOUT
;
622 connection
->doneProcessing
= 1;
623 connection
->doneListOk
= 0;
629 output
= connection
->buffer
+connection
->bufstart
;
630 connection
->bufstart
= rt
- connection
->buffer
+ 1;
632 if(strcmp(output
,"OK")==0) {
633 if(connection
->listOks
> 0) {
634 strcpy(connection
->errorStr
, "expected more list_OK's");
635 connection
->error
= 1;
637 connection
->listOks
= 0;
638 connection
->doneProcessing
= 1;
639 connection
->doneListOk
= 0;
643 if(strcmp(output
, "list_OK") == 0) {
644 if(!connection
->listOks
) {
645 strcpy(connection
->errorStr
,
646 "got an unexpected list_OK");
647 connection
->error
= 1;
650 connection
->doneListOk
= 1;
651 connection
->listOks
--;
656 if(strncmp(output
,"ACK",strlen("ACK"))==0) {
661 strcpy(connection
->errorStr
, output
);
662 connection
->error
= MPD_ERROR_ACK
;
663 connection
->errorCode
= MPD_ACK_ERROR_UNK
;
664 connection
->errorAt
= MPD_ERROR_AT_UNK
;
665 connection
->doneProcessing
= 1;
666 connection
->doneListOk
= 0;
668 needle
= strchr(output
, '[');
670 val
= strtol(needle
+1, &test
, 10);
671 if(*test
!= '@') return;
672 connection
->errorCode
= val
;
673 val
= strtol(test
+1, &test
, 10);
674 if(*test
!= ']') return;
675 connection
->errorAt
= val
;
679 tok
= strchr(output
, ':');
687 connection
->returnElement
= mpd_newReturnElement(name
,&(value
[1]));
690 snprintf(connection
->errorStr
,MPD_ERRORSTR_MAX_LENGTH
,
691 "error parsing: %s:%s",name
,value
);
692 connection
->error
= 1;
696 void mpd_finishCommand(mpd_Connection
* connection
) {
697 while(!connection
->doneProcessing
) {
698 if(connection
->doneListOk
) connection
->doneListOk
= 0;
699 mpd_getNextReturnElement(connection
);
703 static void mpd_finishListOkCommand(mpd_Connection
* connection
) {
704 while(!connection
->doneProcessing
&& connection
->listOks
&&
705 !connection
->doneListOk
)
707 mpd_getNextReturnElement(connection
);
711 int mpd_nextListOkCommand(mpd_Connection
* connection
) {
712 mpd_finishListOkCommand(connection
);
713 if(!connection
->doneProcessing
) connection
->doneListOk
= 0;
714 if(connection
->listOks
== 0 || connection
->doneProcessing
) return -1;
718 void mpd_sendStatusCommand(mpd_Connection
* connection
) {
719 mpd_executeCommand(connection
,"status\n");
722 mpd_Status
* mpd_getStatus(mpd_Connection
* connection
) {
725 /*mpd_executeCommand(connection,"status\n");
727 if(connection->error) return NULL;*/
729 if(connection
->doneProcessing
|| (connection
->listOks
&&
730 connection
->doneListOk
))
735 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
737 status
= malloc(sizeof(mpd_Status
));
741 status
->playlist
= -1;
742 status
->storedplaylist
= -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
) {
1023 mpd_finishSong(song
);
1027 mpd_Song
* mpd_songDup(mpd_Song
* song
) {
1028 mpd_Song
* ret
= mpd_newSong();
1030 if(song
->file
) ret
->file
= strdup(song
->file
);
1031 if(song
->artist
) ret
->artist
= strdup(song
->artist
);
1032 if(song
->album
) ret
->album
= strdup(song
->album
);
1033 if(song
->title
) ret
->title
= strdup(song
->title
);
1034 if(song
->track
) ret
->track
= strdup(song
->track
);
1035 if(song
->name
) ret
->name
= strdup(song
->name
);
1036 if(song
->date
) ret
->date
= strdup(song
->date
);
1037 if(song
->genre
) ret
->genre
= strdup(song
->genre
);
1038 if(song
->composer
) ret
->composer
= strdup(song
->composer
);
1039 if(song
->performer
) ret
->performer
= strdup(song
->performer
);
1040 if(song
->disc
) ret
->disc
= strdup(song
->disc
);
1041 if(song
->comment
) ret
->comment
= strdup(song
->comment
);
1042 ret
->time
= song
->time
;
1043 ret
->pos
= song
->pos
;
1049 static void mpd_initDirectory(mpd_Directory
* directory
) {
1050 directory
->path
= NULL
;
1053 static void mpd_finishDirectory(mpd_Directory
* directory
) {
1054 if(directory
->path
) free(directory
->path
);
1057 mpd_Directory
* mpd_newDirectory(void) {
1058 mpd_Directory
* directory
= malloc(sizeof(mpd_Directory
));;
1060 mpd_initDirectory(directory
);
1065 void mpd_freeDirectory(mpd_Directory
* directory
) {
1066 mpd_finishDirectory(directory
);
1071 mpd_Directory
* mpd_directoryDup(mpd_Directory
* directory
) {
1072 mpd_Directory
* ret
= mpd_newDirectory();
1074 if(directory
->path
) ret
->path
= strdup(directory
->path
);
1079 static void mpd_initPlaylistFile(mpd_PlaylistFile
* playlist
) {
1080 playlist
->path
= NULL
;
1081 playlist
->mtime
= NULL
;
1084 static void mpd_finishPlaylistFile(mpd_PlaylistFile
* playlist
) {
1085 if(playlist
->path
) free(playlist
->path
);
1086 if(playlist
->mtime
) free(playlist
->mtime
);
1089 mpd_PlaylistFile
* mpd_newPlaylistFile(void) {
1090 mpd_PlaylistFile
* playlist
= malloc(sizeof(mpd_PlaylistFile
));
1092 mpd_initPlaylistFile(playlist
);
1097 void mpd_freePlaylistFile(mpd_PlaylistFile
* playlist
) {
1098 mpd_finishPlaylistFile(playlist
);
1102 mpd_PlaylistFile
* mpd_playlistFileDup(mpd_PlaylistFile
* playlist
) {
1103 mpd_PlaylistFile
* ret
= mpd_newPlaylistFile();
1105 if(playlist
->path
) ret
->path
= strdup(playlist
->path
);
1106 if(playlist
->mtime
) ret
->mtime
= strdup(playlist
->mtime
);
1111 static void mpd_initInfoEntity(mpd_InfoEntity
* entity
) {
1112 entity
->info
.directory
= NULL
;
1115 static void mpd_finishInfoEntity(mpd_InfoEntity
* entity
) {
1116 if(entity
->info
.directory
) {
1117 if(entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1118 mpd_freeDirectory(entity
->info
.directory
);
1120 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
) {
1121 mpd_freeSong(entity
->info
.song
);
1123 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1124 mpd_freePlaylistFile(entity
->info
.playlistFile
);
1129 mpd_InfoEntity
* mpd_newInfoEntity(void) {
1130 mpd_InfoEntity
* entity
= malloc(sizeof(mpd_InfoEntity
));
1132 mpd_initInfoEntity(entity
);
1137 void mpd_freeInfoEntity(mpd_InfoEntity
* entity
) {
1138 mpd_finishInfoEntity(entity
);
1142 static void mpd_sendInfoCommand(mpd_Connection
* connection
, char * command
) {
1143 mpd_executeCommand(connection
,command
);
1146 mpd_InfoEntity
* mpd_getNextInfoEntity(mpd_Connection
* connection
) {
1147 mpd_InfoEntity
* entity
= NULL
;
1149 if(connection
->doneProcessing
|| (connection
->listOks
&&
1150 connection
->doneListOk
))
1155 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
1157 if(connection
->returnElement
) {
1158 if(strcmp(connection
->returnElement
->name
,"file")==0) {
1159 entity
= mpd_newInfoEntity();
1160 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1161 entity
->info
.song
= mpd_newSong();
1162 entity
->info
.song
->file
=
1163 strdup(connection
->returnElement
->value
);
1165 else if(strcmp(connection
->returnElement
->name
,
1167 entity
= mpd_newInfoEntity();
1168 entity
->type
= MPD_INFO_ENTITY_TYPE_DIRECTORY
;
1169 entity
->info
.directory
= mpd_newDirectory();
1170 entity
->info
.directory
->path
=
1171 strdup(connection
->returnElement
->value
);
1173 else if(strcmp(connection
->returnElement
->name
,"playlist")==0) {
1174 entity
= mpd_newInfoEntity();
1175 entity
->type
= MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
;
1176 entity
->info
.playlistFile
= mpd_newPlaylistFile();
1177 entity
->info
.playlistFile
->path
=
1178 strdup(connection
->returnElement
->value
);
1180 else if(strcmp(connection
->returnElement
->name
, "cpos") == 0){
1181 entity
= mpd_newInfoEntity();
1182 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1183 entity
->info
.song
= mpd_newSong();
1184 entity
->info
.song
->pos
= atoi(connection
->returnElement
->value
);
1187 connection
->error
= 1;
1188 strcpy(connection
->errorStr
,"problem parsing song info");
1194 mpd_getNextReturnElement(connection
);
1195 while(connection
->returnElement
) {
1196 mpd_ReturnElement
* re
= connection
->returnElement
;
1198 if(strcmp(re
->name
,"file")==0) return entity
;
1199 else if(strcmp(re
->name
,"directory")==0) return entity
;
1200 else if(strcmp(re
->name
,"playlist")==0) return entity
;
1201 else if(strcmp(re
->name
,"cpos")==0) return entity
;
1203 if(entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
&&
1204 strlen(re
->value
)) {
1205 if(strcmp(re
->name
,"Artist")==0) {
1206 if(entity
->info
.song
->artist
) {
1207 int length
= strlen(entity
->info
.song
->artist
);
1208 entity
->info
.song
->artist
= realloc(entity
->info
.song
->artist
,
1209 length
+ strlen(re
->value
) + 3);
1210 strcpy(&((entity
->info
.song
->artist
)[length
]), ", ");
1211 strcpy(&((entity
->info
.song
->artist
)[length
+ 2]), re
->value
);
1214 entity
->info
.song
->artist
= strdup(re
->value
);
1217 else if(!entity
->info
.song
->album
&&
1218 strcmp(re
->name
,"Album")==0) {
1219 entity
->info
.song
->album
= strdup(re
->value
);
1221 else if(!entity
->info
.song
->title
&&
1222 strcmp(re
->name
,"Title")==0) {
1223 entity
->info
.song
->title
= strdup(re
->value
);
1225 else if(!entity
->info
.song
->track
&&
1226 strcmp(re
->name
,"Track")==0) {
1227 entity
->info
.song
->track
= strdup(re
->value
);
1229 else if(!entity
->info
.song
->name
&&
1230 strcmp(re
->name
,"Name")==0) {
1231 entity
->info
.song
->name
= strdup(re
->value
);
1233 else if(entity
->info
.song
->time
==MPD_SONG_NO_TIME
&&
1234 strcmp(re
->name
,"Time")==0) {
1235 entity
->info
.song
->time
= atoi(re
->value
);
1237 else if(entity
->info
.song
->pos
==MPD_SONG_NO_NUM
&&
1238 strcmp(re
->name
,"Pos")==0) {
1239 entity
->info
.song
->pos
= atoi(re
->value
);
1241 else if(entity
->info
.song
->id
==MPD_SONG_NO_ID
&&
1242 strcmp(re
->name
,"Id")==0) {
1243 entity
->info
.song
->id
= atoi(re
->value
);
1245 else if(!entity
->info
.song
->date
&&
1246 strcmp(re
->name
, "Date") == 0) {
1247 entity
->info
.song
->date
= strdup(re
->value
);
1249 else if(!entity
->info
.song
->genre
&&
1250 strcmp(re
->name
, "Genre") == 0) {
1251 if(entity
->info
.song
->genre
) {
1252 int length
= strlen(entity
->info
.song
->genre
);
1253 entity
->info
.song
->genre
= realloc(entity
->info
.song
->genre
,
1254 length
+ strlen(re
->value
) + 4);
1255 strcpy(&((entity
->info
.song
->genre
)[length
]), ", ");
1256 strcpy(&((entity
->info
.song
->genre
)[length
+ 3]), re
->value
);
1259 entity
->info
.song
->genre
= strdup(re
->value
);
1262 else if(strcmp(re
->name
, "Composer") == 0) {
1263 if(entity
->info
.song
->composer
) {
1264 int length
= strlen(entity
->info
.song
->composer
);
1265 entity
->info
.song
->composer
= realloc(entity
->info
.song
->composer
,
1266 length
+ strlen(re
->value
) + 3);
1267 strcpy(&((entity
->info
.song
->composer
)[length
]), ", ");
1268 strcpy(&((entity
->info
.song
->composer
)[length
+ 2]), re
->value
);
1271 entity
->info
.song
->composer
= strdup(re
->value
);
1274 else if(strcmp(re
->name
, "Performer") == 0) {
1275 if(entity
->info
.song
->performer
) {
1276 int length
= strlen(entity
->info
.song
->performer
);
1277 entity
->info
.song
->performer
= realloc(entity
->info
.song
->performer
,
1278 length
+ strlen(re
->value
) + 3);
1279 strcpy(&((entity
->info
.song
->performer
)[length
]), ", ");
1280 strcpy(&((entity
->info
.song
->performer
)[length
+ 2]), re
->value
);
1283 entity
->info
.song
->performer
= strdup(re
->value
);
1286 else if(!entity
->info
.song
->disc
&&
1287 strcmp(re
->name
, "Disc") == 0) {
1288 entity
->info
.song
->disc
= strdup(re
->value
);
1290 else if(!entity
->info
.song
->comment
&&
1291 strcmp(re
->name
, "Comment") == 0) {
1292 entity
->info
.song
->comment
= strdup(re
->value
);
1295 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1297 else if(entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1298 if(!entity
->info
.playlistFile
->mtime
&&
1299 strcmp(re
->name
, "Last-Modified") == 0) {
1300 entity
->info
.playlistFile
->mtime
= strdup(re
->value
);
1304 mpd_getNextReturnElement(connection
);
1310 static char * mpd_getNextReturnElementNamed(mpd_Connection
* connection
,
1313 if(connection
->doneProcessing
|| (connection
->listOks
&&
1314 connection
->doneListOk
))
1319 mpd_getNextReturnElement(connection
);
1320 while(connection
->returnElement
) {
1321 mpd_ReturnElement
* re
= connection
->returnElement
;
1323 if(strcmp(re
->name
,name
)==0) return strdup(re
->value
);
1324 mpd_getNextReturnElement(connection
);
1330 char *mpd_getNextTag(mpd_Connection
*connection
, int type
)
1332 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
||
1333 type
== MPD_TAG_ITEM_ANY
)
1335 if (type
== MPD_TAG_ITEM_FILENAME
)
1336 return mpd_getNextReturnElementNamed(connection
, "file");
1337 return mpd_getNextReturnElementNamed(connection
, mpdTagItemKeys
[type
]);
1340 char * mpd_getNextArtist(mpd_Connection
* connection
) {
1341 return mpd_getNextReturnElementNamed(connection
,"Artist");
1344 char * mpd_getNextAlbum(mpd_Connection
* connection
) {
1345 return mpd_getNextReturnElementNamed(connection
,"Album");
1348 void mpd_sendPlaylistInfoCommand(mpd_Connection
* connection
, int songPos
) {
1349 int len
= strlen("playlistinfo")+2+INTLEN
+3;
1350 char *string
= malloc(len
);
1351 snprintf(string
, len
, "playlistinfo \"%i\"\n", songPos
);
1352 mpd_sendInfoCommand(connection
,string
);
1356 void mpd_sendPlaylistIdCommand(mpd_Connection
* connection
, int id
) {
1357 int len
= strlen("playlistid")+2+INTLEN
+3;
1358 char *string
= malloc(len
);
1359 snprintf(string
, len
, "playlistid \"%i\"\n", id
);
1360 mpd_sendInfoCommand(connection
, string
);
1364 void mpd_sendPlChangesCommand(mpd_Connection
* connection
, long long playlist
) {
1365 int len
= strlen("plchanges")+2+LONGLONGLEN
+3;
1366 char *string
= malloc(len
);
1367 snprintf(string
, len
, "plchanges \"%lld\"\n", playlist
);
1368 mpd_sendInfoCommand(connection
,string
);
1372 void mpd_sendPlChangesPosIdCommand(mpd_Connection
* connection
, long long playlist
) {
1373 int len
= strlen("plchangesposid")+2+LONGLONGLEN
+3;
1374 char *string
= malloc(len
);
1375 snprintf(string
, len
, "plchangesposid \"%lld\"\n", playlist
);
1376 mpd_sendInfoCommand(connection
,string
);
1380 void mpd_sendListallCommand(mpd_Connection
* connection
, const char * dir
) {
1381 char * sDir
= mpd_sanitizeArg(dir
);
1382 int len
= strlen("listall")+2+strlen(sDir
)+3;
1383 char *string
= malloc(len
);
1384 snprintf(string
, len
, "listall \"%s\"\n", sDir
);
1385 mpd_sendInfoCommand(connection
,string
);
1390 void mpd_sendListallInfoCommand(mpd_Connection
* connection
, const char * dir
) {
1391 char * sDir
= mpd_sanitizeArg(dir
);
1392 int len
= strlen("listallinfo")+2+strlen(sDir
)+3;
1393 char *string
= malloc(len
);
1394 snprintf(string
, len
, "listallinfo \"%s\"\n", sDir
);
1395 mpd_sendInfoCommand(connection
,string
);
1400 void mpd_sendLsInfoCommand(mpd_Connection
* connection
, const char * dir
) {
1401 char * sDir
= mpd_sanitizeArg(dir
);
1402 int len
= strlen("lsinfo")+2+strlen(sDir
)+3;
1403 char *string
= malloc(len
);
1404 snprintf(string
, len
, "lsinfo \"%s\"\n", sDir
);
1405 mpd_sendInfoCommand(connection
,string
);
1410 void mpd_sendCurrentSongCommand(mpd_Connection
* connection
) {
1411 mpd_executeCommand(connection
,"currentsong\n");
1414 void mpd_sendSearchCommand(mpd_Connection
* connection
, int table
,
1417 mpd_startSearch(connection
, 0);
1418 mpd_addConstraintSearch(connection
, table
, str
);
1419 mpd_commitSearch(connection
);
1422 void mpd_sendFindCommand(mpd_Connection
* connection
, int table
,
1425 mpd_startSearch(connection
, 1);
1426 mpd_addConstraintSearch(connection
, table
, str
);
1427 mpd_commitSearch(connection
);
1430 void mpd_sendListCommand(mpd_Connection
* connection
, int table
,
1436 if(table
== MPD_TABLE_ARTIST
) strcpy(st
,"artist");
1437 else if(table
== MPD_TABLE_ALBUM
) strcpy(st
,"album");
1439 connection
->error
= 1;
1440 strcpy(connection
->errorStr
,"unknown table for list");
1444 char * sanitArg1
= mpd_sanitizeArg(arg1
);
1445 len
= strlen("list")+1+strlen(sanitArg1
)+2+strlen(st
)+3;
1446 string
= malloc(len
);
1447 snprintf(string
, len
, "list %s \"%s\"\n", st
, sanitArg1
);
1451 len
= strlen("list")+1+strlen(st
)+2;
1452 string
= malloc(len
);
1453 snprintf(string
, len
, "list %s\n", st
);
1455 mpd_sendInfoCommand(connection
,string
);
1459 void mpd_sendAddCommand(mpd_Connection
* connection
, const char * file
) {
1460 char * sFile
= mpd_sanitizeArg(file
);
1461 int len
= strlen("add")+2+strlen(sFile
)+3;
1462 char *string
= malloc(len
);
1463 snprintf(string
, len
, "add \"%s\"\n", sFile
);
1464 mpd_executeCommand(connection
,string
);
1469 int mpd_sendAddIdCommand(mpd_Connection
*connection
, const char *file
)
1472 char *sFile
= mpd_sanitizeArg(file
);
1473 int len
= strlen("addid")+2+strlen(sFile
)+3;
1474 char *string
= malloc(len
);
1476 snprintf(string
, len
, "addid \"%s\"\n", sFile
);
1477 mpd_sendInfoCommand(connection
, string
);
1481 string
= mpd_getNextReturnElementNamed(connection
, "Id");
1483 retval
= atoi(string
);
1490 void mpd_sendDeleteCommand(mpd_Connection
* connection
, int songPos
) {
1491 int len
= strlen("delete")+2+INTLEN
+3;
1492 char *string
= malloc(len
);
1493 snprintf(string
, len
, "delete \"%i\"\n", songPos
);
1494 mpd_sendInfoCommand(connection
,string
);
1498 void mpd_sendDeleteIdCommand(mpd_Connection
* connection
, int id
) {
1499 int len
= strlen("deleteid")+2+INTLEN
+3;
1500 char *string
= malloc(len
);
1501 snprintf(string
, len
, "deleteid \"%i\"\n", id
);
1502 mpd_sendInfoCommand(connection
,string
);
1506 void mpd_sendSaveCommand(mpd_Connection
* connection
, const char * name
) {
1507 char * sName
= mpd_sanitizeArg(name
);
1508 int len
= strlen("save")+2+strlen(sName
)+3;
1509 char *string
= malloc(len
);
1510 snprintf(string
, len
, "save \"%s\"\n", sName
);
1511 mpd_executeCommand(connection
,string
);
1516 void mpd_sendLoadCommand(mpd_Connection
* connection
, const char * name
) {
1517 char * sName
= mpd_sanitizeArg(name
);
1518 int len
= strlen("load")+2+strlen(sName
)+3;
1519 char *string
= malloc(len
);
1520 snprintf(string
, len
, "load \"%s\"\n", sName
);
1521 mpd_executeCommand(connection
,string
);
1526 void mpd_sendRmCommand(mpd_Connection
* connection
, const char * name
) {
1527 char * sName
= mpd_sanitizeArg(name
);
1528 int len
= strlen("rm")+2+strlen(sName
)+3;
1529 char *string
= malloc(len
);
1530 snprintf(string
, len
, "rm \"%s\"\n", sName
);
1531 mpd_executeCommand(connection
,string
);
1536 void mpd_sendRenameCommand(mpd_Connection
*connection
, const char *from
,
1539 char *sFrom
= mpd_sanitizeArg(from
);
1540 char *sTo
= mpd_sanitizeArg(to
);
1541 int len
= strlen("rename")+2+strlen(sFrom
)+3+strlen(sTo
)+3;
1542 char *string
= malloc(len
);
1543 snprintf(string
, len
, "rename \"%s\" \"%s\"\n", sFrom
, sTo
);
1544 mpd_executeCommand(connection
, string
);
1550 void mpd_sendShuffleCommand(mpd_Connection
* connection
) {
1551 mpd_executeCommand(connection
,"shuffle\n");
1554 void mpd_sendClearCommand(mpd_Connection
* connection
) {
1555 mpd_executeCommand(connection
,"clear\n");
1558 void mpd_sendPlayCommand(mpd_Connection
* connection
, int songPos
) {
1559 int len
= strlen("play")+2+INTLEN
+3;
1560 char *string
= malloc(len
);
1561 snprintf(string
, len
, "play \"%i\"\n", songPos
);
1562 mpd_sendInfoCommand(connection
,string
);
1566 void mpd_sendPlayIdCommand(mpd_Connection
* connection
, int id
) {
1567 int len
= strlen("playid")+2+INTLEN
+3;
1568 char *string
= malloc(len
);
1569 snprintf(string
, len
, "playid \"%i\"\n", id
);
1570 mpd_sendInfoCommand(connection
,string
);
1574 void mpd_sendStopCommand(mpd_Connection
* connection
) {
1575 mpd_executeCommand(connection
,"stop\n");
1578 void mpd_sendPauseCommand(mpd_Connection
* connection
, int pauseMode
) {
1579 int len
= strlen("pause")+2+INTLEN
+3;
1580 char *string
= malloc(len
);
1581 snprintf(string
, len
, "pause \"%i\"\n", pauseMode
);
1582 mpd_executeCommand(connection
,string
);
1586 void mpd_sendNextCommand(mpd_Connection
* connection
) {
1587 mpd_executeCommand(connection
,"next\n");
1590 void mpd_sendMoveCommand(mpd_Connection
* connection
, int from
, int to
) {
1591 int len
= strlen("move")+2+INTLEN
+3+INTLEN
+3;
1592 char *string
= malloc(len
);
1593 snprintf(string
, len
, "move \"%i\" \"%i\"\n", from
, to
);
1594 mpd_sendInfoCommand(connection
,string
);
1598 void mpd_sendMoveIdCommand(mpd_Connection
* connection
, int id
, int to
) {
1599 int len
= strlen("moveid")+2+INTLEN
+3+INTLEN
+3;
1600 char *string
= malloc(len
);
1601 snprintf(string
, len
, "moveid \"%i\" \"%i\"\n", id
, to
);
1602 mpd_sendInfoCommand(connection
,string
);
1606 void mpd_sendSwapCommand(mpd_Connection
* connection
, int song1
, int song2
) {
1607 int len
= strlen("swap")+2+INTLEN
+3+INTLEN
+3;
1608 char *string
= malloc(len
);
1609 snprintf(string
, len
, "swap \"%i\" \"%i\"\n", song1
, song2
);
1610 mpd_sendInfoCommand(connection
,string
);
1614 void mpd_sendSwapIdCommand(mpd_Connection
* connection
, int id1
, int id2
) {
1615 int len
= strlen("swapid")+2+INTLEN
+3+INTLEN
+3;
1616 char *string
= malloc(len
);
1617 snprintf(string
, len
, "swapid \"%i\" \"%i\"\n", id1
, id2
);
1618 mpd_sendInfoCommand(connection
,string
);
1622 void mpd_sendSeekCommand(mpd_Connection
* connection
, int song
, int time
) {
1623 int len
= strlen("seek")+2+INTLEN
+3+INTLEN
+3;
1624 char *string
= malloc(len
);
1625 snprintf(string
, len
, "seek \"%i\" \"%i\"\n", song
, time
);
1626 mpd_sendInfoCommand(connection
,string
);
1630 void mpd_sendSeekIdCommand(mpd_Connection
* connection
, int id
, int time
) {
1631 int len
= strlen("seekid")+2+INTLEN
+3+INTLEN
+3;
1632 char *string
= malloc(len
);
1633 snprintf(string
, len
, "seekid \"%i\" \"%i\"\n", id
, time
);
1634 mpd_sendInfoCommand(connection
,string
);
1638 void mpd_sendUpdateCommand(mpd_Connection
* connection
, char * path
) {
1639 char * sPath
= mpd_sanitizeArg(path
);
1640 int len
= strlen("update")+2+strlen(sPath
)+3;
1641 char *string
= malloc(len
);
1642 snprintf(string
, len
, "update \"%s\"\n", sPath
);
1643 mpd_sendInfoCommand(connection
,string
);
1648 int mpd_getUpdateId(mpd_Connection
* connection
) {
1652 jobid
= mpd_getNextReturnElementNamed(connection
,"updating_db");
1661 void mpd_sendPrevCommand(mpd_Connection
* connection
) {
1662 mpd_executeCommand(connection
,"previous\n");
1665 void mpd_sendRepeatCommand(mpd_Connection
* connection
, int repeatMode
) {
1666 int len
= strlen("repeat")+2+INTLEN
+3;
1667 char *string
= malloc(len
);
1668 snprintf(string
, len
, "repeat \"%i\"\n", repeatMode
);
1669 mpd_executeCommand(connection
,string
);
1673 void mpd_sendRandomCommand(mpd_Connection
* connection
, int randomMode
) {
1674 int len
= strlen("random")+2+INTLEN
+3;
1675 char *string
= malloc(len
);
1676 snprintf(string
, len
, "random \"%i\"\n", randomMode
);
1677 mpd_executeCommand(connection
,string
);
1681 void mpd_sendSetvolCommand(mpd_Connection
* connection
, int volumeChange
) {
1682 int len
= strlen("setvol")+2+INTLEN
+3;
1683 char *string
= malloc(len
);
1684 snprintf(string
, len
, "setvol \"%i\"\n", volumeChange
);
1685 mpd_executeCommand(connection
,string
);
1689 void mpd_sendVolumeCommand(mpd_Connection
* connection
, int volumeChange
) {
1690 int len
= strlen("volume")+2+INTLEN
+3;
1691 char *string
= malloc(len
);
1692 snprintf(string
, len
, "volume \"%i\"\n", volumeChange
);
1693 mpd_executeCommand(connection
,string
);
1697 void mpd_sendCrossfadeCommand(mpd_Connection
* connection
, int seconds
) {
1698 int len
= strlen("crossfade")+2+INTLEN
+3;
1699 char *string
= malloc(len
);
1700 snprintf(string
, len
, "crossfade \"%i\"\n", seconds
);
1701 mpd_executeCommand(connection
,string
);
1705 void mpd_sendPasswordCommand(mpd_Connection
* connection
, const char * pass
) {
1706 char * sPass
= mpd_sanitizeArg(pass
);
1707 int len
= strlen("password")+2+strlen(sPass
)+3;
1708 char *string
= malloc(len
);
1709 snprintf(string
, len
, "password \"%s\"\n", sPass
);
1710 mpd_executeCommand(connection
,string
);
1715 void mpd_sendCommandListBegin(mpd_Connection
* connection
) {
1716 if(connection
->commandList
) {
1717 strcpy(connection
->errorStr
,"already in command list mode");
1718 connection
->error
= 1;
1721 connection
->commandList
= COMMAND_LIST
;
1722 mpd_executeCommand(connection
,"command_list_begin\n");
1725 void mpd_sendCommandListOkBegin(mpd_Connection
* connection
) {
1726 if(connection
->commandList
) {
1727 strcpy(connection
->errorStr
,"already in command list mode");
1728 connection
->error
= 1;
1731 connection
->commandList
= COMMAND_LIST_OK
;
1732 mpd_executeCommand(connection
,"command_list_ok_begin\n");
1733 connection
->listOks
= 0;
1736 void mpd_sendCommandListEnd(mpd_Connection
* connection
) {
1737 if(!connection
->commandList
) {
1738 strcpy(connection
->errorStr
,"not in command list mode");
1739 connection
->error
= 1;
1742 connection
->commandList
= 0;
1743 mpd_executeCommand(connection
,"command_list_end\n");
1746 void mpd_sendOutputsCommand(mpd_Connection
* connection
) {
1747 mpd_executeCommand(connection
,"outputs\n");
1750 mpd_OutputEntity
* mpd_getNextOutput(mpd_Connection
* connection
) {
1751 mpd_OutputEntity
* output
= NULL
;
1753 if(connection
->doneProcessing
|| (connection
->listOks
&&
1754 connection
->doneListOk
))
1759 if(connection
->error
) return NULL
;
1761 output
= malloc(sizeof(mpd_OutputEntity
));
1763 output
->name
= NULL
;
1764 output
->enabled
= 0;
1766 if(!connection
->returnElement
) mpd_getNextReturnElement(connection
);
1768 while(connection
->returnElement
) {
1769 mpd_ReturnElement
* re
= connection
->returnElement
;
1770 if(strcmp(re
->name
,"outputid")==0) {
1771 if(output
!=NULL
&& output
->id
>=0) return output
;
1772 output
->id
= atoi(re
->value
);
1774 else if(strcmp(re
->name
,"outputname")==0) {
1775 output
->name
= strdup(re
->value
);
1777 else if(strcmp(re
->name
,"outputenabled")==0) {
1778 output
->enabled
= atoi(re
->value
);
1781 mpd_getNextReturnElement(connection
);
1782 if(connection
->error
) {
1792 void mpd_sendEnableOutputCommand(mpd_Connection
* connection
, int outputId
) {
1793 int len
= strlen("enableoutput")+2+INTLEN
+3;
1794 char *string
= malloc(len
);
1795 snprintf(string
, len
, "enableoutput \"%i\"\n", outputId
);
1796 mpd_executeCommand(connection
,string
);
1800 void mpd_sendDisableOutputCommand(mpd_Connection
* connection
, int outputId
) {
1801 int len
= strlen("disableoutput")+2+INTLEN
+3;
1802 char *string
= malloc(len
);
1803 snprintf(string
, len
, "disableoutput \"%i\"\n", outputId
);
1804 mpd_executeCommand(connection
,string
);
1808 void mpd_freeOutputElement(mpd_OutputEntity
* output
) {
1814 * mpd_sendNotCommandsCommand
1815 * odd naming, but it gets the not allowed commands
1818 void mpd_sendNotCommandsCommand(mpd_Connection
* connection
)
1820 mpd_executeCommand(connection
, "notcommands\n");
1824 * mpd_sendCommandsCommand
1825 * odd naming, but it gets the allowed commands
1827 void mpd_sendCommandsCommand(mpd_Connection
* connection
)
1829 mpd_executeCommand(connection
, "commands\n");
1833 * Get the next returned command
1835 char * mpd_getNextCommand(mpd_Connection
* connection
)
1837 return mpd_getNextReturnElementNamed(connection
, "command");
1840 void mpd_sendUrlHandlersCommand(mpd_Connection
* connection
)
1842 mpd_executeCommand(connection
, "urlhandlers\n");
1845 char * mpd_getNextHandler(mpd_Connection
* connection
)
1847 return mpd_getNextReturnElementNamed(connection
, "handler");
1850 void mpd_sendTagTypesCommand(mpd_Connection
* connection
)
1852 mpd_executeCommand(connection
, "tagtypes\n");
1855 char * mpd_getNextTagType(mpd_Connection
* connection
)
1857 return mpd_getNextReturnElementNamed(connection
, "tagtype");
1860 void mpd_startSearch(mpd_Connection
*connection
, int exact
)
1862 if (connection
->request
) {
1863 strcpy(connection
->errorStr
, "search already in progress");
1864 connection
->error
= 1;
1868 if (exact
) connection
->request
= strdup("find");
1869 else connection
->request
= strdup("search");
1872 void mpd_startStatsSearch(mpd_Connection
*connection
)
1874 if (connection
->request
) {
1875 strcpy(connection
->errorStr
, "search already in progress");
1876 connection
->error
= 1;
1880 connection
->request
= strdup("count");
1883 void mpd_startPlaylistSearch(mpd_Connection
*connection
, int exact
)
1885 if (connection
->request
) {
1886 strcpy(connection
->errorStr
, "search already in progress");
1887 connection
->error
= 1;
1891 if (exact
) connection
->request
= strdup("playlistfind");
1892 else connection
->request
= strdup("playlistsearch");
1895 void mpd_startFieldSearch(mpd_Connection
*connection
, int type
)
1900 if (connection
->request
) {
1901 strcpy(connection
->errorStr
, "search already in progress");
1902 connection
->error
= 1;
1906 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1907 strcpy(connection
->errorStr
, "invalid type specified");
1908 connection
->error
= 1;
1912 strtype
= mpdTagItemKeys
[type
];
1914 len
= 5+strlen(strtype
)+1;
1915 connection
->request
= malloc(len
);
1917 snprintf(connection
->request
, len
, "list %c%s",
1918 tolower(strtype
[0]), strtype
+1);
1921 void mpd_addConstraintSearch(mpd_Connection
*connection
, int type
, const char *name
)
1928 if (!connection
->request
) {
1929 strcpy(connection
->errorStr
, "no search in progress");
1930 connection
->error
= 1;
1934 if (type
< 0 || type
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1935 strcpy(connection
->errorStr
, "invalid type specified");
1936 connection
->error
= 1;
1941 strcpy(connection
->errorStr
, "no name specified");
1942 connection
->error
= 1;
1946 string
= strdup(connection
->request
);
1947 strtype
= mpdTagItemKeys
[type
];
1948 arg
= mpd_sanitizeArg(name
);
1950 len
= strlen(string
)+1+strlen(strtype
)+2+strlen(arg
)+2;
1951 connection
->request
= realloc(connection
->request
, len
);
1952 snprintf(connection
->request
, len
, "%s %c%s \"%s\"",
1953 string
, tolower(strtype
[0]), strtype
+1, arg
);
1959 void mpd_commitSearch(mpd_Connection
*connection
)
1963 if (!connection
->request
) {
1964 strcpy(connection
->errorStr
, "no search in progress");
1965 connection
->error
= 1;
1969 len
= strlen(connection
->request
)+2;
1970 connection
->request
= realloc(connection
->request
, len
);
1971 connection
->request
[len
-2] = '\n';
1972 connection
->request
[len
-1] = '\0';
1973 mpd_sendInfoCommand(connection
, connection
->request
);
1975 free(connection
->request
);
1976 connection
->request
= NULL
;
1980 * @param connection a MpdConnection
1981 * @param path the path to the playlist.
1983 * List the content, with full metadata, of a stored playlist.
1986 void mpd_sendListPlaylistInfoCommand(mpd_Connection
*connection
, char *path
)
1988 char *arg
= mpd_sanitizeArg(path
);
1989 int len
= strlen("listplaylistinfo")+2+strlen(arg
)+3;
1990 char *query
= malloc(len
);
1991 snprintf(query
, len
, "listplaylistinfo \"%s\"\n", arg
);
1992 mpd_sendInfoCommand(connection
, query
);
1998 * @param connection a MpdConnection
1999 * @param path the path to the playlist.
2001 * List the content of a stored playlist.
2004 void mpd_sendListPlaylistCommand(mpd_Connection
*connection
, char *path
)
2006 char *arg
= mpd_sanitizeArg(path
);
2007 int len
= strlen("listplaylist")+2+strlen(arg
)+3;
2008 char *query
= malloc(len
);
2009 snprintf(query
, len
, "listplaylist \"%s\"\n", arg
);
2010 mpd_sendInfoCommand(connection
, query
);
2015 void mpd_sendPlaylistClearCommand(mpd_Connection
*connection
, char *path
)
2017 char *sPath
= mpd_sanitizeArg(path
);
2018 int len
= strlen("playlistclear")+2+strlen(sPath
)+3;
2019 char *string
= malloc(len
);
2020 snprintf(string
, len
, "playlistclear \"%s\"\n", sPath
);
2021 mpd_executeCommand(connection
, string
);
2026 void mpd_sendPlaylistAddCommand(mpd_Connection
*connection
,
2027 char *playlist
, char *path
)
2029 char *sPlaylist
= mpd_sanitizeArg(playlist
);
2030 char *sPath
= mpd_sanitizeArg(path
);
2031 int len
= strlen("playlistadd")+2+strlen(sPlaylist
)+3+strlen(sPath
)+3;
2032 char *string
= malloc(len
);
2033 snprintf(string
, len
, "playlistadd \"%s\" \"%s\"\n", sPlaylist
, sPath
);
2034 mpd_executeCommand(connection
, string
);
2040 void mpd_sendPlaylistMoveCommand(mpd_Connection
*connection
,
2041 char *playlist
, int from
, int to
)
2043 char *sPlaylist
= mpd_sanitizeArg(playlist
);
2044 int len
= strlen("playlistmove")+
2045 2+strlen(sPlaylist
)+3+INTLEN
+3+INTLEN
+3;
2046 char *string
= malloc(len
);
2047 snprintf(string
, len
, "playlistmove \"%s\" \"%i\" \"%i\"\n",
2048 sPlaylist
, from
, to
);
2049 mpd_executeCommand(connection
, string
);
2054 void mpd_sendPlaylistDeleteCommand(mpd_Connection
*connection
,
2055 char *playlist
, int pos
)
2057 char *sPlaylist
= mpd_sanitizeArg(playlist
);
2058 int len
= strlen("playlistdelete")+2+strlen(sPlaylist
)+3+INTLEN
+3;
2059 char *string
= malloc(len
);
2060 snprintf(string
, len
, "playlistdelete \"%s\" \"%i\"\n", sPlaylist
, pos
);
2061 mpd_executeCommand(connection
, string
);
2065 void mpd_sendClearErrorCommand(mpd_Connection
* connection
) {
2066 mpd_executeCommand(connection
,"clearerror\n");
2070 void mpd_sendGetEventsCommand(mpd_Connection
*connection
) {
2071 mpd_executeCommand(connection
, "idle\nnoidle\n");
2072 // mpd_executeCommand(connection, "noidle\n");
2075 char * mpd_getNextEvent(mpd_Connection
*connection
)
2077 return mpd_getNextReturnElementNamed(connection
, "changed");
2080 void mpd_sendListPlaylistsCommand(mpd_Connection
* connection
) {
2081 mpd_sendInfoCommand(connection
, "listplaylists\n");