moved stuff
[monky] / src / libmpdclient.c
1 /* libmpdclient
2    (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
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 */
33
34 #include "libmpdclient.h"
35
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netdb.h>
40 #include <stdio.h>
41 #include <sys/param.h>
42 #include <string.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <fcntl.h>
48
49 #ifndef MPD_NO_IPV6
50 #ifdef AF_INET6
51 #define MPD_HAVE_IPV6
52 #endif
53 #endif
54
55 #define COMMAND_LIST    1
56 #define COMMAND_LIST_OK 2
57
58 #ifdef MPD_HAVE_IPV6
59 int mpd_ipv6Supported()
60 {
61         int s;
62         s = socket(AF_INET6, SOCK_STREAM, 0);
63         if (s == -1)
64                 return 0;
65         close(s);
66         return 1;
67 }
68 #endif
69
70
71 char *mpd_sanitizeArg(const char *arg)
72 {
73         size_t i;
74         int count = 0;
75         char *ret;
76
77         for (i = 0; i < strlen(arg); i++) {
78                 if (arg[i] == '"' || arg[i] == '\\')
79                         count++;
80         }
81
82         ret = malloc(strlen(arg) + count + 1);
83
84         count = 0;
85         for (i = 0; i < strlen(arg) + 1; i++) {
86                 if (arg[i] == '"' || arg[i] == '\\') {
87                         ret[i + count] = '\\';
88                         count++;
89                 }
90                 ret[i + count] = arg[i];
91         }
92
93         return ret;
94 }
95
96 mpd_ReturnElement *mpd_newReturnElement(const char *name,
97                                         const char *value)
98 {
99         mpd_ReturnElement *ret = malloc(sizeof(mpd_ReturnElement));
100
101         ret->name = strdup(name);
102         ret->value = strdup(value);
103
104         return ret;
105 }
106
107 void mpd_freeReturnElement(mpd_ReturnElement * re)
108 {
109         free(re->name);
110         free(re->value);
111         free(re);
112 }
113
114 void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout)
115 {
116         connection->timeout.tv_sec = (int) timeout;
117         connection->timeout.tv_usec = (int) (timeout * 1e6 -
118                                              connection->timeout.tv_sec *
119                                              1000000 + 0.5);
120 }
121
122 mpd_Connection *mpd_newConnection(const char *host, int port,
123                                   float timeout)
124 {
125         int err;
126         struct hostent *he;
127         struct sockaddr *dest;
128 #ifdef HAVE_SOCKLEN_T
129         socklen_t destlen;
130 #else
131         int destlen;
132 #endif
133         struct sockaddr_in sin;
134         char *rt;
135         char *output;
136         mpd_Connection *connection = malloc(sizeof(mpd_Connection));
137         struct timeval tv;
138         fd_set fds;
139 #ifdef MPD_HAVE_IPV6
140         struct sockaddr_in6 sin6;
141 #endif
142         strcpy(connection->buffer, "");
143         connection->buflen = 0;
144         connection->bufstart = 0;
145         strcpy(connection->errorStr, "");
146         connection->error = 0;
147         connection->doneProcessing = 0;
148         connection->commandList = 0;
149         connection->listOks = 0;
150         connection->doneListOk = 0;
151         connection->returnElement = NULL;
152
153         if (!(he = gethostbyname(host))) {
154                 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
155                          "host \"%s\" not found", host);
156                 connection->error = MPD_ERROR_UNKHOST;
157                 return connection;
158         }
159
160         memset(&sin, 0, sizeof(struct sockaddr_in));
161         /*dest.sin_family = he->h_addrtype; */
162         sin.sin_family = AF_INET;
163         sin.sin_port = htons(port);
164 #ifdef MPD_HAVE_IPV6
165         memset(&sin6, 0, sizeof(struct sockaddr_in6));
166         sin6.sin6_family = AF_INET6;
167         sin6.sin6_port = htons(port);
168 #endif
169         switch (he->h_addrtype) {
170         case AF_INET:
171                 memcpy((char *) &sin.sin_addr.s_addr, (char *) he->h_addr,
172                        he->h_length);
173                 dest = (struct sockaddr *) &sin;
174                 destlen = sizeof(struct sockaddr_in);
175                 break;
176 #ifdef MPD_HAVE_IPV6
177         case AF_INET6:
178                 if (!mpd_ipv6Supported()) {
179                         strcpy(connection->errorStr,
180                                "no IPv6 suuport but a "
181                                "IPv6 address found\n");
182                         connection->error = MPD_ERROR_SYSTEM;
183                         return connection;
184                 }
185                 memcpy((char *) &sin6.sin6_addr.s6_addr,
186                        (char *) he->h_addr, he->h_length);
187                 dest = (struct sockaddr *) &sin6;
188                 destlen = sizeof(struct sockaddr_in6);
189                 break;
190 #endif
191         default:
192                 strcpy(connection->errorStr,
193                        "address type is not IPv4 or " "IPv6\n");
194                 connection->error = MPD_ERROR_SYSTEM;
195                 return connection;
196                 break;
197         }
198
199         if ((connection->sock =
200              socket(dest->sa_family, SOCK_STREAM, 0)) < 0) {
201                 strcpy(connection->errorStr, "problems creating socket");
202                 connection->error = MPD_ERROR_SYSTEM;
203                 return connection;
204         }
205
206         mpd_setConnectionTimeout(connection, timeout);
207
208         /* connect stuff */
209         {
210                 int flags = fcntl(connection->sock, F_GETFL, 0);
211                 fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
212
213                 if (connect(connection->sock, dest, destlen) < 0
214                     && errno != EINPROGRESS) {
215                         snprintf(connection->errorStr,
216                                  MPD_BUFFER_MAX_LENGTH,
217                                  "problems connecting to \"%s\" on port"
218                                  " %i", host, port);
219                         connection->error = MPD_ERROR_CONNPORT;
220                         return connection;
221                 }
222         }
223
224         while (!(rt = strstr(connection->buffer, "\n"))) {
225                 tv.tv_sec = connection->timeout.tv_sec;
226                 tv.tv_usec = connection->timeout.tv_usec;
227                 FD_ZERO(&fds);
228                 FD_SET(connection->sock, &fds);
229                 if ((err =
230                      select(connection->sock + 1, &fds, NULL, NULL,
231                             &tv)) == 1) {
232                         int readed;
233                         readed = recv(connection->sock,
234                                       &(connection->
235                                         buffer[connection->buflen]),
236                                       MPD_BUFFER_MAX_LENGTH -
237                                       connection->buflen, 0);
238                         if (readed <= 0) {
239                                 snprintf(connection->errorStr,
240                                          MPD_BUFFER_MAX_LENGTH,
241                                          "problems getting a response from"
242                                          " \"%s\" on port %i", host, port);
243                                 connection->error = MPD_ERROR_NORESPONSE;
244                                 return connection;
245                         }
246                         connection->buflen += readed;
247                         connection->buffer[connection->buflen] = '\0';
248                         tv.tv_sec = connection->timeout.tv_sec;
249                         tv.tv_usec = connection->timeout.tv_usec;
250                 } else if (err < 0) {
251                         switch (errno) {
252                         case EINTR:
253                                 continue;
254                         default:
255                                 snprintf(connection->errorStr,
256                                          MPD_BUFFER_MAX_LENGTH,
257                                          "problems connecting to \"%s\" on port"
258                                          " %i", host, port);
259                                 connection->error = MPD_ERROR_CONNPORT;
260                                 return connection;
261                         }
262                 } else {
263                         snprintf(connection->errorStr,
264                                  MPD_BUFFER_MAX_LENGTH,
265                                  "timeout in attempting to get a response from"
266                                  " \"%s\" on port %i", host, port);
267                         connection->error = MPD_ERROR_NORESPONSE;
268                         return connection;
269                 }
270         }
271
272         *rt = '\0';
273         output = strdup(connection->buffer);
274         strcpy(connection->buffer, rt + 1);
275         connection->buflen = strlen(connection->buffer);
276
277         if (strncmp
278             (output, MPD_WELCOME_MESSAGE, strlen(MPD_WELCOME_MESSAGE))) {
279                 free(output);
280                 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
281                          "mpd not running on port %i on host \"%s\"", port,
282                          host);
283                 connection->error = MPD_ERROR_NOTMPD;
284                 return connection;
285         }
286
287         {
288                 char *test;
289                 char *version[3];
290                 char *tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
291                 char *search = ".";
292                 int i;
293
294                 for (i = 0; i < 3; i++) {
295                         char *tok;
296                         if (i == 3)
297                                 search = " ";
298                         version[i] = strtok_r(tmp, search, &tok);
299                         if (!version[i]) {
300                                 free(output);
301                                 snprintf(connection->errorStr,
302                                          MPD_BUFFER_MAX_LENGTH,
303                                          "error parsing version number at "
304                                          "\"%s\"",
305                                          &output[strlen
306                                                  (MPD_WELCOME_MESSAGE)]);
307                                 connection->error = MPD_ERROR_NOTMPD;
308                                 return connection;
309                         }
310                         connection->version[i] =
311                             strtol(version[i], &test, 10);
312                         if (version[i] == test || *test != '\0') {
313                                 free(output);
314                                 snprintf(connection->errorStr,
315                                          MPD_BUFFER_MAX_LENGTH,
316                                          "error parsing version number at "
317                                          "\"%s\"",
318                                          &output[strlen
319                                                  (MPD_WELCOME_MESSAGE)]);
320                                 connection->error = MPD_ERROR_NOTMPD;
321                                 return connection;
322                         }
323                         tmp = NULL;
324                 }
325         }
326
327         free(output);
328
329         connection->doneProcessing = 1;
330
331         return connection;
332 }
333
334 void mpd_clearError(mpd_Connection * connection)
335 {
336         connection->error = 0;
337         connection->errorStr[0] = '\0';
338 }
339
340 void mpd_closeConnection(mpd_Connection * connection)
341 {
342         close(connection->sock);
343         if (connection->returnElement)
344                 free(connection->returnElement);
345         free(connection);
346 }
347
348 void mpd_executeCommand(mpd_Connection * connection, char *command)
349 {
350         int ret;
351         struct timeval tv;
352         fd_set fds;
353         char *commandPtr = command;
354         int commandLen = strlen(command);
355
356         if (!connection->doneProcessing && !connection->commandList) {
357                 strcpy(connection->errorStr,
358                        "not done processing current command");
359                 connection->error = 1;
360                 return;
361         }
362
363         mpd_clearError(connection);
364
365         FD_ZERO(&fds);
366         FD_SET(connection->sock, &fds);
367         tv.tv_sec = connection->timeout.tv_sec;
368         tv.tv_usec = connection->timeout.tv_usec;
369
370         while ((ret =
371                 select(connection->sock + 1, NULL, &fds, NULL, &tv) == 1)
372                || (ret == -1 && errno == EINTR)) {
373                 ret =
374                     send(connection->sock, commandPtr, commandLen,
375                          MSG_DONTWAIT);
376                 if (ret <= 0) {
377                         if (ret == EAGAIN || ret == EINTR)
378                                 continue;
379                         snprintf(connection->errorStr,
380                                  MPD_BUFFER_MAX_LENGTH,
381                                  "problems giving command \"%s\"",
382                                  command);
383                         connection->error = MPD_ERROR_SENDING;
384                         return;
385                 } else {
386                         commandPtr += ret;
387                         commandLen -= ret;
388                 }
389
390                 if (commandLen <= 0)
391                         break;
392         }
393
394         if (commandLen > 0) {
395                 perror("");
396                 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
397                          "timeout sending command \"%s\"", command);
398                 connection->error = MPD_ERROR_TIMEOUT;
399                 return;
400         }
401
402         if (!connection->commandList)
403                 connection->doneProcessing = 0;
404         else if (connection->commandList == COMMAND_LIST_OK) {
405                 connection->listOks++;
406         }
407 }
408
409 void mpd_getNextReturnElement(mpd_Connection * connection)
410 {
411         char *output = NULL;
412         char *rt = NULL;
413         char *name = NULL;
414         char *value = NULL;
415         fd_set fds;
416         struct timeval tv;
417         char *tok = NULL;
418         int readed;
419         char *bufferCheck = NULL;
420         int err;
421
422         if (connection->returnElement)
423                 mpd_freeReturnElement(connection->returnElement);
424         connection->returnElement = NULL;
425
426         if (connection->doneProcessing || (connection->listOks &&
427                                            connection->doneListOk)) {
428                 strcpy(connection->errorStr,
429                        "already done processing current command");
430                 connection->error = 1;
431                 return;
432         }
433
434         bufferCheck = connection->buffer + connection->bufstart;
435         while (connection->bufstart >= connection->buflen ||
436                !(rt = strstr(bufferCheck, "\n"))) {
437                 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
438                         memmove(connection->buffer,
439                                 connection->buffer +
440                                 connection->bufstart,
441                                 connection->buflen - connection->bufstart +
442                                 1);
443                         bufferCheck -= connection->bufstart;
444                         connection->buflen -= connection->bufstart;
445                         connection->bufstart = 0;
446                 }
447                 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
448                         strcpy(connection->errorStr, "buffer overrun");
449                         connection->error = MPD_ERROR_BUFFEROVERRUN;
450                         connection->doneProcessing = 1;
451                         connection->doneListOk = 0;
452                         return;
453                 }
454                 bufferCheck += connection->buflen - connection->bufstart;
455                 tv.tv_sec = connection->timeout.tv_sec;
456                 tv.tv_usec = connection->timeout.tv_usec;
457                 FD_ZERO(&fds);
458                 FD_SET(connection->sock, &fds);
459                 if ((err =
460                      select(connection->sock + 1, &fds, NULL, NULL,
461                             &tv) == 1)) {
462                         readed =
463                             recv(connection->sock,
464                                  connection->buffer + connection->buflen,
465                                  MPD_BUFFER_MAX_LENGTH -
466                                  connection->buflen, MSG_DONTWAIT);
467                         if (readed < 0
468                             && (errno == EAGAIN || errno == EINTR)) {
469                                 continue;
470                         }
471                         if (readed <= 0) {
472                                 strcpy(connection->errorStr,
473                                        "connection" " closed");
474                                 connection->error = MPD_ERROR_CONNCLOSED;
475                                 connection->doneProcessing = 1;
476                                 connection->doneListOk = 0;
477                                 return;
478                         }
479                         connection->buflen += readed;
480                         connection->buffer[connection->buflen] = '\0';
481                 } else if (err < 0 && errno == EINTR)
482                         continue;
483                 else {
484                         strcpy(connection->errorStr, "connection timeout");
485                         connection->error = MPD_ERROR_TIMEOUT;
486                         connection->doneProcessing = 1;
487                         connection->doneListOk = 0;
488                         return;
489                 }
490         }
491
492         *rt = '\0';
493         output = connection->buffer + connection->bufstart;
494         connection->bufstart = rt - connection->buffer + 1;
495
496         if (strcmp(output, "OK") == 0) {
497                 if (connection->listOks > 0) {
498                         strcpy(connection->errorStr,
499                                "expected more list_OK's");
500                         connection->error = 1;
501                 }
502                 connection->listOks = 0;
503                 connection->doneProcessing = 1;
504                 connection->doneListOk = 0;
505                 return;
506         }
507
508         if (strcmp(output, "list_OK") == 0) {
509                 if (!connection->listOks) {
510                         strcpy(connection->errorStr,
511                                "got an unexpected list_OK");
512                         connection->error = 1;
513                 } else {
514                         connection->doneListOk = 1;
515                         connection->listOks--;
516                 }
517                 return;
518         }
519
520         if (strncmp(output, "ACK", strlen("ACK")) == 0) {
521                 char *test;
522                 char *needle;
523                 int val;
524
525                 strcpy(connection->errorStr, output);
526                 connection->error = MPD_ERROR_ACK;
527                 connection->errorCode = MPD_ACK_ERROR_UNK;
528                 connection->errorAt = MPD_ERROR_AT_UNK;
529                 connection->doneProcessing = 1;
530                 connection->doneListOk = 0;
531
532                 needle = strchr(output, '[');
533                 if (!needle)
534                         return;
535                 val = strtol(needle + 1, &test, 10);
536                 if (*test != '@')
537                         return;
538                 connection->errorCode = val;
539                 val = strtol(test + 1, &test, 10);
540                 if (*test != ']')
541                         return;
542                 connection->errorAt = val;
543                 return;
544         }
545
546         name = strtok_r(output, ":", &tok);
547         if (name && (value = strtok_r(NULL, "", &tok)) && value[0] == ' ') {
548                 connection->returnElement =
549                     mpd_newReturnElement(name, &(value[1]));
550         } else {
551                 if (!name || !value) {
552                         snprintf(connection->errorStr,
553                                  MPD_BUFFER_MAX_LENGTH,
554                                  "error parsing: %s", output);
555                 } else {
556                         snprintf(connection->errorStr,
557                                  MPD_BUFFER_MAX_LENGTH,
558                                  "error parsing: %s:%s", name, value);
559                 }
560                 connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0';
561                 connection->error = 1;
562         }
563 }
564
565 void mpd_finishCommand(mpd_Connection * connection)
566 {
567         while (!connection->doneProcessing) {
568                 if (connection->doneListOk)
569                         connection->doneListOk = 0;
570                 mpd_getNextReturnElement(connection);
571         }
572 }
573
574 void mpd_finishListOkCommand(mpd_Connection * connection)
575 {
576         while (!connection->doneProcessing && connection->listOks &&
577                !connection->doneListOk) {
578                 mpd_getNextReturnElement(connection);
579         }
580 }
581
582 int mpd_nextListOkCommand(mpd_Connection * connection)
583 {
584         mpd_finishListOkCommand(connection);
585         if (!connection->doneProcessing)
586                 connection->doneListOk = 0;
587         if (connection->listOks == 0 || connection->doneProcessing)
588                 return -1;
589         return 0;
590 }
591
592 void mpd_sendStatusCommand(mpd_Connection * connection)
593 {
594         mpd_executeCommand(connection, "status\n");
595 }
596
597 mpd_Status *mpd_getStatus(mpd_Connection * connection)
598 {
599         mpd_Status *status;
600
601         /*mpd_executeCommand(connection,"status\n");
602
603            if(connection->error) return NULL; */
604
605         if (connection->doneProcessing || (connection->listOks &&
606                                            connection->doneListOk)) {
607                 return NULL;
608         }
609
610         if (!connection->returnElement)
611                 mpd_getNextReturnElement(connection);
612
613         status = malloc(sizeof(mpd_Status));
614         status->volume = -1;
615         status->repeat = 0;
616         status->random = 0;
617         status->playlist = -1;
618         status->playlistLength = -1;
619         status->state = -1;
620         status->song = 0;
621         status->elapsedTime = 0;
622         status->totalTime = 0;
623         status->bitRate = 0;
624         status->sampleRate = 0;
625         status->bits = 0;
626         status->channels = 0;
627         status->crossfade = -1;
628         status->error = NULL;
629         status->updatingDb = 0;
630
631         if (connection->error) {
632                 free(status);
633                 return NULL;
634         }
635         while (connection->returnElement) {
636                 mpd_ReturnElement *re = connection->returnElement;
637                 if (strcmp(re->name, "volume") == 0) {
638                         status->volume = atoi(re->value);
639                 } else if (strcmp(re->name, "repeat") == 0) {
640                         status->repeat = atoi(re->value);
641                 } else if (strcmp(re->name, "random") == 0) {
642                         status->random = atoi(re->value);
643                 } else if (strcmp(re->name, "playlist") == 0) {
644                         status->playlist = strtol(re->value, NULL, 10);
645                 } else if (strcmp(re->name, "playlistlength") == 0) {
646                         status->playlistLength = atoi(re->value);
647                 } else if (strcmp(re->name, "bitrate") == 0) {
648                         status->bitRate = atoi(re->value);
649                 } else if (strcmp(re->name, "state") == 0) {
650                         if (strcmp(re->value, "play") == 0) {
651                                 status->state = MPD_STATUS_STATE_PLAY;
652                         } else if (strcmp(re->value, "stop") == 0) {
653                                 status->state = MPD_STATUS_STATE_STOP;
654                         } else if (strcmp(re->value, "pause") == 0) {
655                                 status->state = MPD_STATUS_STATE_PAUSE;
656                         } else {
657                                 status->state = MPD_STATUS_STATE_UNKNOWN;
658                         }
659                 } else if (strcmp(re->name, "song") == 0) {
660                         status->song = atoi(re->value);
661                 } else if (strcmp(re->name, "songid") == 0) {
662                         status->songid = atoi(re->value);
663                 } else if (strcmp(re->name, "time") == 0) {
664                         char *tok;
665                         char *copy;
666                         char *temp;
667                         copy = strdup(re->value);
668                         temp = strtok_r(copy, ":", &tok);
669                         if (temp) {
670                                 status->elapsedTime = atoi(temp);
671                                 temp = strtok_r(NULL, "", &tok);
672                                 if (temp)
673                                         status->totalTime = atoi(temp);
674                         }
675                         free(copy);
676                 } else if (strcmp(re->name, "error") == 0) {
677                         status->error = strdup(re->value);
678                 } else if (strcmp(re->name, "xfade") == 0) {
679                         status->crossfade = atoi(re->value);
680                 } else if (strcmp(re->name, "updating_db") == 0) {
681                         status->updatingDb = atoi(re->value);
682                 } else if (strcmp(re->name, "audio") == 0) {
683                         char *tok;
684                         char *copy;
685                         char *temp;
686                         copy = strdup(re->value);
687                         temp = strtok_r(copy, ":", &tok);
688                         if (temp) {
689                                 status->sampleRate = atoi(temp);
690                                 temp = strtok_r(NULL, ":", &tok);
691                                 if (temp) {
692                                         status->bits = atoi(temp);
693                                         temp = strtok_r(NULL, "", &tok);
694                                         if (temp)
695                                                 status->channels =
696                                                     atoi(temp);
697                                 }
698                         }
699                         free(copy);
700                 }
701
702                 mpd_getNextReturnElement(connection);
703                 if (connection->error) {
704                         free(status);
705                         return NULL;
706                 }
707         }
708
709         if (connection->error) {
710                 free(status);
711                 return NULL;
712         } else if (status->state < 0) {
713                 strcpy(connection->errorStr, "state not found");
714                 connection->error = 1;
715                 free(status);
716                 return NULL;
717         }
718
719         return status;
720 }
721
722 void mpd_freeStatus(mpd_Status * status)
723 {
724         if (status->error)
725                 free(status->error);
726         free(status);
727 }
728
729 void mpd_sendStatsCommand(mpd_Connection * connection)
730 {
731         mpd_executeCommand(connection, "stats\n");
732 }
733
734 mpd_Stats *mpd_getStats(mpd_Connection * connection)
735 {
736         mpd_Stats *stats;
737
738         /*mpd_executeCommand(connection,"stats\n");
739
740            if(connection->error) return NULL; */
741
742         if (connection->doneProcessing || (connection->listOks &&
743                                            connection->doneListOk)) {
744                 return NULL;
745         }
746
747         if (!connection->returnElement)
748                 mpd_getNextReturnElement(connection);
749
750         stats = malloc(sizeof(mpd_Stats));
751         stats->numberOfArtists = 0;
752         stats->numberOfAlbums = 0;
753         stats->numberOfSongs = 0;
754         stats->uptime = 0;
755         stats->dbUpdateTime = 0;
756         stats->playTime = 0;
757         stats->dbPlayTime = 0;
758
759         if (connection->error) {
760                 free(stats);
761                 return NULL;
762         }
763         while (connection->returnElement) {
764                 mpd_ReturnElement *re = connection->returnElement;
765                 if (strcmp(re->name, "artists") == 0) {
766                         stats->numberOfArtists = atoi(re->value);
767                 } else if (strcmp(re->name, "albums") == 0) {
768                         stats->numberOfAlbums = atoi(re->value);
769                 } else if (strcmp(re->name, "songs") == 0) {
770                         stats->numberOfSongs = atoi(re->value);
771                 } else if (strcmp(re->name, "uptime") == 0) {
772                         stats->uptime = strtol(re->value, NULL, 10);
773                 } else if (strcmp(re->name, "db_update") == 0) {
774                         stats->dbUpdateTime = strtol(re->value, NULL, 10);
775                 } else if (strcmp(re->name, "playtime") == 0) {
776                         stats->playTime = strtol(re->value, NULL, 10);
777                 } else if (strcmp(re->name, "db_playtime") == 0) {
778                         stats->dbPlayTime = strtol(re->value, NULL, 10);
779                 }
780
781                 mpd_getNextReturnElement(connection);
782                 if (connection->error) {
783                         free(stats);
784                         return NULL;
785                 }
786         }
787
788         if (connection->error) {
789                 free(stats);
790                 return NULL;
791         }
792
793         return stats;
794 }
795
796 void mpd_freeStats(mpd_Stats * stats)
797 {
798         free(stats);
799 }
800
801 void mpd_initSong(mpd_Song * song)
802 {
803         song->file = NULL;
804         song->artist = NULL;
805         song->album = NULL;
806         song->track = NULL;
807         song->title = NULL;
808         song->name = NULL;
809         song->time = MPD_SONG_NO_TIME;
810         song->pos = MPD_SONG_NO_NUM;
811         song->id = MPD_SONG_NO_ID;
812 }
813
814 void mpd_finishSong(mpd_Song * song)
815 {
816         if (song->file)
817                 free(song->file);
818         if (song->artist)
819                 free(song->artist);
820         if (song->album)
821                 free(song->album);
822         if (song->title)
823                 free(song->title);
824         if (song->track)
825                 free(song->track);
826         if (song->name)
827                 free(song->name);
828 }
829
830 mpd_Song *mpd_newSong()
831 {
832         mpd_Song *ret = malloc(sizeof(mpd_Song));
833
834         mpd_initSong(ret);
835
836         return ret;
837 }
838
839 void mpd_freeSong(mpd_Song * song)
840 {
841         mpd_finishSong(song);
842         free(song);
843 }
844
845 mpd_Song *mpd_songDup(mpd_Song * song)
846 {
847         mpd_Song *ret = mpd_newSong();
848
849         if (song->file)
850                 ret->file = strdup(song->file);
851         if (song->artist)
852                 ret->artist = strdup(song->artist);
853         if (song->album)
854                 ret->album = strdup(song->album);
855         if (song->title)
856                 ret->title = strdup(song->title);
857         if (song->track)
858                 ret->track = strdup(song->track);
859         if (song->name)
860                 ret->name = strdup(song->name);
861         ret->time = song->time;
862         ret->pos = song->pos;
863         ret->id = song->id;
864
865         return ret;
866 }
867
868 void mpd_initDirectory(mpd_Directory * directory)
869 {
870         directory->path = NULL;
871 }
872
873 void mpd_finishDirectory(mpd_Directory * directory)
874 {
875         if (directory->path)
876                 free(directory->path);
877 }
878
879 mpd_Directory *mpd_newDirectory()
880 {
881         mpd_Directory *directory = malloc(sizeof(mpd_Directory));;
882
883         mpd_initDirectory(directory);
884
885         return directory;
886 }
887
888 void mpd_freeDirectory(mpd_Directory * directory)
889 {
890         mpd_finishDirectory(directory);
891
892         free(directory);
893 }
894
895 mpd_Directory *mpd_directoryDup(mpd_Directory * directory)
896 {
897         mpd_Directory *ret = mpd_newDirectory();
898
899         if (directory->path)
900                 ret->path = strdup(directory->path);
901
902         return ret;
903 }
904
905 void mpd_initPlaylistFile(mpd_PlaylistFile * playlist)
906 {
907         playlist->path = NULL;
908 }
909
910 void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist)
911 {
912         if (playlist->path)
913                 free(playlist->path);
914 }
915
916 mpd_PlaylistFile *mpd_newPlaylistFile()
917 {
918         mpd_PlaylistFile *playlist = malloc(sizeof(mpd_PlaylistFile));
919
920         mpd_initPlaylistFile(playlist);
921
922         return playlist;
923 }
924
925 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist)
926 {
927         mpd_finishPlaylistFile(playlist);
928         free(playlist);
929 }
930
931 mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile * playlist)
932 {
933         mpd_PlaylistFile *ret = mpd_newPlaylistFile();
934
935         if (playlist->path)
936                 ret->path = strdup(playlist->path);
937
938         return ret;
939 }
940
941 void mpd_initInfoEntity(mpd_InfoEntity * entity)
942 {
943         entity->info.directory = NULL;
944 }
945
946 void mpd_finishInfoEntity(mpd_InfoEntity * entity)
947 {
948         if (entity->info.directory) {
949                 if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
950                         mpd_freeDirectory(entity->info.directory);
951                 } else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
952                         mpd_freeSong(entity->info.song);
953                 } else if (entity->type ==
954                            MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
955                         mpd_freePlaylistFile(entity->info.playlistFile);
956                 }
957         }
958 }
959
960 mpd_InfoEntity *mpd_newInfoEntity()
961 {
962         mpd_InfoEntity *entity = malloc(sizeof(mpd_InfoEntity));
963
964         mpd_initInfoEntity(entity);
965
966         return entity;
967 }
968
969 void mpd_freeInfoEntity(mpd_InfoEntity * entity)
970 {
971         mpd_finishInfoEntity(entity);
972         free(entity);
973 }
974
975 void mpd_sendInfoCommand(mpd_Connection * connection, char *command)
976 {
977         mpd_executeCommand(connection, command);
978 }
979
980 mpd_InfoEntity *mpd_getNextInfoEntity(mpd_Connection * connection)
981 {
982         mpd_InfoEntity *entity = NULL;
983
984         if (connection->doneProcessing || (connection->listOks &&
985                                            connection->doneListOk)) {
986                 return NULL;
987         }
988
989         if (!connection->returnElement)
990                 mpd_getNextReturnElement(connection);
991
992         if (connection->returnElement) {
993                 if (strcmp(connection->returnElement->name, "file") == 0) {
994                         entity = mpd_newInfoEntity();
995                         entity->type = MPD_INFO_ENTITY_TYPE_SONG;
996                         entity->info.song = mpd_newSong();
997                         entity->info.song->file =
998                             strdup(connection->returnElement->value);
999                 } else
1000                     if (strcmp
1001                         (connection->returnElement->name,
1002                          "directory") == 0) {
1003                         entity = mpd_newInfoEntity();
1004                         entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
1005                         entity->info.directory = mpd_newDirectory();
1006                         entity->info.directory->path =
1007                             strdup(connection->returnElement->value);
1008                 } else
1009                     if (strcmp(connection->returnElement->name, "playlist")
1010                         == 0) {
1011                         entity = mpd_newInfoEntity();
1012                         entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
1013                         entity->info.playlistFile = mpd_newPlaylistFile();
1014                         entity->info.playlistFile->path =
1015                             strdup(connection->returnElement->value);
1016                 } else {
1017                         connection->error = 1;
1018                         strcpy(connection->errorStr,
1019                                "problem parsing song info");
1020                         return NULL;
1021                 }
1022         } else
1023                 return NULL;
1024
1025         mpd_getNextReturnElement(connection);
1026         while (connection->returnElement) {
1027                 mpd_ReturnElement *re = connection->returnElement;
1028
1029                 if (strcmp(re->name, "file") == 0)
1030                         return entity;
1031                 else if (strcmp(re->name, "directory") == 0)
1032                         return entity;
1033                 else if (strcmp(re->name, "playlist") == 0)
1034                         return entity;
1035
1036                 if (entity->type == MPD_INFO_ENTITY_TYPE_SONG
1037                     && strlen(re->value)) {
1038                         if (!entity->info.song->artist
1039                             && strcmp(re->name, "Artist") == 0) {
1040                                 entity->info.song->artist =
1041                                     strdup(re->value);
1042                         } else if (!entity->info.song->album
1043                                    && strcmp(re->name, "Album") == 0) {
1044                                 entity->info.song->album =
1045                                     strdup(re->value);
1046                         } else if (!entity->info.song->title
1047                                    && strcmp(re->name, "Title") == 0) {
1048                                 entity->info.song->title =
1049                                     strdup(re->value);
1050                         } else if (!entity->info.song->track
1051                                    && strcmp(re->name, "Track") == 0) {
1052                                 entity->info.song->track =
1053                                     strdup(re->value);
1054                         } else if (!entity->info.song->name
1055                                    && strcmp(re->name, "Name") == 0) {
1056                                 entity->info.song->name =
1057                                     strdup(re->value);
1058                         } else if (entity->info.song->time ==
1059                                    MPD_SONG_NO_TIME
1060                                    && strcmp(re->name, "Time") == 0) {
1061                                 entity->info.song->time = atoi(re->value);
1062                         } else if (entity->info.song->pos ==
1063                                    MPD_SONG_NO_NUM
1064                                    && strcmp(re->name, "Pos") == 0) {
1065                                 entity->info.song->pos = atoi(re->value);
1066                         } else if (entity->info.song->id == MPD_SONG_NO_ID
1067                                    && strcmp(re->name, "Id") == 0) {
1068                                 entity->info.song->id = atoi(re->value);
1069                         }
1070                 } else if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1071                 } else if (entity->type ==
1072                            MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1073                 }
1074
1075                 mpd_getNextReturnElement(connection);
1076         }
1077
1078         return entity;
1079 }
1080
1081 char *mpd_getNextReturnElementNamed(mpd_Connection * connection,
1082                                     const char *name)
1083 {
1084         if (connection->doneProcessing || (connection->listOks &&
1085                                            connection->doneListOk)) {
1086                 return NULL;
1087         }
1088
1089         mpd_getNextReturnElement(connection);
1090         while (connection->returnElement) {
1091                 mpd_ReturnElement *re = connection->returnElement;
1092
1093                 if (strcmp(re->name, name) == 0)
1094                         return strdup(re->value);
1095                 mpd_getNextReturnElement(connection);
1096         }
1097
1098         return NULL;
1099 }
1100
1101 char *mpd_getNextArtist(mpd_Connection * connection)
1102 {
1103         return mpd_getNextReturnElementNamed(connection, "Artist");
1104 }
1105
1106 char *mpd_getNextAlbum(mpd_Connection * connection)
1107 {
1108         return mpd_getNextReturnElementNamed(connection, "Album");
1109 }
1110
1111 void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos)
1112 {
1113         char *string = malloc(strlen("playlistinfo") + 25);
1114         sprintf(string, "playlistinfo \"%i\"\n", songPos);
1115         mpd_sendInfoCommand(connection, string);
1116         free(string);
1117 }
1118
1119 void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id)
1120 {
1121         char *string = malloc(strlen("playlistid") + 25);
1122         sprintf(string, "playlistid \"%i\"\n", id);
1123         mpd_sendInfoCommand(connection, string);
1124         free(string);
1125 }
1126
1127 void
1128 mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist)
1129 {
1130         char *string = malloc(strlen("plchanges") + 25);
1131         sprintf(string, "plchanges \"%lld\"\n", playlist);
1132         mpd_sendInfoCommand(connection, string);
1133         free(string);
1134 }
1135
1136 void mpd_sendListallCommand(mpd_Connection * connection, const char *dir)
1137 {
1138         char *sDir = mpd_sanitizeArg(dir);
1139         char *string = malloc(strlen("listall") + strlen(sDir) + 5);
1140         sprintf(string, "listall \"%s\"\n", sDir);
1141         mpd_sendInfoCommand(connection, string);
1142         free(string);
1143         free(sDir);
1144 }
1145
1146 void
1147 mpd_sendListallInfoCommand(mpd_Connection * connection, const char *dir)
1148 {
1149         char *sDir = mpd_sanitizeArg(dir);
1150         char *string = malloc(strlen("listallinfo") + strlen(sDir) + 5);
1151         sprintf(string, "listallinfo \"%s\"\n", sDir);
1152         mpd_sendInfoCommand(connection, string);
1153         free(string);
1154         free(sDir);
1155 }
1156
1157 void mpd_sendLsInfoCommand(mpd_Connection * connection, const char *dir)
1158 {
1159         char *sDir = mpd_sanitizeArg(dir);
1160         char *string = malloc(strlen("lsinfo") + strlen(sDir) + 5);
1161         sprintf(string, "lsinfo \"%s\"\n", sDir);
1162         mpd_sendInfoCommand(connection, string);
1163         free(string);
1164         free(sDir);
1165 }
1166
1167 void mpd_sendCurrentSongCommand(mpd_Connection * connection)
1168 {
1169         mpd_executeCommand(connection, "currentsong\n");
1170 }
1171
1172 void
1173 mpd_sendSearchCommand(mpd_Connection * connection, int table,
1174                       const char *str)
1175 {
1176         char st[10];
1177         char *string;
1178         char *sanitStr = mpd_sanitizeArg(str);
1179         if (table == MPD_TABLE_ARTIST)
1180                 strcpy(st, "artist");
1181         else if (table == MPD_TABLE_ALBUM)
1182                 strcpy(st, "album");
1183         else if (table == MPD_TABLE_TITLE)
1184                 strcpy(st, "title");
1185         else if (table == MPD_TABLE_FILENAME)
1186                 strcpy(st, "filename");
1187         else {
1188                 connection->error = 1;
1189                 strcpy(connection->errorStr, "unknown table for search");
1190                 return;
1191         }
1192         string =
1193             malloc(strlen("search") + strlen(sanitStr) + strlen(st) + 6);
1194         sprintf(string, "search %s \"%s\"\n", st, sanitStr);
1195         mpd_sendInfoCommand(connection, string);
1196         free(string);
1197         free(sanitStr);
1198 }
1199
1200 void
1201 mpd_sendFindCommand(mpd_Connection * connection, int table,
1202                     const char *str)
1203 {
1204         char st[10];
1205         char *string;
1206         char *sanitStr = mpd_sanitizeArg(str);
1207         if (table == MPD_TABLE_ARTIST)
1208                 strcpy(st, "artist");
1209         else if (table == MPD_TABLE_ALBUM)
1210                 strcpy(st, "album");
1211         else if (table == MPD_TABLE_TITLE)
1212                 strcpy(st, "title");
1213         else {
1214                 connection->error = 1;
1215                 strcpy(connection->errorStr, "unknown table for find");
1216                 return;
1217         }
1218         string =
1219             malloc(strlen("find") + strlen(sanitStr) + strlen(st) + 6);
1220         sprintf(string, "find %s \"%s\"\n", st, sanitStr);
1221         mpd_sendInfoCommand(connection, string);
1222         free(string);
1223         free(sanitStr);
1224 }
1225
1226 void
1227 mpd_sendListCommand(mpd_Connection * connection, int table,
1228                     const char *arg1)
1229 {
1230         char st[10];
1231         char *string;
1232         if (table == MPD_TABLE_ARTIST)
1233                 strcpy(st, "artist");
1234         else if (table == MPD_TABLE_ALBUM)
1235                 strcpy(st, "album");
1236         else {
1237                 connection->error = 1;
1238                 strcpy(connection->errorStr, "unknown table for list");
1239                 return;
1240         }
1241         if (arg1) {
1242                 char *sanitArg1 = mpd_sanitizeArg(arg1);
1243                 string =
1244                     malloc(strlen("list") + strlen(sanitArg1) +
1245                            strlen(st) + 6);
1246                 sprintf(string, "list %s \"%s\"\n", st, sanitArg1);
1247                 free(sanitArg1);
1248         } else {
1249                 string = malloc(strlen("list") + strlen(st) + 3);
1250                 sprintf(string, "list %s\n", st);
1251         }
1252         mpd_sendInfoCommand(connection, string);
1253         free(string);
1254 }
1255
1256 void mpd_sendAddCommand(mpd_Connection * connection, const char *file)
1257 {
1258         char *sFile = mpd_sanitizeArg(file);
1259         char *string = malloc(strlen("add") + strlen(sFile) + 5);
1260         sprintf(string, "add \"%s\"\n", sFile);
1261         mpd_executeCommand(connection, string);
1262         free(string);
1263         free(sFile);
1264 }
1265
1266 void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos)
1267 {
1268         char *string = malloc(strlen("delete") + 25);
1269         sprintf(string, "delete \"%i\"\n", songPos);
1270         mpd_sendInfoCommand(connection, string);
1271         free(string);
1272 }
1273
1274 void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id)
1275 {
1276         char *string = malloc(strlen("deleteid") + 25);
1277         sprintf(string, "deleteid \"%i\"\n", id);
1278         mpd_sendInfoCommand(connection, string);
1279         free(string);
1280 }
1281
1282 void mpd_sendSaveCommand(mpd_Connection * connection, const char *name)
1283 {
1284         char *sName = mpd_sanitizeArg(name);
1285         char *string = malloc(strlen("save") + strlen(sName) + 5);
1286         sprintf(string, "save \"%s\"\n", sName);
1287         mpd_executeCommand(connection, string);
1288         free(string);
1289         free(sName);
1290 }
1291
1292 void mpd_sendLoadCommand(mpd_Connection * connection, const char *name)
1293 {
1294         char *sName = mpd_sanitizeArg(name);
1295         char *string = malloc(strlen("load") + strlen(sName) + 5);
1296         sprintf(string, "load \"%s\"\n", sName);
1297         mpd_executeCommand(connection, string);
1298         free(string);
1299         free(sName);
1300 }
1301
1302 void mpd_sendRmCommand(mpd_Connection * connection, const char *name)
1303 {
1304         char *sName = mpd_sanitizeArg(name);
1305         char *string = malloc(strlen("rm") + strlen(sName) + 5);
1306         sprintf(string, "rm \"%s\"\n", sName);
1307         mpd_executeCommand(connection, string);
1308         free(string);
1309         free(sName);
1310 }
1311
1312 void mpd_sendShuffleCommand(mpd_Connection * connection)
1313 {
1314         mpd_executeCommand(connection, "shuffle\n");
1315 }
1316
1317 void mpd_sendClearCommand(mpd_Connection * connection)
1318 {
1319         mpd_executeCommand(connection, "clear\n");
1320 }
1321
1322 void mpd_sendPlayCommand(mpd_Connection * connection, int songPos)
1323 {
1324         char *string = malloc(strlen("play") + 25);
1325         sprintf(string, "play \"%i\"\n", songPos);
1326         mpd_sendInfoCommand(connection, string);
1327         free(string);
1328 }
1329
1330 void mpd_sendPlayIdCommand(mpd_Connection * connection, int id)
1331 {
1332         char *string = malloc(strlen("playid") + 25);
1333         sprintf(string, "playid \"%i\"\n", id);
1334         mpd_sendInfoCommand(connection, string);
1335         free(string);
1336 }
1337
1338 void mpd_sendStopCommand(mpd_Connection * connection)
1339 {
1340         mpd_executeCommand(connection, "stop\n");
1341 }
1342
1343 void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode)
1344 {
1345         char *string = malloc(strlen("pause") + 25);
1346         sprintf(string, "pause \"%i\"\n", pauseMode);
1347         mpd_executeCommand(connection, string);
1348         free(string);
1349 }
1350
1351 void mpd_sendNextCommand(mpd_Connection * connection)
1352 {
1353         mpd_executeCommand(connection, "next\n");
1354 }
1355
1356 void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to)
1357 {
1358         char *string = malloc(strlen("move") + 25);
1359         sprintf(string, "move \"%i\" \"%i\"\n", from, to);
1360         mpd_sendInfoCommand(connection, string);
1361         free(string);
1362 }
1363
1364 void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to)
1365 {
1366         char *string = malloc(strlen("moveid") + 25);
1367         sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
1368         mpd_sendInfoCommand(connection, string);
1369         free(string);
1370 }
1371
1372 void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2)
1373 {
1374         char *string = malloc(strlen("swap") + 25);
1375         sprintf(string, "swap \"%i\" \"%i\"\n", song1, song2);
1376         mpd_sendInfoCommand(connection, string);
1377         free(string);
1378 }
1379
1380 void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2)
1381 {
1382         char *string = malloc(strlen("swapid") + 25);
1383         sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
1384         mpd_sendInfoCommand(connection, string);
1385         free(string);
1386 }
1387
1388 void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time)
1389 {
1390         char *string = malloc(strlen("seek") + 25);
1391         sprintf(string, "seek \"%i\" \"%i\"\n", song, time);
1392         mpd_sendInfoCommand(connection, string);
1393         free(string);
1394 }
1395
1396 void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time)
1397 {
1398         char *string = malloc(strlen("seekid") + 25);
1399         sprintf(string, "seekid \"%i\" \"%i\"\n", id, time);
1400         mpd_sendInfoCommand(connection, string);
1401         free(string);
1402 }
1403
1404 void mpd_sendUpdateCommand(mpd_Connection * connection, char *path)
1405 {
1406         char *sPath = mpd_sanitizeArg(path);
1407         char *string = malloc(strlen("update") + strlen(sPath) + 5);
1408         sprintf(string, "update \"%s\"\n", sPath);
1409         mpd_sendInfoCommand(connection, string);
1410         free(string);
1411         free(sPath);
1412 }
1413
1414 int mpd_getUpdateId(mpd_Connection * connection)
1415 {
1416         char *jobid;
1417         int ret = 0;
1418
1419         jobid = mpd_getNextReturnElementNamed(connection, "updating_db");
1420         if (jobid) {
1421                 ret = atoi(jobid);
1422                 free(jobid);
1423         }
1424
1425         return ret;
1426 }
1427
1428 void mpd_sendPrevCommand(mpd_Connection * connection)
1429 {
1430         mpd_executeCommand(connection, "previous\n");
1431 }
1432
1433 void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode)
1434 {
1435         char *string = malloc(strlen("repeat") + 25);
1436         sprintf(string, "repeat \"%i\"\n", repeatMode);
1437         mpd_executeCommand(connection, string);
1438         free(string);
1439 }
1440
1441 void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode)
1442 {
1443         char *string = malloc(strlen("random") + 25);
1444         sprintf(string, "random \"%i\"\n", randomMode);
1445         mpd_executeCommand(connection, string);
1446         free(string);
1447 }
1448
1449 void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange)
1450 {
1451         char *string = malloc(strlen("setvol") + 25);
1452         sprintf(string, "setvol \"%i\"\n", volumeChange);
1453         mpd_executeCommand(connection, string);
1454         free(string);
1455 }
1456
1457 void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange)
1458 {
1459         char *string = malloc(strlen("volume") + 25);
1460         sprintf(string, "volume \"%i\"\n", volumeChange);
1461         mpd_executeCommand(connection, string);
1462         free(string);
1463 }
1464
1465 void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds)
1466 {
1467         char *string = malloc(strlen("crossfade") + 25);
1468         sprintf(string, "crossfade \"%i\"\n", seconds);
1469         mpd_executeCommand(connection, string);
1470         free(string);
1471 }
1472
1473 void mpd_sendPasswordCommand(mpd_Connection * connection, const char *pass)
1474 {
1475         char *sPass = mpd_sanitizeArg(pass);
1476         char *string = malloc(strlen("password") + strlen(sPass) + 5);
1477         sprintf(string, "password \"%s\"\n", sPass);
1478         mpd_executeCommand(connection, string);
1479         free(string);
1480         free(sPass);
1481 }
1482
1483 void mpd_sendCommandListBegin(mpd_Connection * connection)
1484 {
1485         if (connection->commandList) {
1486                 strcpy(connection->errorStr,
1487                        "already in command list mode");
1488                 connection->error = 1;
1489                 return;
1490         }
1491         connection->commandList = COMMAND_LIST;
1492         mpd_executeCommand(connection, "command_list_begin\n");
1493 }
1494
1495 void mpd_sendCommandListOkBegin(mpd_Connection * connection)
1496 {
1497         if (connection->commandList) {
1498                 strcpy(connection->errorStr,
1499                        "already in command list mode");
1500                 connection->error = 1;
1501                 return;
1502         }
1503         connection->commandList = COMMAND_LIST_OK;
1504         mpd_executeCommand(connection, "command_list_ok_begin\n");
1505         connection->listOks = 0;
1506 }
1507
1508 void mpd_sendCommandListEnd(mpd_Connection * connection)
1509 {
1510         if (!connection->commandList) {
1511                 strcpy(connection->errorStr, "not in command list mode");
1512                 connection->error = 1;
1513                 return;
1514         }
1515         connection->commandList = 0;
1516         mpd_executeCommand(connection, "command_list_end\n");
1517 }