Reformatted all code
[monky] / src / libmpdclient.c
1 /* libmpdclient
2  * (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
3  * This project's homepage is: http://www.musicpd.org
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * - Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * - Neither the name of the Music Player Daemon nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
31
32 #include "libmpdclient.h"
33
34 #include <errno.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #include <stdio.h>
38 #include <sys/param.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <limits.h>
44
45 #ifdef WIN32
46 #  include <ws2tcpip.h>
47 #  include <winsock.h>
48 #else
49 #  include <netinet/in.h>
50 #  include <arpa/inet.h>
51 #  include <sys/socket.h>
52 #  include <netdb.h>
53 #endif
54
55 /* (bits + 1) / 3 (plus the sign character) */
56 #define INTLEN          ((sizeof(int)           * CHAR_BIT + 1) / 3 + 1)
57 #define LONGLONGLEN     ((sizeof(long long)     * CHAR_BIT + 1) / 3 + 1)
58
59 #define COMMAND_LIST    1
60 #define COMMAND_LIST_OK 2
61
62 #ifndef MPD_NO_GAI
63 #  ifdef AI_ADDRCONFIG
64 #    define MPD_HAVE_GAI
65 #  endif
66 #endif
67
68 #ifndef MSG_DONTWAIT
69 #  define MSG_DONTWAIT 0
70 #endif
71
72 #ifdef WIN32
73 #  define SELECT_ERRNO_IGNORE   (errno == WSAEINTR || errno == WSAEINPROGRESS)
74 #  define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
75 #else
76 #  define SELECT_ERRNO_IGNORE   (errno == EINTR)
77 #  define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
78 #  define winsock_dll_error(c)  0
79 #  define closesocket(s)                close(s)
80 #  define WSACleanup()                  do { /* nothing */ } while (0)
81 #endif
82
83 #ifdef WIN32
84 static int winsock_dll_error(mpd_Connection *connection)
85 {
86         WSADATA wsaData;
87
88         if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0
89                         || LOBYTE(wsaData.wVersion) != 2
90                         || HIBYTE(wsaData.wVersion) != 2) {
91                 strcpy(connection->errorStr, "Could not find usable WinSock DLL.");
92                 connection->error = MPD_ERROR_SYSTEM;
93                 return 1;
94         }
95         return 0;
96 }
97
98 static int do_connect_fail(mpd_Connection *connection,
99                 const struct sockaddr *serv_addr, int addrlen)
100 {
101         int iMode = 1;  /* 0 = blocking, else non-blocking */
102
103         ioctlsocket(connection->sock, FIONBIO, (u_long FAR *) &iMode);
104         return (connect(connection->sock, serv_addr, addrlen) == SOCKET_ERROR
105                 && WSAGetLastError() != WSAEWOULDBLOCK);
106 }
107 #else /* !WIN32 (sane operating systems) */
108 static int do_connect_fail(mpd_Connection *connection,
109                 const struct sockaddr *serv_addr, int addrlen)
110 {
111         int flags = fcntl(connection->sock, F_GETFL, 0);
112
113         fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
114         return (connect(connection->sock, serv_addr, addrlen) < 0
115                 && errno != EINPROGRESS);
116 }
117 #endif /* !WIN32 */
118
119 #ifdef MPD_HAVE_GAI
120 static int mpd_connect(mpd_Connection *connection, const char *host, int port,
121                 float timeout)
122 {
123         int error;
124         char service[INTLEN + 1];
125         struct addrinfo hints;
126         struct addrinfo *res = NULL;
127         struct addrinfo *addrinfo = NULL;
128
129         /* Setup hints */
130         hints.ai_flags          = AI_ADDRCONFIG;
131         hints.ai_family         = PF_UNSPEC;
132         hints.ai_socktype       = SOCK_STREAM;
133         hints.ai_protocol       = IPPROTO_TCP;
134         hints.ai_addrlen        = 0;
135         hints.ai_addr           = NULL;
136         hints.ai_canonname      = NULL;
137         hints.ai_next           = NULL;
138
139         snprintf(service, sizeof(service), "%i", port);
140
141         error = getaddrinfo(host, service, &hints, &addrinfo);
142
143         if (error) {
144                 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
145                         "host \"%s\" not found: %s", host, gai_strerror(error));
146                 connection->error = MPD_ERROR_UNKHOST;
147                 return -1;
148         }
149
150         for (res = addrinfo; res; res = res->ai_next) {
151                 /* create socket */
152                 connection->sock = socket(res->ai_family, SOCK_STREAM,
153                         res->ai_protocol);
154                 if (connection->sock < 0) {
155                         snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
156                                 "problems creating socket: %s", strerror(errno));
157                         connection->error = MPD_ERROR_SYSTEM;
158                         freeaddrinfo(addrinfo);
159                         return -1;
160                 }
161
162                 mpd_setConnectionTimeout(connection, timeout);
163
164                 /* connect stuff */
165                 if (do_connect_fail(connection, res->ai_addr, res->ai_addrlen)) {
166                         /* try the next address family */
167                         closesocket(connection->sock);
168                         connection->sock = -1;
169                         continue;
170                 }
171         }
172
173         freeaddrinfo(addrinfo);
174
175         if (connection->sock < 0) {
176                 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
177                         "problems connecting to \"%s\" on port %i: %s", host, port,
178                         strerror(errno));
179                 connection->error = MPD_ERROR_CONNPORT;
180
181                 return -1;
182         }
183
184         return 0;
185 }
186 #else /* !MPD_HAVE_GAI */
187 static int mpd_connect(mpd_Connection *connection, const char *host, int port,
188                 float timeout)
189 {
190         struct hostent *he;
191         struct sockaddr *dest;
192         int destlen;
193         struct sockaddr_in sin;
194
195         if (!(he = gethostbyname(host))) {
196                 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
197                         "host \"%s\" not found", host);
198                 connection->error = MPD_ERROR_UNKHOST;
199                 return -1;
200         }
201
202         memset(&sin, 0, sizeof(struct sockaddr_in));
203         /* dest.sin_family = he->h_addrtype; */
204         sin.sin_family = AF_INET;
205         sin.sin_port = htons(port);
206
207         switch (he->h_addrtype) {
208                 case AF_INET:
209                         memcpy((char *) &sin.sin_addr.s_addr, (char *) he->h_addr,
210                                 he->h_length);
211                         dest = (struct sockaddr *) &sin;
212                         destlen = sizeof(struct sockaddr_in);
213                         break;
214                 default:
215                         strcpy(connection->errorStr, "address type is not IPv4");
216                         connection->error = MPD_ERROR_SYSTEM;
217                         return -1;
218                         break;
219         }
220
221         if ((connection->sock = socket(dest->sa_family, SOCK_STREAM, 0)) < 0) {
222                 strcpy(connection->errorStr, "problems creating socket");
223                 connection->error = MPD_ERROR_SYSTEM;
224                 return -1;
225         }
226
227         mpd_setConnectionTimeout(connection, timeout);
228
229         /* connect stuff */
230         if (do_connect_fail(connection, dest, destlen)) {
231                 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
232                         "problems connecting to \"%s\" on port %i", host, port);
233                 connection->error = MPD_ERROR_CONNPORT;
234                 return -1;
235         }
236
237         return 0;
238 }
239 #endif /* !MPD_HAVE_GAI */
240
241 char *mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] = {
242         "Artist",
243         "Album",
244         "Title",
245         "Track",
246         "Name",
247         "Genre",
248         "Date",
249         "Composer",
250         "Performer",
251         "Comment",
252         "Disc",
253         "Filename",
254         "Any"
255 };
256
257 static char *mpd_sanitizeArg(const char *arg)
258 {
259         size_t i;
260         char *ret;
261         register const char *c;
262         register char *rc;
263
264         /* instead of counting in that loop above,
265          * just use a bit more memory and halve running time */
266         ret = malloc(strlen(arg) * 2 + 1);
267
268         c = arg;
269         rc = ret;
270         for (i = strlen(arg) + 1; i != 0; --i) {
271                 if (*c == '"' || *c == '\\') {
272                         *rc++ = '\\';
273                 }
274                 *(rc++) = *(c++);
275         }
276
277         return ret;
278 }
279
280 static mpd_ReturnElement *mpd_newReturnElement(const char *name,
281                 const char *value)
282 {
283         mpd_ReturnElement *ret = malloc(sizeof(mpd_ReturnElement));
284
285         ret->name = strdup(name);
286         ret->value = strdup(value);
287
288         return ret;
289 }
290
291 static void mpd_freeReturnElement(mpd_ReturnElement *re)
292 {
293         free(re->name);
294         free(re->value);
295         free(re);
296 }
297
298 void mpd_setConnectionTimeout(mpd_Connection *connection, float timeout)
299 {
300         connection->timeout.tv_sec = (int) timeout;
301         connection->timeout.tv_usec =
302                 (int) ((timeout - connection->timeout.tv_sec) * 1e6 + 0.5);
303 }
304
305 static int mpd_parseWelcome(mpd_Connection *connection, const char *host,
306                 int port, /* char *rt, */ char *output)
307 {
308         char *tmp;
309         char *test;
310         int i;
311
312         if (strncmp(output, MPD_WELCOME_MESSAGE, strlen(MPD_WELCOME_MESSAGE))) {
313                 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
314                         "mpd not running on port %i on host \"%s\"", port, host);
315                 connection->error = MPD_ERROR_NOTMPD;
316                 return 1;
317         }
318
319         tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
320
321         for (i = 0; i < 3; i++) {
322                 if (tmp) {
323                         connection->version[i] = strtol(tmp, &test, 10);
324                 }
325
326                 if (!tmp || (test[0] != '.' && test[0] != '\0')) {
327                         snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
328                                 "error parsing version number at \"%s\"",
329                                 &output[strlen(MPD_WELCOME_MESSAGE)]);
330                         connection->error = MPD_ERROR_NOTMPD;
331                         return 1;
332                 }
333                 tmp = ++test;
334         }
335
336         return 0;
337 }
338
339 mpd_Connection *mpd_newConnection(const char *host, int port, float timeout)
340 {
341         int err;
342         char *rt;
343         char *output = NULL;
344         mpd_Connection *connection = malloc(sizeof(mpd_Connection));
345         struct timeval tv;
346         fd_set fds;
347
348         strcpy(connection->buffer, "");
349         connection->buflen = 0;
350         connection->bufstart = 0;
351         strcpy(connection->errorStr, "");
352         connection->error = 0;
353         connection->doneProcessing = 0;
354         connection->commandList = 0;
355         connection->listOks = 0;
356         connection->doneListOk = 0;
357         connection->returnElement = NULL;
358         connection->request = NULL;
359
360         if (winsock_dll_error(connection)) {
361                 return connection;
362         }
363
364         if (mpd_connect(connection, host, port, timeout) < 0) {
365                 return connection;
366         }
367
368         while (!(rt = strstr(connection->buffer, "\n"))) {
369                 tv.tv_sec = connection->timeout.tv_sec;
370                 tv.tv_usec = connection->timeout.tv_usec;
371                 FD_ZERO(&fds);
372                 FD_SET(connection->sock, &fds);
373                 if ((err = select(connection->sock + 1, &fds, NULL, NULL, &tv)) == 1) {
374                         int readed;
375
376                         readed = recv(connection->sock,
377                                 &(connection->buffer[connection->buflen]),
378                                 MPD_BUFFER_MAX_LENGTH - connection->buflen, 0);
379                         if (readed <= 0) {
380                                 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
381                                         "problems getting a response from \"%s\" on port %i : %s",
382                                         host, port, strerror(errno));
383                                 connection->error = MPD_ERROR_NORESPONSE;
384                                 return connection;
385                         }
386                         connection->buflen += readed;
387                         connection->buffer[connection->buflen] = '\0';
388                 } else if (err < 0) {
389                         if (SELECT_ERRNO_IGNORE) {
390                                 continue;
391                         }
392                         snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
393                                 "problems connecting to \"%s\" on port %i", host, port);
394                         connection->error = MPD_ERROR_CONNPORT;
395                         return connection;
396                 } else {
397                         snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
398                                 "timeout in attempting to get a response from \"%s\" on "
399                                 "port %i", host, port);
400                         connection->error = MPD_ERROR_NORESPONSE;
401                         return connection;
402                 }
403         }
404
405         *rt = '\0';
406         output = strdup(connection->buffer);
407         strcpy(connection->buffer, rt + 1);
408         connection->buflen = strlen(connection->buffer);
409
410         if (mpd_parseWelcome(connection, host, port, /* rt, */ output) == 0) {
411                 connection->doneProcessing = 1;
412         }
413
414         free(output);
415
416         return connection;
417 }
418
419 void mpd_clearError(mpd_Connection *connection)
420 {
421         connection->error = 0;
422         connection->errorStr[0] = '\0';
423 }
424
425 void mpd_closeConnection(mpd_Connection *connection)
426 {
427         closesocket(connection->sock);
428         if (connection->returnElement) {
429                 free(connection->returnElement);
430         }
431         if (connection->request) {
432                 free(connection->request);
433         }
434         free(connection);
435         WSACleanup();
436 }
437
438 static void mpd_executeCommand(mpd_Connection *connection, char *command)
439 {
440         int ret;
441         struct timeval tv;
442         fd_set fds;
443         char *commandPtr = command;
444         int commandLen = strlen(command);
445
446         if (!connection->doneProcessing && !connection->commandList) {
447                 strcpy(connection->errorStr, "not done processing current command");
448                 connection->error = 1;
449                 return;
450         }
451
452         mpd_clearError(connection);
453
454         FD_ZERO(&fds);
455         FD_SET(connection->sock, &fds);
456         tv.tv_sec = connection->timeout.tv_sec;
457         tv.tv_usec = connection->timeout.tv_usec;
458
459         while ((ret = select(connection->sock + 1, NULL, &fds, NULL, &tv) == 1)
460                         || (ret == -1 && SELECT_ERRNO_IGNORE)) {
461                 ret = send(connection->sock, commandPtr, commandLen, MSG_DONTWAIT);
462                 if (ret <= 0) {
463                         if (SENDRECV_ERRNO_IGNORE) {
464                                 continue;
465                         }
466                         snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
467                                 "problems giving command \"%s\"", command);
468                         connection->error = MPD_ERROR_SENDING;
469                         return;
470                 } else {
471                         commandPtr += ret;
472                         commandLen -= ret;
473                 }
474
475                 if (commandLen <= 0) {
476                         break;
477                 }
478         }
479
480         if (commandLen > 0) {
481                 perror("");
482                 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
483                         "timeout sending command \"%s\"", command);
484                 connection->error = MPD_ERROR_TIMEOUT;
485                 return;
486         }
487
488         if (!connection->commandList) {
489                 connection->doneProcessing = 0;
490         } else if (connection->commandList == COMMAND_LIST_OK) {
491                 connection->listOks++;
492         }
493 }
494
495 static void mpd_getNextReturnElement(mpd_Connection *connection)
496 {
497         char *output = NULL;
498         char *rt = NULL;
499         char *name = NULL;
500         char *value = NULL;
501         fd_set fds;
502         struct timeval tv;
503         char *tok = NULL;
504         int readed;
505         char *bufferCheck = NULL;
506         int err;
507         int pos;
508
509         if (connection->returnElement) {
510                 mpd_freeReturnElement(connection->returnElement);
511         }
512         connection->returnElement = NULL;
513
514         if (connection->doneProcessing
515                         || (connection->listOks && connection->doneListOk)) {
516                 strcpy(connection->errorStr,
517                         "already done processing current command");
518                 connection->error = 1;
519                 return;
520         }
521
522         bufferCheck = connection->buffer + connection->bufstart;
523         while (connection->bufstart >= connection->buflen
524                         || !(rt = strchr(bufferCheck, '\n'))) {
525                 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
526                         memmove(connection->buffer,
527                                 connection->buffer + connection->bufstart,
528                                 connection->buflen - connection->bufstart + 1);
529                         connection->buflen -= connection->bufstart;
530                         connection->bufstart = 0;
531                 }
532                 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
533                         strcpy(connection->errorStr, "buffer overrun");
534                         connection->error = MPD_ERROR_BUFFEROVERRUN;
535                         connection->doneProcessing = 1;
536                         connection->doneListOk = 0;
537                         return;
538                 }
539                 bufferCheck = connection->buffer + connection->buflen;
540                 tv.tv_sec = connection->timeout.tv_sec;
541                 tv.tv_usec = connection->timeout.tv_usec;
542                 FD_ZERO(&fds);
543                 FD_SET(connection->sock, &fds);
544                 if ((err = select(connection->sock + 1, &fds, NULL, NULL, &tv) == 1)) {
545                         readed = recv(connection->sock,
546                                 connection->buffer + connection->buflen,
547                                 MPD_BUFFER_MAX_LENGTH - connection->buflen, MSG_DONTWAIT);
548                         if (readed < 0 && SENDRECV_ERRNO_IGNORE) {
549                                 continue;
550                         }
551                         if (readed <= 0) {
552                                 strcpy(connection->errorStr, "connection closed");
553                                 connection->error = MPD_ERROR_CONNCLOSED;
554                                 connection->doneProcessing = 1;
555                                 connection->doneListOk = 0;
556                                 return;
557                         }
558                         connection->buflen += readed;
559                         connection->buffer[connection->buflen] = '\0';
560                 } else if (err < 0 && SELECT_ERRNO_IGNORE) {
561                         continue;
562                 } else {
563                         strcpy(connection->errorStr, "connection timeout");
564                         connection->error = MPD_ERROR_TIMEOUT;
565                         connection->doneProcessing = 1;
566                         connection->doneListOk = 0;
567                         return;
568                 }
569         }
570
571         *rt = '\0';
572         output = connection->buffer + connection->bufstart;
573         connection->bufstart = rt - connection->buffer + 1;
574
575         if (strcmp(output, "OK") == 0) {
576                 if (connection->listOks > 0) {
577                         strcpy(connection->errorStr, "expected more list_OK's");
578                         connection->error = 1;
579                 }
580                 connection->listOks = 0;
581                 connection->doneProcessing = 1;
582                 connection->doneListOk = 0;
583                 return;
584         }
585
586         if (strcmp(output, "list_OK") == 0) {
587                 if (!connection->listOks) {
588                         strcpy(connection->errorStr, "got an unexpected list_OK");
589                         connection->error = 1;
590                 } else {
591                         connection->doneListOk = 1;
592                         connection->listOks--;
593                 }
594                 return;
595         }
596
597         if (strncmp(output, "ACK", strlen("ACK")) == 0) {
598                 char *test;
599                 char *needle;
600                 int val;
601
602                 strcpy(connection->errorStr, output);
603                 connection->error = MPD_ERROR_ACK;
604                 connection->errorCode = MPD_ACK_ERROR_UNK;
605                 connection->errorAt = MPD_ERROR_AT_UNK;
606                 connection->doneProcessing = 1;
607                 connection->doneListOk = 0;
608
609                 needle = strchr(output, '[');
610                 if (!needle) {
611                         return;
612                 }
613                 val = strtol(needle + 1, &test, 10);
614                 if (*test != '@') {
615                         return;
616                 }
617                 connection->errorCode = val;
618                 val = strtol(test + 1, &test, 10);
619                 if (*test != ']') {
620                         return;
621                 }
622                 connection->errorAt = val;
623                 return;
624         }
625
626         tok = strchr(output, ':');
627         if (!tok) {
628                 return;
629         }
630         pos = tok - output;
631         value = ++tok;
632         name = output;
633         name[pos] = '\0';
634
635         if (value[0] == ' ') {
636                 connection->returnElement = mpd_newReturnElement(name, &(value[1]));
637         } else {
638                 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
639                         "error parsing: %s:%s", name, value);
640                 connection->error = 1;
641         }
642 }
643
644 void mpd_finishCommand(mpd_Connection *connection)
645 {
646         while (!connection->doneProcessing) {
647                 if (connection->doneListOk) {
648                         connection->doneListOk = 0;
649                 }
650                 mpd_getNextReturnElement(connection);
651         }
652 }
653
654 static void mpd_finishListOkCommand(mpd_Connection *connection)
655 {
656         while (!connection->doneProcessing && connection->listOks
657                         && !connection->doneListOk) {
658                 mpd_getNextReturnElement(connection);
659         }
660 }
661
662 int mpd_nextListOkCommand(mpd_Connection *connection)
663 {
664         mpd_finishListOkCommand(connection);
665         if (!connection->doneProcessing) {
666                 connection->doneListOk = 0;
667         }
668         if (connection->listOks == 0 || connection->doneProcessing) {
669                 return -1;
670         }
671         return 0;
672 }
673
674 void mpd_sendStatusCommand(mpd_Connection *connection)
675 {
676         mpd_executeCommand(connection, "status\n");
677 }
678
679 mpd_Status *mpd_getStatus(mpd_Connection *connection)
680 {
681         mpd_Status *status;
682
683         /* mpd_executeCommand(connection, "status\n");
684         if (connection->error) {
685                 return NULL;
686         } */
687
688         if (connection->doneProcessing
689                         || (connection->listOks && connection->doneListOk)) {
690                 return NULL;
691         }
692
693         if (!connection->returnElement) {
694                 mpd_getNextReturnElement(connection);
695         }
696
697         status = malloc(sizeof(mpd_Status));
698         status->volume = -1;
699         status->repeat = 0;
700         status->random = 0;
701         status->playlist = -1;
702         status->playlistLength = -1;
703         status->state = -1;
704         status->song = 0;
705         status->songid = 0;
706         status->elapsedTime = 0;
707         status->totalTime = 0;
708         status->bitRate = 0;
709         status->sampleRate = 0;
710         status->bits = 0;
711         status->channels = 0;
712         status->crossfade = -1;
713         status->error = NULL;
714         status->updatingDb = 0;
715
716         if (connection->error) {
717                 free(status);
718                 return NULL;
719         }
720         while (connection->returnElement) {
721                 mpd_ReturnElement *re = connection->returnElement;
722
723                 if (strcmp(re->name, "volume") == 0) {
724                         status->volume = atoi(re->value);
725                 } else if (strcmp(re->name, "repeat") == 0) {
726                         status->repeat = atoi(re->value);
727                 } else if (strcmp(re->name, "random") == 0) {
728                         status->random = atoi(re->value);
729                 } else if (strcmp(re->name, "playlist") == 0) {
730                         status->playlist = strtol(re->value, NULL, 10);
731                 } else if (strcmp(re->name, "playlistlength") == 0) {
732                         status->playlistLength = atoi(re->value);
733                 } else if (strcmp(re->name, "bitrate") == 0) {
734                         status->bitRate = atoi(re->value);
735                 } else if (strcmp(re->name, "state") == 0) {
736                         if (strcmp(re->value, "play") == 0) {
737                                 status->state = MPD_STATUS_STATE_PLAY;
738                         } else if (strcmp(re->value, "stop") == 0) {
739                                 status->state = MPD_STATUS_STATE_STOP;
740                         } else if (strcmp(re->value, "pause") == 0) {
741                                 status->state = MPD_STATUS_STATE_PAUSE;
742                         } else {
743                                 status->state = MPD_STATUS_STATE_UNKNOWN;
744                         }
745                 } else if (strcmp(re->name, "song") == 0) {
746                         status->song = atoi(re->value);
747                 } else if (strcmp(re->name, "songid") == 0) {
748                         status->songid = atoi(re->value);
749                 } else if (strcmp(re->name, "time") == 0) {
750                         char *tok = strchr(re->value, ':');
751
752                         /* the second strchr below is a safety check */
753                         if (tok && (strchr(tok, 0) > (tok + 1))) {
754                                 /* atoi stops at the first non-[0-9] char: */
755                                 status->elapsedTime = atoi(re->value);
756                                 status->totalTime = atoi(tok + 1);
757                         }
758                 } else if (strcmp(re->name, "error") == 0) {
759                         status->error = strdup(re->value);
760                 } else if (strcmp(re->name, "xfade") == 0) {
761                         status->crossfade = atoi(re->value);
762                 } else if (strcmp(re->name, "updating_db") == 0) {
763                         status->updatingDb = atoi(re->value);
764                 } else if (strcmp(re->name, "audio") == 0) {
765                         char *tok = strchr(re->value, ':');
766
767                         if (tok && (strchr(tok, 0) > (tok + 1))) {
768                                 status->sampleRate = atoi(re->value);
769                                 status->bits = atoi(++tok);
770                                 tok = strchr(tok, ':');
771                                 if (tok && (strchr(tok, 0) > (tok + 1))) {
772                                         status->channels = atoi(tok + 1);
773                                 }
774                         }
775                 }
776
777                 mpd_getNextReturnElement(connection);
778                 if (connection->error) {
779                         free(status);
780                         return NULL;
781                 }
782         }
783
784         if (connection->error) {
785                 free(status);
786                 return NULL;
787         } else if (status->state < 0) {
788                 strcpy(connection->errorStr, "state not found");
789                 connection->error = 1;
790                 free(status);
791                 return NULL;
792         }
793
794         return status;
795 }
796
797 void mpd_freeStatus(mpd_Status *status)
798 {
799         if (status->error) {
800                 free(status->error);
801         }
802         free(status);
803 }
804
805 void mpd_sendStatsCommand(mpd_Connection *connection)
806 {
807         mpd_executeCommand(connection, "stats\n");
808 }
809
810 mpd_Stats *mpd_getStats(mpd_Connection *connection)
811 {
812         mpd_Stats *stats;
813
814         /* mpd_executeCommand(connection, "stats\n");
815         if (connection->error) {
816                 return NULL;
817         } */
818
819         if (connection->doneProcessing
820                         || (connection->listOks && connection->doneListOk)) {
821                 return NULL;
822         }
823
824         if (!connection->returnElement) {
825                 mpd_getNextReturnElement(connection);
826         }
827
828         stats = malloc(sizeof(mpd_Stats));
829         stats->numberOfArtists = 0;
830         stats->numberOfAlbums = 0;
831         stats->numberOfSongs = 0;
832         stats->uptime = 0;
833         stats->dbUpdateTime = 0;
834         stats->playTime = 0;
835         stats->dbPlayTime = 0;
836
837         if (connection->error) {
838                 free(stats);
839                 return NULL;
840         }
841         while (connection->returnElement) {
842                 mpd_ReturnElement *re = connection->returnElement;
843
844                 if (strcmp(re->name, "artists") == 0) {
845                         stats->numberOfArtists = atoi(re->value);
846                 } else if (strcmp(re->name, "albums") == 0) {
847                         stats->numberOfAlbums = atoi(re->value);
848                 } else if (strcmp(re->name, "songs") == 0) {
849                         stats->numberOfSongs = atoi(re->value);
850                 } else if (strcmp(re->name, "uptime") == 0) {
851                         stats->uptime = strtol(re->value, NULL, 10);
852                 } else if (strcmp(re->name, "db_update") == 0) {
853                         stats->dbUpdateTime = strtol(re->value, NULL, 10);
854                 } else if (strcmp(re->name, "playtime") == 0) {
855                         stats->playTime = strtol(re->value, NULL, 10);
856                 } else if (strcmp(re->name, "db_playtime") == 0) {
857                         stats->dbPlayTime = strtol(re->value, NULL, 10);
858                 }
859
860                 mpd_getNextReturnElement(connection);
861                 if (connection->error) {
862                         free(stats);
863                         return NULL;
864                 }
865         }
866
867         if (connection->error) {
868                 free(stats);
869                 return NULL;
870         }
871
872         return stats;
873 }
874
875 void mpd_freeStats(mpd_Stats *stats)
876 {
877         free(stats);
878 }
879
880 mpd_SearchStats *mpd_getSearchStats(mpd_Connection *connection)
881 {
882         mpd_SearchStats *stats;
883         mpd_ReturnElement *re;
884
885         if (connection->doneProcessing
886                         || (connection->listOks && connection->doneListOk)) {
887                 return NULL;
888         }
889
890         if (!connection->returnElement) {
891                 mpd_getNextReturnElement(connection);
892         }
893
894         if (connection->error) {
895                 return NULL;
896         }
897
898         stats = malloc(sizeof(mpd_SearchStats));
899         stats->numberOfSongs = 0;
900         stats->playTime = 0;
901
902         while (connection->returnElement) {
903                 re = connection->returnElement;
904
905                 if (strcmp(re->name, "songs") == 0) {
906                         stats->numberOfSongs = atoi(re->value);
907                 } else if (strcmp(re->name, "playtime") == 0) {
908                         stats->playTime = strtol(re->value, NULL, 10);
909                 }
910
911                 mpd_getNextReturnElement(connection);
912                 if (connection->error) {
913                         free(stats);
914                         return NULL;
915                 }
916         }
917
918         if (connection->error) {
919                 free(stats);
920                 return NULL;
921         }
922
923         return stats;
924 }
925
926 void mpd_freeSearchStats(mpd_SearchStats *stats)
927 {
928         free(stats);
929 }
930
931 static void mpd_initSong(mpd_Song *song)
932 {
933         song->file = NULL;
934         song->artist = NULL;
935         song->album = NULL;
936         song->track = NULL;
937         song->title = NULL;
938         song->name = NULL;
939         song->date = NULL;
940         /* added by Qball */
941         song->genre = NULL;
942         song->composer = NULL;
943         song->performer = NULL;
944         song->disc = NULL;
945         song->comment = NULL;
946
947         song->time = MPD_SONG_NO_TIME;
948         song->pos = MPD_SONG_NO_NUM;
949         song->id = MPD_SONG_NO_ID;
950 }
951
952 static void mpd_finishSong(mpd_Song *song)
953 {
954         if (song->file) {
955                 free(song->file);
956         }
957         if (song->artist) {
958                 free(song->artist);
959         }
960         if (song->album) {
961                 free(song->album);
962         }
963         if (song->title) {
964                 free(song->title);
965         }
966         if (song->track) {
967                 free(song->track);
968         }
969         if (song->name) {
970                 free(song->name);
971         }
972         if (song->date) {
973                 free(song->date);
974         }
975         if (song->genre) {
976                 free(song->genre);
977         }
978         if (song->composer) {
979                 free(song->composer);
980         }
981         if (song->disc) {
982                 free(song->disc);
983         }
984         if (song->comment) {
985                 free(song->comment);
986         }
987 }
988
989 mpd_Song *mpd_newSong(void)
990 {
991         mpd_Song *ret = malloc(sizeof(mpd_Song));
992
993         mpd_initSong(ret);
994
995         return ret;
996 }
997
998 void mpd_freeSong(mpd_Song *song)
999 {
1000         mpd_finishSong(song);
1001         free(song);
1002 }
1003
1004 mpd_Song *mpd_songDup(mpd_Song *song)
1005 {
1006         mpd_Song *ret = mpd_newSong();
1007
1008         if (song->file) {
1009                 ret->file = strdup(song->file);
1010         }
1011         if (song->artist) {
1012                 ret->artist = strdup(song->artist);
1013         }
1014         if (song->album) {
1015                 ret->album = strdup(song->album);
1016         }
1017         if (song->title) {
1018                 ret->title = strdup(song->title);
1019         }
1020         if (song->track) {
1021                 ret->track = strdup(song->track);
1022         }
1023         if (song->name) {
1024                 ret->name = strdup(song->name);
1025         }
1026         if (song->date) {
1027                 ret->date = strdup(song->date);
1028         }
1029         if (song->genre) {
1030                 ret->genre = strdup(song->genre);
1031         }
1032         if (song->composer) {
1033                 ret->composer = strdup(song->composer);
1034         }
1035         if (song->disc) {
1036                 ret->disc = strdup(song->disc);
1037         }
1038         if (song->comment) {
1039                 ret->comment = strdup(song->comment);
1040         }
1041         ret->time = song->time;
1042         ret->pos = song->pos;
1043         ret->id = song->id;
1044
1045         return ret;
1046 }
1047
1048 static void mpd_initDirectory(mpd_Directory *directory)
1049 {
1050         directory->path = NULL;
1051 }
1052
1053 static void mpd_finishDirectory(mpd_Directory *directory)
1054 {
1055         if (directory->path) {
1056                 free(directory->path);
1057         }
1058 }
1059
1060 mpd_Directory *mpd_newDirectory(void)
1061 {
1062         mpd_Directory *directory = malloc(sizeof(mpd_Directory));
1063
1064         mpd_initDirectory(directory);
1065
1066         return directory;
1067 }
1068
1069 void mpd_freeDirectory(mpd_Directory *directory)
1070 {
1071         mpd_finishDirectory(directory);
1072
1073         free(directory);
1074 }
1075
1076 mpd_Directory *mpd_directoryDup(mpd_Directory *directory)
1077 {
1078         mpd_Directory *ret = mpd_newDirectory();
1079
1080         if (directory->path) {
1081                 ret->path = strdup(directory->path);
1082         }
1083
1084         return ret;
1085 }
1086
1087 static void mpd_initPlaylistFile(mpd_PlaylistFile *playlist)
1088 {
1089         playlist->path = NULL;
1090 }
1091
1092 static void mpd_finishPlaylistFile(mpd_PlaylistFile *playlist)
1093 {
1094         if (playlist->path) {
1095                 free(playlist->path);
1096         }
1097 }
1098
1099 mpd_PlaylistFile *mpd_newPlaylistFile(void)
1100 {
1101         mpd_PlaylistFile *playlist = malloc(sizeof(mpd_PlaylistFile));
1102
1103         mpd_initPlaylistFile(playlist);
1104
1105         return playlist;
1106 }
1107
1108 void mpd_freePlaylistFile(mpd_PlaylistFile *playlist)
1109 {
1110         mpd_finishPlaylistFile(playlist);
1111         free(playlist);
1112 }
1113
1114 mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile *playlist)
1115 {
1116         mpd_PlaylistFile *ret = mpd_newPlaylistFile();
1117
1118         if (playlist->path) {
1119                 ret->path = strdup(playlist->path);
1120         }
1121
1122         return ret;
1123 }
1124
1125 static void mpd_initInfoEntity(mpd_InfoEntity *entity)
1126 {
1127         entity->info.directory = NULL;
1128 }
1129
1130 static void mpd_finishInfoEntity(mpd_InfoEntity *entity)
1131 {
1132         if (entity->info.directory) {
1133                 if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1134                         mpd_freeDirectory(entity->info.directory);
1135                 } else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
1136                         mpd_freeSong(entity->info.song);
1137                 } else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1138                         mpd_freePlaylistFile(entity->info.playlistFile);
1139                 }
1140         }
1141 }
1142
1143 mpd_InfoEntity *mpd_newInfoEntity(void)
1144 {
1145         mpd_InfoEntity *entity = malloc(sizeof(mpd_InfoEntity));
1146
1147         mpd_initInfoEntity(entity);
1148
1149         return entity;
1150 }
1151
1152 void mpd_freeInfoEntity(mpd_InfoEntity *entity)
1153 {
1154         mpd_finishInfoEntity(entity);
1155         free(entity);
1156 }
1157
1158 static void mpd_sendInfoCommand(mpd_Connection *connection, char *command)
1159 {
1160         mpd_executeCommand(connection, command);
1161 }
1162
1163 mpd_InfoEntity *mpd_getNextInfoEntity(mpd_Connection *connection)
1164 {
1165         mpd_InfoEntity *entity = NULL;
1166
1167         if (connection->doneProcessing
1168                         || (connection->listOks && connection->doneListOk)) {
1169                 return NULL;
1170         }
1171
1172         if (!connection->returnElement) {
1173                 mpd_getNextReturnElement(connection);
1174         }
1175
1176         if (connection->returnElement) {
1177                 if (strcmp(connection->returnElement->name, "file") == 0) {
1178                         entity = mpd_newInfoEntity();
1179                         entity->type = MPD_INFO_ENTITY_TYPE_SONG;
1180                         entity->info.song = mpd_newSong();
1181                         entity->info.song->file = strdup(connection->returnElement->value);
1182                 } else if (strcmp(connection->returnElement->name, "directory") == 0) {
1183                         entity = mpd_newInfoEntity();
1184                         entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
1185                         entity->info.directory = mpd_newDirectory();
1186                         entity->info.directory->path =
1187                                 strdup(connection->returnElement->value);
1188                 } else if (strcmp(connection->returnElement->name, "playlist") == 0) {
1189                         entity = mpd_newInfoEntity();
1190                         entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
1191                         entity->info.playlistFile = mpd_newPlaylistFile();
1192                         entity->info.playlistFile->path =
1193                                 strdup(connection->returnElement->value);
1194                 } else if (strcmp(connection->returnElement->name, "cpos") == 0) {
1195                         entity = mpd_newInfoEntity();
1196                         entity->type = MPD_INFO_ENTITY_TYPE_SONG;
1197                         entity->info.song = mpd_newSong();
1198                         entity->info.song->pos = atoi(connection->returnElement->value);
1199                 } else {
1200                         connection->error = 1;
1201                         strcpy(connection->errorStr, "problem parsing song info");
1202                         return NULL;
1203                 }
1204         } else {
1205                 return NULL;
1206         }
1207
1208         mpd_getNextReturnElement(connection);
1209         while (connection->returnElement) {
1210                 mpd_ReturnElement *re = connection->returnElement;
1211
1212                 if (strcmp(re->name, "file") == 0) {
1213                         return entity;
1214                 } else if (strcmp(re->name, "directory") == 0) {
1215                         return entity;
1216                 } else if (strcmp(re->name, "playlist") == 0) {
1217                         return entity;
1218                 } else if (strcmp(re->name, "cpos") == 0) {
1219                         return entity;
1220                 }
1221
1222                 if (entity->type == MPD_INFO_ENTITY_TYPE_SONG && strlen(re->value)) {
1223                         if (!entity->info.song->artist
1224                                         && strcmp(re->name, "Artist") == 0) {
1225                                 entity->info.song->artist = strdup(re->value);
1226                         } else if (!entity->info.song->album
1227                                         && strcmp(re->name, "Album") == 0) {
1228                                 entity->info.song->album = strdup(re->value);
1229                         } else if (!entity->info.song->title
1230                                         && strcmp(re->name, "Title") == 0) {
1231                                 entity->info.song->title = strdup(re->value);
1232                         } else if (!entity->info.song->track
1233                                         && strcmp(re->name, "Track") == 0) {
1234                                 entity->info.song->track = strdup(re->value);
1235                         } else if (!entity->info.song->name
1236                                         && strcmp(re->name, "Name") == 0) {
1237                                 entity->info.song->name = strdup(re->value);
1238                         } else if (entity->info.song->time == MPD_SONG_NO_TIME
1239                                         && strcmp(re->name, "Time") == 0) {
1240                                 entity->info.song->time = atoi(re->value);
1241                         } else if (entity->info.song->pos == MPD_SONG_NO_NUM
1242                                         && strcmp(re->name, "Pos") == 0) {
1243                                 entity->info.song->pos = atoi(re->value);
1244                         } else if (entity->info.song->id == MPD_SONG_NO_ID
1245                                         && strcmp(re->name, "Id") == 0) {
1246                                 entity->info.song->id = atoi(re->value);
1247                         } else if (!entity->info.song->date
1248                                         && strcmp(re->name, "Date") == 0) {
1249                                 entity->info.song->date = strdup(re->value);
1250                         } else if (!entity->info.song->genre
1251                                         && strcmp(re->name, "Genre") == 0) {
1252                                 entity->info.song->genre = strdup(re->value);
1253                         } else if (!entity->info.song->composer
1254                                         && strcmp(re->name, "Composer") == 0) {
1255                                 entity->info.song->composer = strdup(re->value);
1256                         } else if (!entity->info.song->performer
1257                                         && strcmp(re->name, "Performer") == 0) {
1258                                 entity->info.song->performer = strdup(re->value);
1259                         } else if (!entity->info.song->disc
1260                                         && strcmp(re->name, "Disc") == 0) {
1261                                 entity->info.song->disc = strdup(re->value);
1262                         } else if (!entity->info.song->comment
1263                                         && strcmp(re->name, "Comment") == 0) {
1264                                 entity->info.song->comment = strdup(re->value);
1265                         }
1266                 } else if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1267                 } else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1268                 }
1269
1270                 mpd_getNextReturnElement(connection);
1271         }
1272
1273         return entity;
1274 }
1275
1276 static char *mpd_getNextReturnElementNamed(mpd_Connection *connection,
1277                 const char *name)
1278 {
1279         if (connection->doneProcessing
1280                         || (connection->listOks && connection->doneListOk)) {
1281                 return NULL;
1282         }
1283
1284         mpd_getNextReturnElement(connection);
1285         while (connection->returnElement) {
1286                 mpd_ReturnElement *re = connection->returnElement;
1287
1288                 if (strcmp(re->name, name) == 0) {
1289                         return strdup(re->value);
1290                 }
1291                 mpd_getNextReturnElement(connection);
1292         }
1293
1294         return NULL;
1295 }
1296
1297 char *mpd_getNextTag(mpd_Connection *connection, int type)
1298 {
1299         if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES
1300                         || type == MPD_TAG_ITEM_ANY) {
1301                 return NULL;
1302         }
1303         if (type == MPD_TAG_ITEM_FILENAME) {
1304                 return mpd_getNextReturnElementNamed(connection, "file");
1305         }
1306         return mpd_getNextReturnElementNamed(connection, mpdTagItemKeys[type]);
1307 }
1308
1309 char *mpd_getNextArtist(mpd_Connection *connection)
1310 {
1311         return mpd_getNextReturnElementNamed(connection, "Artist");
1312 }
1313
1314 char *mpd_getNextAlbum(mpd_Connection *connection)
1315 {
1316         return mpd_getNextReturnElementNamed(connection, "Album");
1317 }
1318
1319 void mpd_sendPlaylistInfoCommand(mpd_Connection *connection, int songPos)
1320 {
1321         int len = strlen("playlistinfo") + 2 + INTLEN + 3;
1322         char *string = malloc(len);
1323
1324         snprintf(string, len, "playlistinfo \"%i\"\n", songPos);
1325         mpd_sendInfoCommand(connection, string);
1326         free(string);
1327 }
1328
1329 void mpd_sendPlaylistIdCommand(mpd_Connection *connection, int id)
1330 {
1331         int len = strlen("playlistid") + 2 + INTLEN + 3;
1332         char *string = malloc(len);
1333
1334         snprintf(string, len, "playlistid \"%i\"\n", id);
1335         mpd_sendInfoCommand(connection, string);
1336         free(string);
1337 }
1338
1339 void mpd_sendPlChangesCommand(mpd_Connection *connection, long long playlist)
1340 {
1341         int len = strlen("plchanges") + 2 + LONGLONGLEN + 3;
1342         char *string = malloc(len);
1343
1344         snprintf(string, len, "plchanges \"%lld\"\n", playlist);
1345         mpd_sendInfoCommand(connection, string);
1346         free(string);
1347 }
1348
1349 void mpd_sendPlChangesPosIdCommand(mpd_Connection *connection,
1350                 long long playlist)
1351 {
1352         int len = strlen("plchangesposid") + 2 + LONGLONGLEN + 3;
1353         char *string = malloc(len);
1354
1355         snprintf(string, len, "plchangesposid \"%lld\"\n", playlist);
1356         mpd_sendInfoCommand(connection, string);
1357         free(string);
1358 }
1359
1360 void mpd_sendListallCommand(mpd_Connection *connection, const char *dir)
1361 {
1362         char *sDir = mpd_sanitizeArg(dir);
1363         int len = strlen("listall") + 2 + strlen(sDir) + 3;
1364         char *string = malloc(len);
1365
1366         snprintf(string, len, "listall \"%s\"\n", sDir);
1367         mpd_sendInfoCommand(connection, string);
1368         free(string);
1369         free(sDir);
1370 }
1371
1372 void mpd_sendListallInfoCommand(mpd_Connection *connection, const char *dir)
1373 {
1374         char *sDir = mpd_sanitizeArg(dir);
1375         int len = strlen("listallinfo") + 2 + strlen(sDir) + 3;
1376         char *string = malloc(len);
1377
1378         snprintf(string, len, "listallinfo \"%s\"\n", sDir);
1379         mpd_sendInfoCommand(connection, string);
1380         free(string);
1381         free(sDir);
1382 }
1383
1384 void mpd_sendLsInfoCommand(mpd_Connection *connection, const char *dir)
1385 {
1386         char *sDir = mpd_sanitizeArg(dir);
1387         int len = strlen("lsinfo") + 2 + strlen(sDir) + 3;
1388         char *string = malloc(len);
1389
1390         snprintf(string, len, "lsinfo \"%s\"\n", sDir);
1391         mpd_sendInfoCommand(connection, string);
1392         free(string);
1393         free(sDir);
1394 }
1395
1396 void mpd_sendCurrentSongCommand(mpd_Connection *connection)
1397 {
1398         mpd_executeCommand(connection, "currentsong\n");
1399 }
1400
1401 void mpd_sendSearchCommand(mpd_Connection *connection, int table,
1402                 const char *str)
1403 {
1404         mpd_startSearch(connection, 0);
1405         mpd_addConstraintSearch(connection, table, str);
1406         mpd_commitSearch(connection);
1407 }
1408
1409 void mpd_sendFindCommand(mpd_Connection *connection, int table,
1410                 const char *str)
1411 {
1412         mpd_startSearch(connection, 1);
1413         mpd_addConstraintSearch(connection, table, str);
1414         mpd_commitSearch(connection);
1415 }
1416
1417 void mpd_sendListCommand(mpd_Connection *connection, int table,
1418                 const char *arg1)
1419 {
1420         char st[10];
1421         int len;
1422         char *string;
1423
1424         if (table == MPD_TABLE_ARTIST) {
1425                 strcpy(st, "artist");
1426         } else if (table == MPD_TABLE_ALBUM) {
1427                 strcpy(st, "album");
1428         } else {
1429                 connection->error = 1;
1430                 strcpy(connection->errorStr, "unknown table for list");
1431                 return;
1432         }
1433         if (arg1) {
1434                 char *sanitArg1 = mpd_sanitizeArg(arg1);
1435
1436                 len = strlen("list") + 1 + strlen(sanitArg1) + 2 + strlen(st) + 3;
1437                 string = malloc(len);
1438                 snprintf(string, len, "list %s \"%s\"\n", st, sanitArg1);
1439                 free(sanitArg1);
1440         } else {
1441                 len = strlen("list") + 1 + strlen(st) + 2;
1442                 string = malloc(len);
1443                 snprintf(string, len, "list %s\n", st);
1444         }
1445         mpd_sendInfoCommand(connection, string);
1446         free(string);
1447 }
1448
1449 void mpd_sendAddCommand(mpd_Connection *connection, const char *file)
1450 {
1451         char *sFile = mpd_sanitizeArg(file);
1452         int len = strlen("add") + 2 + strlen(sFile) + 3;
1453         char *string = malloc(len);
1454
1455         snprintf(string, len, "add \"%s\"\n", sFile);
1456         mpd_executeCommand(connection, string);
1457         free(string);
1458         free(sFile);
1459 }
1460
1461 int mpd_sendAddIdCommand(mpd_Connection *connection, const char *file)
1462 {
1463         int retval = -1;
1464         char *sFile = mpd_sanitizeArg(file);
1465         int len = strlen("addid") + 2 + strlen(sFile) + 3;
1466         char *string = malloc(len);
1467
1468         snprintf(string, len, "addid \"%s\"\n", sFile);
1469         mpd_sendInfoCommand(connection, string);
1470         free(string);
1471         free(sFile);
1472
1473         string = mpd_getNextReturnElementNamed(connection, "Id");
1474         if (string) {
1475                 retval = atoi(string);
1476                 free(string);
1477         }
1478
1479         return retval;
1480 }
1481
1482 void mpd_sendDeleteCommand(mpd_Connection *connection, int songPos)
1483 {
1484         int len = strlen("delete") + 2 + INTLEN + 3;
1485         char *string = malloc(len);
1486
1487         snprintf(string, len, "delete \"%i\"\n", songPos);
1488         mpd_sendInfoCommand(connection, string);
1489         free(string);
1490 }
1491
1492 void mpd_sendDeleteIdCommand(mpd_Connection *connection, int id)
1493 {
1494         int len = strlen("deleteid") + 2 + INTLEN + 3;
1495         char *string = malloc(len);
1496
1497         snprintf(string, len, "deleteid \"%i\"\n", id);
1498         mpd_sendInfoCommand(connection, string);
1499         free(string);
1500 }
1501
1502 void mpd_sendSaveCommand(mpd_Connection *connection, const char *name)
1503 {
1504         char *sName = mpd_sanitizeArg(name);
1505         int len = strlen("save") + 2 + strlen(sName) + 3;
1506         char *string = malloc(len);
1507
1508         snprintf(string, len, "save \"%s\"\n", sName);
1509         mpd_executeCommand(connection, string);
1510         free(string);
1511         free(sName);
1512 }
1513
1514 void mpd_sendLoadCommand(mpd_Connection *connection, const char *name)
1515 {
1516         char *sName = mpd_sanitizeArg(name);
1517         int len = strlen("load") + 2 + strlen(sName) + 3;
1518         char *string = malloc(len);
1519
1520         snprintf(string, len, "load \"%s\"\n", sName);
1521         mpd_executeCommand(connection, string);
1522         free(string);
1523         free(sName);
1524 }
1525
1526 void mpd_sendRmCommand(mpd_Connection *connection, const char *name)
1527 {
1528         char *sName = mpd_sanitizeArg(name);
1529         int len = strlen("rm") + 2 + strlen(sName) + 3;
1530         char *string = malloc(len);
1531
1532         snprintf(string, len, "rm \"%s\"\n", sName);
1533         mpd_executeCommand(connection, string);
1534         free(string);
1535         free(sName);
1536 }
1537
1538 void mpd_sendRenameCommand(mpd_Connection *connection, const char *from,
1539                 const char *to)
1540 {
1541         char *sFrom = mpd_sanitizeArg(from);
1542         char *sTo = mpd_sanitizeArg(to);
1543         int len = strlen("rename") + 2 + strlen(sFrom) + 3 + strlen(sTo) + 3;
1544         char *string = malloc(len);
1545
1546         snprintf(string, len, "rename \"%s\" \"%s\"\n", sFrom, sTo);
1547         mpd_executeCommand(connection, string);
1548         free(string);
1549         free(sFrom);
1550         free(sTo);
1551 }
1552
1553 void mpd_sendShuffleCommand(mpd_Connection *connection)
1554 {
1555         mpd_executeCommand(connection, "shuffle\n");
1556 }
1557
1558 void mpd_sendClearCommand(mpd_Connection *connection)
1559 {
1560         mpd_executeCommand(connection, "clear\n");
1561 }
1562
1563 void mpd_sendPlayCommand(mpd_Connection *connection, int songPos)
1564 {
1565         int len = strlen("play") + 2 + INTLEN + 3;
1566         char *string = malloc(len);
1567
1568         snprintf(string, len, "play \"%i\"\n", songPos);
1569         mpd_sendInfoCommand(connection, string);
1570         free(string);
1571 }
1572
1573 void mpd_sendPlayIdCommand(mpd_Connection *connection, int id)
1574 {
1575         int len = strlen("playid") + 2 + INTLEN + 3;
1576         char *string = malloc(len);
1577
1578         snprintf(string, len, "playid \"%i\"\n", id);
1579         mpd_sendInfoCommand(connection, string);
1580         free(string);
1581 }
1582
1583 void mpd_sendStopCommand(mpd_Connection *connection)
1584 {
1585         mpd_executeCommand(connection, "stop\n");
1586 }
1587
1588 void mpd_sendPauseCommand(mpd_Connection *connection, int pauseMode)
1589 {
1590         int len = strlen("pause") + 2 + INTLEN + 3;
1591         char *string = malloc(len);
1592
1593         snprintf(string, len, "pause \"%i\"\n", pauseMode);
1594         mpd_executeCommand(connection, string);
1595         free(string);
1596 }
1597
1598 void mpd_sendNextCommand(mpd_Connection *connection)
1599 {
1600         mpd_executeCommand(connection, "next\n");
1601 }
1602
1603 void mpd_sendMoveCommand(mpd_Connection *connection, int from, int to)
1604 {
1605         int len = strlen("move") + 2 + INTLEN + 3 + INTLEN + 3;
1606         char *string = malloc(len);
1607
1608         snprintf(string, len, "move \"%i\" \"%i\"\n", from, to);
1609         mpd_sendInfoCommand(connection, string);
1610         free(string);
1611 }
1612
1613 void mpd_sendMoveIdCommand(mpd_Connection *connection, int id, int to)
1614 {
1615         int len = strlen("moveid") + 2 + INTLEN + 3 + INTLEN + 3;
1616         char *string = malloc(len);
1617
1618         snprintf(string, len, "moveid \"%i\" \"%i\"\n", id, to);
1619         mpd_sendInfoCommand(connection, string);
1620         free(string);
1621 }
1622
1623 void mpd_sendSwapCommand(mpd_Connection *connection, int song1, int song2)
1624 {
1625         int len = strlen("swap") + 2 + INTLEN + 3 + INTLEN + 3;
1626         char *string = malloc(len);
1627
1628         snprintf(string, len, "swap \"%i\" \"%i\"\n", song1, song2);
1629         mpd_sendInfoCommand(connection, string);
1630         free(string);
1631 }
1632
1633 void mpd_sendSwapIdCommand(mpd_Connection *connection, int id1, int id2)
1634 {
1635         int len = strlen("swapid") + 2 + INTLEN + 3 + INTLEN + 3;
1636         char *string = malloc(len);
1637
1638         snprintf(string, len, "swapid \"%i\" \"%i\"\n", id1, id2);
1639         mpd_sendInfoCommand(connection, string);
1640         free(string);
1641 }
1642
1643 void mpd_sendSeekCommand(mpd_Connection *connection, int song, int time)
1644 {
1645         int len = strlen("seek") + 2 + INTLEN + 3 + INTLEN + 3;
1646         char *string = malloc(len);
1647
1648         snprintf(string, len, "seek \"%i\" \"%i\"\n", song, time);
1649         mpd_sendInfoCommand(connection, string);
1650         free(string);
1651 }
1652
1653 void mpd_sendSeekIdCommand(mpd_Connection *connection, int id, int time)
1654 {
1655         int len = strlen("seekid") + 2 + INTLEN + 3 + INTLEN + 3;
1656         char *string = malloc(len);
1657
1658         snprintf(string, len, "seekid \"%i\" \"%i\"\n", id, time);
1659         mpd_sendInfoCommand(connection, string);
1660         free(string);
1661 }
1662
1663 void mpd_sendUpdateCommand(mpd_Connection *connection, char *path)
1664 {
1665         char *sPath = mpd_sanitizeArg(path);
1666         int len = strlen("update") + 2 + strlen(sPath) + 3;
1667         char *string = malloc(len);
1668
1669         snprintf(string, len, "update \"%s\"\n", sPath);
1670         mpd_sendInfoCommand(connection, string);
1671         free(string);
1672         free(sPath);
1673 }
1674
1675 int mpd_getUpdateId(mpd_Connection *connection)
1676 {
1677         char *jobid;
1678         int ret = 0;
1679
1680         jobid = mpd_getNextReturnElementNamed(connection, "updating_db");
1681         if (jobid) {
1682                 ret = atoi(jobid);
1683                 free(jobid);
1684         }
1685
1686         return ret;
1687 }
1688
1689 void mpd_sendPrevCommand(mpd_Connection *connection)
1690 {
1691         mpd_executeCommand(connection, "previous\n");
1692 }
1693
1694 void mpd_sendRepeatCommand(mpd_Connection *connection, int repeatMode)
1695 {
1696         int len = strlen("repeat") + 2 + INTLEN + 3;
1697         char *string = malloc(len);
1698
1699         snprintf(string, len, "repeat \"%i\"\n", repeatMode);
1700         mpd_executeCommand(connection, string);
1701         free(string);
1702 }
1703
1704 void mpd_sendRandomCommand(mpd_Connection *connection, int randomMode)
1705 {
1706         int len = strlen("random") + 2 + INTLEN + 3;
1707         char *string = malloc(len);
1708
1709         snprintf(string, len, "random \"%i\"\n", randomMode);
1710         mpd_executeCommand(connection, string);
1711         free(string);
1712 }
1713
1714 void mpd_sendSetvolCommand(mpd_Connection *connection, int volumeChange)
1715 {
1716         int len = strlen("setvol") + 2 + INTLEN + 3;
1717         char *string = malloc(len);
1718
1719         snprintf(string, len, "setvol \"%i\"\n", volumeChange);
1720         mpd_executeCommand(connection, string);
1721         free(string);
1722 }
1723
1724 void mpd_sendVolumeCommand(mpd_Connection *connection, int volumeChange)
1725 {
1726         int len = strlen("volume") + 2 + INTLEN + 3;
1727         char *string = malloc(len);
1728
1729         snprintf(string, len, "volume \"%i\"\n", volumeChange);
1730         mpd_executeCommand(connection, string);
1731         free(string);
1732 }
1733
1734 void mpd_sendCrossfadeCommand(mpd_Connection *connection, int seconds)
1735 {
1736         int len = strlen("crossfade") + 2 + INTLEN + 3;
1737         char *string = malloc(len);
1738
1739         snprintf(string, len, "crossfade \"%i\"\n", seconds);
1740         mpd_executeCommand(connection, string);
1741         free(string);
1742 }
1743
1744 void mpd_sendPasswordCommand(mpd_Connection *connection, const char *pass)
1745 {
1746         char *sPass = mpd_sanitizeArg(pass);
1747         int len = strlen("password") + 2 + strlen(sPass) + 3;
1748         char *string = malloc(len);
1749
1750         snprintf(string, len, "password \"%s\"\n", sPass);
1751         mpd_executeCommand(connection, string);
1752         free(string);
1753         free(sPass);
1754 }
1755
1756 void mpd_sendCommandListBegin(mpd_Connection *connection)
1757 {
1758         if (connection->commandList) {
1759                 strcpy(connection->errorStr, "already in command list mode");
1760                 connection->error = 1;
1761                 return;
1762         }
1763         connection->commandList = COMMAND_LIST;
1764         mpd_executeCommand(connection, "command_list_begin\n");
1765 }
1766
1767 void mpd_sendCommandListOkBegin(mpd_Connection *connection)
1768 {
1769         if (connection->commandList) {
1770                 strcpy(connection->errorStr, "already in command list mode");
1771                 connection->error = 1;
1772                 return;
1773         }
1774         connection->commandList = COMMAND_LIST_OK;
1775         mpd_executeCommand(connection, "command_list_ok_begin\n");
1776         connection->listOks = 0;
1777 }
1778
1779 void mpd_sendCommandListEnd(mpd_Connection *connection)
1780 {
1781         if (!connection->commandList) {
1782                 strcpy(connection->errorStr, "not in command list mode");
1783                 connection->error = 1;
1784                 return;
1785         }
1786         connection->commandList = 0;
1787         mpd_executeCommand(connection, "command_list_end\n");
1788 }
1789
1790 void mpd_sendOutputsCommand(mpd_Connection *connection)
1791 {
1792         mpd_executeCommand(connection, "outputs\n");
1793 }
1794
1795 mpd_OutputEntity *mpd_getNextOutput(mpd_Connection *connection)
1796 {
1797         mpd_OutputEntity *output = NULL;
1798
1799         if (connection->doneProcessing
1800                         || (connection->listOks && connection->doneListOk)) {
1801                 return NULL;
1802         }
1803
1804         if (connection->error) {
1805                 return NULL;
1806         }
1807
1808         output = malloc(sizeof(mpd_OutputEntity));
1809         output->id = -10;
1810         output->name = NULL;
1811         output->enabled = 0;
1812
1813         if (!connection->returnElement) {
1814                 mpd_getNextReturnElement(connection);
1815         }
1816
1817         while (connection->returnElement) {
1818                 mpd_ReturnElement *re = connection->returnElement;
1819
1820                 if (strcmp(re->name, "outputid") == 0) {
1821                         if (output != NULL && output->id >= 0) {
1822                                 return output;
1823                         }
1824                         output->id = atoi(re->value);
1825                 } else if (strcmp(re->name, "outputname") == 0) {
1826                         output->name = strdup(re->value);
1827                 } else if (strcmp(re->name, "outputenabled") == 0) {
1828                         output->enabled = atoi(re->value);
1829                 }
1830
1831                 mpd_getNextReturnElement(connection);
1832                 if (connection->error) {
1833                         free(output);
1834                         return NULL;
1835                 }
1836         }
1837
1838         return output;
1839 }
1840
1841 void mpd_sendEnableOutputCommand(mpd_Connection *connection, int outputId)
1842 {
1843         int len = strlen("enableoutput") + 2 + INTLEN + 3;
1844         char *string = malloc(len);
1845
1846         snprintf(string, len, "enableoutput \"%i\"\n", outputId);
1847         mpd_executeCommand(connection, string);
1848         free(string);
1849 }
1850
1851 void mpd_sendDisableOutputCommand(mpd_Connection *connection, int outputId)
1852 {
1853         int len = strlen("disableoutput") + 2 + INTLEN + 3;
1854         char *string = malloc(len);
1855
1856         snprintf(string, len, "disableoutput \"%i\"\n", outputId);
1857         mpd_executeCommand(connection, string);
1858         free(string);
1859 }
1860
1861 void mpd_freeOutputElement(mpd_OutputEntity *output)
1862 {
1863         free(output->name);
1864         free(output);
1865 }
1866
1867 /** odd naming, but it gets the not allowed commands */
1868 void mpd_sendNotCommandsCommand(mpd_Connection *connection)
1869 {
1870         mpd_executeCommand(connection, "notcommands\n");
1871 }
1872
1873 /** odd naming, but it gets the allowed commands */
1874 void mpd_sendCommandsCommand(mpd_Connection *connection)
1875 {
1876         mpd_executeCommand(connection, "commands\n");
1877 }
1878
1879 /** Get the next returned command */
1880 char *mpd_getNextCommand(mpd_Connection *connection)
1881 {
1882         return mpd_getNextReturnElementNamed(connection, "command");
1883 }
1884
1885 void mpd_sendUrlHandlersCommand(mpd_Connection *connection)
1886 {
1887         mpd_executeCommand(connection, "urlhandlers\n");
1888 }
1889
1890 char *mpd_getNextHandler(mpd_Connection *connection)
1891 {
1892         return mpd_getNextReturnElementNamed(connection, "handler");
1893 }
1894
1895 void mpd_sendTagTypesCommand(mpd_Connection *connection)
1896 {
1897         mpd_executeCommand(connection, "tagtypes\n");
1898 }
1899
1900 char *mpd_getNextTagType(mpd_Connection *connection)
1901 {
1902         return mpd_getNextReturnElementNamed(connection, "tagtype");
1903 }
1904
1905 void mpd_startSearch(mpd_Connection *connection, int exact)
1906 {
1907         if (connection->request) {
1908                 strcpy(connection->errorStr, "search already in progress");
1909                 connection->error = 1;
1910                 return;
1911         }
1912
1913         if (exact) {
1914                 connection->request = strdup("find");
1915         } else {
1916                 connection->request = strdup("search");
1917         }
1918 }
1919
1920 void mpd_startStatsSearch(mpd_Connection *connection)
1921 {
1922         if (connection->request) {
1923                 strcpy(connection->errorStr, "search already in progress");
1924                 connection->error = 1;
1925                 return;
1926         }
1927
1928         connection->request = strdup("count");
1929 }
1930
1931 void mpd_startPlaylistSearch(mpd_Connection *connection, int exact)
1932 {
1933         if (connection->request) {
1934                 strcpy(connection->errorStr, "search already in progress");
1935                 connection->error = 1;
1936                 return;
1937         }
1938
1939         if (exact) {
1940                 connection->request = strdup("playlistfind");
1941         } else {
1942                 connection->request = strdup("playlistsearch");
1943         }
1944 }
1945
1946 void mpd_startFieldSearch(mpd_Connection *connection, int type)
1947 {
1948         char *strtype;
1949         int len;
1950
1951         if (connection->request) {
1952                 strcpy(connection->errorStr, "search already in progress");
1953                 connection->error = 1;
1954                 return;
1955         }
1956
1957         if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES) {
1958                 strcpy(connection->errorStr, "invalid type specified");
1959                 connection->error = 1;
1960                 return;
1961         }
1962
1963         strtype = mpdTagItemKeys[type];
1964
1965         len = 5 + strlen(strtype) + 1;
1966         connection->request = malloc(len);
1967
1968         snprintf(connection->request, len, "list %c%s", tolower(strtype[0]),
1969                 strtype + 1);
1970 }
1971
1972 void mpd_addConstraintSearch(mpd_Connection *connection, int type,
1973                 const char *name)
1974 {
1975         char *strtype;
1976         char *arg;
1977         int len;
1978         char *string;
1979
1980         if (!connection->request) {
1981                 strcpy(connection->errorStr, "no search in progress");
1982                 connection->error = 1;
1983                 return;
1984         }
1985
1986         if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES) {
1987                 strcpy(connection->errorStr, "invalid type specified");
1988                 connection->error = 1;
1989                 return;
1990         }
1991
1992         if (name == NULL) {
1993                 strcpy(connection->errorStr, "no name specified");
1994                 connection->error = 1;
1995                 return;
1996         }
1997
1998         string = strdup(connection->request);
1999         strtype = mpdTagItemKeys[type];
2000         arg = mpd_sanitizeArg(name);
2001
2002         len = strlen(string) + 1 + strlen(strtype) + 2 + strlen(arg) + 2;
2003         connection->request = realloc(connection->request, len);
2004         snprintf(connection->request, len, "%s %c%s \"%s\"", string,
2005                 tolower(strtype[0]), strtype + 1, arg);
2006
2007         free(string);
2008         free(arg);
2009 }
2010
2011 void mpd_commitSearch(mpd_Connection *connection)
2012 {
2013         int len;
2014
2015         if (!connection->request) {
2016                 strcpy(connection->errorStr, "no search in progress");
2017                 connection->error = 1;
2018                 return;
2019         }
2020
2021         len = strlen(connection->request) + 2;
2022         connection->request = realloc(connection->request, len);
2023         connection->request[len - 2] = '\n';
2024         connection->request[len - 1] = '\0';
2025         mpd_sendInfoCommand(connection, connection->request);
2026
2027         free(connection->request);
2028         connection->request = NULL;
2029 }
2030
2031 /**
2032  * @param connection    a MpdConnection
2033  * @param path                  the path to the playlist.
2034  *
2035  * List the content, with full metadata, of a stored playlist. */
2036 void mpd_sendListPlaylistInfoCommand(mpd_Connection *connection, char *path)
2037 {
2038         char *arg = mpd_sanitizeArg(path);
2039         int len = strlen("listplaylistinfo") + 2 + strlen(arg) + 3;
2040         char *query = malloc(len);
2041
2042         snprintf(query, len, "listplaylistinfo \"%s\"\n", arg);
2043         mpd_sendInfoCommand(connection, query);
2044         free(arg);
2045         free(query);
2046 }
2047
2048 /**
2049  * @param connection    a MpdConnection
2050  * @param path                  the path to the playlist.
2051  *
2052  * List the content of a stored playlist. */
2053 void mpd_sendListPlaylistCommand(mpd_Connection *connection, char *path)
2054 {
2055         char *arg = mpd_sanitizeArg(path);
2056         int len = strlen("listplaylist") + 2 + strlen(arg) + 3;
2057         char *query = malloc(len);
2058
2059         snprintf(query, len, "listplaylist \"%s\"\n", arg);
2060         mpd_sendInfoCommand(connection, query);
2061         free(arg);
2062         free(query);
2063 }
2064
2065 void mpd_sendPlaylistClearCommand(mpd_Connection *connection, char *path)
2066 {
2067         char *sPath = mpd_sanitizeArg(path);
2068         int len = strlen("playlistclear") + 2 + strlen(sPath) + 3;
2069         char *string = malloc(len);
2070
2071         snprintf(string, len, "playlistclear \"%s\"\n", sPath);
2072         mpd_executeCommand(connection, string);
2073         free(sPath);
2074         free(string);
2075 }
2076
2077 void mpd_sendPlaylistAddCommand(mpd_Connection *connection, char *playlist,
2078                 char *path)
2079 {
2080         char *sPlaylist = mpd_sanitizeArg(playlist);
2081         char *sPath = mpd_sanitizeArg(path);
2082         int len = strlen("playlistadd") + 2 + strlen(sPlaylist) + 3 +
2083                 strlen(sPath) + 3;
2084         char *string = malloc(len);
2085
2086         snprintf(string, len, "playlistadd \"%s\" \"%s\"\n", sPlaylist, sPath);
2087         mpd_executeCommand(connection, string);
2088         free(sPlaylist);
2089         free(sPath);
2090         free(string);
2091 }
2092
2093 void mpd_sendPlaylistMoveCommand(mpd_Connection *connection, char *playlist,
2094                 int from, int to)
2095 {
2096         char *sPlaylist = mpd_sanitizeArg(playlist);
2097         int len = strlen("playlistmove") + 2 + strlen(sPlaylist) + 3 + INTLEN +
2098                 3 + INTLEN + 3;
2099         char *string = malloc(len);
2100
2101         snprintf(string, len, "playlistmove \"%s\" \"%i\" \"%i\"\n", sPlaylist,
2102                 from, to);
2103         mpd_executeCommand(connection, string);
2104         free(sPlaylist);
2105         free(string);
2106 }
2107
2108 void mpd_sendPlaylistDeleteCommand(mpd_Connection *connection, char *playlist,
2109                 int pos)
2110 {
2111         char *sPlaylist = mpd_sanitizeArg(playlist);
2112         int len = strlen("playlistdelete") + 2 + strlen(sPlaylist) + 3 +
2113                 INTLEN + 3;
2114         char *string = malloc(len);
2115
2116         snprintf(string, len, "playlistdelete \"%s\" \"%i\"\n", sPlaylist, pos);
2117         mpd_executeCommand(connection, string);
2118         free(sPlaylist);
2119         free(string);
2120 }