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>
48 #include <sys/signal.h>
57 static char sigpipe = 0;
59 #define COMMAND_LIST 1
60 #define COMMAND_LIST_OK 2
63 int mpd_ipv6Supported()
66 s = socket(AF_INET6, SOCK_STREAM, 0);
75 char *mpd_sanitizeArg(const char *arg)
81 for (i = 0; i < strlen(arg); i++) {
82 if (arg[i] == '"' || arg[i] == '\\')
86 ret = malloc(strlen(arg) + count + 1);
89 for (i = 0; i < strlen(arg) + 1; i++) {
90 if (arg[i] == '"' || arg[i] == '\\') {
91 ret[i + count] = '\\';
94 ret[i + count] = arg[i];
100 mpd_ReturnElement *mpd_newReturnElement(const char *name,
103 mpd_ReturnElement *ret = malloc(sizeof(mpd_ReturnElement));
105 ret->name = strdup(name);
106 ret->value = strdup(value);
111 void mpd_freeReturnElement(mpd_ReturnElement * re)
118 void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout)
120 connection->timeout.tv_sec = (int) timeout;
121 connection->timeout.tv_usec = (int) (timeout * 1e6 -
122 connection->timeout.tv_sec *
126 mpd_Connection *mpd_newConnection(const char *host, int port,
131 struct sockaddr *dest;
132 #ifdef HAVE_SOCKLEN_T
137 struct sockaddr_in sin;
140 mpd_Connection *connection = malloc(sizeof(mpd_Connection));
143 struct sigaction sapipe; /* definition of signal action */
146 struct sockaddr_in6 sin6;
148 strcpy(connection->buffer, "");
149 connection->buflen = 0;
150 connection->bufstart = 0;
151 strcpy(connection->errorStr, "");
152 connection->error = 0;
153 connection->doneProcessing = 0;
154 connection->commandList = 0;
155 connection->listOks = 0;
156 connection->doneListOk = 0;
157 connection->returnElement = NULL;
160 if (!(he = gethostbyname(host))) {
161 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
162 "host \"%s\" not found", host);
163 connection->error = MPD_ERROR_UNKHOST;
167 memset(&sin, 0, sizeof(struct sockaddr_in));
168 /*dest.sin_family = he->h_addrtype; */
169 sin.sin_family = AF_INET;
170 sin.sin_port = htons(port);
172 memset(&sin6, 0, sizeof(struct sockaddr_in6));
173 sin6.sin6_family = AF_INET6;
174 sin6.sin6_port = htons(port);
176 switch (he->h_addrtype) {
178 memcpy((char *) &sin.sin_addr.s_addr, (char *) he->h_addr,
180 dest = (struct sockaddr *) &sin;
181 destlen = sizeof(struct sockaddr_in);
185 if (!mpd_ipv6Supported()) {
186 strcpy(connection->errorStr,
187 "no IPv6 suuport but a "
188 "IPv6 address found\n");
189 connection->error = MPD_ERROR_SYSTEM;
192 memcpy((char *) &sin6.sin6_addr.s6_addr,
193 (char *) he->h_addr, he->h_length);
194 dest = (struct sockaddr *) &sin6;
195 destlen = sizeof(struct sockaddr_in6);
199 strcpy(connection->errorStr,
200 "address type is not IPv4 or " "IPv6\n");
201 connection->error = MPD_ERROR_SYSTEM;
206 if ((connection->sock =
207 socket(dest->sa_family, SOCK_STREAM, 0)) < 0) {
208 strcpy(connection->errorStr, "problems creating socket");
209 connection->error = MPD_ERROR_SYSTEM;
213 mpd_setConnectionTimeout(connection, timeout);
215 /* install the signal handler */
216 sapipe.sa_handler = mpd_signalHandler;
217 // sapipe.sa_mask = 0;
219 sigaction(SIGPIPE,&sapipe,NULL);
223 int flags = fcntl(connection->sock, F_GETFL, 0);
224 fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
226 if (connect(connection->sock, dest, destlen) < 0
227 && errno != EINPROGRESS) {
228 snprintf(connection->errorStr,
229 MPD_BUFFER_MAX_LENGTH,
230 "problems connecting to \"%s\" on port"
232 connection->error = MPD_ERROR_CONNPORT;
237 while (!(rt = strstr(connection->buffer, "\n"))) {
238 tv.tv_sec = connection->timeout.tv_sec;
239 tv.tv_usec = connection->timeout.tv_usec;
241 FD_SET(connection->sock, &fds);
243 select(connection->sock + 1, &fds, NULL, NULL,
246 readed = recv(connection->sock,
248 buffer[connection->buflen]),
249 MPD_BUFFER_MAX_LENGTH -
250 connection->buflen, 0);
252 snprintf(connection->errorStr,
253 MPD_BUFFER_MAX_LENGTH,
254 "problems getting a response from"
255 " \"%s\" on port %i", host, port);
256 connection->error = MPD_ERROR_NORESPONSE;
259 connection->buflen += readed;
260 connection->buffer[connection->buflen] = '\0';
261 tv.tv_sec = connection->timeout.tv_sec;
262 tv.tv_usec = connection->timeout.tv_usec;
263 } else if (err < 0) {
268 snprintf(connection->errorStr,
269 MPD_BUFFER_MAX_LENGTH,
270 "problems connecting to \"%s\" on port"
272 connection->error = MPD_ERROR_CONNPORT;
276 snprintf(connection->errorStr,
277 MPD_BUFFER_MAX_LENGTH,
278 "timeout in attempting to get a response from"
279 " \"%s\" on port %i", host, port);
280 connection->error = MPD_ERROR_NORESPONSE;
286 output = strdup(connection->buffer);
287 strcpy(connection->buffer, rt + 1);
288 connection->buflen = strlen(connection->buffer);
291 (output, MPD_WELCOME_MESSAGE, strlen(MPD_WELCOME_MESSAGE))) {
293 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
294 "mpd not running on port %i on host \"%s\"", port,
296 connection->error = MPD_ERROR_NOTMPD;
303 char *tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
307 for (i = 0; i < 3; i++) {
311 version[i] = strtok_r(tmp, search, &tok);
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;
323 connection->version[i] =
324 strtol(version[i], &test, 10);
325 if (version[i] == test || *test != '\0') {
327 snprintf(connection->errorStr,
328 MPD_BUFFER_MAX_LENGTH,
329 "error parsing version number at "
332 (MPD_WELCOME_MESSAGE)]);
333 connection->error = MPD_ERROR_NOTMPD;
342 connection->doneProcessing = 1;
347 void mpd_clearError(mpd_Connection * connection)
349 connection->error = 0;
350 connection->errorStr[0] = '\0';
353 void mpd_closeConnection(mpd_Connection * connection)
355 close(connection->sock);
356 if (connection->returnElement)
357 free(connection->returnElement);
361 void mpd_executeCommand(mpd_Connection * connection, char *command)
366 char *commandPtr = command;
367 int commandLen = strlen(command);
369 if (!connection->doneProcessing && !connection->commandList) {
370 strcpy(connection->errorStr,
371 "not done processing current command");
372 connection->error = 1;
376 mpd_clearError(connection);
379 FD_SET(connection->sock, &fds);
380 tv.tv_sec = connection->timeout.tv_sec;
381 tv.tv_usec = connection->timeout.tv_usec;
385 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH, "got SIGINT");
386 connection->error = MPD_ERROR_SENDING;
389 while ((ret = select(connection->sock + 1, NULL, &fds, NULL, &tv) == 1) || (ret == -1 && errno == EINTR)) {
392 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH, "got SIGINT");
393 connection->error = MPD_ERROR_SENDING;
396 ret = send(connection->sock, commandPtr, commandLen, MSG_DONTWAIT);
398 if (ret == EAGAIN || ret == EINTR)
400 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH, "problems giving command \"%s\"", command);
401 connection->error = MPD_ERROR_SENDING;
412 if (commandLen > 0) {
414 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
415 "timeout sending command \"%s\"", command);
416 connection->error = MPD_ERROR_TIMEOUT;
420 if (!connection->commandList)
421 connection->doneProcessing = 0;
422 else if (connection->commandList == COMMAND_LIST_OK) {
423 connection->listOks++;
427 void mpd_getNextReturnElement(mpd_Connection * connection)
437 char *bufferCheck = NULL;
440 if (connection->returnElement)
441 mpd_freeReturnElement(connection->returnElement);
442 connection->returnElement = NULL;
444 if (connection->doneProcessing || (connection->listOks &&
445 connection->doneListOk)) {
446 strcpy(connection->errorStr,
447 "already done processing current command");
448 connection->error = 1;
452 bufferCheck = connection->buffer + connection->bufstart;
453 while (connection->bufstart >= connection->buflen ||
454 !(rt = strstr(bufferCheck, "\n"))) {
455 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
456 memmove(connection->buffer,
458 connection->bufstart,
459 connection->buflen - connection->bufstart +
461 bufferCheck -= connection->bufstart;
462 connection->buflen -= connection->bufstart;
463 connection->bufstart = 0;
465 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
466 strcpy(connection->errorStr, "buffer overrun");
467 connection->error = MPD_ERROR_BUFFEROVERRUN;
468 connection->doneProcessing = 1;
469 connection->doneListOk = 0;
472 bufferCheck += connection->buflen - connection->bufstart;
473 tv.tv_sec = connection->timeout.tv_sec;
474 tv.tv_usec = connection->timeout.tv_usec;
476 FD_SET(connection->sock, &fds);
478 select(connection->sock + 1, &fds, NULL, NULL,
481 recv(connection->sock,
482 connection->buffer + connection->buflen,
483 MPD_BUFFER_MAX_LENGTH -
484 connection->buflen, MSG_DONTWAIT);
486 && (errno == EAGAIN || errno == EINTR)) {
490 strcpy(connection->errorStr,
491 "connection" " closed");
492 connection->error = MPD_ERROR_CONNCLOSED;
493 connection->doneProcessing = 1;
494 connection->doneListOk = 0;
497 connection->buflen += readed;
498 connection->buffer[connection->buflen] = '\0';
499 } else if (err < 0 && errno == EINTR)
502 strcpy(connection->errorStr, "connection timeout");
503 connection->error = MPD_ERROR_TIMEOUT;
504 connection->doneProcessing = 1;
505 connection->doneListOk = 0;
511 output = connection->buffer + connection->bufstart;
512 connection->bufstart = rt - connection->buffer + 1;
514 if (strcmp(output, "OK") == 0) {
515 if (connection->listOks > 0) {
516 strcpy(connection->errorStr,
517 "expected more list_OK's");
518 connection->error = 1;
520 connection->listOks = 0;
521 connection->doneProcessing = 1;
522 connection->doneListOk = 0;
526 if (strcmp(output, "list_OK") == 0) {
527 if (!connection->listOks) {
528 strcpy(connection->errorStr,
529 "got an unexpected list_OK");
530 connection->error = 1;
532 connection->doneListOk = 1;
533 connection->listOks--;
538 if (strncmp(output, "ACK", strlen("ACK")) == 0) {
543 strcpy(connection->errorStr, output);
544 connection->error = MPD_ERROR_ACK;
545 connection->errorCode = MPD_ACK_ERROR_UNK;
546 connection->errorAt = MPD_ERROR_AT_UNK;
547 connection->doneProcessing = 1;
548 connection->doneListOk = 0;
550 needle = strchr(output, '[');
553 val = strtol(needle + 1, &test, 10);
556 connection->errorCode = val;
557 val = strtol(test + 1, &test, 10);
560 connection->errorAt = val;
564 name = strtok_r(output, ":", &tok);
565 if (name && (value = strtok_r(NULL, "", &tok)) && value[0] == ' ') {
566 connection->returnElement =
567 mpd_newReturnElement(name, &(value[1]));
569 if (!name || !value) {
570 snprintf(connection->errorStr,
571 MPD_BUFFER_MAX_LENGTH,
572 "error parsing: %s", output);
574 snprintf(connection->errorStr,
575 MPD_BUFFER_MAX_LENGTH,
576 "error parsing: %s:%s", name, value);
578 connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0';
579 connection->error = 1;
583 void mpd_finishCommand(mpd_Connection * connection)
585 while (!connection->doneProcessing) {
586 if (connection->doneListOk)
587 connection->doneListOk = 0;
588 mpd_getNextReturnElement(connection);
592 void mpd_finishListOkCommand(mpd_Connection * connection)
594 while (!connection->doneProcessing && connection->listOks &&
595 !connection->doneListOk) {
596 mpd_getNextReturnElement(connection);
600 int mpd_nextListOkCommand(mpd_Connection * connection)
602 mpd_finishListOkCommand(connection);
603 if (!connection->doneProcessing)
604 connection->doneListOk = 0;
605 if (connection->listOks == 0 || connection->doneProcessing)
610 void mpd_sendStatusCommand(mpd_Connection * connection)
612 mpd_executeCommand(connection, "status\n");
615 mpd_Status *mpd_getStatus(mpd_Connection * connection)
619 /*mpd_executeCommand(connection,"status\n");
621 if(connection->error) return NULL; */
623 if (connection->doneProcessing || (connection->listOks &&
624 connection->doneListOk)) {
628 if (!connection->returnElement)
629 mpd_getNextReturnElement(connection);
631 status = malloc(sizeof(mpd_Status));
635 status->playlist = -1;
636 status->playlistLength = -1;
639 status->elapsedTime = 0;
640 status->totalTime = 0;
642 status->sampleRate = 0;
644 status->channels = 0;
645 status->crossfade = -1;
646 status->error = NULL;
647 status->updatingDb = 0;
649 if (connection->error) {
653 while (connection->returnElement) {
654 mpd_ReturnElement *re = connection->returnElement;
655 if (strcmp(re->name, "volume") == 0) {
656 status->volume = atoi(re->value);
657 } else if (strcmp(re->name, "repeat") == 0) {
658 status->repeat = atoi(re->value);
659 } else if (strcmp(re->name, "random") == 0) {
660 status->random = atoi(re->value);
661 } else if (strcmp(re->name, "playlist") == 0) {
662 status->playlist = strtol(re->value, NULL, 10);
663 } else if (strcmp(re->name, "playlistlength") == 0) {
664 status->playlistLength = atoi(re->value);
665 } else if (strcmp(re->name, "bitrate") == 0) {
666 status->bitRate = atoi(re->value);
667 } else if (strcmp(re->name, "state") == 0) {
668 if (strcmp(re->value, "play") == 0) {
669 status->state = MPD_STATUS_STATE_PLAY;
670 } else if (strcmp(re->value, "stop") == 0) {
671 status->state = MPD_STATUS_STATE_STOP;
672 } else if (strcmp(re->value, "pause") == 0) {
673 status->state = MPD_STATUS_STATE_PAUSE;
675 status->state = MPD_STATUS_STATE_UNKNOWN;
677 } else if (strcmp(re->name, "song") == 0) {
678 status->song = atoi(re->value);
679 } else if (strcmp(re->name, "songid") == 0) {
680 status->songid = atoi(re->value);
681 } else if (strcmp(re->name, "time") == 0) {
685 copy = strdup(re->value);
686 temp = strtok_r(copy, ":", &tok);
688 status->elapsedTime = atoi(temp);
689 temp = strtok_r(NULL, "", &tok);
691 status->totalTime = atoi(temp);
694 } else if (strcmp(re->name, "error") == 0) {
695 status->error = strdup(re->value);
696 } else if (strcmp(re->name, "xfade") == 0) {
697 status->crossfade = atoi(re->value);
698 } else if (strcmp(re->name, "updating_db") == 0) {
699 status->updatingDb = atoi(re->value);
700 } else if (strcmp(re->name, "audio") == 0) {
704 copy = strdup(re->value);
705 temp = strtok_r(copy, ":", &tok);
707 status->sampleRate = atoi(temp);
708 temp = strtok_r(NULL, ":", &tok);
710 status->bits = atoi(temp);
711 temp = strtok_r(NULL, "", &tok);
720 mpd_getNextReturnElement(connection);
721 if (connection->error) {
727 if (connection->error) {
730 } else if (status->state < 0) {
731 strcpy(connection->errorStr, "state not found");
732 connection->error = 1;
740 void mpd_freeStatus(mpd_Status * status)
747 void mpd_sendStatsCommand(mpd_Connection * connection)
749 mpd_executeCommand(connection, "stats\n");
752 mpd_Stats *mpd_getStats(mpd_Connection * connection)
756 /*mpd_executeCommand(connection,"stats\n");
758 if(connection->error) return NULL; */
760 if (connection->doneProcessing || (connection->listOks &&
761 connection->doneListOk)) {
765 if (!connection->returnElement)
766 mpd_getNextReturnElement(connection);
768 stats = malloc(sizeof(mpd_Stats));
769 stats->numberOfArtists = 0;
770 stats->numberOfAlbums = 0;
771 stats->numberOfSongs = 0;
773 stats->dbUpdateTime = 0;
775 stats->dbPlayTime = 0;
777 if (connection->error) {
781 while (connection->returnElement) {
782 mpd_ReturnElement *re = connection->returnElement;
783 if (strcmp(re->name, "artists") == 0) {
784 stats->numberOfArtists = atoi(re->value);
785 } else if (strcmp(re->name, "albums") == 0) {
786 stats->numberOfAlbums = atoi(re->value);
787 } else if (strcmp(re->name, "songs") == 0) {
788 stats->numberOfSongs = atoi(re->value);
789 } else if (strcmp(re->name, "uptime") == 0) {
790 stats->uptime = strtol(re->value, NULL, 10);
791 } else if (strcmp(re->name, "db_update") == 0) {
792 stats->dbUpdateTime = strtol(re->value, NULL, 10);
793 } else if (strcmp(re->name, "playtime") == 0) {
794 stats->playTime = strtol(re->value, NULL, 10);
795 } else if (strcmp(re->name, "db_playtime") == 0) {
796 stats->dbPlayTime = strtol(re->value, NULL, 10);
799 mpd_getNextReturnElement(connection);
800 if (connection->error) {
806 if (connection->error) {
814 void mpd_freeStats(mpd_Stats * stats)
819 void mpd_initSong(mpd_Song * song)
827 song->time = MPD_SONG_NO_TIME;
828 song->pos = MPD_SONG_NO_NUM;
829 song->id = MPD_SONG_NO_ID;
832 void mpd_finishSong(mpd_Song * song)
848 mpd_Song *mpd_newSong()
850 mpd_Song *ret = malloc(sizeof(mpd_Song));
857 void mpd_freeSong(mpd_Song * song)
859 mpd_finishSong(song);
863 mpd_Song *mpd_songDup(mpd_Song * song)
865 mpd_Song *ret = mpd_newSong();
868 ret->file = strdup(song->file);
870 ret->artist = strdup(song->artist);
872 ret->album = strdup(song->album);
874 ret->title = strdup(song->title);
876 ret->track = strdup(song->track);
878 ret->name = strdup(song->name);
879 ret->time = song->time;
880 ret->pos = song->pos;
886 void mpd_initDirectory(mpd_Directory * directory)
888 directory->path = NULL;
891 void mpd_finishDirectory(mpd_Directory * directory)
894 free(directory->path);
897 mpd_Directory *mpd_newDirectory()
899 mpd_Directory *directory = malloc(sizeof(mpd_Directory));;
901 mpd_initDirectory(directory);
906 void mpd_freeDirectory(mpd_Directory * directory)
908 mpd_finishDirectory(directory);
913 mpd_Directory *mpd_directoryDup(mpd_Directory * directory)
915 mpd_Directory *ret = mpd_newDirectory();
918 ret->path = strdup(directory->path);
923 void mpd_initPlaylistFile(mpd_PlaylistFile * playlist)
925 playlist->path = NULL;
928 void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist)
931 free(playlist->path);
934 mpd_PlaylistFile *mpd_newPlaylistFile()
936 mpd_PlaylistFile *playlist = malloc(sizeof(mpd_PlaylistFile));
938 mpd_initPlaylistFile(playlist);
943 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist)
945 mpd_finishPlaylistFile(playlist);
949 mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile * playlist)
951 mpd_PlaylistFile *ret = mpd_newPlaylistFile();
954 ret->path = strdup(playlist->path);
959 void mpd_initInfoEntity(mpd_InfoEntity * entity)
961 entity->info.directory = NULL;
964 void mpd_finishInfoEntity(mpd_InfoEntity * entity)
966 if (entity->info.directory) {
967 if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
968 mpd_freeDirectory(entity->info.directory);
969 } else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
970 mpd_freeSong(entity->info.song);
971 } else if (entity->type ==
972 MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
973 mpd_freePlaylistFile(entity->info.playlistFile);
978 mpd_InfoEntity *mpd_newInfoEntity()
980 mpd_InfoEntity *entity = malloc(sizeof(mpd_InfoEntity));
982 mpd_initInfoEntity(entity);
987 void mpd_freeInfoEntity(mpd_InfoEntity * entity)
989 mpd_finishInfoEntity(entity);
993 void mpd_sendInfoCommand(mpd_Connection * connection, char *command)
995 mpd_executeCommand(connection, command);
998 mpd_InfoEntity *mpd_getNextInfoEntity(mpd_Connection * connection)
1000 mpd_InfoEntity *entity = NULL;
1002 if (connection->doneProcessing || (connection->listOks &&
1003 connection->doneListOk)) {
1007 if (!connection->returnElement)
1008 mpd_getNextReturnElement(connection);
1010 if (connection->returnElement) {
1011 if (strcmp(connection->returnElement->name, "file") == 0) {
1012 entity = mpd_newInfoEntity();
1013 entity->type = MPD_INFO_ENTITY_TYPE_SONG;
1014 entity->info.song = mpd_newSong();
1015 entity->info.song->file =
1016 strdup(connection->returnElement->value);
1019 (connection->returnElement->name,
1020 "directory") == 0) {
1021 entity = mpd_newInfoEntity();
1022 entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
1023 entity->info.directory = mpd_newDirectory();
1024 entity->info.directory->path =
1025 strdup(connection->returnElement->value);
1027 if (strcmp(connection->returnElement->name, "playlist")
1029 entity = mpd_newInfoEntity();
1030 entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
1031 entity->info.playlistFile = mpd_newPlaylistFile();
1032 entity->info.playlistFile->path =
1033 strdup(connection->returnElement->value);
1035 connection->error = 1;
1036 strcpy(connection->errorStr,
1037 "problem parsing song info");
1043 mpd_getNextReturnElement(connection);
1044 while (connection->returnElement) {
1045 mpd_ReturnElement *re = connection->returnElement;
1047 if (strcmp(re->name, "file") == 0)
1049 else if (strcmp(re->name, "directory") == 0)
1051 else if (strcmp(re->name, "playlist") == 0)
1054 if (entity->type == MPD_INFO_ENTITY_TYPE_SONG
1055 && strlen(re->value)) {
1056 if (!entity->info.song->artist
1057 && strcmp(re->name, "Artist") == 0) {
1058 entity->info.song->artist =
1060 } else if (!entity->info.song->album
1061 && strcmp(re->name, "Album") == 0) {
1062 entity->info.song->album =
1064 } else if (!entity->info.song->title
1065 && strcmp(re->name, "Title") == 0) {
1066 entity->info.song->title =
1068 } else if (!entity->info.song->track
1069 && strcmp(re->name, "Track") == 0) {
1070 entity->info.song->track =
1072 } else if (!entity->info.song->name
1073 && strcmp(re->name, "Name") == 0) {
1074 entity->info.song->name =
1076 } else if (entity->info.song->time ==
1078 && strcmp(re->name, "Time") == 0) {
1079 entity->info.song->time = atoi(re->value);
1080 } else if (entity->info.song->pos ==
1082 && strcmp(re->name, "Pos") == 0) {
1083 entity->info.song->pos = atoi(re->value);
1084 } else if (entity->info.song->id == MPD_SONG_NO_ID
1085 && strcmp(re->name, "Id") == 0) {
1086 entity->info.song->id = atoi(re->value);
1088 } else if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1089 } else if (entity->type ==
1090 MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1093 mpd_getNextReturnElement(connection);
1099 char *mpd_getNextReturnElementNamed(mpd_Connection * connection,
1102 if (connection->doneProcessing || (connection->listOks &&
1103 connection->doneListOk)) {
1107 mpd_getNextReturnElement(connection);
1108 while (connection->returnElement) {
1109 mpd_ReturnElement *re = connection->returnElement;
1111 if (strcmp(re->name, name) == 0)
1112 return strdup(re->value);
1113 mpd_getNextReturnElement(connection);
1119 char *mpd_getNextArtist(mpd_Connection * connection)
1121 return mpd_getNextReturnElementNamed(connection, "Artist");
1124 char *mpd_getNextAlbum(mpd_Connection * connection)
1126 return mpd_getNextReturnElementNamed(connection, "Album");
1129 void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos)
1131 char *string = malloc(strlen("playlistinfo") + 25);
1132 sprintf(string, "playlistinfo \"%i\"\n", songPos);
1133 mpd_sendInfoCommand(connection, string);
1137 void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id)
1139 char *string = malloc(strlen("playlistid") + 25);
1140 sprintf(string, "playlistid \"%i\"\n", id);
1141 mpd_sendInfoCommand(connection, string);
1146 mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist)
1148 char *string = malloc(strlen("plchanges") + 25);
1149 sprintf(string, "plchanges \"%lld\"\n", playlist);
1150 mpd_sendInfoCommand(connection, string);
1154 void mpd_sendListallCommand(mpd_Connection * connection, const char *dir)
1156 char *sDir = mpd_sanitizeArg(dir);
1157 char *string = malloc(strlen("listall") + strlen(sDir) + 5);
1158 sprintf(string, "listall \"%s\"\n", sDir);
1159 mpd_sendInfoCommand(connection, string);
1165 mpd_sendListallInfoCommand(mpd_Connection * connection, const char *dir)
1167 char *sDir = mpd_sanitizeArg(dir);
1168 char *string = malloc(strlen("listallinfo") + strlen(sDir) + 5);
1169 sprintf(string, "listallinfo \"%s\"\n", sDir);
1170 mpd_sendInfoCommand(connection, string);
1175 void mpd_sendLsInfoCommand(mpd_Connection * connection, const char *dir)
1177 char *sDir = mpd_sanitizeArg(dir);
1178 char *string = malloc(strlen("lsinfo") + strlen(sDir) + 5);
1179 sprintf(string, "lsinfo \"%s\"\n", sDir);
1180 mpd_sendInfoCommand(connection, string);
1185 void mpd_sendCurrentSongCommand(mpd_Connection * connection)
1187 mpd_executeCommand(connection, "currentsong\n");
1191 mpd_sendSearchCommand(mpd_Connection * connection, int table,
1196 char *sanitStr = mpd_sanitizeArg(str);
1197 if (table == MPD_TABLE_ARTIST)
1198 strcpy(st, "artist");
1199 else if (table == MPD_TABLE_ALBUM)
1200 strcpy(st, "album");
1201 else if (table == MPD_TABLE_TITLE)
1202 strcpy(st, "title");
1203 else if (table == MPD_TABLE_FILENAME)
1204 strcpy(st, "filename");
1206 connection->error = 1;
1207 strcpy(connection->errorStr, "unknown table for search");
1211 malloc(strlen("search") + strlen(sanitStr) + strlen(st) + 6);
1212 sprintf(string, "search %s \"%s\"\n", st, sanitStr);
1213 mpd_sendInfoCommand(connection, string);
1219 mpd_sendFindCommand(mpd_Connection * connection, int table,
1224 char *sanitStr = mpd_sanitizeArg(str);
1225 if (table == MPD_TABLE_ARTIST)
1226 strcpy(st, "artist");
1227 else if (table == MPD_TABLE_ALBUM)
1228 strcpy(st, "album");
1229 else if (table == MPD_TABLE_TITLE)
1230 strcpy(st, "title");
1232 connection->error = 1;
1233 strcpy(connection->errorStr, "unknown table for find");
1237 malloc(strlen("find") + strlen(sanitStr) + strlen(st) + 6);
1238 sprintf(string, "find %s \"%s\"\n", st, sanitStr);
1239 mpd_sendInfoCommand(connection, string);
1245 mpd_sendListCommand(mpd_Connection * connection, int table,
1250 if (table == MPD_TABLE_ARTIST)
1251 strcpy(st, "artist");
1252 else if (table == MPD_TABLE_ALBUM)
1253 strcpy(st, "album");
1255 connection->error = 1;
1256 strcpy(connection->errorStr, "unknown table for list");
1260 char *sanitArg1 = mpd_sanitizeArg(arg1);
1262 malloc(strlen("list") + strlen(sanitArg1) +
1264 sprintf(string, "list %s \"%s\"\n", st, sanitArg1);
1267 string = malloc(strlen("list") + strlen(st) + 3);
1268 sprintf(string, "list %s\n", st);
1270 mpd_sendInfoCommand(connection, string);
1274 void mpd_sendAddCommand(mpd_Connection * connection, const char *file)
1276 char *sFile = mpd_sanitizeArg(file);
1277 char *string = malloc(strlen("add") + strlen(sFile) + 5);
1278 sprintf(string, "add \"%s\"\n", sFile);
1279 mpd_executeCommand(connection, string);
1284 void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos)
1286 char *string = malloc(strlen("delete") + 25);
1287 sprintf(string, "delete \"%i\"\n", songPos);
1288 mpd_sendInfoCommand(connection, string);
1292 void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id)
1294 char *string = malloc(strlen("deleteid") + 25);
1295 sprintf(string, "deleteid \"%i\"\n", id);
1296 mpd_sendInfoCommand(connection, string);
1300 void mpd_sendSaveCommand(mpd_Connection * connection, const char *name)
1302 char *sName = mpd_sanitizeArg(name);
1303 char *string = malloc(strlen("save") + strlen(sName) + 5);
1304 sprintf(string, "save \"%s\"\n", sName);
1305 mpd_executeCommand(connection, string);
1310 void mpd_sendLoadCommand(mpd_Connection * connection, const char *name)
1312 char *sName = mpd_sanitizeArg(name);
1313 char *string = malloc(strlen("load") + strlen(sName) + 5);
1314 sprintf(string, "load \"%s\"\n", sName);
1315 mpd_executeCommand(connection, string);
1320 void mpd_sendRmCommand(mpd_Connection * connection, const char *name)
1322 char *sName = mpd_sanitizeArg(name);
1323 char *string = malloc(strlen("rm") + strlen(sName) + 5);
1324 sprintf(string, "rm \"%s\"\n", sName);
1325 mpd_executeCommand(connection, string);
1330 void mpd_sendShuffleCommand(mpd_Connection * connection)
1332 mpd_executeCommand(connection, "shuffle\n");
1335 void mpd_sendClearCommand(mpd_Connection * connection)
1337 mpd_executeCommand(connection, "clear\n");
1340 void mpd_sendPlayCommand(mpd_Connection * connection, int songPos)
1342 char *string = malloc(strlen("play") + 25);
1343 sprintf(string, "play \"%i\"\n", songPos);
1344 mpd_sendInfoCommand(connection, string);
1348 void mpd_sendPlayIdCommand(mpd_Connection * connection, int id)
1350 char *string = malloc(strlen("playid") + 25);
1351 sprintf(string, "playid \"%i\"\n", id);
1352 mpd_sendInfoCommand(connection, string);
1356 void mpd_sendStopCommand(mpd_Connection * connection)
1358 mpd_executeCommand(connection, "stop\n");
1361 void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode)
1363 char *string = malloc(strlen("pause") + 25);
1364 sprintf(string, "pause \"%i\"\n", pauseMode);
1365 mpd_executeCommand(connection, string);
1369 void mpd_sendNextCommand(mpd_Connection * connection)
1371 mpd_executeCommand(connection, "next\n");
1374 void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to)
1376 char *string = malloc(strlen("move") + 25);
1377 sprintf(string, "move \"%i\" \"%i\"\n", from, to);
1378 mpd_sendInfoCommand(connection, string);
1382 void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to)
1384 char *string = malloc(strlen("moveid") + 25);
1385 sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
1386 mpd_sendInfoCommand(connection, string);
1390 void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2)
1392 char *string = malloc(strlen("swap") + 25);
1393 sprintf(string, "swap \"%i\" \"%i\"\n", song1, song2);
1394 mpd_sendInfoCommand(connection, string);
1398 void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2)
1400 char *string = malloc(strlen("swapid") + 25);
1401 sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
1402 mpd_sendInfoCommand(connection, string);
1406 void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time)
1408 char *string = malloc(strlen("seek") + 25);
1409 sprintf(string, "seek \"%i\" \"%i\"\n", song, time);
1410 mpd_sendInfoCommand(connection, string);
1414 void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time)
1416 char *string = malloc(strlen("seekid") + 25);
1417 sprintf(string, "seekid \"%i\" \"%i\"\n", id, time);
1418 mpd_sendInfoCommand(connection, string);
1422 void mpd_sendUpdateCommand(mpd_Connection * connection, char *path)
1424 char *sPath = mpd_sanitizeArg(path);
1425 char *string = malloc(strlen("update") + strlen(sPath) + 5);
1426 sprintf(string, "update \"%s\"\n", sPath);
1427 mpd_sendInfoCommand(connection, string);
1432 int mpd_getUpdateId(mpd_Connection * connection)
1437 jobid = mpd_getNextReturnElementNamed(connection, "updating_db");
1446 void mpd_sendPrevCommand(mpd_Connection * connection)
1448 mpd_executeCommand(connection, "previous\n");
1451 void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode)
1453 char *string = malloc(strlen("repeat") + 25);
1454 sprintf(string, "repeat \"%i\"\n", repeatMode);
1455 mpd_executeCommand(connection, string);
1459 void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode)
1461 char *string = malloc(strlen("random") + 25);
1462 sprintf(string, "random \"%i\"\n", randomMode);
1463 mpd_executeCommand(connection, string);
1467 void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange)
1469 char *string = malloc(strlen("setvol") + 25);
1470 sprintf(string, "setvol \"%i\"\n", volumeChange);
1471 mpd_executeCommand(connection, string);
1475 void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange)
1477 char *string = malloc(strlen("volume") + 25);
1478 sprintf(string, "volume \"%i\"\n", volumeChange);
1479 mpd_executeCommand(connection, string);
1483 void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds)
1485 char *string = malloc(strlen("crossfade") + 25);
1486 sprintf(string, "crossfade \"%i\"\n", seconds);
1487 mpd_executeCommand(connection, string);
1491 void mpd_sendPasswordCommand(mpd_Connection * connection, const char *pass)
1493 char *sPass = mpd_sanitizeArg(pass);
1494 char *string = malloc(strlen("password") + strlen(sPass) + 5);
1495 sprintf(string, "password \"%s\"\n", sPass);
1496 mpd_executeCommand(connection, string);
1501 void mpd_sendCommandListBegin(mpd_Connection * connection)
1503 if (connection->commandList) {
1504 strcpy(connection->errorStr,
1505 "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)
1515 if (connection->commandList) {
1516 strcpy(connection->errorStr,
1517 "already in command list mode");
1518 connection->error = 1;
1521 connection->commandList = COMMAND_LIST_OK;
1522 mpd_executeCommand(connection, "command_list_ok_begin\n");
1523 connection->listOks = 0;
1526 void mpd_sendCommandListEnd(mpd_Connection * connection)
1528 if (!connection->commandList) {
1529 strcpy(connection->errorStr, "not in command list mode");
1530 connection->error = 1;
1533 connection->commandList = 0;
1534 mpd_executeCommand(connection, "command_list_end\n");
1537 void mpd_signalHandler(int signal)
1539 if (signal == SIGPIPE) {
1540 fprintf(stderr, "Conky: recieved SIGPIPE from MPD connection\n");