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
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.
34 #include "libmpdclient.h"
37 #include <sys/types.h>
38 #include <sys/socket.h>
41 #include <sys/param.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
55 #define COMMAND_LIST 1
56 #define COMMAND_LIST_OK 2
59 int mpd_ipv6Supported()
62 s = socket(AF_INET6, SOCK_STREAM, 0);
71 char *mpd_sanitizeArg(const char *arg)
77 for (i = 0; i < strlen(arg); i++) {
78 if (arg[i] == '"' || arg[i] == '\\')
82 ret = malloc(strlen(arg) + count + 1);
85 for (i = 0; i < strlen(arg) + 1; i++) {
86 if (arg[i] == '"' || arg[i] == '\\') {
87 ret[i + count] = '\\';
90 ret[i + count] = arg[i];
96 mpd_ReturnElement *mpd_newReturnElement(const char *name,
99 mpd_ReturnElement *ret = malloc(sizeof(mpd_ReturnElement));
101 ret->name = strdup(name);
102 ret->value = strdup(value);
107 void mpd_freeReturnElement(mpd_ReturnElement * re)
114 void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout)
116 connection->timeout.tv_sec = (int) timeout;
117 connection->timeout.tv_usec = (int) (timeout * 1e6 -
118 connection->timeout.tv_sec *
122 mpd_Connection *mpd_newConnection(const char *host, int port,
127 struct sockaddr *dest;
128 #ifdef HAVE_SOCKLEN_T
133 struct sockaddr_in sin;
136 mpd_Connection *connection = malloc(sizeof(mpd_Connection));
140 struct sockaddr_in6 sin6;
142 strcpy(connection->buffer, "");
143 connection->buflen = 0;
144 connection->bufstart = 0;
145 strcpy(connection->errorStr, "");
146 connection->error = 0;
147 connection->doneProcessing = 0;
148 connection->commandList = 0;
149 connection->listOks = 0;
150 connection->doneListOk = 0;
151 connection->returnElement = NULL;
153 if (!(he = gethostbyname(host))) {
154 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
155 "host \"%s\" not found", host);
156 connection->error = MPD_ERROR_UNKHOST;
160 memset(&sin, 0, sizeof(struct sockaddr_in));
161 /*dest.sin_family = he->h_addrtype; */
162 sin.sin_family = AF_INET;
163 sin.sin_port = htons(port);
165 memset(&sin6, 0, sizeof(struct sockaddr_in6));
166 sin6.sin6_family = AF_INET6;
167 sin6.sin6_port = htons(port);
169 switch (he->h_addrtype) {
171 memcpy((char *) &sin.sin_addr.s_addr, (char *) he->h_addr,
173 dest = (struct sockaddr *) &sin;
174 destlen = sizeof(struct sockaddr_in);
178 if (!mpd_ipv6Supported()) {
179 strcpy(connection->errorStr,
180 "no IPv6 suuport but a "
181 "IPv6 address found\n");
182 connection->error = MPD_ERROR_SYSTEM;
185 memcpy((char *) &sin6.sin6_addr.s6_addr,
186 (char *) he->h_addr, he->h_length);
187 dest = (struct sockaddr *) &sin6;
188 destlen = sizeof(struct sockaddr_in6);
192 strcpy(connection->errorStr,
193 "address type is not IPv4 or " "IPv6\n");
194 connection->error = MPD_ERROR_SYSTEM;
199 if ((connection->sock =
200 socket(dest->sa_family, SOCK_STREAM, 0)) < 0) {
201 strcpy(connection->errorStr, "problems creating socket");
202 connection->error = MPD_ERROR_SYSTEM;
206 mpd_setConnectionTimeout(connection, timeout);
210 int flags = fcntl(connection->sock, F_GETFL, 0);
211 fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
213 if (connect(connection->sock, dest, destlen) < 0
214 && errno != EINPROGRESS) {
215 snprintf(connection->errorStr,
216 MPD_BUFFER_MAX_LENGTH,
217 "problems connecting to \"%s\" on port"
219 connection->error = MPD_ERROR_CONNPORT;
224 while (!(rt = strstr(connection->buffer, "\n"))) {
225 tv.tv_sec = connection->timeout.tv_sec;
226 tv.tv_usec = connection->timeout.tv_usec;
228 FD_SET(connection->sock, &fds);
230 select(connection->sock + 1, &fds, NULL, NULL,
233 readed = recv(connection->sock,
235 buffer[connection->buflen]),
236 MPD_BUFFER_MAX_LENGTH -
237 connection->buflen, 0);
239 snprintf(connection->errorStr,
240 MPD_BUFFER_MAX_LENGTH,
241 "problems getting a response from"
242 " \"%s\" on port %i", host, port);
243 connection->error = MPD_ERROR_NORESPONSE;
246 connection->buflen += readed;
247 connection->buffer[connection->buflen] = '\0';
248 tv.tv_sec = connection->timeout.tv_sec;
249 tv.tv_usec = connection->timeout.tv_usec;
250 } else if (err < 0) {
255 snprintf(connection->errorStr,
256 MPD_BUFFER_MAX_LENGTH,
257 "problems connecting to \"%s\" on port"
259 connection->error = MPD_ERROR_CONNPORT;
263 snprintf(connection->errorStr,
264 MPD_BUFFER_MAX_LENGTH,
265 "timeout in attempting to get a response from"
266 " \"%s\" on port %i", host, port);
267 connection->error = MPD_ERROR_NORESPONSE;
273 output = strdup(connection->buffer);
274 strcpy(connection->buffer, rt + 1);
275 connection->buflen = strlen(connection->buffer);
278 (output, MPD_WELCOME_MESSAGE, strlen(MPD_WELCOME_MESSAGE))) {
280 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
281 "mpd not running on port %i on host \"%s\"", port,
283 connection->error = MPD_ERROR_NOTMPD;
290 char *tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
294 for (i = 0; i < 3; i++) {
298 version[i] = strtok_r(tmp, search, &tok);
301 snprintf(connection->errorStr,
302 MPD_BUFFER_MAX_LENGTH,
303 "error parsing version number at "
306 (MPD_WELCOME_MESSAGE)]);
307 connection->error = MPD_ERROR_NOTMPD;
310 connection->version[i] =
311 strtol(version[i], &test, 10);
312 if (version[i] == test || *test != '\0') {
314 snprintf(connection->errorStr,
315 MPD_BUFFER_MAX_LENGTH,
316 "error parsing version number at "
319 (MPD_WELCOME_MESSAGE)]);
320 connection->error = MPD_ERROR_NOTMPD;
329 connection->doneProcessing = 1;
334 void mpd_clearError(mpd_Connection * connection)
336 connection->error = 0;
337 connection->errorStr[0] = '\0';
340 void mpd_closeConnection(mpd_Connection * connection)
342 close(connection->sock);
343 if (connection->returnElement)
344 free(connection->returnElement);
348 void mpd_executeCommand(mpd_Connection * connection, char *command)
353 char *commandPtr = command;
354 int commandLen = strlen(command);
356 if (!connection->doneProcessing && !connection->commandList) {
357 strcpy(connection->errorStr,
358 "not done processing current command");
359 connection->error = 1;
363 mpd_clearError(connection);
366 FD_SET(connection->sock, &fds);
367 tv.tv_sec = connection->timeout.tv_sec;
368 tv.tv_usec = connection->timeout.tv_usec;
371 select(connection->sock + 1, NULL, &fds, NULL, &tv) == 1)
372 || (ret == -1 && errno == EINTR)) {
374 send(connection->sock, commandPtr, commandLen,
377 if (ret == EAGAIN || ret == EINTR)
379 snprintf(connection->errorStr,
380 MPD_BUFFER_MAX_LENGTH,
381 "problems giving command \"%s\"",
383 connection->error = MPD_ERROR_SENDING;
394 if (commandLen > 0) {
396 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
397 "timeout sending command \"%s\"", command);
398 connection->error = MPD_ERROR_TIMEOUT;
402 if (!connection->commandList)
403 connection->doneProcessing = 0;
404 else if (connection->commandList == COMMAND_LIST_OK) {
405 connection->listOks++;
409 void mpd_getNextReturnElement(mpd_Connection * connection)
419 char *bufferCheck = NULL;
422 if (connection->returnElement)
423 mpd_freeReturnElement(connection->returnElement);
424 connection->returnElement = NULL;
426 if (connection->doneProcessing || (connection->listOks &&
427 connection->doneListOk)) {
428 strcpy(connection->errorStr,
429 "already done processing current command");
430 connection->error = 1;
434 bufferCheck = connection->buffer + connection->bufstart;
435 while (connection->bufstart >= connection->buflen ||
436 !(rt = strstr(bufferCheck, "\n"))) {
437 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
438 memmove(connection->buffer,
440 connection->bufstart,
441 connection->buflen - connection->bufstart +
443 bufferCheck -= connection->bufstart;
444 connection->buflen -= connection->bufstart;
445 connection->bufstart = 0;
447 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
448 strcpy(connection->errorStr, "buffer overrun");
449 connection->error = MPD_ERROR_BUFFEROVERRUN;
450 connection->doneProcessing = 1;
451 connection->doneListOk = 0;
454 bufferCheck += connection->buflen - connection->bufstart;
455 tv.tv_sec = connection->timeout.tv_sec;
456 tv.tv_usec = connection->timeout.tv_usec;
458 FD_SET(connection->sock, &fds);
460 select(connection->sock + 1, &fds, NULL, NULL,
463 recv(connection->sock,
464 connection->buffer + connection->buflen,
465 MPD_BUFFER_MAX_LENGTH -
466 connection->buflen, MSG_DONTWAIT);
468 && (errno == EAGAIN || errno == EINTR)) {
472 strcpy(connection->errorStr,
473 "connection" " closed");
474 connection->error = MPD_ERROR_CONNCLOSED;
475 connection->doneProcessing = 1;
476 connection->doneListOk = 0;
479 connection->buflen += readed;
480 connection->buffer[connection->buflen] = '\0';
481 } else if (err < 0 && errno == EINTR)
484 strcpy(connection->errorStr, "connection timeout");
485 connection->error = MPD_ERROR_TIMEOUT;
486 connection->doneProcessing = 1;
487 connection->doneListOk = 0;
493 output = connection->buffer + connection->bufstart;
494 connection->bufstart = rt - connection->buffer + 1;
496 if (strcmp(output, "OK") == 0) {
497 if (connection->listOks > 0) {
498 strcpy(connection->errorStr,
499 "expected more list_OK's");
500 connection->error = 1;
502 connection->listOks = 0;
503 connection->doneProcessing = 1;
504 connection->doneListOk = 0;
508 if (strcmp(output, "list_OK") == 0) {
509 if (!connection->listOks) {
510 strcpy(connection->errorStr,
511 "got an unexpected list_OK");
512 connection->error = 1;
514 connection->doneListOk = 1;
515 connection->listOks--;
520 if (strncmp(output, "ACK", strlen("ACK")) == 0) {
525 strcpy(connection->errorStr, output);
526 connection->error = MPD_ERROR_ACK;
527 connection->errorCode = MPD_ACK_ERROR_UNK;
528 connection->errorAt = MPD_ERROR_AT_UNK;
529 connection->doneProcessing = 1;
530 connection->doneListOk = 0;
532 needle = strchr(output, '[');
535 val = strtol(needle + 1, &test, 10);
538 connection->errorCode = val;
539 val = strtol(test + 1, &test, 10);
542 connection->errorAt = val;
546 name = strtok_r(output, ":", &tok);
547 if (name && (value = strtok_r(NULL, "", &tok)) && value[0] == ' ') {
548 connection->returnElement =
549 mpd_newReturnElement(name, &(value[1]));
551 if (!name || !value) {
552 snprintf(connection->errorStr,
553 MPD_BUFFER_MAX_LENGTH,
554 "error parsing: %s", output);
556 snprintf(connection->errorStr,
557 MPD_BUFFER_MAX_LENGTH,
558 "error parsing: %s:%s", name, value);
560 connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0';
561 connection->error = 1;
565 void mpd_finishCommand(mpd_Connection * connection)
567 while (!connection->doneProcessing) {
568 if (connection->doneListOk)
569 connection->doneListOk = 0;
570 mpd_getNextReturnElement(connection);
574 void mpd_finishListOkCommand(mpd_Connection * connection)
576 while (!connection->doneProcessing && connection->listOks &&
577 !connection->doneListOk) {
578 mpd_getNextReturnElement(connection);
582 int mpd_nextListOkCommand(mpd_Connection * connection)
584 mpd_finishListOkCommand(connection);
585 if (!connection->doneProcessing)
586 connection->doneListOk = 0;
587 if (connection->listOks == 0 || connection->doneProcessing)
592 void mpd_sendStatusCommand(mpd_Connection * connection)
594 mpd_executeCommand(connection, "status\n");
597 mpd_Status *mpd_getStatus(mpd_Connection * connection)
601 /*mpd_executeCommand(connection,"status\n");
603 if(connection->error) return NULL; */
605 if (connection->doneProcessing || (connection->listOks &&
606 connection->doneListOk)) {
610 if (!connection->returnElement)
611 mpd_getNextReturnElement(connection);
613 status = malloc(sizeof(mpd_Status));
617 status->playlist = -1;
618 status->playlistLength = -1;
621 status->elapsedTime = 0;
622 status->totalTime = 0;
624 status->sampleRate = 0;
626 status->channels = 0;
627 status->crossfade = -1;
628 status->error = NULL;
629 status->updatingDb = 0;
631 if (connection->error) {
635 while (connection->returnElement) {
636 mpd_ReturnElement *re = connection->returnElement;
637 if (strcmp(re->name, "volume") == 0) {
638 status->volume = atoi(re->value);
639 } else if (strcmp(re->name, "repeat") == 0) {
640 status->repeat = atoi(re->value);
641 } else if (strcmp(re->name, "random") == 0) {
642 status->random = atoi(re->value);
643 } else if (strcmp(re->name, "playlist") == 0) {
644 status->playlist = strtol(re->value, NULL, 10);
645 } else if (strcmp(re->name, "playlistlength") == 0) {
646 status->playlistLength = atoi(re->value);
647 } else if (strcmp(re->name, "bitrate") == 0) {
648 status->bitRate = atoi(re->value);
649 } else if (strcmp(re->name, "state") == 0) {
650 if (strcmp(re->value, "play") == 0) {
651 status->state = MPD_STATUS_STATE_PLAY;
652 } else if (strcmp(re->value, "stop") == 0) {
653 status->state = MPD_STATUS_STATE_STOP;
654 } else if (strcmp(re->value, "pause") == 0) {
655 status->state = MPD_STATUS_STATE_PAUSE;
657 status->state = MPD_STATUS_STATE_UNKNOWN;
659 } else if (strcmp(re->name, "song") == 0) {
660 status->song = atoi(re->value);
661 } else if (strcmp(re->name, "songid") == 0) {
662 status->songid = atoi(re->value);
663 } else if (strcmp(re->name, "time") == 0) {
667 copy = strdup(re->value);
668 temp = strtok_r(copy, ":", &tok);
670 status->elapsedTime = atoi(temp);
671 temp = strtok_r(NULL, "", &tok);
673 status->totalTime = atoi(temp);
676 } else if (strcmp(re->name, "error") == 0) {
677 status->error = strdup(re->value);
678 } else if (strcmp(re->name, "xfade") == 0) {
679 status->crossfade = atoi(re->value);
680 } else if (strcmp(re->name, "updating_db") == 0) {
681 status->updatingDb = atoi(re->value);
682 } else if (strcmp(re->name, "audio") == 0) {
686 copy = strdup(re->value);
687 temp = strtok_r(copy, ":", &tok);
689 status->sampleRate = atoi(temp);
690 temp = strtok_r(NULL, ":", &tok);
692 status->bits = atoi(temp);
693 temp = strtok_r(NULL, "", &tok);
702 mpd_getNextReturnElement(connection);
703 if (connection->error) {
709 if (connection->error) {
712 } else if (status->state < 0) {
713 strcpy(connection->errorStr, "state not found");
714 connection->error = 1;
722 void mpd_freeStatus(mpd_Status * status)
729 void mpd_sendStatsCommand(mpd_Connection * connection)
731 mpd_executeCommand(connection, "stats\n");
734 mpd_Stats *mpd_getStats(mpd_Connection * connection)
738 /*mpd_executeCommand(connection,"stats\n");
740 if(connection->error) return NULL; */
742 if (connection->doneProcessing || (connection->listOks &&
743 connection->doneListOk)) {
747 if (!connection->returnElement)
748 mpd_getNextReturnElement(connection);
750 stats = malloc(sizeof(mpd_Stats));
751 stats->numberOfArtists = 0;
752 stats->numberOfAlbums = 0;
753 stats->numberOfSongs = 0;
755 stats->dbUpdateTime = 0;
757 stats->dbPlayTime = 0;
759 if (connection->error) {
763 while (connection->returnElement) {
764 mpd_ReturnElement *re = connection->returnElement;
765 if (strcmp(re->name, "artists") == 0) {
766 stats->numberOfArtists = atoi(re->value);
767 } else if (strcmp(re->name, "albums") == 0) {
768 stats->numberOfAlbums = atoi(re->value);
769 } else if (strcmp(re->name, "songs") == 0) {
770 stats->numberOfSongs = atoi(re->value);
771 } else if (strcmp(re->name, "uptime") == 0) {
772 stats->uptime = strtol(re->value, NULL, 10);
773 } else if (strcmp(re->name, "db_update") == 0) {
774 stats->dbUpdateTime = strtol(re->value, NULL, 10);
775 } else if (strcmp(re->name, "playtime") == 0) {
776 stats->playTime = strtol(re->value, NULL, 10);
777 } else if (strcmp(re->name, "db_playtime") == 0) {
778 stats->dbPlayTime = strtol(re->value, NULL, 10);
781 mpd_getNextReturnElement(connection);
782 if (connection->error) {
788 if (connection->error) {
796 void mpd_freeStats(mpd_Stats * stats)
801 void mpd_initSong(mpd_Song * song)
809 song->time = MPD_SONG_NO_TIME;
810 song->pos = MPD_SONG_NO_NUM;
811 song->id = MPD_SONG_NO_ID;
814 void mpd_finishSong(mpd_Song * song)
830 mpd_Song *mpd_newSong()
832 mpd_Song *ret = malloc(sizeof(mpd_Song));
839 void mpd_freeSong(mpd_Song * song)
841 mpd_finishSong(song);
845 mpd_Song *mpd_songDup(mpd_Song * song)
847 mpd_Song *ret = mpd_newSong();
850 ret->file = strdup(song->file);
852 ret->artist = strdup(song->artist);
854 ret->album = strdup(song->album);
856 ret->title = strdup(song->title);
858 ret->track = strdup(song->track);
860 ret->name = strdup(song->name);
861 ret->time = song->time;
862 ret->pos = song->pos;
868 void mpd_initDirectory(mpd_Directory * directory)
870 directory->path = NULL;
873 void mpd_finishDirectory(mpd_Directory * directory)
876 free(directory->path);
879 mpd_Directory *mpd_newDirectory()
881 mpd_Directory *directory = malloc(sizeof(mpd_Directory));;
883 mpd_initDirectory(directory);
888 void mpd_freeDirectory(mpd_Directory * directory)
890 mpd_finishDirectory(directory);
895 mpd_Directory *mpd_directoryDup(mpd_Directory * directory)
897 mpd_Directory *ret = mpd_newDirectory();
900 ret->path = strdup(directory->path);
905 void mpd_initPlaylistFile(mpd_PlaylistFile * playlist)
907 playlist->path = NULL;
910 void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist)
913 free(playlist->path);
916 mpd_PlaylistFile *mpd_newPlaylistFile()
918 mpd_PlaylistFile *playlist = malloc(sizeof(mpd_PlaylistFile));
920 mpd_initPlaylistFile(playlist);
925 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist)
927 mpd_finishPlaylistFile(playlist);
931 mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile * playlist)
933 mpd_PlaylistFile *ret = mpd_newPlaylistFile();
936 ret->path = strdup(playlist->path);
941 void mpd_initInfoEntity(mpd_InfoEntity * entity)
943 entity->info.directory = NULL;
946 void mpd_finishInfoEntity(mpd_InfoEntity * entity)
948 if (entity->info.directory) {
949 if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
950 mpd_freeDirectory(entity->info.directory);
951 } else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
952 mpd_freeSong(entity->info.song);
953 } else if (entity->type ==
954 MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
955 mpd_freePlaylistFile(entity->info.playlistFile);
960 mpd_InfoEntity *mpd_newInfoEntity()
962 mpd_InfoEntity *entity = malloc(sizeof(mpd_InfoEntity));
964 mpd_initInfoEntity(entity);
969 void mpd_freeInfoEntity(mpd_InfoEntity * entity)
971 mpd_finishInfoEntity(entity);
975 void mpd_sendInfoCommand(mpd_Connection * connection, char *command)
977 mpd_executeCommand(connection, command);
980 mpd_InfoEntity *mpd_getNextInfoEntity(mpd_Connection * connection)
982 mpd_InfoEntity *entity = NULL;
984 if (connection->doneProcessing || (connection->listOks &&
985 connection->doneListOk)) {
989 if (!connection->returnElement)
990 mpd_getNextReturnElement(connection);
992 if (connection->returnElement) {
993 if (strcmp(connection->returnElement->name, "file") == 0) {
994 entity = mpd_newInfoEntity();
995 entity->type = MPD_INFO_ENTITY_TYPE_SONG;
996 entity->info.song = mpd_newSong();
997 entity->info.song->file =
998 strdup(connection->returnElement->value);
1001 (connection->returnElement->name,
1002 "directory") == 0) {
1003 entity = mpd_newInfoEntity();
1004 entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
1005 entity->info.directory = mpd_newDirectory();
1006 entity->info.directory->path =
1007 strdup(connection->returnElement->value);
1009 if (strcmp(connection->returnElement->name, "playlist")
1011 entity = mpd_newInfoEntity();
1012 entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
1013 entity->info.playlistFile = mpd_newPlaylistFile();
1014 entity->info.playlistFile->path =
1015 strdup(connection->returnElement->value);
1017 connection->error = 1;
1018 strcpy(connection->errorStr,
1019 "problem parsing song info");
1025 mpd_getNextReturnElement(connection);
1026 while (connection->returnElement) {
1027 mpd_ReturnElement *re = connection->returnElement;
1029 if (strcmp(re->name, "file") == 0)
1031 else if (strcmp(re->name, "directory") == 0)
1033 else if (strcmp(re->name, "playlist") == 0)
1036 if (entity->type == MPD_INFO_ENTITY_TYPE_SONG
1037 && strlen(re->value)) {
1038 if (!entity->info.song->artist
1039 && strcmp(re->name, "Artist") == 0) {
1040 entity->info.song->artist =
1042 } else if (!entity->info.song->album
1043 && strcmp(re->name, "Album") == 0) {
1044 entity->info.song->album =
1046 } else if (!entity->info.song->title
1047 && strcmp(re->name, "Title") == 0) {
1048 entity->info.song->title =
1050 } else if (!entity->info.song->track
1051 && strcmp(re->name, "Track") == 0) {
1052 entity->info.song->track =
1054 } else if (!entity->info.song->name
1055 && strcmp(re->name, "Name") == 0) {
1056 entity->info.song->name =
1058 } else if (entity->info.song->time ==
1060 && strcmp(re->name, "Time") == 0) {
1061 entity->info.song->time = atoi(re->value);
1062 } else if (entity->info.song->pos ==
1064 && strcmp(re->name, "Pos") == 0) {
1065 entity->info.song->pos = atoi(re->value);
1066 } else if (entity->info.song->id == MPD_SONG_NO_ID
1067 && strcmp(re->name, "Id") == 0) {
1068 entity->info.song->id = atoi(re->value);
1070 } else if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1071 } else if (entity->type ==
1072 MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1075 mpd_getNextReturnElement(connection);
1081 char *mpd_getNextReturnElementNamed(mpd_Connection * connection,
1084 if (connection->doneProcessing || (connection->listOks &&
1085 connection->doneListOk)) {
1089 mpd_getNextReturnElement(connection);
1090 while (connection->returnElement) {
1091 mpd_ReturnElement *re = connection->returnElement;
1093 if (strcmp(re->name, name) == 0)
1094 return strdup(re->value);
1095 mpd_getNextReturnElement(connection);
1101 char *mpd_getNextArtist(mpd_Connection * connection)
1103 return mpd_getNextReturnElementNamed(connection, "Artist");
1106 char *mpd_getNextAlbum(mpd_Connection * connection)
1108 return mpd_getNextReturnElementNamed(connection, "Album");
1111 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);
1119 void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id)
1121 char *string = malloc(strlen("playlistid") + 25);
1122 sprintf(string, "playlistid \"%i\"\n", id);
1123 mpd_sendInfoCommand(connection, string);
1128 mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist)
1130 char *string = malloc(strlen("plchanges") + 25);
1131 sprintf(string, "plchanges \"%lld\"\n", playlist);
1132 mpd_sendInfoCommand(connection, string);
1136 void mpd_sendListallCommand(mpd_Connection * connection, const char *dir)
1138 char *sDir = mpd_sanitizeArg(dir);
1139 char *string = malloc(strlen("listall") + strlen(sDir) + 5);
1140 sprintf(string, "listall \"%s\"\n", sDir);
1141 mpd_sendInfoCommand(connection, string);
1147 mpd_sendListallInfoCommand(mpd_Connection * connection, const char *dir)
1149 char *sDir = mpd_sanitizeArg(dir);
1150 char *string = malloc(strlen("listallinfo") + strlen(sDir) + 5);
1151 sprintf(string, "listallinfo \"%s\"\n", sDir);
1152 mpd_sendInfoCommand(connection, string);
1157 void mpd_sendLsInfoCommand(mpd_Connection * connection, const char *dir)
1159 char *sDir = mpd_sanitizeArg(dir);
1160 char *string = malloc(strlen("lsinfo") + strlen(sDir) + 5);
1161 sprintf(string, "lsinfo \"%s\"\n", sDir);
1162 mpd_sendInfoCommand(connection, string);
1167 void mpd_sendCurrentSongCommand(mpd_Connection * connection)
1169 mpd_executeCommand(connection, "currentsong\n");
1173 mpd_sendSearchCommand(mpd_Connection * connection, int table,
1178 char *sanitStr = mpd_sanitizeArg(str);
1179 if (table == MPD_TABLE_ARTIST)
1180 strcpy(st, "artist");
1181 else if (table == MPD_TABLE_ALBUM)
1182 strcpy(st, "album");
1183 else if (table == MPD_TABLE_TITLE)
1184 strcpy(st, "title");
1185 else if (table == MPD_TABLE_FILENAME)
1186 strcpy(st, "filename");
1188 connection->error = 1;
1189 strcpy(connection->errorStr, "unknown table for search");
1193 malloc(strlen("search") + strlen(sanitStr) + strlen(st) + 6);
1194 sprintf(string, "search %s \"%s\"\n", st, sanitStr);
1195 mpd_sendInfoCommand(connection, string);
1201 mpd_sendFindCommand(mpd_Connection * connection, int table,
1206 char *sanitStr = mpd_sanitizeArg(str);
1207 if (table == MPD_TABLE_ARTIST)
1208 strcpy(st, "artist");
1209 else if (table == MPD_TABLE_ALBUM)
1210 strcpy(st, "album");
1211 else if (table == MPD_TABLE_TITLE)
1212 strcpy(st, "title");
1214 connection->error = 1;
1215 strcpy(connection->errorStr, "unknown table for find");
1219 malloc(strlen("find") + strlen(sanitStr) + strlen(st) + 6);
1220 sprintf(string, "find %s \"%s\"\n", st, sanitStr);
1221 mpd_sendInfoCommand(connection, string);
1227 mpd_sendListCommand(mpd_Connection * connection, int table,
1232 if (table == MPD_TABLE_ARTIST)
1233 strcpy(st, "artist");
1234 else if (table == MPD_TABLE_ALBUM)
1235 strcpy(st, "album");
1237 connection->error = 1;
1238 strcpy(connection->errorStr, "unknown table for list");
1242 char *sanitArg1 = mpd_sanitizeArg(arg1);
1244 malloc(strlen("list") + strlen(sanitArg1) +
1246 sprintf(string, "list %s \"%s\"\n", st, sanitArg1);
1249 string = malloc(strlen("list") + strlen(st) + 3);
1250 sprintf(string, "list %s\n", st);
1252 mpd_sendInfoCommand(connection, string);
1256 void mpd_sendAddCommand(mpd_Connection * connection, const char *file)
1258 char *sFile = mpd_sanitizeArg(file);
1259 char *string = malloc(strlen("add") + strlen(sFile) + 5);
1260 sprintf(string, "add \"%s\"\n", sFile);
1261 mpd_executeCommand(connection, string);
1266 void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos)
1268 char *string = malloc(strlen("delete") + 25);
1269 sprintf(string, "delete \"%i\"\n", songPos);
1270 mpd_sendInfoCommand(connection, string);
1274 void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id)
1276 char *string = malloc(strlen("deleteid") + 25);
1277 sprintf(string, "deleteid \"%i\"\n", id);
1278 mpd_sendInfoCommand(connection, string);
1282 void mpd_sendSaveCommand(mpd_Connection * connection, const char *name)
1284 char *sName = mpd_sanitizeArg(name);
1285 char *string = malloc(strlen("save") + strlen(sName) + 5);
1286 sprintf(string, "save \"%s\"\n", sName);
1287 mpd_executeCommand(connection, string);
1292 void mpd_sendLoadCommand(mpd_Connection * connection, const char *name)
1294 char *sName = mpd_sanitizeArg(name);
1295 char *string = malloc(strlen("load") + strlen(sName) + 5);
1296 sprintf(string, "load \"%s\"\n", sName);
1297 mpd_executeCommand(connection, string);
1302 void mpd_sendRmCommand(mpd_Connection * connection, const char *name)
1304 char *sName = mpd_sanitizeArg(name);
1305 char *string = malloc(strlen("rm") + strlen(sName) + 5);
1306 sprintf(string, "rm \"%s\"\n", sName);
1307 mpd_executeCommand(connection, string);
1312 void mpd_sendShuffleCommand(mpd_Connection * connection)
1314 mpd_executeCommand(connection, "shuffle\n");
1317 void mpd_sendClearCommand(mpd_Connection * connection)
1319 mpd_executeCommand(connection, "clear\n");
1322 void mpd_sendPlayCommand(mpd_Connection * connection, int songPos)
1324 char *string = malloc(strlen("play") + 25);
1325 sprintf(string, "play \"%i\"\n", songPos);
1326 mpd_sendInfoCommand(connection, string);
1330 void mpd_sendPlayIdCommand(mpd_Connection * connection, int id)
1332 char *string = malloc(strlen("playid") + 25);
1333 sprintf(string, "playid \"%i\"\n", id);
1334 mpd_sendInfoCommand(connection, string);
1338 void mpd_sendStopCommand(mpd_Connection * connection)
1340 mpd_executeCommand(connection, "stop\n");
1343 void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode)
1345 char *string = malloc(strlen("pause") + 25);
1346 sprintf(string, "pause \"%i\"\n", pauseMode);
1347 mpd_executeCommand(connection, string);
1351 void mpd_sendNextCommand(mpd_Connection * connection)
1353 mpd_executeCommand(connection, "next\n");
1356 void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to)
1358 char *string = malloc(strlen("move") + 25);
1359 sprintf(string, "move \"%i\" \"%i\"\n", from, to);
1360 mpd_sendInfoCommand(connection, string);
1364 void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to)
1366 char *string = malloc(strlen("moveid") + 25);
1367 sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
1368 mpd_sendInfoCommand(connection, string);
1372 void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2)
1374 char *string = malloc(strlen("swap") + 25);
1375 sprintf(string, "swap \"%i\" \"%i\"\n", song1, song2);
1376 mpd_sendInfoCommand(connection, string);
1380 void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2)
1382 char *string = malloc(strlen("swapid") + 25);
1383 sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
1384 mpd_sendInfoCommand(connection, string);
1388 void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time)
1390 char *string = malloc(strlen("seek") + 25);
1391 sprintf(string, "seek \"%i\" \"%i\"\n", song, time);
1392 mpd_sendInfoCommand(connection, string);
1396 void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time)
1398 char *string = malloc(strlen("seekid") + 25);
1399 sprintf(string, "seekid \"%i\" \"%i\"\n", id, time);
1400 mpd_sendInfoCommand(connection, string);
1404 void mpd_sendUpdateCommand(mpd_Connection * connection, char *path)
1406 char *sPath = mpd_sanitizeArg(path);
1407 char *string = malloc(strlen("update") + strlen(sPath) + 5);
1408 sprintf(string, "update \"%s\"\n", sPath);
1409 mpd_sendInfoCommand(connection, string);
1414 int mpd_getUpdateId(mpd_Connection * connection)
1419 jobid = mpd_getNextReturnElementNamed(connection, "updating_db");
1428 void mpd_sendPrevCommand(mpd_Connection * connection)
1430 mpd_executeCommand(connection, "previous\n");
1433 void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode)
1435 char *string = malloc(strlen("repeat") + 25);
1436 sprintf(string, "repeat \"%i\"\n", repeatMode);
1437 mpd_executeCommand(connection, string);
1441 void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode)
1443 char *string = malloc(strlen("random") + 25);
1444 sprintf(string, "random \"%i\"\n", randomMode);
1445 mpd_executeCommand(connection, string);
1449 void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange)
1451 char *string = malloc(strlen("setvol") + 25);
1452 sprintf(string, "setvol \"%i\"\n", volumeChange);
1453 mpd_executeCommand(connection, string);
1457 void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange)
1459 char *string = malloc(strlen("volume") + 25);
1460 sprintf(string, "volume \"%i\"\n", volumeChange);
1461 mpd_executeCommand(connection, string);
1465 void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds)
1467 char *string = malloc(strlen("crossfade") + 25);
1468 sprintf(string, "crossfade \"%i\"\n", seconds);
1469 mpd_executeCommand(connection, string);
1473 void mpd_sendPasswordCommand(mpd_Connection * connection, const char *pass)
1475 char *sPass = mpd_sanitizeArg(pass);
1476 char *string = malloc(strlen("password") + strlen(sPass) + 5);
1477 sprintf(string, "password \"%s\"\n", sPass);
1478 mpd_executeCommand(connection, string);
1483 void mpd_sendCommandListBegin(mpd_Connection * connection)
1485 if (connection->commandList) {
1486 strcpy(connection->errorStr,
1487 "already in command list mode");
1488 connection->error = 1;
1491 connection->commandList = COMMAND_LIST;
1492 mpd_executeCommand(connection, "command_list_begin\n");
1495 void mpd_sendCommandListOkBegin(mpd_Connection * connection)
1497 if (connection->commandList) {
1498 strcpy(connection->errorStr,
1499 "already in command list mode");
1500 connection->error = 1;
1503 connection->commandList = COMMAND_LIST_OK;
1504 mpd_executeCommand(connection, "command_list_ok_begin\n");
1505 connection->listOks = 0;
1508 void mpd_sendCommandListEnd(mpd_Connection * connection)
1510 if (!connection->commandList) {
1511 strcpy(connection->errorStr, "not in command list mode");
1512 connection->error = 1;
1515 connection->commandList = 0;
1516 mpd_executeCommand(connection, "command_list_end\n");