lede-packages-rs

git clone git://archive.git.mtrnord.blog/MTRNord/lede-packages-rs.git
Log | Files | Refs | README | LICENSE

150-addlibmpdclient.patch (78059B)


      1 --- /dev/null
      2 +++ b/libmpdclient.c
      3 @@ -0,0 +1,1957 @@
      4 +/* libmpdclient
      5 +   (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
      6 +   This project's homepage is: http://www.musicpd.org
      7 +
      8 +   Redistribution and use in source and binary forms, with or without
      9 +   modification, are permitted provided that the following conditions
     10 +   are met:
     11 +
     12 +   - Redistributions of source code must retain the above copyright
     13 +   notice, this list of conditions and the following disclaimer.
     14 +
     15 +   - Redistributions in binary form must reproduce the above copyright
     16 +   notice, this list of conditions and the following disclaimer in the
     17 +   documentation and/or other materials provided with the distribution.
     18 +
     19 +   - Neither the name of the Music Player Daemon nor the names of its
     20 +   contributors may be used to endorse or promote products derived from
     21 +   this software without specific prior written permission.
     22 +
     23 +   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24 +   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25 +   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     26 +   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
     27 +   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     28 +   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     29 +   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     30 +   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     31 +   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     32 +   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     33 +   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34 +*/
     35 +
     36 +#include "libmpdclient.h"
     37 +
     38 +#include <errno.h>
     39 +#include <ctype.h>
     40 +#include <sys/types.h>
     41 +#include <stdio.h>
     42 +#include <sys/param.h>
     43 +#include <string.h>
     44 +#include <unistd.h>
     45 +#include <stdlib.h>
     46 +#include <fcntl.h>
     47 +#include <limits.h>
     48 +
     49 +#ifdef WIN32
     50 +#  include <ws2tcpip.h>
     51 +#  include <winsock.h>
     52 +#else
     53 +#  include <netinet/in.h>
     54 +#  include <arpa/inet.h>
     55 +#  include <sys/socket.h>
     56 +#  include <netdb.h>
     57 +#endif
     58 +
     59 +/* (bits+1)/3 (plus the sign character) */
     60 +#define INTLEN      ((sizeof(int)       * CHAR_BIT + 1) / 3 + 1)
     61 +#define LONGLONGLEN ((sizeof(long long) * CHAR_BIT + 1) / 3 + 1)
     62 +
     63 +#define COMMAND_LIST    1
     64 +#define COMMAND_LIST_OK 2
     65 +
     66 +#ifndef MPD_NO_GAI
     67 +#  ifdef AI_ADDRCONFIG
     68 +#    define MPD_HAVE_GAI
     69 +#  endif
     70 +#endif
     71 +
     72 +#ifndef MSG_DONTWAIT
     73 +#  define MSG_DONTWAIT 0
     74 +#endif
     75 +
     76 +#ifdef WIN32
     77 +#  define SELECT_ERRNO_IGNORE   (errno == WSAEINTR || errno == WSAEINPROGRESS)
     78 +#  define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
     79 +#else
     80 +#  define SELECT_ERRNO_IGNORE   (errno == EINTR)
     81 +#  define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
     82 +#  define winsock_dll_error(c)  0
     83 +#  define closesocket(s)        close(s)
     84 +#  define WSACleanup()          do { /* nothing */ } while (0)
     85 +#endif
     86 +
     87 +#ifdef WIN32
     88 +static int winsock_dll_error(mpd_Connection * connection)
     89 +{
     90 +    WSADATA wsaData;
     91 +    if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0 || LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
     92 +	strcpy(connection->errorStr, "Could not find usable WinSock DLL.");
     93 +	connection->error = MPD_ERROR_SYSTEM;
     94 +	return 1;
     95 +    }
     96 +    return 0;
     97 +}
     98 +
     99 +static int do_connect_fail(mpd_Connection * connection, const struct sockaddr *serv_addr, int addrlen)
    100 +{
    101 +    int iMode = 1;		/* 0 = blocking, else non-blocking */
    102 +    ioctlsocket(connection->sock, FIONBIO, (u_long FAR *) & iMode);
    103 +    return (connect(connection->sock, serv_addr, addrlen) == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK);
    104 +}
    105 +#else				/* !WIN32 (sane operating systems) */
    106 +static int do_connect_fail(mpd_Connection * connection, const struct sockaddr *serv_addr, int addrlen)
    107 +{
    108 +    int flags = fcntl(connection->sock, F_GETFL, 0);
    109 +    fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
    110 +    return (connect(connection->sock, serv_addr, addrlen) < 0 && errno != EINPROGRESS);
    111 +}
    112 +#endif				/* !WIN32 */
    113 +
    114 +#ifdef MPD_HAVE_GAI
    115 +static int mpd_connect(mpd_Connection * connection, const char *host, int port, float timeout)
    116 +{
    117 +    int error;
    118 +    char service[INTLEN + 1];
    119 +    struct addrinfo hints;
    120 +    struct addrinfo *res = NULL;
    121 +    struct addrinfo *addrinfo = NULL;
    122 +
    123 +	/**
    124 +	 * Setup hints
    125 +	 */
    126 +    hints.ai_flags = AI_ADDRCONFIG;
    127 +    hints.ai_family = PF_UNSPEC;
    128 +    hints.ai_socktype = SOCK_STREAM;
    129 +    hints.ai_protocol = IPPROTO_TCP;
    130 +    hints.ai_addrlen = 0;
    131 +    hints.ai_addr = NULL;
    132 +    hints.ai_canonname = NULL;
    133 +    hints.ai_next = NULL;
    134 +
    135 +    snprintf(service, sizeof(service), "%i", port);
    136 +
    137 +    error = getaddrinfo(host, service, &hints, &addrinfo);
    138 +
    139 +    if (error) {
    140 +	snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH, "host \"%s\" not found: %s", host, gai_strerror(error));
    141 +	connection->error = MPD_ERROR_UNKHOST;
    142 +	return -1;
    143 +    }
    144 +
    145 +    for (res = addrinfo; res; res = res->ai_next) {
    146 +	/* create socket */
    147 +	connection->sock = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
    148 +	if (connection->sock < 0) {
    149 +	    snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH, "problems creating socket: %s", strerror(errno));
    150 +	    connection->error = MPD_ERROR_SYSTEM;
    151 +	    freeaddrinfo(addrinfo);
    152 +	    return -1;
    153 +	}
    154 +
    155 +	mpd_setConnectionTimeout(connection, timeout);
    156 +
    157 +	/* connect stuff */
    158 +	if (do_connect_fail(connection, res->ai_addr, res->ai_addrlen)) {
    159 +	    /* try the next address family */
    160 +	    closesocket(connection->sock);
    161 +	    connection->sock = -1;
    162 +	    continue;
    163 +	}
    164 +    }
    165 +
    166 +    freeaddrinfo(addrinfo);
    167 +
    168 +    if (connection->sock < 0) {
    169 +	snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
    170 +		 "problems connecting to \"%s\" on port %i: %s", host, port, strerror(errno));
    171 +	connection->error = MPD_ERROR_CONNPORT;
    172 +
    173 +	return -1;
    174 +    }
    175 +
    176 +    return 0;
    177 +}
    178 +#else				/* !MPD_HAVE_GAI */
    179 +static int mpd_connect(mpd_Connection * connection, const char *host, int port, float timeout)
    180 +{
    181 +    struct hostent *he;
    182 +    struct sockaddr *dest;
    183 +    int destlen;
    184 +    struct sockaddr_in sin;
    185 +
    186 +    if (!(he = gethostbyname(host))) {
    187 +	snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH, "host \"%s\" not found", host);
    188 +	connection->error = MPD_ERROR_UNKHOST;
    189 +	return -1;
    190 +    }
    191 +
    192 +    memset(&sin, 0, sizeof(struct sockaddr_in));
    193 +    /*dest.sin_family = he->h_addrtype; */
    194 +    sin.sin_family = AF_INET;
    195 +    sin.sin_port = htons(port);
    196 +
    197 +    switch (he->h_addrtype) {
    198 +    case AF_INET:
    199 +	memcpy((char *) &sin.sin_addr.s_addr, (char *) he->h_addr, he->h_length);
    200 +	dest = (struct sockaddr *) &sin;
    201 +	destlen = sizeof(struct sockaddr_in);
    202 +	break;
    203 +    default:
    204 +	strcpy(connection->errorStr, "address type is not IPv4");
    205 +	connection->error = MPD_ERROR_SYSTEM;
    206 +	return -1;
    207 +	break;
    208 +    }
    209 +
    210 +    if ((connection->sock = socket(dest->sa_family, SOCK_STREAM, 0)) < 0) {
    211 +	strcpy(connection->errorStr, "problems creating socket");
    212 +	connection->error = MPD_ERROR_SYSTEM;
    213 +	return -1;
    214 +    }
    215 +
    216 +    mpd_setConnectionTimeout(connection, timeout);
    217 +
    218 +    /* connect stuff */
    219 +    if (do_connect_fail(connection, dest, destlen)) {
    220 +	snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
    221 +		 "problems connecting to \"%s\" on port" " %i", host, port);
    222 +	connection->error = MPD_ERROR_CONNPORT;
    223 +	return -1;
    224 +    }
    225 +
    226 +    return 0;
    227 +}
    228 +#endif				/* !MPD_HAVE_GAI */
    229 +
    230 +char *mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] = {
    231 +    "Artist",
    232 +    "Album",
    233 +    "Title",
    234 +    "Track",
    235 +    "Name",
    236 +    "Genre",
    237 +    "Date",
    238 +    "Composer",
    239 +    "Performer",
    240 +    "Comment",
    241 +    "Disc",
    242 +    "Filename",
    243 +    "Any"
    244 +};
    245 +
    246 +static char *mpd_sanitizeArg(const char *arg)
    247 +{
    248 +    size_t i;
    249 +    char *ret;
    250 +    register const char *c;
    251 +    register char *rc;
    252 +
    253 +    /* instead of counting in that loop above, just
    254 +     * use a bit more memory and half running time
    255 +     */
    256 +    ret = malloc(strlen(arg) * 2 + 1);
    257 +
    258 +    c = arg;
    259 +    rc = ret;
    260 +    for (i = strlen(arg) + 1; i != 0; --i) {
    261 +	if (*c == '"' || *c == '\\')
    262 +	    *rc++ = '\\';
    263 +	*(rc++) = *(c++);
    264 +    }
    265 +
    266 +    return ret;
    267 +}
    268 +
    269 +static mpd_ReturnElement *mpd_newReturnElement(const char *name, const char *value)
    270 +{
    271 +    mpd_ReturnElement *ret = malloc(sizeof(mpd_ReturnElement));
    272 +
    273 +    ret->name = strdup(name);
    274 +    ret->value = strdup(value);
    275 +
    276 +    return ret;
    277 +}
    278 +
    279 +static void mpd_freeReturnElement(mpd_ReturnElement * re)
    280 +{
    281 +    free(re->name);
    282 +    free(re->value);
    283 +    free(re);
    284 +}
    285 +
    286 +void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout)
    287 +{
    288 +    connection->timeout.tv_sec = (int) timeout;
    289 +    connection->timeout.tv_usec = (int) (timeout * 1e6 - connection->timeout.tv_sec * 1000000 + 0.5);
    290 +}
    291 +
    292 +static int mpd_parseWelcome(mpd_Connection * connection, const char *host, int port, char *rt, char *output)
    293 +{
    294 +    char *tmp;
    295 +    char *test;
    296 +    int i;
    297 +
    298 +    if (strncmp(output, MPD_WELCOME_MESSAGE, strlen(MPD_WELCOME_MESSAGE))) {
    299 +	snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
    300 +		 "mpd not running on port %i on host \"%s\"", port, host);
    301 +	connection->error = MPD_ERROR_NOTMPD;
    302 +	return 1;
    303 +    }
    304 +
    305 +    tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
    306 +
    307 +    for (i = 0; i < 3; i++) {
    308 +	if (tmp)
    309 +	    connection->version[i] = strtol(tmp, &test, 10);
    310 +
    311 +	if (!tmp || (test[0] != '.' && test[0] != '\0')) {
    312 +	    snprintf(connection->errorStr,
    313 +		     MPD_ERRORSTR_MAX_LENGTH,
    314 +		     "error parsing version number at " "\"%s\"", &output[strlen(MPD_WELCOME_MESSAGE)]);
    315 +	    connection->error = MPD_ERROR_NOTMPD;
    316 +	    return 1;
    317 +	}
    318 +	tmp = ++test;
    319 +    }
    320 +
    321 +    return 0;
    322 +}
    323 +
    324 +mpd_Connection *mpd_newConnection(const char *host, int port, float timeout)
    325 +{
    326 +    int err;
    327 +    char *rt;
    328 +    char *output = NULL;
    329 +    mpd_Connection *connection = malloc(sizeof(mpd_Connection));
    330 +    struct timeval tv;
    331 +    fd_set fds;
    332 +    strcpy(connection->buffer, "");
    333 +    connection->buflen = 0;
    334 +    connection->bufstart = 0;
    335 +    strcpy(connection->errorStr, "");
    336 +    connection->error = 0;
    337 +    connection->doneProcessing = 0;
    338 +    connection->commandList = 0;
    339 +    connection->listOks = 0;
    340 +    connection->doneListOk = 0;
    341 +    connection->returnElement = NULL;
    342 +    connection->request = NULL;
    343 +
    344 +    if (winsock_dll_error(connection))
    345 +	return connection;
    346 +
    347 +    if (mpd_connect(connection, host, port, timeout) < 0)
    348 +	return connection;
    349 +
    350 +    while (!(rt = strstr(connection->buffer, "\n"))) {
    351 +	tv.tv_sec = connection->timeout.tv_sec;
    352 +	tv.tv_usec = connection->timeout.tv_usec;
    353 +	FD_ZERO(&fds);
    354 +	FD_SET(connection->sock, &fds);
    355 +	if ((err = select(connection->sock + 1, &fds, NULL, NULL, &tv)) == 1) {
    356 +	    int readed;
    357 +	    readed = recv(connection->sock,
    358 +			  &(connection->buffer[connection->buflen]), MPD_BUFFER_MAX_LENGTH - connection->buflen, 0);
    359 +	    if (readed <= 0) {
    360 +		snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
    361 +			 "problems getting a response from" " \"%s\" on port %i : %s", host, port, strerror(errno));
    362 +		connection->error = MPD_ERROR_NORESPONSE;
    363 +		return connection;
    364 +	    }
    365 +	    connection->buflen += readed;
    366 +	    connection->buffer[connection->buflen] = '\0';
    367 +	} else if (err < 0) {
    368 +	    if (SELECT_ERRNO_IGNORE)
    369 +		continue;
    370 +	    snprintf(connection->errorStr,
    371 +		     MPD_ERRORSTR_MAX_LENGTH, "problems connecting to \"%s\" on port" " %i", host, port);
    372 +	    connection->error = MPD_ERROR_CONNPORT;
    373 +	    return connection;
    374 +	} else {
    375 +	    snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
    376 +		     "timeout in attempting to get a response from" " \"%s\" on port %i", host, port);
    377 +	    connection->error = MPD_ERROR_NORESPONSE;
    378 +	    return connection;
    379 +	}
    380 +    }
    381 +
    382 +    *rt = '\0';
    383 +    output = strdup(connection->buffer);
    384 +    strcpy(connection->buffer, rt + 1);
    385 +    connection->buflen = strlen(connection->buffer);
    386 +
    387 +    if (mpd_parseWelcome(connection, host, port, rt, output) == 0)
    388 +	connection->doneProcessing = 1;
    389 +
    390 +    free(output);
    391 +
    392 +    return connection;
    393 +}
    394 +
    395 +void mpd_clearError(mpd_Connection * connection)
    396 +{
    397 +    connection->error = 0;
    398 +    connection->errorStr[0] = '\0';
    399 +}
    400 +
    401 +void mpd_closeConnection(mpd_Connection * connection)
    402 +{
    403 +    closesocket(connection->sock);
    404 +    if (connection->returnElement)
    405 +	free(connection->returnElement);
    406 +    if (connection->request)
    407 +	free(connection->request);
    408 +    free(connection);
    409 +    WSACleanup();
    410 +}
    411 +
    412 +static void mpd_executeCommand(mpd_Connection * connection, char *command)
    413 +{
    414 +    int ret;
    415 +    struct timeval tv;
    416 +    fd_set fds;
    417 +    char *commandPtr = command;
    418 +    int commandLen = strlen(command);
    419 +
    420 +    if (!connection->doneProcessing && !connection->commandList) {
    421 +	strcpy(connection->errorStr, "not done processing current command");
    422 +	connection->error = 1;
    423 +	return;
    424 +    }
    425 +
    426 +    mpd_clearError(connection);
    427 +
    428 +    FD_ZERO(&fds);
    429 +    FD_SET(connection->sock, &fds);
    430 +    tv.tv_sec = connection->timeout.tv_sec;
    431 +    tv.tv_usec = connection->timeout.tv_usec;
    432 +
    433 +    while ((ret = select(connection->sock + 1, NULL, &fds, NULL, &tv) == 1) || (ret == -1 && SELECT_ERRNO_IGNORE)) {
    434 +	ret = send(connection->sock, commandPtr, commandLen, MSG_DONTWAIT);
    435 +	if (ret <= 0) {
    436 +	    if (SENDRECV_ERRNO_IGNORE)
    437 +		continue;
    438 +	    snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH, "problems giving command \"%s\"", command);
    439 +	    connection->error = MPD_ERROR_SENDING;
    440 +	    return;
    441 +	} else {
    442 +	    commandPtr += ret;
    443 +	    commandLen -= ret;
    444 +	}
    445 +
    446 +	if (commandLen <= 0)
    447 +	    break;
    448 +    }
    449 +
    450 +    if (commandLen > 0) {
    451 +	perror("");
    452 +	snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH, "timeout sending command \"%s\"", command);
    453 +	connection->error = MPD_ERROR_TIMEOUT;
    454 +	return;
    455 +    }
    456 +
    457 +    if (!connection->commandList)
    458 +	connection->doneProcessing = 0;
    459 +    else if (connection->commandList == COMMAND_LIST_OK) {
    460 +	connection->listOks++;
    461 +    }
    462 +}
    463 +
    464 +static void mpd_getNextReturnElement(mpd_Connection * connection)
    465 +{
    466 +    char *output = NULL;
    467 +    char *rt = NULL;
    468 +    char *name = NULL;
    469 +    char *value = NULL;
    470 +    fd_set fds;
    471 +    struct timeval tv;
    472 +    char *tok = NULL;
    473 +    int readed;
    474 +    char *bufferCheck = NULL;
    475 +    int err;
    476 +    int pos;
    477 +
    478 +    if (connection->returnElement)
    479 +	mpd_freeReturnElement(connection->returnElement);
    480 +    connection->returnElement = NULL;
    481 +
    482 +    if (connection->doneProcessing || (connection->listOks && connection->doneListOk)) {
    483 +	strcpy(connection->errorStr, "already done processing current command");
    484 +	connection->error = 1;
    485 +	return;
    486 +    }
    487 +
    488 +    bufferCheck = connection->buffer + connection->bufstart;
    489 +    while (connection->bufstart >= connection->buflen || !(rt = strchr(bufferCheck, '\n'))) {
    490 +	if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
    491 +	    memmove(connection->buffer,
    492 +		    connection->buffer + connection->bufstart, connection->buflen - connection->bufstart + 1);
    493 +	    connection->buflen -= connection->bufstart;
    494 +	    connection->bufstart = 0;
    495 +	}
    496 +	if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
    497 +	    strcpy(connection->errorStr, "buffer overrun");
    498 +	    connection->error = MPD_ERROR_BUFFEROVERRUN;
    499 +	    connection->doneProcessing = 1;
    500 +	    connection->doneListOk = 0;
    501 +	    return;
    502 +	}
    503 +	bufferCheck = connection->buffer + connection->buflen;
    504 +	tv.tv_sec = connection->timeout.tv_sec;
    505 +	tv.tv_usec = connection->timeout.tv_usec;
    506 +	FD_ZERO(&fds);
    507 +	FD_SET(connection->sock, &fds);
    508 +	if ((err = select(connection->sock + 1, &fds, NULL, NULL, &tv) == 1)) {
    509 +	    readed = recv(connection->sock,
    510 +			  connection->buffer + connection->buflen,
    511 +			  MPD_BUFFER_MAX_LENGTH - connection->buflen, MSG_DONTWAIT);
    512 +	    if (readed < 0 && SENDRECV_ERRNO_IGNORE) {
    513 +		continue;
    514 +	    }
    515 +	    if (readed <= 0) {
    516 +		strcpy(connection->errorStr, "connection" " closed");
    517 +		connection->error = MPD_ERROR_CONNCLOSED;
    518 +		connection->doneProcessing = 1;
    519 +		connection->doneListOk = 0;
    520 +		return;
    521 +	    }
    522 +	    connection->buflen += readed;
    523 +	    connection->buffer[connection->buflen] = '\0';
    524 +	} else if (err < 0 && SELECT_ERRNO_IGNORE)
    525 +	    continue;
    526 +	else {
    527 +	    strcpy(connection->errorStr, "connection timeout");
    528 +	    connection->error = MPD_ERROR_TIMEOUT;
    529 +	    connection->doneProcessing = 1;
    530 +	    connection->doneListOk = 0;
    531 +	    return;
    532 +	}
    533 +    }
    534 +
    535 +    *rt = '\0';
    536 +    output = connection->buffer + connection->bufstart;
    537 +    connection->bufstart = rt - connection->buffer + 1;
    538 +
    539 +    if (strcmp(output, "OK") == 0) {
    540 +	if (connection->listOks > 0) {
    541 +	    strcpy(connection->errorStr, "expected more list_OK's");
    542 +	    connection->error = 1;
    543 +	}
    544 +	connection->listOks = 0;
    545 +	connection->doneProcessing = 1;
    546 +	connection->doneListOk = 0;
    547 +	return;
    548 +    }
    549 +
    550 +    if (strcmp(output, "list_OK") == 0) {
    551 +	if (!connection->listOks) {
    552 +	    strcpy(connection->errorStr, "got an unexpected list_OK");
    553 +	    connection->error = 1;
    554 +	} else {
    555 +	    connection->doneListOk = 1;
    556 +	    connection->listOks--;
    557 +	}
    558 +	return;
    559 +    }
    560 +
    561 +    if (strncmp(output, "ACK", strlen("ACK")) == 0) {
    562 +	char *test;
    563 +	char *needle;
    564 +	int val;
    565 +
    566 +	strcpy(connection->errorStr, output);
    567 +	connection->error = MPD_ERROR_ACK;
    568 +	connection->errorCode = MPD_ACK_ERROR_UNK;
    569 +	connection->errorAt = MPD_ERROR_AT_UNK;
    570 +	connection->doneProcessing = 1;
    571 +	connection->doneListOk = 0;
    572 +
    573 +	needle = strchr(output, '[');
    574 +	if (!needle)
    575 +	    return;
    576 +	val = strtol(needle + 1, &test, 10);
    577 +	if (*test != '@')
    578 +	    return;
    579 +	connection->errorCode = val;
    580 +	val = strtol(test + 1, &test, 10);
    581 +	if (*test != ']')
    582 +	    return;
    583 +	connection->errorAt = val;
    584 +	return;
    585 +    }
    586 +
    587 +    tok = strchr(output, ':');
    588 +    if (!tok)
    589 +	return;
    590 +    pos = tok - output;
    591 +    value = ++tok;
    592 +    name = output;
    593 +    name[pos] = '\0';
    594 +
    595 +    if (value[0] == ' ') {
    596 +	connection->returnElement = mpd_newReturnElement(name, &(value[1]));
    597 +    } else {
    598 +	snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH, "error parsing: %s:%s", name, value);
    599 +	connection->error = 1;
    600 +    }
    601 +}
    602 +
    603 +void mpd_finishCommand(mpd_Connection * connection)
    604 +{
    605 +    while (!connection->doneProcessing) {
    606 +	if (connection->doneListOk)
    607 +	    connection->doneListOk = 0;
    608 +	mpd_getNextReturnElement(connection);
    609 +    }
    610 +}
    611 +
    612 +static void mpd_finishListOkCommand(mpd_Connection * connection)
    613 +{
    614 +    while (!connection->doneProcessing && connection->listOks && !connection->doneListOk) {
    615 +	mpd_getNextReturnElement(connection);
    616 +    }
    617 +}
    618 +
    619 +int mpd_nextListOkCommand(mpd_Connection * connection)
    620 +{
    621 +    mpd_finishListOkCommand(connection);
    622 +    if (!connection->doneProcessing)
    623 +	connection->doneListOk = 0;
    624 +    if (connection->listOks == 0 || connection->doneProcessing)
    625 +	return -1;
    626 +    return 0;
    627 +}
    628 +
    629 +void mpd_sendStatusCommand(mpd_Connection * connection)
    630 +{
    631 +    mpd_executeCommand(connection, "status\n");
    632 +}
    633 +
    634 +mpd_Status *mpd_getStatus(mpd_Connection * connection)
    635 +{
    636 +    mpd_Status *status;
    637 +
    638 +    /*mpd_executeCommand(connection,"status\n");
    639 +
    640 +       if(connection->error) return NULL; */
    641 +
    642 +    if (connection->doneProcessing || (connection->listOks && connection->doneListOk)) {
    643 +	return NULL;
    644 +    }
    645 +
    646 +    if (!connection->returnElement)
    647 +	mpd_getNextReturnElement(connection);
    648 +
    649 +    status = malloc(sizeof(mpd_Status));
    650 +    status->volume = -1;
    651 +    status->repeat = 0;
    652 +    status->random = 0;
    653 +    status->playlist = -1;
    654 +    status->playlistLength = -1;
    655 +    status->state = -1;
    656 +    status->song = 0;
    657 +    status->songid = 0;
    658 +    status->elapsedTime = 0;
    659 +    status->totalTime = 0;
    660 +    status->bitRate = 0;
    661 +    status->sampleRate = 0;
    662 +    status->bits = 0;
    663 +    status->channels = 0;
    664 +    status->crossfade = -1;
    665 +    status->error = NULL;
    666 +    status->updatingDb = 0;
    667 +
    668 +    if (connection->error) {
    669 +	free(status);
    670 +	return NULL;
    671 +    }
    672 +    while (connection->returnElement) {
    673 +	mpd_ReturnElement *re = connection->returnElement;
    674 +	if (strcmp(re->name, "volume") == 0) {
    675 +	    status->volume = atoi(re->value);
    676 +	} else if (strcmp(re->name, "repeat") == 0) {
    677 +	    status->repeat = atoi(re->value);
    678 +	} else if (strcmp(re->name, "random") == 0) {
    679 +	    status->random = atoi(re->value);
    680 +	} else if (strcmp(re->name, "playlist") == 0) {
    681 +	    status->playlist = strtol(re->value, NULL, 10);
    682 +	} else if (strcmp(re->name, "playlistlength") == 0) {
    683 +	    status->playlistLength = atoi(re->value);
    684 +	} else if (strcmp(re->name, "bitrate") == 0) {
    685 +	    status->bitRate = atoi(re->value);
    686 +	} else if (strcmp(re->name, "state") == 0) {
    687 +	    if (strcmp(re->value, "play") == 0) {
    688 +		status->state = MPD_STATUS_STATE_PLAY;
    689 +	    } else if (strcmp(re->value, "stop") == 0) {
    690 +		status->state = MPD_STATUS_STATE_STOP;
    691 +	    } else if (strcmp(re->value, "pause") == 0) {
    692 +		status->state = MPD_STATUS_STATE_PAUSE;
    693 +	    } else {
    694 +		status->state = MPD_STATUS_STATE_UNKNOWN;
    695 +	    }
    696 +	} else if (strcmp(re->name, "song") == 0) {
    697 +	    status->song = atoi(re->value);
    698 +	} else if (strcmp(re->name, "songid") == 0) {
    699 +	    status->songid = atoi(re->value);
    700 +	} else if (strcmp(re->name, "time") == 0) {
    701 +	    char *tok = strchr(re->value, ':');
    702 +	    /* the second strchr below is a safety check */
    703 +	    if (tok && (strchr(tok, 0) > (tok + 1))) {
    704 +		/* atoi stops at the first non-[0-9] char: */
    705 +		status->elapsedTime = atoi(re->value);
    706 +		status->totalTime = atoi(tok + 1);
    707 +	    }
    708 +	} else if (strcmp(re->name, "error") == 0) {
    709 +	    status->error = strdup(re->value);
    710 +	} else if (strcmp(re->name, "xfade") == 0) {
    711 +	    status->crossfade = atoi(re->value);
    712 +	} else if (strcmp(re->name, "updating_db") == 0) {
    713 +	    status->updatingDb = atoi(re->value);
    714 +	} else if (strcmp(re->name, "audio") == 0) {
    715 +	    char *tok = strchr(re->value, ':');
    716 +	    if (tok && (strchr(tok, 0) > (tok + 1))) {
    717 +		status->sampleRate = atoi(re->value);
    718 +		status->bits = atoi(++tok);
    719 +		tok = strchr(tok, ':');
    720 +		if (tok && (strchr(tok, 0) > (tok + 1)))
    721 +		    status->channels = atoi(tok + 1);
    722 +	    }
    723 +	}
    724 +
    725 +	mpd_getNextReturnElement(connection);
    726 +	if (connection->error) {
    727 +	    free(status);
    728 +	    return NULL;
    729 +	}
    730 +    }
    731 +
    732 +    if (connection->error) {
    733 +	free(status);
    734 +	return NULL;
    735 +    } else if (status->state < 0) {
    736 +	strcpy(connection->errorStr, "state not found");
    737 +	connection->error = 1;
    738 +	free(status);
    739 +	return NULL;
    740 +    }
    741 +
    742 +    return status;
    743 +}
    744 +
    745 +void mpd_freeStatus(mpd_Status * status)
    746 +{
    747 +    if (status->error)
    748 +	free(status->error);
    749 +    free(status);
    750 +}
    751 +
    752 +void mpd_sendStatsCommand(mpd_Connection * connection)
    753 +{
    754 +    mpd_executeCommand(connection, "stats\n");
    755 +}
    756 +
    757 +mpd_Stats *mpd_getStats(mpd_Connection * connection)
    758 +{
    759 +    mpd_Stats *stats;
    760 +
    761 +    /*mpd_executeCommand(connection,"stats\n");
    762 +
    763 +       if(connection->error) return NULL; */
    764 +
    765 +    if (connection->doneProcessing || (connection->listOks && connection->doneListOk)) {
    766 +	return NULL;
    767 +    }
    768 +
    769 +    if (!connection->returnElement)
    770 +	mpd_getNextReturnElement(connection);
    771 +
    772 +    stats = malloc(sizeof(mpd_Stats));
    773 +    stats->numberOfArtists = 0;
    774 +    stats->numberOfAlbums = 0;
    775 +    stats->numberOfSongs = 0;
    776 +    stats->uptime = 0;
    777 +    stats->dbUpdateTime = 0;
    778 +    stats->playTime = 0;
    779 +    stats->dbPlayTime = 0;
    780 +
    781 +    if (connection->error) {
    782 +	free(stats);
    783 +	return NULL;
    784 +    }
    785 +    while (connection->returnElement) {
    786 +	mpd_ReturnElement *re = connection->returnElement;
    787 +	if (strcmp(re->name, "artists") == 0) {
    788 +	    stats->numberOfArtists = atoi(re->value);
    789 +	} else if (strcmp(re->name, "albums") == 0) {
    790 +	    stats->numberOfAlbums = atoi(re->value);
    791 +	} else if (strcmp(re->name, "songs") == 0) {
    792 +	    stats->numberOfSongs = atoi(re->value);
    793 +	} else if (strcmp(re->name, "uptime") == 0) {
    794 +	    stats->uptime = strtol(re->value, NULL, 10);
    795 +	} else if (strcmp(re->name, "db_update") == 0) {
    796 +	    stats->dbUpdateTime = strtol(re->value, NULL, 10);
    797 +	} else if (strcmp(re->name, "playtime") == 0) {
    798 +	    stats->playTime = strtol(re->value, NULL, 10);
    799 +	} else if (strcmp(re->name, "db_playtime") == 0) {
    800 +	    stats->dbPlayTime = strtol(re->value, NULL, 10);
    801 +	}
    802 +
    803 +	mpd_getNextReturnElement(connection);
    804 +	if (connection->error) {
    805 +	    free(stats);
    806 +	    return NULL;
    807 +	}
    808 +    }
    809 +
    810 +    if (connection->error) {
    811 +	free(stats);
    812 +	return NULL;
    813 +    }
    814 +
    815 +    return stats;
    816 +}
    817 +
    818 +void mpd_freeStats(mpd_Stats * stats)
    819 +{
    820 +    free(stats);
    821 +}
    822 +
    823 +mpd_SearchStats *mpd_getSearchStats(mpd_Connection * connection)
    824 +{
    825 +    mpd_SearchStats *stats;
    826 +    mpd_ReturnElement *re;
    827 +
    828 +    if (connection->doneProcessing || (connection->listOks && connection->doneListOk)) {
    829 +	return NULL;
    830 +    }
    831 +
    832 +    if (!connection->returnElement)
    833 +	mpd_getNextReturnElement(connection);
    834 +
    835 +    if (connection->error)
    836 +	return NULL;
    837 +
    838 +    stats = malloc(sizeof(mpd_SearchStats));
    839 +    stats->numberOfSongs = 0;
    840 +    stats->playTime = 0;
    841 +
    842 +    while (connection->returnElement) {
    843 +	re = connection->returnElement;
    844 +
    845 +	if (strcmp(re->name, "songs") == 0) {
    846 +	    stats->numberOfSongs = atoi(re->value);
    847 +	} else if (strcmp(re->name, "playtime") == 0) {
    848 +	    stats->playTime = strtol(re->value, NULL, 10);
    849 +	}
    850 +
    851 +	mpd_getNextReturnElement(connection);
    852 +	if (connection->error) {
    853 +	    free(stats);
    854 +	    return NULL;
    855 +	}
    856 +    }
    857 +
    858 +    if (connection->error) {
    859 +	free(stats);
    860 +	return NULL;
    861 +    }
    862 +
    863 +    return stats;
    864 +}
    865 +
    866 +void mpd_freeSearchStats(mpd_SearchStats * stats)
    867 +{
    868 +    free(stats);
    869 +}
    870 +
    871 +static void mpd_initSong(mpd_Song * song)
    872 +{
    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->performer = NULL;
    884 +    song->disc = NULL;
    885 +    song->comment = NULL;
    886 +
    887 +    song->time = MPD_SONG_NO_TIME;
    888 +    song->pos = MPD_SONG_NO_NUM;
    889 +    song->id = MPD_SONG_NO_ID;
    890 +}
    891 +
    892 +static void mpd_finishSong(mpd_Song * song)
    893 +{
    894 +    if (song->file)
    895 +	free(song->file);
    896 +    if (song->artist)
    897 +	free(song->artist);
    898 +    if (song->album)
    899 +	free(song->album);
    900 +    if (song->title)
    901 +	free(song->title);
    902 +    if (song->track)
    903 +	free(song->track);
    904 +    if (song->name)
    905 +	free(song->name);
    906 +    if (song->date)
    907 +	free(song->date);
    908 +    if (song->genre)
    909 +	free(song->genre);
    910 +    if (song->composer)
    911 +	free(song->composer);
    912 +    if (song->disc)
    913 +	free(song->disc);
    914 +    if (song->comment)
    915 +	free(song->comment);
    916 +}
    917 +
    918 +mpd_Song *mpd_newSong(void)
    919 +{
    920 +    mpd_Song *ret = malloc(sizeof(mpd_Song));
    921 +
    922 +    mpd_initSong(ret);
    923 +
    924 +    return ret;
    925 +}
    926 +
    927 +void mpd_freeSong(mpd_Song * song)
    928 +{
    929 +    mpd_finishSong(song);
    930 +    free(song);
    931 +}
    932 +
    933 +mpd_Song *mpd_songDup(mpd_Song * song)
    934 +{
    935 +    mpd_Song *ret = mpd_newSong();
    936 +
    937 +    if (song->file)
    938 +	ret->file = strdup(song->file);
    939 +    if (song->artist)
    940 +	ret->artist = strdup(song->artist);
    941 +    if (song->album)
    942 +	ret->album = strdup(song->album);
    943 +    if (song->title)
    944 +	ret->title = strdup(song->title);
    945 +    if (song->track)
    946 +	ret->track = strdup(song->track);
    947 +    if (song->name)
    948 +	ret->name = strdup(song->name);
    949 +    if (song->date)
    950 +	ret->date = strdup(song->date);
    951 +    if (song->genre)
    952 +	ret->genre = strdup(song->genre);
    953 +    if (song->composer)
    954 +	ret->composer = strdup(song->composer);
    955 +    if (song->disc)
    956 +	ret->disc = strdup(song->disc);
    957 +    if (song->comment)
    958 +	ret->comment = strdup(song->comment);
    959 +    ret->time = song->time;
    960 +    ret->pos = song->pos;
    961 +    ret->id = song->id;
    962 +
    963 +    return ret;
    964 +}
    965 +
    966 +static void mpd_initDirectory(mpd_Directory * directory)
    967 +{
    968 +    directory->path = NULL;
    969 +}
    970 +
    971 +static void mpd_finishDirectory(mpd_Directory * directory)
    972 +{
    973 +    if (directory->path)
    974 +	free(directory->path);
    975 +}
    976 +
    977 +mpd_Directory *mpd_newDirectory(void)
    978 +{
    979 +    mpd_Directory *directory = malloc(sizeof(mpd_Directory));;
    980 +
    981 +    mpd_initDirectory(directory);
    982 +
    983 +    return directory;
    984 +}
    985 +
    986 +void mpd_freeDirectory(mpd_Directory * directory)
    987 +{
    988 +    mpd_finishDirectory(directory);
    989 +
    990 +    free(directory);
    991 +}
    992 +
    993 +mpd_Directory *mpd_directoryDup(mpd_Directory * directory)
    994 +{
    995 +    mpd_Directory *ret = mpd_newDirectory();
    996 +
    997 +    if (directory->path)
    998 +	ret->path = strdup(directory->path);
    999 +
   1000 +    return ret;
   1001 +}
   1002 +
   1003 +static void mpd_initPlaylistFile(mpd_PlaylistFile * playlist)
   1004 +{
   1005 +    playlist->path = NULL;
   1006 +}
   1007 +
   1008 +static void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist)
   1009 +{
   1010 +    if (playlist->path)
   1011 +	free(playlist->path);
   1012 +}
   1013 +
   1014 +mpd_PlaylistFile *mpd_newPlaylistFile(void)
   1015 +{
   1016 +    mpd_PlaylistFile *playlist = malloc(sizeof(mpd_PlaylistFile));
   1017 +
   1018 +    mpd_initPlaylistFile(playlist);
   1019 +
   1020 +    return playlist;
   1021 +}
   1022 +
   1023 +void mpd_freePlaylistFile(mpd_PlaylistFile * playlist)
   1024 +{
   1025 +    mpd_finishPlaylistFile(playlist);
   1026 +    free(playlist);
   1027 +}
   1028 +
   1029 +mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile * playlist)
   1030 +{
   1031 +    mpd_PlaylistFile *ret = mpd_newPlaylistFile();
   1032 +
   1033 +    if (playlist->path)
   1034 +	ret->path = strdup(playlist->path);
   1035 +
   1036 +    return ret;
   1037 +}
   1038 +
   1039 +static void mpd_initInfoEntity(mpd_InfoEntity * entity)
   1040 +{
   1041 +    entity->info.directory = NULL;
   1042 +}
   1043 +
   1044 +static void mpd_finishInfoEntity(mpd_InfoEntity * entity)
   1045 +{
   1046 +    if (entity->info.directory) {
   1047 +	if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
   1048 +	    mpd_freeDirectory(entity->info.directory);
   1049 +	} else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
   1050 +	    mpd_freeSong(entity->info.song);
   1051 +	} else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
   1052 +	    mpd_freePlaylistFile(entity->info.playlistFile);
   1053 +	}
   1054 +    }
   1055 +}
   1056 +
   1057 +mpd_InfoEntity *mpd_newInfoEntity(void)
   1058 +{
   1059 +    mpd_InfoEntity *entity = malloc(sizeof(mpd_InfoEntity));
   1060 +
   1061 +    mpd_initInfoEntity(entity);
   1062 +
   1063 +    return entity;
   1064 +}
   1065 +
   1066 +void mpd_freeInfoEntity(mpd_InfoEntity * entity)
   1067 +{
   1068 +    mpd_finishInfoEntity(entity);
   1069 +    free(entity);
   1070 +}
   1071 +
   1072 +static void mpd_sendInfoCommand(mpd_Connection * connection, char *command)
   1073 +{
   1074 +    mpd_executeCommand(connection, command);
   1075 +}
   1076 +
   1077 +mpd_InfoEntity *mpd_getNextInfoEntity(mpd_Connection * connection)
   1078 +{
   1079 +    mpd_InfoEntity *entity = NULL;
   1080 +
   1081 +    if (connection->doneProcessing || (connection->listOks && connection->doneListOk)) {
   1082 +	return NULL;
   1083 +    }
   1084 +
   1085 +    if (!connection->returnElement)
   1086 +	mpd_getNextReturnElement(connection);
   1087 +
   1088 +    if (connection->returnElement) {
   1089 +	if (strcmp(connection->returnElement->name, "file") == 0) {
   1090 +	    entity = mpd_newInfoEntity();
   1091 +	    entity->type = MPD_INFO_ENTITY_TYPE_SONG;
   1092 +	    entity->info.song = mpd_newSong();
   1093 +	    entity->info.song->file = strdup(connection->returnElement->value);
   1094 +	} else if (strcmp(connection->returnElement->name, "directory") == 0) {
   1095 +	    entity = mpd_newInfoEntity();
   1096 +	    entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
   1097 +	    entity->info.directory = mpd_newDirectory();
   1098 +	    entity->info.directory->path = strdup(connection->returnElement->value);
   1099 +	} else if (strcmp(connection->returnElement->name, "playlist") == 0) {
   1100 +	    entity = mpd_newInfoEntity();
   1101 +	    entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
   1102 +	    entity->info.playlistFile = mpd_newPlaylistFile();
   1103 +	    entity->info.playlistFile->path = strdup(connection->returnElement->value);
   1104 +	} else if (strcmp(connection->returnElement->name, "cpos") == 0) {
   1105 +	    entity = mpd_newInfoEntity();
   1106 +	    entity->type = MPD_INFO_ENTITY_TYPE_SONG;
   1107 +	    entity->info.song = mpd_newSong();
   1108 +	    entity->info.song->pos = atoi(connection->returnElement->value);
   1109 +	} else {
   1110 +	    connection->error = 1;
   1111 +	    strcpy(connection->errorStr, "problem parsing song info");
   1112 +	    return NULL;
   1113 +	}
   1114 +    } else
   1115 +	return NULL;
   1116 +
   1117 +    mpd_getNextReturnElement(connection);
   1118 +    while (connection->returnElement) {
   1119 +	mpd_ReturnElement *re = connection->returnElement;
   1120 +
   1121 +	if (strcmp(re->name, "file") == 0)
   1122 +	    return entity;
   1123 +	else if (strcmp(re->name, "directory") == 0)
   1124 +	    return entity;
   1125 +	else if (strcmp(re->name, "playlist") == 0)
   1126 +	    return entity;
   1127 +	else if (strcmp(re->name, "cpos") == 0)
   1128 +	    return entity;
   1129 +
   1130 +	if (entity->type == MPD_INFO_ENTITY_TYPE_SONG && strlen(re->value)) {
   1131 +	    if (!entity->info.song->artist && strcmp(re->name, "Artist") == 0) {
   1132 +		entity->info.song->artist = strdup(re->value);
   1133 +	    } else if (!entity->info.song->album && strcmp(re->name, "Album") == 0) {
   1134 +		entity->info.song->album = strdup(re->value);
   1135 +	    } else if (!entity->info.song->title && strcmp(re->name, "Title") == 0) {
   1136 +		entity->info.song->title = strdup(re->value);
   1137 +	    } else if (!entity->info.song->track && strcmp(re->name, "Track") == 0) {
   1138 +		entity->info.song->track = strdup(re->value);
   1139 +	    } else if (!entity->info.song->name && strcmp(re->name, "Name") == 0) {
   1140 +		entity->info.song->name = strdup(re->value);
   1141 +	    } else if (entity->info.song->time == MPD_SONG_NO_TIME && strcmp(re->name, "Time") == 0) {
   1142 +		entity->info.song->time = atoi(re->value);
   1143 +	    } else if (entity->info.song->pos == MPD_SONG_NO_NUM && strcmp(re->name, "Pos") == 0) {
   1144 +		entity->info.song->pos = atoi(re->value);
   1145 +	    } else if (entity->info.song->id == MPD_SONG_NO_ID && strcmp(re->name, "Id") == 0) {
   1146 +		entity->info.song->id = atoi(re->value);
   1147 +	    } else if (!entity->info.song->date && strcmp(re->name, "Date") == 0) {
   1148 +		entity->info.song->date = strdup(re->value);
   1149 +	    } else if (!entity->info.song->genre && strcmp(re->name, "Genre") == 0) {
   1150 +		entity->info.song->genre = strdup(re->value);
   1151 +	    } else if (!entity->info.song->composer && strcmp(re->name, "Composer") == 0) {
   1152 +		entity->info.song->composer = strdup(re->value);
   1153 +	    } else if (!entity->info.song->performer && strcmp(re->name, "Performer") == 0) {
   1154 +		entity->info.song->performer = strdup(re->value);
   1155 +	    } else if (!entity->info.song->disc && strcmp(re->name, "Disc") == 0) {
   1156 +		entity->info.song->disc = strdup(re->value);
   1157 +	    } else if (!entity->info.song->comment && strcmp(re->name, "Comment") == 0) {
   1158 +		entity->info.song->comment = strdup(re->value);
   1159 +	    }
   1160 +	} else if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
   1161 +	} else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
   1162 +	}
   1163 +
   1164 +	mpd_getNextReturnElement(connection);
   1165 +    }
   1166 +
   1167 +    return entity;
   1168 +}
   1169 +
   1170 +static char *mpd_getNextReturnElementNamed(mpd_Connection * connection, const char *name)
   1171 +{
   1172 +    if (connection->doneProcessing || (connection->listOks && connection->doneListOk)) {
   1173 +	return NULL;
   1174 +    }
   1175 +
   1176 +    mpd_getNextReturnElement(connection);
   1177 +    while (connection->returnElement) {
   1178 +	mpd_ReturnElement *re = connection->returnElement;
   1179 +
   1180 +	if (strcmp(re->name, name) == 0)
   1181 +	    return strdup(re->value);
   1182 +	mpd_getNextReturnElement(connection);
   1183 +    }
   1184 +
   1185 +    return NULL;
   1186 +}
   1187 +
   1188 +char *mpd_getNextTag(mpd_Connection * connection, int type)
   1189 +{
   1190 +    if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES || type == MPD_TAG_ITEM_ANY)
   1191 +	return NULL;
   1192 +    if (type == MPD_TAG_ITEM_FILENAME)
   1193 +	return mpd_getNextReturnElementNamed(connection, "file");
   1194 +    return mpd_getNextReturnElementNamed(connection, mpdTagItemKeys[type]);
   1195 +}
   1196 +
   1197 +char *mpd_getNextArtist(mpd_Connection * connection)
   1198 +{
   1199 +    return mpd_getNextReturnElementNamed(connection, "Artist");
   1200 +}
   1201 +
   1202 +char *mpd_getNextAlbum(mpd_Connection * connection)
   1203 +{
   1204 +    return mpd_getNextReturnElementNamed(connection, "Album");
   1205 +}
   1206 +
   1207 +void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos)
   1208 +{
   1209 +    int len = strlen("playlistinfo") + 2 + INTLEN + 3;
   1210 +    char *string = malloc(len);
   1211 +    snprintf(string, len, "playlistinfo \"%i\"\n", songPos);
   1212 +    mpd_sendInfoCommand(connection, string);
   1213 +    free(string);
   1214 +}
   1215 +
   1216 +void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id)
   1217 +{
   1218 +    int len = strlen("playlistid") + 2 + INTLEN + 3;
   1219 +    char *string = malloc(len);
   1220 +    snprintf(string, len, "playlistid \"%i\"\n", id);
   1221 +    mpd_sendInfoCommand(connection, string);
   1222 +    free(string);
   1223 +}
   1224 +
   1225 +void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist)
   1226 +{
   1227 +    int len = strlen("plchanges") + 2 + LONGLONGLEN + 3;
   1228 +    char *string = malloc(len);
   1229 +    snprintf(string, len, "plchanges \"%lld\"\n", playlist);
   1230 +    mpd_sendInfoCommand(connection, string);
   1231 +    free(string);
   1232 +}
   1233 +
   1234 +void mpd_sendPlChangesPosIdCommand(mpd_Connection * connection, long long playlist)
   1235 +{
   1236 +    int len = strlen("plchangesposid") + 2 + LONGLONGLEN + 3;
   1237 +    char *string = malloc(len);
   1238 +    snprintf(string, len, "plchangesposid \"%lld\"\n", playlist);
   1239 +    mpd_sendInfoCommand(connection, string);
   1240 +    free(string);
   1241 +}
   1242 +
   1243 +void mpd_sendListallCommand(mpd_Connection * connection, const char *dir)
   1244 +{
   1245 +    char *sDir = mpd_sanitizeArg(dir);
   1246 +    int len = strlen("listall") + 2 + strlen(sDir) + 3;
   1247 +    char *string = malloc(len);
   1248 +    snprintf(string, len, "listall \"%s\"\n", sDir);
   1249 +    mpd_sendInfoCommand(connection, string);
   1250 +    free(string);
   1251 +    free(sDir);
   1252 +}
   1253 +
   1254 +void mpd_sendListallInfoCommand(mpd_Connection * connection, const char *dir)
   1255 +{
   1256 +    char *sDir = mpd_sanitizeArg(dir);
   1257 +    int len = strlen("listallinfo") + 2 + strlen(sDir) + 3;
   1258 +    char *string = malloc(len);
   1259 +    snprintf(string, len, "listallinfo \"%s\"\n", sDir);
   1260 +    mpd_sendInfoCommand(connection, string);
   1261 +    free(string);
   1262 +    free(sDir);
   1263 +}
   1264 +
   1265 +void mpd_sendLsInfoCommand(mpd_Connection * connection, const char *dir)
   1266 +{
   1267 +    char *sDir = mpd_sanitizeArg(dir);
   1268 +    int len = strlen("lsinfo") + 2 + strlen(sDir) + 3;
   1269 +    char *string = malloc(len);
   1270 +    snprintf(string, len, "lsinfo \"%s\"\n", sDir);
   1271 +    mpd_sendInfoCommand(connection, string);
   1272 +    free(string);
   1273 +    free(sDir);
   1274 +}
   1275 +
   1276 +void mpd_sendCurrentSongCommand(mpd_Connection * connection)
   1277 +{
   1278 +    mpd_executeCommand(connection, "currentsong\n");
   1279 +}
   1280 +
   1281 +void mpd_sendSearchCommand(mpd_Connection * connection, int table, const char *str)
   1282 +{
   1283 +    mpd_startSearch(connection, 0);
   1284 +    mpd_addConstraintSearch(connection, table, str);
   1285 +    mpd_commitSearch(connection);
   1286 +}
   1287 +
   1288 +void mpd_sendFindCommand(mpd_Connection * connection, int table, const char *str)
   1289 +{
   1290 +    mpd_startSearch(connection, 1);
   1291 +    mpd_addConstraintSearch(connection, table, str);
   1292 +    mpd_commitSearch(connection);
   1293 +}
   1294 +
   1295 +void mpd_sendListCommand(mpd_Connection * connection, int table, const char *arg1)
   1296 +{
   1297 +    char st[10];
   1298 +    int len;
   1299 +    char *string;
   1300 +    if (table == MPD_TABLE_ARTIST)
   1301 +	strcpy(st, "artist");
   1302 +    else if (table == MPD_TABLE_ALBUM)
   1303 +	strcpy(st, "album");
   1304 +    else {
   1305 +	connection->error = 1;
   1306 +	strcpy(connection->errorStr, "unknown table for list");
   1307 +	return;
   1308 +    }
   1309 +    if (arg1) {
   1310 +	char *sanitArg1 = mpd_sanitizeArg(arg1);
   1311 +	len = strlen("list") + 1 + strlen(sanitArg1) + 2 + strlen(st) + 3;
   1312 +	string = malloc(len);
   1313 +	snprintf(string, len, "list %s \"%s\"\n", st, sanitArg1);
   1314 +	free(sanitArg1);
   1315 +    } else {
   1316 +	len = strlen("list") + 1 + strlen(st) + 2;
   1317 +	string = malloc(len);
   1318 +	snprintf(string, len, "list %s\n", st);
   1319 +    }
   1320 +    mpd_sendInfoCommand(connection, string);
   1321 +    free(string);
   1322 +}
   1323 +
   1324 +void mpd_sendAddCommand(mpd_Connection * connection, const char *file)
   1325 +{
   1326 +    char *sFile = mpd_sanitizeArg(file);
   1327 +    int len = strlen("add") + 2 + strlen(sFile) + 3;
   1328 +    char *string = malloc(len);
   1329 +    snprintf(string, len, "add \"%s\"\n", sFile);
   1330 +    mpd_executeCommand(connection, string);
   1331 +    free(string);
   1332 +    free(sFile);
   1333 +}
   1334 +
   1335 +int mpd_sendAddIdCommand(mpd_Connection * connection, const char *file)
   1336 +{
   1337 +    int retval = -1;
   1338 +    char *sFile = mpd_sanitizeArg(file);
   1339 +    int len = strlen("addid") + 2 + strlen(sFile) + 3;
   1340 +    char *string = malloc(len);
   1341 +
   1342 +    snprintf(string, len, "addid \"%s\"\n", sFile);
   1343 +    mpd_sendInfoCommand(connection, string);
   1344 +    free(string);
   1345 +    free(sFile);
   1346 +
   1347 +    string = mpd_getNextReturnElementNamed(connection, "Id");
   1348 +    if (string) {
   1349 +	retval = atoi(string);
   1350 +	free(string);
   1351 +    }
   1352 +
   1353 +    return retval;
   1354 +}
   1355 +
   1356 +void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos)
   1357 +{
   1358 +    int len = strlen("delete") + 2 + INTLEN + 3;
   1359 +    char *string = malloc(len);
   1360 +    snprintf(string, len, "delete \"%i\"\n", songPos);
   1361 +    mpd_sendInfoCommand(connection, string);
   1362 +    free(string);
   1363 +}
   1364 +
   1365 +void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id)
   1366 +{
   1367 +    int len = strlen("deleteid") + 2 + INTLEN + 3;
   1368 +    char *string = malloc(len);
   1369 +    snprintf(string, len, "deleteid \"%i\"\n", id);
   1370 +    mpd_sendInfoCommand(connection, string);
   1371 +    free(string);
   1372 +}
   1373 +
   1374 +void mpd_sendSaveCommand(mpd_Connection * connection, const char *name)
   1375 +{
   1376 +    char *sName = mpd_sanitizeArg(name);
   1377 +    int len = strlen("save") + 2 + strlen(sName) + 3;
   1378 +    char *string = malloc(len);
   1379 +    snprintf(string, len, "save \"%s\"\n", sName);
   1380 +    mpd_executeCommand(connection, string);
   1381 +    free(string);
   1382 +    free(sName);
   1383 +}
   1384 +
   1385 +void mpd_sendLoadCommand(mpd_Connection * connection, const char *name)
   1386 +{
   1387 +    char *sName = mpd_sanitizeArg(name);
   1388 +    int len = strlen("load") + 2 + strlen(sName) + 3;
   1389 +    char *string = malloc(len);
   1390 +    snprintf(string, len, "load \"%s\"\n", sName);
   1391 +    mpd_executeCommand(connection, string);
   1392 +    free(string);
   1393 +    free(sName);
   1394 +}
   1395 +
   1396 +void mpd_sendRmCommand(mpd_Connection * connection, const char *name)
   1397 +{
   1398 +    char *sName = mpd_sanitizeArg(name);
   1399 +    int len = strlen("rm") + 2 + strlen(sName) + 3;
   1400 +    char *string = malloc(len);
   1401 +    snprintf(string, len, "rm \"%s\"\n", sName);
   1402 +    mpd_executeCommand(connection, string);
   1403 +    free(string);
   1404 +    free(sName);
   1405 +}
   1406 +
   1407 +void mpd_sendRenameCommand(mpd_Connection * connection, const char *from, const char *to)
   1408 +{
   1409 +    char *sFrom = mpd_sanitizeArg(from);
   1410 +    char *sTo = mpd_sanitizeArg(to);
   1411 +    int len = strlen("rename") + 2 + strlen(sFrom) + 3 + strlen(sTo) + 3;
   1412 +    char *string = malloc(len);
   1413 +    snprintf(string, len, "rename \"%s\" \"%s\"\n", sFrom, sTo);
   1414 +    mpd_executeCommand(connection, string);
   1415 +    free(string);
   1416 +    free(sFrom);
   1417 +    free(sTo);
   1418 +}
   1419 +
   1420 +void mpd_sendShuffleCommand(mpd_Connection * connection)
   1421 +{
   1422 +    mpd_executeCommand(connection, "shuffle\n");
   1423 +}
   1424 +
   1425 +void mpd_sendClearCommand(mpd_Connection * connection)
   1426 +{
   1427 +    mpd_executeCommand(connection, "clear\n");
   1428 +}
   1429 +
   1430 +void mpd_sendPlayCommand(mpd_Connection * connection, int songPos)
   1431 +{
   1432 +    int len = strlen("play") + 2 + INTLEN + 3;
   1433 +    char *string = malloc(len);
   1434 +    snprintf(string, len, "play \"%i\"\n", songPos);
   1435 +    mpd_sendInfoCommand(connection, string);
   1436 +    free(string);
   1437 +}
   1438 +
   1439 +void mpd_sendPlayIdCommand(mpd_Connection * connection, int id)
   1440 +{
   1441 +    int len = strlen("playid") + 2 + INTLEN + 3;
   1442 +    char *string = malloc(len);
   1443 +    snprintf(string, len, "playid \"%i\"\n", id);
   1444 +    mpd_sendInfoCommand(connection, string);
   1445 +    free(string);
   1446 +}
   1447 +
   1448 +void mpd_sendStopCommand(mpd_Connection * connection)
   1449 +{
   1450 +    mpd_executeCommand(connection, "stop\n");
   1451 +}
   1452 +
   1453 +void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode)
   1454 +{
   1455 +    int len = strlen("pause") + 2 + INTLEN + 3;
   1456 +    char *string = malloc(len);
   1457 +    snprintf(string, len, "pause \"%i\"\n", pauseMode);
   1458 +    mpd_executeCommand(connection, string);
   1459 +    free(string);
   1460 +}
   1461 +
   1462 +void mpd_sendNextCommand(mpd_Connection * connection)
   1463 +{
   1464 +    mpd_executeCommand(connection, "next\n");
   1465 +}
   1466 +
   1467 +void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to)
   1468 +{
   1469 +    int len = strlen("move") + 2 + INTLEN + 3 + INTLEN + 3;
   1470 +    char *string = malloc(len);
   1471 +    snprintf(string, len, "move \"%i\" \"%i\"\n", from, to);
   1472 +    mpd_sendInfoCommand(connection, string);
   1473 +    free(string);
   1474 +}
   1475 +
   1476 +void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to)
   1477 +{
   1478 +    int len = strlen("moveid") + 2 + INTLEN + 3 + INTLEN + 3;
   1479 +    char *string = malloc(len);
   1480 +    snprintf(string, len, "moveid \"%i\" \"%i\"\n", id, to);
   1481 +    mpd_sendInfoCommand(connection, string);
   1482 +    free(string);
   1483 +}
   1484 +
   1485 +void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2)
   1486 +{
   1487 +    int len = strlen("swap") + 2 + INTLEN + 3 + INTLEN + 3;
   1488 +    char *string = malloc(len);
   1489 +    snprintf(string, len, "swap \"%i\" \"%i\"\n", song1, song2);
   1490 +    mpd_sendInfoCommand(connection, string);
   1491 +    free(string);
   1492 +}
   1493 +
   1494 +void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2)
   1495 +{
   1496 +    int len = strlen("swapid") + 2 + INTLEN + 3 + INTLEN + 3;
   1497 +    char *string = malloc(len);
   1498 +    snprintf(string, len, "swapid \"%i\" \"%i\"\n", id1, id2);
   1499 +    mpd_sendInfoCommand(connection, string);
   1500 +    free(string);
   1501 +}
   1502 +
   1503 +void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time)
   1504 +{
   1505 +    int len = strlen("seek") + 2 + INTLEN + 3 + INTLEN + 3;
   1506 +    char *string = malloc(len);
   1507 +    snprintf(string, len, "seek \"%i\" \"%i\"\n", song, time);
   1508 +    mpd_sendInfoCommand(connection, string);
   1509 +    free(string);
   1510 +}
   1511 +
   1512 +void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time)
   1513 +{
   1514 +    int len = strlen("seekid") + 2 + INTLEN + 3 + INTLEN + 3;
   1515 +    char *string = malloc(len);
   1516 +    snprintf(string, len, "seekid \"%i\" \"%i\"\n", id, time);
   1517 +    mpd_sendInfoCommand(connection, string);
   1518 +    free(string);
   1519 +}
   1520 +
   1521 +void mpd_sendUpdateCommand(mpd_Connection * connection, char *path)
   1522 +{
   1523 +    char *sPath = mpd_sanitizeArg(path);
   1524 +    int len = strlen("update") + 2 + strlen(sPath) + 3;
   1525 +    char *string = malloc(len);
   1526 +    snprintf(string, len, "update \"%s\"\n", sPath);
   1527 +    mpd_sendInfoCommand(connection, string);
   1528 +    free(string);
   1529 +    free(sPath);
   1530 +}
   1531 +
   1532 +int mpd_getUpdateId(mpd_Connection * connection)
   1533 +{
   1534 +    char *jobid;
   1535 +    int ret = 0;
   1536 +
   1537 +    jobid = mpd_getNextReturnElementNamed(connection, "updating_db");
   1538 +    if (jobid) {
   1539 +	ret = atoi(jobid);
   1540 +	free(jobid);
   1541 +    }
   1542 +
   1543 +    return ret;
   1544 +}
   1545 +
   1546 +void mpd_sendPrevCommand(mpd_Connection * connection)
   1547 +{
   1548 +    mpd_executeCommand(connection, "previous\n");
   1549 +}
   1550 +
   1551 +void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode)
   1552 +{
   1553 +    int len = strlen("repeat") + 2 + INTLEN + 3;
   1554 +    char *string = malloc(len);
   1555 +    snprintf(string, len, "repeat \"%i\"\n", repeatMode);
   1556 +    mpd_executeCommand(connection, string);
   1557 +    free(string);
   1558 +}
   1559 +
   1560 +void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode)
   1561 +{
   1562 +    int len = strlen("random") + 2 + INTLEN + 3;
   1563 +    char *string = malloc(len);
   1564 +    snprintf(string, len, "random \"%i\"\n", randomMode);
   1565 +    mpd_executeCommand(connection, string);
   1566 +    free(string);
   1567 +}
   1568 +
   1569 +void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange)
   1570 +{
   1571 +    int len = strlen("setvol") + 2 + INTLEN + 3;
   1572 +    char *string = malloc(len);
   1573 +    snprintf(string, len, "setvol \"%i\"\n", volumeChange);
   1574 +    mpd_executeCommand(connection, string);
   1575 +    free(string);
   1576 +}
   1577 +
   1578 +void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange)
   1579 +{
   1580 +    int len = strlen("volume") + 2 + INTLEN + 3;
   1581 +    char *string = malloc(len);
   1582 +    snprintf(string, len, "volume \"%i\"\n", volumeChange);
   1583 +    mpd_executeCommand(connection, string);
   1584 +    free(string);
   1585 +}
   1586 +
   1587 +void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds)
   1588 +{
   1589 +    int len = strlen("crossfade") + 2 + INTLEN + 3;
   1590 +    char *string = malloc(len);
   1591 +    snprintf(string, len, "crossfade \"%i\"\n", seconds);
   1592 +    mpd_executeCommand(connection, string);
   1593 +    free(string);
   1594 +}
   1595 +
   1596 +void mpd_sendPasswordCommand(mpd_Connection * connection, const char *pass)
   1597 +{
   1598 +    char *sPass = mpd_sanitizeArg(pass);
   1599 +    int len = strlen("password") + 2 + strlen(sPass) + 3;
   1600 +    char *string = malloc(len);
   1601 +    snprintf(string, len, "password \"%s\"\n", sPass);
   1602 +    mpd_executeCommand(connection, string);
   1603 +    free(string);
   1604 +    free(sPass);
   1605 +}
   1606 +
   1607 +void mpd_sendCommandListBegin(mpd_Connection * connection)
   1608 +{
   1609 +    if (connection->commandList) {
   1610 +	strcpy(connection->errorStr, "already in command list mode");
   1611 +	connection->error = 1;
   1612 +	return;
   1613 +    }
   1614 +    connection->commandList = COMMAND_LIST;
   1615 +    mpd_executeCommand(connection, "command_list_begin\n");
   1616 +}
   1617 +
   1618 +void mpd_sendCommandListOkBegin(mpd_Connection * connection)
   1619 +{
   1620 +    if (connection->commandList) {
   1621 +	strcpy(connection->errorStr, "already in command list mode");
   1622 +	connection->error = 1;
   1623 +	return;
   1624 +    }
   1625 +    connection->commandList = COMMAND_LIST_OK;
   1626 +    mpd_executeCommand(connection, "command_list_ok_begin\n");
   1627 +    connection->listOks = 0;
   1628 +}
   1629 +
   1630 +void mpd_sendCommandListEnd(mpd_Connection * connection)
   1631 +{
   1632 +    if (!connection->commandList) {
   1633 +	strcpy(connection->errorStr, "not in command list mode");
   1634 +	connection->error = 1;
   1635 +	return;
   1636 +    }
   1637 +    connection->commandList = 0;
   1638 +    mpd_executeCommand(connection, "command_list_end\n");
   1639 +}
   1640 +
   1641 +void mpd_sendOutputsCommand(mpd_Connection * connection)
   1642 +{
   1643 +    mpd_executeCommand(connection, "outputs\n");
   1644 +}
   1645 +
   1646 +mpd_OutputEntity *mpd_getNextOutput(mpd_Connection * connection)
   1647 +{
   1648 +    mpd_OutputEntity *output = NULL;
   1649 +
   1650 +    if (connection->doneProcessing || (connection->listOks && connection->doneListOk)) {
   1651 +	return NULL;
   1652 +    }
   1653 +
   1654 +    if (connection->error)
   1655 +	return NULL;
   1656 +
   1657 +    output = malloc(sizeof(mpd_OutputEntity));
   1658 +    output->id = -10;
   1659 +    output->name = NULL;
   1660 +    output->enabled = 0;
   1661 +
   1662 +    if (!connection->returnElement)
   1663 +	mpd_getNextReturnElement(connection);
   1664 +
   1665 +    while (connection->returnElement) {
   1666 +	mpd_ReturnElement *re = connection->returnElement;
   1667 +	if (strcmp(re->name, "outputid") == 0) {
   1668 +	    if (output != NULL && output->id >= 0)
   1669 +		return output;
   1670 +	    output->id = atoi(re->value);
   1671 +	} else if (strcmp(re->name, "outputname") == 0) {
   1672 +	    output->name = strdup(re->value);
   1673 +	} else if (strcmp(re->name, "outputenabled") == 0) {
   1674 +	    output->enabled = atoi(re->value);
   1675 +	}
   1676 +
   1677 +	mpd_getNextReturnElement(connection);
   1678 +	if (connection->error) {
   1679 +	    free(output);
   1680 +	    return NULL;
   1681 +	}
   1682 +
   1683 +    }
   1684 +
   1685 +    return output;
   1686 +}
   1687 +
   1688 +void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId)
   1689 +{
   1690 +    int len = strlen("enableoutput") + 2 + INTLEN + 3;
   1691 +    char *string = malloc(len);
   1692 +    snprintf(string, len, "enableoutput \"%i\"\n", outputId);
   1693 +    mpd_executeCommand(connection, string);
   1694 +    free(string);
   1695 +}
   1696 +
   1697 +void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId)
   1698 +{
   1699 +    int len = strlen("disableoutput") + 2 + INTLEN + 3;
   1700 +    char *string = malloc(len);
   1701 +    snprintf(string, len, "disableoutput \"%i\"\n", outputId);
   1702 +    mpd_executeCommand(connection, string);
   1703 +    free(string);
   1704 +}
   1705 +
   1706 +void mpd_freeOutputElement(mpd_OutputEntity * output)
   1707 +{
   1708 +    free(output->name);
   1709 +    free(output);
   1710 +}
   1711 +
   1712 +/**
   1713 + * mpd_sendNotCommandsCommand
   1714 + * odd naming, but it gets the not allowed commands
   1715 + */
   1716 +
   1717 +void mpd_sendNotCommandsCommand(mpd_Connection * connection)
   1718 +{
   1719 +    mpd_executeCommand(connection, "notcommands\n");
   1720 +}
   1721 +
   1722 +/**
   1723 + * mpd_sendCommandsCommand
   1724 + * odd naming, but it gets the allowed commands
   1725 + */
   1726 +void mpd_sendCommandsCommand(mpd_Connection * connection)
   1727 +{
   1728 +    mpd_executeCommand(connection, "commands\n");
   1729 +}
   1730 +
   1731 +/**
   1732 + * Get the next returned command
   1733 + */
   1734 +char *mpd_getNextCommand(mpd_Connection * connection)
   1735 +{
   1736 +    return mpd_getNextReturnElementNamed(connection, "command");
   1737 +}
   1738 +
   1739 +void mpd_sendUrlHandlersCommand(mpd_Connection * connection)
   1740 +{
   1741 +    mpd_executeCommand(connection, "urlhandlers\n");
   1742 +}
   1743 +
   1744 +char *mpd_getNextHandler(mpd_Connection * connection)
   1745 +{
   1746 +    return mpd_getNextReturnElementNamed(connection, "handler");
   1747 +}
   1748 +
   1749 +void mpd_sendTagTypesCommand(mpd_Connection * connection)
   1750 +{
   1751 +    mpd_executeCommand(connection, "tagtypes\n");
   1752 +}
   1753 +
   1754 +char *mpd_getNextTagType(mpd_Connection * connection)
   1755 +{
   1756 +    return mpd_getNextReturnElementNamed(connection, "tagtype");
   1757 +}
   1758 +
   1759 +void mpd_startSearch(mpd_Connection * connection, int exact)
   1760 +{
   1761 +    if (connection->request) {
   1762 +	strcpy(connection->errorStr, "search already in progress");
   1763 +	connection->error = 1;
   1764 +	return;
   1765 +    }
   1766 +
   1767 +    if (exact)
   1768 +	connection->request = strdup("find");
   1769 +    else
   1770 +	connection->request = strdup("search");
   1771 +}
   1772 +
   1773 +void mpd_startStatsSearch(mpd_Connection * connection)
   1774 +{
   1775 +    if (connection->request) {
   1776 +	strcpy(connection->errorStr, "search already in progress");
   1777 +	connection->error = 1;
   1778 +	return;
   1779 +    }
   1780 +
   1781 +    connection->request = strdup("count");
   1782 +}
   1783 +
   1784 +void mpd_startPlaylistSearch(mpd_Connection * connection, int exact)
   1785 +{
   1786 +    if (connection->request) {
   1787 +	strcpy(connection->errorStr, "search already in progress");
   1788 +	connection->error = 1;
   1789 +	return;
   1790 +    }
   1791 +
   1792 +    if (exact)
   1793 +	connection->request = strdup("playlistfind");
   1794 +    else
   1795 +	connection->request = strdup("playlistsearch");
   1796 +}
   1797 +
   1798 +void mpd_startFieldSearch(mpd_Connection * connection, int type)
   1799 +{
   1800 +    char *strtype;
   1801 +    int len;
   1802 +
   1803 +    if (connection->request) {
   1804 +	strcpy(connection->errorStr, "search already in progress");
   1805 +	connection->error = 1;
   1806 +	return;
   1807 +    }
   1808 +
   1809 +    if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES) {
   1810 +	strcpy(connection->errorStr, "invalid type specified");
   1811 +	connection->error = 1;
   1812 +	return;
   1813 +    }
   1814 +
   1815 +    strtype = mpdTagItemKeys[type];
   1816 +
   1817 +    len = 5 + strlen(strtype) + 1;
   1818 +    connection->request = malloc(len);
   1819 +
   1820 +    snprintf(connection->request, len, "list %c%s", tolower(strtype[0]), strtype + 1);
   1821 +}
   1822 +
   1823 +void mpd_addConstraintSearch(mpd_Connection * connection, int type, const char *name)
   1824 +{
   1825 +    char *strtype;
   1826 +    char *arg;
   1827 +    int len;
   1828 +    char *string;
   1829 +
   1830 +    if (!connection->request) {
   1831 +	strcpy(connection->errorStr, "no search in progress");
   1832 +	connection->error = 1;
   1833 +	return;
   1834 +    }
   1835 +
   1836 +    if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES) {
   1837 +	strcpy(connection->errorStr, "invalid type specified");
   1838 +	connection->error = 1;
   1839 +	return;
   1840 +    }
   1841 +
   1842 +    if (name == NULL) {
   1843 +	strcpy(connection->errorStr, "no name specified");
   1844 +	connection->error = 1;
   1845 +	return;
   1846 +    }
   1847 +
   1848 +    string = strdup(connection->request);
   1849 +    strtype = mpdTagItemKeys[type];
   1850 +    arg = mpd_sanitizeArg(name);
   1851 +
   1852 +    len = strlen(string) + 1 + strlen(strtype) + 2 + strlen(arg) + 2;
   1853 +    connection->request = realloc(connection->request, len);
   1854 +    snprintf(connection->request, len, "%s %c%s \"%s\"", string, tolower(strtype[0]), strtype + 1, arg);
   1855 +
   1856 +    free(string);
   1857 +    free(arg);
   1858 +}
   1859 +
   1860 +void mpd_commitSearch(mpd_Connection * connection)
   1861 +{
   1862 +    int len;
   1863 +
   1864 +    if (!connection->request) {
   1865 +	strcpy(connection->errorStr, "no search in progress");
   1866 +	connection->error = 1;
   1867 +	return;
   1868 +    }
   1869 +
   1870 +    len = strlen(connection->request) + 2;
   1871 +    connection->request = realloc(connection->request, len);
   1872 +    connection->request[len - 2] = '\n';
   1873 +    connection->request[len - 1] = '\0';
   1874 +    mpd_sendInfoCommand(connection, connection->request);
   1875 +
   1876 +    free(connection->request);
   1877 +    connection->request = NULL;
   1878 +}
   1879 +
   1880 +/**
   1881 + * @param connection a MpdConnection
   1882 + * @param path	the path to the playlist.
   1883 + *
   1884 + * List the content, with full metadata, of a stored playlist.
   1885 + *
   1886 + */
   1887 +void mpd_sendListPlaylistInfoCommand(mpd_Connection * connection, char *path)
   1888 +{
   1889 +    char *arg = mpd_sanitizeArg(path);
   1890 +    int len = strlen("listplaylistinfo") + 2 + strlen(arg) + 3;
   1891 +    char *query = malloc(len);
   1892 +    snprintf(query, len, "listplaylistinfo \"%s\"\n", arg);
   1893 +    mpd_sendInfoCommand(connection, query);
   1894 +    free(arg);
   1895 +    free(query);
   1896 +}
   1897 +
   1898 +/**
   1899 + * @param connection a MpdConnection
   1900 + * @param path	the path to the playlist.
   1901 + *
   1902 + * List the content of a stored playlist.
   1903 + *
   1904 + */
   1905 +void mpd_sendListPlaylistCommand(mpd_Connection * connection, char *path)
   1906 +{
   1907 +    char *arg = mpd_sanitizeArg(path);
   1908 +    int len = strlen("listplaylist") + 2 + strlen(arg) + 3;
   1909 +    char *query = malloc(len);
   1910 +    snprintf(query, len, "listplaylist \"%s\"\n", arg);
   1911 +    mpd_sendInfoCommand(connection, query);
   1912 +    free(arg);
   1913 +    free(query);
   1914 +}
   1915 +
   1916 +void mpd_sendPlaylistClearCommand(mpd_Connection * connection, char *path)
   1917 +{
   1918 +    char *sPath = mpd_sanitizeArg(path);
   1919 +    int len = strlen("playlistclear") + 2 + strlen(sPath) + 3;
   1920 +    char *string = malloc(len);
   1921 +    snprintf(string, len, "playlistclear \"%s\"\n", sPath);
   1922 +    mpd_executeCommand(connection, string);
   1923 +    free(sPath);
   1924 +    free(string);
   1925 +}
   1926 +
   1927 +void mpd_sendPlaylistAddCommand(mpd_Connection * connection, char *playlist, char *path)
   1928 +{
   1929 +    char *sPlaylist = mpd_sanitizeArg(playlist);
   1930 +    char *sPath = mpd_sanitizeArg(path);
   1931 +    int len = strlen("playlistadd") + 2 + strlen(sPlaylist) + 3 + strlen(sPath) + 3;
   1932 +    char *string = malloc(len);
   1933 +    snprintf(string, len, "playlistadd \"%s\" \"%s\"\n", sPlaylist, sPath);
   1934 +    mpd_executeCommand(connection, string);
   1935 +    free(sPlaylist);
   1936 +    free(sPath);
   1937 +    free(string);
   1938 +}
   1939 +
   1940 +void mpd_sendPlaylistMoveCommand(mpd_Connection * connection, char *playlist, int from, int to)
   1941 +{
   1942 +    char *sPlaylist = mpd_sanitizeArg(playlist);
   1943 +    int len = strlen("playlistmove") + 2 + strlen(sPlaylist) + 3 + INTLEN + 3 + INTLEN + 3;
   1944 +    char *string = malloc(len);
   1945 +    snprintf(string, len, "playlistmove \"%s\" \"%i\" \"%i\"\n", sPlaylist, from, to);
   1946 +    mpd_executeCommand(connection, string);
   1947 +    free(sPlaylist);
   1948 +    free(string);
   1949 +}
   1950 +
   1951 +void mpd_sendPlaylistDeleteCommand(mpd_Connection * connection, char *playlist, int pos)
   1952 +{
   1953 +    char *sPlaylist = mpd_sanitizeArg(playlist);
   1954 +    int len = strlen("playlistdelete") + 2 + strlen(sPlaylist) + 3 + INTLEN + 3;
   1955 +    char *string = malloc(len);
   1956 +    snprintf(string, len, "playlistdelete \"%s\" \"%i\"\n", sPlaylist, pos);
   1957 +    mpd_executeCommand(connection, string);
   1958 +    free(sPlaylist);
   1959 +    free(string);
   1960 +}
   1961 --- /dev/null
   1962 +++ b/libmpdclient.h
   1963 @@ -0,0 +1,661 @@
   1964 +/* libmpdclient
   1965 +   (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
   1966 +   This project's homepage is: http://www.musicpd.org
   1967 +
   1968 +   Redistribution and use in source and binary forms, with or without
   1969 +   modification, are permitted provided that the following conditions
   1970 +   are met:
   1971 +
   1972 +   - Redistributions of source code must retain the above copyright
   1973 +   notice, this list of conditions and the following disclaimer.
   1974 +
   1975 +   - Redistributions in binary form must reproduce the above copyright
   1976 +   notice, this list of conditions and the following disclaimer in the
   1977 +   documentation and/or other materials provided with the distribution.
   1978 +
   1979 +   - Neither the name of the Music Player Daemon nor the names of its
   1980 +   contributors may be used to endorse or promote products derived from
   1981 +   this software without specific prior written permission.
   1982 +
   1983 +   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   1984 +   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   1985 +   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   1986 +   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   1987 +   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   1988 +   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   1989 +   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   1990 +   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   1991 +   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   1992 +   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   1993 +   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1994 +*/
   1995 +
   1996 +#ifndef LIBMPDCLIENT_H
   1997 +#define LIBMPDCLIENT_H
   1998 +
   1999 +#ifdef WIN32
   2000 +#  define __W32API_USE_DLLIMPORT__ 1
   2001 +#endif
   2002 +
   2003 +#include <sys/time.h>
   2004 +#include <stdarg.h>
   2005 +#define MPD_BUFFER_MAX_LENGTH	50000
   2006 +#define MPD_ERRORSTR_MAX_LENGTH	1000
   2007 +#define MPD_WELCOME_MESSAGE	"OK MPD "
   2008 +
   2009 +#define MPD_ERROR_TIMEOUT	10	/* timeout trying to talk to mpd */
   2010 +#define MPD_ERROR_SYSTEM	11	/* system error */
   2011 +#define MPD_ERROR_UNKHOST	12	/* unknown host */
   2012 +#define MPD_ERROR_CONNPORT	13	/* problems connecting to port on host */
   2013 +#define MPD_ERROR_NOTMPD	14	/* mpd not running on port at host */
   2014 +#define MPD_ERROR_NORESPONSE	15	/* no response on attempting to connect */
   2015 +#define MPD_ERROR_SENDING	16	/* error sending command */
   2016 +#define MPD_ERROR_CONNCLOSED	17	/* connection closed by mpd */
   2017 +#define MPD_ERROR_ACK		18	/* ACK returned! */
   2018 +#define MPD_ERROR_BUFFEROVERRUN	19	/* Buffer was overrun! */
   2019 +
   2020 +#define MPD_ACK_ERROR_UNK	-1
   2021 +#define MPD_ERROR_AT_UNK	-1
   2022 +
   2023 +#define MPD_ACK_ERROR_NOT_LIST			1
   2024 +#define MPD_ACK_ERROR_ARG			2
   2025 +#define MPD_ACK_ERROR_PASSWORD			3
   2026 +#define MPD_ACK_ERROR_PERMISSION		4
   2027 +#define MPD_ACK_ERROR_UNKNOWN_CMD		5
   2028 +
   2029 +#define MPD_ACK_ERROR_NO_EXIST			50
   2030 +#define MPD_ACK_ERROR_PLAYLIST_MAX		51
   2031 +#define MPD_ACK_ERROR_SYSTEM			52
   2032 +#define MPD_ACK_ERROR_PLAYLIST_LOAD		53
   2033 +#define MPD_ACK_ERROR_UPDATE_ALREADY		54
   2034 +#define MPD_ACK_ERROR_PLAYER_SYNC		55
   2035 +#define MPD_ACK_ERROR_EXIST			56
   2036 +
   2037 +#ifdef __cplusplus
   2038 +extern "C" {
   2039 +#endif
   2040 +
   2041 +    typedef enum mpd_TagItems {
   2042 +	MPD_TAG_ITEM_ARTIST,
   2043 +	MPD_TAG_ITEM_ALBUM,
   2044 +	MPD_TAG_ITEM_TITLE,
   2045 +	MPD_TAG_ITEM_TRACK,
   2046 +	MPD_TAG_ITEM_NAME,
   2047 +	MPD_TAG_ITEM_GENRE,
   2048 +	MPD_TAG_ITEM_DATE,
   2049 +	MPD_TAG_ITEM_COMPOSER,
   2050 +	MPD_TAG_ITEM_PERFORMER,
   2051 +	MPD_TAG_ITEM_COMMENT,
   2052 +	MPD_TAG_ITEM_DISC,
   2053 +	MPD_TAG_ITEM_FILENAME,
   2054 +	MPD_TAG_ITEM_ANY,
   2055 +	MPD_TAG_NUM_OF_ITEM_TYPES
   2056 +    } mpd_TagItems;
   2057 +
   2058 +    extern char *mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES];
   2059 +
   2060 +/* internal stuff don't touch this struct */
   2061 +    typedef struct _mpd_ReturnElement {
   2062 +	char *name;
   2063 +	char *value;
   2064 +    } mpd_ReturnElement;
   2065 +
   2066 +/* mpd_Connection
   2067 + * holds info about connection to mpd
   2068 + * use error, and errorStr to detect errors
   2069 + */
   2070 +    typedef struct _mpd_Connection {
   2071 +	/* use this to check the version of mpd */
   2072 +	int version[3];
   2073 +	/* IMPORTANT, you want to get the error messages from here */
   2074 +	char errorStr[MPD_ERRORSTR_MAX_LENGTH + 1];
   2075 +	int errorCode;
   2076 +	int errorAt;
   2077 +	/* this will be set to MPD_ERROR_* if there is an error, 0 if not */
   2078 +	int error;
   2079 +	/* DON'T TOUCH any of the rest of this stuff */
   2080 +	int sock;
   2081 +	char buffer[MPD_BUFFER_MAX_LENGTH + 1];
   2082 +	int buflen;
   2083 +	int bufstart;
   2084 +	int doneProcessing;
   2085 +	int listOks;
   2086 +	int doneListOk;
   2087 +	int commandList;
   2088 +	mpd_ReturnElement *returnElement;
   2089 +	struct timeval timeout;
   2090 +	char *request;
   2091 +    } mpd_Connection;
   2092 +
   2093 +/* mpd_newConnection
   2094 + * use this to open a new connection
   2095 + * you should use mpd_closeConnection, when your done with the connection,
   2096 + * even if an error has occurred
   2097 + * _timeout_ is the connection timeout period in seconds
   2098 + */
   2099 +    mpd_Connection *mpd_newConnection(const char *host, int port, float timeout);
   2100 +
   2101 +    void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout);
   2102 +
   2103 +/* mpd_closeConnection
   2104 + * use this to close a connection and free'ing subsequent memory
   2105 + */
   2106 +    void mpd_closeConnection(mpd_Connection * connection);
   2107 +
   2108 +/* mpd_clearError
   2109 + * clears error
   2110 + */
   2111 +    void mpd_clearError(mpd_Connection * connection);
   2112 +
   2113 +/* STATUS STUFF */
   2114 +
   2115 +/* use these with status.state to determine what state the player is in */
   2116 +#define MPD_STATUS_STATE_UNKNOWN	0
   2117 +#define MPD_STATUS_STATE_STOP		1
   2118 +#define MPD_STATUS_STATE_PLAY		2
   2119 +#define MPD_STATUS_STATE_PAUSE		3
   2120 +
   2121 +/* us this with status.volume to determine if mpd has volume support */
   2122 +#define MPD_STATUS_NO_VOLUME		-1
   2123 +
   2124 +/* mpd_Status
   2125 + * holds info return from status command
   2126 + */
   2127 +    typedef struct mpd_Status {
   2128 +	/* 0-100, or MPD_STATUS_NO_VOLUME when there is no volume support */
   2129 +	int volume;
   2130 +	/* 1 if repeat is on, 0 otherwise */
   2131 +	int repeat;
   2132 +	/* 1 if random is on, 0 otherwise */
   2133 +	int random;
   2134 +	/* playlist length */
   2135 +	int playlistLength;
   2136 +	/* playlist, use this to determine when the playlist has changed */
   2137 +	long long playlist;
   2138 +	/* use with MPD_STATUS_STATE_* to determine state of player */
   2139 +	int state;
   2140 +	/* crossfade setting in seconds */
   2141 +	int crossfade;
   2142 +	/* if a song is currently selected (always the case when state is
   2143 +	 * PLAY or PAUSE), this is the position of the currently
   2144 +	 * playing song in the playlist, beginning with 0
   2145 +	 */
   2146 +	int song;
   2147 +	/* Song ID of the currently selected song */
   2148 +	int songid;
   2149 +	/* time in seconds that have elapsed in the currently playing/paused
   2150 +	 * song
   2151 +	 */
   2152 +	int elapsedTime;
   2153 +	/* length in seconds of the currently playing/paused song */
   2154 +	int totalTime;
   2155 +	/* current bit rate in kbs */
   2156 +	int bitRate;
   2157 +	/* audio sample rate */
   2158 +	unsigned int sampleRate;
   2159 +	/* audio bits */
   2160 +	int bits;
   2161 +	/* audio channels */
   2162 +	int channels;
   2163 +	/* 1 if mpd is updating, 0 otherwise */
   2164 +	int updatingDb;
   2165 +	/* error */
   2166 +	char *error;
   2167 +    } mpd_Status;
   2168 +
   2169 +    void mpd_sendStatusCommand(mpd_Connection * connection);
   2170 +
   2171 +/* mpd_getStatus
   2172 + * returns status info, be sure to free it with mpd_freeStatus()
   2173 + * call this after mpd_sendStatusCommand()
   2174 + */
   2175 +    mpd_Status *mpd_getStatus(mpd_Connection * connection);
   2176 +
   2177 +/* mpd_freeStatus
   2178 + * free's status info malloc'd and returned by mpd_getStatus
   2179 + */
   2180 +    void mpd_freeStatus(mpd_Status * status);
   2181 +
   2182 +    typedef struct _mpd_Stats {
   2183 +	int numberOfArtists;
   2184 +	int numberOfAlbums;
   2185 +	int numberOfSongs;
   2186 +	unsigned long uptime;
   2187 +	unsigned long dbUpdateTime;
   2188 +	unsigned long playTime;
   2189 +	unsigned long dbPlayTime;
   2190 +    } mpd_Stats;
   2191 +
   2192 +    typedef struct _mpd_SearchStats {
   2193 +	int numberOfSongs;
   2194 +	unsigned long playTime;
   2195 +    } mpd_SearchStats;
   2196 +
   2197 +    void mpd_sendStatsCommand(mpd_Connection * connection);
   2198 +
   2199 +    mpd_Stats *mpd_getStats(mpd_Connection * connection);
   2200 +
   2201 +    void mpd_freeStats(mpd_Stats * stats);
   2202 +
   2203 +    mpd_SearchStats *mpd_getSearchStats(mpd_Connection * connection);
   2204 +
   2205 +    void mpd_freeSearchStats(mpd_SearchStats * stats);
   2206 +
   2207 +/* SONG STUFF */
   2208 +
   2209 +#define MPD_SONG_NO_TIME	-1
   2210 +#define MPD_SONG_NO_NUM		-1
   2211 +#define MPD_SONG_NO_ID		-1
   2212 +
   2213 +/* mpd_Song
   2214 + * for storing song info returned by mpd
   2215 + */
   2216 +    typedef struct _mpd_Song {
   2217 +	/* filename of song */
   2218 +	char *file;
   2219 +	/* artist, maybe NULL if there is no tag */
   2220 +	char *artist;
   2221 +	/* title, maybe NULL if there is no tag */
   2222 +	char *title;
   2223 +	/* album, maybe NULL if there is no tag */
   2224 +	char *album;
   2225 +	/* track, maybe NULL if there is no tag */
   2226 +	char *track;
   2227 +	/* name, maybe NULL if there is no tag; it's the name of the current
   2228 +	 * song, f.e. the icyName of the stream */
   2229 +	char *name;
   2230 +	/* date */
   2231 +	char *date;
   2232 +
   2233 +	/* added by qball */
   2234 +	/* Genre */
   2235 +	char *genre;
   2236 +	/* Composer */
   2237 +	char *composer;
   2238 +	/* Performer */
   2239 +	char *performer;
   2240 +	/* Disc */
   2241 +	char *disc;
   2242 +	/* Comment */
   2243 +	char *comment;
   2244 +
   2245 +	/* length of song in seconds, check that it is not MPD_SONG_NO_TIME  */
   2246 +	int time;
   2247 +	/* if plchanges/playlistinfo/playlistid used, is the position of the
   2248 +	 * song in the playlist */
   2249 +	int pos;
   2250 +	/* song id for a song in the playlist */
   2251 +	int id;
   2252 +    } mpd_Song;
   2253 +
   2254 +/* mpd_newSong
   2255 + * use to allocate memory for a new mpd_Song
   2256 + * file, artist, etc all initialized to NULL
   2257 + * if your going to assign values to file, artist, etc
   2258 + * be sure to malloc or strdup the memory
   2259 + * use mpd_freeSong to free the memory for the mpd_Song, it will also
   2260 + * free memory for file, artist, etc, so don't do it yourself
   2261 + */
   2262 +    mpd_Song *mpd_newSong(void);
   2263 +
   2264 +/* mpd_freeSong
   2265 + * use to free memory allocated by mpd_newSong
   2266 + * also it will free memory pointed to by file, artist, etc, so be careful
   2267 + */
   2268 +    void mpd_freeSong(mpd_Song * song);
   2269 +
   2270 +/* mpd_songDup
   2271 + * works like strDup, but for a mpd_Song
   2272 + */
   2273 +    mpd_Song *mpd_songDup(mpd_Song * song);
   2274 +
   2275 +/* DIRECTORY STUFF */
   2276 +
   2277 +/* mpd_Directory
   2278 + * used to store info fro directory (right now that just the path)
   2279 + */
   2280 +    typedef struct _mpd_Directory {
   2281 +	char *path;
   2282 +    } mpd_Directory;
   2283 +
   2284 +/* mpd_newDirectory
   2285 + * allocates memory for a new directory
   2286 + * use mpd_freeDirectory to free this memory
   2287 + */
   2288 +    mpd_Directory *mpd_newDirectory(void);
   2289 +
   2290 +/* mpd_freeDirectory
   2291 + * used to free memory allocated with mpd_newDirectory, and it frees
   2292 + * path of mpd_Directory, so be careful
   2293 + */
   2294 +    void mpd_freeDirectory(mpd_Directory * directory);
   2295 +
   2296 +/* mpd_directoryDup
   2297 + * works like strdup, but for mpd_Directory
   2298 + */
   2299 +    mpd_Directory *mpd_directoryDup(mpd_Directory * directory);
   2300 +
   2301 +/* PLAYLISTFILE STUFF */
   2302 +
   2303 +/* mpd_PlaylistFile
   2304 + * stores info about playlist file returned by lsinfo
   2305 + */
   2306 +    typedef struct _mpd_PlaylistFile {
   2307 +	char *path;
   2308 +    } mpd_PlaylistFile;
   2309 +
   2310 +/* mpd_newPlaylistFile
   2311 + * allocates memory for new mpd_PlaylistFile, path is set to NULL
   2312 + * free this memory with mpd_freePlaylistFile
   2313 + */
   2314 +    mpd_PlaylistFile *mpd_newPlaylistFile(void);
   2315 +
   2316 +/* mpd_freePlaylist
   2317 + * free memory allocated for freePlaylistFile, will also free
   2318 + * path, so be careful
   2319 + */
   2320 +    void mpd_freePlaylistFile(mpd_PlaylistFile * playlist);
   2321 +
   2322 +/* mpd_playlistFileDup
   2323 + * works like strdup, but for mpd_PlaylistFile
   2324 + */
   2325 +    mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile * playlist);
   2326 +
   2327 +/* INFO ENTITY STUFF */
   2328 +
   2329 +/* the type of entity returned from one of the commands that generates info
   2330 + * use in conjunction with mpd_InfoEntity.type
   2331 + */
   2332 +#define MPD_INFO_ENTITY_TYPE_DIRECTORY		0
   2333 +#define MPD_INFO_ENTITY_TYPE_SONG		1
   2334 +#define MPD_INFO_ENTITY_TYPE_PLAYLISTFILE	2
   2335 +
   2336 +/* mpd_InfoEntity
   2337 + * stores info on stuff returned info commands
   2338 + */
   2339 +    typedef struct mpd_InfoEntity {
   2340 +	/* the type of entity, use with MPD_INFO_ENTITY_TYPE_* to determine
   2341 +	 * what this entity is (song, directory, etc...)
   2342 +	 */
   2343 +	int type;
   2344 +	/* the actual data you want, mpd_Song, mpd_Directory, etc */
   2345 +	union {
   2346 +	    mpd_Directory *directory;
   2347 +	    mpd_Song *song;
   2348 +	    mpd_PlaylistFile *playlistFile;
   2349 +	} info;
   2350 +    } mpd_InfoEntity;
   2351 +
   2352 +    mpd_InfoEntity *mpd_newInfoEntity(void);
   2353 +
   2354 +    void mpd_freeInfoEntity(mpd_InfoEntity * entity);
   2355 +
   2356 +/* INFO COMMANDS AND STUFF */
   2357 +
   2358 +/* use this function to loop over after calling Info/Listall functions */
   2359 +    mpd_InfoEntity *mpd_getNextInfoEntity(mpd_Connection * connection);
   2360 +
   2361 +/* fetches the currently seeletect song (the song referenced by status->song
   2362 + * and status->songid*/
   2363 +    void mpd_sendCurrentSongCommand(mpd_Connection * connection);
   2364 +
   2365 +/* songNum of -1, means to display the whole list */
   2366 +    void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songNum);
   2367 +
   2368 +/* songId of -1, means to display the whole list */
   2369 +    void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int songId);
   2370 +
   2371 +/* use this to get the changes in the playlist since version _playlist_ */
   2372 +    void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist);
   2373 +
   2374 +/**
   2375 + * @param connection: A valid and connected mpd_Connection.
   2376 + * @param playlist: The playlist version you want the diff with.
   2377 + * A more bandwidth efficient version of the mpd_sendPlChangesCommand.
   2378 + * It only returns the pos+id of the changes song.
   2379 + */
   2380 +    void mpd_sendPlChangesPosIdCommand(mpd_Connection * connection, long long playlist);
   2381 +
   2382 +/* recursivel fetches all songs/dir/playlists in "dir* (no metadata is
   2383 + * returned) */
   2384 +    void mpd_sendListallCommand(mpd_Connection * connection, const char *dir);
   2385 +
   2386 +/* same as sendListallCommand, but also metadata is returned */
   2387 +    void mpd_sendListallInfoCommand(mpd_Connection * connection, const char *dir);
   2388 +
   2389 +/* non-recursive version of ListallInfo */
   2390 +    void mpd_sendLsInfoCommand(mpd_Connection * connection, const char *dir);
   2391 +
   2392 +#define MPD_TABLE_ARTIST	MPD_TAG_ITEM_ARTIST
   2393 +#define MPD_TABLE_ALBUM		MPD_TAG_ITEM_ALBUM
   2394 +#define MPD_TABLE_TITLE		MPD_TAG_ITEM_TITLE
   2395 +#define MPD_TABLE_FILENAME	MPD_TAG_ITEM_FILENAME
   2396 +
   2397 +    void mpd_sendSearchCommand(mpd_Connection * connection, int table, const char *str);
   2398 +
   2399 +    void mpd_sendFindCommand(mpd_Connection * connection, int table, const char *str);
   2400 +
   2401 +/* LIST TAG COMMANDS */
   2402 +
   2403 +/* use this function fetch next artist entry, be sure to free the returned
   2404 + * string.  NULL means there are no more.  Best used with sendListArtists
   2405 + */
   2406 +    char *mpd_getNextArtist(mpd_Connection * connection);
   2407 +
   2408 +    char *mpd_getNextAlbum(mpd_Connection * connection);
   2409 +
   2410 +    char *mpd_getNextTag(mpd_Connection * connection, int type);
   2411 +
   2412 +/* list artist or albums by artist, arg1 should be set to the artist if
   2413 + * listing albums by a artist, otherwise NULL for listing all artists or albums
   2414 + */
   2415 +    void mpd_sendListCommand(mpd_Connection * connection, int table, const char *arg1);
   2416 +
   2417 +/* SIMPLE COMMANDS */
   2418 +
   2419 +    void mpd_sendAddCommand(mpd_Connection * connection, const char *file);
   2420 +
   2421 +    int mpd_sendAddIdCommand(mpd_Connection * connection, const char *file);
   2422 +
   2423 +    void mpd_sendDeleteCommand(mpd_Connection * connection, int songNum);
   2424 +
   2425 +    void mpd_sendDeleteIdCommand(mpd_Connection * connection, int songNum);
   2426 +
   2427 +    void mpd_sendSaveCommand(mpd_Connection * connection, const char *name);
   2428 +
   2429 +    void mpd_sendLoadCommand(mpd_Connection * connection, const char *name);
   2430 +
   2431 +    void mpd_sendRmCommand(mpd_Connection * connection, const char *name);
   2432 +
   2433 +    void mpd_sendRenameCommand(mpd_Connection * connection, const char *from, const char *to);
   2434 +
   2435 +    void mpd_sendShuffleCommand(mpd_Connection * connection);
   2436 +
   2437 +    void mpd_sendClearCommand(mpd_Connection * connection);
   2438 +
   2439 +/* use this to start playing at the beginning, useful when in random mode */
   2440 +#define MPD_PLAY_AT_BEGINNING	-1
   2441 +
   2442 +    void mpd_sendPlayCommand(mpd_Connection * connection, int songNum);
   2443 +
   2444 +    void mpd_sendPlayIdCommand(mpd_Connection * connection, int songNum);
   2445 +
   2446 +    void mpd_sendStopCommand(mpd_Connection * connection);
   2447 +
   2448 +    void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode);
   2449 +
   2450 +    void mpd_sendNextCommand(mpd_Connection * connection);
   2451 +
   2452 +    void mpd_sendPrevCommand(mpd_Connection * connection);
   2453 +
   2454 +    void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to);
   2455 +
   2456 +    void mpd_sendMoveIdCommand(mpd_Connection * connection, int from, int to);
   2457 +
   2458 +    void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2);
   2459 +
   2460 +    void mpd_sendSwapIdCommand(mpd_Connection * connection, int song1, int song2);
   2461 +
   2462 +    void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time);
   2463 +
   2464 +    void mpd_sendSeekIdCommand(mpd_Connection * connection, int song, int time);
   2465 +
   2466 +    void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode);
   2467 +
   2468 +    void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode);
   2469 +
   2470 +    void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange);
   2471 +
   2472 +/* WARNING: don't use volume command, its depreacted */
   2473 +    void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange);
   2474 +
   2475 +    void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds);
   2476 +
   2477 +    void mpd_sendUpdateCommand(mpd_Connection * connection, char *path);
   2478 +
   2479 +/* returns the update job id, call this after a update command*/
   2480 +    int mpd_getUpdateId(mpd_Connection * connection);
   2481 +
   2482 +    void mpd_sendPasswordCommand(mpd_Connection * connection, const char *pass);
   2483 +
   2484 +/* after executing a command, when your done with it to get its status
   2485 + * (you want to check connection->error for an error)
   2486 + */
   2487 +    void mpd_finishCommand(mpd_Connection * connection);
   2488 +
   2489 +/* command list stuff, use this to do things like add files very quickly */
   2490 +    void mpd_sendCommandListBegin(mpd_Connection * connection);
   2491 +
   2492 +    void mpd_sendCommandListOkBegin(mpd_Connection * connection);
   2493 +
   2494 +    void mpd_sendCommandListEnd(mpd_Connection * connection);
   2495 +
   2496 +/* advance to the next listOk
   2497 + * returns 0 if advanced to the next list_OK,
   2498 + * returns -1 if it advanced to an OK or ACK */
   2499 +    int mpd_nextListOkCommand(mpd_Connection * connection);
   2500 +
   2501 +    typedef struct _mpd_OutputEntity {
   2502 +	int id;
   2503 +	char *name;
   2504 +	int enabled;
   2505 +    } mpd_OutputEntity;
   2506 +
   2507 +    void mpd_sendOutputsCommand(mpd_Connection * connection);
   2508 +
   2509 +    mpd_OutputEntity *mpd_getNextOutput(mpd_Connection * connection);
   2510 +
   2511 +    void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId);
   2512 +
   2513 +    void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId);
   2514 +
   2515 +    void mpd_freeOutputElement(mpd_OutputEntity * output);
   2516 +
   2517 +/**
   2518 + * @param connection a #mpd_Connection
   2519 + *
   2520 + * Queries mpd for the allowed commands
   2521 + */
   2522 +    void mpd_sendCommandsCommand(mpd_Connection * connection);
   2523 +
   2524 +/**
   2525 + * @param connection a #mpd_Connection
   2526 + *
   2527 + * Queries mpd for the not allowed commands
   2528 + */
   2529 +    void mpd_sendNotCommandsCommand(mpd_Connection * connection);
   2530 +
   2531 +/**
   2532 + * @param connection a #mpd_Connection
   2533 + *
   2534 + * returns the next supported command.
   2535 + *
   2536 + * @returns a string, needs to be free'ed
   2537 + */
   2538 +    char *mpd_getNextCommand(mpd_Connection * connection);
   2539 +
   2540 +    void mpd_sendUrlHandlersCommand(mpd_Connection * connection);
   2541 +
   2542 +    char *mpd_getNextHandler(mpd_Connection * connection);
   2543 +
   2544 +    void mpd_sendTagTypesCommand(mpd_Connection * connection);
   2545 +
   2546 +    char *mpd_getNextTagType(mpd_Connection * connection);
   2547 +
   2548 +/**
   2549 + * @param connection a MpdConnection
   2550 + * @param path	the path to the playlist.
   2551 + *
   2552 + * List the content, with full metadata, of a stored playlist.
   2553 + *
   2554 + */
   2555 +    void mpd_sendListPlaylistInfoCommand(mpd_Connection * connection, char *path);
   2556 +
   2557 +/**
   2558 + * @param connection a MpdConnection
   2559 + * @param path	the path to the playlist.
   2560 + *
   2561 + * List the content of a stored playlist.
   2562 + *
   2563 + */
   2564 +    void mpd_sendListPlaylistCommand(mpd_Connection * connection, char *path);
   2565 +
   2566 +/**
   2567 + * @param connection a #mpd_Connection
   2568 + * @param exact if to match exact
   2569 + *
   2570 + * starts a search, use mpd_addConstraintSearch to add
   2571 + * a constraint to the search, and mpd_commitSearch to do the actual search
   2572 + */
   2573 +    void mpd_startSearch(mpd_Connection * connection, int exact);
   2574 +
   2575 +/**
   2576 + * @param connection a #mpd_Connection
   2577 + * @param type
   2578 + * @param name
   2579 + */
   2580 +    void mpd_addConstraintSearch(mpd_Connection * connection, int type, const char *name);
   2581 +
   2582 +/**
   2583 + * @param connection a #mpd_Connection
   2584 + */
   2585 +    void mpd_commitSearch(mpd_Connection * connection);
   2586 +
   2587 +/**
   2588 + * @param connection a #mpd_Connection
   2589 + * @param type The type to search for
   2590 + *
   2591 + * starts a search for fields... f.e. get a list of artists would be:
   2592 + * @code
   2593 + * mpd_startFieldSearch(connection, MPD_TAG_ITEM_ARTIST);
   2594 + * mpd_commitSearch(connection);
   2595 + * @endcode
   2596 + *
   2597 + * or get a list of artist in genre "jazz" would be:
   2598 + * @code
   2599 + * mpd_startFieldSearch(connection, MPD_TAG_ITEM_ARTIST);
   2600 + * mpd_addConstraintSearch(connection, MPD_TAG_ITEM_GENRE, "jazz")
   2601 + * mpd_commitSearch(connection);
   2602 + * @endcode
   2603 + *
   2604 + * mpd_startSearch will return  a list of songs (and you need mpd_getNextInfoEntity)
   2605 + * this one will return a list of only one field (the one specified with type) and you need
   2606 + * mpd_getNextTag to get the results
   2607 + */
   2608 +    void mpd_startFieldSearch(mpd_Connection * connection, int type);
   2609 +
   2610 +    void mpd_startPlaylistSearch(mpd_Connection * connection, int exact);
   2611 +
   2612 +    void mpd_startStatsSearch(mpd_Connection * connection);
   2613 +
   2614 +    void mpd_sendPlaylistClearCommand(mpd_Connection * connection, char *path);
   2615 +
   2616 +    void mpd_sendPlaylistAddCommand(mpd_Connection * connection, char *playlist, char *path);
   2617 +
   2618 +    void mpd_sendPlaylistMoveCommand(mpd_Connection * connection, char *playlist, int from, int to);
   2619 +
   2620 +    void mpd_sendPlaylistDeleteCommand(mpd_Connection * connection, char *playlist, int pos);
   2621 +#ifdef __cplusplus
   2622 +}
   2623 +#endif
   2624 +#endif