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