mirror of
https://github.com/Llewellynvdm/conky.git
synced 2024-12-27 04:32:55 +00:00
1518 lines
38 KiB
C
1518 lines
38 KiB
C
|
/* libmpdclient
|
||
|
(c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
|
||
|
This project's homepage is: http://www.musicpd.org
|
||
|
|
||
|
Redistribution and use in source and binary forms, with or without
|
||
|
modification, are permitted provided that the following conditions
|
||
|
are met:
|
||
|
|
||
|
- Redistributions of source code must retain the above copyright
|
||
|
notice, this list of conditions and the following disclaimer.
|
||
|
|
||
|
- Redistributions in binary form must reproduce the above copyright
|
||
|
notice, this list of conditions and the following disclaimer in the
|
||
|
documentation and/or other materials provided with the distribution.
|
||
|
|
||
|
- Neither the name of the Music Player Daemon nor the names of its
|
||
|
contributors may be used to endorse or promote products derived from
|
||
|
this software without specific prior written permission.
|
||
|
|
||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "libmpdclient.h"
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <netdb.h>
|
||
|
#include <stdio.h>
|
||
|
#include <sys/param.h>
|
||
|
#include <string.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <fcntl.h>
|
||
|
|
||
|
#ifndef MPD_NO_IPV6
|
||
|
#ifdef AF_INET6
|
||
|
#define MPD_HAVE_IPV6
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#define COMMAND_LIST 1
|
||
|
#define COMMAND_LIST_OK 2
|
||
|
|
||
|
#ifdef MPD_HAVE_IPV6
|
||
|
int mpd_ipv6Supported()
|
||
|
{
|
||
|
int s;
|
||
|
s = socket(AF_INET6, SOCK_STREAM, 0);
|
||
|
if (s == -1)
|
||
|
return 0;
|
||
|
close(s);
|
||
|
return 1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
char *mpd_sanitizeArg(const char *arg)
|
||
|
{
|
||
|
size_t i;
|
||
|
int count = 0;
|
||
|
char *ret;
|
||
|
|
||
|
for (i = 0; i < strlen(arg); i++) {
|
||
|
if (arg[i] == '"' || arg[i] == '\\')
|
||
|
count++;
|
||
|
}
|
||
|
|
||
|
ret = malloc(strlen(arg) + count + 1);
|
||
|
|
||
|
count = 0;
|
||
|
for (i = 0; i < strlen(arg) + 1; i++) {
|
||
|
if (arg[i] == '"' || arg[i] == '\\') {
|
||
|
ret[i + count] = '\\';
|
||
|
count++;
|
||
|
}
|
||
|
ret[i + count] = arg[i];
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
mpd_ReturnElement *mpd_newReturnElement(const char *name,
|
||
|
const char *value)
|
||
|
{
|
||
|
mpd_ReturnElement *ret = malloc(sizeof(mpd_ReturnElement));
|
||
|
|
||
|
ret->name = strdup(name);
|
||
|
ret->value = strdup(value);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void mpd_freeReturnElement(mpd_ReturnElement * re)
|
||
|
{
|
||
|
free(re->name);
|
||
|
free(re->value);
|
||
|
free(re);
|
||
|
}
|
||
|
|
||
|
void mpd_setConnectionTimeout(mpd_Connection * connection, float timeout)
|
||
|
{
|
||
|
connection->timeout.tv_sec = (int) timeout;
|
||
|
connection->timeout.tv_usec = (int) (timeout * 1e6 -
|
||
|
connection->timeout.tv_sec *
|
||
|
1000000 + 0.5);
|
||
|
}
|
||
|
|
||
|
mpd_Connection *mpd_newConnection(const char *host, int port,
|
||
|
float timeout)
|
||
|
{
|
||
|
int err;
|
||
|
struct hostent *he;
|
||
|
struct sockaddr *dest;
|
||
|
#ifdef HAVE_SOCKLEN_T
|
||
|
socklen_t destlen;
|
||
|
#else
|
||
|
int destlen;
|
||
|
#endif
|
||
|
struct sockaddr_in sin;
|
||
|
char *rt;
|
||
|
char *output;
|
||
|
mpd_Connection *connection = malloc(sizeof(mpd_Connection));
|
||
|
struct timeval tv;
|
||
|
fd_set fds;
|
||
|
#ifdef MPD_HAVE_IPV6
|
||
|
struct sockaddr_in6 sin6;
|
||
|
#endif
|
||
|
strcpy(connection->buffer, "");
|
||
|
connection->buflen = 0;
|
||
|
connection->bufstart = 0;
|
||
|
strcpy(connection->errorStr, "");
|
||
|
connection->error = 0;
|
||
|
connection->doneProcessing = 0;
|
||
|
connection->commandList = 0;
|
||
|
connection->listOks = 0;
|
||
|
connection->doneListOk = 0;
|
||
|
connection->returnElement = NULL;
|
||
|
|
||
|
if (!(he = gethostbyname(host))) {
|
||
|
snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
|
||
|
"host \"%s\" not found", host);
|
||
|
connection->error = MPD_ERROR_UNKHOST;
|
||
|
return connection;
|
||
|
}
|
||
|
|
||
|
memset(&sin, 0, sizeof(struct sockaddr_in));
|
||
|
/*dest.sin_family = he->h_addrtype; */
|
||
|
sin.sin_family = AF_INET;
|
||
|
sin.sin_port = htons(port);
|
||
|
#ifdef MPD_HAVE_IPV6
|
||
|
memset(&sin6, 0, sizeof(struct sockaddr_in6));
|
||
|
sin6.sin6_family = AF_INET6;
|
||
|
sin6.sin6_port = htons(port);
|
||
|
#endif
|
||
|
switch (he->h_addrtype) {
|
||
|
case AF_INET:
|
||
|
memcpy((char *) &sin.sin_addr.s_addr, (char *) he->h_addr,
|
||
|
he->h_length);
|
||
|
dest = (struct sockaddr *) &sin;
|
||
|
destlen = sizeof(struct sockaddr_in);
|
||
|
break;
|
||
|
#ifdef MPD_HAVE_IPV6
|
||
|
case AF_INET6:
|
||
|
if (!mpd_ipv6Supported()) {
|
||
|
strcpy(connection->errorStr,
|
||
|
"no IPv6 suuport but a "
|
||
|
"IPv6 address found\n");
|
||
|
connection->error = MPD_ERROR_SYSTEM;
|
||
|
return connection;
|
||
|
}
|
||
|
memcpy((char *) &sin6.sin6_addr.s6_addr,
|
||
|
(char *) he->h_addr, he->h_length);
|
||
|
dest = (struct sockaddr *) &sin6;
|
||
|
destlen = sizeof(struct sockaddr_in6);
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
strcpy(connection->errorStr,
|
||
|
"address type is not IPv4 or " "IPv6\n");
|
||
|
connection->error = MPD_ERROR_SYSTEM;
|
||
|
return connection;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((connection->sock =
|
||
|
socket(dest->sa_family, SOCK_STREAM, 0)) < 0) {
|
||
|
strcpy(connection->errorStr, "problems creating socket");
|
||
|
connection->error = MPD_ERROR_SYSTEM;
|
||
|
return connection;
|
||
|
}
|
||
|
|
||
|
mpd_setConnectionTimeout(connection, timeout);
|
||
|
|
||
|
/* connect stuff */
|
||
|
{
|
||
|
int flags = fcntl(connection->sock, F_GETFL, 0);
|
||
|
fcntl(connection->sock, F_SETFL, flags | O_NONBLOCK);
|
||
|
|
||
|
if (connect(connection->sock, dest, destlen) < 0
|
||
|
&& errno != EINPROGRESS) {
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"problems connecting to \"%s\" on port"
|
||
|
" %i", host, port);
|
||
|
connection->error = MPD_ERROR_CONNPORT;
|
||
|
return connection;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (!(rt = strstr(connection->buffer, "\n"))) {
|
||
|
tv.tv_sec = connection->timeout.tv_sec;
|
||
|
tv.tv_usec = connection->timeout.tv_usec;
|
||
|
FD_ZERO(&fds);
|
||
|
FD_SET(connection->sock, &fds);
|
||
|
if ((err =
|
||
|
select(connection->sock + 1, &fds, NULL, NULL,
|
||
|
&tv)) == 1) {
|
||
|
int readed;
|
||
|
readed = recv(connection->sock,
|
||
|
&(connection->
|
||
|
buffer[connection->buflen]),
|
||
|
MPD_BUFFER_MAX_LENGTH -
|
||
|
connection->buflen, 0);
|
||
|
if (readed <= 0) {
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"problems getting a response from"
|
||
|
" \"%s\" on port %i", host, port);
|
||
|
connection->error = MPD_ERROR_NORESPONSE;
|
||
|
return connection;
|
||
|
}
|
||
|
connection->buflen += readed;
|
||
|
connection->buffer[connection->buflen] = '\0';
|
||
|
tv.tv_sec = connection->timeout.tv_sec;
|
||
|
tv.tv_usec = connection->timeout.tv_usec;
|
||
|
} else if (err < 0) {
|
||
|
switch (errno) {
|
||
|
case EINTR:
|
||
|
continue;
|
||
|
default:
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"problems connecting to \"%s\" on port"
|
||
|
" %i", host, port);
|
||
|
connection->error = MPD_ERROR_CONNPORT;
|
||
|
return connection;
|
||
|
}
|
||
|
} else {
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"timeout in attempting to get a response from"
|
||
|
" \"%s\" on port %i", host, port);
|
||
|
connection->error = MPD_ERROR_NORESPONSE;
|
||
|
return connection;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*rt = '\0';
|
||
|
output = strdup(connection->buffer);
|
||
|
strcpy(connection->buffer, rt + 1);
|
||
|
connection->buflen = strlen(connection->buffer);
|
||
|
|
||
|
if (strncmp
|
||
|
(output, MPD_WELCOME_MESSAGE, strlen(MPD_WELCOME_MESSAGE))) {
|
||
|
free(output);
|
||
|
snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
|
||
|
"mpd not running on port %i on host \"%s\"", port,
|
||
|
host);
|
||
|
connection->error = MPD_ERROR_NOTMPD;
|
||
|
return connection;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
char *test;
|
||
|
char *version[3];
|
||
|
char *tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
|
||
|
char *search = ".";
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < 3; i++) {
|
||
|
char *tok;
|
||
|
if (i == 3)
|
||
|
search = " ";
|
||
|
version[i] = strtok_r(tmp, search, &tok);
|
||
|
if (!version[i]) {
|
||
|
free(output);
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"error parsing version number at "
|
||
|
"\"%s\"",
|
||
|
&output[strlen
|
||
|
(MPD_WELCOME_MESSAGE)]);
|
||
|
connection->error = MPD_ERROR_NOTMPD;
|
||
|
return connection;
|
||
|
}
|
||
|
connection->version[i] =
|
||
|
strtol(version[i], &test, 10);
|
||
|
if (version[i] == test || *test != '\0') {
|
||
|
free(output);
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"error parsing version number at "
|
||
|
"\"%s\"",
|
||
|
&output[strlen
|
||
|
(MPD_WELCOME_MESSAGE)]);
|
||
|
connection->error = MPD_ERROR_NOTMPD;
|
||
|
return connection;
|
||
|
}
|
||
|
tmp = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(output);
|
||
|
|
||
|
connection->doneProcessing = 1;
|
||
|
|
||
|
return connection;
|
||
|
}
|
||
|
|
||
|
void mpd_clearError(mpd_Connection * connection)
|
||
|
{
|
||
|
connection->error = 0;
|
||
|
connection->errorStr[0] = '\0';
|
||
|
}
|
||
|
|
||
|
void mpd_closeConnection(mpd_Connection * connection)
|
||
|
{
|
||
|
close(connection->sock);
|
||
|
if (connection->returnElement)
|
||
|
free(connection->returnElement);
|
||
|
free(connection);
|
||
|
}
|
||
|
|
||
|
void mpd_executeCommand(mpd_Connection * connection, char *command)
|
||
|
{
|
||
|
int ret;
|
||
|
struct timeval tv;
|
||
|
fd_set fds;
|
||
|
char *commandPtr = command;
|
||
|
int commandLen = strlen(command);
|
||
|
|
||
|
if (!connection->doneProcessing && !connection->commandList) {
|
||
|
strcpy(connection->errorStr,
|
||
|
"not done processing current command");
|
||
|
connection->error = 1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mpd_clearError(connection);
|
||
|
|
||
|
FD_ZERO(&fds);
|
||
|
FD_SET(connection->sock, &fds);
|
||
|
tv.tv_sec = connection->timeout.tv_sec;
|
||
|
tv.tv_usec = connection->timeout.tv_usec;
|
||
|
|
||
|
while ((ret =
|
||
|
select(connection->sock + 1, NULL, &fds, NULL, &tv) == 1)
|
||
|
|| (ret == -1 && errno == EINTR)) {
|
||
|
ret =
|
||
|
send(connection->sock, commandPtr, commandLen,
|
||
|
MSG_DONTWAIT);
|
||
|
if (ret <= 0) {
|
||
|
if (ret == EAGAIN || ret == EINTR)
|
||
|
continue;
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"problems giving command \"%s\"",
|
||
|
command);
|
||
|
connection->error = MPD_ERROR_SENDING;
|
||
|
return;
|
||
|
} else {
|
||
|
commandPtr += ret;
|
||
|
commandLen -= ret;
|
||
|
}
|
||
|
|
||
|
if (commandLen <= 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (commandLen > 0) {
|
||
|
perror("");
|
||
|
snprintf(connection->errorStr, MPD_BUFFER_MAX_LENGTH,
|
||
|
"timeout sending command \"%s\"", command);
|
||
|
connection->error = MPD_ERROR_TIMEOUT;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!connection->commandList)
|
||
|
connection->doneProcessing = 0;
|
||
|
else if (connection->commandList == COMMAND_LIST_OK) {
|
||
|
connection->listOks++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void mpd_getNextReturnElement(mpd_Connection * connection)
|
||
|
{
|
||
|
char *output = NULL;
|
||
|
char *rt = NULL;
|
||
|
char *name = NULL;
|
||
|
char *value = NULL;
|
||
|
fd_set fds;
|
||
|
struct timeval tv;
|
||
|
char *tok = NULL;
|
||
|
int readed;
|
||
|
char *bufferCheck = NULL;
|
||
|
int err;
|
||
|
|
||
|
if (connection->returnElement)
|
||
|
mpd_freeReturnElement(connection->returnElement);
|
||
|
connection->returnElement = NULL;
|
||
|
|
||
|
if (connection->doneProcessing || (connection->listOks &&
|
||
|
connection->doneListOk)) {
|
||
|
strcpy(connection->errorStr,
|
||
|
"already done processing current command");
|
||
|
connection->error = 1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bufferCheck = connection->buffer + connection->bufstart;
|
||
|
while (connection->bufstart >= connection->buflen ||
|
||
|
!(rt = strstr(bufferCheck, "\n"))) {
|
||
|
if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
|
||
|
memmove(connection->buffer,
|
||
|
connection->buffer +
|
||
|
connection->bufstart,
|
||
|
connection->buflen - connection->bufstart +
|
||
|
1);
|
||
|
bufferCheck -= connection->bufstart;
|
||
|
connection->buflen -= connection->bufstart;
|
||
|
connection->bufstart = 0;
|
||
|
}
|
||
|
if (connection->buflen >= MPD_BUFFER_MAX_LENGTH) {
|
||
|
strcpy(connection->errorStr, "buffer overrun");
|
||
|
connection->error = MPD_ERROR_BUFFEROVERRUN;
|
||
|
connection->doneProcessing = 1;
|
||
|
connection->doneListOk = 0;
|
||
|
return;
|
||
|
}
|
||
|
bufferCheck += connection->buflen - connection->bufstart;
|
||
|
tv.tv_sec = connection->timeout.tv_sec;
|
||
|
tv.tv_usec = connection->timeout.tv_usec;
|
||
|
FD_ZERO(&fds);
|
||
|
FD_SET(connection->sock, &fds);
|
||
|
if ((err =
|
||
|
select(connection->sock + 1, &fds, NULL, NULL,
|
||
|
&tv) == 1)) {
|
||
|
readed =
|
||
|
recv(connection->sock,
|
||
|
connection->buffer + connection->buflen,
|
||
|
MPD_BUFFER_MAX_LENGTH -
|
||
|
connection->buflen, MSG_DONTWAIT);
|
||
|
if (readed < 0
|
||
|
&& (errno == EAGAIN || errno == EINTR)) {
|
||
|
continue;
|
||
|
}
|
||
|
if (readed <= 0) {
|
||
|
strcpy(connection->errorStr,
|
||
|
"connection" " closed");
|
||
|
connection->error = MPD_ERROR_CONNCLOSED;
|
||
|
connection->doneProcessing = 1;
|
||
|
connection->doneListOk = 0;
|
||
|
return;
|
||
|
}
|
||
|
connection->buflen += readed;
|
||
|
connection->buffer[connection->buflen] = '\0';
|
||
|
} else if (err < 0 && errno == EINTR)
|
||
|
continue;
|
||
|
else {
|
||
|
strcpy(connection->errorStr, "connection timeout");
|
||
|
connection->error = MPD_ERROR_TIMEOUT;
|
||
|
connection->doneProcessing = 1;
|
||
|
connection->doneListOk = 0;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*rt = '\0';
|
||
|
output = connection->buffer + connection->bufstart;
|
||
|
connection->bufstart = rt - connection->buffer + 1;
|
||
|
|
||
|
if (strcmp(output, "OK") == 0) {
|
||
|
if (connection->listOks > 0) {
|
||
|
strcpy(connection->errorStr,
|
||
|
"expected more list_OK's");
|
||
|
connection->error = 1;
|
||
|
}
|
||
|
connection->listOks = 0;
|
||
|
connection->doneProcessing = 1;
|
||
|
connection->doneListOk = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (strcmp(output, "list_OK") == 0) {
|
||
|
if (!connection->listOks) {
|
||
|
strcpy(connection->errorStr,
|
||
|
"got an unexpected list_OK");
|
||
|
connection->error = 1;
|
||
|
} else {
|
||
|
connection->doneListOk = 1;
|
||
|
connection->listOks--;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (strncmp(output, "ACK", strlen("ACK")) == 0) {
|
||
|
char *test;
|
||
|
char *needle;
|
||
|
int val;
|
||
|
|
||
|
strcpy(connection->errorStr, output);
|
||
|
connection->error = MPD_ERROR_ACK;
|
||
|
connection->errorCode = MPD_ACK_ERROR_UNK;
|
||
|
connection->errorAt = MPD_ERROR_AT_UNK;
|
||
|
connection->doneProcessing = 1;
|
||
|
connection->doneListOk = 0;
|
||
|
|
||
|
needle = strchr(output, '[');
|
||
|
if (!needle)
|
||
|
return;
|
||
|
val = strtol(needle + 1, &test, 10);
|
||
|
if (*test != '@')
|
||
|
return;
|
||
|
connection->errorCode = val;
|
||
|
val = strtol(test + 1, &test, 10);
|
||
|
if (*test != ']')
|
||
|
return;
|
||
|
connection->errorAt = val;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
name = strtok_r(output, ":", &tok);
|
||
|
if (name && (value = strtok_r(NULL, "", &tok)) && value[0] == ' ') {
|
||
|
connection->returnElement =
|
||
|
mpd_newReturnElement(name, &(value[1]));
|
||
|
} else {
|
||
|
if (!name || !value) {
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"error parsing: %s", output);
|
||
|
} else {
|
||
|
snprintf(connection->errorStr,
|
||
|
MPD_BUFFER_MAX_LENGTH,
|
||
|
"error parsing: %s:%s", name, value);
|
||
|
}
|
||
|
connection->errorStr[MPD_BUFFER_MAX_LENGTH] = '\0';
|
||
|
connection->error = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void mpd_finishCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
while (!connection->doneProcessing) {
|
||
|
if (connection->doneListOk)
|
||
|
connection->doneListOk = 0;
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void mpd_finishListOkCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
while (!connection->doneProcessing && connection->listOks &&
|
||
|
!connection->doneListOk) {
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int mpd_nextListOkCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_finishListOkCommand(connection);
|
||
|
if (!connection->doneProcessing)
|
||
|
connection->doneListOk = 0;
|
||
|
if (connection->listOks == 0 || connection->doneProcessing)
|
||
|
return -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void mpd_sendStatusCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_executeCommand(connection, "status\n");
|
||
|
}
|
||
|
|
||
|
mpd_Status *mpd_getStatus(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_Status *status;
|
||
|
|
||
|
/*mpd_executeCommand(connection,"status\n");
|
||
|
|
||
|
if(connection->error) return NULL; */
|
||
|
|
||
|
if (connection->doneProcessing || (connection->listOks &&
|
||
|
connection->doneListOk)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!connection->returnElement)
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
|
||
|
status = malloc(sizeof(mpd_Status));
|
||
|
status->volume = -1;
|
||
|
status->repeat = 0;
|
||
|
status->random = 0;
|
||
|
status->playlist = -1;
|
||
|
status->playlistLength = -1;
|
||
|
status->state = -1;
|
||
|
status->song = 0;
|
||
|
status->elapsedTime = 0;
|
||
|
status->totalTime = 0;
|
||
|
status->bitRate = 0;
|
||
|
status->sampleRate = 0;
|
||
|
status->bits = 0;
|
||
|
status->channels = 0;
|
||
|
status->crossfade = -1;
|
||
|
status->error = NULL;
|
||
|
status->updatingDb = 0;
|
||
|
|
||
|
if (connection->error) {
|
||
|
free(status);
|
||
|
return NULL;
|
||
|
}
|
||
|
while (connection->returnElement) {
|
||
|
mpd_ReturnElement *re = connection->returnElement;
|
||
|
if (strcmp(re->name, "volume") == 0) {
|
||
|
status->volume = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "repeat") == 0) {
|
||
|
status->repeat = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "random") == 0) {
|
||
|
status->random = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "playlist") == 0) {
|
||
|
status->playlist = strtol(re->value, NULL, 10);
|
||
|
} else if (strcmp(re->name, "playlistlength") == 0) {
|
||
|
status->playlistLength = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "bitrate") == 0) {
|
||
|
status->bitRate = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "state") == 0) {
|
||
|
if (strcmp(re->value, "play") == 0) {
|
||
|
status->state = MPD_STATUS_STATE_PLAY;
|
||
|
} else if (strcmp(re->value, "stop") == 0) {
|
||
|
status->state = MPD_STATUS_STATE_STOP;
|
||
|
} else if (strcmp(re->value, "pause") == 0) {
|
||
|
status->state = MPD_STATUS_STATE_PAUSE;
|
||
|
} else {
|
||
|
status->state = MPD_STATUS_STATE_UNKNOWN;
|
||
|
}
|
||
|
} else if (strcmp(re->name, "song") == 0) {
|
||
|
status->song = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "songid") == 0) {
|
||
|
status->songid = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "time") == 0) {
|
||
|
char *tok;
|
||
|
char *copy;
|
||
|
char *temp;
|
||
|
copy = strdup(re->value);
|
||
|
temp = strtok_r(copy, ":", &tok);
|
||
|
if (temp) {
|
||
|
status->elapsedTime = atoi(temp);
|
||
|
temp = strtok_r(NULL, "", &tok);
|
||
|
if (temp)
|
||
|
status->totalTime = atoi(temp);
|
||
|
}
|
||
|
free(copy);
|
||
|
} else if (strcmp(re->name, "error") == 0) {
|
||
|
status->error = strdup(re->value);
|
||
|
} else if (strcmp(re->name, "xfade") == 0) {
|
||
|
status->crossfade = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "updating_db") == 0) {
|
||
|
status->updatingDb = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "audio") == 0) {
|
||
|
char *tok;
|
||
|
char *copy;
|
||
|
char *temp;
|
||
|
copy = strdup(re->value);
|
||
|
temp = strtok_r(copy, ":", &tok);
|
||
|
if (temp) {
|
||
|
status->sampleRate = atoi(temp);
|
||
|
temp = strtok_r(NULL, ":", &tok);
|
||
|
if (temp) {
|
||
|
status->bits = atoi(temp);
|
||
|
temp = strtok_r(NULL, "", &tok);
|
||
|
if (temp)
|
||
|
status->channels =
|
||
|
atoi(temp);
|
||
|
}
|
||
|
}
|
||
|
free(copy);
|
||
|
}
|
||
|
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
if (connection->error) {
|
||
|
free(status);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (connection->error) {
|
||
|
free(status);
|
||
|
return NULL;
|
||
|
} else if (status->state < 0) {
|
||
|
strcpy(connection->errorStr, "state not found");
|
||
|
connection->error = 1;
|
||
|
free(status);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
void mpd_freeStatus(mpd_Status * status)
|
||
|
{
|
||
|
if (status->error)
|
||
|
free(status->error);
|
||
|
free(status);
|
||
|
}
|
||
|
|
||
|
void mpd_sendStatsCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_executeCommand(connection, "stats\n");
|
||
|
}
|
||
|
|
||
|
mpd_Stats *mpd_getStats(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_Stats *stats;
|
||
|
|
||
|
/*mpd_executeCommand(connection,"stats\n");
|
||
|
|
||
|
if(connection->error) return NULL; */
|
||
|
|
||
|
if (connection->doneProcessing || (connection->listOks &&
|
||
|
connection->doneListOk)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!connection->returnElement)
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
|
||
|
stats = malloc(sizeof(mpd_Stats));
|
||
|
stats->numberOfArtists = 0;
|
||
|
stats->numberOfAlbums = 0;
|
||
|
stats->numberOfSongs = 0;
|
||
|
stats->uptime = 0;
|
||
|
stats->dbUpdateTime = 0;
|
||
|
stats->playTime = 0;
|
||
|
stats->dbPlayTime = 0;
|
||
|
|
||
|
if (connection->error) {
|
||
|
free(stats);
|
||
|
return NULL;
|
||
|
}
|
||
|
while (connection->returnElement) {
|
||
|
mpd_ReturnElement *re = connection->returnElement;
|
||
|
if (strcmp(re->name, "artists") == 0) {
|
||
|
stats->numberOfArtists = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "albums") == 0) {
|
||
|
stats->numberOfAlbums = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "songs") == 0) {
|
||
|
stats->numberOfSongs = atoi(re->value);
|
||
|
} else if (strcmp(re->name, "uptime") == 0) {
|
||
|
stats->uptime = strtol(re->value, NULL, 10);
|
||
|
} else if (strcmp(re->name, "db_update") == 0) {
|
||
|
stats->dbUpdateTime = strtol(re->value, NULL, 10);
|
||
|
} else if (strcmp(re->name, "playtime") == 0) {
|
||
|
stats->playTime = strtol(re->value, NULL, 10);
|
||
|
} else if (strcmp(re->name, "db_playtime") == 0) {
|
||
|
stats->dbPlayTime = strtol(re->value, NULL, 10);
|
||
|
}
|
||
|
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
if (connection->error) {
|
||
|
free(stats);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (connection->error) {
|
||
|
free(stats);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return stats;
|
||
|
}
|
||
|
|
||
|
void mpd_freeStats(mpd_Stats * stats)
|
||
|
{
|
||
|
free(stats);
|
||
|
}
|
||
|
|
||
|
void mpd_initSong(mpd_Song * song)
|
||
|
{
|
||
|
song->file = NULL;
|
||
|
song->artist = NULL;
|
||
|
song->album = NULL;
|
||
|
song->track = NULL;
|
||
|
song->title = NULL;
|
||
|
song->name = NULL;
|
||
|
song->time = MPD_SONG_NO_TIME;
|
||
|
song->pos = MPD_SONG_NO_NUM;
|
||
|
song->id = MPD_SONG_NO_ID;
|
||
|
}
|
||
|
|
||
|
void mpd_finishSong(mpd_Song * song)
|
||
|
{
|
||
|
if (song->file)
|
||
|
free(song->file);
|
||
|
if (song->artist)
|
||
|
free(song->artist);
|
||
|
if (song->album)
|
||
|
free(song->album);
|
||
|
if (song->title)
|
||
|
free(song->title);
|
||
|
if (song->track)
|
||
|
free(song->track);
|
||
|
if (song->name)
|
||
|
free(song->name);
|
||
|
}
|
||
|
|
||
|
mpd_Song *mpd_newSong()
|
||
|
{
|
||
|
mpd_Song *ret = malloc(sizeof(mpd_Song));
|
||
|
|
||
|
mpd_initSong(ret);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void mpd_freeSong(mpd_Song * song)
|
||
|
{
|
||
|
mpd_finishSong(song);
|
||
|
free(song);
|
||
|
}
|
||
|
|
||
|
mpd_Song *mpd_songDup(mpd_Song * song)
|
||
|
{
|
||
|
mpd_Song *ret = mpd_newSong();
|
||
|
|
||
|
if (song->file)
|
||
|
ret->file = strdup(song->file);
|
||
|
if (song->artist)
|
||
|
ret->artist = strdup(song->artist);
|
||
|
if (song->album)
|
||
|
ret->album = strdup(song->album);
|
||
|
if (song->title)
|
||
|
ret->title = strdup(song->title);
|
||
|
if (song->track)
|
||
|
ret->track = strdup(song->track);
|
||
|
if (song->name)
|
||
|
ret->name = strdup(song->name);
|
||
|
ret->time = song->time;
|
||
|
ret->pos = song->pos;
|
||
|
ret->id = song->id;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void mpd_initDirectory(mpd_Directory * directory)
|
||
|
{
|
||
|
directory->path = NULL;
|
||
|
}
|
||
|
|
||
|
void mpd_finishDirectory(mpd_Directory * directory)
|
||
|
{
|
||
|
if (directory->path)
|
||
|
free(directory->path);
|
||
|
}
|
||
|
|
||
|
mpd_Directory *mpd_newDirectory()
|
||
|
{
|
||
|
mpd_Directory *directory = malloc(sizeof(mpd_Directory));;
|
||
|
|
||
|
mpd_initDirectory(directory);
|
||
|
|
||
|
return directory;
|
||
|
}
|
||
|
|
||
|
void mpd_freeDirectory(mpd_Directory * directory)
|
||
|
{
|
||
|
mpd_finishDirectory(directory);
|
||
|
|
||
|
free(directory);
|
||
|
}
|
||
|
|
||
|
mpd_Directory *mpd_directoryDup(mpd_Directory * directory)
|
||
|
{
|
||
|
mpd_Directory *ret = mpd_newDirectory();
|
||
|
|
||
|
if (directory->path)
|
||
|
ret->path = strdup(directory->path);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void mpd_initPlaylistFile(mpd_PlaylistFile * playlist)
|
||
|
{
|
||
|
playlist->path = NULL;
|
||
|
}
|
||
|
|
||
|
void mpd_finishPlaylistFile(mpd_PlaylistFile * playlist)
|
||
|
{
|
||
|
if (playlist->path)
|
||
|
free(playlist->path);
|
||
|
}
|
||
|
|
||
|
mpd_PlaylistFile *mpd_newPlaylistFile()
|
||
|
{
|
||
|
mpd_PlaylistFile *playlist = malloc(sizeof(mpd_PlaylistFile));
|
||
|
|
||
|
mpd_initPlaylistFile(playlist);
|
||
|
|
||
|
return playlist;
|
||
|
}
|
||
|
|
||
|
void mpd_freePlaylistFile(mpd_PlaylistFile * playlist)
|
||
|
{
|
||
|
mpd_finishPlaylistFile(playlist);
|
||
|
free(playlist);
|
||
|
}
|
||
|
|
||
|
mpd_PlaylistFile *mpd_playlistFileDup(mpd_PlaylistFile * playlist)
|
||
|
{
|
||
|
mpd_PlaylistFile *ret = mpd_newPlaylistFile();
|
||
|
|
||
|
if (playlist->path)
|
||
|
ret->path = strdup(playlist->path);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void mpd_initInfoEntity(mpd_InfoEntity * entity)
|
||
|
{
|
||
|
entity->info.directory = NULL;
|
||
|
}
|
||
|
|
||
|
void mpd_finishInfoEntity(mpd_InfoEntity * entity)
|
||
|
{
|
||
|
if (entity->info.directory) {
|
||
|
if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
|
||
|
mpd_freeDirectory(entity->info.directory);
|
||
|
} else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG) {
|
||
|
mpd_freeSong(entity->info.song);
|
||
|
} else if (entity->type ==
|
||
|
MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
|
||
|
mpd_freePlaylistFile(entity->info.playlistFile);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mpd_InfoEntity *mpd_newInfoEntity()
|
||
|
{
|
||
|
mpd_InfoEntity *entity = malloc(sizeof(mpd_InfoEntity));
|
||
|
|
||
|
mpd_initInfoEntity(entity);
|
||
|
|
||
|
return entity;
|
||
|
}
|
||
|
|
||
|
void mpd_freeInfoEntity(mpd_InfoEntity * entity)
|
||
|
{
|
||
|
mpd_finishInfoEntity(entity);
|
||
|
free(entity);
|
||
|
}
|
||
|
|
||
|
void mpd_sendInfoCommand(mpd_Connection * connection, char *command)
|
||
|
{
|
||
|
mpd_executeCommand(connection, command);
|
||
|
}
|
||
|
|
||
|
mpd_InfoEntity *mpd_getNextInfoEntity(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_InfoEntity *entity = NULL;
|
||
|
|
||
|
if (connection->doneProcessing || (connection->listOks &&
|
||
|
connection->doneListOk)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!connection->returnElement)
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
|
||
|
if (connection->returnElement) {
|
||
|
if (strcmp(connection->returnElement->name, "file") == 0) {
|
||
|
entity = mpd_newInfoEntity();
|
||
|
entity->type = MPD_INFO_ENTITY_TYPE_SONG;
|
||
|
entity->info.song = mpd_newSong();
|
||
|
entity->info.song->file =
|
||
|
strdup(connection->returnElement->value);
|
||
|
} else
|
||
|
if (strcmp
|
||
|
(connection->returnElement->name,
|
||
|
"directory") == 0) {
|
||
|
entity = mpd_newInfoEntity();
|
||
|
entity->type = MPD_INFO_ENTITY_TYPE_DIRECTORY;
|
||
|
entity->info.directory = mpd_newDirectory();
|
||
|
entity->info.directory->path =
|
||
|
strdup(connection->returnElement->value);
|
||
|
} else
|
||
|
if (strcmp(connection->returnElement->name, "playlist")
|
||
|
== 0) {
|
||
|
entity = mpd_newInfoEntity();
|
||
|
entity->type = MPD_INFO_ENTITY_TYPE_PLAYLISTFILE;
|
||
|
entity->info.playlistFile = mpd_newPlaylistFile();
|
||
|
entity->info.playlistFile->path =
|
||
|
strdup(connection->returnElement->value);
|
||
|
} else {
|
||
|
connection->error = 1;
|
||
|
strcpy(connection->errorStr,
|
||
|
"problem parsing song info");
|
||
|
return NULL;
|
||
|
}
|
||
|
} else
|
||
|
return NULL;
|
||
|
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
while (connection->returnElement) {
|
||
|
mpd_ReturnElement *re = connection->returnElement;
|
||
|
|
||
|
if (strcmp(re->name, "file") == 0)
|
||
|
return entity;
|
||
|
else if (strcmp(re->name, "directory") == 0)
|
||
|
return entity;
|
||
|
else if (strcmp(re->name, "playlist") == 0)
|
||
|
return entity;
|
||
|
|
||
|
if (entity->type == MPD_INFO_ENTITY_TYPE_SONG
|
||
|
&& strlen(re->value)) {
|
||
|
if (!entity->info.song->artist
|
||
|
&& strcmp(re->name, "Artist") == 0) {
|
||
|
entity->info.song->artist =
|
||
|
strdup(re->value);
|
||
|
} else if (!entity->info.song->album
|
||
|
&& strcmp(re->name, "Album") == 0) {
|
||
|
entity->info.song->album =
|
||
|
strdup(re->value);
|
||
|
} else if (!entity->info.song->title
|
||
|
&& strcmp(re->name, "Title") == 0) {
|
||
|
entity->info.song->title =
|
||
|
strdup(re->value);
|
||
|
} else if (!entity->info.song->track
|
||
|
&& strcmp(re->name, "Track") == 0) {
|
||
|
entity->info.song->track =
|
||
|
strdup(re->value);
|
||
|
} else if (!entity->info.song->name
|
||
|
&& strcmp(re->name, "Name") == 0) {
|
||
|
entity->info.song->name =
|
||
|
strdup(re->value);
|
||
|
} else if (entity->info.song->time ==
|
||
|
MPD_SONG_NO_TIME
|
||
|
&& strcmp(re->name, "Time") == 0) {
|
||
|
entity->info.song->time = atoi(re->value);
|
||
|
} else if (entity->info.song->pos ==
|
||
|
MPD_SONG_NO_NUM
|
||
|
&& strcmp(re->name, "Pos") == 0) {
|
||
|
entity->info.song->pos = atoi(re->value);
|
||
|
} else if (entity->info.song->id == MPD_SONG_NO_ID
|
||
|
&& strcmp(re->name, "Id") == 0) {
|
||
|
entity->info.song->id = atoi(re->value);
|
||
|
}
|
||
|
} else if (entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
|
||
|
} else if (entity->type ==
|
||
|
MPD_INFO_ENTITY_TYPE_PLAYLISTFILE) {
|
||
|
}
|
||
|
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
}
|
||
|
|
||
|
return entity;
|
||
|
}
|
||
|
|
||
|
char *mpd_getNextReturnElementNamed(mpd_Connection * connection,
|
||
|
const char *name)
|
||
|
{
|
||
|
if (connection->doneProcessing || (connection->listOks &&
|
||
|
connection->doneListOk)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
while (connection->returnElement) {
|
||
|
mpd_ReturnElement *re = connection->returnElement;
|
||
|
|
||
|
if (strcmp(re->name, name) == 0)
|
||
|
return strdup(re->value);
|
||
|
mpd_getNextReturnElement(connection);
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
char *mpd_getNextArtist(mpd_Connection * connection)
|
||
|
{
|
||
|
return mpd_getNextReturnElementNamed(connection, "Artist");
|
||
|
}
|
||
|
|
||
|
char *mpd_getNextAlbum(mpd_Connection * connection)
|
||
|
{
|
||
|
return mpd_getNextReturnElementNamed(connection, "Album");
|
||
|
}
|
||
|
|
||
|
void mpd_sendPlaylistInfoCommand(mpd_Connection * connection, int songPos)
|
||
|
{
|
||
|
char *string = malloc(strlen("playlistinfo") + 25);
|
||
|
sprintf(string, "playlistinfo \"%i\"\n", songPos);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendPlaylistIdCommand(mpd_Connection * connection, int id)
|
||
|
{
|
||
|
char *string = malloc(strlen("playlistid") + 25);
|
||
|
sprintf(string, "playlistid \"%i\"\n", id);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
mpd_sendPlChangesCommand(mpd_Connection * connection, long long playlist)
|
||
|
{
|
||
|
char *string = malloc(strlen("plchanges") + 25);
|
||
|
sprintf(string, "plchanges \"%lld\"\n", playlist);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendListallCommand(mpd_Connection * connection, const char *dir)
|
||
|
{
|
||
|
char *sDir = mpd_sanitizeArg(dir);
|
||
|
char *string = malloc(strlen("listall") + strlen(sDir) + 5);
|
||
|
sprintf(string, "listall \"%s\"\n", sDir);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sDir);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
mpd_sendListallInfoCommand(mpd_Connection * connection, const char *dir)
|
||
|
{
|
||
|
char *sDir = mpd_sanitizeArg(dir);
|
||
|
char *string = malloc(strlen("listallinfo") + strlen(sDir) + 5);
|
||
|
sprintf(string, "listallinfo \"%s\"\n", sDir);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sDir);
|
||
|
}
|
||
|
|
||
|
void mpd_sendLsInfoCommand(mpd_Connection * connection, const char *dir)
|
||
|
{
|
||
|
char *sDir = mpd_sanitizeArg(dir);
|
||
|
char *string = malloc(strlen("lsinfo") + strlen(sDir) + 5);
|
||
|
sprintf(string, "lsinfo \"%s\"\n", sDir);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sDir);
|
||
|
}
|
||
|
|
||
|
void mpd_sendCurrentSongCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_executeCommand(connection, "currentsong\n");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
mpd_sendSearchCommand(mpd_Connection * connection, int table,
|
||
|
const char *str)
|
||
|
{
|
||
|
char st[10];
|
||
|
char *string;
|
||
|
char *sanitStr = mpd_sanitizeArg(str);
|
||
|
if (table == MPD_TABLE_ARTIST)
|
||
|
strcpy(st, "artist");
|
||
|
else if (table == MPD_TABLE_ALBUM)
|
||
|
strcpy(st, "album");
|
||
|
else if (table == MPD_TABLE_TITLE)
|
||
|
strcpy(st, "title");
|
||
|
else if (table == MPD_TABLE_FILENAME)
|
||
|
strcpy(st, "filename");
|
||
|
else {
|
||
|
connection->error = 1;
|
||
|
strcpy(connection->errorStr, "unknown table for search");
|
||
|
return;
|
||
|
}
|
||
|
string =
|
||
|
malloc(strlen("search") + strlen(sanitStr) + strlen(st) + 6);
|
||
|
sprintf(string, "search %s \"%s\"\n", st, sanitStr);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sanitStr);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
mpd_sendFindCommand(mpd_Connection * connection, int table,
|
||
|
const char *str)
|
||
|
{
|
||
|
char st[10];
|
||
|
char *string;
|
||
|
char *sanitStr = mpd_sanitizeArg(str);
|
||
|
if (table == MPD_TABLE_ARTIST)
|
||
|
strcpy(st, "artist");
|
||
|
else if (table == MPD_TABLE_ALBUM)
|
||
|
strcpy(st, "album");
|
||
|
else if (table == MPD_TABLE_TITLE)
|
||
|
strcpy(st, "title");
|
||
|
else {
|
||
|
connection->error = 1;
|
||
|
strcpy(connection->errorStr, "unknown table for find");
|
||
|
return;
|
||
|
}
|
||
|
string =
|
||
|
malloc(strlen("find") + strlen(sanitStr) + strlen(st) + 6);
|
||
|
sprintf(string, "find %s \"%s\"\n", st, sanitStr);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sanitStr);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
mpd_sendListCommand(mpd_Connection * connection, int table,
|
||
|
const char *arg1)
|
||
|
{
|
||
|
char st[10];
|
||
|
char *string;
|
||
|
if (table == MPD_TABLE_ARTIST)
|
||
|
strcpy(st, "artist");
|
||
|
else if (table == MPD_TABLE_ALBUM)
|
||
|
strcpy(st, "album");
|
||
|
else {
|
||
|
connection->error = 1;
|
||
|
strcpy(connection->errorStr, "unknown table for list");
|
||
|
return;
|
||
|
}
|
||
|
if (arg1) {
|
||
|
char *sanitArg1 = mpd_sanitizeArg(arg1);
|
||
|
string =
|
||
|
malloc(strlen("list") + strlen(sanitArg1) +
|
||
|
strlen(st) + 6);
|
||
|
sprintf(string, "list %s \"%s\"\n", st, sanitArg1);
|
||
|
free(sanitArg1);
|
||
|
} else {
|
||
|
string = malloc(strlen("list") + strlen(st) + 3);
|
||
|
sprintf(string, "list %s\n", st);
|
||
|
}
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendAddCommand(mpd_Connection * connection, const char *file)
|
||
|
{
|
||
|
char *sFile = mpd_sanitizeArg(file);
|
||
|
char *string = malloc(strlen("add") + strlen(sFile) + 5);
|
||
|
sprintf(string, "add \"%s\"\n", sFile);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sFile);
|
||
|
}
|
||
|
|
||
|
void mpd_sendDeleteCommand(mpd_Connection * connection, int songPos)
|
||
|
{
|
||
|
char *string = malloc(strlen("delete") + 25);
|
||
|
sprintf(string, "delete \"%i\"\n", songPos);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendDeleteIdCommand(mpd_Connection * connection, int id)
|
||
|
{
|
||
|
char *string = malloc(strlen("deleteid") + 25);
|
||
|
sprintf(string, "deleteid \"%i\"\n", id);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendSaveCommand(mpd_Connection * connection, const char *name)
|
||
|
{
|
||
|
char *sName = mpd_sanitizeArg(name);
|
||
|
char *string = malloc(strlen("save") + strlen(sName) + 5);
|
||
|
sprintf(string, "save \"%s\"\n", sName);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sName);
|
||
|
}
|
||
|
|
||
|
void mpd_sendLoadCommand(mpd_Connection * connection, const char *name)
|
||
|
{
|
||
|
char *sName = mpd_sanitizeArg(name);
|
||
|
char *string = malloc(strlen("load") + strlen(sName) + 5);
|
||
|
sprintf(string, "load \"%s\"\n", sName);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sName);
|
||
|
}
|
||
|
|
||
|
void mpd_sendRmCommand(mpd_Connection * connection, const char *name)
|
||
|
{
|
||
|
char *sName = mpd_sanitizeArg(name);
|
||
|
char *string = malloc(strlen("rm") + strlen(sName) + 5);
|
||
|
sprintf(string, "rm \"%s\"\n", sName);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sName);
|
||
|
}
|
||
|
|
||
|
void mpd_sendShuffleCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_executeCommand(connection, "shuffle\n");
|
||
|
}
|
||
|
|
||
|
void mpd_sendClearCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_executeCommand(connection, "clear\n");
|
||
|
}
|
||
|
|
||
|
void mpd_sendPlayCommand(mpd_Connection * connection, int songPos)
|
||
|
{
|
||
|
char *string = malloc(strlen("play") + 25);
|
||
|
sprintf(string, "play \"%i\"\n", songPos);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendPlayIdCommand(mpd_Connection * connection, int id)
|
||
|
{
|
||
|
char *string = malloc(strlen("playid") + 25);
|
||
|
sprintf(string, "playid \"%i\"\n", id);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendStopCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_executeCommand(connection, "stop\n");
|
||
|
}
|
||
|
|
||
|
void mpd_sendPauseCommand(mpd_Connection * connection, int pauseMode)
|
||
|
{
|
||
|
char *string = malloc(strlen("pause") + 25);
|
||
|
sprintf(string, "pause \"%i\"\n", pauseMode);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendNextCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_executeCommand(connection, "next\n");
|
||
|
}
|
||
|
|
||
|
void mpd_sendMoveCommand(mpd_Connection * connection, int from, int to)
|
||
|
{
|
||
|
char *string = malloc(strlen("move") + 25);
|
||
|
sprintf(string, "move \"%i\" \"%i\"\n", from, to);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendMoveIdCommand(mpd_Connection * connection, int id, int to)
|
||
|
{
|
||
|
char *string = malloc(strlen("moveid") + 25);
|
||
|
sprintf(string, "moveid \"%i\" \"%i\"\n", id, to);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendSwapCommand(mpd_Connection * connection, int song1, int song2)
|
||
|
{
|
||
|
char *string = malloc(strlen("swap") + 25);
|
||
|
sprintf(string, "swap \"%i\" \"%i\"\n", song1, song2);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendSwapIdCommand(mpd_Connection * connection, int id1, int id2)
|
||
|
{
|
||
|
char *string = malloc(strlen("swapid") + 25);
|
||
|
sprintf(string, "swapid \"%i\" \"%i\"\n", id1, id2);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendSeekCommand(mpd_Connection * connection, int song, int time)
|
||
|
{
|
||
|
char *string = malloc(strlen("seek") + 25);
|
||
|
sprintf(string, "seek \"%i\" \"%i\"\n", song, time);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendSeekIdCommand(mpd_Connection * connection, int id, int time)
|
||
|
{
|
||
|
char *string = malloc(strlen("seekid") + 25);
|
||
|
sprintf(string, "seekid \"%i\" \"%i\"\n", id, time);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendUpdateCommand(mpd_Connection * connection, char *path)
|
||
|
{
|
||
|
char *sPath = mpd_sanitizeArg(path);
|
||
|
char *string = malloc(strlen("update") + strlen(sPath) + 5);
|
||
|
sprintf(string, "update \"%s\"\n", sPath);
|
||
|
mpd_sendInfoCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sPath);
|
||
|
}
|
||
|
|
||
|
int mpd_getUpdateId(mpd_Connection * connection)
|
||
|
{
|
||
|
char *jobid;
|
||
|
int ret = 0;
|
||
|
|
||
|
jobid = mpd_getNextReturnElementNamed(connection, "updating_db");
|
||
|
if (jobid) {
|
||
|
ret = atoi(jobid);
|
||
|
free(jobid);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void mpd_sendPrevCommand(mpd_Connection * connection)
|
||
|
{
|
||
|
mpd_executeCommand(connection, "previous\n");
|
||
|
}
|
||
|
|
||
|
void mpd_sendRepeatCommand(mpd_Connection * connection, int repeatMode)
|
||
|
{
|
||
|
char *string = malloc(strlen("repeat") + 25);
|
||
|
sprintf(string, "repeat \"%i\"\n", repeatMode);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendRandomCommand(mpd_Connection * connection, int randomMode)
|
||
|
{
|
||
|
char *string = malloc(strlen("random") + 25);
|
||
|
sprintf(string, "random \"%i\"\n", randomMode);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendSetvolCommand(mpd_Connection * connection, int volumeChange)
|
||
|
{
|
||
|
char *string = malloc(strlen("setvol") + 25);
|
||
|
sprintf(string, "setvol \"%i\"\n", volumeChange);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendVolumeCommand(mpd_Connection * connection, int volumeChange)
|
||
|
{
|
||
|
char *string = malloc(strlen("volume") + 25);
|
||
|
sprintf(string, "volume \"%i\"\n", volumeChange);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendCrossfadeCommand(mpd_Connection * connection, int seconds)
|
||
|
{
|
||
|
char *string = malloc(strlen("crossfade") + 25);
|
||
|
sprintf(string, "crossfade \"%i\"\n", seconds);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
}
|
||
|
|
||
|
void mpd_sendPasswordCommand(mpd_Connection * connection, const char *pass)
|
||
|
{
|
||
|
char *sPass = mpd_sanitizeArg(pass);
|
||
|
char *string = malloc(strlen("password") + strlen(sPass) + 5);
|
||
|
sprintf(string, "password \"%s\"\n", sPass);
|
||
|
mpd_executeCommand(connection, string);
|
||
|
free(string);
|
||
|
free(sPass);
|
||
|
}
|
||
|
|
||
|
void mpd_sendCommandListBegin(mpd_Connection * connection)
|
||
|
{
|
||
|
if (connection->commandList) {
|
||
|
strcpy(connection->errorStr,
|
||
|
"already in command list mode");
|
||
|
connection->error = 1;
|
||
|
return;
|
||
|
}
|
||
|
connection->commandList = COMMAND_LIST;
|
||
|
mpd_executeCommand(connection, "command_list_begin\n");
|
||
|
}
|
||
|
|
||
|
void mpd_sendCommandListOkBegin(mpd_Connection * connection)
|
||
|
{
|
||
|
if (connection->commandList) {
|
||
|
strcpy(connection->errorStr,
|
||
|
"already in command list mode");
|
||
|
connection->error = 1;
|
||
|
return;
|
||
|
}
|
||
|
connection->commandList = COMMAND_LIST_OK;
|
||
|
mpd_executeCommand(connection, "command_list_ok_begin\n");
|
||
|
connection->listOks = 0;
|
||
|
}
|
||
|
|
||
|
void mpd_sendCommandListEnd(mpd_Connection * connection)
|
||
|
{
|
||
|
if (!connection->commandList) {
|
||
|
strcpy(connection->errorStr, "not in command list mode");
|
||
|
connection->error = 1;
|
||
|
return;
|
||
|
}
|
||
|
connection->commandList = 0;
|
||
|
mpd_executeCommand(connection, "command_list_end\n");
|
||
|
}
|