Code

a8bbabef7bd046a2b3bf0de1992c64e3764c9511
[ncmpc.git] / 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.
32 */
35 #include "libmpdclient.h"
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netdb.h>
41 #include <stdio.h>
42 #include <sys/param.h>
45 #include <string.h>
46 #include <strings.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <unistd.h>
50 #include <stdlib.h>
51 #include <fcntl.h>
52 #include <stdarg.h>
54 #ifndef MPD_NO_IPV6
55 #ifdef AF_INET6
56 #define MPD_HAVE_IPV6
57 #endif
58 #endif
60 #ifndef MSG_DONTWAIT
61 #define MSG_DONTWAIT 0
62 #endif
64 #define COMMAND_LIST    1
65 #define COMMAND_LIST_OK 2
67 char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] =
68 {
69         "Artist",
70         "Album",
71         "Title",
72         "Track",
73         "Name",
74         "Genre",
75         "Date",
76         "Composer",
77         "Performer",
78         "Comment",
79         "filename"
80 };
83 #ifdef MPD_HAVE_IPV6        
84 int mpd_ipv6Supported() {
85         int s;          
86         s = socket(AF_INET6,SOCK_STREAM,0);
87         if(s == -1) return 0;
88         close(s);       
89         return 1;                       
90 }                       
91 #endif  
93 static char * mpd_sanitizeArg(const char * arg) {
94         size_t i;
95         char * ret;
96         register const char *c;
97         register char *rc;
98         
99         /* 
100         unsigned int count = 0;
101         
102         c = arg;
103         for(i = strlen(arg); i != 0; --i) {
104                 if(*c=='"' || *c=='\\') count++;
105                 c++;
106         }
107         ret = malloc(strlen(arg)+count+1);
108         */
109         /* instead of counting in that loop above, just
110          * use a bit more memory and half running time
111          */
112         ret = malloc(strlen(arg) * 2 + 1);
114         c = arg;
115         rc = ret;
116         for(i = strlen(arg)+1; i != 0; --i) {
117                 if(*c=='"' || *c=='\\')
118                         *rc++ = '\\';
119                 *(rc++) = *(c++);
120         }
122         return ret;
125 mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
127         mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));
129         ret->name = (char *)strdup(name);
130         ret->value = (char *)strdup(value);
132         return ret;
135 void mpd_freeReturnElement(mpd_ReturnElement * re) {
136         free(re->name);
137         free(re->value);
138         free(re);
141 void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout) {
142                 connection->timeout.tv_sec = (int)timeout;
143                 connection->timeout.tv_usec = (int)(timeout*1e6 -
144                                 connection->timeout.tv_sec*1000000+0.5);
147 mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
148         int err;
149         struct hostent * he;
150         struct sockaddr * dest;
151 #ifdef HAVE_SOCKLEN_T
152         socklen_t destlen;
153 #else
154         int destlen;
155 #endif
156         struct sockaddr_in sin;
157         char * rt;
158         char * output;
159         mpd_Connection * connection = malloc(sizeof(mpd_Connection));
160         struct timeval tv;
161         fd_set fds;
162 #ifdef MPD_HAVE_IPV6
163         struct sockaddr_in6 sin6;
164 #endif
165         strcpy(connection->buffer,"");
166         connection->buflen = 0;
167         connection->bufstart = 0;
168         strcpy(connection->errorStr,"");
169         connection->error = 0;
170         connection->doneProcessing = 0;
171         connection->commandList = 0;
172         connection->listOks = 0;
173         connection->doneListOk = 0;
174         connection->returnElement = NULL;
176         if(!(he=gethostbyname(host))) {
177                 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
178                                 "host \"%s\" not found",host);
179                 connection->error = MPD_ERROR_UNKHOST;
180                 return connection;
181         }
183         memset(&sin,0,sizeof(struct sockaddr_in));
184         /*dest.sin_family = he->h_addrtype;*/
185         sin.sin_family = AF_INET;
186         sin.sin_port = htons(port);
187 #ifdef MPD_HAVE_IPV6
188         memset(&sin6,0,sizeof(struct sockaddr_in6));
189         sin6.sin6_family = AF_INET6;
190         sin6.sin6_port = htons(port);
191 #endif
192         switch(he->h_addrtype) {
193         case AF_INET:
194                 memcpy((char *)&sin.sin_addr.s_addr,(char *)he->h_addr,
195                                 he->h_length);
196                 dest = (struct sockaddr *)&sin;
197                 destlen = sizeof(struct sockaddr_in);
198                 break;
199 #ifdef MPD_HAVE_IPV6
200         case AF_INET6:
201                 if(!mpd_ipv6Supported()) {
202                         strcpy(connection->errorStr,"no IPv6 suuport but a "
203                                         "IPv6 address found\n");
204                         connection->error = MPD_ERROR_SYSTEM;
205                         return connection;
206                 }
207                 memcpy((char *)&sin6.sin6_addr.s6_addr,(char *)he->h_addr,
208                                 he->h_length);
209                 dest = (struct sockaddr *)&sin6;
210                 destlen = sizeof(struct sockaddr_in6);
211                 break;
212 #endif
213         default:
214                 strcpy(connection->errorStr,"address type is not IPv4 or "
215                                 "IPv6\n");
216                 connection->error = MPD_ERROR_SYSTEM;
217                 return connection;
218                 break;
219         }
220         
221         if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) {
222                 strcpy(connection->errorStr,"problems creating socket");
223                 connection->error = MPD_ERROR_SYSTEM;
224                 return connection;
225         }
227         mpd_setConnectionTimeout(connection,timeout);
229         /* connect stuff */
230         {
231                 int flags = fcntl(connection->sock, F_GETFL, 0);
232                 fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
234                 if(connect(connection->sock,dest,destlen)<0 && 
235                                 errno!=EINPROGRESS) 
236                 {
237                         snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
238                                         "problems connecting to \"%s\" on port"
239                                         " %i",host,port);
240                         connection->error = MPD_ERROR_CONNPORT;
241                         return connection;
242                 }
243         }
245         while(!(rt = strstr(connection->buffer,"\n"))) {
246                 tv.tv_sec = connection->timeout.tv_sec;
247                 tv.tv_usec = connection->timeout.tv_usec;
248                 FD_ZERO(&fds);
249                 FD_SET(connection->sock,&fds);
250                 if((err = select(connection->sock+1,&fds,NULL,NULL,&tv)) == 1) {
251                         int readed;
252                         readed = recv(connection->sock,
253                                 &(connection->buffer[connection->buflen]),
254                                 MPD_BUFFER_MAX_LENGTH-connection->buflen,0);
255                         if(readed<=0) {
256                                 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
257                                         "problems getting a response from"
258                                         " \"%s\" on port %i : %s",host,
259                                         port, strerror(errno));
260                                 connection->error = MPD_ERROR_NORESPONSE;
261                                 return connection;
262                         }
263                         connection->buflen+=readed;
264                         connection->buffer[connection->buflen] = '\0';
265                         tv.tv_sec = connection->timeout.tv_sec;
266                         tv.tv_usec = connection->timeout.tv_usec;
267                 }
268                 else if(err<0) {
269                         switch(errno) {
270                         case EINTR:
271                                 continue;
272                         default:
273                                 snprintf(connection->errorStr,
274                                         MPD_BUFFER_MAX_LENGTH,
275                                         "problems connecting to \"%s\" on port"
276                                         " %i",host,port);
277                                 connection->error = MPD_ERROR_CONNPORT;
278                                 return connection;
279                         }
280                 }
281                 else {
282                         snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
283                                 "timeout in attempting to get a response from"
284                                  " \"%s\" on port %i",host,port);
285                         connection->error = MPD_ERROR_NORESPONSE;
286                         return connection;
287                 }
288         }
290         *rt = '\0';
291         output = strdup(connection->buffer);
292         strcpy(connection->buffer,rt+1);
293         connection->buflen = strlen(connection->buffer);
295         if(strncmp(output,MPD_WELCOME_MESSAGE,strlen(MPD_WELCOME_MESSAGE))) {
296                 free(output);
297                 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
298                                 "mpd not running on port %i on host \"%s\"",
299                                 port,host);
300                 connection->error = MPD_ERROR_NOTMPD;
301                 return connection;
302         }
304         {
305                 char * test;
306                 char * version[3];
307                 char * tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
308                 char * search = ".";
309                 int i;
311                 for(i=0;i<3;i++) {
312                         char * tok;
313                         if(i==3) search = " ";
314                         version[i] = strtok_r(tmp,search,&tok);
315                         if(!version[i]) {
316                                 free(output);
317                                 snprintf(connection->errorStr,
318                                         MPD_BUFFER_MAX_LENGTH,
319                                         "error parsing version number at "
320                                         "\"%s\"",
321                                         &output[strlen(MPD_WELCOME_MESSAGE)]);
322                                 connection->error = MPD_ERROR_NOTMPD;
323                                 return connection;
324                         }
325                         connection->version[i] = strtol(version[i],&test,10);
326                         if(version[i]==test || *test!='\0') {
327                                 free(output);
328                                 snprintf(connection->errorStr,
329                                         MPD_BUFFER_MAX_LENGTH,
330                                         "error parsing version number at "
331                                         "\"%s\"",
332                                         &output[strlen(MPD_WELCOME_MESSAGE)]);
333                                 connection->error = MPD_ERROR_NOTMPD;
334                                 return connection;
335                         }
336                         tmp = NULL;
337                 }
338         }
340         free(output);
342         connection->doneProcessing = 1;
344         return connection;
347 void mpd_clearError(mpd_Connection * connection) {
348         connection->error = 0;
349         connection->errorStr[0] = '\0';
352 void mpd_closeConnection(mpd_Connection * connection) {
353         close(connection->sock);
354         if(connection->returnElement) free(connection->returnElement);
355         free(connection);
358 void mpd_executeCommand(mpd_Connection * connection, char * command) {
359         int ret;
360         struct timeval tv;
361         fd_set fds;
362         char * commandPtr = command;
363         int commandLen = strlen(command);
365         if(!connection->doneProcessing && !connection->commandList) {
366                 strcpy(connection->errorStr,"not done processing current command");
367                 connection->error = 1;
368                 return;
369         }
371         mpd_clearError(connection);
373         FD_ZERO(&fds);
374         FD_SET(connection->sock,&fds);
375         tv.tv_sec = connection->timeout.tv_sec;
376         tv.tv_usec = connection->timeout.tv_usec;
378         while((ret = select(connection->sock+1,NULL,&fds,NULL,&tv)==1) || 
379                         (ret==-1 && errno==EINTR)) {
380                 ret = send(connection->sock,commandPtr,commandLen,
381 #ifdef WIN32
382                            ioctlsocket(connection->sock, commandLen, commandPtr));
383 #endif
384 #ifndef WIN32
385                                 MSG_DONTWAIT);
386 #endif
387                 if(ret<=0)
388                 {
389                         if(ret==EAGAIN || ret==EINTR) continue;
390                         snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
391                                 "problems giving command \"%s\"",command);
392                         connection->error = MPD_ERROR_SENDING;
393                         return;
394                 }
395                 else {
396                         commandPtr+=ret;
397                         commandLen-=ret;
398                 }
400                 if(commandLen<=0) break;
401         }
403         if(commandLen>0) {
404                 perror("");
405                 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
406                         "timeout sending command \"%s\"",command);
407                 connection->error = MPD_ERROR_TIMEOUT;
408                 return;
409         }
411         if(!connection->commandList) connection->doneProcessing = 0;
412         else if(connection->commandList == COMMAND_LIST_OK) {
413                 connection->listOks++;
414         }
417 void mpd_getNextReturnElement(mpd_Connection * connection) {
418         char * output = NULL;
419         char * rt = NULL;
420         char * name = NULL;
421         char * value = NULL;
422         fd_set fds;
423         struct timeval tv;
424         char * tok = NULL;
425         int readed;
426         char * bufferCheck = NULL;
427         int err;
429         if(connection->returnElement) mpd_freeReturnElement(connection->returnElement);
430         connection->returnElement = NULL;
432         if(connection->doneProcessing || (connection->listOks &&
433                         connection->doneListOk)) 
434         {
435                 strcpy(connection->errorStr,"already done processing current command");
436                 connection->error = 1;
437                 return;
438         }
440         bufferCheck = connection->buffer+connection->bufstart;
441         while(connection->bufstart>=connection->buflen || 
442                         !(rt = strchr(bufferCheck,'\n'))) {
443                 if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
444                         memmove(connection->buffer,
445                                         connection->buffer+
446                                         connection->bufstart,
447                                         connection->buflen-
448                                         connection->bufstart+1);
449                         connection->buflen-=connection->bufstart;
450                         connection->bufstart = 0;
451                 }
452                 if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
453                         strcpy(connection->errorStr,"buffer overrun");
454                         connection->error = MPD_ERROR_BUFFEROVERRUN;
455                         connection->doneProcessing = 1;
456                         connection->doneListOk = 0;
457                         return;
458                 }
459                 bufferCheck = connection->buffer+connection->buflen;
460                 tv.tv_sec = connection->timeout.tv_sec;
461                 tv.tv_usec = connection->timeout.tv_usec;
462                 FD_ZERO(&fds);
463                 FD_SET(connection->sock,&fds);
464                 if((err = select(connection->sock+1,&fds,NULL,NULL,&tv) == 1)) {
465                         readed = recv(connection->sock,
466                                 connection->buffer+connection->buflen,
467                                 MPD_BUFFER_MAX_LENGTH-connection->buflen,
468 #ifdef WIN32
469                                 ioctlsocket(connection->sock, 
470                                             commandLen, 
471                                             commandPtr));
472 #endif
473 #ifndef WIN32
474                                 MSG_DONTWAIT);
475 #endif
476                         if(readed<0 && (errno==EAGAIN || errno==EINTR)) {
477                                 continue;
478                         }
479                         if(readed<=0) {
480                                 strcpy(connection->errorStr,"connection"
481                                         " closed");
482                                 connection->error = MPD_ERROR_CONNCLOSED;
483                                 connection->doneProcessing = 1;
484                                 connection->doneListOk = 0;
485                                 return;
486                         }
487                         connection->buflen+=readed;
488                         connection->buffer[connection->buflen] = '\0';
489                 }
490                 else if(err<0 && errno==EINTR) continue;
491                 else {
492                         strcpy(connection->errorStr,"connection timeout");
493                         connection->error = MPD_ERROR_TIMEOUT;
494                         connection->doneProcessing = 1;
495                         connection->doneListOk = 0;
496                         return;
497                 }
498         }
500         *rt = '\0';
501         output = connection->buffer+connection->bufstart;
502         connection->bufstart = rt - connection->buffer + 1;
504         if(strcmp(output,"OK")==0) {
505                 if(connection->listOks > 0) {
506                         strcpy(connection->errorStr, "expected more list_OK's");
507                         connection->error = 1;
508                 }
509                 connection->listOks = 0;
510                 connection->doneProcessing = 1;
511                 connection->doneListOk = 0;
512                 return;
513         }
515         if(strcmp(output, "list_OK") == 0) {
516                 if(!connection->listOks) {
517                         strcpy(connection->errorStr, 
518                                         "got an unexpected list_OK");
519                         connection->error = 1;
520                 }
521                 else {
522                         connection->doneListOk = 1;
523                         connection->listOks--;
524                 }
525                 return;
526         }
528         if(strncmp(output,"ACK",strlen("ACK"))==0) {
529                 char * test;
530                 char * needle;
531                 int val;
532         
533                 strcpy(connection->errorStr, output);
534                 connection->error = MPD_ERROR_ACK;
535                 connection->errorCode = MPD_ACK_ERROR_UNK;
536                 connection->errorAt = MPD_ERROR_AT_UNK;
537                 connection->doneProcessing = 1;
538                 connection->doneListOk = 0;
540                 needle = strchr(output, '[');
541                 if(!needle) return;
542                 val = strtol(needle+1, &test, 10);
543                 if(*test != '@') return;
544                 connection->errorCode = val;
545                 val = strtol(test+1, &test, 10);
546                 if(*test != ']') return;
547                 connection->errorAt = val;
548                 return;
549         }
551         name = strtok_r(output,":",&tok);
552         if(name && (value = strtok_r(NULL,"",&tok)) && value[0]==' ') {
553                 connection->returnElement = mpd_newReturnElement(name,&(value[1]));
554         }
555         else {
556                 if(!name || !value) {
557                         snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
558                                         "error parsing: %s",output);
559                 }
560                 else {
561                         snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
562                                         "error parsing: %s:%s",name,value);
563                 }
564                 connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0';
565                 connection->error = 1;
566         }
569 void mpd_finishCommand(mpd_Connection * connection) {
570         while(!connection->doneProcessing) {
571                 if(connection->doneListOk) connection->doneListOk = 0;
572                 mpd_getNextReturnElement(connection);
573         }
576 void mpd_finishListOkCommand(mpd_Connection * connection) {
577         while(!connection->doneProcessing && connection->listOks && 
578                         !connection->doneListOk ) 
579         {
580                 mpd_getNextReturnElement(connection);
581         }
584 int mpd_nextListOkCommand(mpd_Connection * connection) {
585         mpd_finishListOkCommand(connection);
586         if(!connection->doneProcessing) connection->doneListOk = 0;
587         if(connection->listOks == 0 || connection->doneProcessing) return -1;
588         return 0;
591 void mpd_sendStatusCommand(mpd_Connection * connection) {
592         mpd_executeCommand(connection,"status\n");
595 mpd_Status * mpd_getStatus(mpd_Connection * connection) {
596         mpd_Status * status;
598         /*mpd_executeCommand(connection,"status\n");
599                 
600         if(connection->error) return NULL;*/
602         if(connection->doneProcessing || (connection->listOks && 
603                         connection->doneListOk))
604         {
605                 return NULL;
606         }
608         if(!connection->returnElement) mpd_getNextReturnElement(connection);
610         status = malloc(sizeof(mpd_Status));
611         status->volume = -1;
612         status->repeat = 0;
613         status->random = 0;
614         status->playlist = -1;
615         status->playlistLength = -1;
616         status->state = -1;
617         status->song = 0;
618         status->elapsedTime = 0;
619         status->totalTime = 0;
620         status->bitRate = 0;
621         status->sampleRate = 0;
622         status->bits = 0;
623         status->channels = 0;
624         status->crossfade = -1;
625         status->error = NULL;
626         status->updatingDb = 0;
628         if(connection->error) {
629                 free(status);
630                 return NULL;
631         }
632         while(connection->returnElement) {
633                 mpd_ReturnElement * re = connection->returnElement;
634                 if(strcmp(re->name,"volume")==0) {
635                         status->volume = atoi(re->value);
636                 }
637                 else if(strcmp(re->name,"repeat")==0) {
638                         status->repeat = atoi(re->value);
639                 }
640                 else if(strcmp(re->name,"random")==0) {
641                         status->random = atoi(re->value);
642                 }
643                 else if(strcmp(re->name,"playlist")==0) {
644                         status->playlist = strtol(re->value,NULL,10);
645                 }
646                 else if(strcmp(re->name,"playlistlength")==0) {
647                         status->playlistLength = atoi(re->value);
648                 }
649                 else if(strcmp(re->name,"bitrate")==0) {
650                         status->bitRate = atoi(re->value);
651                 }
652                 else if(strcmp(re->name,"state")==0) {
653                         if(strcmp(re->value,"play")==0) {
654                                 status->state = MPD_STATUS_STATE_PLAY;
655                         }
656                         else if(strcmp(re->value,"stop")==0) {
657                                 status->state = MPD_STATUS_STATE_STOP;
658                         }
659                         else if(strcmp(re->value,"pause")==0) {
660                                 status->state = MPD_STATUS_STATE_PAUSE;
661                         }
662                         else {
663                                 status->state = MPD_STATUS_STATE_UNKNOWN;
664                         }
665                 }
666                 else if(strcmp(re->name,"song")==0) {
667                         status->song = atoi(re->value);
668                 }
669                 else if(strcmp(re->name,"songid")==0) {
670                         status->songid = atoi(re->value);
671                 }
672                 else if(strcmp(re->name,"time")==0) {
673                         char * tok;
674                         char * copy;
675                         char * temp;
676                         copy = strdup(re->value);
677                         temp = strtok_r(copy,":",&tok);
678                         if(temp) {
679                                 status->elapsedTime = atoi(temp);
680                                 temp = strtok_r(NULL,"",&tok);
681                                 if(temp) status->totalTime = atoi(temp);
682                         }
683                         free(copy);
684                 }
685                 else if(strcmp(re->name,"error")==0) {
686                         status->error = strdup(re->value);
687                 }
688                 else if(strcmp(re->name,"xfade")==0) {
689                         status->crossfade = atoi(re->value);
690                 }
691                 else if(strcmp(re->name,"updating_db")==0) {
692                         status->updatingDb = atoi(re->value);
693                 }
694                 else if(strcmp(re->name,"audio")==0) {
695                         char * tok;
696                         char * copy;
697                         char * temp;
698                         copy = strdup(re->value);
699                         temp = strtok_r(copy,":",&tok);
700                         if(temp) {
701                                 status->sampleRate = atoi(temp);
702                                 temp = strtok_r(NULL,":",&tok);
703                                 if(temp) {
704                                         status->bits = atoi(temp);
705                                         temp = strtok_r(NULL,"",&tok);
706                                         if(temp) status->channels = atoi(temp);
707                                 }
708                         }
709                         free(copy);
710                 }
712                 mpd_getNextReturnElement(connection);
713                 if(connection->error) {
714                         free(status);
715                         return NULL;
716                 }
717         }
719         if(connection->error) {
720                 free(status);
721                 return NULL;
722         }
723         else if(status->state<0) {
724                 strcpy(connection->errorStr,"state not found");
725                 connection->error = 1;
726                 free(status);
727                 return NULL;
728         }
730         return status;
733 void mpd_freeStatus(mpd_Status * status) {
734         if(status->error) free(status->error);
735         free(status);
738 void mpd_sendStatsCommand(mpd_Connection * connection) {
739         mpd_executeCommand(connection,"stats\n");
742 mpd_Stats * mpd_getStats(mpd_Connection * connection) {
743         mpd_Stats * stats;
745         /*mpd_executeCommand(connection,"stats\n");
746                 
747         if(connection->error) return NULL;*/
749         if(connection->doneProcessing || (connection->listOks && 
750                         connection->doneListOk))
751         {
752                 return NULL;
753         }
755         if(!connection->returnElement) mpd_getNextReturnElement(connection);
757         stats = malloc(sizeof(mpd_Stats));
758         stats->numberOfArtists = 0;
759         stats->numberOfAlbums = 0;
760         stats->numberOfSongs = 0;
761         stats->uptime = 0;
762         stats->dbUpdateTime = 0;
763         stats->playTime = 0;
764         stats->dbPlayTime = 0;
766         if(connection->error) {
767                 free(stats);
768                 return NULL;
769         }
770         while(connection->returnElement) {
771                 mpd_ReturnElement * re = connection->returnElement;
772                 if(strcmp(re->name,"artists")==0) {
773                         stats->numberOfArtists = atoi(re->value);
774                 }
775                 else if(strcmp(re->name,"albums")==0) {
776                         stats->numberOfAlbums = atoi(re->value);
777                 }
778                 else if(strcmp(re->name,"songs")==0) {
779                         stats->numberOfSongs = atoi(re->value);
780                 }
781                 else if(strcmp(re->name,"uptime")==0) {
782                         stats->uptime = strtol(re->value,NULL,10);
783                 }
784                 else if(strcmp(re->name,"db_update")==0) {
785                         stats->dbUpdateTime = strtol(re->value,NULL,10);
786                 }
787                 else if(strcmp(re->name,"playtime")==0) {
788                         stats->playTime = strtol(re->value,NULL,10);
789                 }
790                 else if(strcmp(re->name,"db_playtime")==0) {
791                         stats->dbPlayTime = strtol(re->value,NULL,10);
792                 }
794                 mpd_getNextReturnElement(connection);
795                 if(connection->error) {
796                         free(stats);
797                         return NULL;
798                 }
799         }
801         if(connection->error) {
802                 free(stats);
803                 return NULL;
804         }
806         return stats;
809 void mpd_freeStats(mpd_Stats * stats) {
810         free(stats);
813 void mpd_initSong(mpd_Song * song) {
814         song->file = NULL;
815         song->artist = NULL;
816         song->album = NULL;
817         song->track = NULL;
818         song->title = NULL;
819         song->name = NULL;
820         song->date = NULL;
821         /* added by Qball */
822         song->genre = NULL;
823         song->composer = NULL;
825         song->time = MPD_SONG_NO_TIME;
826         song->pos = MPD_SONG_NO_NUM;
827         song->id = MPD_SONG_NO_ID;
830 void mpd_finishSong(mpd_Song * song) {
831         if(song->file) free(song->file);
832         if(song->artist) free(song->artist);
833         if(song->album) free(song->album);
834         if(song->title) free(song->title);
835         if(song->track) free(song->track);
836         if(song->name) free(song->name);
837         if(song->date) free(song->date);
838         if(song->genre) free(song->genre);
839         if(song->composer) free(song->composer);
842 mpd_Song * mpd_newSong() {
843         mpd_Song * ret = malloc(sizeof(mpd_Song));
845         mpd_initSong(ret);
847         return ret;
850 void mpd_freeSong(mpd_Song * song) {
851         mpd_finishSong(song);
852         free(song);
855 mpd_Song * mpd_songDup(mpd_Song * song) {
856         mpd_Song * ret = mpd_newSong();
858         if(song->file) ret->file = strdup(song->file);
859         if(song->artist) ret->artist = strdup(song->artist);
860         if(song->album) ret->album = strdup(song->album);
861         if(song->title) ret->title = strdup(song->title);
862         if(song->track) ret->track = strdup(song->track);
863         if(song->name) ret->name = strdup(song->name);
864         if(song->date) ret->date = strdup(song->date);
865         if(song->genre) ret->genre= strdup(song->genre);
866         if(song->composer) ret->composer= strdup(song->composer);
867         ret->time = song->time;
868         ret->pos = song->pos;
869         ret->id = song->id;
871         return ret;
874 void mpd_initDirectory(mpd_Directory * directory) {
875         directory->path = NULL;
878 void mpd_finishDirectory(mpd_Directory * directory) {
879         if(directory->path) free(directory->path);
882 mpd_Directory * mpd_newDirectory () {
883         mpd_Directory * directory = malloc(sizeof(mpd_Directory));;
885         mpd_initDirectory(directory);
886         
887         return directory;
890 void mpd_freeDirectory(mpd_Directory * directory) {
891         mpd_finishDirectory(directory);
893         free(directory);
896 mpd_Directory * mpd_directoryDup(mpd_Directory * directory) {
897         mpd_Directory * ret = mpd_newDirectory();
899         if(directory->path) ret->path = strdup(directory->path);
901         return ret;
904 void mpd_initPlaylistFile(mpd_PlaylistFile * playlist) {
905         playlist->path = NULL;
908 void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist) {
909         if(playlist->path) free(playlist->path);
912 mpd_PlaylistFile * mpd_newPlaylistFile() {
913         mpd_PlaylistFile * playlist = malloc(sizeof(mpd_PlaylistFile));
915         mpd_initPlaylistFile(playlist);
917         return playlist;
920 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist) {
921         mpd_finishPlaylistFile(playlist);
922         free(playlist);
925 mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist) {
926         mpd_PlaylistFile * ret = mpd_newPlaylistFile();
928         if(playlist->path) ret->path = strdup(playlist->path);
930         return ret;
933 void mpd_initInfoEntity(mpd_InfoEntity * entity) {
934         entity->info.directory = NULL;
935
937 void mpd_finishInfoEntity(mpd_InfoEntity * entity) {
938         if(entity->info.directory) {
939                 if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
940                         mpd_freeDirectory(entity->info.directory);
941                 }
942                 else if(entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
943                         mpd_freeSong(entity->info.song);
944                 }
945                 else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
946                         mpd_freePlaylistFile(entity->info.playlistFile);
947                 }
948         }
951 mpd_InfoEntity * mpd_newInfoEntity() {
952         mpd_InfoEntity * entity = malloc(sizeof(mpd_InfoEntity));
953         
954         mpd_initInfoEntity(entity);
956         return entity;
959 void mpd_freeInfoEntity(mpd_InfoEntity * entity) {
960         mpd_finishInfoEntity(entity);
961         free(entity);
964 void mpd_sendInfoCommand(mpd_Connection * connection, char * command) {
965         mpd_executeCommand(connection,command);
968 mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) {
969         mpd_InfoEntity * entity = NULL;
971         if(connection->doneProcessing || (connection->listOks && 
972                         connection->doneListOk))
973         {
974                 return NULL;
975         }
977         if(!connection->returnElement) mpd_getNextReturnElement(connection);
979         if(connection->returnElement) { 
980                 if(strcmp(connection->returnElement->name,"file")==0) {
981                         entity = mpd_newInfoEntity();
982                         entity->type = MPD_INFO_ENTITY_TYPE_SONG;
983                         entity->info.song = mpd_newSong();
984                         entity->info.song->file = 
985                                 strdup(connection->returnElement->value);
986                 }
987                 else if(strcmp(connection->returnElement->name,
988                                         "directory")==0) {
989                         entity = mpd_newInfoEntity();
990                         entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
991                         entity->info.directory = mpd_newDirectory();
992                         entity->info.directory->path = 
993                                 strdup(connection->returnElement->value);
994                 }
995                 else if(strcmp(connection->returnElement->name,"playlist")==0) {
996                         entity = mpd_newInfoEntity();
997                         entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
998                         entity->info.playlistFile = mpd_newPlaylistFile();
999                         entity->info.playlistFile->path = 
1000                                 strdup(connection->returnElement->value);
1001                 }
1002                 else {
1003                         connection->error = 1;
1004                         strcpy(connection->errorStr,"problem parsing song info");
1005                         return NULL;
1006                 }
1007         }
1008         else return NULL;
1010         mpd_getNextReturnElement(connection);
1011         while(connection->returnElement) {
1012                 mpd_ReturnElement * re = connection->returnElement;
1014                 if(strcmp(re->name,"file")==0) return entity;
1015                 else if(strcmp(re->name,"directory")==0) return entity;
1016                 else if(strcmp(re->name,"playlist")==0) return entity;
1018                 if(entity->type == MPD_INFO_ENTITY_TYPE_SONG && 
1019                                 strlen(re->value)) {
1020                         if(!entity->info.song->artist &&
1021                                         strcmp(re->name,"Artist")==0) {
1022                                 entity->info.song->artist = strdup(re->value);
1023                         }
1024                         else if(!entity->info.song->album &&
1025                                         strcmp(re->name,"Album")==0) {
1026                                 entity->info.song->album = strdup(re->value);
1027                         }
1028                         else if(!entity->info.song->title &&
1029                                         strcmp(re->name,"Title")==0) {
1030                                 entity->info.song->title = strdup(re->value);
1031                         }
1032                         else if(!entity->info.song->track &&
1033                                         strcmp(re->name,"Track")==0) {
1034                                 entity->info.song->track = strdup(re->value);
1035                         }
1036                         else if(!entity->info.song->name &&
1037                                         strcmp(re->name,"Name")==0) {
1038                                 entity->info.song->name = strdup(re->value);
1039                         }
1040                         else if(entity->info.song->time==MPD_SONG_NO_TIME &&
1041                                         strcmp(re->name,"Time")==0) {
1042                                 entity->info.song->time = atoi(re->value);
1043                         }
1044                         else if(entity->info.song->pos==MPD_SONG_NO_NUM &&
1045                                         strcmp(re->name,"Pos")==0) {
1046                                 entity->info.song->pos = atoi(re->value);
1047                         }
1048                         else if(entity->info.song->id==MPD_SONG_NO_ID &&
1049                                         strcmp(re->name,"Id")==0) {
1050                                 entity->info.song->id = atoi(re->value);
1051                         }
1052                         else if(!entity->info.song->date &&
1053                                         strcmp(re->name, "Date") == 0) {
1054                                 entity->info.song->date = strdup(re->value);
1055                         }
1056                         else if(!entity->info.song->genre &&
1057                                         strcmp(re->name, "Genre") == 0) {
1058                                 entity->info.song->genre = strdup(re->value);
1059                         }
1060                         else if(!entity->info.song->composer &&
1061                                         strcmp(re->name, "Composer") == 0) {
1062                                 entity->info.song->composer = strdup(re->value);
1063                         }                                                                       
1064                         
1065                 }
1066                 else if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1067                 }
1068                 else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1069                 }
1071                 mpd_getNextReturnElement(connection);
1072         }
1074         return entity;
1077 char * mpd_getNextReturnElementNamed(mpd_Connection * connection, 
1078                 const char * name) 
1080         if(connection->doneProcessing || (connection->listOks && 
1081                         connection->doneListOk)) 
1082         {
1083                 return NULL;
1084         }
1086         mpd_getNextReturnElement(connection);
1087         while(connection->returnElement) {
1088                 mpd_ReturnElement * re = connection->returnElement;
1090                 if(strcmp(re->name,name)==0) return strdup(re->value);
1091                 mpd_getNextReturnElement(connection);
1092         }
1094         return NULL;
1097 char * mpd_getNextTag(mpd_Connection * connection,int table) {
1098         if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
1099         {
1100                 return mpd_getNextReturnElementNamed(connection,mpdTagItemKeys[table]);
1101         }
1102         return NULL;
1104 char * mpd_getNextArtist(mpd_Connection * connection) {
1105         return mpd_getNextReturnElementNamed(connection,"Artist");
1108 char * mpd_getNextAlbum(mpd_Connection * connection) {
1109         return mpd_getNextReturnElementNamed(connection,"Album");
1112 void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos) {
1113         char * string = malloc(strlen("playlistinfo")+25);
1114         sprintf(string,"playlistinfo \"%i\"\n",songPos);
1115         mpd_sendInfoCommand(connection,string);
1116         free(string);
1119 void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id) {
1120         char * string = malloc(strlen("playlistid")+25);
1121         sprintf(string, "playlistid \"%i\"\n", id);
1122         mpd_sendInfoCommand(connection, string);
1123         free(string);
1126 void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist) {
1127         char * string = malloc(strlen("plchanges")+25);
1128         sprintf(string,"plchanges \"%lld\"\n",playlist);
1129         mpd_sendInfoCommand(connection,string);
1130         free(string);
1133 void mpd_sendListallCommand(mpd_Connection * connection, const char * dir) {
1134         char * sDir = mpd_sanitizeArg(dir);
1135         char * string = malloc(strlen("listall")+strlen(sDir)+5);
1136         sprintf(string,"listall \"%s\"\n",sDir);
1137         mpd_sendInfoCommand(connection,string);
1138         free(string);
1139         free(sDir);
1142 void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir) {
1143         char * sDir = mpd_sanitizeArg(dir);
1144         char * string = malloc(strlen("listallinfo")+strlen(sDir)+5);
1145         sprintf(string,"listallinfo \"%s\"\n",sDir);
1146         mpd_sendInfoCommand(connection,string);
1147         free(string);
1148         free(sDir);
1151 void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir) {
1152         char * sDir = mpd_sanitizeArg(dir);
1153         char * string = malloc(strlen("lsinfo")+strlen(sDir)+5);
1154         sprintf(string,"lsinfo \"%s\"\n",sDir);
1155         mpd_sendInfoCommand(connection,string);
1156         free(string);
1157         free(sDir);
1160 void mpd_sendCurrentSongCommand(mpd_Connection * connection) {
1161         mpd_executeCommand(connection,"currentsong\n");
1164 void mpd_sendSearchCommand(mpd_Connection * connection, int table, 
1165                 const char * str) 
1167         char st[10];
1168         char * string;
1169         char * sanitStr = mpd_sanitizeArg(str);
1170         if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
1171         else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
1172         else if(table == MPD_TABLE_TITLE) strcpy(st,"title");
1173         else if(table == MPD_TABLE_FILENAME) strcpy(st,"filename");
1174         else {
1175                 connection->error = 1;
1176                 strcpy(connection->errorStr,"unknown table for search");
1177                 return;
1178         }
1179         string = malloc(strlen("search")+strlen(sanitStr)+strlen(st)+6);
1180         sprintf(string,"search %s \"%s\"\n",st,sanitStr);
1181         mpd_sendInfoCommand(connection,string);
1182         free(string);
1183         free(sanitStr);
1185 void mpd_sendSearchTagCommand(mpd_Connection *connection, ...)
1187         va_list arglist;
1188         va_start(arglist, connection);
1189         mpd_sendVSearchTagCommand(connection, arglist);
1190         va_end(arglist);
1193 void mpd_sendVSearchTagCommand(mpd_Connection * connection, va_list arglist) 
1195         char *st, *str;
1196         char * string=NULL;
1197         int table;
1198         char * sanitStr;
1199         string = realloc(string,strlen("search")+1);
1200         strcpy(string, "search");
1201         while((table = va_arg(arglist, int)) != -1)
1202         {
1203                 if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
1204                 {
1205                         st = mpdTagItemKeys[table];
1206                         str = va_arg(arglist,char *);
1207                         sanitStr = mpd_sanitizeArg(str);
1208                         string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+6);
1209                         sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
1210                         free(sanitStr);
1211                 }       
1212                 else {
1213                         connection->error = 1;
1214                         sprintf(connection->errorStr,"unknown table for search %i",table);
1215                         va_end(arglist);
1216                         return;
1217                 }
1218         }
1219         /* set the last to '\n', should be sufficient space in the string for this */
1220         sprintf(string, "%s\n", string);
1221         mpd_sendInfoCommand(connection,string);
1222         free(string);
1226 void mpd_sendFindTagCommand(mpd_Connection *connection, ...)
1228         va_list arglist;
1229         va_start(arglist, connection);
1230         mpd_sendVFindTagCommand(connection, arglist);
1231         va_end(arglist);
1237 void mpd_sendVFindTagCommand(mpd_Connection * connection, va_list arglist) 
1239         char *st, *str;
1240         char * string=NULL;
1241         int table;
1242         char * sanitStr;
1243         string = realloc(string,strlen("find")+1);
1244         strcpy(string, "find");
1245         while((table = va_arg(arglist, int)) != -1)
1246         {
1247                 if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
1248                 {
1249                         st = mpdTagItemKeys[table];
1250                         str = va_arg(arglist,char *);
1251                         sanitStr = mpd_sanitizeArg(str);
1252                         string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+6);
1253                         sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
1254                         free(sanitStr);
1255                 }       
1256                 else {
1257                         connection->error = 1;
1258                         sprintf(connection->errorStr,"unknown table for find %i",table);
1259                         va_end(arglist);
1260                         return;
1261                 }
1262         }
1263         /* set the last to '\n', should be sufficient space in the string for this */
1264         sprintf(string, "%s\n", string);
1265         mpd_sendInfoCommand(connection,string);
1266         free(string);
1269 void mpd_sendFindCommand(mpd_Connection * connection, int table, 
1270                 const char * str) 
1272         char st[10];
1273         char * string;
1274         char * sanitStr = mpd_sanitizeArg(str);
1275         if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
1276         else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
1277         else if(table == MPD_TABLE_TITLE) strcpy(st,"title");
1278         else {
1279                 connection->error = 1;
1280                 strcpy(connection->errorStr,"unknown table for find");
1281                 return;
1282         }
1283         string = malloc(strlen("find")+strlen(sanitStr)+strlen(st)+6);
1284         sprintf(string,"find %s \"%s\"\n",st,sanitStr);
1285         mpd_sendInfoCommand(connection,string);
1286         free(string);
1287         free(sanitStr);
1290 void mpd_sendListCommand(mpd_Connection * connection, int table, 
1291                 const char * arg1) 
1293         char st[10];
1294         char * string;
1295         if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
1296         else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
1297         else {
1298                 connection->error = 1;
1299                 strcpy(connection->errorStr,"unknown table for list");
1300                 return;
1301         }
1302         if(arg1) {
1303                 char * sanitArg1 = mpd_sanitizeArg(arg1);
1304                 string = malloc(strlen("list")+strlen(sanitArg1)+strlen(st)+6);
1305                 sprintf(string,"list %s \"%s\"\n",st,sanitArg1);
1306                 free(sanitArg1);
1307         }
1308         else {
1309                 string = malloc(strlen("list")+strlen(st)+3);
1310                 sprintf(string,"list %s\n",st);
1311         }
1312         mpd_sendInfoCommand(connection,string);
1313         free(string);
1316 void mpd_sendListTagCommand(mpd_Connection *connection, int ret_table, ...)
1318         va_list arglist;
1319         va_start(arglist, ret_table);
1320         mpd_sendVListTagCommand(connection, ret_table, arglist);
1321         va_end(arglist);
1323 void mpd_sendVListTagCommand(mpd_Connection * connection,int ret_table, va_list arglist) 
1325         char *st, *str;
1326         char * string=NULL;
1327         int table;
1328         char * sanitStr;
1329         if(ret_table < 0 && ret_table >= MPD_TAG_NUM_OF_ITEM_TYPES)
1330         {
1331                 connection->error = 1;
1332                 sprintf(connection->errorStr,"unknown ret_table for search %i",ret_table);
1333                 return;
1334         }
1336         string = realloc(string,strlen("list")+3+strlen(mpdTagItemKeys[ret_table]));
1337         sprintf(string, "list %s",mpdTagItemKeys[ret_table]);
1338         while((table = va_arg(arglist, int)) != -1)
1339         {
1340                 if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
1341                 {
1342                         st = mpdTagItemKeys[table];
1343                         str = va_arg(arglist,char *);
1344                         sanitStr = mpd_sanitizeArg(str);
1345                         string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+7);
1346                         sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
1347                         free(sanitStr);
1348                 }       
1349                 else {
1350                         connection->error = 1;
1351                         sprintf(connection->errorStr,"unknown table for search %i",table);
1352                         va_end(arglist);
1353                         return;
1354                 }
1355         }
1356         /* set the last to '\n', should be sufficient space in the string for this */
1357         sprintf(string,"%s\n", string);
1358         mpd_sendInfoCommand(connection,string);
1359         free(string);
1363 void mpd_sendAddCommand(mpd_Connection * connection, const char * file) {
1364         char * sFile = mpd_sanitizeArg(file);
1365         char * string = malloc(strlen("add")+strlen(sFile)+5);
1366         sprintf(string,"add \"%s\"\n",sFile);
1367         mpd_executeCommand(connection,string);
1368         free(string);
1369         free(sFile);
1372 void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos) {
1373         char * string = malloc(strlen("delete")+25);
1374         sprintf(string,"delete \"%i\"\n",songPos);
1375         mpd_sendInfoCommand(connection,string);
1376         free(string);
1379 void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id) {
1380         char * string = malloc(strlen("deleteid")+25);
1381         sprintf(string, "deleteid \"%i\"\n", id);
1382         mpd_sendInfoCommand(connection,string);
1383         free(string);
1386 void mpd_sendSaveCommand(mpd_Connection * connection, const char * name) {
1387         char * sName = mpd_sanitizeArg(name);
1388         char * string = malloc(strlen("save")+strlen(sName)+5);
1389         sprintf(string,"save \"%s\"\n",sName);
1390         mpd_executeCommand(connection,string);
1391         free(string);
1392         free(sName);
1395 void mpd_sendLoadCommand(mpd_Connection * connection, const char * name) {
1396         char * sName = mpd_sanitizeArg(name);
1397         char * string = malloc(strlen("load")+strlen(sName)+5);
1398         sprintf(string,"load \"%s\"\n",sName);
1399         mpd_executeCommand(connection,string);
1400         free(string);
1401         free(sName);
1404 void mpd_sendRmCommand(mpd_Connection * connection, const char * name) {
1405         char * sName = mpd_sanitizeArg(name);
1406         char * string = malloc(strlen("rm")+strlen(sName)+5);
1407         sprintf(string,"rm \"%s\"\n",sName);
1408         mpd_executeCommand(connection,string);
1409         free(string);
1410         free(sName);
1413 void mpd_sendShuffleCommand(mpd_Connection * connection) {
1414         mpd_executeCommand(connection,"shuffle\n");
1417 void mpd_sendClearCommand(mpd_Connection * connection) {
1418         mpd_executeCommand(connection,"clear\n");
1421 void mpd_sendPlayCommand(mpd_Connection * connection, int songPos) {
1422         char * string = malloc(strlen("play")+25);
1423         sprintf(string,"play \"%i\"\n",songPos);
1424         mpd_sendInfoCommand(connection,string);
1425         free(string);
1428 void mpd_sendPlayIdCommand(mpd_Connection * connection, int id) {
1429         char * string = malloc(strlen("playid")+25);
1430         sprintf(string,"playid \"%i\"\n",id);
1431         mpd_sendInfoCommand(connection,string);
1432         free(string);
1435 void mpd_sendStopCommand(mpd_Connection * connection) {
1436         mpd_executeCommand(connection,"stop\n");
1439 void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode) {
1440         char * string = malloc(strlen("pause")+25);
1441         sprintf(string,"pause \"%i\"\n",pauseMode);
1442         mpd_executeCommand(connection,string);
1443         free(string);
1446 void mpd_sendNextCommand(mpd_Connection * connection) {
1447         mpd_executeCommand(connection,"next\n");
1450 void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to) {
1451         char * string = malloc(strlen("move")+25);
1452         sprintf(string,"move \"%i\" \"%i\"\n",from,to);
1453         mpd_sendInfoCommand(connection,string);
1454         free(string);
1457 void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to) {
1458         char * string = malloc(strlen("moveid")+25);
1459         sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
1460         mpd_sendInfoCommand(connection,string);
1461         free(string);
1464 void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2) {
1465         char * string = malloc(strlen("swap")+25);
1466         sprintf(string,"swap \"%i\" \"%i\"\n",song1,song2);
1467         mpd_sendInfoCommand(connection,string);
1468         free(string);
1471 void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2) {
1472         char * string = malloc(strlen("swapid")+25);
1473         sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
1474         mpd_sendInfoCommand(connection,string);
1475         free(string);
1478 void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time) {
1479         char * string = malloc(strlen("seek")+25);
1480         sprintf(string,"seek \"%i\" \"%i\"\n",song,time);
1481         mpd_sendInfoCommand(connection,string);
1482         free(string);
1485 void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time) {
1486         char * string = malloc(strlen("seekid")+25);
1487         sprintf(string,"seekid \"%i\" \"%i\"\n",id,time);
1488         mpd_sendInfoCommand(connection,string);
1489         free(string);
1492 void mpd_sendUpdateCommand(mpd_Connection * connection, char * path) {
1493         char * sPath = mpd_sanitizeArg(path);
1494         char * string = malloc(strlen("update")+strlen(sPath)+5);
1495         sprintf(string,"update \"%s\"\n",sPath);
1496         mpd_sendInfoCommand(connection,string);
1497         free(string);
1498         free(sPath);
1501 int mpd_getUpdateId(mpd_Connection * connection) {
1502         char * jobid;
1503         int ret = 0;
1505         jobid = mpd_getNextReturnElementNamed(connection,"updating_db");
1506         if(jobid) {
1507                 ret = atoi(jobid);
1508                 free(jobid);
1509         }
1511         return ret;
1514 void mpd_sendPrevCommand(mpd_Connection * connection) {
1515         mpd_executeCommand(connection,"previous\n");
1518 void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode) {
1519         char * string = malloc(strlen("repeat")+25);
1520         sprintf(string,"repeat \"%i\"\n",repeatMode);
1521         mpd_executeCommand(connection,string);
1522         free(string);
1525 void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode) {
1526         char * string = malloc(strlen("random")+25);
1527         sprintf(string,"random \"%i\"\n",randomMode);
1528         mpd_executeCommand(connection,string);
1529         free(string);
1532 void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange) {
1533         char * string = malloc(strlen("setvol")+25);
1534         sprintf(string,"setvol \"%i\"\n",volumeChange);
1535         mpd_executeCommand(connection,string);
1536         free(string);
1539 void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange) {
1540         char * string = malloc(strlen("volume")+25);
1541         sprintf(string,"volume \"%i\"\n",volumeChange);
1542         mpd_executeCommand(connection,string);
1543         free(string);
1546 void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds) {
1547         char * string = malloc(strlen("crossfade")+25);
1548         sprintf(string,"crossfade \"%i\"\n",seconds);
1549         mpd_executeCommand(connection,string);
1550         free(string);
1553 void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass) {
1554         char * sPass = mpd_sanitizeArg(pass);
1555         char * string = malloc(strlen("password")+strlen(sPass)+5);
1556         sprintf(string,"password \"%s\"\n",sPass);
1557         mpd_executeCommand(connection,string);
1558         free(string);
1559         free(sPass);
1562 void mpd_sendCommandListBegin(mpd_Connection * connection) {
1563         if(connection->commandList) {
1564                 strcpy(connection->errorStr,"already in command list mode");
1565                 connection->error = 1;
1566                 return;
1567         }
1568         connection->commandList = COMMAND_LIST;
1569         mpd_executeCommand(connection,"command_list_begin\n");
1572 void mpd_sendCommandListOkBegin(mpd_Connection * connection) {
1573         if(connection->commandList) {
1574                 strcpy(connection->errorStr,"already in command list mode");
1575                 connection->error = 1;
1576                 return;
1577         }
1578         connection->commandList = COMMAND_LIST_OK;
1579         mpd_executeCommand(connection,"command_list_ok_begin\n");
1580         connection->listOks = 0;
1583 void mpd_sendCommandListEnd(mpd_Connection * connection) {
1584         if(!connection->commandList) {
1585                 strcpy(connection->errorStr,"not in command list mode");
1586                 connection->error = 1;
1587                 return;
1588         }
1589         connection->commandList = 0;
1590         mpd_executeCommand(connection,"command_list_end\n");
1593 void mpd_sendOutputsCommand(mpd_Connection * connection) {
1594         mpd_executeCommand(connection,"outputs\n");
1597 mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
1598         mpd_OutputEntity * output = NULL;
1600         if(connection->doneProcessing || (connection->listOks &&
1601                                 connection->doneListOk))
1602         {
1603                 return NULL;
1604         }
1606         if(connection->error) return NULL;
1608         output = malloc(sizeof(mpd_OutputEntity));
1609         output->id = -10;
1610         output->name = NULL;
1611         output->enabled = 0;
1613         if(!connection->returnElement) mpd_getNextReturnElement(connection);
1615         while(connection->returnElement) {
1616                 mpd_ReturnElement * re = connection->returnElement;
1617                 if(strcmp(re->name,"outputid")==0) {
1618                         if(output!=NULL && output->id>=0) return output;
1619                         output->id = atoi(re->value);
1620                 }
1621                 else if(strcmp(re->name,"outputname")==0) {
1622                         output->name = strdup(re->value);
1623                 }
1624                 else if(strcmp(re->name,"outputenabled")==0) {
1625                         output->enabled = atoi(re->value);
1626                 }
1628                 mpd_getNextReturnElement(connection);
1629                 if(connection->error) {
1630                         free(output);
1631                         return NULL;
1632                 }
1634         }
1636         return output;
1639 void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId) {
1640         char * string = malloc(strlen("enableoutput")+25);
1641         sprintf(string,"enableoutput \"%i\"\n",outputId);
1642         mpd_executeCommand(connection,string);
1643         free(string);
1646 void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId) {
1647         char * string = malloc(strlen("disableoutput")+25);
1648         sprintf(string,"disableoutput \"%i\"\n",outputId);
1649         mpd_executeCommand(connection,string);
1650         free(string);
1653 void mpd_freeOutputElement(mpd_OutputEntity * output) {
1654         free(output->name);
1655         free(output);