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"
36 #include <sys/types.h>
38 #include <sys/param.h>
45 # include <ws2tcpip.h>
48 # include <netinet/in.h>
49 # include <arpa/inet.h>
50 # include <sys/socket.h>
55 # define MSG_DONTWAIT 0
64 #define COMMAND_LIST 1
65 #define COMMAND_LIST_OK 2
68 # define SELECT_ERRNO_IGNORE (errno == WSAEINTR || errno == WSAEINPROGRESS)
69 # define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
71 # define SELECT_ERRNO_IGNORE (errno == EINTR)
72 # define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
73 # define winsock_dll_error(c) 0
74 # define closesocket(s) close(s)
75 # define WSACleanup() do { /* nothing */ } while (0)
79 static int winsock_dll_error(mpd_Connection
* connection
)
82 if ((WSAStartup(MAKEWORD(2, 2), &wsaData
)) != 0 ||
83 LOBYTE(wsaData
.wVersion
) != 2 || HIBYTE(wsaData
.wVersion
) != 2) {
84 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
85 "Could not find usable WinSock DLL.");
86 connection
->error
= MPD_ERROR_SYSTEM
;
92 static int do_connect_fail(mpd_Connection
* connection
,
93 const struct sockaddr
*serv_addr
, int addrlen
)
95 int iMode
= 1; /* 0 = blocking, else non-blocking */
96 ioctlsocket(connection
->sock
, FIONBIO
, (u_long FAR
*) & iMode
);
97 return (connect(connection
->sock
, serv_addr
, addrlen
) == SOCKET_ERROR
98 && WSAGetLastError() != WSAEWOULDBLOCK
);
100 #else /* !WIN32 (sane operating systems) */
101 static int do_connect_fail(mpd_Connection
* connection
,
102 const struct sockaddr
*serv_addr
, int addrlen
)
104 int flags
= fcntl(connection
->sock
, F_GETFL
, 0);
105 fcntl(connection
->sock
, F_SETFL
, flags
| O_NONBLOCK
);
106 return (connect(connection
->sock
, serv_addr
, addrlen
) < 0 &&
107 errno
!= EINPROGRESS
);
112 static int mpd_connect(mpd_Connection
* connection
, const char *host
, int port
,
117 struct addrinfo hints
;
118 struct addrinfo
*res
= NULL
;
119 struct addrinfo
*addrinfo
= NULL
;
124 hints
.ai_flags
= AI_ADDRCONFIG
;
125 hints
.ai_family
= PF_UNSPEC
;
126 hints
.ai_socktype
= SOCK_STREAM
;
127 hints
.ai_protocol
= IPPROTO_TCP
;
128 hints
.ai_addrlen
= 0;
129 hints
.ai_addr
= NULL
;
130 hints
.ai_canonname
= NULL
;
131 hints
.ai_next
= NULL
;
133 snprintf(service
, sizeof(service
), "%d", port
);
135 error
= getaddrinfo(host
, service
, &hints
, &addrinfo
);
138 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
139 "host \"%s\" not found: %s", host
,
140 gai_strerror(error
));
141 connection
->error
= MPD_ERROR_UNKHOST
;
145 for (res
= addrinfo
; res
; res
= res
->ai_next
) {
148 socket(res
->ai_family
, SOCK_STREAM
, res
->ai_protocol
);
149 if (connection
->sock
< 0) {
150 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
151 "problems creating socket: %s",
153 connection
->error
= MPD_ERROR_SYSTEM
;
154 freeaddrinfo(addrinfo
);
158 mpd_setConnectionTimeout(connection
, timeout
);
161 if (do_connect_fail(connection
, res
->ai_addr
, res
->ai_addrlen
)) {
162 /* try the next address family */
163 closesocket(connection
->sock
);
164 connection
->sock
= -1;
168 freeaddrinfo(addrinfo
);
170 if (connection
->sock
< 0) {
171 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
172 "problems connecting to \"%s\" on port"
173 " %i: %s", host
, port
, strerror(errno
));
174 connection
->error
= MPD_ERROR_CONNPORT
;
181 #else /* !MPD_HAVE_GAI */
182 static int mpd_connect(mpd_Connection
* connection
, const char *host
, int port
,
186 struct sockaddr
*dest
;
188 struct sockaddr_in sin
;
190 if (!(he
= gethostbyname(host
))) {
191 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
192 "host \"%s\" not found", host
);
193 connection
->error
= MPD_ERROR_UNKHOST
;
197 memset(&sin
, 0, sizeof(struct sockaddr_in
));
198 /*dest.sin_family = he->h_addrtype; */
199 sin
.sin_family
= AF_INET
;
200 sin
.sin_port
= htons(port
);
202 switch (he
->h_addrtype
) {
204 memcpy((char *)&sin
.sin_addr
.s_addr
, (char *)he
->h_addr
,
206 dest
= (struct sockaddr
*)&sin
;
207 destlen
= sizeof(struct sockaddr_in
);
210 strcpy(connection
->errorStr
, "address type is not IPv4\n");
211 connection
->error
= MPD_ERROR_SYSTEM
;
216 if ((connection
->sock
= socket(dest
->sa_family
, SOCK_STREAM
, 0)) < 0) {
217 strcpy(connection
->errorStr
, "problems creating socket");
218 connection
->error
= MPD_ERROR_SYSTEM
;
222 mpd_setConnectionTimeout(connection
, timeout
);
225 if (do_connect_fail(connection
, dest
, destlen
)) {
226 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
227 "problems connecting to \"%s\" on port"
229 connection
->error
= MPD_ERROR_CONNPORT
;
235 #endif /* !MPD_HAVE_GAI */
237 char *mpdTagItemKeys
[MPD_TAG_NUM_OF_ITEM_TYPES
] = {
252 static char *mpd_sanitizeArg(const char *arg
)
256 register const char *c
;
259 /* instead of counting in that loop above, just
260 * use a bit more memory and half running time
262 ret
= malloc(strlen(arg
) * 2 + 1);
266 for (i
= strlen(arg
) + 1; i
!= 0; --i
) {
267 if (*c
== '"' || *c
== '\\')
275 static mpd_ReturnElement
*mpd_newReturnElement(const char *name
,
278 mpd_ReturnElement
*ret
= malloc(sizeof(mpd_ReturnElement
));
280 ret
->name
= strdup(name
);
281 ret
->value
= strdup(value
);
286 static void mpd_freeReturnElement(mpd_ReturnElement
* re
)
293 void mpd_setConnectionTimeout(mpd_Connection
* connection
, float timeout
)
295 connection
->timeout
.tv_sec
= (int)timeout
;
296 connection
->timeout
.tv_usec
= (int)(timeout
* 1e6
-
297 connection
->timeout
.tv_sec
*
301 static int mpd_parseWelcome(mpd_Connection
* connection
, const char *host
,
302 int port
, char *output
)
308 if (strncmp(output
, MPD_WELCOME_MESSAGE
, strlen(MPD_WELCOME_MESSAGE
))) {
309 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
310 "mpd not running on port %i on host \"%s\"",
312 connection
->error
= MPD_ERROR_NOTMPD
;
316 tmp
= &output
[strlen(MPD_WELCOME_MESSAGE
)];
318 for (i
= 0; i
< 3; i
++) {
320 connection
->version
[i
] = strtol(tmp
, &test
, 10);
322 if (!tmp
|| (test
[0] != '.' && test
[0] != '\0')) {
323 snprintf(connection
->errorStr
,
324 MPD_BUFFER_MAX_LENGTH
,
325 "error parsing version number at "
327 &output
[strlen(MPD_WELCOME_MESSAGE
)]);
328 connection
->error
= MPD_ERROR_NOTMPD
;
337 mpd_Connection
*mpd_newConnection(const char *host
, int port
, float timeout
)
342 mpd_Connection
*connection
= malloc(sizeof(mpd_Connection
));
345 strcpy(connection
->buffer
, "");
346 connection
->buflen
= 0;
347 connection
->bufstart
= 0;
348 strcpy(connection
->errorStr
, "");
349 connection
->error
= 0;
350 connection
->doneProcessing
= 0;
351 connection
->commandList
= 0;
352 connection
->listOks
= 0;
353 connection
->doneListOk
= 0;
354 connection
->returnElement
= NULL
;
355 connection
->request
= NULL
;
357 if (winsock_dll_error(connection
))
360 if (mpd_connect(connection
, host
, port
, timeout
) < 0)
363 while (!(rt
= strstr(connection
->buffer
, "\n"))) {
364 tv
.tv_sec
= connection
->timeout
.tv_sec
;
365 tv
.tv_usec
= connection
->timeout
.tv_usec
;
367 FD_SET(connection
->sock
, &fds
);
369 select(connection
->sock
+ 1, &fds
, NULL
, NULL
,
372 readed
= recv(connection
->sock
,
373 &(connection
->buffer
[connection
->buflen
]),
374 MPD_BUFFER_MAX_LENGTH
-
375 connection
->buflen
, 0);
377 snprintf(connection
->errorStr
,
378 MPD_BUFFER_MAX_LENGTH
,
379 "problems getting a response from"
380 " \"%s\" on port %i : %s", host
, port
,
382 connection
->error
= MPD_ERROR_NORESPONSE
;
385 connection
->buflen
+= readed
;
386 connection
->buffer
[connection
->buflen
] = '\0';
387 } else if (err
< 0) {
388 if (SELECT_ERRNO_IGNORE
)
390 snprintf(connection
->errorStr
,
391 MPD_BUFFER_MAX_LENGTH
,
392 "problems connecting to \"%s\" on port"
394 connection
->error
= MPD_ERROR_CONNPORT
;
397 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
398 "timeout in attempting to get a response from"
399 " \"%s\" on port %i", host
, port
);
400 connection
->error
= MPD_ERROR_NORESPONSE
;
406 output
= strdup(connection
->buffer
);
407 strcpy(connection
->buffer
, rt
+ 1);
408 connection
->buflen
= strlen(connection
->buffer
);
410 if (mpd_parseWelcome(connection
, host
, port
, output
) == 0)
411 connection
->doneProcessing
= 1;
418 void mpd_clearError(mpd_Connection
* connection
)
420 connection
->error
= 0;
421 connection
->errorStr
[0] = '\0';
424 void mpd_closeConnection(mpd_Connection
* connection
)
426 closesocket(connection
->sock
);
427 if (connection
->returnElement
)
428 free(connection
->returnElement
);
429 if (connection
->request
)
430 free(connection
->request
);
435 static void mpd_executeCommand(mpd_Connection
* connection
, char *command
)
440 char *commandPtr
= command
;
441 int commandLen
= strlen(command
);
443 if (!connection
->doneProcessing
&& !connection
->commandList
) {
444 strcpy(connection
->errorStr
,
445 "not done processing current command");
446 connection
->error
= 1;
450 mpd_clearError(connection
);
453 FD_SET(connection
->sock
, &fds
);
454 tv
.tv_sec
= connection
->timeout
.tv_sec
;
455 tv
.tv_usec
= connection
->timeout
.tv_usec
;
457 while ((ret
= select(connection
->sock
+ 1, NULL
, &fds
, NULL
, &tv
) == 1)
458 || (ret
== -1 && SELECT_ERRNO_IGNORE
)) {
460 send(connection
->sock
, commandPtr
, commandLen
,
463 if (SENDRECV_ERRNO_IGNORE
)
465 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
466 "problems giving command \"%s\"", command
);
467 connection
->error
= MPD_ERROR_SENDING
;
478 if (commandLen
> 0) {
480 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
481 "timeout sending command \"%s\"", command
);
482 connection
->error
= MPD_ERROR_TIMEOUT
;
486 if (!connection
->commandList
)
487 connection
->doneProcessing
= 0;
488 else if (connection
->commandList
== COMMAND_LIST_OK
) {
489 connection
->listOks
++;
493 static void mpd_getNextReturnElement(mpd_Connection
* connection
)
503 char *bufferCheck
= NULL
;
507 if (connection
->returnElement
)
508 mpd_freeReturnElement(connection
->returnElement
);
509 connection
->returnElement
= NULL
;
511 if (connection
->doneProcessing
|| (connection
->listOks
&&
512 connection
->doneListOk
)) {
513 strcpy(connection
->errorStr
,
514 "already done processing current command");
515 connection
->error
= 1;
519 bufferCheck
= connection
->buffer
+ connection
->bufstart
;
520 while (connection
->bufstart
>= connection
->buflen
||
521 !(rt
= strchr(bufferCheck
, '\n'))) {
522 if (connection
->buflen
>= MPD_BUFFER_MAX_LENGTH
) {
523 memmove(connection
->buffer
,
525 connection
->bufstart
,
526 connection
->buflen
- connection
->bufstart
+ 1);
527 connection
->buflen
-= connection
->bufstart
;
528 connection
->bufstart
= 0;
530 if (connection
->buflen
>= MPD_BUFFER_MAX_LENGTH
) {
531 strcpy(connection
->errorStr
, "buffer overrun");
532 connection
->error
= MPD_ERROR_BUFFEROVERRUN
;
533 connection
->doneProcessing
= 1;
534 connection
->doneListOk
= 0;
537 bufferCheck
= connection
->buffer
+ connection
->buflen
;
538 tv
.tv_sec
= connection
->timeout
.tv_sec
;
539 tv
.tv_usec
= connection
->timeout
.tv_usec
;
541 FD_SET(connection
->sock
, &fds
);
543 select(connection
->sock
+ 1, &fds
, NULL
, NULL
,
546 recv(connection
->sock
,
547 connection
->buffer
+ connection
->buflen
,
548 MPD_BUFFER_MAX_LENGTH
- connection
->buflen
,
550 if (readed
< 0 && SENDRECV_ERRNO_IGNORE
) {
554 strcpy(connection
->errorStr
, "connection"
556 connection
->error
= MPD_ERROR_CONNCLOSED
;
557 connection
->doneProcessing
= 1;
558 connection
->doneListOk
= 0;
561 connection
->buflen
+= readed
;
562 connection
->buffer
[connection
->buflen
] = '\0';
563 } else if (err
< 0 && SELECT_ERRNO_IGNORE
)
566 strcpy(connection
->errorStr
, "connection timeout");
567 connection
->error
= MPD_ERROR_TIMEOUT
;
568 connection
->doneProcessing
= 1;
569 connection
->doneListOk
= 0;
575 output
= connection
->buffer
+ connection
->bufstart
;
576 connection
->bufstart
= rt
- connection
->buffer
+ 1;
578 if (strcmp(output
, "OK") == 0) {
579 if (connection
->listOks
> 0) {
580 strcpy(connection
->errorStr
, "expected more list_OK's");
581 connection
->error
= 1;
583 connection
->listOks
= 0;
584 connection
->doneProcessing
= 1;
585 connection
->doneListOk
= 0;
589 if (strcmp(output
, "list_OK") == 0) {
590 if (!connection
->listOks
) {
591 strcpy(connection
->errorStr
,
592 "got an unexpected list_OK");
593 connection
->error
= 1;
595 connection
->doneListOk
= 1;
596 connection
->listOks
--;
601 if (strncmp(output
, "ACK", strlen("ACK")) == 0) {
606 strcpy(connection
->errorStr
, output
);
607 connection
->error
= MPD_ERROR_ACK
;
608 connection
->errorCode
= MPD_ACK_ERROR_UNK
;
609 connection
->errorAt
= MPD_ERROR_AT_UNK
;
610 connection
->doneProcessing
= 1;
611 connection
->doneListOk
= 0;
613 needle
= strchr(output
, '[');
616 val
= strtol(needle
+ 1, &test
, 10);
619 connection
->errorCode
= val
;
620 val
= strtol(test
+ 1, &test
, 10);
623 connection
->errorAt
= val
;
627 tok
= strchr(output
, ':');
635 if (value
[0] == ' ') {
636 connection
->returnElement
=
637 mpd_newReturnElement(name
, &(value
[1]));
639 snprintf(connection
->errorStr
, MPD_BUFFER_MAX_LENGTH
,
640 "error parsing: %s:%s", name
, value
);
641 connection
->errorStr
[MPD_BUFFER_MAX_LENGTH
] = '\0';
642 connection
->error
= 1;
646 void mpd_finishCommand(mpd_Connection
* connection
)
648 while (!connection
->doneProcessing
) {
649 if (connection
->doneListOk
)
650 connection
->doneListOk
= 0;
651 mpd_getNextReturnElement(connection
);
655 static void mpd_finishListOkCommand(mpd_Connection
* connection
)
657 while (!connection
->doneProcessing
&& connection
->listOks
&&
658 !connection
->doneListOk
) {
659 mpd_getNextReturnElement(connection
);
663 int mpd_nextListOkCommand(mpd_Connection
* connection
)
665 mpd_finishListOkCommand(connection
);
666 if (!connection
->doneProcessing
)
667 connection
->doneListOk
= 0;
668 if (connection
->listOks
== 0 || connection
->doneProcessing
)
673 void mpd_sendStatusCommand(mpd_Connection
* connection
)
675 mpd_executeCommand(connection
, "status\n");
678 mpd_Status
*mpd_getStatus(mpd_Connection
* connection
)
682 /*mpd_executeCommand(connection,"status\n");
684 if(connection->error) return NULL; */
686 if (connection
->doneProcessing
|| (connection
->listOks
&&
687 connection
->doneListOk
)) {
691 if (!connection
->returnElement
)
692 mpd_getNextReturnElement(connection
);
694 status
= malloc(sizeof(mpd_Status
));
698 /* status->playlist = -1; */
699 status
->playlistLength
= -1;
703 status
->elapsedTime
= 0;
704 status
->totalTime
= 0;
706 status
->sampleRate
= 0;
708 status
->channels
= 0;
709 status
->crossfade
= -1;
710 status
->error
= NULL
;
711 status
->updatingDb
= 0;
713 if (connection
->error
) {
717 while (connection
->returnElement
) {
718 mpd_ReturnElement
*re
= connection
->returnElement
;
719 if (strcmp(re
->name
, "volume") == 0) {
720 status
->volume
= atoi(re
->value
);
721 } else if (strcmp(re
->name
, "repeat") == 0) {
722 status
->repeat
= atoi(re
->value
);
723 } else if (strcmp(re
->name
, "random") == 0) {
724 status
->random
= atoi(re
->value
);
725 /* } else if (strcmp(re->name, "playlist") == 0) {
726 status->playlist = strtol(re->value, NULL, 10); */
727 } else if (strcmp(re
->name
, "playlistlength") == 0) {
728 status
->playlistLength
= atoi(re
->value
);
729 } else if (strcmp(re
->name
, "bitrate") == 0) {
730 status
->bitRate
= atoi(re
->value
);
731 } else if (strcmp(re
->name
, "state") == 0) {
732 if (strcmp(re
->value
, "play") == 0) {
733 status
->state
= MPD_STATUS_STATE_PLAY
;
734 } else if (strcmp(re
->value
, "stop") == 0) {
735 status
->state
= MPD_STATUS_STATE_STOP
;
736 } else if (strcmp(re
->value
, "pause") == 0) {
737 status
->state
= MPD_STATUS_STATE_PAUSE
;
739 status
->state
= MPD_STATUS_STATE_UNKNOWN
;
741 } else if (strcmp(re
->name
, "song") == 0) {
742 status
->song
= atoi(re
->value
);
743 } else if (strcmp(re
->name
, "songid") == 0) {
744 status
->songid
= atoi(re
->value
);
745 } else if (strcmp(re
->name
, "time") == 0) {
746 char *tok
= strchr(re
->value
, ':');
747 /* the second strchr below is a safety check */
748 if (tok
&& (strchr(tok
, 0) > (tok
+ 1))) {
749 /* atoi stops at the first non-[0-9] char: */
750 status
->elapsedTime
= atoi(re
->value
);
751 status
->totalTime
= atoi(tok
+ 1);
753 } else if (strcmp(re
->name
, "error") == 0) {
754 status
->error
= strdup(re
->value
);
755 } else if (strcmp(re
->name
, "xfade") == 0) {
756 status
->crossfade
= atoi(re
->value
);
757 } else if (strcmp(re
->name
, "updating_db") == 0) {
758 status
->updatingDb
= atoi(re
->value
);
759 } else if (strcmp(re
->name
, "audio") == 0) {
760 char *tok
= strchr(re
->value
, ':');
761 if (tok
&& (strchr(tok
, 0) > (tok
+ 1))) {
762 status
->sampleRate
= atoi(re
->value
);
763 status
->bits
= atoi(++tok
);
764 tok
= strchr(tok
, ':');
765 if (tok
&& (strchr(tok
, 0) > (tok
+ 1)))
766 status
->channels
= atoi(tok
+ 1);
770 mpd_getNextReturnElement(connection
);
771 if (connection
->error
) {
777 if (connection
->error
) {
780 } else if (status
->state
< 0) {
781 strcpy(connection
->errorStr
, "state not found");
782 connection
->error
= 1;
790 void mpd_freeStatus(mpd_Status
* status
)
797 void mpd_sendStatsCommand(mpd_Connection
* connection
)
799 mpd_executeCommand(connection
, "stats\n");
802 mpd_Stats
*mpd_getStats(mpd_Connection
* connection
)
806 /*mpd_executeCommand(connection,"stats\n");
808 if(connection->error) return NULL; */
810 if (connection
->doneProcessing
|| (connection
->listOks
&&
811 connection
->doneListOk
)) {
815 if (!connection
->returnElement
)
816 mpd_getNextReturnElement(connection
);
818 stats
= malloc(sizeof(mpd_Stats
));
819 stats
->numberOfArtists
= 0;
820 stats
->numberOfAlbums
= 0;
821 stats
->numberOfSongs
= 0;
823 stats
->dbUpdateTime
= 0;
825 stats
->dbPlayTime
= 0;
827 if (connection
->error
) {
831 while (connection
->returnElement
) {
832 mpd_ReturnElement
*re
= connection
->returnElement
;
833 if (strcmp(re
->name
, "artists") == 0) {
834 stats
->numberOfArtists
= atoi(re
->value
);
835 } else if (strcmp(re
->name
, "albums") == 0) {
836 stats
->numberOfAlbums
= atoi(re
->value
);
837 } else if (strcmp(re
->name
, "songs") == 0) {
838 stats
->numberOfSongs
= atoi(re
->value
);
839 } else if (strcmp(re
->name
, "uptime") == 0) {
840 stats
->uptime
= strtol(re
->value
, NULL
, 10);
841 } else if (strcmp(re
->name
, "db_update") == 0) {
842 stats
->dbUpdateTime
= strtol(re
->value
, NULL
, 10);
843 } else if (strcmp(re
->name
, "playtime") == 0) {
844 stats
->playTime
= strtol(re
->value
, NULL
, 10);
845 } else if (strcmp(re
->name
, "db_playtime") == 0) {
846 stats
->dbPlayTime
= strtol(re
->value
, NULL
, 10);
849 mpd_getNextReturnElement(connection
);
850 if (connection
->error
) {
856 if (connection
->error
) {
864 void mpd_freeStats(mpd_Stats
* stats
)
871 static void mpd_initSong(mpd_Song
* song
)
882 song
->composer
= NULL
;
884 song
->comment
= NULL
;
886 song
->time
= MPD_SONG_NO_TIME
;
887 song
->pos
= MPD_SONG_NO_NUM
;
888 song
->id
= MPD_SONG_NO_ID
;
891 static void mpd_finishSong(mpd_Song
* song
)
910 free(song
->composer
);
917 mpd_Song
*mpd_newSong(void)
919 mpd_Song
*ret
= malloc(sizeof(mpd_Song
));
926 void mpd_freeSong(mpd_Song
* song
)
928 mpd_finishSong(song
);
932 mpd_Song
*mpd_songDup(mpd_Song
* song
)
934 mpd_Song
*ret
= mpd_newSong();
937 ret
->file
= strdup(song
->file
);
939 ret
->artist
= strdup(song
->artist
);
941 ret
->album
= strdup(song
->album
);
943 ret
->title
= strdup(song
->title
);
945 ret
->track
= strdup(song
->track
);
947 ret
->name
= strdup(song
->name
);
949 ret
->date
= strdup(song
->date
);
951 ret
->genre
= strdup(song
->genre
);
953 ret
->composer
= strdup(song
->composer
);
955 ret
->disc
= strdup(song
->disc
);
957 ret
->comment
= strdup(song
->comment
);
958 ret
->time
= song
->time
;
959 ret
->pos
= song
->pos
;
965 static void mpd_initDirectory(mpd_Directory
* directory
)
967 directory
->path
= NULL
;
969 static void mpd_finishDirectory(mpd_Directory
* directory
)
972 free(directory
->path
);
975 mpd_Directory
*mpd_newDirectory(void)
977 mpd_Directory
*directory
= malloc(sizeof(mpd_Directory
));;
979 mpd_initDirectory(directory
);
984 void mpd_freeDirectory(mpd_Directory
* directory
)
986 mpd_finishDirectory(directory
);
991 mpd_Directory
*mpd_directoryDup(mpd_Directory
* directory
)
993 mpd_Directory
*ret
= mpd_newDirectory();
996 ret
->path
= strdup(directory
->path
);
1000 static void mpd_initPlaylistFile(mpd_PlaylistFile
* playlist
)
1002 playlist
->path
= NULL
;
1005 static void mpd_finishPlaylistFile(mpd_PlaylistFile
* playlist
)
1008 free(playlist
->path
);
1011 mpd_PlaylistFile
*mpd_newPlaylistFile(void)
1013 mpd_PlaylistFile
*playlist
= malloc(sizeof(mpd_PlaylistFile
));
1015 mpd_initPlaylistFile(playlist
);
1019 void mpd_freePlaylistFile(mpd_PlaylistFile
* playlist
)
1021 mpd_finishPlaylistFile(playlist
);
1024 mpd_PlaylistFile
*mpd_playlistFileDup(mpd_PlaylistFile
* playlist
)
1026 mpd_PlaylistFile
*ret
= mpd_newPlaylistFile();
1029 ret
->path
= strdup(playlist
->path
);
1035 static void mpd_initInfoEntity(mpd_InfoEntity
* entity
)
1037 entity
->info
.directory
= NULL
;
1040 static void mpd_finishInfoEntity(mpd_InfoEntity
* entity
)
1042 if (entity
->info
.directory
) {
1044 if (entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1045 mpd_freeDirectory(entity
->info
.directory
);
1048 if (entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
)
1049 mpd_freeSong(entity
->info
.song
);
1051 } else if (entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1052 mpd_freePlaylistFile(entity
->info
.playlistFile
);
1058 mpd_InfoEntity
*mpd_newInfoEntity(void)
1060 mpd_InfoEntity
*entity
= malloc(sizeof(mpd_InfoEntity
));
1062 mpd_initInfoEntity(entity
);
1067 void mpd_freeInfoEntity(mpd_InfoEntity
* entity
)
1069 mpd_finishInfoEntity(entity
);
1073 static void mpd_sendInfoCommand(mpd_Connection
* connection
, char *command
)
1075 mpd_executeCommand(connection
, command
);
1078 mpd_InfoEntity
*mpd_getNextInfoEntity(mpd_Connection
* connection
)
1080 mpd_InfoEntity
*entity
= NULL
;
1082 if (connection
->doneProcessing
|| (connection
->listOks
&&
1083 connection
->doneListOk
)) {
1087 if (!connection
->returnElement
)
1088 mpd_getNextReturnElement(connection
);
1090 if (connection
->returnElement
) {
1091 if (strcmp(connection
->returnElement
->name
, "file") == 0) {
1092 entity
= mpd_newInfoEntity();
1093 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1094 entity
->info
.song
= mpd_newSong();
1095 entity
->info
.song
->file
=
1096 strdup(connection
->returnElement
->value
);
1098 } else if (strcmp(connection
->returnElement
->name
,
1099 "directory") == 0) {
1100 entity
= mpd_newInfoEntity();
1101 entity
->type
= MPD_INFO_ENTITY_TYPE_DIRECTORY
;
1102 entity
->info
.directory
= mpd_newDirectory();
1103 entity
->info
.directory
->path
=
1104 strdup(connection
->returnElement
->value
);
1105 } else if (strcmp(connection
->returnElement
->name
, "playlist")
1107 entity
= mpd_newInfoEntity();
1108 entity
->type
= MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
;
1109 entity
->info
.playlistFile
= mpd_newPlaylistFile();
1110 entity
->info
.playlistFile
->path
=
1111 strdup(connection
->returnElement
->value
);
1113 } else if (strcmp(connection
->returnElement
->name
, "cpos") == 0) {
1114 entity
= mpd_newInfoEntity();
1115 entity
->type
= MPD_INFO_ENTITY_TYPE_SONG
;
1116 entity
->info
.song
= mpd_newSong();
1117 entity
->info
.song
->pos
=
1118 atoi(connection
->returnElement
->value
);
1120 connection
->error
= 1;
1121 strcpy(connection
->errorStr
,
1122 "problem parsing song info");
1128 mpd_getNextReturnElement(connection
);
1129 while (connection
->returnElement
) {
1130 mpd_ReturnElement
*re
= connection
->returnElement
;
1132 if (strcmp(re
->name
, "file") == 0)
1134 else if (strcmp(re
->name
, "directory") == 0)
1136 else if (strcmp(re
->name
, "playlist") == 0)
1138 else if (strcmp(re
->name
, "cpos") == 0)
1141 if (entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
&&
1142 strlen(re
->value
)) {
1143 if (!entity
->info
.song
->artist
&&
1144 strcmp(re
->name
, "Artist") == 0) {
1145 entity
->info
.song
->artist
= strdup(re
->value
);
1146 } else if (!entity
->info
.song
->album
&&
1147 strcmp(re
->name
, "Album") == 0) {
1148 entity
->info
.song
->album
= strdup(re
->value
);
1149 } else if (!entity
->info
.song
->title
&&
1150 strcmp(re
->name
, "Title") == 0) {
1151 entity
->info
.song
->title
= strdup(re
->value
);
1152 } else if (!entity
->info
.song
->track
&&
1153 strcmp(re
->name
, "Track") == 0) {
1154 entity
->info
.song
->track
= strdup(re
->value
);
1155 } else if (!entity
->info
.song
->name
&&
1156 strcmp(re
->name
, "Name") == 0) {
1157 entity
->info
.song
->name
= strdup(re
->value
);
1158 } else if (entity
->info
.song
->time
== MPD_SONG_NO_TIME
1159 && strcmp(re
->name
, "Time") == 0) {
1160 entity
->info
.song
->time
= atoi(re
->value
);
1161 } else if (entity
->info
.song
->pos
== MPD_SONG_NO_NUM
&&
1162 strcmp(re
->name
, "Pos") == 0) {
1163 entity
->info
.song
->pos
= atoi(re
->value
);
1164 } else if (entity
->info
.song
->id
== MPD_SONG_NO_ID
&&
1165 strcmp(re
->name
, "Id") == 0) {
1166 entity
->info
.song
->id
= atoi(re
->value
);
1167 } else if (!entity
->info
.song
->date
&&
1168 strcmp(re
->name
, "Date") == 0) {
1169 entity
->info
.song
->date
= strdup(re
->value
);
1170 } else if (!entity
->info
.song
->genre
&&
1171 strcmp(re
->name
, "Genre") == 0) {
1172 entity
->info
.song
->genre
= strdup(re
->value
);
1173 } else if (!entity
->info
.song
->composer
&&
1174 strcmp(re
->name
, "Composer") == 0) {
1175 entity
->info
.song
->composer
= strdup(re
->value
);
1176 } else if (!entity
->info
.song
->disc
&&
1177 strcmp(re
->name
, "Disc") == 0) {
1178 entity
->info
.song
->disc
= strdup(re
->value
);
1179 } else if (!entity
->info
.song
->comment
&&
1180 strcmp(re
->name
, "Comment") == 0) {
1181 entity
->info
.song
->comment
= strdup(re
->value
);
1183 } else if (entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
1184 } else if (entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
1187 mpd_getNextReturnElement(connection
);
1193 static char *mpd_getNextReturnElementNamed(mpd_Connection
* connection
,
1196 if (connection
->doneProcessing
|| (connection
->listOks
&&
1197 connection
->doneListOk
)) {
1201 mpd_getNextReturnElement(connection
);
1202 while (connection
->returnElement
) {
1203 mpd_ReturnElement
*re
= connection
->returnElement
;
1205 if (strcmp(re
->name
, name
) == 0)
1206 return strdup(re
->value
);
1207 mpd_getNextReturnElement(connection
);
1213 char *mpd_getNextTag(mpd_Connection
* connection
, int table
)
1215 if (table
>= 0 && table
< MPD_TAG_NUM_OF_ITEM_TYPES
) {
1216 return mpd_getNextReturnElementNamed(connection
,
1217 mpdTagItemKeys
[table
]);
1222 char *mpd_getNextArtist(mpd_Connection
* connection
)
1224 return mpd_getNextReturnElementNamed(connection
, "Artist");
1227 char *mpd_getNextAlbum(mpd_Connection
* connection
)
1229 return mpd_getNextReturnElementNamed(connection
, "Album");
1232 void mpd_sendPlaylistInfoCommand(mpd_Connection
* connection
, int songPos
)
1234 char *string
= malloc(strlen("playlistinfo") + 25);
1235 sprintf(string
, "playlistinfo \"%i\"\n", songPos
);
1236 mpd_sendInfoCommand(connection
, string
);
1240 void mpd_sendPlaylistIdCommand(mpd_Connection
* connection
, int id
)
1242 char *string
= malloc(strlen("playlistid") + 25);
1243 sprintf(string
, "playlistid \"%i\"\n", id
);
1244 mpd_sendInfoCommand(connection
, string
);
1248 void mpd_sendPlChangesCommand(mpd_Connection
* connection
, long long playlist
)
1250 char *string
= malloc(strlen("plchanges") + 25);
1251 sprintf(string
, "plchanges \"%lld\"\n", playlist
);
1252 mpd_sendInfoCommand(connection
, string
);
1256 void mpd_sendPlChangesPosIdCommand(mpd_Connection
* connection
,
1259 char *string
= malloc(strlen("plchangesposid") + 25);
1260 sprintf(string
, "plchangesposid \"%lld\"\n", playlist
);
1261 mpd_sendInfoCommand(connection
, string
);
1265 void mpd_sendListallCommand(mpd_Connection
* connection
, const char *dir
)
1267 char *sDir
= mpd_sanitizeArg(dir
);
1268 char *string
= malloc(strlen("listall") + strlen(sDir
) + 5);
1269 sprintf(string
, "listall \"%s\"\n", sDir
);
1270 mpd_sendInfoCommand(connection
, string
);
1275 void mpd_sendListallInfoCommand(mpd_Connection
* connection
, const char *dir
)
1277 char *sDir
= mpd_sanitizeArg(dir
);
1278 char *string
= malloc(strlen("listallinfo") + strlen(sDir
) + 5);
1279 sprintf(string
, "listallinfo \"%s\"\n", sDir
);
1280 mpd_sendInfoCommand(connection
, string
);
1285 void mpd_sendLsInfoCommand(mpd_Connection
* connection
, const char *dir
)
1287 char *sDir
= mpd_sanitizeArg(dir
);
1288 char *string
= malloc(strlen("lsinfo") + strlen(sDir
) + 5);
1289 sprintf(string
, "lsinfo \"%s\"\n", sDir
);
1290 mpd_sendInfoCommand(connection
, string
);
1295 void mpd_sendCurrentSongCommand(mpd_Connection
* connection
)
1297 mpd_executeCommand(connection
, "currentsong\n");
1300 void mpd_sendSearchCommand(mpd_Connection
* connection
, int table
,
1305 char *sanitStr
= mpd_sanitizeArg(str
);
1306 if (table
== MPD_TABLE_ARTIST
)
1307 strcpy(st
, "artist");
1308 else if (table
== MPD_TABLE_ALBUM
)
1309 strcpy(st
, "album");
1310 else if (table
== MPD_TABLE_TITLE
)
1311 strcpy(st
, "title");
1312 else if (table
== MPD_TABLE_FILENAME
)
1313 strcpy(st
, "filename");
1315 connection
->error
= 1;
1316 strcpy(connection
->errorStr
, "unknown table for search");
1319 string
= malloc(strlen("search") + strlen(sanitStr
) + strlen(st
) + 6);
1320 sprintf(string
, "search %s \"%s\"\n", st
, sanitStr
);
1321 mpd_sendInfoCommand(connection
, string
);
1326 void mpd_sendFindCommand(mpd_Connection
* connection
, int table
,
1331 char *sanitStr
= mpd_sanitizeArg(str
);
1332 if (table
== MPD_TABLE_ARTIST
)
1333 strcpy(st
, "artist");
1334 else if (table
== MPD_TABLE_ALBUM
)
1335 strcpy(st
, "album");
1336 else if (table
== MPD_TABLE_TITLE
)
1337 strcpy(st
, "title");
1339 connection
->error
= 1;
1340 strcpy(connection
->errorStr
, "unknown table for find");
1343 string
= malloc(strlen("find") + strlen(sanitStr
) + strlen(st
) + 6);
1344 sprintf(string
, "find %s \"%s\"\n", st
, sanitStr
);
1345 mpd_sendInfoCommand(connection
, string
);
1350 void mpd_sendListCommand(mpd_Connection
* connection
, int table
,
1355 if (table
== MPD_TABLE_ARTIST
)
1356 strcpy(st
, "artist");
1357 else if (table
== MPD_TABLE_ALBUM
)
1358 strcpy(st
, "album");
1360 connection
->error
= 1;
1361 strcpy(connection
->errorStr
, "unknown table for list");
1365 char *sanitArg1
= mpd_sanitizeArg(arg1
);
1367 malloc(strlen("list") + strlen(sanitArg1
) + strlen(st
) + 6);
1368 sprintf(string
, "list %s \"%s\"\n", st
, sanitArg1
);
1371 string
= malloc(strlen("list") + strlen(st
) + 3);
1372 sprintf(string
, "list %s\n", st
);
1374 mpd_sendInfoCommand(connection
, string
);
1378 void mpd_sendAddCommand(mpd_Connection
* connection
, const char *file
)
1380 char *sFile
= mpd_sanitizeArg(file
);
1381 char *string
= malloc(strlen("add") + strlen(sFile
) + 5);
1382 sprintf(string
, "add \"%s\"\n", sFile
);
1383 mpd_executeCommand(connection
, string
);
1388 void mpd_sendDeleteCommand(mpd_Connection
* connection
, int songPos
)
1390 char *string
= malloc(strlen("delete") + 25);
1391 sprintf(string
, "delete \"%i\"\n", songPos
);
1392 mpd_sendInfoCommand(connection
, string
);
1396 void mpd_sendDeleteIdCommand(mpd_Connection
* connection
, int id
)
1398 char *string
= malloc(strlen("deleteid") + 25);
1399 sprintf(string
, "deleteid \"%i\"\n", id
);
1400 mpd_sendInfoCommand(connection
, string
);
1404 void mpd_sendSaveCommand(mpd_Connection
* connection
, const char *name
)
1406 char *sName
= mpd_sanitizeArg(name
);
1407 char *string
= malloc(strlen("save") + strlen(sName
) + 5);
1408 sprintf(string
, "save \"%s\"\n", sName
);
1409 mpd_executeCommand(connection
, string
);
1414 void mpd_sendLoadCommand(mpd_Connection
* connection
, const char *name
)
1416 char *sName
= mpd_sanitizeArg(name
);
1417 char *string
= malloc(strlen("load") + strlen(sName
) + 5);
1418 sprintf(string
, "load \"%s\"\n", sName
);
1419 mpd_executeCommand(connection
, string
);
1424 void mpd_sendRmCommand(mpd_Connection
* connection
, const char *name
)
1426 char *sName
= mpd_sanitizeArg(name
);
1427 char *string
= malloc(strlen("rm") + strlen(sName
) + 5);
1428 sprintf(string
, "rm \"%s\"\n", sName
);
1429 mpd_executeCommand(connection
, string
);
1434 void mpd_sendShuffleCommand(mpd_Connection
* connection
)
1436 mpd_executeCommand(connection
, "shuffle\n");
1439 void mpd_sendClearCommand(mpd_Connection
* connection
)
1441 mpd_executeCommand(connection
, "clear\n");
1444 void mpd_sendPlayCommand(mpd_Connection
* connection
, int songPos
)
1446 char *string
= malloc(strlen("play") + 25);
1447 sprintf(string
, "play \"%i\"\n", songPos
);
1448 mpd_sendInfoCommand(connection
, string
);
1452 void mpd_sendPlayIdCommand(mpd_Connection
* connection
, int id
)
1454 char *string
= malloc(strlen("playid") + 25);
1455 sprintf(string
, "playid \"%i\"\n", id
);
1456 mpd_sendInfoCommand(connection
, string
);
1460 void mpd_sendStopCommand(mpd_Connection
* connection
)
1462 mpd_executeCommand(connection
, "stop\n");
1465 void mpd_sendPauseCommand(mpd_Connection
* connection
, int pauseMode
)
1467 char *string
= malloc(strlen("pause") + 25);
1468 sprintf(string
, "pause \"%i\"\n", pauseMode
);
1469 mpd_executeCommand(connection
, string
);
1473 void mpd_sendNextCommand(mpd_Connection
* connection
)
1475 mpd_executeCommand(connection
, "next\n");
1478 void mpd_sendMoveCommand(mpd_Connection
* connection
, int from
, int to
)
1480 char *string
= malloc(strlen("move") + 25);
1481 sprintf(string
, "move \"%i\" \"%i\"\n", from
, to
);
1482 mpd_sendInfoCommand(connection
, string
);
1486 void mpd_sendMoveIdCommand(mpd_Connection
* connection
, int id
, int to
)
1488 char *string
= malloc(strlen("moveid") + 25);
1489 sprintf(string
, "moveid \"%i\" \"%i\"\n", id
, to
);
1490 mpd_sendInfoCommand(connection
, string
);
1494 void mpd_sendSwapCommand(mpd_Connection
* connection
, int song1
, int song2
)
1496 char *string
= malloc(strlen("swap") + 25);
1497 sprintf(string
, "swap \"%i\" \"%i\"\n", song1
, song2
);
1498 mpd_sendInfoCommand(connection
, string
);
1502 void mpd_sendSwapIdCommand(mpd_Connection
* connection
, int id1
, int id2
)
1504 char *string
= malloc(strlen("swapid") + 25);
1505 sprintf(string
, "swapid \"%i\" \"%i\"\n", id1
, id2
);
1506 mpd_sendInfoCommand(connection
, string
);
1510 void mpd_sendSeekCommand(mpd_Connection
* connection
, int song
, int time
)
1512 char *string
= malloc(strlen("seek") + 25);
1513 sprintf(string
, "seek \"%i\" \"%i\"\n", song
, time
);
1514 mpd_sendInfoCommand(connection
, string
);
1518 void mpd_sendSeekIdCommand(mpd_Connection
* connection
, int id
, int time
)
1520 char *string
= malloc(strlen("seekid") + 25);
1521 sprintf(string
, "seekid \"%i\" \"%i\"\n", id
, time
);
1522 mpd_sendInfoCommand(connection
, string
);
1526 void mpd_sendUpdateCommand(mpd_Connection
* connection
, char *path
)
1528 char *sPath
= mpd_sanitizeArg(path
);
1529 char *string
= malloc(strlen("update") + strlen(sPath
) + 5);
1530 sprintf(string
, "update \"%s\"\n", sPath
);
1531 mpd_sendInfoCommand(connection
, string
);
1536 int mpd_getUpdateId(mpd_Connection
* connection
)
1541 jobid
= mpd_getNextReturnElementNamed(connection
, "updating_db");
1550 void mpd_sendPrevCommand(mpd_Connection
* connection
)
1552 mpd_executeCommand(connection
, "previous\n");
1555 void mpd_sendRepeatCommand(mpd_Connection
* connection
, int repeatMode
)
1557 char *string
= malloc(strlen("repeat") + 25);
1558 sprintf(string
, "repeat \"%i\"\n", repeatMode
);
1559 mpd_executeCommand(connection
, string
);
1563 void mpd_sendRandomCommand(mpd_Connection
* connection
, int randomMode
)
1565 char *string
= malloc(strlen("random") + 25);
1566 sprintf(string
, "random \"%i\"\n", randomMode
);
1567 mpd_executeCommand(connection
, string
);
1571 void mpd_sendSetvolCommand(mpd_Connection
* connection
, int volumeChange
)
1573 char *string
= malloc(strlen("setvol") + 25);
1574 sprintf(string
, "setvol \"%i\"\n", volumeChange
);
1575 mpd_executeCommand(connection
, string
);
1579 void mpd_sendVolumeCommand(mpd_Connection
* connection
, int volumeChange
)
1581 char *string
= malloc(strlen("volume") + 25);
1582 sprintf(string
, "volume \"%i\"\n", volumeChange
);
1583 mpd_executeCommand(connection
, string
);
1587 void mpd_sendCrossfadeCommand(mpd_Connection
* connection
, int seconds
)
1589 char *string
= malloc(strlen("crossfade") + 25);
1590 sprintf(string
, "crossfade \"%i\"\n", seconds
);
1591 mpd_executeCommand(connection
, string
);
1595 void mpd_sendPasswordCommand(mpd_Connection
* connection
, const char *pass
)
1597 char *sPass
= mpd_sanitizeArg(pass
);
1598 char *string
= malloc(strlen("password") + strlen(sPass
) + 5);
1599 sprintf(string
, "password \"%s\"\n", sPass
);
1600 mpd_executeCommand(connection
, string
);
1605 void mpd_sendCommandListBegin(mpd_Connection
* connection
)
1607 if (connection
->commandList
) {
1608 strcpy(connection
->errorStr
, "already in command list mode");
1609 connection
->error
= 1;
1612 connection
->commandList
= COMMAND_LIST
;
1613 mpd_executeCommand(connection
, "command_list_begin\n");
1616 void mpd_sendCommandListOkBegin(mpd_Connection
* connection
)
1618 if (connection
->commandList
) {
1619 strcpy(connection
->errorStr
, "already in command list mode");
1620 connection
->error
= 1;
1623 connection
->commandList
= COMMAND_LIST_OK
;
1624 mpd_executeCommand(connection
, "command_list_ok_begin\n");
1625 connection
->listOks
= 0;
1628 void mpd_sendCommandListEnd(mpd_Connection
* connection
)
1630 if (!connection
->commandList
) {
1631 strcpy(connection
->errorStr
, "not in command list mode");
1632 connection
->error
= 1;
1635 connection
->commandList
= 0;
1636 mpd_executeCommand(connection
, "command_list_end\n");
1639 void mpd_sendOutputsCommand(mpd_Connection
* connection
)
1641 mpd_executeCommand(connection
, "outputs\n");
1644 mpd_OutputEntity
*mpd_getNextOutput(mpd_Connection
* connection
)
1646 mpd_OutputEntity
*output
= NULL
;
1648 if (connection
->doneProcessing
|| (connection
->listOks
&&
1649 connection
->doneListOk
)) {
1653 if (connection
->error
)
1656 output
= malloc(sizeof(mpd_OutputEntity
));
1658 output
->name
= NULL
;
1659 output
->enabled
= 0;
1661 if (!connection
->returnElement
)
1662 mpd_getNextReturnElement(connection
);
1664 while (connection
->returnElement
) {
1665 mpd_ReturnElement
*re
= connection
->returnElement
;
1666 if (strcmp(re
->name
, "outputid") == 0) {
1667 if (output
!= NULL
&& output
->id
>= 0)
1669 output
->id
= atoi(re
->value
);
1670 } else if (strcmp(re
->name
, "outputname") == 0) {
1671 output
->name
= strdup(re
->value
);
1672 } else if (strcmp(re
->name
, "outputenabled") == 0) {
1673 output
->enabled
= atoi(re
->value
);
1676 mpd_getNextReturnElement(connection
);
1677 if (connection
->error
) {
1687 void mpd_sendEnableOutputCommand(mpd_Connection
* connection
, int outputId
)
1689 char *string
= malloc(strlen("enableoutput") + 25);
1690 sprintf(string
, "enableoutput \"%i\"\n", outputId
);
1691 mpd_executeCommand(connection
, string
);
1695 void mpd_sendDisableOutputCommand(mpd_Connection
* connection
, int outputId
)
1697 char *string
= malloc(strlen("disableoutput") + 25);
1698 sprintf(string
, "disableoutput \"%i\"\n", outputId
);
1699 mpd_executeCommand(connection
, string
);
1703 void mpd_freeOutputElement(mpd_OutputEntity
* output
)
1710 * mpd_sendNotCommandsCommand
1711 * odd naming, but it gets the not allowed commands
1714 void mpd_sendNotCommandsCommand(mpd_Connection
* connection
)
1716 mpd_executeCommand(connection
, "notcommands\n");
1720 * mpd_sendCommandsCommand
1721 * odd naming, but it gets the allowed commands
1724 void mpd_sendCommandsCommand(mpd_Connection
* connection
)
1726 mpd_executeCommand(connection
, "commands\n");
1730 * Get the next returned command
1732 char *mpd_getNextCommand(mpd_Connection
* connection
)
1734 return mpd_getNextReturnElementNamed(connection
, "command");
1737 void mpd_startSearch(mpd_Connection
* connection
, int exact
)
1739 if (connection
->request
) {
1740 /* search/find allready in progress */
1741 /* TODO: set error here? */
1745 connection
->request
= strdup("find");
1747 connection
->request
= strdup("search");
1751 void mpd_startFieldSearch(mpd_Connection
* connection
, int field
)
1753 if (connection
->request
) {
1754 /* search/find allready in progress */
1755 /* TODO: set error here? */
1758 if (field
< 0 || field
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1759 /* set error here */
1763 connection
->request
= malloc(sizeof(char) * (
1764 /* length of the field name */
1768 /* "list"+space+\0 */
1770 sprintf(connection
->request
, "list %s", mpdTagItemKeys
[field
]);
1773 void mpd_addConstraintSearch(mpd_Connection
* connection
, int field
, char *name
)
1776 if (!connection
->request
) {
1782 if (field
< 0 || field
>= MPD_TAG_NUM_OF_ITEM_TYPES
) {
1785 /* clean up the query */
1786 arg
= mpd_sanitizeArg(name
);
1787 /* create space for the query */
1788 connection
->request
= realloc(connection
->request
, (
1789 /* length of the old string */
1795 /* length of the field name */
1799 /* space plus starting " */
1801 /* length of search term */
1803 /* closign " +\0 that is added sprintf */
1806 /* and form the query */
1807 sprintf(connection
->request
, "%s %s \"%s\"",
1808 connection
->request
, mpdTagItemKeys
[field
], arg
);
1812 void mpd_commitSearch(mpd_Connection
* connection
)
1814 if (connection
->request
) {
1815 int length
= strlen(connection
->request
);
1816 /* fixing up the string for mpd to like */
1817 connection
->request
= realloc(connection
->request
, (length
+ /* old length */
1818 2 /* closing \n and \0 */
1820 connection
->request
[length
] = '\n';
1821 connection
->request
[length
+ 1] = '\0';
1823 mpd_sendInfoCommand(connection
, connection
->request
);
1824 /* clean up a bit */
1825 free(connection
->request
);
1826 connection
->request
= NULL
;
1831 * @param connection a MpdConnection
1832 * @param path the path to the playlist.
1834 * List the content, with full metadata, of a stored playlist.
1837 void mpd_sendListPlaylistInfoCommand(mpd_Connection
* connection
, char *path
)
1839 char *arg
= mpd_sanitizeArg(path
);
1840 char *query
= malloc(strlen("listplaylistinfo") + strlen(arg
) + 5);
1841 sprintf(query
, "listplaylistinfo \"%s\"\n", arg
);
1842 mpd_sendInfoCommand(connection
, query
);
1848 * @param connection a MpdConnection
1849 * @param path the path to the playlist.
1851 * List the content of a stored playlist.
1854 void mpd_sendListPlaylistCommand(mpd_Connection
* connection
, char *path
)
1856 char *arg
= mpd_sanitizeArg(path
);
1857 char *query
= malloc(strlen("listplaylist") + strlen(arg
) + 5);
1858 sprintf(query
, "listplaylist \"%s\"\n", arg
);
1859 mpd_sendInfoCommand(connection
, query
);