Much disabled from libmpdclient that results in smaller binaries
[state-utils.git] / src / libmpdclient.c
blob66692868d6d21ce7aecf84bd8cd0dd259a5d1834
1 /* libmpdclient
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
7 are met:
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"
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <stdio.h>
38 #include <sys/param.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
44 #ifdef WIN32
45 # include <ws2tcpip.h>
46 # include <winsock.h>
47 #else
48 # include <netinet/in.h>
49 # include <arpa/inet.h>
50 # include <sys/socket.h>
51 # include <netdb.h>
52 #endif
54 #ifndef MSG_DONTWAIT
55 # define MSG_DONTWAIT 0
56 #endif
58 #ifndef MPD_NO_GAI
59 # ifdef AI_ADDRCONFIG
60 # define MPD_HAVE_GAI
61 # endif
62 #endif
64 #define COMMAND_LIST 1
65 #define COMMAND_LIST_OK 2
67 #ifdef WIN32
68 # define SELECT_ERRNO_IGNORE (errno == WSAEINTR || errno == WSAEINPROGRESS)
69 # define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
70 #else
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)
76 #endif
78 #ifdef WIN32
79 static int winsock_dll_error(mpd_Connection * connection)
81 WSADATA wsaData;
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;
87 return 1;
89 return 0;
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);
109 #endif /* !WIN32 */
111 #ifdef MPD_HAVE_GAI
112 static int mpd_connect(mpd_Connection * connection, const char *host, int port,
113 float timeout)
115 int error;
116 char service[20];
117 struct addrinfo hints;
118 struct addrinfo *res = NULL;
119 struct addrinfo *addrinfo = NULL;
122 * Setup hints
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);
137 if (error) {
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;
142 return -1;
145 for (res = addrinfo; res; res = res->ai_next) {
146 /* create socket */
147 connection->sock =
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",
152 strerror(errno));
153 connection->error = MPD_ERROR_SYSTEM;
154 freeaddrinfo(addrinfo);
155 return -1;
158 mpd_setConnectionTimeout(connection, timeout);
160 /* connect stuff */
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;
165 continue;
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;
176 return -1;
179 return 0;
181 #else /* !MPD_HAVE_GAI */
182 static int mpd_connect(mpd_Connection * connection, const char *host, int port,
183 float timeout)
185 struct hostent *he;
186 struct sockaddr *dest;
187 int destlen;
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;
194 return -1;
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) {
203 case AF_INET:
204 memcpy((char *)&sin.sin_addr.s_addr, (char *)he->h_addr,
205 he->h_length);
206 dest = (struct sockaddr *)&sin;
207 destlen = sizeof(struct sockaddr_in);
208 break;
209 default:
210 strcpy(connection->errorStr, "address type is not IPv4\n");
211 connection->error = MPD_ERROR_SYSTEM;
212 return -1;
213 break;
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;
219 return -1;
222 mpd_setConnectionTimeout(connection, timeout);
224 /* connect stuff */
225 if (do_connect_fail(connection, dest, destlen)) {
226 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
227 "problems connecting to \"%s\" on port"
228 " %i", host, port);
229 connection->error = MPD_ERROR_CONNPORT;
230 return -1;
233 return 0;
235 #endif /* !MPD_HAVE_GAI */
236 #if 0
237 char *mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] = {
238 "Artist",
239 "Album",
240 "Title",
241 "Track",
242 "Name",
243 "Genre",
244 "Date",
245 "Composer",
246 "Performer",
247 "Comment",
248 "Disc",
249 "filename"
251 #endif
252 static char *mpd_sanitizeArg(const char *arg)
254 size_t i;
255 char *ret;
256 register const char *c;
257 register char *rc;
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);
264 c = arg;
265 rc = ret;
266 for (i = strlen(arg) + 1; i != 0; --i) {
267 if (*c == '"' || *c == '\\')
268 *rc++ = '\\';
269 *(rc++) = *(c++);
272 return ret;
275 static mpd_ReturnElement *mpd_newReturnElement(const char *name,
276 const char *value)
278 mpd_ReturnElement *ret = malloc(sizeof(mpd_ReturnElement));
280 ret->name = strdup(name);
281 ret->value = strdup(value);
283 return ret;
286 static void mpd_freeReturnElement(mpd_ReturnElement * re)
288 free(re->name);
289 free(re->value);
290 free(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 *
298 1000000 + 0.5);
301 static int mpd_parseWelcome(mpd_Connection * connection, const char *host,
302 int port, char *output)
304 char *tmp;
305 char *test;
306 int i;
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\"",
311 port, host);
312 connection->error = MPD_ERROR_NOTMPD;
313 return 1;
316 tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
318 for (i = 0; i < 3; i++) {
319 if (tmp)
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 "
326 "\"%s\"",
327 &output[strlen(MPD_WELCOME_MESSAGE)]);
328 connection->error = MPD_ERROR_NOTMPD;
329 return 1;
331 tmp = ++test;
334 return 0;
337 mpd_Connection *mpd_newConnection(const char *host, int port, float timeout)
339 int err;
340 char *rt;
341 char *output = NULL;
342 mpd_Connection *connection = malloc(sizeof(mpd_Connection));
343 struct timeval tv;
344 fd_set fds;
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))
358 return connection;
360 if (mpd_connect(connection, host, port, timeout) < 0)
361 return connection;
363 while (!(rt = strstr(connection->buffer, "\n"))) {
364 tv.tv_sec = connection->timeout.tv_sec;
365 tv.tv_usec = connection->timeout.tv_usec;
366 FD_ZERO(&fds);
367 FD_SET(connection->sock, &fds);
368 if ((err =
369 select(connection->sock + 1, &fds, NULL, NULL,
370 &tv)) == 1) {
371 int readed;
372 readed = recv(connection->sock,
373 &(connection->buffer[connection->buflen]),
374 MPD_BUFFER_MAX_LENGTH -
375 connection->buflen, 0);
376 if (readed <= 0) {
377 snprintf(connection->errorStr,
378 MPD_BUFFER_MAX_LENGTH,
379 "problems getting a response from"
380 " \"%s\" on port %i : %s", host, port,
381 strerror(errno));
382 connection->error = MPD_ERROR_NORESPONSE;
383 return connection;
385 connection->buflen += readed;
386 connection->buffer[connection->buflen] = '\0';
387 } else if (err < 0) {
388 if (SELECT_ERRNO_IGNORE)
389 continue;
390 snprintf(connection->errorStr,
391 MPD_BUFFER_MAX_LENGTH,
392 "problems connecting to \"%s\" on port"
393 " %i", host, port);
394 connection->error = MPD_ERROR_CONNPORT;
395 return connection;
396 } else {
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;
401 return connection;
405 *rt = '\0';
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;
413 free(output);
415 return connection;
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);
431 free(connection);
432 WSACleanup();
435 static void mpd_executeCommand(mpd_Connection * connection, char *command)
437 int ret;
438 struct timeval tv;
439 fd_set fds;
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;
447 return;
450 mpd_clearError(connection);
452 FD_ZERO(&fds);
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)) {
459 ret =
460 send(connection->sock, commandPtr, commandLen,
461 MSG_DONTWAIT);
462 if (ret <= 0) {
463 if (SENDRECV_ERRNO_IGNORE)
464 continue;
465 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
466 "problems giving command \"%s\"", command);
467 connection->error = MPD_ERROR_SENDING;
468 return;
469 } else {
470 commandPtr += ret;
471 commandLen -= ret;
474 if (commandLen <= 0)
475 break;
478 if (commandLen > 0) {
479 perror("");
480 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
481 "timeout sending command \"%s\"", command);
482 connection->error = MPD_ERROR_TIMEOUT;
483 return;
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)
495 char *output = NULL;
496 char *rt = NULL;
497 char *name = NULL;
498 char *value = NULL;
499 fd_set fds;
500 struct timeval tv;
501 char *tok = NULL;
502 int readed;
503 char *bufferCheck = NULL;
504 int err;
505 int pos;
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;
516 return;
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,
524 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;
535 return;
537 bufferCheck = connection->buffer + connection->buflen;
538 tv.tv_sec = connection->timeout.tv_sec;
539 tv.tv_usec = connection->timeout.tv_usec;
540 FD_ZERO(&fds);
541 FD_SET(connection->sock, &fds);
542 if ((err =
543 select(connection->sock + 1, &fds, NULL, NULL,
544 &tv) == 1)) {
545 readed =
546 recv(connection->sock,
547 connection->buffer + connection->buflen,
548 MPD_BUFFER_MAX_LENGTH - connection->buflen,
549 MSG_DONTWAIT);
550 if (readed < 0 && SENDRECV_ERRNO_IGNORE) {
551 continue;
553 if (readed <= 0) {
554 strcpy(connection->errorStr, "connection"
555 " closed");
556 connection->error = MPD_ERROR_CONNCLOSED;
557 connection->doneProcessing = 1;
558 connection->doneListOk = 0;
559 return;
561 connection->buflen += readed;
562 connection->buffer[connection->buflen] = '\0';
563 } else if (err < 0 && SELECT_ERRNO_IGNORE)
564 continue;
565 else {
566 strcpy(connection->errorStr, "connection timeout");
567 connection->error = MPD_ERROR_TIMEOUT;
568 connection->doneProcessing = 1;
569 connection->doneListOk = 0;
570 return;
574 *rt = '\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;
586 return;
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;
594 } else {
595 connection->doneListOk = 1;
596 connection->listOks--;
598 return;
601 if (strncmp(output, "ACK", strlen("ACK")) == 0) {
602 char *test;
603 char *needle;
604 int val;
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, '[');
614 if (!needle)
615 return;
616 val = strtol(needle + 1, &test, 10);
617 if (*test != '@')
618 return;
619 connection->errorCode = val;
620 val = strtol(test + 1, &test, 10);
621 if (*test != ']')
622 return;
623 connection->errorAt = val;
624 return;
627 tok = strchr(output, ':');
628 if (!tok)
629 return;
630 pos = tok - output;
631 value = ++tok;
632 name = output;
633 name[pos] = '\0';
635 if (value[0] == ' ') {
636 connection->returnElement =
637 mpd_newReturnElement(name, &(value[1]));
638 } else {
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)
669 return -1;
670 return 0;
673 void mpd_sendStatusCommand(mpd_Connection * connection)
675 mpd_executeCommand(connection, "status\n");
678 mpd_Status *mpd_getStatus(mpd_Connection * connection)
680 mpd_Status *status;
682 /*mpd_executeCommand(connection,"status\n");
684 if(connection->error) return NULL; */
686 if (connection->doneProcessing || (connection->listOks &&
687 connection->doneListOk)) {
688 return NULL;
691 if (!connection->returnElement)
692 mpd_getNextReturnElement(connection);
694 status = malloc(sizeof(mpd_Status));
695 status->volume = -1;
696 status->repeat = 0;
697 status->random = 0;
698 /* status->playlist = -1; */
699 status->playlistLength = -1;
700 status->state = -1;
701 status->song = 0;
702 status->songid = 0;
703 status->elapsedTime = 0;
704 status->totalTime = 0;
705 status->bitRate = 0;
706 status->sampleRate = 0;
707 status->bits = 0;
708 status->channels = 0;
709 status->crossfade = -1;
710 status->error = NULL;
711 status->updatingDb = 0;
713 if (connection->error) {
714 free(status);
715 return NULL;
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;
738 } else {
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) {
772 free(status);
773 return NULL;
777 if (connection->error) {
778 free(status);
779 return NULL;
780 } else if (status->state < 0) {
781 strcpy(connection->errorStr, "state not found");
782 connection->error = 1;
783 free(status);
784 return NULL;
787 return status;
790 void mpd_freeStatus(mpd_Status * status)
792 if (status->error)
793 free(status->error);
794 free(status);
796 #if 0
797 void mpd_sendStatsCommand(mpd_Connection * connection)
799 mpd_executeCommand(connection, "stats\n");
802 mpd_Stats *mpd_getStats(mpd_Connection * connection)
804 mpd_Stats *stats;
806 /*mpd_executeCommand(connection,"stats\n");
808 if(connection->error) return NULL; */
810 if (connection->doneProcessing || (connection->listOks &&
811 connection->doneListOk)) {
812 return NULL;
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;
822 stats->uptime = 0;
823 stats->dbUpdateTime = 0;
824 stats->playTime = 0;
825 stats->dbPlayTime = 0;
827 if (connection->error) {
828 free(stats);
829 return NULL;
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) {
851 free(stats);
852 return NULL;
856 if (connection->error) {
857 free(stats);
858 return NULL;
861 return stats;
864 void mpd_freeStats(mpd_Stats * stats)
865 #endif
866 #if 0
868 free(stats);
870 #endif
871 static void mpd_initSong(mpd_Song * song)
873 song->file = NULL;
874 song->artist = NULL;
875 song->album = NULL;
876 song->track = NULL;
877 song->title = NULL;
878 song->name = NULL;
879 song->date = NULL;
880 /* added by Qball */
881 song->genre = NULL;
882 song->composer = NULL;
883 song->disc = 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)
893 if (song->file)
894 free(song->file);
895 if (song->artist)
896 free(song->artist);
897 if (song->album)
898 free(song->album);
899 if (song->title)
900 free(song->title);
901 if (song->track)
902 free(song->track);
903 if (song->name)
904 free(song->name);
905 if (song->date)
906 free(song->date);
907 if (song->genre)
908 free(song->genre);
909 if (song->composer)
910 free(song->composer);
911 if (song->disc)
912 free(song->disc);
913 if (song->comment)
914 free(song->comment);
917 mpd_Song *mpd_newSong(void)
919 mpd_Song *ret = malloc(sizeof(mpd_Song));
921 mpd_initSong(ret);
923 return ret;
926 void mpd_freeSong(mpd_Song * song)
928 mpd_finishSong(song);
929 free(song);
932 mpd_Song *mpd_songDup(mpd_Song * song)
934 mpd_Song *ret = mpd_newSong();
936 if (song->file)
937 ret->file = strdup(song->file);
938 if (song->artist)
939 ret->artist = strdup(song->artist);
940 if (song->album)
941 ret->album = strdup(song->album);
942 if (song->title)
943 ret->title = strdup(song->title);
944 if (song->track)
945 ret->track = strdup(song->track);
946 if (song->name)
947 ret->name = strdup(song->name);
948 if (song->date)
949 ret->date = strdup(song->date);
950 if (song->genre)
951 ret->genre = strdup(song->genre);
952 if (song->composer)
953 ret->composer = strdup(song->composer);
954 if (song->disc)
955 ret->disc = strdup(song->disc);
956 if (song->comment)
957 ret->comment = strdup(song->comment);
958 ret->time = song->time;
959 ret->pos = song->pos;
960 ret->id = song->id;
962 return ret;
964 #if 0
965 static void mpd_initDirectory(mpd_Directory * directory)
967 directory->path = NULL;
969 static void mpd_finishDirectory(mpd_Directory * directory)
971 if (directory->path)
972 free(directory->path);
975 mpd_Directory *mpd_newDirectory(void)
977 mpd_Directory *directory = malloc(sizeof(mpd_Directory));;
979 mpd_initDirectory(directory);
981 return directory;
984 void mpd_freeDirectory(mpd_Directory * directory)
986 mpd_finishDirectory(directory);
988 free(directory);
991 mpd_Directory *mpd_directoryDup(mpd_Directory * directory)
993 mpd_Directory *ret = mpd_newDirectory();
995 if (directory->path)
996 ret->path = strdup(directory->path);
998 return ret;
1000 static void mpd_initPlaylistFile(mpd_PlaylistFile * playlist)
1002 playlist->path = NULL;
1005 static void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist)
1007 if (playlist->path)
1008 free(playlist->path);
1011 mpd_PlaylistFile *mpd_newPlaylistFile(void)
1013 mpd_PlaylistFile *playlist = malloc(sizeof(mpd_PlaylistFile));
1015 mpd_initPlaylistFile(playlist);
1017 return playlist;
1019 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist)
1021 mpd_finishPlaylistFile(playlist);
1022 free(playlist);
1024 mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile * playlist)
1026 mpd_PlaylistFile *ret = mpd_newPlaylistFile();
1028 if (playlist->path)
1029 ret->path = strdup(playlist->path);
1031 return ret;
1033 #endif
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) {
1043 #if 0
1044 if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1045 mpd_freeDirectory(entity->info.directory);
1046 } else
1047 #endif
1048 if (entity->type == MPD_INFO_ENTITY_TYPE_SONG)
1049 mpd_freeSong(entity->info.song);
1050 #if 0
1051 } else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1052 mpd_freePlaylistFile(entity->info.playlistFile);
1054 #endif
1058 mpd_InfoEntity *mpd_newInfoEntity(void)
1060 mpd_InfoEntity *entity = malloc(sizeof(mpd_InfoEntity));
1062 mpd_initInfoEntity(entity);
1064 return entity;
1067 void mpd_freeInfoEntity(mpd_InfoEntity * entity)
1069 mpd_finishInfoEntity(entity);
1070 free(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)) {
1084 return NULL;
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);
1097 #if 0
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")
1106 == 0) {
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);
1112 #endif
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);
1119 } else {
1120 connection->error = 1;
1121 strcpy(connection->errorStr,
1122 "problem parsing song info");
1123 return NULL;
1125 } else
1126 return NULL;
1128 mpd_getNextReturnElement(connection);
1129 while (connection->returnElement) {
1130 mpd_ReturnElement *re = connection->returnElement;
1132 if (strcmp(re->name, "file") == 0)
1133 return entity;
1134 else if (strcmp(re->name, "directory") == 0)
1135 return entity;
1136 else if (strcmp(re->name, "playlist") == 0)
1137 return entity;
1138 else if (strcmp(re->name, "cpos") == 0)
1139 return entity;
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);
1190 return entity;
1193 static char *mpd_getNextReturnElementNamed(mpd_Connection * connection,
1194 const char *name)
1196 if (connection->doneProcessing || (connection->listOks &&
1197 connection->doneListOk)) {
1198 return NULL;
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);
1210 return NULL;
1212 #if 0
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]);
1219 return NULL;
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");
1231 #endif
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);
1237 free(string);
1239 #if 0
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);
1245 free(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);
1253 free(string);
1256 void mpd_sendPlChangesPosIdCommand(mpd_Connection * connection,
1257 long long playlist)
1259 char *string = malloc(strlen("plchangesposid") + 25);
1260 sprintf(string, "plchangesposid \"%lld\"\n", playlist);
1261 mpd_sendInfoCommand(connection, string);
1262 free(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);
1271 free(string);
1272 free(sDir);
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);
1281 free(string);
1282 free(sDir);
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);
1291 free(string);
1292 free(sDir);
1294 #endif
1295 void mpd_sendCurrentSongCommand(mpd_Connection * connection)
1297 mpd_executeCommand(connection, "currentsong\n");
1299 #if 0
1300 void mpd_sendSearchCommand(mpd_Connection * connection, int table,
1301 const char *str)
1303 char st[10];
1304 char *string;
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");
1314 else {
1315 connection->error = 1;
1316 strcpy(connection->errorStr, "unknown table for search");
1317 return;
1319 string = malloc(strlen("search") + strlen(sanitStr) + strlen(st) + 6);
1320 sprintf(string, "search %s \"%s\"\n", st, sanitStr);
1321 mpd_sendInfoCommand(connection, string);
1322 free(string);
1323 free(sanitStr);
1326 void mpd_sendFindCommand(mpd_Connection * connection, int table,
1327 const char *str)
1329 char st[10];
1330 char *string;
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");
1338 else {
1339 connection->error = 1;
1340 strcpy(connection->errorStr, "unknown table for find");
1341 return;
1343 string = malloc(strlen("find") + strlen(sanitStr) + strlen(st) + 6);
1344 sprintf(string, "find %s \"%s\"\n", st, sanitStr);
1345 mpd_sendInfoCommand(connection, string);
1346 free(string);
1347 free(sanitStr);
1350 void mpd_sendListCommand(mpd_Connection * connection, int table,
1351 const char *arg1)
1353 char st[10];
1354 char *string;
1355 if (table == MPD_TABLE_ARTIST)
1356 strcpy(st, "artist");
1357 else if (table == MPD_TABLE_ALBUM)
1358 strcpy(st, "album");
1359 else {
1360 connection->error = 1;
1361 strcpy(connection->errorStr, "unknown table for list");
1362 return;
1364 if (arg1) {
1365 char *sanitArg1 = mpd_sanitizeArg(arg1);
1366 string =
1367 malloc(strlen("list") + strlen(sanitArg1) + strlen(st) + 6);
1368 sprintf(string, "list %s \"%s\"\n", st, sanitArg1);
1369 free(sanitArg1);
1370 } else {
1371 string = malloc(strlen("list") + strlen(st) + 3);
1372 sprintf(string, "list %s\n", st);
1374 mpd_sendInfoCommand(connection, string);
1375 free(string);
1377 #endif
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);
1384 free(string);
1385 free(sFile);
1387 #if 0
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);
1393 free(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);
1401 free(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);
1410 free(string);
1411 free(sName);
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);
1420 free(string);
1421 free(sName);
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);
1430 free(string);
1431 free(sName);
1433 #endif
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);
1449 free(string);
1451 #if 0
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);
1457 free(string);
1459 #endif
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);
1470 free(string);
1472 #if 0
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);
1483 free(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);
1491 free(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);
1499 free(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);
1507 free(string);
1509 #endif
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);
1515 free(string);
1517 #if 0
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);
1523 free(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);
1532 free(string);
1533 free(sPath);
1536 int mpd_getUpdateId(mpd_Connection * connection)
1538 char *jobid;
1539 int ret = 0;
1541 jobid = mpd_getNextReturnElementNamed(connection, "updating_db");
1542 if (jobid) {
1543 ret = atoi(jobid);
1544 free(jobid);
1547 return ret;
1550 void mpd_sendPrevCommand(mpd_Connection * connection)
1552 mpd_executeCommand(connection, "previous\n");
1554 #endif
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);
1560 free(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);
1568 free(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);
1576 free(string);
1578 #if 0
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);
1584 free(string);
1586 #endif
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);
1592 free(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);
1601 free(string);
1602 free(sPass);
1605 void mpd_sendCommandListBegin(mpd_Connection * connection)
1607 if (connection->commandList) {
1608 strcpy(connection->errorStr, "already in command list mode");
1609 connection->error = 1;
1610 return;
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;
1621 return;
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;
1633 return;
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)) {
1650 return NULL;
1653 if (connection->error)
1654 return NULL;
1656 output = malloc(sizeof(mpd_OutputEntity));
1657 output->id = -10;
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)
1668 return output;
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) {
1678 free(output);
1679 return NULL;
1684 return output;
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);
1692 free(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);
1700 free(string);
1703 void mpd_freeOutputElement(mpd_OutputEntity * output)
1705 free(output->name);
1706 free(output);
1710 * mpd_sendNotCommandsCommand
1711 * odd naming, but it gets the not allowed commands
1713 #if 0
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");
1728 #endif
1730 * Get the next returned command
1732 char *mpd_getNextCommand(mpd_Connection * connection)
1734 return mpd_getNextReturnElementNamed(connection, "command");
1736 #if 0
1737 void mpd_startSearch(mpd_Connection * connection, int exact)
1739 if (connection->request) {
1740 /* search/find allready in progress */
1741 /* TODO: set error here? */
1742 return;
1744 if (exact) {
1745 connection->request = strdup("find");
1746 } else {
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? */
1756 return;
1758 if (field < 0 || field >= MPD_TAG_NUM_OF_ITEM_TYPES) {
1759 /* set error here */
1760 return;
1763 connection->request = malloc(sizeof(char) * (
1764 /* length of the field name */
1765 strlen
1766 (mpdTagItemKeys
1767 [field]) +
1768 /* "list"+space+\0 */
1769 6));
1770 sprintf(connection->request, "list %s", mpdTagItemKeys[field]);
1773 void mpd_addConstraintSearch(mpd_Connection * connection, int field, char *name)
1775 char *arg = NULL;
1776 if (!connection->request) {
1777 return;
1779 if (name == NULL) {
1780 return;
1782 if (field < 0 || field >= MPD_TAG_NUM_OF_ITEM_TYPES) {
1783 return;
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 */
1790 strlen
1791 (connection->
1792 request) +
1793 /* space between */
1795 /* length of the field name */
1796 strlen
1797 (mpdTagItemKeys
1798 [field]) +
1799 /* space plus starting " */
1801 /* length of search term */
1802 strlen(arg) +
1803 /* closign " +\0 that is added sprintf */
1804 2) *
1805 sizeof(char));
1806 /* and form the query */
1807 sprintf(connection->request, "%s %s \"%s\"",
1808 connection->request, mpdTagItemKeys[field], arg);
1809 free(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 */
1819 ) * sizeof(char));
1820 connection->request[length] = '\n';
1821 connection->request[length + 1] = '\0';
1822 /* and off we go */
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);
1843 free(arg);
1844 free(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);
1860 free(arg);
1861 free(query);
1863 #endif