2 (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
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
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.
33 #include "libmpdclient.h"
37 #include <sys/types.h>
39 #include <sys/param.h>
47 # include <ws2tcpip.h>
50 # include <netinet/in.h>
51 # include <arpa/inet.h>
52 # include <sys/socket.h>
56 /* (bits+1)/3 (plus the sign character) */
57 #define INTLEN ((sizeof(int) * CHAR_BIT + 1) / 3 + 1)
58 #define LONGLONGLEN ((sizeof(long long) * CHAR_BIT + 1) / 3 + 1)
60 #define COMMAND_LIST 1
61 #define COMMAND_LIST_OK 2
70 # define MSG_DONTWAIT 0
74 # define SELECT_ERRNO_IGNORE (errno == WSAEINTR || errno == WSAEINPROGRESS)
75 # define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
77 # define SELECT_ERRNO_IGNORE (errno == EINTR)
78 # define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
79 # define winsock_dll_error(c) 0
80 # define closesocket(s) close(s)
81 # define WSACleanup() do { /* nothing */ } while (0)
85 static int winsock_dll_error(mpd_Connection *connection)
88 if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0 ||
89 LOBYTE(wsaData.wVersion) != 2 ||
90 HIBYTE(wsaData.wVersion) != 2 ) {
91 strcpy(connection->errorStr,
92 "Could not find usable WinSock DLL.");
93 connection->error = MPD_ERROR_SYSTEM;
99 static int do_connect_fail(mpd_Connection *connection,
100 const struct sockaddr *serv_addr, int addrlen)
102 int iMode = 1; /* 0 = blocking, else non-blocking */
103 ioctlsocket(connection->sock, FIONBIO, (u_long FAR*) &iMode);
104 return (connect(connection->sock,serv_addr,addrlen) == SOCKET_ERROR
105 && WSAGetLastError() != WSAEWOULDBLOCK);
107 #else /* !WIN32 (sane operating systems) */
108 static int do_connect_fail(mpd_Connection *connection,
109 const struct sockaddr *serv_addr, int addrlen)
111 int flags = fcntl(connection->sock, F_GETFL, 0);
112 fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
113 return (connect(connection->sock,serv_addr,addrlen)<0 &&
119 static int mpd_connect(mpd_Connection * connection, const char * host, int port,
123 char service[INTLEN+1];
124 struct addrinfo hints;
125 struct addrinfo *res = NULL;
126 struct addrinfo *addrinfo = NULL;
131 hints.ai_flags = AI_ADDRCONFIG;
132 hints.ai_family = PF_UNSPEC;
133 hints.ai_socktype = SOCK_STREAM;
134 hints.ai_protocol = IPPROTO_TCP;
135 hints.ai_addrlen = 0;
136 hints.ai_addr = NULL;
137 hints.ai_canonname = NULL;
138 hints.ai_next = NULL;
140 snprintf(service, sizeof(service), "%i", port);
142 error = getaddrinfo(host, service, &hints, &addrinfo);
145 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
146 "host \"%s\" not found: %s",
147 host, gai_strerror(error));
148 connection->error = MPD_ERROR_UNKHOST;
152 for (res = addrinfo; res; res = res->ai_next) {
154 connection->sock = socket(res->ai_family, SOCK_STREAM,
156 if (connection->sock < 0) {
157 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
158 "problems creating socket: %s",
160 connection->error = MPD_ERROR_SYSTEM;
161 freeaddrinfo(addrinfo);
165 mpd_setConnectionTimeout(connection, timeout);
168 if (do_connect_fail(connection,
169 res->ai_addr, res->ai_addrlen)) {
170 /* try the next address family */
171 closesocket(connection->sock);
172 connection->sock = -1;
177 freeaddrinfo(addrinfo);
179 if (connection->sock < 0) {
180 snprintf(connection->errorStr, MPD_ERRORSTR_MAX_LENGTH,
181 "problems connecting to \"%s\" on port %i: %s",
182 host, port, strerror(errno));
183 connection->error = MPD_ERROR_CONNPORT;
190 #else /* !MPD_HAVE_GAI */
191 static int mpd_connect(mpd_Connection * connection, const char * host, int port,
195 struct sockaddr * dest;
197 struct sockaddr_in sin;
199 if(!(he=gethostbyname(host))) {
200 snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
201 "host \"%s\" not found",host);
202 connection->error = MPD_ERROR_UNKHOST;
206 memset(&sin,0,sizeof(struct sockaddr_in));
207 /*dest.sin_family = he->h_addrtype;*/
208 sin.sin_family = AF_INET;
209 sin.sin_port = htons(port);
211 switch(he->h_addrtype) {
213 memcpy((char *)&sin.sin_addr.s_addr,(char *)he->h_addr,
215 dest = (struct sockaddr *)&sin;
216 destlen = sizeof(struct sockaddr_in);
219 strcpy(connection->errorStr,"address type is not IPv4");
220 connection->error = MPD_ERROR_SYSTEM;
225 if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) {
226 strcpy(connection->errorStr,"problems creating socket");
227 connection->error = MPD_ERROR_SYSTEM;
231 mpd_setConnectionTimeout(connection,timeout);
234 if (do_connect_fail(connection, dest, destlen)) {
235 snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
236 "problems connecting to \"%s\" on port"
238 connection->error = MPD_ERROR_CONNPORT;
244 #endif /* !MPD_HAVE_GAI */
246 char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] =
263 static char * mpd_sanitizeArg(const char * arg) {
266 register const char *c;
269 /* instead of counting in that loop above, just
270 * use a bit more memory and half running time
272 ret = malloc(strlen(arg) * 2 + 1);
276 for(i = strlen(arg)+1; i != 0; --i) {
277 if(*c=='"' || *c=='\\')
285 static mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
287 mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));
289 ret->name = strdup(name);
290 ret->value = strdup(value);
295 static void mpd_freeReturnElement(mpd_ReturnElement * re) {
301 void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout) {
302 connection->timeout.tv_sec = (int)timeout;
303 connection->timeout.tv_usec = (int)(timeout*1e6 -
304 connection->timeout.tv_sec*1000000 +
308 static int mpd_parseWelcome(mpd_Connection * connection, const char * host, int port,
309 char * rt, char * output) {
314 if(strncmp(output,MPD_WELCOME_MESSAGE,strlen(MPD_WELCOME_MESSAGE))) {
315 snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
316 "mpd not running on port %i on host \"%s\"",
318 connection->error = MPD_ERROR_NOTMPD;
322 tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
325 if(tmp) connection->version[i] = strtol(tmp,&test,10);
327 if (!tmp || (test[0] != '.' && test[0] != '\0')) {
328 snprintf(connection->errorStr,
329 MPD_ERRORSTR_MAX_LENGTH,
330 "error parsing version number at "
332 &output[strlen(MPD_WELCOME_MESSAGE)]);
333 connection->error = MPD_ERROR_NOTMPD;
342 mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
345 char * output = NULL;
346 mpd_Connection * connection = malloc(sizeof(mpd_Connection));
349 strcpy(connection->buffer,"");
350 connection->buflen = 0;
351 connection->bufstart = 0;
352 strcpy(connection->errorStr,"");
353 connection->error = 0;
354 connection->doneProcessing = 0;
355 connection->commandList = 0;
356 connection->listOks = 0;
357 connection->doneListOk = 0;
358 connection->returnElement = NULL;
359 connection->request = NULL;
361 if (winsock_dll_error(connection))
364 if (mpd_connect(connection, host, port, timeout) < 0)
367 while(!(rt = strstr(connection->buffer,"\n"))) {
368 tv.tv_sec = connection->timeout.tv_sec;
369 tv.tv_usec = connection->timeout.tv_usec;
371 FD_SET(connection->sock,&fds);
372 if((err = select(connection->sock+1,&fds,NULL,NULL,&tv)) == 1) {
374 readed = recv(connection->sock,
375 &(connection->buffer[connection->buflen]),
376 MPD_BUFFER_MAX_LENGTH-connection->buflen,0);
378 snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
379 "problems getting a response from"
380 " \"%s\" on port %i : %s",host,
381 port, strerror(errno));
382 connection->error = MPD_ERROR_NORESPONSE;
385 connection->buflen+=readed;
386 connection->buffer[connection->buflen] = '\0';
389 if (SELECT_ERRNO_IGNORE)
391 snprintf(connection->errorStr,
392 MPD_ERRORSTR_MAX_LENGTH,
393 "problems connecting to \"%s\" on port"
395 connection->error = MPD_ERROR_CONNPORT;
399 snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
400 "timeout in attempting to get a response from"
401 " \"%s\" on port %i",host,port);
402 connection->error = MPD_ERROR_NORESPONSE;
408 output = strdup(connection->buffer);
409 strcpy(connection->buffer,rt+1);
410 connection->buflen = strlen(connection->buffer);
412 if(mpd_parseWelcome(connection,host,port,rt,output) == 0) connection->doneProcessing = 1;
419 void mpd_clearError(mpd_Connection * connection) {
420 connection->error = 0;
421 connection->errorStr[0] = '\0';
424 void mpd_closeConnection(mpd_Connection * connection) {
425 closesocket(connection->sock);
426 if(connection->returnElement) free(connection->returnElement);
427 if(connection->request) free(connection->request);
432 static void mpd_executeCommand(mpd_Connection * connection, char * command) {
436 char * commandPtr = command;
437 int commandLen = strlen(command);
439 if(!connection->doneProcessing && !connection->commandList) {
440 strcpy(connection->errorStr,"not done processing current command");
441 connection->error = 1;
445 mpd_clearError(connection);
448 FD_SET(connection->sock,&fds);
449 tv.tv_sec = connection->timeout.tv_sec;
450 tv.tv_usec = connection->timeout.tv_usec;
452 while((ret = select(connection->sock+1,NULL,&fds,NULL,&tv)==1) ||
453 (ret==-1 && SELECT_ERRNO_IGNORE)) {
454 ret = send(connection->sock,commandPtr,commandLen,MSG_DONTWAIT);
457 if (SENDRECV_ERRNO_IGNORE) continue;
458 snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
459 "problems giving command \"%s\"",command);
460 connection->error = MPD_ERROR_SENDING;
468 if(commandLen<=0) break;
473 snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
474 "timeout sending command \"%s\"",command);
475 connection->error = MPD_ERROR_TIMEOUT;
479 if(!connection->commandList) connection->doneProcessing = 0;
480 else if(connection->commandList == COMMAND_LIST_OK) {
481 connection->listOks++;
485 static void mpd_getNextReturnElement(mpd_Connection * connection) {
486 char * output = NULL;
494 char * bufferCheck = NULL;
498 if(connection->returnElement) mpd_freeReturnElement(connection->returnElement);
499 connection->returnElement = NULL;
501 if(connection->doneProcessing || (connection->listOks &&
502 connection->doneListOk))
504 strcpy(connection->errorStr,"already done processing current command");
505 connection->error = 1;
509 bufferCheck = connection->buffer+connection->bufstart;
510 while(connection->bufstart>=connection->buflen ||
511 !(rt = strchr(bufferCheck,'\n'))) {
512 if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
513 memmove(connection->buffer,
515 connection->bufstart,
517 connection->bufstart+1);
518 connection->buflen-=connection->bufstart;
519 connection->bufstart = 0;
521 if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
522 strcpy(connection->errorStr,"buffer overrun");
523 connection->error = MPD_ERROR_BUFFEROVERRUN;
524 connection->doneProcessing = 1;
525 connection->doneListOk = 0;
528 bufferCheck = connection->buffer+connection->buflen;
529 tv.tv_sec = connection->timeout.tv_sec;
530 tv.tv_usec = connection->timeout.tv_usec;
532 FD_SET(connection->sock,&fds);
533 if((err = select(connection->sock+1,&fds,NULL,NULL,&tv) == 1)) {
534 readed = recv(connection->sock,
535 connection->buffer+connection->buflen,
536 MPD_BUFFER_MAX_LENGTH-connection->buflen,
538 if(readed<0 && SENDRECV_ERRNO_IGNORE) {
542 strcpy(connection->errorStr,"connection"
544 connection->error = MPD_ERROR_CONNCLOSED;
545 connection->doneProcessing = 1;
546 connection->doneListOk = 0;
549 connection->buflen+=readed;
550 connection->buffer[connection->buflen] = '\0';
552 else if(err<0 && SELECT_ERRNO_IGNORE) continue;
554 strcpy(connection->errorStr,"connection timeout");
555 connection->error = MPD_ERROR_TIMEOUT;
556 connection->doneProcessing = 1;
557 connection->doneListOk = 0;
563 output = connection->buffer+connection->bufstart;
564 connection->bufstart = rt - connection->buffer + 1;
566 if(strcmp(output,"OK")==0) {
567 if(connection->listOks > 0) {
568 strcpy(connection->errorStr, "expected more list_OK's");
569 connection->error = 1;
571 connection->listOks = 0;
572 connection->doneProcessing = 1;
573 connection->doneListOk = 0;
577 if(strcmp(output, "list_OK") == 0) {
578 if(!connection->listOks) {
579 strcpy(connection->errorStr,
580 "got an unexpected list_OK");
581 connection->error = 1;
584 connection->doneListOk = 1;
585 connection->listOks--;
590 if(strncmp(output,"ACK",strlen("ACK"))==0) {
595 strcpy(connection->errorStr, output);
596 connection->error = MPD_ERROR_ACK;
597 connection->errorCode = MPD_ACK_ERROR_UNK;
598 connection->errorAt = MPD_ERROR_AT_UNK;
599 connection->doneProcessing = 1;
600 connection->doneListOk = 0;
602 needle = strchr(output, '[');
604 val = strtol(needle+1, &test, 10);
605 if(*test != '@') return;
606 connection->errorCode = val;
607 val = strtol(test+1, &test, 10);
608 if(*test != ']') return;
609 connection->errorAt = val;
613 tok = strchr(output, ':');
621 connection->returnElement = mpd_newReturnElement(name,&(value[1]));
624 snprintf(connection->errorStr,MPD_ERRORSTR_MAX_LENGTH,
625 "error parsing: %s:%s",name,value);
626 connection->error = 1;
630 void mpd_finishCommand(mpd_Connection * connection) {
631 while(!connection->doneProcessing) {
632 if(connection->doneListOk) connection->doneListOk = 0;
633 mpd_getNextReturnElement(connection);
637 static void mpd_finishListOkCommand(mpd_Connection * connection) {
638 while(!connection->doneProcessing && connection->listOks &&
639 !connection->doneListOk)
641 mpd_getNextReturnElement(connection);
645 int mpd_nextListOkCommand(mpd_Connection * connection) {
646 mpd_finishListOkCommand(connection);
647 if(!connection->doneProcessing) connection->doneListOk = 0;
648 if(connection->listOks == 0 || connection->doneProcessing) return -1;
652 void mpd_sendStatusCommand(mpd_Connection * connection) {
653 mpd_executeCommand(connection,"status\n");
656 mpd_Status * mpd_getStatus(mpd_Connection * connection) {
659 /*mpd_executeCommand(connection,"status\n");
661 if(connection->error) return NULL;*/
663 if(connection->doneProcessing || (connection->listOks &&
664 connection->doneListOk))
669 if(!connection->returnElement) mpd_getNextReturnElement(connection);
671 status = malloc(sizeof(mpd_Status));
675 status->playlist = -1;
676 status->playlistLength = -1;
680 status->elapsedTime = 0;
681 status->totalTime = 0;
683 status->sampleRate = 0;
685 status->channels = 0;
686 status->crossfade = -1;
687 status->error = NULL;
688 status->updatingDb = 0;
690 if(connection->error) {
694 while(connection->returnElement) {
695 mpd_ReturnElement * re = connection->returnElement;
696 if(strcmp(re->name,"volume")==0) {
697 status->volume = atoi(re->value);
699 else if(strcmp(re->name,"repeat")==0) {
700 status->repeat = atoi(re->value);
702 else if(strcmp(re->name,"random")==0) {
703 status->random = atoi(re->value);
705 else if(strcmp(re->name,"playlist")==0) {
706 status->playlist = strtol(re->value,NULL,10);
708 else if(strcmp(re->name,"playlistlength")==0) {
709 status->playlistLength = atoi(re->value);
711 else if(strcmp(re->name,"bitrate")==0) {
712 status->bitRate = atoi(re->value);
714 else if(strcmp(re->name,"state")==0) {
715 if(strcmp(re->value,"play")==0) {
716 status->state = MPD_STATUS_STATE_PLAY;
718 else if(strcmp(re->value,"stop")==0) {
719 status->state = MPD_STATUS_STATE_STOP;
721 else if(strcmp(re->value,"pause")==0) {
722 status->state = MPD_STATUS_STATE_PAUSE;
725 status->state = MPD_STATUS_STATE_UNKNOWN;
728 else if(strcmp(re->name,"song")==0) {
729 status->song = atoi(re->value);
731 else if(strcmp(re->name,"songid")==0) {
732 status->songid = atoi(re->value);
734 else if(strcmp(re->name,"time")==0) {
735 char * tok = strchr(re->value,':');
736 /* the second strchr below is a safety check */
737 if (tok && (strchr(tok,0) > (tok+1))) {
738 /* atoi stops at the first non-[0-9] char: */
739 status->elapsedTime = atoi(re->value);
740 status->totalTime = atoi(tok+1);
743 else if(strcmp(re->name,"error")==0) {
744 status->error = strdup(re->value);
746 else if(strcmp(re->name,"xfade")==0) {
747 status->crossfade = atoi(re->value);
749 else if(strcmp(re->name,"updating_db")==0) {
750 status->updatingDb = atoi(re->value);
752 else if(strcmp(re->name,"audio")==0) {
753 char * tok = strchr(re->value,':');
754 if (tok && (strchr(tok,0) > (tok+1))) {
755 status->sampleRate = atoi(re->value);
756 status->bits = atoi(++tok);
757 tok = strchr(tok,':');
758 if (tok && (strchr(tok,0) > (tok+1)))
759 status->channels = atoi(tok+1);
763 mpd_getNextReturnElement(connection);
764 if(connection->error) {
770 if(connection->error) {
774 else if(status->state<0) {
775 strcpy(connection->errorStr,"state not found");
776 connection->error = 1;
784 void mpd_freeStatus(mpd_Status * status) {
785 if(status->error) free(status->error);
789 void mpd_sendStatsCommand(mpd_Connection * connection) {
790 mpd_executeCommand(connection,"stats\n");
793 mpd_Stats * mpd_getStats(mpd_Connection * connection) {
796 /*mpd_executeCommand(connection,"stats\n");
798 if(connection->error) return NULL;*/
800 if(connection->doneProcessing || (connection->listOks &&
801 connection->doneListOk))
806 if(!connection->returnElement) mpd_getNextReturnElement(connection);
808 stats = malloc(sizeof(mpd_Stats));
809 stats->numberOfArtists = 0;
810 stats->numberOfAlbums = 0;
811 stats->numberOfSongs = 0;
813 stats->dbUpdateTime = 0;
815 stats->dbPlayTime = 0;
817 if(connection->error) {
821 while(connection->returnElement) {
822 mpd_ReturnElement * re = connection->returnElement;
823 if(strcmp(re->name,"artists")==0) {
824 stats->numberOfArtists = atoi(re->value);
826 else if(strcmp(re->name,"albums")==0) {
827 stats->numberOfAlbums = atoi(re->value);
829 else if(strcmp(re->name,"songs")==0) {
830 stats->numberOfSongs = atoi(re->value);
832 else if(strcmp(re->name,"uptime")==0) {
833 stats->uptime = strtol(re->value,NULL,10);
835 else if(strcmp(re->name,"db_update")==0) {
836 stats->dbUpdateTime = strtol(re->value,NULL,10);
838 else if(strcmp(re->name,"playtime")==0) {
839 stats->playTime = strtol(re->value,NULL,10);
841 else if(strcmp(re->name,"db_playtime")==0) {
842 stats->dbPlayTime = strtol(re->value,NULL,10);
845 mpd_getNextReturnElement(connection);
846 if(connection->error) {
852 if(connection->error) {
860 void mpd_freeStats(mpd_Stats * stats) {
864 mpd_SearchStats * mpd_getSearchStats(mpd_Connection * connection)
866 mpd_SearchStats * stats;
867 mpd_ReturnElement * re;
869 if (connection->doneProcessing ||
870 (connection->listOks && connection->doneListOk)) {
874 if (!connection->returnElement) mpd_getNextReturnElement(connection);
876 if (connection->error)
879 stats = malloc(sizeof(mpd_SearchStats));
880 stats->numberOfSongs = 0;
883 while (connection->returnElement) {
884 re = connection->returnElement;
886 if (strcmp(re->name, "songs") == 0) {
887 stats->numberOfSongs = atoi(re->value);
888 } else if (strcmp(re->name, "playtime") == 0) {
889 stats->playTime = strtol(re->value, NULL, 10);
892 mpd_getNextReturnElement(connection);
893 if (connection->error) {
899 if (connection->error) {
907 void mpd_freeSearchStats(mpd_SearchStats * stats)
912 static void mpd_initSong(mpd_Song * song) {
922 song->composer = NULL;
923 song->performer = NULL;
925 song->comment = NULL;
927 song->time = MPD_SONG_NO_TIME;
928 song->pos = MPD_SONG_NO_NUM;
929 song->id = MPD_SONG_NO_ID;
932 static void mpd_finishSong(mpd_Song * song) {
933 if(song->file) free(song->file);
934 if(song->artist) free(song->artist);
935 if(song->album) free(song->album);
936 if(song->title) free(song->title);
937 if(song->track) free(song->track);
938 if(song->name) free(song->name);
939 if(song->date) free(song->date);
940 if(song->genre) free(song->genre);
941 if(song->composer) free(song->composer);
942 if(song->disc) free(song->disc);
943 if(song->comment) free(song->comment);
946 mpd_Song * mpd_newSong(void) {
947 mpd_Song * ret = malloc(sizeof(mpd_Song));
954 void mpd_freeSong(mpd_Song * song) {
955 mpd_finishSong(song);
959 mpd_Song * mpd_songDup(mpd_Song * song) {
960 mpd_Song * ret = mpd_newSong();
962 if(song->file) ret->file = strdup(song->file);
963 if(song->artist) ret->artist = strdup(song->artist);
964 if(song->album) ret->album = strdup(song->album);
965 if(song->title) ret->title = strdup(song->title);
966 if(song->track) ret->track = strdup(song->track);
967 if(song->name) ret->name = strdup(song->name);
968 if(song->date) ret->date = strdup(song->date);
969 if(song->genre) ret->genre= strdup(song->genre);
970 if(song->composer) ret->composer= strdup(song->composer);
971 if(song->disc) ret->disc = strdup(song->disc);
972 if(song->comment) ret->comment = strdup(song->comment);
973 ret->time = song->time;
974 ret->pos = song->pos;
980 static void mpd_initDirectory(mpd_Directory * directory) {
981 directory->path = NULL;
984 static void mpd_finishDirectory(mpd_Directory * directory) {
985 if(directory->path) free(directory->path);
988 mpd_Directory * mpd_newDirectory(void) {
989 mpd_Directory * directory = malloc(sizeof(mpd_Directory));;
991 mpd_initDirectory(directory);
996 void mpd_freeDirectory(mpd_Directory * directory) {
997 mpd_finishDirectory(directory);
1002 mpd_Directory * mpd_directoryDup(mpd_Directory * directory) {
1003 mpd_Directory * ret = mpd_newDirectory();
1005 if(directory->path) ret->path = strdup(directory->path);
1010 static void mpd_initPlaylistFile(mpd_PlaylistFile * playlist) {
1011 playlist->path = NULL;
1014 static void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist) {
1015 if(playlist->path) free(playlist->path);
1018 mpd_PlaylistFile * mpd_newPlaylistFile(void) {
1019 mpd_PlaylistFile * playlist = malloc(sizeof(mpd_PlaylistFile));
1021 mpd_initPlaylistFile(playlist);
1026 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist) {
1027 mpd_finishPlaylistFile(playlist);
1031 mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist) {
1032 mpd_PlaylistFile * ret = mpd_newPlaylistFile();
1034 if(playlist->path) ret->path = strdup(playlist->path);
1039 static void mpd_initInfoEntity(mpd_InfoEntity * entity) {
1040 entity->info.directory = NULL;
1043 static void mpd_finishInfoEntity(mpd_InfoEntity * entity) {
1044 if(entity->info.directory) {
1045 if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1046 mpd_freeDirectory(entity->info.directory);
1048 else if(entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
1049 mpd_freeSong(entity->info.song);
1051 else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1052 mpd_freePlaylistFile(entity->info.playlistFile);
1057 mpd_InfoEntity * mpd_newInfoEntity(void) {
1058 mpd_InfoEntity * entity = malloc(sizeof(mpd_InfoEntity));
1060 mpd_initInfoEntity(entity);
1065 void mpd_freeInfoEntity(mpd_InfoEntity * entity) {
1066 mpd_finishInfoEntity(entity);
1070 static void mpd_sendInfoCommand(mpd_Connection * connection, char * command) {
1071 mpd_executeCommand(connection,command);
1074 mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) {
1075 mpd_InfoEntity * entity = NULL;
1077 if(connection->doneProcessing || (connection->listOks &&
1078 connection->doneListOk))
1083 if(!connection->returnElement) mpd_getNextReturnElement(connection);
1085 if(connection->returnElement) {
1086 if(strcmp(connection->returnElement->name,"file")==0) {
1087 entity = mpd_newInfoEntity();
1088 entity->type = MPD_INFO_ENTITY_TYPE_SONG;
1089 entity->info.song = mpd_newSong();
1090 entity->info.song->file =
1091 strdup(connection->returnElement->value);
1093 else if(strcmp(connection->returnElement->name,
1095 entity = mpd_newInfoEntity();
1096 entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
1097 entity->info.directory = mpd_newDirectory();
1098 entity->info.directory->path =
1099 strdup(connection->returnElement->value);
1101 else if(strcmp(connection->returnElement->name,"playlist")==0) {
1102 entity = mpd_newInfoEntity();
1103 entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
1104 entity->info.playlistFile = mpd_newPlaylistFile();
1105 entity->info.playlistFile->path =
1106 strdup(connection->returnElement->value);
1108 else if(strcmp(connection->returnElement->name, "cpos") == 0){
1109 entity = mpd_newInfoEntity();
1110 entity->type = MPD_INFO_ENTITY_TYPE_SONG;
1111 entity->info.song = mpd_newSong();
1112 entity->info.song->pos = atoi(connection->returnElement->value);
1115 connection->error = 1;
1116 strcpy(connection->errorStr,"problem parsing song info");
1122 mpd_getNextReturnElement(connection);
1123 while(connection->returnElement) {
1124 mpd_ReturnElement * re = connection->returnElement;
1126 if(strcmp(re->name,"file")==0) return entity;
1127 else if(strcmp(re->name,"directory")==0) return entity;
1128 else if(strcmp(re->name,"playlist")==0) return entity;
1129 else if(strcmp(re->name,"cpos")==0) return entity;
1131 if(entity->type == MPD_INFO_ENTITY_TYPE_SONG &&
1132 strlen(re->value)) {
1133 if(!entity->info.song->artist &&
1134 strcmp(re->name,"Artist")==0) {
1135 entity->info.song->artist = strdup(re->value);
1137 else if(!entity->info.song->album &&
1138 strcmp(re->name,"Album")==0) {
1139 entity->info.song->album = strdup(re->value);
1141 else if(!entity->info.song->title &&
1142 strcmp(re->name,"Title")==0) {
1143 entity->info.song->title = strdup(re->value);
1145 else if(!entity->info.song->track &&
1146 strcmp(re->name,"Track")==0) {
1147 entity->info.song->track = strdup(re->value);
1149 else if(!entity->info.song->name &&
1150 strcmp(re->name,"Name")==0) {
1151 entity->info.song->name = strdup(re->value);
1153 else if(entity->info.song->time==MPD_SONG_NO_TIME &&
1154 strcmp(re->name,"Time")==0) {
1155 entity->info.song->time = atoi(re->value);
1157 else if(entity->info.song->pos==MPD_SONG_NO_NUM &&
1158 strcmp(re->name,"Pos")==0) {
1159 entity->info.song->pos = atoi(re->value);
1161 else if(entity->info.song->id==MPD_SONG_NO_ID &&
1162 strcmp(re->name,"Id")==0) {
1163 entity->info.song->id = atoi(re->value);
1165 else if(!entity->info.song->date &&
1166 strcmp(re->name, "Date") == 0) {
1167 entity->info.song->date = strdup(re->value);
1169 else if(!entity->info.song->genre &&
1170 strcmp(re->name, "Genre") == 0) {
1171 entity->info.song->genre = strdup(re->value);
1173 else if(!entity->info.song->composer &&
1174 strcmp(re->name, "Composer") == 0) {
1175 entity->info.song->composer = strdup(re->value);
1177 else if(!entity->info.song->performer &&
1178 strcmp(re->name, "Performer") == 0) {
1179 entity->info.song->performer = strdup(re->value);
1181 else if(!entity->info.song->disc &&
1182 strcmp(re->name, "Disc") == 0) {
1183 entity->info.song->disc = strdup(re->value);
1185 else if(!entity->info.song->comment &&
1186 strcmp(re->name, "Comment") == 0) {
1187 entity->info.song->comment = strdup(re->value);
1190 else if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1192 else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1195 mpd_getNextReturnElement(connection);
1201 static char * mpd_getNextReturnElementNamed(mpd_Connection * connection,
1204 if(connection->doneProcessing || (connection->listOks &&
1205 connection->doneListOk))
1210 mpd_getNextReturnElement(connection);
1211 while(connection->returnElement) {
1212 mpd_ReturnElement * re = connection->returnElement;
1214 if(strcmp(re->name,name)==0) return strdup(re->value);
1215 mpd_getNextReturnElement(connection);
1221 char *mpd_getNextTag(mpd_Connection *connection, int type)
1223 if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES ||
1224 type == MPD_TAG_ITEM_ANY)
1226 if (type == MPD_TAG_ITEM_FILENAME)
1227 return mpd_getNextReturnElementNamed(connection, "file");
1228 return mpd_getNextReturnElementNamed(connection, mpdTagItemKeys[type]);
1231 char * mpd_getNextArtist(mpd_Connection * connection) {
1232 return mpd_getNextReturnElementNamed(connection,"Artist");
1235 char * mpd_getNextAlbum(mpd_Connection * connection) {
1236 return mpd_getNextReturnElementNamed(connection,"Album");
1239 void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos) {
1240 int len = strlen("playlistinfo")+2+INTLEN+3;
1241 char *string = malloc(len);
1242 snprintf(string, len, "playlistinfo \"%i\"\n", songPos);
1243 mpd_sendInfoCommand(connection,string);
1247 void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id) {
1248 int len = strlen("playlistid")+2+INTLEN+3;
1249 char *string = malloc(len);
1250 snprintf(string, len, "playlistid \"%i\"\n", id);
1251 mpd_sendInfoCommand(connection, string);
1255 void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist) {
1256 int len = strlen("plchanges")+2+LONGLONGLEN+3;
1257 char *string = malloc(len);
1258 snprintf(string, len, "plchanges \"%lld\"\n", playlist);
1259 mpd_sendInfoCommand(connection,string);
1263 void mpd_sendPlChangesPosIdCommand(mpd_Connection * connection, long long playlist) {
1264 int len = strlen("plchangesposid")+2+LONGLONGLEN+3;
1265 char *string = malloc(len);
1266 snprintf(string, len, "plchangesposid \"%lld\"\n", playlist);
1267 mpd_sendInfoCommand(connection,string);
1271 void mpd_sendListallCommand(mpd_Connection * connection, const char * dir) {
1272 char * sDir = mpd_sanitizeArg(dir);
1273 int len = strlen("listall")+2+strlen(sDir)+3;
1274 char *string = malloc(len);
1275 snprintf(string, len, "listall \"%s\"\n", sDir);
1276 mpd_sendInfoCommand(connection,string);
1281 void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir) {
1282 char * sDir = mpd_sanitizeArg(dir);
1283 int len = strlen("listallinfo")+2+strlen(sDir)+3;
1284 char *string = malloc(len);
1285 snprintf(string, len, "listallinfo \"%s\"\n", sDir);
1286 mpd_sendInfoCommand(connection,string);
1291 void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir) {
1292 char * sDir = mpd_sanitizeArg(dir);
1293 int len = strlen("lsinfo")+2+strlen(sDir)+3;
1294 char *string = malloc(len);
1295 snprintf(string, len, "lsinfo \"%s\"\n", sDir);
1296 mpd_sendInfoCommand(connection,string);
1301 void mpd_sendCurrentSongCommand(mpd_Connection * connection) {
1302 mpd_executeCommand(connection,"currentsong\n");
1305 void mpd_sendSearchCommand(mpd_Connection * connection, int table,
1308 mpd_startSearch(connection, 0);
1309 mpd_addConstraintSearch(connection, table, str);
1310 mpd_commitSearch(connection);
1313 void mpd_sendFindCommand(mpd_Connection * connection, int table,
1316 mpd_startSearch(connection, 1);
1317 mpd_addConstraintSearch(connection, table, str);
1318 mpd_commitSearch(connection);
1321 void mpd_sendListCommand(mpd_Connection * connection, int table,
1327 if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
1328 else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
1330 connection->error = 1;
1331 strcpy(connection->errorStr,"unknown table for list");
1335 char * sanitArg1 = mpd_sanitizeArg(arg1);
1336 len = strlen("list")+1+strlen(sanitArg1)+2+strlen(st)+3;
1337 string = malloc(len);
1338 snprintf(string, len, "list %s \"%s\"\n", st, sanitArg1);
1342 len = strlen("list")+1+strlen(st)+2;
1343 string = malloc(len);
1344 snprintf(string, len, "list %s\n", st);
1346 mpd_sendInfoCommand(connection,string);
1350 void mpd_sendAddCommand(mpd_Connection * connection, const char * file) {
1351 char * sFile = mpd_sanitizeArg(file);
1352 int len = strlen("add")+2+strlen(sFile)+3;
1353 char *string = malloc(len);
1354 snprintf(string, len, "add \"%s\"\n", sFile);
1355 mpd_executeCommand(connection,string);
1360 int mpd_sendAddIdCommand(mpd_Connection *connection, const char *file)
1363 char *sFile = mpd_sanitizeArg(file);
1364 int len = strlen("addid")+2+strlen(sFile)+3;
1365 char *string = malloc(len);
1367 snprintf(string, len, "addid \"%s\"\n", sFile);
1368 mpd_sendInfoCommand(connection, string);
1372 string = mpd_getNextReturnElementNamed(connection, "Id");
1374 retval = atoi(string);
1381 void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos) {
1382 int len = strlen("delete")+2+INTLEN+3;
1383 char *string = malloc(len);
1384 snprintf(string, len, "delete \"%i\"\n", songPos);
1385 mpd_sendInfoCommand(connection,string);
1389 void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id) {
1390 int len = strlen("deleteid")+2+INTLEN+3;
1391 char *string = malloc(len);
1392 snprintf(string, len, "deleteid \"%i\"\n", id);
1393 mpd_sendInfoCommand(connection,string);
1397 void mpd_sendSaveCommand(mpd_Connection * connection, const char * name) {
1398 char * sName = mpd_sanitizeArg(name);
1399 int len = strlen("save")+2+strlen(sName)+3;
1400 char *string = malloc(len);
1401 snprintf(string, len, "save \"%s\"\n", sName);
1402 mpd_executeCommand(connection,string);
1407 void mpd_sendLoadCommand(mpd_Connection * connection, const char * name) {
1408 char * sName = mpd_sanitizeArg(name);
1409 int len = strlen("load")+2+strlen(sName)+3;
1410 char *string = malloc(len);
1411 snprintf(string, len, "load \"%s\"\n", sName);
1412 mpd_executeCommand(connection,string);
1417 void mpd_sendRmCommand(mpd_Connection * connection, const char * name) {
1418 char * sName = mpd_sanitizeArg(name);
1419 int len = strlen("rm")+2+strlen(sName)+3;
1420 char *string = malloc(len);
1421 snprintf(string, len, "rm \"%s\"\n", sName);
1422 mpd_executeCommand(connection,string);
1427 void mpd_sendRenameCommand(mpd_Connection *connection, const char *from,
1430 char *sFrom = mpd_sanitizeArg(from);
1431 char *sTo = mpd_sanitizeArg(to);
1432 int len = strlen("rename")+2+strlen(sFrom)+3+strlen(sTo)+3;
1433 char *string = malloc(len);
1434 snprintf(string, len, "rename \"%s\" \"%s\"\n", sFrom, sTo);
1435 mpd_executeCommand(connection, string);
1441 void mpd_sendShuffleCommand(mpd_Connection * connection) {
1442 mpd_executeCommand(connection,"shuffle\n");
1445 void mpd_sendClearCommand(mpd_Connection * connection) {
1446 mpd_executeCommand(connection,"clear\n");
1449 void mpd_sendPlayCommand(mpd_Connection * connection, int songPos) {
1450 int len = strlen("play")+2+INTLEN+3;
1451 char *string = malloc(len);
1452 snprintf(string, len, "play \"%i\"\n", songPos);
1453 mpd_sendInfoCommand(connection,string);
1457 void mpd_sendPlayIdCommand(mpd_Connection * connection, int id) {
1458 int len = strlen("playid")+2+INTLEN+3;
1459 char *string = malloc(len);
1460 snprintf(string, len, "playid \"%i\"\n", id);
1461 mpd_sendInfoCommand(connection,string);
1465 void mpd_sendStopCommand(mpd_Connection * connection) {
1466 mpd_executeCommand(connection,"stop\n");
1469 void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode) {
1470 int len = strlen("pause")+2+INTLEN+3;
1471 char *string = malloc(len);
1472 snprintf(string, len, "pause \"%i\"\n", pauseMode);
1473 mpd_executeCommand(connection,string);
1477 void mpd_sendNextCommand(mpd_Connection * connection) {
1478 mpd_executeCommand(connection,"next\n");
1481 void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to) {
1482 int len = strlen("move")+2+INTLEN+3+INTLEN+3;
1483 char *string = malloc(len);
1484 snprintf(string, len, "move \"%i\" \"%i\"\n", from, to);
1485 mpd_sendInfoCommand(connection,string);
1489 void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to) {
1490 int len = strlen("moveid")+2+INTLEN+3+INTLEN+3;
1491 char *string = malloc(len);
1492 snprintf(string, len, "moveid \"%i\" \"%i\"\n", id, to);
1493 mpd_sendInfoCommand(connection,string);
1497 void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2) {
1498 int len = strlen("swap")+2+INTLEN+3+INTLEN+3;
1499 char *string = malloc(len);
1500 snprintf(string, len, "swap \"%i\" \"%i\"\n", song1, song2);
1501 mpd_sendInfoCommand(connection,string);
1505 void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2) {
1506 int len = strlen("swapid")+2+INTLEN+3+INTLEN+3;
1507 char *string = malloc(len);
1508 snprintf(string, len, "swapid \"%i\" \"%i\"\n", id1, id2);
1509 mpd_sendInfoCommand(connection,string);
1513 void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time) {
1514 int len = strlen("seek")+2+INTLEN+3+INTLEN+3;
1515 char *string = malloc(len);
1516 snprintf(string, len, "seek \"%i\" \"%i\"\n", song, time);
1517 mpd_sendInfoCommand(connection,string);
1521 void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time) {
1522 int len = strlen("seekid")+2+INTLEN+3+INTLEN+3;
1523 char *string = malloc(len);
1524 snprintf(string, len, "seekid \"%i\" \"%i\"\n", id, time);
1525 mpd_sendInfoCommand(connection,string);
1529 void mpd_sendUpdateCommand(mpd_Connection * connection, char * path) {
1530 char * sPath = mpd_sanitizeArg(path);
1531 int len = strlen("update")+2+strlen(sPath)+3;
1532 char *string = malloc(len);
1533 snprintf(string, len, "update \"%s\"\n", sPath);
1534 mpd_sendInfoCommand(connection,string);
1539 int mpd_getUpdateId(mpd_Connection * connection) {
1543 jobid = mpd_getNextReturnElementNamed(connection,"updating_db");
1552 void mpd_sendPrevCommand(mpd_Connection * connection) {
1553 mpd_executeCommand(connection,"previous\n");
1556 void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode) {
1557 int len = strlen("repeat")+2+INTLEN+3;
1558 char *string = malloc(len);
1559 snprintf(string, len, "repeat \"%i\"\n", repeatMode);
1560 mpd_executeCommand(connection,string);
1564 void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode) {
1565 int len = strlen("random")+2+INTLEN+3;
1566 char *string = malloc(len);
1567 snprintf(string, len, "random \"%i\"\n", randomMode);
1568 mpd_executeCommand(connection,string);
1572 void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange) {
1573 int len = strlen("setvol")+2+INTLEN+3;
1574 char *string = malloc(len);
1575 snprintf(string, len, "setvol \"%i\"\n", volumeChange);
1576 mpd_executeCommand(connection,string);
1580 void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange) {
1581 int len = strlen("volume")+2+INTLEN+3;
1582 char *string = malloc(len);
1583 snprintf(string, len, "volume \"%i\"\n", volumeChange);
1584 mpd_executeCommand(connection,string);
1588 void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds) {
1589 int len = strlen("crossfade")+2+INTLEN+3;
1590 char *string = malloc(len);
1591 snprintf(string, len, "crossfade \"%i\"\n", seconds);
1592 mpd_executeCommand(connection,string);
1596 void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass) {
1597 char * sPass = mpd_sanitizeArg(pass);
1598 int len = strlen("password")+2+strlen(sPass)+3;
1599 char *string = malloc(len);
1600 snprintf(string, len, "password \"%s\"\n", sPass);
1601 mpd_executeCommand(connection,string);
1606 void mpd_sendCommandListBegin(mpd_Connection * connection) {
1607 if(connection->commandList) {
1608 strcpy(connection->errorStr,"already in command list mode");
1609 connection->error = 1;
1612 connection->commandList = COMMAND_LIST;
1613 mpd_executeCommand(connection,"command_list_begin\n");
1616 void mpd_sendCommandListOkBegin(mpd_Connection * connection) {
1617 if(connection->commandList) {
1618 strcpy(connection->errorStr,"already in command list mode");
1619 connection->error = 1;
1622 connection->commandList = COMMAND_LIST_OK;
1623 mpd_executeCommand(connection,"command_list_ok_begin\n");
1624 connection->listOks = 0;
1627 void mpd_sendCommandListEnd(mpd_Connection * connection) {
1628 if(!connection->commandList) {
1629 strcpy(connection->errorStr,"not in command list mode");
1630 connection->error = 1;
1633 connection->commandList = 0;
1634 mpd_executeCommand(connection,"command_list_end\n");
1637 void mpd_sendOutputsCommand(mpd_Connection * connection) {
1638 mpd_executeCommand(connection,"outputs\n");
1641 mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
1642 mpd_OutputEntity * output = NULL;
1644 if(connection->doneProcessing || (connection->listOks &&
1645 connection->doneListOk))
1650 if(connection->error) return NULL;
1652 output = malloc(sizeof(mpd_OutputEntity));
1654 output->name = NULL;
1655 output->enabled = 0;
1657 if(!connection->returnElement) mpd_getNextReturnElement(connection);
1659 while(connection->returnElement) {
1660 mpd_ReturnElement * re = connection->returnElement;
1661 if(strcmp(re->name,"outputid")==0) {
1662 if(output!=NULL && output->id>=0) return output;
1663 output->id = atoi(re->value);
1665 else if(strcmp(re->name,"outputname")==0) {
1666 output->name = strdup(re->value);
1668 else if(strcmp(re->name,"outputenabled")==0) {
1669 output->enabled = atoi(re->value);
1672 mpd_getNextReturnElement(connection);
1673 if(connection->error) {
1683 void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId) {
1684 int len = strlen("enableoutput")+2+INTLEN+3;
1685 char *string = malloc(len);
1686 snprintf(string, len, "enableoutput \"%i\"\n", outputId);
1687 mpd_executeCommand(connection,string);
1691 void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId) {
1692 int len = strlen("disableoutput")+2+INTLEN+3;
1693 char *string = malloc(len);
1694 snprintf(string, len, "disableoutput \"%i\"\n", outputId);
1695 mpd_executeCommand(connection,string);
1699 void mpd_freeOutputElement(mpd_OutputEntity * output) {
1705 * mpd_sendNotCommandsCommand
1706 * odd naming, but it gets the not allowed commands
1709 void mpd_sendNotCommandsCommand(mpd_Connection * connection)
1711 mpd_executeCommand(connection, "notcommands\n");
1715 * mpd_sendCommandsCommand
1716 * odd naming, but it gets the allowed commands
1718 void mpd_sendCommandsCommand(mpd_Connection * connection)
1720 mpd_executeCommand(connection, "commands\n");
1724 * Get the next returned command
1726 char * mpd_getNextCommand(mpd_Connection * connection)
1728 return mpd_getNextReturnElementNamed(connection, "command");
1731 void mpd_sendUrlHandlersCommand(mpd_Connection * connection)
1733 mpd_executeCommand(connection, "urlhandlers\n");
1736 char * mpd_getNextHandler(mpd_Connection * connection)
1738 return mpd_getNextReturnElementNamed(connection, "handler");
1741 void mpd_sendTagTypesCommand(mpd_Connection * connection)
1743 mpd_executeCommand(connection, "tagtypes\n");
1746 char * mpd_getNextTagType(mpd_Connection * connection)
1748 return mpd_getNextReturnElementNamed(connection, "tagtype");
1751 void mpd_startSearch(mpd_Connection *connection, int exact)
1753 if (connection->request) {
1754 strcpy(connection->errorStr, "search already in progress");
1755 connection->error = 1;
1759 if (exact) connection->request = strdup("find");
1760 else connection->request = strdup("search");
1763 void mpd_startStatsSearch(mpd_Connection *connection)
1765 if (connection->request) {
1766 strcpy(connection->errorStr, "search already in progress");
1767 connection->error = 1;
1771 connection->request = strdup("count");
1774 void mpd_startPlaylistSearch(mpd_Connection *connection, int exact)
1776 if (connection->request) {
1777 strcpy(connection->errorStr, "search already in progress");
1778 connection->error = 1;
1782 if (exact) connection->request = strdup("playlistfind");
1783 else connection->request = strdup("playlistsearch");
1786 void mpd_startFieldSearch(mpd_Connection *connection, int type)
1791 if (connection->request) {
1792 strcpy(connection->errorStr, "search already in progress");
1793 connection->error = 1;
1797 if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES) {
1798 strcpy(connection->errorStr, "invalid type specified");
1799 connection->error = 1;
1803 strtype = mpdTagItemKeys[type];
1805 len = 5+strlen(strtype)+1;
1806 connection->request = malloc(len);
1808 snprintf(connection->request, len, "list %c%s",
1809 tolower(strtype[0]), strtype+1);
1812 void mpd_addConstraintSearch(mpd_Connection *connection, int type, const char *name)
1819 if (!connection->request) {
1820 strcpy(connection->errorStr, "no search in progress");
1821 connection->error = 1;
1825 if (type < 0 || type >= MPD_TAG_NUM_OF_ITEM_TYPES) {
1826 strcpy(connection->errorStr, "invalid type specified");
1827 connection->error = 1;
1832 strcpy(connection->errorStr, "no name specified");
1833 connection->error = 1;
1837 string = strdup(connection->request);
1838 strtype = mpdTagItemKeys[type];
1839 arg = mpd_sanitizeArg(name);
1841 len = strlen(string)+1+strlen(strtype)+2+strlen(arg)+2;
1842 connection->request = realloc(connection->request, len);
1843 snprintf(connection->request, len, "%s %c%s \"%s\"",
1844 string, tolower(strtype[0]), strtype+1, arg);
1850 void mpd_commitSearch(mpd_Connection *connection)
1854 if (!connection->request) {
1855 strcpy(connection->errorStr, "no search in progress");
1856 connection->error = 1;
1860 len = strlen(connection->request)+2;
1861 connection->request = realloc(connection->request, len);
1862 connection->request[len-2] = '\n';
1863 connection->request[len-1] = '\0';
1864 mpd_sendInfoCommand(connection, connection->request);
1866 free(connection->request);
1867 connection->request = NULL;
1871 * @param connection a MpdConnection
1872 * @param path the path to the playlist.
1874 * List the content, with full metadata, of a stored playlist.
1877 void mpd_sendListPlaylistInfoCommand(mpd_Connection *connection, char *path)
1879 char *arg = mpd_sanitizeArg(path);
1880 int len = strlen("listplaylistinfo")+2+strlen(arg)+3;
1881 char *query = malloc(len);
1882 snprintf(query, len, "listplaylistinfo \"%s\"\n", arg);
1883 mpd_sendInfoCommand(connection, query);
1889 * @param connection a MpdConnection
1890 * @param path the path to the playlist.
1892 * List the content of a stored playlist.
1895 void mpd_sendListPlaylistCommand(mpd_Connection *connection, char *path)
1897 char *arg = mpd_sanitizeArg(path);
1898 int len = strlen("listplaylist")+2+strlen(arg)+3;
1899 char *query = malloc(len);
1900 snprintf(query, len, "listplaylist \"%s\"\n", arg);
1901 mpd_sendInfoCommand(connection, query);
1906 void mpd_sendPlaylistClearCommand(mpd_Connection *connection, char *path)
1908 char *sPath = mpd_sanitizeArg(path);
1909 int len = strlen("playlistclear")+2+strlen(sPath)+3;
1910 char *string = malloc(len);
1911 snprintf(string, len, "playlistclear \"%s\"\n", sPath);
1912 mpd_executeCommand(connection, string);
1917 void mpd_sendPlaylistAddCommand(mpd_Connection *connection,
1918 char *playlist, char *path)
1920 char *sPlaylist = mpd_sanitizeArg(playlist);
1921 char *sPath = mpd_sanitizeArg(path);
1922 int len = strlen("playlistadd")+2+strlen(sPlaylist)+3+strlen(sPath)+3;
1923 char *string = malloc(len);
1924 snprintf(string, len, "playlistadd \"%s\" \"%s\"\n", sPlaylist, sPath);
1925 mpd_executeCommand(connection, string);
1931 void mpd_sendPlaylistMoveCommand(mpd_Connection *connection,
1932 char *playlist, int from, int to)
1934 char *sPlaylist = mpd_sanitizeArg(playlist);
1935 int len = strlen("playlistmove")+
1936 2+strlen(sPlaylist)+3+INTLEN+3+INTLEN+3;
1937 char *string = malloc(len);
1938 snprintf(string, len, "playlistmove \"%s\" \"%i\" \"%i\"\n",
1939 sPlaylist, from, to);
1940 mpd_executeCommand(connection, string);
1945 void mpd_sendPlaylistDeleteCommand(mpd_Connection *connection,
1946 char *playlist, int pos)
1948 char *sPlaylist = mpd_sanitizeArg(playlist);
1949 int len = strlen("playlistdelete")+2+strlen(sPlaylist)+3+INTLEN+3;
1950 char *string = malloc(len);
1951 snprintf(string, len, "playlistdelete \"%s\" \"%i\"\n", sPlaylist, pos);
1952 mpd_executeCommand(connection, string);