a8bbabef7bd046a2b3bf0de1992c64e3764c9511
1 /* libmpdclient
2 (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
3 This project's homepage is: http://www.musicpd.org
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
9 - Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
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;
99 /*
100 unsigned int count = 0;
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;
123 }
125 mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
126 {
127 mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));
129 ret->name = (char *)strdup(name);
130 ret->value = (char *)strdup(value);
132 return ret;
133 }
135 void mpd_freeReturnElement(mpd_ReturnElement * re) {
136 free(re->name);
137 free(re->value);
138 free(re);
139 }
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);
145 }
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 }
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;
345 }
347 void mpd_clearError(mpd_Connection * connection) {
348 connection->error = 0;
349 connection->errorStr[0] = '\0';
350 }
352 void mpd_closeConnection(mpd_Connection * connection) {
353 close(connection->sock);
354 if(connection->returnElement) free(connection->returnElement);
355 free(connection);
356 }
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 }
415 }
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;
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 }
567 }
569 void mpd_finishCommand(mpd_Connection * connection) {
570 while(!connection->doneProcessing) {
571 if(connection->doneListOk) connection->doneListOk = 0;
572 mpd_getNextReturnElement(connection);
573 }
574 }
576 void mpd_finishListOkCommand(mpd_Connection * connection) {
577 while(!connection->doneProcessing && connection->listOks &&
578 !connection->doneListOk )
579 {
580 mpd_getNextReturnElement(connection);
581 }
582 }
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;
589 }
591 void mpd_sendStatusCommand(mpd_Connection * connection) {
592 mpd_executeCommand(connection,"status\n");
593 }
595 mpd_Status * mpd_getStatus(mpd_Connection * connection) {
596 mpd_Status * status;
598 /*mpd_executeCommand(connection,"status\n");
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;
731 }
733 void mpd_freeStatus(mpd_Status * status) {
734 if(status->error) free(status->error);
735 free(status);
736 }
738 void mpd_sendStatsCommand(mpd_Connection * connection) {
739 mpd_executeCommand(connection,"stats\n");
740 }
742 mpd_Stats * mpd_getStats(mpd_Connection * connection) {
743 mpd_Stats * stats;
745 /*mpd_executeCommand(connection,"stats\n");
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;
807 }
809 void mpd_freeStats(mpd_Stats * stats) {
810 free(stats);
811 }
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;
828 }
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);
840 }
842 mpd_Song * mpd_newSong() {
843 mpd_Song * ret = malloc(sizeof(mpd_Song));
845 mpd_initSong(ret);
847 return ret;
848 }
850 void mpd_freeSong(mpd_Song * song) {
851 mpd_finishSong(song);
852 free(song);
853 }
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;
872 }
874 void mpd_initDirectory(mpd_Directory * directory) {
875 directory->path = NULL;
876 }
878 void mpd_finishDirectory(mpd_Directory * directory) {
879 if(directory->path) free(directory->path);
880 }
882 mpd_Directory * mpd_newDirectory () {
883 mpd_Directory * directory = malloc(sizeof(mpd_Directory));;
885 mpd_initDirectory(directory);
887 return directory;
888 }
890 void mpd_freeDirectory(mpd_Directory * directory) {
891 mpd_finishDirectory(directory);
893 free(directory);
894 }
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;
902 }
904 void mpd_initPlaylistFile(mpd_PlaylistFile * playlist) {
905 playlist->path = NULL;
906 }
908 void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist) {
909 if(playlist->path) free(playlist->path);
910 }
912 mpd_PlaylistFile * mpd_newPlaylistFile() {
913 mpd_PlaylistFile * playlist = malloc(sizeof(mpd_PlaylistFile));
915 mpd_initPlaylistFile(playlist);
917 return playlist;
918 }
920 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist) {
921 mpd_finishPlaylistFile(playlist);
922 free(playlist);
923 }
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;
931 }
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 }
949 }
951 mpd_InfoEntity * mpd_newInfoEntity() {
952 mpd_InfoEntity * entity = malloc(sizeof(mpd_InfoEntity));
954 mpd_initInfoEntity(entity);
956 return entity;
957 }
959 void mpd_freeInfoEntity(mpd_InfoEntity * entity) {
960 mpd_finishInfoEntity(entity);
961 free(entity);
962 }
964 void mpd_sendInfoCommand(mpd_Connection * connection, char * command) {
965 mpd_executeCommand(connection,command);
966 }
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 }
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;
1075 }
1077 char * mpd_getNextReturnElementNamed(mpd_Connection * connection,
1078 const char * name)
1079 {
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;
1095 }
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;
1103 }
1104 char * mpd_getNextArtist(mpd_Connection * connection) {
1105 return mpd_getNextReturnElementNamed(connection,"Artist");
1106 }
1108 char * mpd_getNextAlbum(mpd_Connection * connection) {
1109 return mpd_getNextReturnElementNamed(connection,"Album");
1110 }
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);
1117 }
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);
1124 }
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);
1131 }
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);
1140 }
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);
1149 }
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);
1158 }
1160 void mpd_sendCurrentSongCommand(mpd_Connection * connection) {
1161 mpd_executeCommand(connection,"currentsong\n");
1162 }
1164 void mpd_sendSearchCommand(mpd_Connection * connection, int table,
1165 const char * str)
1166 {
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);
1184 }
1185 void mpd_sendSearchTagCommand(mpd_Connection *connection, ...)
1186 {
1187 va_list arglist;
1188 va_start(arglist, connection);
1189 mpd_sendVSearchTagCommand(connection, arglist);
1190 va_end(arglist);
1191 }
1193 void mpd_sendVSearchTagCommand(mpd_Connection * connection, va_list arglist)
1194 {
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);
1223 }
1226 void mpd_sendFindTagCommand(mpd_Connection *connection, ...)
1227 {
1228 va_list arglist;
1229 va_start(arglist, connection);
1230 mpd_sendVFindTagCommand(connection, arglist);
1231 va_end(arglist);
1232 }
1237 void mpd_sendVFindTagCommand(mpd_Connection * connection, va_list arglist)
1238 {
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);
1267 }
1269 void mpd_sendFindCommand(mpd_Connection * connection, int table,
1270 const char * str)
1271 {
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);
1288 }
1290 void mpd_sendListCommand(mpd_Connection * connection, int table,
1291 const char * arg1)
1292 {
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);
1314 }
1316 void mpd_sendListTagCommand(mpd_Connection *connection, int ret_table, ...)
1317 {
1318 va_list arglist;
1319 va_start(arglist, ret_table);
1320 mpd_sendVListTagCommand(connection, ret_table, arglist);
1321 va_end(arglist);
1322 }
1323 void mpd_sendVListTagCommand(mpd_Connection * connection,int ret_table, va_list arglist)
1324 {
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);
1360 }
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);
1370 }
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);
1377 }
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);
1384 }
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);
1393 }
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);
1402 }
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);
1411 }
1413 void mpd_sendShuffleCommand(mpd_Connection * connection) {
1414 mpd_executeCommand(connection,"shuffle\n");
1415 }
1417 void mpd_sendClearCommand(mpd_Connection * connection) {
1418 mpd_executeCommand(connection,"clear\n");
1419 }
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);
1426 }
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);
1433 }
1435 void mpd_sendStopCommand(mpd_Connection * connection) {
1436 mpd_executeCommand(connection,"stop\n");
1437 }
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);
1444 }
1446 void mpd_sendNextCommand(mpd_Connection * connection) {
1447 mpd_executeCommand(connection,"next\n");
1448 }
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);
1455 }
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);
1462 }
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);
1469 }
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);
1476 }
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);
1483 }
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);
1490 }
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);
1499 }
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;
1512 }
1514 void mpd_sendPrevCommand(mpd_Connection * connection) {
1515 mpd_executeCommand(connection,"previous\n");
1516 }
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);
1523 }
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);
1530 }
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);
1537 }
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);
1544 }
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);
1551 }
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);
1560 }
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");
1570 }
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;
1581 }
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");
1591 }
1593 void mpd_sendOutputsCommand(mpd_Connection * connection) {
1594 mpd_executeCommand(connection,"outputs\n");
1595 }
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;
1637 }
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);
1644 }
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);
1651 }
1653 void mpd_freeOutputElement(mpd_OutputEntity * output) {
1654 free(output->name);
1655 free(output);
1656 }