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;
220 sapipe.sa_restorer = NULL;
221 #endif /* __linux__ */
222 sigaction(SIGPIPE,&sapipe,NULL);
226 int flags = fcntl(connection->sock, F_GETFL, 0);
227 fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
229 if (connect(connection->sock, dest, destlen) < 0
230 && errno != EINPROGRESS) {
231 snprintf(connection->errorStr,
232 MPD_BUFFER_MAX_LENGTH,
233 "problems connecting to \"%s\" on port"
235 connection->error = MPD_ERROR_CONNPORT;
240 while (!(rt = strstr(connection->buffer, "\n"))) {
241 tv.tv_sec = connection->timeout.tv_sec;
242 tv.tv_usec = connection->timeout.tv_usec;
244 FD_SET(connection->sock, &fds);
246 select(connection->sock + 1, &fds, NULL, NULL,
249 readed = recv(connection->sock,
251 buffer[connection->buflen]),
252 MPD_BUFFER_MAX_LENGTH -
253 connection->buflen, 0);
255 snprintf(connection->errorStr,
256 MPD_BUFFER_MAX_LENGTH,
257 "problems getting a response from"
258 " \"%s\" on port %i", host, port);
259 connection->error = MPD_ERROR_NORESPONSE;
262 connection->buflen += readed;
263 connection->buffer[connection->buflen] = '\0';
264 tv.tv_sec = connection->timeout.tv_sec;
265 tv.tv_usec = connection->timeout.tv_usec;
266 } else if (err < 0) {
271 snprintf(connection->errorStr,
272 MPD_BUFFER_MAX_LENGTH,
273 "problems connecting to \"%s\" on port"
275 connection->error = MPD_ERROR_CONNPORT;
279 snprintf(connection->errorStr,
280 MPD_BUFFER_MAX_LENGTH,
281 "timeout in attempting to get a response from"
282 " \"%s\" on port %i", host, port);
283 connection->error = MPD_ERROR_NORESPONSE;
289 output = strdup(connection->buffer);
290 strcpy(connection->buffer, rt + 1);
291 connection->buflen = strlen(connection->buffer);
294 (output, MPD_WELCOME_MESSAGE, strlen(MPD_WELCOME_MESSAGE))) {
296 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
297 "mpd not running on port %i on host \"%s\"", port,
299 connection->error = MPD_ERROR_NOTMPD;
306 char *tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
310 for (i = 0; i < 3; i++) {
314 version[i] = strtok_r(tmp, search, &tok);
317 snprintf(connection->errorStr,
318 MPD_BUFFER_MAX_LENGTH,
319 "error parsing version number at "
322 (MPD_WELCOME_MESSAGE)]);
323 connection->error = MPD_ERROR_NOTMPD;
326 connection->version[i] =
327 strtol(version[i], &test, 10);
328 if (version[i] == test || *test != '\0') {
330 snprintf(connection->errorStr,
331 MPD_BUFFER_MAX_LENGTH,
332 "error parsing version number at "
335 (MPD_WELCOME_MESSAGE)]);
336 connection->error = MPD_ERROR_NOTMPD;
345 connection->doneProcessing = 1;
350 void mpd_clearError(mpd_Connection * connection)
352 connection->error = 0;
353 connection->errorStr[0] = '\0';
356 void mpd_closeConnection(mpd_Connection * connection)
358 close(connection->sock);
359 if (connection->returnElement)
360 free(connection->returnElement);
364 void mpd_executeCommand(mpd_Connection * connection, char *command)
369 char *commandPtr = command;
370 int commandLen = strlen(command);
372 if (!connection->doneProcessing && !connection->commandList) {
373 strcpy(connection->errorStr,
374 "not done processing current command");
375 connection->error = 1;
379 mpd_clearError(connection);
382 FD_SET(connection->sock, &fds);
383 tv.tv_sec = connection->timeout.tv_sec;
384 tv.tv_usec = connection->timeout.tv_usec;
388 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH, "got SIGINT");
389 connection->error = MPD_ERROR_SENDING;
392 while ((ret = select(connection->sock + 1, NULL, &fds, NULL, &tv) == 1) || (ret == -1 && errno == EINTR)) {
395 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH, "got SIGINT");
396 connection->error = MPD_ERROR_SENDING;
399 ret = send(connection->sock, commandPtr, commandLen, MSG_DONTWAIT);
401 if (ret == EAGAIN || ret == EINTR)
403 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH, "problems giving command \"%s\"", command);
404 connection->error = MPD_ERROR_SENDING;
415 if (commandLen > 0) {
417 snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
418 "timeout sending command \"%s\"", command);
419 connection->error = MPD_ERROR_TIMEOUT;
423 if (!connection->commandList)
424 connection->doneProcessing = 0;
425 else if (connection->commandList == COMMAND_LIST_OK) {
426 connection->listOks++;
430 void mpd_getNextReturnElement(mpd_Connection * connection)
440 char *bufferCheck = NULL;
443 if (connection->returnElement)
444 mpd_freeReturnElement(connection->returnElement);
445 connection->returnElement = NULL;
447 if (connection->doneProcessing || (connection->listOks &&
448 connection->doneListOk)) {
449 strcpy(connection->errorStr,
450 "already done processing current command");
451 connection->error = 1;
455 bufferCheck = connection->buffer + connection->bufstart;
456 while (connection->bufstart >= connection->buflen ||
457 !(rt = strstr(bufferCheck, "\n"))) {
458 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
459 memmove(connection->buffer,
461 connection->bufstart,
462 connection->buflen - connection->bufstart +
464 bufferCheck -= connection->bufstart;
465 connection->buflen -= connection->bufstart;
466 connection->bufstart = 0;
468 if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
469 strcpy(connection->errorStr, "buffer overrun");
470 connection->error = MPD_ERROR_BUFFEROVERRUN;
471 connection->doneProcessing = 1;
472 connection->doneListOk = 0;
475 bufferCheck += connection->buflen - connection->bufstart;
476 tv.tv_sec = connection->timeout.tv_sec;
477 tv.tv_usec = connection->timeout.tv_usec;
479 FD_SET(connection->sock, &fds);
481 select(connection->sock + 1, &fds, NULL, NULL,
484 recv(connection->sock,
485 connection->buffer + connection->buflen,
486 MPD_BUFFER_MAX_LENGTH -
487 connection->buflen, MSG_DONTWAIT);
489 && (errno == EAGAIN || errno == EINTR)) {
493 strcpy(connection->errorStr,
494 "connection" " closed");
495 connection->error = MPD_ERROR_CONNCLOSED;
496 connection->doneProcessing = 1;
497 connection->doneListOk = 0;
500 connection->buflen += readed;
501 connection->buffer[connection->buflen] = '\0';
502 } else if (err < 0 && errno == EINTR)
505 strcpy(connection->errorStr, "connection timeout");
506 connection->error = MPD_ERROR_TIMEOUT;
507 connection->doneProcessing = 1;
508 connection->doneListOk = 0;
514 output = connection->buffer + connection->bufstart;
515 connection->bufstart = rt - connection->buffer + 1;
517 if (strcmp(output, "OK") == 0) {
518 if (connection->listOks > 0) {
519 strcpy(connection->errorStr,
520 "expected more list_OK's");
521 connection->error = 1;
523 connection->listOks = 0;
524 connection->doneProcessing = 1;
525 connection->doneListOk = 0;
529 if (strcmp(output, "list_OK") == 0) {
530 if (!connection->listOks) {
531 strcpy(connection->errorStr,
532 "got an unexpected list_OK");
533 connection->error = 1;
535 connection->doneListOk = 1;
536 connection->listOks--;
541 if (strncmp(output, "ACK", strlen("ACK")) == 0) {
546 strcpy(connection->errorStr, output);
547 connection->error = MPD_ERROR_ACK;
548 connection->errorCode = MPD_ACK_ERROR_UNK;
549 connection->errorAt = MPD_ERROR_AT_UNK;
550 connection->doneProcessing = 1;
551 connection->doneListOk = 0;
553 needle = strchr(output, '[');
556 val = strtol(needle + 1, &test, 10);
559 connection->errorCode = val;
560 val = strtol(test + 1, &test, 10);
563 connection->errorAt = val;
567 name = strtok_r(output, ":", &tok);
568 if (name && (value = strtok_r(NULL, "", &tok)) && value[0] == ' ') {
569 connection->returnElement =
570 mpd_newReturnElement(name, &(value[1]));
572 if (!name || !value) {
573 snprintf(connection->errorStr,
574 MPD_BUFFER_MAX_LENGTH,
575 "error parsing: %s", output);
577 snprintf(connection->errorStr,
578 MPD_BUFFER_MAX_LENGTH,
579 "error parsing: %s:%s", name, value);
581 connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0';
582 connection->error = 1;
586 void mpd_finishCommand(mpd_Connection * connection)
588 while (!connection->doneProcessing) {
589 if (connection->doneListOk)
590 connection->doneListOk = 0;
591 mpd_getNextReturnElement(connection);
595 void mpd_finishListOkCommand(mpd_Connection * connection)
597 while (!connection->doneProcessing && connection->listOks &&
598 !connection->doneListOk) {
599 mpd_getNextReturnElement(connection);
603 int mpd_nextListOkCommand(mpd_Connection * connection)
605 mpd_finishListOkCommand(connection);
606 if (!connection->doneProcessing)
607 connection->doneListOk = 0;
608 if (connection->listOks == 0 || connection->doneProcessing)
613 void mpd_sendStatusCommand(mpd_Connection * connection)
615 mpd_executeCommand(connection, "status\n");
618 mpd_Status *mpd_getStatus(mpd_Connection * connection)
622 /*mpd_executeCommand(connection,"status\n");
624 if(connection->error) return NULL; */
626 if (connection->doneProcessing || (connection->listOks &&
627 connection->doneListOk)) {
631 if (!connection->returnElement)
632 mpd_getNextReturnElement(connection);
634 status = malloc(sizeof(mpd_Status));
638 status->playlist = -1;
639 status->playlistLength = -1;
642 status->elapsedTime = 0;
643 status->totalTime = 0;
645 status->sampleRate = 0;
647 status->channels = 0;
648 status->crossfade = -1;
649 status->error = NULL;
650 status->updatingDb = 0;
652 if (connection->error) {
656 while (connection->returnElement) {
657 mpd_ReturnElement *re = connection->returnElement;
658 if (strcmp(re->name, "volume") == 0) {
659 status->volume = atoi(re->value);
660 } else if (strcmp(re->name, "repeat") == 0) {
661 status->repeat = atoi(re->value);
662 } else if (strcmp(re->name, "random") == 0) {
663 status->random = atoi(re->value);
664 } else if (strcmp(re->name, "playlist") == 0) {
665 status->playlist = strtol(re->value, NULL, 10);
666 } else if (strcmp(re->name, "playlistlength") == 0) {
667 status->playlistLength = atoi(re->value);
668 } else if (strcmp(re->name, "bitrate") == 0) {
669 status->bitRate = atoi(re->value);
670 } else if (strcmp(re->name, "state") == 0) {
671 if (strcmp(re->value, "play") == 0) {
672 status->state = MPD_STATUS_STATE_PLAY;
673 } else if (strcmp(re->value, "stop") == 0) {
674 status->state = MPD_STATUS_STATE_STOP;
675 } else if (strcmp(re->value, "pause") == 0) {
676 status->state = MPD_STATUS_STATE_PAUSE;
678 status->state = MPD_STATUS_STATE_UNKNOWN;
680 } else if (strcmp(re->name, "song") == 0) {
681 status->song = atoi(re->value);
682 } else if (strcmp(re->name, "songid") == 0) {
683 status->songid = atoi(re->value);
684 } else if (strcmp(re->name, "time") == 0) {
688 copy = strdup(re->value);
689 temp = strtok_r(copy, ":", &tok);
691 status->elapsedTime = atoi(temp);
692 temp = strtok_r(NULL, "", &tok);
694 status->totalTime = atoi(temp);
697 } else if (strcmp(re->name, "error") == 0) {
698 status->error = strdup(re->value);
699 } else if (strcmp(re->name, "xfade") == 0) {
700 status->crossfade = atoi(re->value);
701 } else if (strcmp(re->name, "updating_db") == 0) {
702 status->updatingDb = atoi(re->value);
703 } else if (strcmp(re->name, "audio") == 0) {
707 copy = strdup(re->value);
708 temp = strtok_r(copy, ":", &tok);
710 status->sampleRate = atoi(temp);
711 temp = strtok_r(NULL, ":", &tok);
713 status->bits = atoi(temp);
714 temp = strtok_r(NULL, "", &tok);
723 mpd_getNextReturnElement(connection);
724 if (connection->error) {
730 if (connection->error) {
733 } else if (status->state < 0) {
734 strcpy(connection->errorStr, "state not found");
735 connection->error = 1;
743 void mpd_freeStatus(mpd_Status * status)
750 void mpd_sendStatsCommand(mpd_Connection * connection)
752 mpd_executeCommand(connection, "stats\n");
755 mpd_Stats *mpd_getStats(mpd_Connection * connection)
759 /*mpd_executeCommand(connection,"stats\n");
761 if(connection->error) return NULL; */
763 if (connection->doneProcessing || (connection->listOks &&
764 connection->doneListOk)) {
768 if (!connection->returnElement)
769 mpd_getNextReturnElement(connection);
771 stats = malloc(sizeof(mpd_Stats));
772 stats->numberOfArtists = 0;
773 stats->numberOfAlbums = 0;
774 stats->numberOfSongs = 0;
776 stats->dbUpdateTime = 0;
778 stats->dbPlayTime = 0;
780 if (connection->error) {
784 while (connection->returnElement) {
785 mpd_ReturnElement *re = connection->returnElement;
786 if (strcmp(re->name, "artists") == 0) {
787 stats->numberOfArtists = atoi(re->value);
788 } else if (strcmp(re->name, "albums") == 0) {
789 stats->numberOfAlbums = atoi(re->value);
790 } else if (strcmp(re->name, "songs") == 0) {
791 stats->numberOfSongs = atoi(re->value);
792 } else if (strcmp(re->name, "uptime") == 0) {
793 stats->uptime = strtol(re->value, NULL, 10);
794 } else if (strcmp(re->name, "db_update") == 0) {
795 stats->dbUpdateTime = strtol(re->value, NULL, 10);
796 } else if (strcmp(re->name, "playtime") == 0) {
797 stats->playTime = strtol(re->value, NULL, 10);
798 } else if (strcmp(re->name, "db_playtime") == 0) {
799 stats->dbPlayTime = strtol(re->value, NULL, 10);
802 mpd_getNextReturnElement(connection);
803 if (connection->error) {
809 if (connection->error) {
817 void mpd_freeStats(mpd_Stats * stats)
822 void mpd_initSong(mpd_Song * song)
830 song->time = MPD_SONG_NO_TIME;
831 song->pos = MPD_SONG_NO_NUM;
832 song->id = MPD_SONG_NO_ID;
835 void mpd_finishSong(mpd_Song * song)
851 mpd_Song *mpd_newSong()
853 mpd_Song *ret = malloc(sizeof(mpd_Song));
860 void mpd_freeSong(mpd_Song * song)
862 mpd_finishSong(song);
866 mpd_Song *mpd_songDup(mpd_Song * song)
868 mpd_Song *ret = mpd_newSong();
871 ret->file = strdup(song->file);
873 ret->artist = strdup(song->artist);
875 ret->album = strdup(song->album);
877 ret->title = strdup(song->title);
879 ret->track = strdup(song->track);
881 ret->name = strdup(song->name);
882 ret->time = song->time;
883 ret->pos = song->pos;
889 void mpd_initDirectory(mpd_Directory * directory)
891 directory->path = NULL;
894 void mpd_finishDirectory(mpd_Directory * directory)
897 free(directory->path);
900 mpd_Directory *mpd_newDirectory()
902 mpd_Directory *directory = malloc(sizeof(mpd_Directory));;
904 mpd_initDirectory(directory);
909 void mpd_freeDirectory(mpd_Directory * directory)
911 mpd_finishDirectory(directory);
916 mpd_Directory *mpd_directoryDup(mpd_Directory * directory)
918 mpd_Directory *ret = mpd_newDirectory();
921 ret->path = strdup(directory->path);
926 void mpd_initPlaylistFile(mpd_PlaylistFile * playlist)
928 playlist->path = NULL;
931 void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist)
934 free(playlist->path);
937 mpd_PlaylistFile *mpd_newPlaylistFile()
939 mpd_PlaylistFile *playlist = malloc(sizeof(mpd_PlaylistFile));
941 mpd_initPlaylistFile(playlist);
946 void mpd_freePlaylistFile(mpd_PlaylistFile * playlist)
948 mpd_finishPlaylistFile(playlist);
952 mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile * playlist)
954 mpd_PlaylistFile *ret = mpd_newPlaylistFile();
957 ret->path = strdup(playlist->path);
962 void mpd_initInfoEntity(mpd_InfoEntity * entity)
964 entity->info.directory = NULL;
967 void mpd_finishInfoEntity(mpd_InfoEntity * entity)
969 if (entity->info.directory) {
970 if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
971 mpd_freeDirectory(entity->info.directory);
972 } else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
973 mpd_freeSong(entity->info.song);
974 } else if (entity->type ==
975 MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
976 mpd_freePlaylistFile(entity->info.playlistFile);
981 mpd_InfoEntity *mpd_newInfoEntity()
983 mpd_InfoEntity *entity = malloc(sizeof(mpd_InfoEntity));
985 mpd_initInfoEntity(entity);
990 void mpd_freeInfoEntity(mpd_InfoEntity * entity)
992 mpd_finishInfoEntity(entity);
996 void mpd_sendInfoCommand(mpd_Connection * connection, char *command)
998 mpd_executeCommand(connection, command);
1001 mpd_InfoEntity *mpd_getNextInfoEntity(mpd_Connection * connection)
1003 mpd_InfoEntity *entity = NULL;
1005 if (connection->doneProcessing || (connection->listOks &&
1006 connection->doneListOk)) {
1010 if (!connection->returnElement)
1011 mpd_getNextReturnElement(connection);
1013 if (connection->returnElement) {
1014 if (strcmp(connection->returnElement->name, "file") == 0) {
1015 entity = mpd_newInfoEntity();
1016 entity->type = MPD_INFO_ENTITY_TYPE_SONG;
1017 entity->info.song = mpd_newSong();
1018 entity->info.song->file =
1019 strdup(connection->returnElement->value);
1022 (connection->returnElement->name,
1023 "directory") == 0) {
1024 entity = mpd_newInfoEntity();
1025 entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
1026 entity->info.directory = mpd_newDirectory();
1027 entity->info.directory->path =
1028 strdup(connection->returnElement->value);
1030 if (strcmp(connection->returnElement->name, "playlist")
1032 entity = mpd_newInfoEntity();
1033 entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
1034 entity->info.playlistFile = mpd_newPlaylistFile();
1035 entity->info.playlistFile->path =
1036 strdup(connection->returnElement->value);
1038 connection->error = 1;
1039 strcpy(connection->errorStr,
1040 "problem parsing song info");
1046 mpd_getNextReturnElement(connection);
1047 while (connection->returnElement) {
1048 mpd_ReturnElement *re = connection->returnElement;
1050 if (strcmp(re->name, "file") == 0)
1052 else if (strcmp(re->name, "directory") == 0)
1054 else if (strcmp(re->name, "playlist") == 0)
1057 if (entity->type == MPD_INFO_ENTITY_TYPE_SONG
1058 && strlen(re->value)) {
1059 if (!entity->info.song->artist
1060 && strcmp(re->name, "Artist") == 0) {
1061 entity->info.song->artist =
1063 } else if (!entity->info.song->album
1064 && strcmp(re->name, "Album") == 0) {
1065 entity->info.song->album =
1067 } else if (!entity->info.song->title
1068 && strcmp(re->name, "Title") == 0) {
1069 entity->info.song->title =
1071 } else if (!entity->info.song->track
1072 && strcmp(re->name, "Track") == 0) {
1073 entity->info.song->track =
1075 } else if (!entity->info.song->name
1076 && strcmp(re->name, "Name") == 0) {
1077 entity->info.song->name =
1079 } else if (entity->info.song->time ==
1081 && strcmp(re->name, "Time") == 0) {
1082 entity->info.song->time = atoi(re->value);
1083 } else if (entity->info.song->pos ==
1085 && strcmp(re->name, "Pos") == 0) {
1086 entity->info.song->pos = atoi(re->value);
1087 } else if (entity->info.song->id == MPD_SONG_NO_ID
1088 && strcmp(re->name, "Id") == 0) {
1089 entity->info.song->id = atoi(re->value);
1091 } else if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
1092 } else if (entity->type ==
1093 MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
1096 mpd_getNextReturnElement(connection);
1102 char *mpd_getNextReturnElementNamed(mpd_Connection * connection,
1105 if (connection->doneProcessing || (connection->listOks &&
1106 connection->doneListOk)) {
1110 mpd_getNextReturnElement(connection);
1111 while (connection->returnElement) {
1112 mpd_ReturnElement *re = connection->returnElement;
1114 if (strcmp(re->name, name) == 0)
1115 return strdup(re->value);
1116 mpd_getNextReturnElement(connection);
1122 char *mpd_getNextArtist(mpd_Connection * connection)
1124 return mpd_getNextReturnElementNamed(connection, "Artist");
1127 char *mpd_getNextAlbum(mpd_Connection * connection)
1129 return mpd_getNextReturnElementNamed(connection, "Album");
1132 void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos)
1134 char *string = malloc(strlen("playlistinfo") + 25);
1135 sprintf(string, "playlistinfo \"%i\"\n", songPos);
1136 mpd_sendInfoCommand(connection, string);
1140 void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id)
1142 char *string = malloc(strlen("playlistid") + 25);
1143 sprintf(string, "playlistid \"%i\"\n", id);
1144 mpd_sendInfoCommand(connection, string);
1149 mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist)
1151 char *string = malloc(strlen("plchanges") + 25);
1152 sprintf(string, "plchanges \"%lld\"\n", playlist);
1153 mpd_sendInfoCommand(connection, string);
1157 void mpd_sendListallCommand(mpd_Connection * connection, const char *dir)
1159 char *sDir = mpd_sanitizeArg(dir);
1160 char *string = malloc(strlen("listall") + strlen(sDir) + 5);
1161 sprintf(string, "listall \"%s\"\n", sDir);
1162 mpd_sendInfoCommand(connection, string);
1168 mpd_sendListallInfoCommand(mpd_Connection * connection, const char *dir)
1170 char *sDir = mpd_sanitizeArg(dir);
1171 char *string = malloc(strlen("listallinfo") + strlen(sDir) + 5);
1172 sprintf(string, "listallinfo \"%s\"\n", sDir);
1173 mpd_sendInfoCommand(connection, string);
1178 void mpd_sendLsInfoCommand(mpd_Connection * connection, const char *dir)
1180 char *sDir = mpd_sanitizeArg(dir);
1181 char *string = malloc(strlen("lsinfo") + strlen(sDir) + 5);
1182 sprintf(string, "lsinfo \"%s\"\n", sDir);
1183 mpd_sendInfoCommand(connection, string);
1188 void mpd_sendCurrentSongCommand(mpd_Connection * connection)
1190 mpd_executeCommand(connection, "currentsong\n");
1194 mpd_sendSearchCommand(mpd_Connection * connection, int table,
1199 char *sanitStr = mpd_sanitizeArg(str);
1200 if (table == MPD_TABLE_ARTIST)
1201 strcpy(st, "artist");
1202 else if (table == MPD_TABLE_ALBUM)
1203 strcpy(st, "album");
1204 else if (table == MPD_TABLE_TITLE)
1205 strcpy(st, "title");
1206 else if (table == MPD_TABLE_FILENAME)
1207 strcpy(st, "filename");
1209 connection->error = 1;
1210 strcpy(connection->errorStr, "unknown table for search");
1214 malloc(strlen("search") + strlen(sanitStr) + strlen(st) + 6);
1215 sprintf(string, "search %s \"%s\"\n", st, sanitStr);
1216 mpd_sendInfoCommand(connection, string);
1222 mpd_sendFindCommand(mpd_Connection * connection, int table,
1227 char *sanitStr = mpd_sanitizeArg(str);
1228 if (table == MPD_TABLE_ARTIST)
1229 strcpy(st, "artist");
1230 else if (table == MPD_TABLE_ALBUM)
1231 strcpy(st, "album");
1232 else if (table == MPD_TABLE_TITLE)
1233 strcpy(st, "title");
1235 connection->error = 1;
1236 strcpy(connection->errorStr, "unknown table for find");
1240 malloc(strlen("find") + strlen(sanitStr) + strlen(st) + 6);
1241 sprintf(string, "find %s \"%s\"\n", st, sanitStr);
1242 mpd_sendInfoCommand(connection, string);
1248 mpd_sendListCommand(mpd_Connection * connection, int table,
1253 if (table == MPD_TABLE_ARTIST)
1254 strcpy(st, "artist");
1255 else if (table == MPD_TABLE_ALBUM)
1256 strcpy(st, "album");
1258 connection->error = 1;
1259 strcpy(connection->errorStr, "unknown table for list");
1263 char *sanitArg1 = mpd_sanitizeArg(arg1);
1265 malloc(strlen("list") + strlen(sanitArg1) +
1267 sprintf(string, "list %s \"%s\"\n", st, sanitArg1);
1270 string = malloc(strlen("list") + strlen(st) + 3);
1271 sprintf(string, "list %s\n", st);
1273 mpd_sendInfoCommand(connection, string);
1277 void mpd_sendAddCommand(mpd_Connection * connection, const char *file)
1279 char *sFile = mpd_sanitizeArg(file);
1280 char *string = malloc(strlen("add") + strlen(sFile) + 5);
1281 sprintf(string, "add \"%s\"\n", sFile);
1282 mpd_executeCommand(connection, string);
1287 void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos)
1289 char *string = malloc(strlen("delete") + 25);
1290 sprintf(string, "delete \"%i\"\n", songPos);
1291 mpd_sendInfoCommand(connection, string);
1295 void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id)
1297 char *string = malloc(strlen("deleteid") + 25);
1298 sprintf(string, "deleteid \"%i\"\n", id);
1299 mpd_sendInfoCommand(connection, string);
1303 void mpd_sendSaveCommand(mpd_Connection * connection, const char *name)
1305 char *sName = mpd_sanitizeArg(name);
1306 char *string = malloc(strlen("save") + strlen(sName) + 5);
1307 sprintf(string, "save \"%s\"\n", sName);
1308 mpd_executeCommand(connection, string);
1313 void mpd_sendLoadCommand(mpd_Connection * connection, const char *name)
1315 char *sName = mpd_sanitizeArg(name);
1316 char *string = malloc(strlen("load") + strlen(sName) + 5);
1317 sprintf(string, "load \"%s\"\n", sName);
1318 mpd_executeCommand(connection, string);
1323 void mpd_sendRmCommand(mpd_Connection * connection, const char *name)
1325 char *sName = mpd_sanitizeArg(name);
1326 char *string = malloc(strlen("rm") + strlen(sName) + 5);
1327 sprintf(string, "rm \"%s\"\n", sName);
1328 mpd_executeCommand(connection, string);
1333 void mpd_sendShuffleCommand(mpd_Connection * connection)
1335 mpd_executeCommand(connection, "shuffle\n");
1338 void mpd_sendClearCommand(mpd_Connection * connection)
1340 mpd_executeCommand(connection, "clear\n");
1343 void mpd_sendPlayCommand(mpd_Connection * connection, int songPos)
1345 char *string = malloc(strlen("play") + 25);
1346 sprintf(string, "play \"%i\"\n", songPos);
1347 mpd_sendInfoCommand(connection, string);
1351 void mpd_sendPlayIdCommand(mpd_Connection * connection, int id)
1353 char *string = malloc(strlen("playid") + 25);
1354 sprintf(string, "playid \"%i\"\n", id);
1355 mpd_sendInfoCommand(connection, string);
1359 void mpd_sendStopCommand(mpd_Connection * connection)
1361 mpd_executeCommand(connection, "stop\n");
1364 void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode)
1366 char *string = malloc(strlen("pause") + 25);
1367 sprintf(string, "pause \"%i\"\n", pauseMode);
1368 mpd_executeCommand(connection, string);
1372 void mpd_sendNextCommand(mpd_Connection * connection)
1374 mpd_executeCommand(connection, "next\n");
1377 void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to)
1379 char *string = malloc(strlen("move") + 25);
1380 sprintf(string, "move \"%i\" \"%i\"\n", from, to);
1381 mpd_sendInfoCommand(connection, string);
1385 void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to)
1387 char *string = malloc(strlen("moveid") + 25);
1388 sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
1389 mpd_sendInfoCommand(connection, string);
1393 void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2)
1395 char *string = malloc(strlen("swap") + 25);
1396 sprintf(string, "swap \"%i\" \"%i\"\n", song1, song2);
1397 mpd_sendInfoCommand(connection, string);
1401 void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2)
1403 char *string = malloc(strlen("swapid") + 25);
1404 sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
1405 mpd_sendInfoCommand(connection, string);
1409 void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time)
1411 char *string = malloc(strlen("seek") + 25);
1412 sprintf(string, "seek \"%i\" \"%i\"\n", song, time);
1413 mpd_sendInfoCommand(connection, string);
1417 void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time)
1419 char *string = malloc(strlen("seekid") + 25);
1420 sprintf(string, "seekid \"%i\" \"%i\"\n", id, time);
1421 mpd_sendInfoCommand(connection, string);
1425 void mpd_sendUpdateCommand(mpd_Connection * connection, char *path)
1427 char *sPath = mpd_sanitizeArg(path);
1428 char *string = malloc(strlen("update") + strlen(sPath) + 5);
1429 sprintf(string, "update \"%s\"\n", sPath);
1430 mpd_sendInfoCommand(connection, string);
1435 int mpd_getUpdateId(mpd_Connection * connection)
1440 jobid = mpd_getNextReturnElementNamed(connection, "updating_db");
1449 void mpd_sendPrevCommand(mpd_Connection * connection)
1451 mpd_executeCommand(connection, "previous\n");
1454 void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode)
1456 char *string = malloc(strlen("repeat") + 25);
1457 sprintf(string, "repeat \"%i\"\n", repeatMode);
1458 mpd_executeCommand(connection, string);
1462 void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode)
1464 char *string = malloc(strlen("random") + 25);
1465 sprintf(string, "random \"%i\"\n", randomMode);
1466 mpd_executeCommand(connection, string);
1470 void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange)
1472 char *string = malloc(strlen("setvol") + 25);
1473 sprintf(string, "setvol \"%i\"\n", volumeChange);
1474 mpd_executeCommand(connection, string);
1478 void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange)
1480 char *string = malloc(strlen("volume") + 25);
1481 sprintf(string, "volume \"%i\"\n", volumeChange);
1482 mpd_executeCommand(connection, string);
1486 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)
1496 char *sPass = mpd_sanitizeArg(pass);
1497 char *string = malloc(strlen("password") + strlen(sPass) + 5);
1498 sprintf(string, "password \"%s\"\n", sPass);
1499 mpd_executeCommand(connection, string);
1504 void mpd_sendCommandListBegin(mpd_Connection * connection)
1506 if (connection->commandList) {
1507 strcpy(connection->errorStr,
1508 "already in command list mode");
1509 connection->error = 1;
1512 connection->commandList = COMMAND_LIST;
1513 mpd_executeCommand(connection, "command_list_begin\n");
1516 void mpd_sendCommandListOkBegin(mpd_Connection * connection)
1518 if (connection->commandList) {
1519 strcpy(connection->errorStr,
1520 "already in command list mode");
1521 connection->error = 1;
1524 connection->commandList = COMMAND_LIST_OK;
1525 mpd_executeCommand(connection, "command_list_ok_begin\n");
1526 connection->listOks = 0;
1529 void mpd_sendCommandListEnd(mpd_Connection * connection)
1531 if (!connection->commandList) {
1532 strcpy(connection->errorStr, "not in command list mode");
1533 connection->error = 1;
1536 connection->commandList = 0;
1537 mpd_executeCommand(connection, "command_list_end\n");
1540 void mpd_signalHandler(int signal)
1542 if (signal == SIGPIPE) {
1543 fprintf(stderr, "Conky: recieved SIGPIPE from MPD connection\n");