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"
36 #include <sys/types.h>
38 #include <sys/param.h>
45 # include <ws2tcpip.h>
48 # include <netinet/in.h>
49 # include <arpa/inet.h>
50 # include <sys/socket.h>
55 # define MSG_DONTWAIT 0
64 #define COMMAND_LIST 1
65 #define COMMAND_LIST_OK 2
68 # define SELECT_ERRNO_IGNORE (errno == WSAEINTR || errno == WSAEINPROGRESS)
69 # define SENDRECV_ERRNO_IGNORE SELECT_ERRNO_IGNORE
71 # define SELECT_ERRNO_IGNORE (errno == EINTR)
72 # define SENDRECV_ERRNO_IGNORE (errno == EINTR || errno == EAGAIN)
73 # define winsock_dll_error(c) 0
74 # define closesocket(s) close(s)
75 # define WSACleanup() do { /* nothing */ } while (0)
79 static int winsock_dll_error(mpd_Connection *connection)
82 if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0 ||
83 LOBYTE(wsaData.wVersion) != 2 ||
84 HIBYTE(wsaData.wVersion) != 2 ) {
85 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
86 "Could not find usable WinSock DLL.");
87 connection->error = MPD_ERROR_SYSTEM;
93 static int do_connect_fail(mpd_Connection *connection,
94 const struct sockaddr *serv_addr, int addrlen)
96 int iMode = 1; /* 0 = blocking, else non-blocking */
97 ioctlsocket(connection->sock, FIONBIO, (u_long FAR*) &iMode);
98 return (connect(connection->sock,serv_addr,addrlen) == SOCKET_ERROR
99 && WSAGetLastError() != WSAEWOULDBLOCK);
101 #else /* !WIN32 (sane operating systems) */
102 static int do_connect_fail(mpd_Connection *connection,
103 const struct sockaddr *serv_addr, int addrlen)
105 int flags = fcntl(connection->sock, F_GETFL, 0);
106 fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
107 return (connect(connection->sock,serv_addr,addrlen)<0 &&
113 static int mpd_connect(mpd_Connection * connection, const char * host, int port,
118 struct addrinfo hints;
119 struct addrinfo *res = NULL;
120 struct addrinfo *addrinfo = NULL;
125 hints.ai_flags = AI_ADDRCONFIG;
126 hints.ai_family = PF_UNSPEC;
127 hints.ai_socktype = SOCK_STREAM;
128 hints.ai_protocol = IPPROTO_TCP;
129 hints.ai_addrlen = 0;
130 hints.ai_addr = NULL;
131 hints.ai_canonname = NULL;
132 hints.ai_next = NULL;
134 snprintf(service, sizeof(service), "%d", port);
136 error = getaddrinfo(host, service, &hints, &addrinfo);
139 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
140 "host \"%s\" not found: %s",host, gai_strerror(error));
141 connection->error = MPD_ERROR_UNKHOST;
145 for (res = addrinfo; res; res = res->ai_next) {
147 connection->sock = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
148 if (connection->sock < 0) {
149 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
150 "problems creating socket: %s",
152 connection->error = MPD_ERROR_SYSTEM;
153 freeaddrinfo(addrinfo);
157 mpd_setConnectionTimeout(connection,timeout);
160 if (do_connect_fail(connection, res->ai_addr, res->ai_addrlen)) {
161 /* try the next address family */
162 closesocket(connection->sock);
163 connection->sock = -1;
167 freeaddrinfo(addrinfo);
169 if (connection->sock < 0) {
170 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
171 "problems connecting to \"%s\" on port"
172 " %i: %s",host,port, strerror(errno));
173 connection->error = MPD_ERROR_CONNPORT;
180 #else /* !MPD_HAVE_GAI */
181 static int mpd_connect(mpd_Connection * connection, const char * host, int port,
185 struct sockaddr * dest;
187 struct sockaddr_in sin;
189 if(!(he=gethostbyname(host))) {
190 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
191 "host \"%s\" not found",host);
192 connection->error = MPD_ERROR_UNKHOST;
196 memset(&sin,0,sizeof(struct sockaddr_in));
197 /*dest.sin_family = he->h_addrtype;*/
198 sin.sin_family = AF_INET;
199 sin.sin_port = htons(port);
201 switch(he->h_addrtype) {
203 memcpy((char *)&sin.sin_addr.s_addr,(char *)he->h_addr,
205 dest = (struct sockaddr *)&sin;
206 destlen = sizeof(struct sockaddr_in);
209 strcpy(connection->errorStr,"address type is not IPv4\n");
210 connection->error = MPD_ERROR_SYSTEM;
215 if((connection->sock = socket(dest->sa_family,SOCK_STREAM,0))<0) {
216 strcpy(connection->errorStr,"problems creating socket");
217 connection->error = MPD_ERROR_SYSTEM;
221 mpd_setConnectionTimeout(connection,timeout);
224 if (do_connect_fail(connection, dest, destlen)) {
225 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
226 "problems connecting to \"%s\" on port"
228 connection->error = MPD_ERROR_CONNPORT;
234 #endif /* !MPD_HAVE_GAI */
236 char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] =
252 static char * mpd_sanitizeArg(const char * arg) {
255 register const char *c;
258 /* instead of counting in that loop above, just
259 * use a bit more memory and half running time
261 ret = malloc(strlen(arg) * 2 + 1);
265 for(i = strlen(arg)+1; i != 0; --i) {
266 if(*c=='"' || *c=='\\')
274 static mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
276 mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));
278 ret->name = strdup(name);
279 ret->value = strdup(value);
284 static void mpd_freeReturnElement(mpd_ReturnElement * re) {
290 void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout) {
291 connection->timeout.tv_sec = (int)timeout;
292 connection->timeout.tv_usec = (int)(timeout*1e6 -
293 connection->timeout.tv_sec*1000000 +
297 static int mpd_parseWelcome(mpd_Connection * connection, const char * host, int port,
298 char * rt, char * output) {
305 if(strncmp(output,MPD_WELCOME_MESSAGE,strlen(MPD_WELCOME_MESSAGE))) {
306 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
307 "mpd not running on port %i on host \"%s\"",
309 connection->error = MPD_ERROR_NOTMPD;
313 tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
316 if(tmp) connection->version[i] = strtol(tmp,&test,10);
318 if (!tmp || (test[0] != '.' && test[0] != '\0')) {
319 snprintf(connection->errorStr,
320 MPD_BUFFER_MAX_LENGTH,
321 "error parsing version number at "
323 &output[strlen(MPD_WELCOME_MESSAGE)]);
324 connection->error = MPD_ERROR_NOTMPD;
333 mpd_Connection * mpd_newConnection(const char * host, int port, float timeout) {
336 char * output = NULL;
337 mpd_Connection * connection = malloc(sizeof(mpd_Connection));
340 strcpy(connection->buffer,"");
341 connection->buflen = 0;
342 connection->bufstart = 0;
343 strcpy(connection->errorStr,"");
344 connection->error = 0;
345 connection->doneProcessing = 0;
346 connection->commandList = 0;
347 connection->listOks = 0;
348 connection->doneListOk = 0;
349 connection->returnElement = NULL;
350 connection->request = NULL;
352 if (winsock_dll_error(connection))
355 if (mpd_connect(connection, host, port, timeout) < 0)
358 while(!(rt = strstr(connection->buffer,"\n"))) {
359 tv.tv_sec = connection->timeout.tv_sec;
360 tv.tv_usec = connection->timeout.tv_usec;
362 FD_SET(connection->sock,&fds);
363 if((err = select(connection->sock+1,&fds,NULL,NULL,&tv)) == 1) {
365 readed = recv(connection->sock,
366 &(connection->buffer[connection->buflen]),
367 MPD_BUFFER_MAX_LENGTH-connection->buflen,0);
369 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
370 "problems getting a response from"
371 " \"%s\" on port %i : %s",host,
372 port, strerror(errno));
373 connection->error = MPD_ERROR_NORESPONSE;
376 connection->buflen+=readed;
377 connection->buffer[connection->buflen] = '\0';
380 if (SELECT_ERRNO_IGNORE)
382 snprintf(connection->errorStr,
383 MPD_BUFFER_MAX_LENGTH,
384 "problems connecting to \"%s\" on port"
386 connection->error = MPD_ERROR_CONNPORT;
390 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
391 "timeout in attempting to get a response from"
392 " \"%s\" on port %i",host,port);
393 connection->error = MPD_ERROR_NORESPONSE;
399 output = strdup(connection->buffer);
400 strcpy(connection->buffer,rt+1);
401 connection->buflen = strlen(connection->buffer);
403 if(mpd_parseWelcome(connection,host,port,rt,output) == 0) connection->doneProcessing = 1;
410 void mpd_clearError(mpd_Connection * connection) {
411 connection->error = 0;
412 connection->errorStr[0] = '\0';
415 void mpd_closeConnection(mpd_Connection * connection) {
416 closesocket(connection->sock);
417 if(connection->returnElement) free(connection->returnElement);
418 if(connection->request) free(connection->request);
423 static void mpd_executeCommand(mpd_Connection * connection, char * command) {
427 char * commandPtr = command;
428 int commandLen = strlen(command);
430 if(!connection->doneProcessing && !connection->commandList) {
431 strcpy(connection->errorStr,"not done processing current command");
432 connection->error = 1;
436 mpd_clearError(connection);
439 FD_SET(connection->sock,&fds);
440 tv.tv_sec = connection->timeout.tv_sec;
441 tv.tv_usec = connection->timeout.tv_usec;
443 while((ret = select(connection->sock+1,NULL,&fds,NULL,&tv)==1) ||
444 (ret==-1 && SELECT_ERRNO_IGNORE)) {
445 ret = send(connection->sock,commandPtr,commandLen,MSG_DONTWAIT);
448 if (SENDRECV_ERRNO_IGNORE) continue;
449 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
450 "problems giving command \"%s\"",command);
451 connection->error = MPD_ERROR_SENDING;
459 if(commandLen<=0) break;
464 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
465 "timeout sending command \"%s\"",command);
466 connection->error = MPD_ERROR_TIMEOUT;
470 if(!connection->commandList) connection->doneProcessing = 0;
471 else if(connection->commandList == COMMAND_LIST_OK) {
472 connection->listOks++;
476 static void mpd_getNextReturnElement(mpd_Connection * connection) {
477 char * output = NULL;
485 char * bufferCheck = NULL;
489 if(connection->returnElement) mpd_freeReturnElement(connection->returnElement);
490 connection->returnElement = NULL;
492 if(connection->doneProcessing || (connection->listOks &&
493 connection->doneListOk))
495 strcpy(connection->errorStr,"already done processing current command");
496 connection->error = 1;
500 bufferCheck = connection->buffer+connection->bufstart;
501 while(connection->bufstart>=connection->buflen ||
502 !(rt = strchr(bufferCheck,'\n'))) {
503 if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
504 memmove(connection->buffer,
506 connection->bufstart,
508 connection->bufstart+1);
509 connection->buflen-=connection->bufstart;
510 connection->bufstart = 0;
512 if(connection->buflen>=MPD_BUFFER_MAX_LENGTH) {
513 strcpy(connection->errorStr,"buffer overrun");
514 connection->error = MPD_ERROR_BUFFEROVERRUN;
515 connection->doneProcessing = 1;
516 connection->doneListOk = 0;
519 bufferCheck = connection->buffer+connection->buflen;
520 tv.tv_sec = connection->timeout.tv_sec;
521 tv.tv_usec = connection->timeout.tv_usec;
523 FD_SET(connection->sock,&fds);
524 if((err = select(connection->sock+1,&fds,NULL,NULL,&tv) == 1)) {
525 readed = recv(connection->sock,
526 connection->buffer+connection->buflen,
527 MPD_BUFFER_MAX_LENGTH-connection->buflen,
529 if(readed<0 && SENDRECV_ERRNO_IGNORE) {
533 strcpy(connection->errorStr,"connection"
535 connection->error = MPD_ERROR_CONNCLOSED;
536 connection->doneProcessing = 1;
537 connection->doneListOk = 0;
540 connection->buflen+=readed;
541 connection->buffer[connection->buflen] = '\0';
543 else if(err<0 && SELECT_ERRNO_IGNORE) continue;
545 strcpy(connection->errorStr,"connection timeout");
546 connection->error = MPD_ERROR_TIMEOUT;
547 connection->doneProcessing = 1;
548 connection->doneListOk = 0;
554 output = connection->buffer+connection->bufstart;
555 connection->bufstart = rt - connection->buffer + 1;
557 if(strcmp(output,"OK")==0) {
558 if(connection->listOks > 0) {
559 strcpy(connection->errorStr, "expected more list_OK's");
560 connection->error = 1;
562 connection->listOks = 0;
563 connection->doneProcessing = 1;
564 connection->doneListOk = 0;
568 if(strcmp(output, "list_OK") == 0) {
569 if(!connection->listOks) {
570 strcpy(connection->errorStr,
571 "got an unexpected list_OK");
572 connection->error = 1;
575 connection->doneListOk = 1;
576 connection->listOks--;
581 if(strncmp(output,"ACK",strlen("ACK"))==0) {
586 strcpy(connection->errorStr, output);
587 connection->error = MPD_ERROR_ACK;
588 connection->errorCode = MPD_ACK_ERROR_UNK;
589 connection->errorAt = MPD_ERROR_AT_UNK;
590 connection->doneProcessing = 1;
591 connection->doneListOk = 0;
593 needle = strchr(output, '[');
595 val = strtol(needle+1, &test, 10);
596 if(*test != '@') return;
597 connection->errorCode = val;
598 val = strtol(test+1, &test, 10);
599 if(*test != ']') return;
600 connection->errorAt = val;
604 tok = strchr(output, ':');
612 connection->returnElement = mpd_newReturnElement(name,&(value[1]));
615 snprintf(connection->errorStr,MPD_BUFFER_MAX_LENGTH,
616 "error parsing: %s:%s",name,value);
617 connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0';
618 connection->error = 1;
622 void mpd_finishCommand(mpd_Connection * connection) {
623 while(!connection->doneProcessing) {
624 if(connection->doneListOk) connection->doneListOk = 0;
625 mpd_getNextReturnElement(connection);
629 static void mpd_finishListOkCommand(mpd_Connection * connection) {
630 while(!connection->doneProcessing && connection->listOks &&
631 !connection->doneListOk)
633 mpd_getNextReturnElement(connection);
637 int mpd_nextListOkCommand(mpd_Connection * connection) {
638 mpd_finishListOkCommand(connection);
639 if(!connection->doneProcessing) connection->doneListOk = 0;
640 if(connection->listOks == 0 || connection->doneProcessing) return -1;
644 void mpd_sendStatusCommand(mpd_Connection * connection) {
645 mpd_executeCommand(connection,"status\n");
648 mpd_Status * mpd_getStatus(mpd_Connection * connection) {
651 /*mpd_executeCommand(connection,"status\n");
653 if(connection->error) return NULL;*/
655 if(connection->doneProcessing || (connection->listOks &&
656 connection->doneListOk))
661 if(!connection->returnElement) mpd_getNextReturnElement(connection);
663 status = malloc(sizeof(mpd_Status));
667 status->playlist = -1;
668 status->playlistLength = -1;
672 status->elapsedTime = 0;
673 status->totalTime = 0;
675 status->sampleRate = 0;
677 status->channels = 0;
678 status->crossfade = -1;
679 status->error = NULL;
680 status->updatingDb = 0;
682 if(connection->error) {
686 while(connection->returnElement) {
687 mpd_ReturnElement * re = connection->returnElement;
688 if(strcmp(re->name,"volume")==0) {
689 status->volume = atoi(re->value);
691 else if(strcmp(re->name,"repeat")==0) {
692 status->repeat = atoi(re->value);
694 else if(strcmp(re->name,"random")==0) {
695 status->random = atoi(re->value);
697 else if(strcmp(re->name,"playlist")==0) {
698 status->playlist = strtol(re->value,NULL,10);
700 else if(strcmp(re->name,"playlistlength")==0) {
701 status->playlistLength = atoi(re->value);
703 else if(strcmp(re->name,"bitrate")==0) {
704 status->bitRate = atoi(re->value);
706 else if(strcmp(re->name,"state")==0) {
707 if(strcmp(re->value,"play")==0) {
708 status->state = MPD_STATUS_STATE_PLAY;
710 else if(strcmp(re->value,"stop")==0) {
711 status->state = MPD_STATUS_STATE_STOP;
713 else if(strcmp(re->value,"pause")==0) {
714 status->state = MPD_STATUS_STATE_PAUSE;
717 status->state = MPD_STATUS_STATE_UNKNOWN;
720 else if(strcmp(re->name,"song")==0) {
721 status->song = atoi(re->value);
723 else if(strcmp(re->name,"songid")==0) {
724 status->songid = atoi(re->value);
726 else if(strcmp(re->name,"time")==0) {
727 char * tok = strchr(re->value,':');
728 /* the second strchr below is a safety check */
729 if (tok && (strchr(tok,0) > (tok+1))) {
730 /* atoi stops at the first non-[0-9] char: */
731 status->elapsedTime = atoi(re->value);
732 status->totalTime = atoi(tok+1);
735 else if(strcmp(re->name,"error")==0) {
736 status->error = strdup(re->value);
738 else if(strcmp(re->name,"xfade")==0) {
739 status->crossfade = atoi(re->value);
741 else if(strcmp(re->name,"updating_db")==0) {
742 status->updatingDb = atoi(re->value);
744 else if(strcmp(re->name,"audio")==0) {
745 char * tok = strchr(re->value,':');
746 if (tok && (strchr(tok,0) > (tok+1))) {
747 status->sampleRate = atoi(re->value);
748 status->bits = atoi(++tok);
749 tok = strchr(tok,':');
750 if (tok && (strchr(tok,0) > (tok+1)))
751 status->channels = atoi(tok+1);
755 mpd_getNextReturnElement(connection);
756 if(connection->error) {
762 if(connection->error) {
766 else if(status->state<0) {
767 strcpy(connection->errorStr,"state not found");
768 connection->error = 1;
776 void mpd_freeStatus(mpd_Status * status) {
777 if(status->error) free(status->error);
781 void mpd_sendStatsCommand(mpd_Connection * connection) {
782 mpd_executeCommand(connection,"stats\n");
785 mpd_Stats * mpd_getStats(mpd_Connection * connection) {
788 /*mpd_executeCommand(connection,"stats\n");
790 if(connection->error) return NULL;*/
792 if(connection->doneProcessing || (connection->listOks &&
793 connection->doneListOk))
798 if(!connection->returnElement) mpd_getNextReturnElement(connection);
800 stats = malloc(sizeof(mpd_Stats));
801 stats->numberOfArtists = 0;
802 stats->numberOfAlbums = 0;
803 stats->numberOfSongs = 0;
805 stats->dbUpdateTime = 0;
807 stats->dbPlayTime = 0;
809 if(connection->error) {
813 while(connection->returnElement) {
814 mpd_ReturnElement * re = connection->returnElement;
815 if(strcmp(re->name,"artists")==0) {
816 stats->numberOfArtists = atoi(re->value);
818 else if(strcmp(re->name,"albums")==0) {
819 stats->numberOfAlbums = atoi(re->value);
821 else if(strcmp(re->name,"songs")==0) {
822 stats->numberOfSongs = atoi(re->value);
824 else if(strcmp(re->name,"uptime")==0) {
825 stats->uptime = strtol(re->value,NULL,10);
827 else if(strcmp(re->name,"db_update")==0) {
828 stats->dbUpdateTime = strtol(re->value,NULL,10);
830 else if(strcmp(re->name,"playtime")==0) {
831 stats->playTime = strtol(re->value,NULL,10);
833 else if(strcmp(re->name,"db_playtime")==0) {
834 stats->dbPlayTime = strtol(re->value,NULL,10);
837 mpd_getNextReturnElement(connection);
838 if(connection->error) {
844 if(connection->error) {
852 void mpd_freeStats(mpd_Stats * stats) {
856 static void mpd_initSong(mpd_Song * song) {
866 song->composer = NULL;
868 song->comment = NULL;
870 song->time = MPD_SONG_NO_TIME;
871 song->pos = MPD_SONG_NO_NUM;
872 song->id = MPD_SONG_NO_ID;
875 static void mpd_finishSong(mpd_Song * song) {
876 if(song->file) free(song->file);
877 if(song->artist) free(song->artist);
878 if(song->album) free(song->album);
879 if(song->title) free(song->title);
880 if(song->track) free(song->track);
881 if(song->name) free(song->name);
882 if(song->date) free(song->date);
883 if(song->genre) free(song->genre);
884 if(song->composer) free(song->composer);
885 if(song->disc) free(song->disc);
886 if(song->comment) free(song->comment);
889 mpd_Song * mpd_newSong(void) {
890 mpd_Song * ret = malloc(sizeof(mpd_Song));
897 void mpd_freeSong(mpd_Song * song) {
898 mpd_finishSong(song);
902 mpd_Song * mpd_songDup(mpd_Song * song) {
903 mpd_Song * ret = mpd_newSong();
905 if(song->file) ret->file = strdup(song->file);
906 if(song->artist) ret->artist = strdup(song->artist);
907 if(song->album) ret->album = strdup(song->album);
908 if(song->title) ret->title = strdup(song->title);
909 if(song->track) ret->track = strdup(song->track);
910 if(song->name) ret->name = strdup(song->name);
911 if(song->date) ret->date = strdup(song->date);
912 if(song->genre) ret->genre= strdup(song->genre);
913 if(song->composer) ret->composer= strdup(song->composer);
914 if(song->disc) ret->disc = strdup(song->disc);
915 if(song->comment) ret->comment = strdup(song->comment);
916 ret->time = song->time;
917 ret->pos = song->pos;
923 static void mpd_initDirectory(mpd_Directory * directory) {
924 directory->path = NULL;
927 static void mpd_finishDirectory(mpd_Directory * directory) {
928 if(directory->path) free(directory->path);
931 mpd_Directory * mpd_newDirectory(void) {
932 mpd_Directory * directory = malloc(sizeof(mpd_Directory));;
934 mpd_initDirectory(directory);
939 void mpd_freeDirectory(mpd_Directory * directory) {
940 mpd_finishDirectory(directory);
945 mpd_Directory * mpd_directoryDup(mpd_Directory * directory) {
946 mpd_Directory * ret = mpd_newDirectory();
948 if(directory->path) ret->path = strdup(directory->path);
953 static void mpd_initPlaylistFile(mpd_PlaylistFile * playlist) {
954 playlist->path = NULL;
957 static void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist) {
958 if(playlist->path) free(playlist->path);
961 mpd_PlaylistFile * mpd_newPlaylistFile(void) {
962 mpd_PlaylistFile * playlist = malloc(sizeof(mpd_PlaylistFile));
964 mpd_initPlaylistFile(playlist);
969 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist) {
970 mpd_finishPlaylistFile(playlist);
974 mpd_PlaylistFile * mpd_playlistFileDup(mpd_PlaylistFile * playlist) {
975 mpd_PlaylistFile * ret = mpd_newPlaylistFile();
977 if(playlist->path) ret->path = strdup(playlist->path);
982 static void mpd_initInfoEntity(mpd_InfoEntity * entity) {
983 entity->info.directory = NULL;
986 static void mpd_finishInfoEntity(mpd_InfoEntity * entity) {
987 if(entity->info.directory) {
988 if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
989 mpd_freeDirectory(entity->info.directory);
991 else if(entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
992 mpd_freeSong(entity->info.song);
994 else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
995 mpd_freePlaylistFile(entity->info.playlistFile);
1000 mpd_InfoEntity * mpd_newInfoEntity(void) {
1001 mpd_InfoEntity * entity = malloc(sizeof(mpd_InfoEntity));
1003 mpd_initInfoEntity(entity);
1008 void mpd_freeInfoEntity(mpd_InfoEntity * entity) {
1009 mpd_finishInfoEntity(entity);
1013 static void mpd_sendInfoCommand(mpd_Connection * connection, char * command) {
1014 mpd_executeCommand(connection,command);
1017 mpd_InfoEntity * mpd_getNextInfoEntity(mpd_Connection * connection) {
1018 mpd_InfoEntity * entity = NULL;
1020 if(connection->doneProcessing || (connection->listOks &&
1021 connection->doneListOk))
1026 if(!connection->returnElement) mpd_getNextReturnElement(connection);
1028 if(connection->returnElement) {
1029 if(strcmp(connection->returnElement->name,"file")==0) {
1030 entity = mpd_newInfoEntity();
1031 entity->type = MPD_INFO_ENTITY_TYPE_SONG;
1032 entity->info.song = mpd_newSong();
1033 entity->info.song->file =
1034 strdup(connection->returnElement->value);
1036 else if(strcmp(connection->returnElement->name,
1038 entity = mpd_newInfoEntity();
1039 entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
1040 entity->info.directory = mpd_newDirectory();
1041 entity->info.directory->path =
1042 strdup(connection->returnElement->value);
1044 else if(strcmp(connection->returnElement->name,"playlist")==0) {
1045 entity = mpd_newInfoEntity();
1046 entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
1047 entity->info.playlistFile = mpd_newPlaylistFile();
1048 entity->info.playlistFile->path =
1049 strdup(connection->returnElement->value);
1051 else if(strcmp(connection->returnElement->name, "cpos") == 0){
1052 entity = mpd_newInfoEntity();
1053 entity->type = MPD_INFO_ENTITY_TYPE_SONG;
1054 entity->info.song = mpd_newSong();
1055 entity->info.song->pos = atoi(connection->returnElement->value);
1058 connection->error = 1;
1059 strcpy(connection->errorStr,"problem parsing song info");
1065 mpd_getNextReturnElement(connection);
1066 while(connection->returnElement) {
1067 mpd_ReturnElement * re = connection->returnElement;
1069 if(strcmp(re->name,"file")==0) return entity;
1070 else if(strcmp(re->name,"directory")==0) return entity;
1071 else if(strcmp(re->name,"playlist")==0) return entity;
1072 else if(strcmp(re->name,"cpos")==0) return entity;
1074 if(entity->type == MPD_INFO_ENTITY_TYPE_SONG &&
1075 strlen(re->value)) {
1076 if(!entity->info.song->artist &&
1077 strcmp(re->name,"Artist")==0) {
1078 entity->info.song->artist = strdup(re->value);
1080 else if(!entity->info.song->album &&
1081 strcmp(re->name,"Album")==0) {
1082 entity->info.song->album = strdup(re->value);
1084 else if(!entity->info.song->title &&
1085 strcmp(re->name,"Title")==0) {
1086 entity->info.song->title = strdup(re->value);
1088 else if(!entity->info.song->track &&
1089 strcmp(re->name,"Track")==0) {
1090 entity->info.song->track = strdup(re->value);
1092 else if(!entity->info.song->name &&
1093 strcmp(re->name,"Name")==0) {
1094 entity->info.song->name = strdup(re->value);
1096 else if(entity->info.song->time==MPD_SONG_NO_TIME &&
1097 strcmp(re->name,"Time")==0) {
1098 entity->info.song->time = atoi(re->value);
1100 else if(entity->info.song->pos==MPD_SONG_NO_NUM &&
1101 strcmp(re->name,"Pos")==0) {
1102 entity->info.song->pos = atoi(re->value);
1104 else if(entity->info.song->id==MPD_SONG_NO_ID &&
1105 strcmp(re->name,"Id")==0) {
1106 entity->info.song->id = atoi(re->value);
1108 else if(!entity->info.song->date &&
1109 strcmp(re->name, "Date") == 0) {
1110 entity->info.song->date = strdup(re->value);
1112 else if(!entity->info.song->genre &&
1113 strcmp(re->name, "Genre") == 0) {
1114 entity->info.song->genre = strdup(re->value);
1116 else if(!entity->info.song->composer &&
1117 strcmp(re->name, "Composer") == 0) {
1118 entity->info.song->composer = strdup(re->value);
1120 else if(!entity->info.song->disc &&
1121 strcmp(re->name, "Disc") == 0) {
1122 entity->info.song->disc = strdup(re->value);
1124 else if(!entity->info.song->comment &&
1125 strcmp(re->name, "Comment") == 0) {
1126 entity->info.song->comment = strdup(re->value);
1129 else if(entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1131 else if(entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1134 mpd_getNextReturnElement(connection);
1140 static char * mpd_getNextReturnElementNamed(mpd_Connection * connection,
1143 if(connection->doneProcessing || (connection->listOks &&
1144 connection->doneListOk))
1149 mpd_getNextReturnElement(connection);
1150 while(connection->returnElement) {
1151 mpd_ReturnElement * re = connection->returnElement;
1153 if(strcmp(re->name,name)==0) return strdup(re->value);
1154 mpd_getNextReturnElement(connection);
1160 char * mpd_getNextTag(mpd_Connection * connection,int table) {
1161 if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
1163 return mpd_getNextReturnElementNamed(connection,mpdTagItemKeys[table]);
1168 char * mpd_getNextArtist(mpd_Connection * connection) {
1169 return mpd_getNextReturnElementNamed(connection,"Artist");
1172 char * mpd_getNextAlbum(mpd_Connection * connection) {
1173 return mpd_getNextReturnElementNamed(connection,"Album");
1176 void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos) {
1177 char * string = malloc(strlen("playlistinfo")+25);
1178 sprintf(string,"playlistinfo \"%i\"\n",songPos);
1179 mpd_sendInfoCommand(connection,string);
1183 void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id) {
1184 char * string = malloc(strlen("playlistid")+25);
1185 sprintf(string, "playlistid \"%i\"\n", id);
1186 mpd_sendInfoCommand(connection, string);
1190 void mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist) {
1191 char * string = malloc(strlen("plchanges")+25);
1192 sprintf(string,"plchanges \"%lld\"\n",playlist);
1193 mpd_sendInfoCommand(connection,string);
1197 void mpd_sendPlChangesPosIdCommand(mpd_Connection * connection, long long playlist) {
1198 char * string = malloc(strlen("plchangesposid")+25);
1199 sprintf(string,"plchangesposid \"%lld\"\n",playlist);
1200 mpd_sendInfoCommand(connection,string);
1204 void mpd_sendListallCommand(mpd_Connection * connection, const char * dir) {
1205 char * sDir = mpd_sanitizeArg(dir);
1206 char * string = malloc(strlen("listall")+strlen(sDir)+5);
1207 sprintf(string,"listall \"%s\"\n",sDir);
1208 mpd_sendInfoCommand(connection,string);
1213 void mpd_sendListallInfoCommand(mpd_Connection * connection, const char * dir) {
1214 char * sDir = mpd_sanitizeArg(dir);
1215 char * string = malloc(strlen("listallinfo")+strlen(sDir)+5);
1216 sprintf(string,"listallinfo \"%s\"\n",sDir);
1217 mpd_sendInfoCommand(connection,string);
1222 void mpd_sendLsInfoCommand(mpd_Connection * connection, const char * dir) {
1223 char * sDir = mpd_sanitizeArg(dir);
1224 char * string = malloc(strlen("lsinfo")+strlen(sDir)+5);
1225 sprintf(string,"lsinfo \"%s\"\n",sDir);
1226 mpd_sendInfoCommand(connection,string);
1231 void mpd_sendCurrentSongCommand(mpd_Connection * connection) {
1232 mpd_executeCommand(connection,"currentsong\n");
1235 void mpd_sendSearchCommand(mpd_Connection * connection, int table,
1240 char * sanitStr = mpd_sanitizeArg(str);
1241 if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
1242 else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
1243 else if(table == MPD_TABLE_TITLE) strcpy(st,"title");
1244 else if(table == MPD_TABLE_FILENAME) strcpy(st,"filename");
1246 connection->error = 1;
1247 strcpy(connection->errorStr,"unknown table for search");
1250 string = malloc(strlen("search")+strlen(sanitStr)+strlen(st)+6);
1251 sprintf(string,"search %s \"%s\"\n",st,sanitStr);
1252 mpd_sendInfoCommand(connection,string);
1257 void mpd_sendFindCommand(mpd_Connection * connection, int table,
1262 char * sanitStr = mpd_sanitizeArg(str);
1263 if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
1264 else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
1265 else if(table == MPD_TABLE_TITLE) strcpy(st,"title");
1267 connection->error = 1;
1268 strcpy(connection->errorStr,"unknown table for find");
1271 string = malloc(strlen("find")+strlen(sanitStr)+strlen(st)+6);
1272 sprintf(string,"find %s \"%s\"\n",st,sanitStr);
1273 mpd_sendInfoCommand(connection,string);
1278 void mpd_sendListCommand(mpd_Connection * connection, int table,
1283 if(table == MPD_TABLE_ARTIST) strcpy(st,"artist");
1284 else if(table == MPD_TABLE_ALBUM) strcpy(st,"album");
1286 connection->error = 1;
1287 strcpy(connection->errorStr,"unknown table for list");
1291 char * sanitArg1 = mpd_sanitizeArg(arg1);
1292 string = malloc(strlen("list")+strlen(sanitArg1)+strlen(st)+6);
1293 sprintf(string,"list %s \"%s\"\n",st,sanitArg1);
1297 string = malloc(strlen("list")+strlen(st)+3);
1298 sprintf(string,"list %s\n",st);
1300 mpd_sendInfoCommand(connection,string);
1304 void mpd_sendAddCommand(mpd_Connection * connection, const char * file) {
1305 char * sFile = mpd_sanitizeArg(file);
1306 char * string = malloc(strlen("add")+strlen(sFile)+5);
1307 sprintf(string,"add \"%s\"\n",sFile);
1308 mpd_executeCommand(connection,string);
1313 void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos) {
1314 char * string = malloc(strlen("delete")+25);
1315 sprintf(string,"delete \"%i\"\n",songPos);
1316 mpd_sendInfoCommand(connection,string);
1320 void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id) {
1321 char * string = malloc(strlen("deleteid")+25);
1322 sprintf(string, "deleteid \"%i\"\n", id);
1323 mpd_sendInfoCommand(connection,string);
1327 void mpd_sendSaveCommand(mpd_Connection * connection, const char * name) {
1328 char * sName = mpd_sanitizeArg(name);
1329 char * string = malloc(strlen("save")+strlen(sName)+5);
1330 sprintf(string,"save \"%s\"\n",sName);
1331 mpd_executeCommand(connection,string);
1336 void mpd_sendLoadCommand(mpd_Connection * connection, const char * name) {
1337 char * sName = mpd_sanitizeArg(name);
1338 char * string = malloc(strlen("load")+strlen(sName)+5);
1339 sprintf(string,"load \"%s\"\n",sName);
1340 mpd_executeCommand(connection,string);
1345 void mpd_sendRmCommand(mpd_Connection * connection, const char * name) {
1346 char * sName = mpd_sanitizeArg(name);
1347 char * string = malloc(strlen("rm")+strlen(sName)+5);
1348 sprintf(string,"rm \"%s\"\n",sName);
1349 mpd_executeCommand(connection,string);
1354 void mpd_sendShuffleCommand(mpd_Connection * connection) {
1355 mpd_executeCommand(connection,"shuffle\n");
1358 void mpd_sendClearCommand(mpd_Connection * connection) {
1359 mpd_executeCommand(connection,"clear\n");
1362 void mpd_sendPlayCommand(mpd_Connection * connection, int songPos) {
1363 char * string = malloc(strlen("play")+25);
1364 sprintf(string,"play \"%i\"\n",songPos);
1365 mpd_sendInfoCommand(connection,string);
1369 void mpd_sendPlayIdCommand(mpd_Connection * connection, int id) {
1370 char * string = malloc(strlen("playid")+25);
1371 sprintf(string,"playid \"%i\"\n",id);
1372 mpd_sendInfoCommand(connection,string);
1376 void mpd_sendStopCommand(mpd_Connection * connection) {
1377 mpd_executeCommand(connection,"stop\n");
1380 void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode) {
1381 char * string = malloc(strlen("pause")+25);
1382 sprintf(string,"pause \"%i\"\n",pauseMode);
1383 mpd_executeCommand(connection,string);
1387 void mpd_sendNextCommand(mpd_Connection * connection) {
1388 mpd_executeCommand(connection,"next\n");
1391 void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to) {
1392 char * string = malloc(strlen("move")+25);
1393 sprintf(string,"move \"%i\" \"%i\"\n",from,to);
1394 mpd_sendInfoCommand(connection,string);
1398 void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to) {
1399 char * string = malloc(strlen("moveid")+25);
1400 sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
1401 mpd_sendInfoCommand(connection,string);
1405 void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2) {
1406 char * string = malloc(strlen("swap")+25);
1407 sprintf(string,"swap \"%i\" \"%i\"\n",song1,song2);
1408 mpd_sendInfoCommand(connection,string);
1412 void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2) {
1413 char * string = malloc(strlen("swapid")+25);
1414 sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
1415 mpd_sendInfoCommand(connection,string);
1419 void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time) {
1420 char * string = malloc(strlen("seek")+25);
1421 sprintf(string,"seek \"%i\" \"%i\"\n",song,time);
1422 mpd_sendInfoCommand(connection,string);
1426 void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time) {
1427 char * string = malloc(strlen("seekid")+25);
1428 sprintf(string,"seekid \"%i\" \"%i\"\n",id,time);
1429 mpd_sendInfoCommand(connection,string);
1433 void mpd_sendUpdateCommand(mpd_Connection * connection, char * path) {
1434 char * sPath = mpd_sanitizeArg(path);
1435 char * string = malloc(strlen("update")+strlen(sPath)+5);
1436 sprintf(string,"update \"%s\"\n",sPath);
1437 mpd_sendInfoCommand(connection,string);
1442 int mpd_getUpdateId(mpd_Connection * connection) {
1446 jobid = mpd_getNextReturnElementNamed(connection,"updating_db");
1455 void mpd_sendPrevCommand(mpd_Connection * connection) {
1456 mpd_executeCommand(connection,"previous\n");
1459 void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode) {
1460 char * string = malloc(strlen("repeat")+25);
1461 sprintf(string,"repeat \"%i\"\n",repeatMode);
1462 mpd_executeCommand(connection,string);
1466 void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode) {
1467 char * string = malloc(strlen("random")+25);
1468 sprintf(string,"random \"%i\"\n",randomMode);
1469 mpd_executeCommand(connection,string);
1473 void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange) {
1474 char * string = malloc(strlen("setvol")+25);
1475 sprintf(string,"setvol \"%i\"\n",volumeChange);
1476 mpd_executeCommand(connection,string);
1480 void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange) {
1481 char * string = malloc(strlen("volume")+25);
1482 sprintf(string,"volume \"%i\"\n",volumeChange);
1483 mpd_executeCommand(connection,string);
1487 void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds) {
1488 char * string = malloc(strlen("crossfade")+25);
1489 sprintf(string,"crossfade \"%i\"\n",seconds);
1490 mpd_executeCommand(connection,string);
1494 void mpd_sendPasswordCommand(mpd_Connection * connection, const char * pass) {
1495 char * sPass = mpd_sanitizeArg(pass);
1496 char * string = malloc(strlen("password")+strlen(sPass)+5);
1497 sprintf(string,"password \"%s\"\n",sPass);
1498 mpd_executeCommand(connection,string);
1503 void mpd_sendCommandListBegin(mpd_Connection * connection) {
1504 if(connection->commandList) {
1505 strcpy(connection->errorStr,"already in command list mode");
1506 connection->error = 1;
1509 connection->commandList = COMMAND_LIST;
1510 mpd_executeCommand(connection,"command_list_begin\n");
1513 void mpd_sendCommandListOkBegin(mpd_Connection * connection) {
1514 if(connection->commandList) {
1515 strcpy(connection->errorStr,"already in command list mode");
1516 connection->error = 1;
1519 connection->commandList = COMMAND_LIST_OK;
1520 mpd_executeCommand(connection,"command_list_ok_begin\n");
1521 connection->listOks = 0;
1524 void mpd_sendCommandListEnd(mpd_Connection * connection) {
1525 if(!connection->commandList) {
1526 strcpy(connection->errorStr,"not in command list mode");
1527 connection->error = 1;
1530 connection->commandList = 0;
1531 mpd_executeCommand(connection,"command_list_end\n");
1534 void mpd_sendOutputsCommand(mpd_Connection * connection) {
1535 mpd_executeCommand(connection,"outputs\n");
1538 mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
1539 mpd_OutputEntity * output = NULL;
1541 if(connection->doneProcessing || (connection->listOks &&
1542 connection->doneListOk))
1547 if(connection->error) return NULL;
1549 output = malloc(sizeof(mpd_OutputEntity));
1551 output->name = NULL;
1552 output->enabled = 0;
1554 if(!connection->returnElement) mpd_getNextReturnElement(connection);
1556 while(connection->returnElement) {
1557 mpd_ReturnElement * re = connection->returnElement;
1558 if(strcmp(re->name,"outputid")==0) {
1559 if(output!=NULL && output->id>=0) return output;
1560 output->id = atoi(re->value);
1562 else if(strcmp(re->name,"outputname")==0) {
1563 output->name = strdup(re->value);
1565 else if(strcmp(re->name,"outputenabled")==0) {
1566 output->enabled = atoi(re->value);
1569 mpd_getNextReturnElement(connection);
1570 if(connection->error) {
1580 void mpd_sendEnableOutputCommand(mpd_Connection * connection, int outputId) {
1581 char * string = malloc(strlen("enableoutput")+25);
1582 sprintf(string,"enableoutput \"%i\"\n",outputId);
1583 mpd_executeCommand(connection,string);
1587 void mpd_sendDisableOutputCommand(mpd_Connection * connection, int outputId) {
1588 char * string = malloc(strlen("disableoutput")+25);
1589 sprintf(string,"disableoutput \"%i\"\n",outputId);
1590 mpd_executeCommand(connection,string);
1594 void mpd_freeOutputElement(mpd_OutputEntity * output) {
1600 * mpd_sendNotCommandsCommand
1601 * odd naming, but it gets the not allowed commands
1604 void mpd_sendNotCommandsCommand(mpd_Connection * connection) {
1605 mpd_executeCommand(connection,"notcommands\n");
1609 * mpd_sendCommandsCommand
1610 * odd naming, but it gets the allowed commands
1613 void mpd_sendCommandsCommand(mpd_Connection * connection) {
1614 mpd_executeCommand(connection,"commands\n");
1617 * Get the next returned command
1619 char * mpd_getNextCommand(mpd_Connection * connection) {
1620 return mpd_getNextReturnElementNamed(connection,"command");
1623 void mpd_startSearch(mpd_Connection * connection,int exact) {
1624 if(connection->request) {
1625 /* search/find allready in progress */
1626 /* TODO: set error here? */
1630 connection->request = strdup("find");
1633 connection->request = strdup("search");
1638 void mpd_startFieldSearch(mpd_Connection * connection,int field) {
1639 if(connection->request) {
1640 /* search/find allready in progress */
1641 /* TODO: set error here? */
1644 if(field < 0 || field >= MPD_TAG_NUM_OF_ITEM_TYPES) {
1645 /* set error here */
1649 connection->request = malloc(sizeof(char)*(
1650 /* length of the field name */
1651 strlen(mpdTagItemKeys[field])+
1652 /* "list"+space+\0 */
1655 sprintf(connection->request, "list %s", mpdTagItemKeys[field]);
1660 void mpd_addConstraintSearch(mpd_Connection *connection,
1665 if(!connection->request){
1671 if(field < 0 || field >= MPD_TAG_NUM_OF_ITEM_TYPES) {
1674 /* clean up the query */
1675 arg = mpd_sanitizeArg(name);
1676 /* create space for the query */
1677 connection->request = realloc(connection->request, (
1678 /* length of the old string */
1679 strlen(connection->request)+
1682 /* length of the field name */
1683 strlen(mpdTagItemKeys[field])+
1684 /* space plus starting " */
1686 /* length of search term */
1688 /* closign " +\0 that is added sprintf */
1691 /* and form the query */
1692 sprintf(connection->request, "%s %s \"%s\"",
1693 connection->request,
1694 mpdTagItemKeys[field],
1700 void mpd_commitSearch(mpd_Connection *connection)
1702 if(connection->request)
1704 int length = strlen(connection->request);
1705 /* fixing up the string for mpd to like */
1706 connection->request = realloc(connection->request,
1707 (length+ /* old length */
1708 2 /* closing \n and \0 */
1710 connection->request[length] = '\n';
1711 connection->request[length+1] = '\0';
1713 mpd_sendInfoCommand(connection, connection->request);
1714 /* clean up a bit */
1715 free(connection->request);
1716 connection->request = NULL;
1721 * @param connection a MpdConnection
1722 * @param path the path to the playlist.
1724 * List the content, with full metadata, of a stored playlist.
1727 void mpd_sendListPlaylistInfoCommand(mpd_Connection *connection, char *path)
1729 char *arg = mpd_sanitizeArg(path);
1730 char *query = malloc(strlen("listplaylistinfo")+strlen(arg)+5);
1731 sprintf(query, "listplaylistinfo \"%s\"\n",arg);
1732 mpd_sendInfoCommand(connection, query);
1738 * @param connection a MpdConnection
1739 * @param path the path to the playlist.
1741 * List the content of a stored playlist.
1744 void mpd_sendListPlaylistCommand(mpd_Connection *connection, char *path)
1746 char *arg = mpd_sanitizeArg(path);
1747 char *query = malloc(strlen("listplaylist")+strlen(arg)+5);
1748 sprintf(query, "listplaylist \"%s\"\n",arg);
1749 mpd_sendInfoCommand(connection, query);