aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/audio.c17
-rw-r--r--src/audio.h4
-rw-r--r--src/audioOutputs/audioOutput_jack.c17
-rw-r--r--src/audioOutputs/audioOutput_shout.c4
-rw-r--r--src/client.c784
-rw-r--r--src/client.h (renamed from src/interface.h)13
-rw-r--r--src/command.c377
-rw-r--r--src/dbUtils.c127
-rw-r--r--src/dbUtils.h18
-rw-r--r--src/directory.c45
-rw-r--r--src/directory.h8
-rw-r--r--src/dlist.h484
-rw-r--r--src/inputPlugins/mod_plugin.c17
-rw-r--r--src/inputPlugins/wavpack_plugin.c12
-rw-r--r--src/interface.c794
-rw-r--r--src/listen.c4
-rw-r--r--src/main.c10
-rw-r--r--src/myfprintf.c4
-rw-r--r--src/pcm_utils.c19
-rw-r--r--src/playlist.c300
-rw-r--r--src/playlist.h64
-rw-r--r--src/stats.c4
-rw-r--r--src/storedPlaylist.c167
-rw-r--r--src/storedPlaylist.h19
-rw-r--r--src/volume.c25
-rw-r--r--src/volume.h2
27 files changed, 1981 insertions, 1363 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0592d8e72..15efaf78e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -49,8 +49,9 @@ mpd_headers = \
inputStream_file.h \
inputStream_http.h \
inputStream_http_auth.h \
- interface.h \
+ client.h \
list.h \
+ dlist.h \
listen.h \
log.h \
ls.h \
@@ -112,7 +113,7 @@ mpd_SOURCES = \
inputStream.c \
inputStream_file.c \
inputStream_http.c \
- interface.c \
+ client.c \
ioops.c \
list.c \
listen.c \
diff --git a/src/audio.c b/src/audio.c
index 9a65df858..d4447bc7e 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -19,9 +19,7 @@
#include "audio.h"
#include "audioOutput.h"
#include "log.h"
-#include "command.h"
#include "path.h"
-#include "ack.h"
#include "myfprintf.h"
#include "os_compat.h"
@@ -428,13 +426,10 @@ void sendMetadataToAudioDevice(const struct mpd_tag *tag)
}
}
-int enableAudioDevice(int fd, unsigned int device)
+int enableAudioDevice(unsigned int device)
{
- if (device >= audioOutputArraySize) {
- commandError(fd, ACK_ERROR_ARG, "audio output device id %i "
- "doesn't exist\n", device);
+ if (device >= audioOutputArraySize)
return -1;
- }
if (!(audioDeviceStates[device] & 0x01))
audioDeviceStates[device] = DEVICE_ENABLE;
@@ -442,13 +437,11 @@ int enableAudioDevice(int fd, unsigned int device)
return 0;
}
-int disableAudioDevice(int fd, unsigned int device)
+int disableAudioDevice(unsigned int device)
{
- if (device >= audioOutputArraySize) {
- commandError(fd, ACK_ERROR_ARG, "audio output device id %i "
- "doesn't exist\n", device);
+ if (device >= audioOutputArraySize)
return -1;
- }
+
if (audioDeviceStates[device] & 0x01)
audioDeviceStates[device] = DEVICE_DISABLE;
diff --git a/src/audio.h b/src/audio.h
index 92cb9cf11..7ff0d5d4a 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -59,9 +59,9 @@ void sendMetadataToAudioDevice(const struct mpd_tag *tag);
/* these functions are called in the main parent process while the child
process is busy playing to the audio */
-int enableAudioDevice(int fd, unsigned int device);
+int enableAudioDevice(unsigned int device);
-int disableAudioDevice(int fd, unsigned int device);
+int disableAudioDevice(unsigned int device);
void printAudioDevices(int fd);
diff --git a/src/audioOutputs/audioOutput_jack.c b/src/audioOutputs/audioOutput_jack.c
index 8818bb739..77ee077a4 100644
--- a/src/audioOutputs/audioOutput_jack.c
+++ b/src/audioOutputs/audioOutput_jack.c
@@ -31,8 +31,8 @@ static const size_t sample_size = sizeof(jack_default_audio_sample_t);
typedef struct _JackData {
/* configuration */
- char *name;
- char *output_ports[2];
+ const char *name;
+ const char *output_ports[2];
int ringbuf_sz;
/* locks */
@@ -52,6 +52,7 @@ typedef struct _JackData {
static JackData *newJackData(void)
{
JackData *ret;
+
ret = xcalloc(sizeof(JackData), 1);
ret->name = "mpd";
@@ -97,12 +98,12 @@ static void freeJackData(AudioOutput *audioOutput)
freeJackClient(jd);
if (strcmp(jd->name, "mpd") != 0)
- free(jd->name);
+ free(deconst_ptr(jd->name));
for ( i = ARRAY_SIZE(jd->output_ports); --i >= 0; ) {
if (!jd->output_ports[i])
continue;
- free(jd->output_ports[i]);
+ free(deconst_ptr(jd->output_ports[i]));
}
free(jd);
@@ -267,7 +268,7 @@ static int jack_testDefault(void)
static int connect_jack(AudioOutput *audioOutput)
{
JackData *jd = audioOutput->data;
- char **jports;
+ const char **jports;
char *port_name;
if ( (jd->client = jack_client_new(jd->name)) == NULL ) {
@@ -304,9 +305,9 @@ static int connect_jack(AudioOutput *audioOutput)
/* hay que buscar que hay */
if ( !jd->output_ports[1]
- && (jports = (char **)jack_get_ports(jd->client, NULL, NULL,
- JackPortIsPhysical|
- JackPortIsInput)) ) {
+ && (jports = jack_get_ports(jd->client, NULL, NULL,
+ JackPortIsPhysical|
+ JackPortIsInput)) ) {
jd->output_ports[0] = jports[0];
jd->output_ports[1] = jports[1] ? jports[1] : jports[0];
DEBUG("output_ports: %s %s\n",
diff --git a/src/audioOutputs/audioOutput_shout.c b/src/audioOutputs/audioOutput_shout.c
index b65a8253f..2ee942809 100644
--- a/src/audioOutputs/audioOutput_shout.c
+++ b/src/audioOutputs/audioOutput_shout.c
@@ -636,8 +636,8 @@ static int myShout_play(AudioOutput * audioOutput,
for (i = 0; i < samples; i++) {
for (j = 0; j < sd->audioFormat->channels; j++) {
- vorbbuf[j][i] =
- (*((mpd_sint16 *)deconst_ptr(playChunk))) / 32768.0;
+ vorbbuf[j][i] = (*((const mpd_sint16 *) playChunk))
+ / 32768.0;
playChunk += bytes;
}
}
diff --git a/src/client.c b/src/client.c
new file mode 100644
index 000000000..c3ed7fec5
--- /dev/null
+++ b/src/client.c
@@ -0,0 +1,784 @@
+/* the Music Player Daemon (MPD)
+ * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "client.h"
+#include "command.h"
+#include "conf.h"
+#include "log.h"
+#include "listen.h"
+#include "permission.h"
+#include "sllist.h"
+#include "utils.h"
+#include "ioops.h"
+#include "myfprintf.h"
+#include "os_compat.h"
+#include "main_notify.h"
+#include "dlist.h"
+
+#include "../config.h"
+
+#define GREETING "OK MPD " PROTOCOL_VERSION "\n"
+
+#define CLIENT_MAX_BUFFER_LENGTH (40960)
+#define CLIENT_LIST_MODE_BEGIN "command_list_begin"
+#define CLIENT_LIST_OK_MODE_BEGIN "command_list_ok_begin"
+#define CLIENT_LIST_MODE_END "command_list_end"
+#define CLIENT_DEFAULT_OUT_BUFFER_SIZE (4096)
+#define CLIENT_TIMEOUT_DEFAULT (60)
+#define CLIENT_MAX_CONNECTIONS_DEFAULT (10)
+#define CLIENT_MAX_COMMAND_LIST_DEFAULT (2048*1024)
+#define CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024)
+
+/* set this to zero to indicate we have no possible clients */
+static unsigned int client_max_connections; /*CLIENT_MAX_CONNECTIONS_DEFAULT; */
+static int client_timeout = CLIENT_TIMEOUT_DEFAULT;
+static size_t client_max_command_list_size =
+ CLIENT_MAX_COMMAND_LIST_DEFAULT;
+static size_t client_max_output_buffer_size =
+ CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT;
+
+/* maybe make conf option for this, or... 32 might be good enough */
+static long int client_list_cache_size = 32;
+
+/* shared globally between all clients: */
+static struct strnode *list_cache;
+static struct strnode *list_cache_head;
+static struct strnode *list_cache_tail;
+
+struct client {
+ struct list_head siblings;
+
+ char buffer[CLIENT_MAX_BUFFER_LENGTH];
+ size_t bufferLength;
+ size_t bufferPos;
+ int fd; /* file descriptor; -1 if expired */
+ int permission;
+ time_t lastTime;
+ struct strnode *cmd_list; /* for when in list mode */
+ struct strnode *cmd_list_tail; /* for when in list mode */
+ int cmd_list_OK; /* print OK after each command execution */
+ size_t cmd_list_size; /* mem cmd_list consumes */
+ int cmd_list_dup; /* has the cmd_list been copied to private space? */
+ struct sllnode *deferred_send; /* for output if client is slow */
+ size_t deferred_bytes; /* mem deferred_send consumes */
+ unsigned int num; /* client number */
+
+ char *send_buf;
+ size_t send_buf_used; /* bytes used this instance */
+ size_t send_buf_size; /* bytes usable this instance */
+ size_t send_buf_alloc; /* bytes actually allocated */
+};
+
+static LIST_HEAD(clients);
+static unsigned num_clients;
+
+static void client_write_deferred(struct client *cl);
+
+static void client_write_output(struct client *cl);
+
+#ifdef SO_SNDBUF
+static size_t get_default_snd_buf_size(struct client *cl)
+{
+ int new_size;
+ socklen_t sockOptLen = sizeof(int);
+
+ if (getsockopt(cl->fd, SOL_SOCKET, SO_SNDBUF,
+ (char *)&new_size, &sockOptLen) < 0) {
+ DEBUG("problem getting sockets send buffer size\n");
+ return CLIENT_DEFAULT_OUT_BUFFER_SIZE;
+ }
+ if (new_size > 0)
+ return (size_t)new_size;
+ DEBUG("sockets send buffer size is not positive\n");
+ return CLIENT_DEFAULT_OUT_BUFFER_SIZE;
+}
+#else /* !SO_SNDBUF */
+static size_t get_default_snd_buf_size(struct client *cl)
+{
+ return CLIENT_DEFAULT_OUT_BUFFER_SIZE;
+}
+#endif /* !SO_SNDBUF */
+
+static void set_send_buf_size(struct client *cl)
+{
+ size_t new_size = get_default_snd_buf_size(cl);
+ if (cl->send_buf_size != new_size) {
+ cl->send_buf_size = new_size;
+ /* don't resize to get smaller, only bigger */
+ if (cl->send_buf_alloc < new_size) {
+ if (cl->send_buf)
+ free(cl->send_buf);
+ cl->send_buf = xmalloc(new_size);
+ cl->send_buf_alloc = new_size;
+ }
+ }
+}
+
+static inline int client_is_expired(const struct client *cl)
+{
+ return cl->fd < 0;
+}
+
+static int global_expired;
+
+static inline void client_set_expired(struct client *cl)
+{
+ if (cl->fd >= 0) {
+ xclose(cl->fd);
+ cl->fd = -1;
+ }
+
+ global_expired = 1;
+}
+
+static void client_init(struct client *cl, int fd)
+{
+ static unsigned int next_client_num;
+
+ assert(fd >= 0);
+
+ cl->cmd_list_size = 0;
+ cl->cmd_list_dup = 0;
+ cl->cmd_list_OK = -1;
+ cl->bufferLength = 0;
+ cl->bufferPos = 0;
+ cl->fd = fd;
+ set_nonblocking(fd);
+ cl->lastTime = time(NULL);
+ cl->cmd_list = NULL;
+ cl->cmd_list_tail = NULL;
+ cl->deferred_send = NULL;
+ cl->deferred_bytes = 0;
+ cl->num = next_client_num++;
+ cl->send_buf_used = 0;
+
+ cl->permission = getDefaultPermissions();
+ set_send_buf_size(cl);
+
+ xwrite(fd, GREETING, strlen(GREETING));
+}
+
+static void free_cmd_list(struct strnode *list)
+{
+ struct strnode *tmp = list;
+
+ while (tmp) {
+ struct strnode *next = tmp->next;
+ if (tmp >= list_cache_head && tmp <= list_cache_tail) {
+ /* inside list_cache[] array */
+ tmp->data = NULL;
+ tmp->next = NULL;
+ } else
+ free(tmp);
+ tmp = next;
+ }
+}
+
+static void cmd_list_clone(struct client *cl)
+{
+ struct strnode *new = dup_strlist(cl->cmd_list);
+ free_cmd_list(cl->cmd_list);
+ cl->cmd_list = new;
+ cl->cmd_list_dup = 1;
+
+ /* new tail */
+ while (new && new->next)
+ new = new->next;
+ cl->cmd_list_tail = new;
+}
+
+static void new_cmd_list_ptr(struct client *cl, char *s, const int size)
+{
+ int i;
+ struct strnode *new;
+
+ if (!cl->cmd_list_dup) {
+ for (i = client_list_cache_size - 1; i >= 0; --i) {
+ if (list_cache[i].data)
+ continue;
+ new = &(list_cache[i]);
+ new->data = s;
+ /* implied in free_cmd_list() and init: */
+ /* last->next->next = NULL; */
+ goto out;
+ }
+ }
+
+ /* allocate from the heap */
+ new = cl->cmd_list_dup ? new_strnode_dup(s, size)
+ : new_strnode(s);
+out:
+ if (cl->cmd_list) {
+ cl->cmd_list_tail->next = new;
+ cl->cmd_list_tail = new;
+ } else
+ cl->cmd_list = cl->cmd_list_tail = new;
+}
+
+static void client_close(struct client *cl)
+{
+ struct sllnode *buf;
+
+ assert(num_clients > 0);
+ assert(!list_empty(&clients));
+ list_del(&cl->siblings);
+ --num_clients;
+
+ client_set_expired(cl);
+
+ if (cl->cmd_list) {
+ free_cmd_list(cl->cmd_list);
+ cl->cmd_list = NULL;
+ }
+
+ if ((buf = cl->deferred_send)) {
+ do {
+ struct sllnode *prev = buf;
+ buf = buf->next;
+ free(prev);
+ } while (buf);
+ cl->deferred_send = NULL;
+ }
+
+ if (cl->send_buf)
+ free(cl->send_buf);
+
+ SECURE("client %i: closed\n", cl->num);
+ free(cl);
+}
+
+static const char *
+sockaddr_to_tmp_string(const struct sockaddr *addr)
+{
+ const char *hostname;
+
+ switch (addr->sa_family) {
+#ifdef HAVE_TCP
+ case AF_INET:
+ hostname = (const char *)inet_ntoa(((const struct sockaddr_in *)
+ addr)->sin_addr);
+ if (!hostname)
+ hostname = "error getting ipv4 address";
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ static char host[INET6_ADDRSTRLEN + 1];
+ memset(host, 0, INET6_ADDRSTRLEN + 1);
+ if (inet_ntop(AF_INET6, (const void *)
+ &(((const struct sockaddr_in6 *)addr)->
+ sin6_addr), host,
+ INET6_ADDRSTRLEN)) {
+ hostname = (const char *)host;
+ } else {
+ hostname = "error getting ipv6 address";
+ }
+ }
+ break;
+#endif
+#endif /* HAVE_TCP */
+#ifdef HAVE_UN
+ case AF_UNIX:
+ hostname = "local connection";
+ break;
+#endif /* HAVE_UN */
+ default:
+ hostname = "unknown";
+ }
+
+ return hostname;
+}
+
+void client_new(int fd, const struct sockaddr *addr)
+{
+ struct client *cl;
+
+ if (num_clients >= client_max_connections) {
+ ERROR("Max Connections Reached!\n");
+ xclose(fd);
+ return;
+ }
+
+ cl = xcalloc(1, sizeof(struct client));
+ list_add(&cl->siblings, &clients);
+ ++num_clients;
+ client_init(cl, fd);
+ SECURE("client %i: opened from %s\n", cl->num,
+ sockaddr_to_tmp_string(addr));
+}
+
+static int client_process_line(struct client *cl)
+{
+ int ret = 1;
+ char *line = cl->buffer + cl->bufferPos;
+
+ if (cl->cmd_list_OK >= 0) {
+ if (strcmp(line, CLIENT_LIST_MODE_END) == 0) {
+ DEBUG("client %i: process command "
+ "list\n", cl->num);
+
+ global_expired = 0;
+ ret = processListOfCommands(cl->fd,
+ &(cl->permission),
+ &global_expired,
+ cl->cmd_list_OK,
+ cl->cmd_list);
+ DEBUG("client %i: process command "
+ "list returned %i\n", cl->num, ret);
+
+ if (ret == COMMAND_RETURN_CLOSE ||
+ client_is_expired(cl))
+ return COMMAND_RETURN_CLOSE;
+
+ if (ret == 0)
+ commandSuccess(cl->fd);
+
+ client_write_output(cl);
+ free_cmd_list(cl->cmd_list);
+ cl->cmd_list = NULL;
+ cl->cmd_list_OK = -1;
+ } else {
+ size_t len = strlen(line) + 1;
+ cl->cmd_list_size += len;
+ if (cl->cmd_list_size >
+ client_max_command_list_size) {
+ ERROR("client %i: command "
+ "list size (%lu) is "
+ "larger than the max "
+ "(%lu)\n",
+ cl->num,
+ (unsigned long)cl->cmd_list_size,
+ (unsigned long)
+ client_max_command_list_size);
+ return COMMAND_RETURN_CLOSE;
+ } else
+ new_cmd_list_ptr(cl, line, len);
+ }
+ } else {
+ if (strcmp(line, CLIENT_LIST_MODE_BEGIN) == 0) {
+ cl->cmd_list_OK = 0;
+ ret = 1;
+ } else if (strcmp(line, CLIENT_LIST_OK_MODE_BEGIN) == 0) {
+ cl->cmd_list_OK = 1;
+ ret = 1;
+ } else {
+ DEBUG("client %i: process command \"%s\"\n",
+ cl->num, line);
+ ret = processCommand(cl->fd,
+ &(cl->permission), line);
+ DEBUG("client %i: command returned %i\n",
+ cl->num, ret);
+
+ if (ret == COMMAND_RETURN_CLOSE ||
+ client_is_expired(cl))
+ return COMMAND_RETURN_CLOSE;
+
+ if (ret == 0)
+ commandSuccess(cl->fd);
+
+ client_write_output(cl);
+ }
+ }
+
+ return ret;
+}
+
+static int client_input_received(struct client *cl, int bytesRead)
+{
+ int ret;
+ char *buf_tail = &(cl->buffer[cl->bufferLength - 1]);
+
+ while (bytesRead > 0) {
+ cl->bufferLength++;
+ bytesRead--;
+ buf_tail++;
+ if (*buf_tail == '\n') {
+ *buf_tail = '\0';
+ if (cl->bufferLength > cl->bufferPos) {
+ if (*(buf_tail - 1) == '\r')
+ *(buf_tail - 1) = '\0';
+ }
+ ret = client_process_line(cl);
+ if (ret == COMMAND_RETURN_KILL ||
+ ret == COMMAND_RETURN_CLOSE)
+ return ret;
+ assert(!client_is_expired(cl));
+ cl->bufferPos = cl->bufferLength;
+ }
+ if (cl->bufferLength == CLIENT_MAX_BUFFER_LENGTH) {
+ if (cl->bufferPos == 0) {
+ ERROR("client %i: buffer overflow\n",
+ cl->num);
+ return COMMAND_RETURN_CLOSE;
+ }
+ if (cl->cmd_list_OK >= 0 &&
+ cl->cmd_list &&
+ !cl->cmd_list_dup)
+ cmd_list_clone(cl);
+ assert(cl->bufferLength >= cl->bufferPos
+ && "bufferLength >= bufferPos");
+ cl->bufferLength -= cl->bufferPos;
+ memmove(cl->buffer,
+ cl->buffer + cl->bufferPos,
+ cl->bufferLength);
+ cl->bufferPos = 0;
+ }
+ }
+
+ return 0;
+}
+
+static int client_read(struct client *cl)
+{
+ int bytesRead;
+
+ bytesRead = read(cl->fd,
+ cl->buffer + cl->bufferLength,
+ CLIENT_MAX_BUFFER_LENGTH - cl->bufferLength);
+
+ if (bytesRead > 0)
+ return client_input_received(cl, bytesRead);
+ else if (bytesRead < 0 && errno == EINTR)
+ /* try again later, after select() */
+ return 0;
+ else
+ /* peer disconnected or I/O error */
+ return COMMAND_RETURN_CLOSE;
+}
+
+static void client_manager_register_read_fd(fd_set * fds, int *fdmax)
+{
+ struct client *cl;
+
+ FD_ZERO(fds);
+ addListenSocketsToFdSet(fds, fdmax);
+
+ list_for_each_entry(cl, &clients, siblings) {
+ if (!client_is_expired(cl) && !cl->deferred_send) {
+ FD_SET(cl->fd, fds);
+ if (*fdmax < cl->fd)
+ *fdmax = cl->fd;
+ }
+ }
+}
+
+static void client_manager_register_write_fd(fd_set * fds, int *fdmax)
+{
+ struct client *cl;
+
+ FD_ZERO(fds);
+
+ list_for_each_entry(cl, &clients, siblings) {
+ if (cl->fd >= 0 && !client_is_expired(cl)
+ && cl->deferred_send) {
+ FD_SET(cl->fd, fds);
+ if (*fdmax < cl->fd)
+ *fdmax = cl->fd;
+ }
+ }
+}
+
+int client_manager_io(void)
+{
+ fd_set rfds;
+ fd_set wfds;
+ fd_set efds;
+ struct client *cl, *n;
+ int ret;
+ int fdmax = 0;
+
+ FD_ZERO( &efds );
+ client_manager_register_read_fd(&rfds, &fdmax);
+ client_manager_register_write_fd(&wfds, &fdmax);
+
+ registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds);
+
+ ret = select(fdmax + 1, &rfds, &wfds, &efds, NULL);
+
+ if (ret < 0) {
+ if (errno == EINTR)
+ return 0;
+
+ FATAL("select() failed: %s\n", strerror(errno));
+ }
+
+ registered_IO_consume_fds(&ret, &rfds, &wfds, &efds);
+
+ getConnections(&rfds);
+
+ list_for_each_entry_safe(cl, n, &clients, siblings) {
+ if (FD_ISSET(cl->fd, &rfds)) {
+ ret = client_read(cl);
+ if (ret == COMMAND_RETURN_KILL)
+ return COMMAND_RETURN_KILL;
+ if (ret == COMMAND_RETURN_CLOSE) {
+ client_close(cl);
+ continue;
+ }
+
+ assert(!client_is_expired(cl));
+
+ cl->lastTime = time(NULL);
+ }
+ if (!client_is_expired(cl) &&
+ FD_ISSET(cl->fd, &wfds)) {
+ client_write_deferred(cl);
+ cl->lastTime = time(NULL);
+ }
+ }
+
+ return 0;
+}
+
+void client_manager_init(void)
+{
+ char *test;
+ ConfigParam *param;
+
+ param = getConfigParam(CONF_CONN_TIMEOUT);
+
+ if (param) {
+ client_timeout = strtol(param->value, &test, 10);
+ if (*test != '\0' || client_timeout <= 0) {
+ FATAL("connection timeout \"%s\" is not a positive "
+ "integer, line %i\n", CONF_CONN_TIMEOUT,
+ param->line);
+ }
+ }
+
+ param = getConfigParam(CONF_MAX_CONN);
+
+ if (param) {
+ client_max_connections = strtol(param->value, &test, 10);
+ if (*test != '\0' || client_max_connections <= 0) {
+ FATAL("max connections \"%s\" is not a positive integer"
+ ", line %i\n", param->value, param->line);
+ }
+ } else
+ client_max_connections = CLIENT_MAX_CONNECTIONS_DEFAULT;
+
+ param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE);
+
+ if (param) {
+ long tmp = strtol(param->value, &test, 10);
+ if (*test != '\0' || tmp <= 0) {
+ FATAL("max command list size \"%s\" is not a positive "
+ "integer, line %i\n", param->value, param->line);
+ }
+ client_max_command_list_size = tmp * 1024;
+ }
+
+ param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE);
+
+ if (param) {
+ long tmp = strtol(param->value, &test, 10);
+ if (*test != '\0' || tmp <= 0) {
+ FATAL("max output buffer size \"%s\" is not a positive "
+ "integer, line %i\n", param->value, param->line);
+ }
+ client_max_output_buffer_size = tmp * 1024;
+ }
+
+ list_cache = xcalloc(client_list_cache_size, sizeof(struct strnode));
+ list_cache_head = &(list_cache[0]);
+ list_cache_tail = &(list_cache[client_list_cache_size - 1]);
+}
+
+static void client_close_all(void)
+{
+ struct client *cl, *n;
+
+ list_for_each_entry_safe(cl, n, &clients, siblings)
+ client_close(cl);
+ num_clients = 0;
+
+ free(list_cache);
+}
+
+void client_manager_deinit(void)
+{
+ client_close_all();
+
+ client_max_connections = 0;
+}
+
+void client_manager_expire(void)
+{
+ struct client *cl, *n;
+
+ list_for_each_entry_safe(cl, n, &clients, siblings) {
+ if (client_is_expired(cl)) {
+ DEBUG("client %i: expired\n", cl->num);
+ client_close(cl);
+ } else if (time(NULL) - cl->lastTime >
+ client_timeout) {
+ DEBUG("client %i: timeout\n", cl->num);
+ client_close(cl);
+ }
+ }
+}
+
+static void client_write_deferred(struct client *cl)
+{
+ struct sllnode *buf;
+ ssize_t ret = 0;
+
+ buf = cl->deferred_send;
+ while (buf) {
+ assert(buf->size > 0);
+
+ ret = write(cl->fd, buf->data, buf->size);
+ if (ret < 0)
+ break;
+ else if ((size_t)ret < buf->size) {
+ assert(cl->deferred_bytes >= (size_t)ret);
+ cl->deferred_bytes -= ret;
+ buf->data = (char *)buf->data + ret;
+ buf->size -= ret;
+ } else {
+ struct sllnode *tmp = buf;
+ size_t decr = (buf->size + sizeof(struct sllnode));
+
+ assert(cl->deferred_bytes >= decr);
+ cl->deferred_bytes -= decr;
+ buf = buf->next;
+ free(tmp);
+ cl->deferred_send = buf;
+ }
+ cl->lastTime = time(NULL);
+ }
+
+ if (!cl->deferred_send) {
+ DEBUG("client %i: buffer empty %lu\n", cl->num,
+ (unsigned long)cl->deferred_bytes);
+ assert(cl->deferred_bytes == 0);
+ } else if (ret < 0 && errno != EAGAIN && errno != EINTR) {
+ /* cause client to close */
+ DEBUG("client %i: problems flushing buffer\n",
+ cl->num);
+ client_set_expired(cl);
+ }
+}
+
+static struct client * client_by_fd(int fd)
+{
+ struct client *cl;
+
+ list_for_each_entry(cl, &clients, siblings)
+ if (cl->fd == fd)
+ return cl;
+
+ return NULL;
+}
+
+int client_print(int fd, const char *buffer, size_t buflen)
+{
+ size_t copylen;
+ struct client *cl;
+
+ assert(fd >= 0);
+
+ cl = client_by_fd(fd);
+ if (cl == NULL)
+ return -1;
+
+ /* if fd isn't found or client is going to be closed, do nothing */
+ if (client_is_expired(cl))
+ return 0;
+
+ while (buflen > 0 && !client_is_expired(cl)) {
+ size_t left;
+
+ assert(cl->send_buf_size >= cl->send_buf_used);
+ left = cl->send_buf_size - cl->send_buf_used;
+
+ copylen = buflen > left ? left : buflen;
+ memcpy(cl->send_buf + cl->send_buf_used, buffer,
+ copylen);
+ buflen -= copylen;
+ cl->send_buf_used += copylen;
+ buffer += copylen;
+ if (cl->send_buf_used >= cl->send_buf_size)
+ client_write_output(cl);
+ }
+
+ return 0;
+}
+
+static void client_defer_output(struct client *cl,
+ const void *data, size_t length)
+{
+ struct sllnode **buf_r;
+
+ assert(length > 0);
+
+ cl->deferred_bytes += sizeof(struct sllnode) + length;
+ if (cl->deferred_bytes > client_max_output_buffer_size) {
+ ERROR("client %i: output buffer size (%lu) is "
+ "larger than the max (%lu)\n",
+ cl->num,
+ (unsigned long)cl->deferred_bytes,
+ (unsigned long)client_max_output_buffer_size);
+ /* cause client to close */
+ client_set_expired(cl);
+ return;
+ }
+
+ buf_r = &cl->deferred_send;
+ while (*buf_r != NULL)
+ buf_r = &(*buf_r)->next;
+ *buf_r = new_sllnode(data, length);
+}
+
+static void client_write(struct client *cl,
+ const char *data, size_t length)
+{
+ ssize_t ret;
+
+ assert(length > 0);
+ assert(cl->deferred_send == NULL);
+
+ if ((ret = write(cl->fd, data, length)) < 0) {
+ if (errno == EAGAIN || errno == EINTR) {
+ client_defer_output(cl, data, length);
+ } else {
+ DEBUG("client %i: problems writing\n", cl->num);
+ client_set_expired(cl);
+ return;
+ }
+ } else if ((size_t)ret < cl->send_buf_used) {
+ client_defer_output(cl, data + ret, length - ret);
+ }
+
+ if (cl->deferred_send)
+ DEBUG("client %i: buffer created\n", cl->num);
+}
+
+static void client_write_output(struct client *cl)
+{
+ if (client_is_expired(cl) || !cl->send_buf_used)
+ return;
+
+ if (cl->deferred_send != NULL)
+ client_defer_output(cl, cl->send_buf, cl->send_buf_used);
+ else
+ client_write(cl, cl->send_buf, cl->send_buf_used);
+
+ cl->send_buf_used = 0;
+}
+
diff --git a/src/interface.h b/src/client.h
index c83381319..a4cb4a902 100644
--- a/src/interface.h
+++ b/src/client.h
@@ -21,12 +21,13 @@
#include "os_compat.h"
-void initInterfaces(void);
-void openAInterface(int fd, const struct sockaddr *addr);
-void freeAllInterfaces(void);
-void closeOldInterfaces(void);
-int interfacePrintWithFD(int fd, const char *buffer, size_t len);
+void client_manager_init(void);
+void client_manager_deinit(void);
+int client_manager_io(void);
+void client_manager_expire(void);
-int doIOForInterfaces(void);
+void client_new(int fd, const struct sockaddr *addr);
+
+int client_print(int fd, const char *buffer, size_t len);
#endif
diff --git a/src/command.c b/src/command.c
index bc646804e..ebca41bde 100644
--- a/src/command.c
+++ b/src/command.c
@@ -218,6 +218,54 @@ static int mpd_fprintf__ check_int(int fd, int *dst,
return 0;
}
+static int print_playlist_result(int fd, enum playlist_result result)
+{
+ switch (result) {
+ case PLAYLIST_RESULT_SUCCESS:
+ return 0;
+
+ case PLAYLIST_RESULT_ERRNO:
+ commandError(fd, ACK_ERROR_SYSTEM, strerror(errno));
+ return -1;
+
+ case PLAYLIST_RESULT_NO_SUCH_SONG:
+ commandError(fd, ACK_ERROR_NO_EXIST, "No such song");
+ return -1;
+
+ case PLAYLIST_RESULT_NO_SUCH_LIST:
+ commandError(fd, ACK_ERROR_NO_EXIST, "No such playlist");
+ return -1;
+
+ case PLAYLIST_RESULT_LIST_EXISTS:
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "Playlist already exists");
+ return -1;
+
+ case PLAYLIST_RESULT_BAD_NAME:
+ commandError(fd, ACK_ERROR_ARG,
+ "playlist name is invalid: "
+ "playlist names may not contain slashes,"
+ " newlines or carriage returns");
+ return -1;
+
+ case PLAYLIST_RESULT_BAD_RANGE:
+ commandError(fd, ACK_ERROR_ARG, "Bad song index");
+ return -1;
+
+ case PLAYLIST_RESULT_NOT_PLAYING:
+ commandError(fd, ACK_ERROR_PLAYER_SYNC, "Not playing");
+ return -1;
+
+ case PLAYLIST_RESULT_TOO_LARGE:
+ commandError(fd, ACK_ERROR_PLAYLIST_MAX,
+ "playlist is at the max size");
+ return -1;
+ }
+
+ assert(0);
+ return -1;
+}
+
static void addCommand(const char *name,
int reqPermission,
int minargs,
@@ -253,21 +301,25 @@ static int handlePlay(int fd, mpd_unused int *permission,
int argc, char *argv[])
{
int song = -1;
+ enum playlist_result result;
if (argc == 2 && check_int(fd, &song, argv[1], need_positive) < 0)
return -1;
- return playPlaylist(fd, song, 0);
+ result = playPlaylist(song, 0);
+ return print_playlist_result(fd, result);
}
static int handlePlayId(int fd, mpd_unused int *permission,
int argc, char *argv[])
{
int id = -1;
+ enum playlist_result result;
if (argc == 2 && check_int(fd, &id, argv[1], need_positive) < 0)
return -1;
- return playPlaylistById(fd, id, 0);
+ result = playPlaylistById(id, 0);
+ return print_playlist_result(fd, result);
}
static int handleStop(mpd_unused int fd, mpd_unused int *permission,
@@ -281,11 +333,13 @@ static int handleCurrentSong(int fd, mpd_unused int *permission,
mpd_unused int argc, mpd_unused char *argv[])
{
int song = getPlaylistCurrentSong();
+ enum playlist_result result;
- if (song >= 0) {
- return playlistInfo(fd, song);
- } else
+ if (song < 0)
return 0;
+
+ result = playlistInfo(fd, song);
+ return print_playlist_result(fd, result);
}
static int handlePause(int fd, mpd_unused int *permission,
@@ -323,44 +377,50 @@ static int commandStatus(mpd_unused int fd, mpd_unused int *permission,
break;
}
- fdprintf(fd, "%s: %i\n", COMMAND_STATUS_VOLUME, getVolumeLevel());
- fdprintf(fd, "%s: %i\n", COMMAND_STATUS_REPEAT,
- getPlaylistRepeatStatus());
- fdprintf(fd, "%s: %i\n", COMMAND_STATUS_RANDOM,
- getPlaylistRandomStatus());
- fdprintf(fd, "%s: %li\n", COMMAND_STATUS_PLAYLIST,
- getPlaylistVersion());
- fdprintf(fd, "%s: %i\n", COMMAND_STATUS_PLAYLIST_LENGTH,
- getPlaylistLength());
- fdprintf(fd, "%s: %i\n", COMMAND_STATUS_CROSSFADE,
- (int)(ob_get_xfade() + 0.5));
-
- fdprintf(fd, "%s: %s\n", COMMAND_STATUS_STATE, state);
+ fdprintf(fd,
+ COMMAND_STATUS_VOLUME ": %i\n"
+ COMMAND_STATUS_REPEAT ": %i\n"
+ COMMAND_STATUS_RANDOM ": %i\n"
+ COMMAND_STATUS_PLAYLIST ": %li\n"
+ COMMAND_STATUS_PLAYLIST_LENGTH ": %i\n"
+ COMMAND_STATUS_CROSSFADE ": %i\n"
+ COMMAND_STATUS_STATE ": %s\n",
+ getVolumeLevel(),
+ getPlaylistRepeatStatus(),
+ getPlaylistRandomStatus(),
+ getPlaylistVersion(),
+ getPlaylistLength(),
+ (int)(ob_get_xfade() + 0.5),
+ state);
song = getPlaylistCurrentSong();
if (song >= 0) {
- fdprintf(fd, "%s: %i\n", COMMAND_STATUS_SONG, song);
- fdprintf(fd, "%s: %i\n", COMMAND_STATUS_SONGID,
- getPlaylistSongId(song));
+ fdprintf(fd,
+ COMMAND_STATUS_SONG ": %i\n"
+ COMMAND_STATUS_SONGID ": %i\n",
+ song, getPlaylistSongId(song));
}
if (ob_get_state() != OB_STATE_STOP) {
- fdprintf(fd, "%s: %lu:%lu\n", COMMAND_STATUS_TIME,
- ob_get_elapsed_time(), ob_get_total_time());
- fdprintf(fd, "%s: %u\n", COMMAND_STATUS_BITRATE,
- ob_get_bit_rate());
- fdprintf(fd, "%s: %u:%u:%u\n", COMMAND_STATUS_AUDIO,
- ob_get_sample_rate(), ob_get_bits(),
- ob_get_channels());
+ fdprintf(fd,
+ COMMAND_STATUS_TIME ": %lu:%lu\n"
+ COMMAND_STATUS_BITRATE ": %u\n"
+ COMMAND_STATUS_AUDIO ": %u:%u:%u\n",
+ ob_get_elapsed_time(),
+ ob_get_total_time(),
+ ob_get_bit_rate(),
+ ob_get_sample_rate(),
+ ob_get_bits(),
+ ob_get_channels());
}
if ((updateJobId = isUpdatingDB())) {
- fdprintf(fd, "%s: %i\n", COMMAND_STATUS_UPDATING_DB,
- updateJobId);
+ fdprintf(fd, COMMAND_STATUS_UPDATING_DB ": %i\n",
+ updateJobId);
}
if (player_errno != PLAYER_ERROR_NONE) {
- fdprintf(fd, "%s: %s\n", COMMAND_STATUS_ERROR,
- player_strerror());
+ fdprintf(fd, COMMAND_STATUS_ERROR ": %s\n",
+ player_strerror());
}
return 0;
@@ -382,66 +442,85 @@ static int handleAdd(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
char *path = argv[1];
+ enum playlist_result result;
if (isRemoteUrl(path))
- return addToPlaylist(fd, path, NULL);
+ return addToPlaylist(path, NULL);
+
+ result = addAllIn(path);
+ if (result == (enum playlist_result)-1) {
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "directory or file not found");
+ return -1;
+ }
- return addAllIn(fd, path);
+ return print_playlist_result(fd, result);
}
static int handleAddId(int fd, mpd_unused int *permission,
int argc, char *argv[])
{
int added_id;
- int ret = addToPlaylist(fd, argv[1], &added_id);
-
- if (!ret) {
- if (argc == 3) {
- int to;
- if (check_int(fd, &to, argv[2],
- check_integer, argv[2]) < 0)
- return -1;
- ret = moveSongInPlaylistById(fd, added_id, to);
- if (ret) { /* move failed */
- deleteFromPlaylistById(fd, added_id);
- return ret;
- }
+ enum playlist_result result = addToPlaylist(argv[1], &added_id);
+
+ if (result == PLAYLIST_RESULT_SUCCESS)
+ return result;
+
+ if (argc == 3) {
+ int to;
+ if (check_int(fd, &to, argv[2],
+ check_integer, argv[2]) < 0)
+ return -1;
+ result = moveSongInPlaylistById(added_id, to);
+ if (result != PLAYLIST_RESULT_SUCCESS) {
+ int ret = print_playlist_result(fd, result);
+ deleteFromPlaylistById(added_id);
+ return ret;
}
- fdprintf(fd, "Id: %d\n", added_id);
}
- return ret;
+
+ fdprintf(fd, "Id: %d\n", added_id);
+ return result;
}
static int handleDelete(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
int song;
+ enum playlist_result result;
if (check_int(fd, &song, argv[1], need_positive) < 0)
return -1;
- return deleteFromPlaylist(fd, song);
+
+ result = deleteFromPlaylist(song);
+ return print_playlist_result(fd, result);
}
static int handleDeleteId(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
int id;
+ enum playlist_result result;
if (check_int(fd, &id, argv[1], need_positive) < 0)
return -1;
- return deleteFromPlaylistById(fd, id);
+
+ result = deleteFromPlaylistById(id);
+ return print_playlist_result(fd, result);
}
static int handlePlaylist(int fd, mpd_unused int *permission,
mpd_unused int argc, mpd_unused char *argv[])
{
- return showPlaylist(fd);
+ showPlaylist(fd);
+ return 0;
}
-static int handleShuffle(int fd, mpd_unused int *permission,
+static int handleShuffle(mpd_unused int fd, mpd_unused int *permission,
mpd_unused int argc, mpd_unused char *argv[])
{
- return shufflePlaylist(fd);
+ shufflePlaylist();
+ return 0;
}
static int handleClear(mpd_unused int fd, mpd_unused int *permission,
@@ -454,25 +533,43 @@ static int handleClear(mpd_unused int fd, mpd_unused int *permission,
static int handleSave(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- return savePlaylist(fd, argv[1]);
+ enum playlist_result result;
+
+ result = savePlaylist(argv[1]);
+ return print_playlist_result(fd, result);
}
static int handleLoad(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- return loadPlaylist(fd, argv[1]);
+ enum playlist_result result;
+
+ result = loadPlaylist(fd, argv[1]);
+ return print_playlist_result(fd, result);
}
static int handleListPlaylist(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- return PlaylistInfo(fd, argv[1], 0);
+ int ret;
+
+ ret = PlaylistInfo(fd, argv[1], 0);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST, "No such playlist");
+
+ return ret;
}
static int handleListPlaylistInfo(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- return PlaylistInfo(fd, argv[1], 1);
+ int ret;
+
+ ret = PlaylistInfo(fd, argv[1], 1);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST, "No such playlist");
+
+ return ret;
}
static int handleLsInfo(int fd, mpd_unused int *permission,
@@ -483,8 +580,10 @@ static int handleLsInfo(int fd, mpd_unused int *permission,
if (argc == 2)
path = argv[1];
- if (printDirectoryInfo(fd, path) < 0)
+ if (printDirectoryInfo(fd, path) < 0) {
+ commandError(fd, ACK_ERROR_NO_EXIST, "directory not found");
return -1;
+ }
if (isRootDirectory(path))
return lsPlaylists(fd, path);
@@ -495,13 +594,19 @@ static int handleLsInfo(int fd, mpd_unused int *permission,
static int handleRm(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- return deletePlaylist(fd, argv[1]);
+ enum playlist_result result;
+
+ result = deletePlaylist(argv[1]);
+ return print_playlist_result(fd, result);
}
static int handleRename(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- return renameStoredPlaylist(fd, argv[1], argv[2]);
+ enum playlist_result result;
+
+ result = renameStoredPlaylist(argv[1], argv[2]);
+ return print_playlist_result(fd, result);
}
static int handlePlaylistChanges(int fd, mpd_unused int *permission,
@@ -528,20 +633,26 @@ static int handlePlaylistInfo(int fd, mpd_unused int *permission,
int argc, char *argv[])
{
int song = -1;
+ enum playlist_result result;
if (argc == 2 && check_int(fd, &song, argv[1], need_positive) < 0)
return -1;
- return playlistInfo(fd, song);
+
+ result = playlistInfo(fd, song);
+ return print_playlist_result(fd, result);
}
static int handlePlaylistId(int fd, mpd_unused int *permission,
int argc, char *argv[])
{
int id = -1;
+ enum playlist_result result;
if (argc == 2 && check_int(fd, &id, argv[1], need_positive) < 0)
return -1;
- return playlistId(fd, id);
+
+ result = playlistId(fd, id);
+ return print_playlist_result(fd, result);
}
static int handleFind(int fd, mpd_unused int *permission,
@@ -560,6 +671,9 @@ static int handleFind(int fd, mpd_unused int *permission,
}
ret = findSongsIn(fd, NULL, numItems, items);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "directory or file not found");
freeLocateTagItemArray(numItems, items);
@@ -582,6 +696,9 @@ static int handleSearch(int fd, mpd_unused int *permission,
}
ret = searchForSongsIn(fd, NULL, numItems, items);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "directory or file not found");
freeLocateTagItemArray(numItems, items);
@@ -604,6 +721,9 @@ static int handleCount(int fd, mpd_unused int *permission,
}
ret = searchStatsForSongsIn(fd, NULL, numItems, items);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "directory or file not found");
freeLocateTagItemArray(numItems, items);
@@ -654,11 +774,13 @@ static int handlePlaylistDelete(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[]) {
char *playlist = argv[1];
int from;
+ enum playlist_result result;
if (check_int(fd, &from, argv[2], check_integer, argv[2]) < 0)
return -1;
- return removeOneSongFromStoredPlaylistByPath(fd, playlist, from);
+ result = removeOneSongFromStoredPlaylistByPath(playlist, from);
+ return print_playlist_result(fd, result);
}
static int handlePlaylistMove(int fd, mpd_unused int *permission,
@@ -666,13 +788,15 @@ static int handlePlaylistMove(int fd, mpd_unused int *permission,
{
char *playlist = argv[1];
int from, to;
+ enum playlist_result result;
if (check_int(fd, &from, argv[2], check_integer, argv[2]) < 0)
return -1;
if (check_int(fd, &to, argv[3], check_integer, argv[3]) < 0)
return -1;
- return moveSongInStoredPlaylistByPath(fd, playlist, from, to);
+ result = moveSongInStoredPlaylistByPath(playlist, from, to);
+ return print_playlist_result(fd, result);
}
static int listHandleUpdate(int fd,
@@ -738,30 +862,49 @@ static int handleListAll(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
char *directory = NULL;
+ int ret;
if (argc == 2)
directory = argv[1];
- return printAllIn(fd, directory);
+
+ ret = printAllIn(fd, directory);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "directory or file not found");
+
+ return ret;
}
static int handleVolume(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- int change;
+ int change, ret;
if (check_int(fd, &change, argv[1], need_integer) < 0)
return -1;
- return changeVolumeLevel(fd, change, 1);
+
+ ret = changeVolumeLevel(change, 1);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_SYSTEM,
+ "problems setting volume");
+
+ return ret;
}
static int handleSetVol(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- int level;
+ int level, ret;
if (check_int(fd, &level, argv[1], need_integer) < 0)
return -1;
- return changeVolumeLevel(fd, level, 0);
+
+ ret = changeVolumeLevel(level, 0);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_SYSTEM,
+ "problems setting volume");
+
+ return ret;
}
static int handleRepeat(int fd, mpd_unused int *permission,
@@ -771,7 +914,15 @@ static int handleRepeat(int fd, mpd_unused int *permission,
if (check_int(fd, &status, argv[1], need_integer) < 0)
return -1;
- return setPlaylistRepeatStatus(fd, status);
+
+ if (status != 0 && status != 1) {
+ commandError(fd, ACK_ERROR_ARG,
+ "\"%i\" is not 0 or 1", status);
+ return -1;
+ }
+
+ setPlaylistRepeatStatus(status);
+ return 0;
}
static int handleRandom(int fd, mpd_unused int *permission,
@@ -781,7 +932,15 @@ static int handleRandom(int fd, mpd_unused int *permission,
if (check_int(fd, &status, argv[1], need_integer) < 0)
return -1;
- return setPlaylistRandomStatus(fd, status);
+
+ if (status != 0 && status != 1) {
+ commandError(fd, ACK_ERROR_ARG,
+ "\"%i\" is not 0 or 1", status);
+ return -1;
+ }
+
+ setPlaylistRandomStatus(status);
+ return 0;
}
static int handleStats(int fd, mpd_unused int *permission,
@@ -844,6 +1003,10 @@ static int handleList(int fd, mpd_unused int *permission,
if (conditionals)
freeLocateTagItemArray(numConditionals, conditionals);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "directory or file not found");
+
return ret;
}
@@ -851,82 +1014,102 @@ static int handleMove(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
int from, to;
+ enum playlist_result result;
if (check_int(fd, &from, argv[1], check_integer, argv[1]) < 0)
return -1;
if (check_int(fd, &to, argv[2], check_integer, argv[2]) < 0)
return -1;
- return moveSongInPlaylist(fd, from, to);
+ result = moveSongInPlaylist(from, to);
+ return print_playlist_result(fd, result);
}
static int handleMoveId(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
int id, to;
+ enum playlist_result result;
if (check_int(fd, &id, argv[1], check_integer, argv[1]) < 0)
return -1;
if (check_int(fd, &to, argv[2], check_integer, argv[2]) < 0)
return -1;
- return moveSongInPlaylistById(fd, id, to);
+ result = moveSongInPlaylistById(id, to);
+ return print_playlist_result(fd, result);
}
static int handleSwap(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
int song1, song2;
+ enum playlist_result result;
if (check_int(fd, &song1, argv[1], check_integer, argv[1]) < 0)
return -1;
if (check_int(fd, &song2, argv[2], check_integer, argv[2]) < 0)
return -1;
- return swapSongsInPlaylist(fd, song1, song2);
+ result = swapSongsInPlaylist(song1, song2);
+ return print_playlist_result(fd, result);
}
static int handleSwapId(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
int id1, id2;
+ enum playlist_result result;
if (check_int(fd, &id1, argv[1], check_integer, argv[1]) < 0)
return -1;
if (check_int(fd, &id2, argv[2], check_integer, argv[2]) < 0)
return -1;
- return swapSongsInPlaylistById(fd, id1, id2);
+ result = swapSongsInPlaylistById(id1, id2);
+ return print_playlist_result(fd, result);
}
static int handleSeek(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
int song, seek_time;
+ enum playlist_result result;
if (check_int(fd, &song, argv[1], check_integer, argv[1]) < 0)
return -1;
if (check_int(fd, &seek_time, argv[2], check_integer, argv[2]) < 0)
return -1;
- return seekSongInPlaylist(fd, song, seek_time);
+
+ result = seekSongInPlaylist(song, seek_time);
+ return print_playlist_result(fd, result);
}
static int handleSeekId(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
int id, seek_time;
+ enum playlist_result result;
if (check_int(fd, &id, argv[1], check_integer, argv[1]) < 0)
return -1;
if (check_int(fd, &seek_time, argv[2], check_integer, argv[2]) < 0)
return -1;
- return seekSongInPlaylistById(fd, id, seek_time);
+
+ result = seekSongInPlaylistById(id, seek_time);
+ return print_playlist_result(fd, result);
}
static int handleListAllInfo(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
char *directory = NULL;
+ int ret;
if (argc == 2)
directory = argv[1];
- return printInfoForAllIn(fd, directory);
+ ret = printInfoForAllIn(fd, directory);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "directory or file not found");
+
+ return ret;
}
static int handlePing(mpd_unused int fd, mpd_unused int *permission,
@@ -961,21 +1144,31 @@ static int handleCrossfade(int fd, mpd_unused int *permission,
static int handleEnableDevice(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- int device;
+ int device, ret;
if (check_int(fd, &device, argv[1], check_non_negative, argv[1]) < 0)
return -1;
- return enableAudioDevice(fd, device);
+
+ ret = enableAudioDevice(device);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST, "No such audio output");
+
+ return ret;
}
static int handleDisableDevice(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- int device;
+ int device, ret;
if (check_int(fd, &device, argv[1], check_non_negative, argv[1]) < 0)
return -1;
- return disableAudioDevice(fd, device);
+
+ ret = disableAudioDevice(device);
+ if (ret == -1)
+ commandError(fd, ACK_ERROR_NO_EXIST, "No such audio output");
+
+ return ret;
}
static int handleDevices(int fd, mpd_unused int *permission,
@@ -1027,7 +1220,10 @@ static int handleNotcommands(int fd, mpd_unused int *permission,
static int handlePlaylistClear(int fd, mpd_unused int *permission,
mpd_unused int argc, char *argv[])
{
- return clearStoredPlaylist(fd, argv[1]);
+ enum playlist_result result;
+
+ result = clearStoredPlaylist(argv[1]);
+ return print_playlist_result(fd, result);
}
static int handlePlaylistAdd(int fd, mpd_unused int *permission,
@@ -1035,11 +1231,20 @@ static int handlePlaylistAdd(int fd, mpd_unused int *permission,
{
char *playlist = argv[1];
char *path = argv[2];
+ enum playlist_result result;
if (isRemoteUrl(path))
- return addToStoredPlaylist(fd, path, playlist);
+ result = addToStoredPlaylist(path, playlist);
+ else
+ result = addAllInToStoredPlaylist(path, playlist);
+
+ if (result == (enum playlist_result)-1) {
+ commandError(fd, ACK_ERROR_NO_EXIST,
+ "directory or file not found");
+ return -1;
+ }
- return addAllInToStoredPlaylist(fd, path, playlist);
+ return print_playlist_result(fd, result);
}
void initCommands(void)
diff --git a/src/dbUtils.c b/src/dbUtils.c
index 00fa1d441..0eb485f1e 100644
--- a/src/dbUtils.c
+++ b/src/dbUtils.c
@@ -45,7 +45,7 @@ typedef struct _SearchStats {
unsigned long playTime;
} SearchStats;
-static int countSongsInDirectory(mpd_unused int fd, Directory * directory,
+static int countSongsInDirectory(Directory * directory,
void *data)
{
int *count = (int *)data;
@@ -55,24 +55,32 @@ static int countSongsInDirectory(mpd_unused int fd, Directory * directory,
return 0;
}
-static int printDirectoryInDirectory(int fd, Directory * directory,
- mpd_unused void *data)
+static int printDirectoryInDirectory(Directory * directory, void *data)
{
+ int fd = (int)(size_t)data;
if (directory->path) {
fdprintf(fd, "directory: %s\n", getDirectoryPath(directory));
}
return 0;
}
-static int printSongInDirectory(int fd, Song * song, mpd_unused void *data)
+static int printSongInDirectory(Song * song, mpd_unused void *data)
{
+ int fd = (int)(size_t)data;
printSongUrl(fd, song);
return 0;
}
-static int searchInDirectory(int fd, Song * song, void *data)
+struct search_data {
+ int fd;
+ LocateTagItemArray array;
+};
+
+static int searchInDirectory(Song * song, void *_data)
{
- LocateTagItemArray *array = data;
+ struct search_data *data = _data;
+ int fd = data->fd;
+ LocateTagItemArray *array = &data->array;
if (strstrSearchTags(song, array->numItems, array->items))
printSongInfo(fd, song);
@@ -80,23 +88,25 @@ static int searchInDirectory(int fd, Song * song, void *data)
return 0;
}
-int searchForSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
+int searchForSongsIn(int fd, const char *name, int numItems,
+ LocateTagItem * items)
{
int ret;
int i;
char **originalNeedles = xmalloc(numItems * sizeof(char *));
- LocateTagItemArray array;
+ struct search_data data;
for (i = 0; i < numItems; i++) {
originalNeedles[i] = items[i].needle;
items[i].needle = strDupToUpper(originalNeedles[i]);
}
- array.numItems = numItems;
- array.items = items;
+ data.fd = fd;
+ data.array.numItems = numItems;
+ data.array.items = items;
- ret = traverseAllIn(fd, name, searchInDirectory, NULL, &array);
+ ret = traverseAllIn(name, searchInDirectory, NULL, &data);
for (i = 0; i < numItems; i++) {
free(items[i].needle);
@@ -108,9 +118,11 @@ int searchForSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
return ret;
}
-static int findInDirectory(int fd, Song * song, void *data)
+static int findInDirectory(Song * song, void *_data)
{
- LocateTagItemArray *array = data;
+ struct search_data *data = _data;
+ int fd = data->fd;
+ LocateTagItemArray *array = &data->array;
if (tagItemsFoundAndMatches(song, array->numItems, array->items))
printSongInfo(fd, song);
@@ -118,14 +130,15 @@ static int findInDirectory(int fd, Song * song, void *data)
return 0;
}
-int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
+int findSongsIn(int fd, const char *name, int numItems, LocateTagItem * items)
{
- LocateTagItemArray array;
+ struct search_data data;
- array.numItems = numItems;
- array.items = items;
+ data.fd = fd;
+ data.array.numItems = numItems;
+ data.array.items = items;
- return traverseAllIn(fd, name, findInDirectory, NULL, (void *)&array);
+ return traverseAllIn(name, findInDirectory, NULL, &data);
}
static void printSearchStats(int fd, SearchStats *stats)
@@ -134,7 +147,7 @@ static void printSearchStats(int fd, SearchStats *stats)
fdprintf(fd, "playtime: %li\n", stats->playTime);
}
-static int searchStatsInDirectory(mpd_unused int fd, Song * song, void *data)
+static int searchStatsInDirectory(Song * song, void *data)
{
SearchStats *stats = data;
@@ -148,7 +161,7 @@ static int searchStatsInDirectory(mpd_unused int fd, Song * song, void *data)
return 0;
}
-int searchStatsForSongsIn(int fd, char *name, int numItems,
+int searchStatsForSongsIn(int fd, const char *name, int numItems,
LocateTagItem * items)
{
SearchStats stats;
@@ -159,49 +172,60 @@ int searchStatsForSongsIn(int fd, char *name, int numItems,
stats.numberOfSongs = 0;
stats.playTime = 0;
- ret = traverseAllIn(fd, name, searchStatsInDirectory, NULL, &stats);
+ ret = traverseAllIn(name, searchStatsInDirectory, NULL, &stats);
if (ret == 0)
printSearchStats(fd, &stats);
return ret;
}
-int printAllIn(int fd, char *name)
+int printAllIn(int fd, const char *name)
{
- return traverseAllIn(fd, name, printSongInDirectory,
- printDirectoryInDirectory, NULL);
+ return traverseAllIn(name, printSongInDirectory,
+ printDirectoryInDirectory, (void*)(size_t)fd);
}
-static int directoryAddSongToPlaylist(int fd, Song * song,
- mpd_unused void *data)
+static int directoryAddSongToPlaylist(Song * song, mpd_unused void *data)
{
- return addSongToPlaylist(fd, song, NULL);
+ return addSongToPlaylist(song, NULL);
}
-static int directoryAddSongToStoredPlaylist(int fd, Song *song, void *data)
+struct add_data {
+ const char *path;
+};
+
+static int directoryAddSongToStoredPlaylist(Song *song, void *_data)
{
- if (appendSongToStoredPlaylistByPath(fd, (char *)data, song) != 0)
+ struct add_data *data = _data;
+
+ if (appendSongToStoredPlaylistByPath(data->path, song) != 0)
return -1;
return 0;
}
-int addAllIn(int fd, char *name)
+int addAllIn(const char *name)
{
- return traverseAllIn(fd, name, directoryAddSongToPlaylist, NULL, NULL);
+ return traverseAllIn(name, directoryAddSongToPlaylist, NULL, NULL);
}
-int addAllInToStoredPlaylist(int fd, char *name, char *utf8file)
+int addAllInToStoredPlaylist(const char *name, const char *utf8file)
{
- return traverseAllIn(fd, name, directoryAddSongToStoredPlaylist, NULL,
- (void *)utf8file);
+ struct add_data data = {
+ .path = utf8file,
+ };
+
+ return traverseAllIn(name, directoryAddSongToStoredPlaylist, NULL,
+ &data);
}
-static int directoryPrintSongInfo(int fd, Song * song, mpd_unused void *data)
+static int directoryPrintSongInfo(Song * song, void *data)
{
+ int fd = (int)(size_t)data;
+
return printSongInfo(fd, song);
}
-static int sumSongTime(mpd_unused int fd, Song * song, void *data)
+static int sumSongTime(Song * song, void *data)
{
unsigned long *sum_time = (unsigned long *)data;
@@ -211,28 +235,28 @@ static int sumSongTime(mpd_unused int fd, Song * song, void *data)
return 0;
}
-int printInfoForAllIn(int fd, char *name)
+int printInfoForAllIn(int fd, const char *name)
{
- return traverseAllIn(fd, name, directoryPrintSongInfo,
- printDirectoryInDirectory, NULL);
+ return traverseAllIn(name, directoryPrintSongInfo,
+ printDirectoryInDirectory, (void*)(size_t)fd);
}
-int countSongsIn(int fd, char *name)
+int countSongsIn(const char *name)
{
int count = 0;
void *ptr = (void *)&count;
- traverseAllIn(fd, name, NULL, countSongsInDirectory, ptr);
+ traverseAllIn(name, NULL, countSongsInDirectory, ptr);
return count;
}
-unsigned long sumSongTimesIn(int fd, char *name)
+unsigned long sumSongTimesIn(const char *name)
{
unsigned long dbPlayTime = 0;
void *ptr = (void *)&dbPlayTime;
- traverseAllIn(fd, name, sumSongTime, NULL, ptr);
+ traverseAllIn(name, sumSongTime, NULL, ptr);
return dbPlayTime;
}
@@ -281,14 +305,14 @@ struct list_tags_data {
struct strset *set;
};
-static int listUniqueTagsInDirectory(int fd, Song * song, void *_data)
+static int listUniqueTagsInDirectory(Song * song, void *_data)
{
struct list_tags_data *data = _data;
ListCommandItem *item = data->item;
if (tagItemsFoundAndMatches(song, item->numConditionals,
item->conditionals)) {
- visitTag(fd, data->set, song, item->tagType);
+ visitTag(data->fd, data->set, song, item->tagType);
}
return 0;
@@ -301,15 +325,13 @@ int listAllUniqueTags(int fd, int type, int numConditionals,
struct list_tags_data data;
ListCommandItem *item = newListCommandItem(type, numConditionals,
conditionals);
-
- data.fd = fd;
data.item = item;
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
data.set = strset_new();
}
- ret = traverseAllIn(fd, NULL, listUniqueTagsInDirectory, NULL, &data);
+ ret = traverseAllIn(NULL, listUniqueTagsInDirectory, NULL, &data);
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
const char *value;
@@ -327,9 +349,7 @@ int listAllUniqueTags(int fd, int type, int numConditionals,
return ret;
}
-static int sumSavedFilenameMemoryInDirectory(mpd_unused int fd,
- Directory * dir,
- void *data)
+static int sumSavedFilenameMemoryInDirectory(Directory * dir, void *data)
{
int *sum = data;
@@ -342,8 +362,7 @@ static int sumSavedFilenameMemoryInDirectory(mpd_unused int fd,
return 0;
}
-static int sumSavedFilenameMemoryInSong(mpd_unused int fd, Song * song,
- void *data)
+static int sumSavedFilenameMemoryInSong(Song * song, void *data)
{
int *sum = data;
@@ -356,7 +375,7 @@ void printSavedMemoryFromFilenames(void)
{
int sum = 0;
- traverseAllIn(STDERR_FILENO, NULL, sumSavedFilenameMemoryInSong,
+ traverseAllIn(NULL, sumSavedFilenameMemoryInSong,
sumSavedFilenameMemoryInDirectory, (void *)&sum);
DEBUG("saved memory from filenames: %i\n", sum);
diff --git a/src/dbUtils.h b/src/dbUtils.h
index f2237eab7..592b62e95 100644
--- a/src/dbUtils.h
+++ b/src/dbUtils.h
@@ -21,25 +21,25 @@
#include "locate.h"
-int printAllIn(int fd, char *name);
+int printAllIn(int fd, const char *name);
-int addAllIn(int fd, char *name);
+int addAllIn(const char *name);
-int addAllInToStoredPlaylist(int fd, char *name, char *utf8file);
+int addAllInToStoredPlaylist(const char *name, const char *utf8file);
-int printInfoForAllIn(int fd, char *name);
+int printInfoForAllIn(int fd, const char *name);
-int searchForSongsIn(int fd, char *name, int numItems,
+int searchForSongsIn(int fd, const char *name, int numItems,
LocateTagItem * items);
-int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items);
+int findSongsIn(int fd, const char *name, int numItems, LocateTagItem * items);
-int searchStatsForSongsIn(int fd, char *name, int numItems,
+int searchStatsForSongsIn(int fd, const char *name, int numItems,
LocateTagItem * items);
-int countSongsIn(int fd, char *name);
+int countSongsIn(const char *name);
-unsigned long sumSongTimesIn(int fd, char *name);
+unsigned long sumSongTimesIn(const char *name);
int listAllUniqueTags(int fd, int type, int numConditiionals,
LocateTagItem * conditionals);
diff --git a/src/directory.c b/src/directory.c
index 33a862ddd..2175c54a0 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -20,7 +20,7 @@
#include "command.h"
#include "conf.h"
-#include "interface.h"
+#include "client.h"
#include "listen.h"
#include "log.h"
#include "ls.h"
@@ -177,7 +177,7 @@ int updateInit(int fd, List * pathList)
finishSigHandlers();
closeAllListenSockets();
- freeAllInterfaces();
+ client_manager_deinit();
finishPlaylist();
finishVolume();
@@ -848,10 +848,8 @@ int printDirectoryInfo(int fd, const char *name)
{
Directory *directory;
- if ((directory = getDirectory(name)) == NULL) {
- commandError(fd, ACK_ERROR_NO_EXIST, "directory not found");
+ if ((directory = getDirectory(name)) == NULL)
return -1;
- }
printDirectoryList(fd, directory->subDirectories);
printSongInfoFromList(fd, directory->songs);
@@ -1153,8 +1151,8 @@ int readDirectoryDB(void)
readDirectoryInfo(fp, mp3rootDirectory);
while (fclose(fp) && errno == EINTR) ;
- stats.numberOfSongs = countSongsIn(STDERR_FILENO, NULL);
- stats.dbPlayTime = sumSongTimesIn(STDERR_FILENO, NULL);
+ stats.numberOfSongs = countSongsIn(NULL);
+ stats.dbPlayTime = sumSongTimesIn(NULL);
if (stat(dbFile, &st) == 0)
directory_dbModTime = st.st_mtime;
@@ -1180,11 +1178,10 @@ void updateMp3Directory(void)
return;
}
-static int traverseAllInSubDirectory(int fd, Directory * directory,
- int (*forEachSong) (int, Song *,
- void *),
- int (*forEachDir) (int, Directory *,
- void *), void *data)
+static int traverseAllInSubDirectory(Directory * directory,
+ int (*forEachSong) (Song *, void *),
+ int (*forEachDir) (Directory *, void *),
+ void *data)
{
ListNode *node = directory->songs->firstNode;
Song *song;
@@ -1192,7 +1189,7 @@ static int traverseAllInSubDirectory(int fd, Directory * directory,
int errFlag = 0;
if (forEachDir) {
- errFlag = forEachDir(fd, directory, data);
+ errFlag = forEachDir(directory, data);
if (errFlag)
return errFlag;
}
@@ -1200,7 +1197,7 @@ static int traverseAllInSubDirectory(int fd, Directory * directory,
if (forEachSong) {
while (node != NULL && !errFlag) {
song = (Song *) node->data;
- errFlag = forEachSong(fd, song, data);
+ errFlag = forEachSong(song, data);
node = node->nextNode;
}
if (errFlag)
@@ -1211,7 +1208,7 @@ static int traverseAllInSubDirectory(int fd, Directory * directory,
while (node != NULL && !errFlag) {
dir = (Directory *) node->data;
- errFlag = traverseAllInSubDirectory(fd, dir, forEachSong,
+ errFlag = traverseAllInSubDirectory(dir, forEachSong,
forEachDir, data);
node = node->nextNode;
}
@@ -1219,23 +1216,21 @@ static int traverseAllInSubDirectory(int fd, Directory * directory,
return errFlag;
}
-int traverseAllIn(int fd, char *name,
- int (*forEachSong) (int, Song *, void *),
- int (*forEachDir) (int, Directory *, void *), void *data)
+int traverseAllIn(const char *name,
+ int (*forEachSong) (Song *, void *),
+ int (*forEachDir) (Directory *, void *), void *data)
{
Directory *directory;
if ((directory = getDirectory(name)) == NULL) {
Song *song;
if ((song = getSongFromDB(name)) && forEachSong) {
- return forEachSong(fd, song, data);
+ return forEachSong(song, data);
}
- commandError(fd, ACK_ERROR_NO_EXIST,
- "directory or file not found");
return -1;
}
- return traverseAllInSubDirectory(fd, directory, forEachSong, forEachDir,
+ return traverseAllInSubDirectory(directory, forEachSong, forEachDir,
data);
}
@@ -1256,8 +1251,8 @@ void initMp3Directory(void)
mp3rootDirectory = newDirectory(NULL, NULL);
exploreDirectory(mp3rootDirectory);
freeAllDirectoryStats(mp3rootDirectory);
- stats.numberOfSongs = countSongsIn(STDERR_FILENO, NULL);
- stats.dbPlayTime = sumSongTimesIn(STDERR_FILENO, NULL);
+ stats.numberOfSongs = countSongsIn(NULL);
+ stats.dbPlayTime = sumSongTimesIn(NULL);
}
static Song *getSongDetails(const char *file, const char **shortnameRet,
@@ -1303,7 +1298,7 @@ static Song *getSongDetails(const char *file, const char **shortnameRet,
return (Song *) song;
}
-Song *getSongFromDB(char *file)
+Song *getSongFromDB(const char *file)
{
return getSongDetails(file, NULL, NULL);
}
diff --git a/src/directory.h b/src/directory.h
index acb173fc0..19dada309 100644
--- a/src/directory.h
+++ b/src/directory.h
@@ -60,13 +60,13 @@ int readDirectoryDB(void);
void updateMp3Directory(void);
-Song *getSongFromDB(char *file);
+Song *getSongFromDB(const char *file);
time_t getDbModTime(void);
-int traverseAllIn(int fd, char *name,
- int (*forEachSong) (int, Song *, void *),
- int (*forEachDir) (int, Directory *, void *), void *data);
+int traverseAllIn(const char *name,
+ int (*forEachSong) (Song *, void *),
+ int (*forEachDir) (Directory *, void *), void *data);
#define getDirectoryPath(dir) ((dir && dir->path) ? dir->path : "")
diff --git a/src/dlist.h b/src/dlist.h
new file mode 100644
index 000000000..6123d7136
--- /dev/null
+++ b/src/dlist.h
@@ -0,0 +1,484 @@
+/* the Music Player Daemon (MPD)
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * This source was imported from the Linux kernel. It is licensed
+ * GPLv2 only.
+ *
+ */
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+#else
+extern void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next);
+#endif
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+#else
+extern void list_add(struct list_head *new, struct list_head *head);
+#endif
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+#else
+extern void list_del(struct list_head *entry);
+#endif
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type*)ptr)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+ for (pos = (head)->prev, n = pos->prev; \
+ pos != (head); \
+ pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+#endif
diff --git a/src/inputPlugins/mod_plugin.c b/src/inputPlugins/mod_plugin.c
index 586d87ae9..6b09e3cf0 100644
--- a/src/inputPlugins/mod_plugin.c
+++ b/src/inputPlugins/mod_plugin.c
@@ -48,14 +48,21 @@ static BOOL mod_mpd_IsThere(void)
return 1;
}
+static char drv_name[] = "MPD";
+static char drv_version[] = "MPD Output Driver v0.1";
+
+#if (LIBMIKMOD_VERSION > 0x030106)
+static char drv_alias[] = "mpd";
+#endif
+
static MDRIVER drv_mpd = {
NULL,
- "MPD",
- "MPD Output Driver v0.1",
+ drv_name,
+ drv_version,
0,
255,
#if (LIBMIKMOD_VERSION > 0x030106)
- "mpd", /* Alias */
+ drv_alias,
#if (LIBMIKMOD_VERSION >= 0x030200)
NULL, /* CmdLineHelp */
#endif
@@ -92,6 +99,8 @@ static int mod_mikModInitError;
static int mod_initMikMod(void)
{
+ static char params[] = "";
+
if (mod_mikModInitError)
return -1;
@@ -110,7 +119,7 @@ static int mod_initMikMod(void)
md_mode = (DMODE_SOFT_MUSIC | DMODE_INTERP | DMODE_STEREO |
DMODE_16BITS);
- if (MikMod_Init("")) {
+ if (MikMod_Init(params)) {
ERROR("Could not init MikMod: %s\n",
MikMod_strerror(MikMod_errno));
mod_mikModInitError = 1;
diff --git a/src/inputPlugins/wavpack_plugin.c b/src/inputPlugins/wavpack_plugin.c
index 77339dabd..8bba8ae2b 100644
--- a/src/inputPlugins/wavpack_plugin.c
+++ b/src/inputPlugins/wavpack_plugin.c
@@ -224,34 +224,38 @@ static char *wavpack_tag(WavpackContext *wpc, char *key)
static ReplayGainInfo *wavpack_replaygain(WavpackContext *wpc)
{
+ static char replaygain_track_gain[] = "replaygain_track_gain";
+ static char replaygain_album_gain[] = "replaygain_album_gain";
+ static char replaygain_track_peak[] = "replaygain_track_peak";
+ static char replaygain_album_peak[] = "replaygain_album_peak";
ReplayGainInfo *replayGainInfo;
int found = 0;
char *value;
replayGainInfo = newReplayGainInfo();
- value = wavpack_tag(wpc, "replaygain_track_gain");
+ value = wavpack_tag(wpc, replaygain_track_gain);
if (value) {
replayGainInfo->trackGain = atof(value);
free(value);
found = 1;
}
- value = wavpack_tag(wpc, "replaygain_album_gain");
+ value = wavpack_tag(wpc, replaygain_album_gain);
if (value) {
replayGainInfo->albumGain = atof(value);
free(value);
found = 1;
}
- value = wavpack_tag(wpc, "replaygain_track_peak");
+ value = wavpack_tag(wpc, replaygain_track_peak);
if (value) {
replayGainInfo->trackPeak = atof(value);
free(value);
found = 1;
}
- value = wavpack_tag(wpc, "replaygain_album_peak");
+ value = wavpack_tag(wpc, replaygain_album_peak);
if (value) {
replayGainInfo->albumPeak = atof(value);
free(value);
diff --git a/src/interface.c b/src/interface.c
deleted file mode 100644
index 83e0084b5..000000000
--- a/src/interface.c
+++ /dev/null
@@ -1,794 +0,0 @@
-/* the Music Player Daemon (MPD)
- * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
- * This project's homepage is: http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "interface.h"
-#include "command.h"
-#include "conf.h"
-#include "log.h"
-#include "listen.h"
-#include "permission.h"
-#include "sllist.h"
-#include "utils.h"
-#include "ioops.h"
-#include "myfprintf.h"
-#include "os_compat.h"
-#include "main_notify.h"
-
-#include "../config.h"
-
-#define GREETING "OK MPD " PROTOCOL_VERSION "\n"
-
-#define INTERFACE_MAX_BUFFER_LENGTH (40960)
-#define INTERFACE_LIST_MODE_BEGIN "command_list_begin"
-#define INTERFACE_LIST_OK_MODE_BEGIN "command_list_ok_begin"
-#define INTERFACE_LIST_MODE_END "command_list_end"
-#define INTERFACE_DEFAULT_OUT_BUFFER_SIZE (4096)
-#define INTERFACE_TIMEOUT_DEFAULT (60)
-#define INTERFACE_MAX_CONNECTIONS_DEFAULT (10)
-#define INTERFACE_MAX_COMMAND_LIST_DEFAULT (2048*1024)
-#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024)
-
-/* set this to zero to indicate we have no possible interfaces */
-static unsigned int interface_max_connections; /*INTERFACE_MAX_CONNECTIONS_DEFAULT; */
-static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT;
-static size_t interface_max_command_list_size =
- INTERFACE_MAX_COMMAND_LIST_DEFAULT;
-static size_t interface_max_output_buffer_size =
- INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT;
-
-/* maybe make conf option for this, or... 32 might be good enough */
-static long int interface_list_cache_size = 32;
-
-/* shared globally between all interfaces: */
-static struct strnode *list_cache;
-static struct strnode *list_cache_head;
-static struct strnode *list_cache_tail;
-
-typedef struct _Interface {
- char buffer[INTERFACE_MAX_BUFFER_LENGTH];
- size_t bufferLength;
- size_t bufferPos;
- int fd; /* file descriptor */
- int permission;
- time_t lastTime;
- struct strnode *cmd_list; /* for when in list mode */
- struct strnode *cmd_list_tail; /* for when in list mode */
- int cmd_list_OK; /* print OK after each command execution */
- size_t cmd_list_size; /* mem cmd_list consumes */
- int cmd_list_dup; /* has the cmd_list been copied to private space? */
- struct sllnode *deferred_send; /* for output if client is slow */
- size_t deferred_bytes; /* mem deferred_send consumes */
- int expired; /* set whether this interface should be closed on next
- check of old interfaces */
- unsigned int num; /* interface number */
-
- char *send_buf;
- size_t send_buf_used; /* bytes used this instance */
- size_t send_buf_size; /* bytes usable this instance */
- size_t send_buf_alloc; /* bytes actually allocated */
-} Interface;
-
-static Interface *interfaces;
-
-static void flushInterfaceBuffer(Interface * interface);
-
-static void printInterfaceOutBuffer(Interface * interface);
-
-#ifdef SO_SNDBUF
-static size_t get_default_snd_buf_size(Interface * interface)
-{
- int new_size;
- socklen_t sockOptLen = sizeof(int);
-
- if (getsockopt(interface->fd, SOL_SOCKET, SO_SNDBUF,
- (char *)&new_size, &sockOptLen) < 0) {
- DEBUG("problem getting sockets send buffer size\n");
- return INTERFACE_DEFAULT_OUT_BUFFER_SIZE;
- }
- if (new_size > 0)
- return (size_t)new_size;
- DEBUG("sockets send buffer size is not positive\n");
- return INTERFACE_DEFAULT_OUT_BUFFER_SIZE;
-}
-#else /* !SO_SNDBUF */
-static size_t get_default_snd_buf_size(Interface * interface)
-{
- return INTERFACE_DEFAULT_OUT_BUFFER_SIZE;
-}
-#endif /* !SO_SNDBUF */
-
-static void set_send_buf_size(Interface * interface)
-{
- size_t new_size = get_default_snd_buf_size(interface);
- if (interface->send_buf_size != new_size) {
- interface->send_buf_size = new_size;
- /* don't resize to get smaller, only bigger */
- if (interface->send_buf_alloc < new_size) {
- if (interface->send_buf)
- free(interface->send_buf);
- interface->send_buf = xmalloc(new_size);
- interface->send_buf_alloc = new_size;
- }
- }
-}
-
-static void openInterface(Interface * interface, int fd)
-{
- assert(interface->fd < 0);
-
- interface->cmd_list_size = 0;
- interface->cmd_list_dup = 0;
- interface->cmd_list_OK = -1;
- interface->bufferLength = 0;
- interface->bufferPos = 0;
- interface->fd = fd;
- set_nonblocking(fd);
- interface->lastTime = time(NULL);
- interface->cmd_list = NULL;
- interface->cmd_list_tail = NULL;
- interface->deferred_send = NULL;
- interface->expired = 0;
- interface->deferred_bytes = 0;
- interface->send_buf_used = 0;
-
- interface->permission = getDefaultPermissions();
- set_send_buf_size(interface);
-
- xwrite(fd, GREETING, strlen(GREETING));
-}
-
-static void free_cmd_list(struct strnode *list)
-{
- struct strnode *tmp = list;
-
- while (tmp) {
- struct strnode *next = tmp->next;
- if (tmp >= list_cache_head && tmp <= list_cache_tail) {
- /* inside list_cache[] array */
- tmp->data = NULL;
- tmp->next = NULL;
- } else
- free(tmp);
- tmp = next;
- }
-}
-
-static void cmd_list_clone(Interface * interface)
-{
- struct strnode *new = dup_strlist(interface->cmd_list);
- free_cmd_list(interface->cmd_list);
- interface->cmd_list = new;
- interface->cmd_list_dup = 1;
-
- /* new tail */
- while (new && new->next)
- new = new->next;
- interface->cmd_list_tail = new;
-}
-
-static void new_cmd_list_ptr(Interface * interface, char *s, const int size)
-{
- int i;
- struct strnode *new;
-
- if (!interface->cmd_list_dup) {
- for (i = interface_list_cache_size - 1; i >= 0; --i) {
- if (list_cache[i].data)
- continue;
- new = &(list_cache[i]);
- new->data = s;
- /* implied in free_cmd_list() and init: */
- /* last->next->next = NULL; */
- goto out;
- }
- }
-
- /* allocate from the heap */
- new = interface->cmd_list_dup ? new_strnode_dup(s, size)
- : new_strnode(s);
-out:
- if (interface->cmd_list) {
- interface->cmd_list_tail->next = new;
- interface->cmd_list_tail = new;
- } else
- interface->cmd_list = interface->cmd_list_tail = new;
-}
-
-static void closeInterface(Interface * interface)
-{
- struct sllnode *buf;
- if (interface->fd < 0)
- return;
- xclose(interface->fd);
- interface->fd = -1;
-
- if (interface->cmd_list) {
- free_cmd_list(interface->cmd_list);
- interface->cmd_list = NULL;
- }
-
- if ((buf = interface->deferred_send)) {
- do {
- struct sllnode *prev = buf;
- buf = buf->next;
- free(prev);
- } while (buf);
- interface->deferred_send = NULL;
- }
-
- SECURE("interface %i: closed\n", interface->num);
-}
-
-void openAInterface(int fd, const struct sockaddr *addr)
-{
- unsigned int i;
-
- for (i = 0; i < interface_max_connections
- && interfaces[i].fd >= 0; i++) /* nothing */ ;
-
- if (i == interface_max_connections) {
- ERROR("Max Connections Reached!\n");
- xclose(fd);
- } else {
- const char *hostname;
- switch (addr->sa_family) {
-#ifdef HAVE_TCP
- case AF_INET:
- hostname = (const char *)inet_ntoa(((const struct sockaddr_in *)
- addr)->sin_addr);
- if (!hostname)
- hostname = "error getting ipv4 address";
- break;
-#ifdef HAVE_IPV6
- case AF_INET6:
- {
- static char host[INET6_ADDRSTRLEN + 1];
- memset(host, 0, INET6_ADDRSTRLEN + 1);
- if (inet_ntop(AF_INET6, (const void *)
- &(((const struct sockaddr_in6 *)addr)->
- sin6_addr), host,
- INET6_ADDRSTRLEN)) {
- hostname = (const char *)host;
- } else {
- hostname = "error getting ipv6 address";
- }
- }
- break;
-#endif
-#endif /* HAVE_TCP */
-#ifdef HAVE_UN
- case AF_UNIX:
- hostname = "local connection";
- break;
-#endif /* HAVE_UN */
- default:
- hostname = "unknown";
- }
- SECURE("interface %i: opened from %s\n", i, hostname);
- openInterface(&(interfaces[i]), fd);
- }
-}
-
-static int processLineOfInput(Interface * interface)
-{
- int ret = 1;
- char *line = interface->buffer + interface->bufferPos;
-
- if (interface->cmd_list_OK >= 0) {
- if (strcmp(line, INTERFACE_LIST_MODE_END) == 0) {
- DEBUG("interface %i: process command "
- "list\n", interface->num);
- ret = processListOfCommands(interface->fd,
- &(interface->permission),
- &(interface->expired),
- interface->cmd_list_OK,
- interface->cmd_list);
- DEBUG("interface %i: process command "
- "list returned %i\n", interface->num, ret);
- if (ret == 0)
- commandSuccess(interface->fd);
- else if (ret == COMMAND_RETURN_CLOSE
- || interface->expired)
- closeInterface(interface);
-
- printInterfaceOutBuffer(interface);
- free_cmd_list(interface->cmd_list);
- interface->cmd_list = NULL;
- interface->cmd_list_OK = -1;
- } else {
- size_t len = strlen(line) + 1;
- interface->cmd_list_size += len;
- if (interface->cmd_list_size >
- interface_max_command_list_size) {
- ERROR("interface %i: command "
- "list size (%lu) is "
- "larger than the max "
- "(%lu)\n",
- interface->num,
- (unsigned long)interface->cmd_list_size,
- (unsigned long)
- interface_max_command_list_size);
- closeInterface(interface);
- ret = COMMAND_RETURN_CLOSE;
- } else
- new_cmd_list_ptr(interface, line, len);
- }
- } else {
- if (strcmp(line, INTERFACE_LIST_MODE_BEGIN) == 0) {
- interface->cmd_list_OK = 0;
- ret = 1;
- } else if (strcmp(line, INTERFACE_LIST_OK_MODE_BEGIN) == 0) {
- interface->cmd_list_OK = 1;
- ret = 1;
- } else {
- DEBUG("interface %i: process command \"%s\"\n",
- interface->num, line);
- ret = processCommand(interface->fd,
- &(interface->permission), line);
- DEBUG("interface %i: command returned %i\n",
- interface->num, ret);
- if (ret == 0)
- commandSuccess(interface->fd);
- else if (ret == COMMAND_RETURN_CLOSE
- || interface->expired) {
- closeInterface(interface);
- }
- printInterfaceOutBuffer(interface);
- }
- }
-
- return ret;
-}
-
-static int processBytesRead(Interface * interface, int bytesRead)
-{
- int ret = 0;
- char *buf_tail = &(interface->buffer[interface->bufferLength - 1]);
-
- while (bytesRead > 0) {
- interface->bufferLength++;
- bytesRead--;
- buf_tail++;
- if (*buf_tail == '\n') {
- *buf_tail = '\0';
- if (interface->bufferLength > interface->bufferPos) {
- if (*(buf_tail - 1) == '\r')
- *(buf_tail - 1) = '\0';
- }
- ret = processLineOfInput(interface);
- if (interface->expired)
- return ret;
- interface->bufferPos = interface->bufferLength;
- }
- if (interface->bufferLength == INTERFACE_MAX_BUFFER_LENGTH) {
- if (interface->bufferPos == 0) {
- ERROR("interface %i: buffer overflow\n",
- interface->num);
- closeInterface(interface);
- return 1;
- }
- if (interface->cmd_list_OK >= 0 &&
- interface->cmd_list &&
- !interface->cmd_list_dup)
- cmd_list_clone(interface);
- assert(interface->bufferLength >= interface->bufferPos
- && "bufferLength >= bufferPos");
- interface->bufferLength -= interface->bufferPos;
- memmove(interface->buffer,
- interface->buffer + interface->bufferPos,
- interface->bufferLength);
- interface->bufferPos = 0;
- }
- if (ret == COMMAND_RETURN_KILL || ret == COMMAND_RETURN_CLOSE) {
- return ret;
- }
-
- }
-
- return ret;
-}
-
-static int interfaceReadInput(Interface * interface)
-{
- int bytesRead;
-
- bytesRead = read(interface->fd,
- interface->buffer + interface->bufferLength,
- INTERFACE_MAX_BUFFER_LENGTH - interface->bufferLength);
-
- if (bytesRead > 0)
- return processBytesRead(interface, bytesRead);
- else if (bytesRead == 0 || (bytesRead < 0 && errno != EINTR)) {
- closeInterface(interface);
- } else
- return 0;
-
- return 1;
-}
-
-static void addInterfacesReadyToReadAndListenSocketToFdSet(fd_set * fds,
- int *fdmax)
-{
- unsigned int i;
-
- FD_ZERO(fds);
- addListenSocketsToFdSet(fds, fdmax);
-
- for (i = 0; i < interface_max_connections; i++) {
- if (interfaces[i].fd >= 0 && !interfaces[i].expired
- && !interfaces[i].deferred_send) {
- FD_SET(interfaces[i].fd, fds);
- if (*fdmax < interfaces[i].fd)
- *fdmax = interfaces[i].fd;
- }
- }
-}
-
-static void addInterfacesForBufferFlushToFdSet(fd_set * fds, int *fdmax)
-{
- unsigned int i;
-
- FD_ZERO(fds);
-
- for (i = 0; i < interface_max_connections; i++) {
- if (interfaces[i].fd >= 0 && !interfaces[i].expired
- && interfaces[i].deferred_send) {
- FD_SET(interfaces[i].fd, fds);
- if (*fdmax < interfaces[i].fd)
- *fdmax = interfaces[i].fd;
- }
- }
-}
-
-static void closeNextErroredInterface(void)
-{
- fd_set fds;
- struct timeval tv;
- unsigned int i;
-
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
- for (i = 0; i < interface_max_connections; i++) {
- if (interfaces[i].fd >= 0) {
- FD_ZERO(&fds);
- FD_SET(interfaces[i].fd, &fds);
- if (select(interfaces[i].fd + 1,
- &fds, NULL, NULL, &tv) < 0) {
- closeInterface(&interfaces[i]);
- return;
- }
- }
- }
-}
-
-int doIOForInterfaces(void)
-{
- fd_set rfds;
- fd_set wfds;
- fd_set efds;
- unsigned int i;
- int selret;
- int fdmax;
-
- while (1) {
- fdmax = 0;
-
- FD_ZERO( &efds );
- addInterfacesReadyToReadAndListenSocketToFdSet(&rfds, &fdmax);
- addInterfacesForBufferFlushToFdSet(&wfds, &fdmax);
-
- registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds);
-
- selret = select(fdmax + 1, &rfds, &wfds, &efds, NULL);
- if (selret < 0 && errno == EINTR)
- break;
-
- registered_IO_consume_fds(&selret, &rfds, &wfds, &efds);
-
- if (selret == 0)
- break;
-
- if (selret < 0) {
- closeNextErroredInterface();
- continue;
- }
-
- getConnections(&rfds);
-
- for (i = 0; i < interface_max_connections; i++) {
- if (interfaces[i].fd >= 0
- && FD_ISSET(interfaces[i].fd, &rfds)) {
- if (COMMAND_RETURN_KILL ==
- interfaceReadInput(&(interfaces[i]))) {
- return COMMAND_RETURN_KILL;
- }
- interfaces[i].lastTime = time(NULL);
- }
- if (interfaces[i].fd >= 0
- && FD_ISSET(interfaces[i].fd, &wfds)) {
- flushInterfaceBuffer(&interfaces[i]);
- interfaces[i].lastTime = time(NULL);
- }
- }
-
- break;
- }
-
- return 1;
-}
-
-void initInterfaces(void)
-{
- unsigned int i;
- char *test;
- ConfigParam *param;
-
- param = getConfigParam(CONF_CONN_TIMEOUT);
-
- if (param) {
- interface_timeout = strtol(param->value, &test, 10);
- if (*test != '\0' || interface_timeout <= 0) {
- FATAL("connection timeout \"%s\" is not a positive "
- "integer, line %i\n", CONF_CONN_TIMEOUT,
- param->line);
- }
- }
-
- param = getConfigParam(CONF_MAX_CONN);
-
- if (param) {
- interface_max_connections = strtol(param->value, &test, 10);
- if (*test != '\0' || interface_max_connections <= 0) {
- FATAL("max connections \"%s\" is not a positive integer"
- ", line %i\n", param->value, param->line);
- }
- } else
- interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT;
-
- param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE);
-
- if (param) {
- long tmp = strtol(param->value, &test, 10);
- if (*test != '\0' || tmp <= 0) {
- FATAL("max command list size \"%s\" is not a positive "
- "integer, line %i\n", param->value, param->line);
- }
- interface_max_command_list_size = tmp * 1024;
- }
-
- param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE);
-
- if (param) {
- long tmp = strtol(param->value, &test, 10);
- if (*test != '\0' || tmp <= 0) {
- FATAL("max output buffer size \"%s\" is not a positive "
- "integer, line %i\n", param->value, param->line);
- }
- interface_max_output_buffer_size = tmp * 1024;
- }
-
- interfaces = xmalloc(sizeof(Interface) * interface_max_connections);
-
- list_cache = xcalloc(interface_list_cache_size, sizeof(struct strnode));
- list_cache_head = &(list_cache[0]);
- list_cache_tail = &(list_cache[interface_list_cache_size - 1]);
-
- for (i = 0; i < interface_max_connections; i++) {
- interfaces[i].fd = -1;
- interfaces[i].send_buf = NULL;
- interfaces[i].send_buf_size = 0;
- interfaces[i].send_buf_alloc = 0;
- interfaces[i].num = i;
- }
-}
-
-static void closeAllInterfaces(void)
-{
- unsigned int i;
-
- for (i = 0; i < interface_max_connections; i++) {
- if (interfaces[i].fd >= 0)
- closeInterface(&(interfaces[i]));
- if (interfaces[i].send_buf)
- free(interfaces[i].send_buf);
- }
- free(list_cache);
-}
-
-void freeAllInterfaces(void)
-{
- closeAllInterfaces();
-
- free(interfaces);
-
- interface_max_connections = 0;
-}
-
-void closeOldInterfaces(void)
-{
- unsigned int i;
-
- for (i = 0; i < interface_max_connections; i++) {
- if (interfaces[i].fd >= 0) {
- if (interfaces[i].expired) {
- DEBUG("interface %i: expired\n", i);
- closeInterface(&(interfaces[i]));
- } else if (time(NULL) - interfaces[i].lastTime >
- interface_timeout) {
- DEBUG("interface %i: timeout\n", i);
- closeInterface(&(interfaces[i]));
- }
- }
- }
-}
-
-static void flushInterfaceBuffer(Interface * interface)
-{
- struct sllnode *buf;
- ssize_t ret = 0;
-
- buf = interface->deferred_send;
- while (buf) {
- ret = write(interface->fd, buf->data, buf->size);
- if (ret < 0)
- break;
- else if ((size_t)ret < buf->size) {
- assert(interface->deferred_bytes >= (size_t)ret);
- interface->deferred_bytes -= ret;
- buf->data = (char *)buf->data + ret;
- buf->size -= ret;
- } else {
- struct sllnode *tmp = buf;
- size_t decr = (buf->size + sizeof(struct sllnode));
-
- assert(interface->deferred_bytes >= decr);
- interface->deferred_bytes -= decr;
- buf = buf->next;
- free(tmp);
- interface->deferred_send = buf;
- }
- interface->lastTime = time(NULL);
- }
-
- if (!interface->deferred_send) {
- DEBUG("interface %i: buffer empty %lu\n", interface->num,
- (unsigned long)interface->deferred_bytes);
- assert(interface->deferred_bytes == 0);
- } else if (ret < 0 && errno != EAGAIN && errno != EINTR) {
- /* cause interface to close */
- DEBUG("interface %i: problems flushing buffer\n",
- interface->num);
- buf = interface->deferred_send;
- do {
- struct sllnode *prev = buf;
- buf = buf->next;
- free(prev);
- } while (buf);
- interface->deferred_send = NULL;
- interface->deferred_bytes = 0;
- interface->expired = 1;
- }
-}
-
-int interfacePrintWithFD(int fd, const char *buffer, size_t buflen)
-{
- static unsigned int i;
- size_t copylen;
- Interface *interface;
-
- assert(fd >= 0);
-
- if (i >= interface_max_connections ||
- interfaces[i].fd < 0 || interfaces[i].fd != fd) {
- for (i = 0; i < interface_max_connections; i++) {
- if (interfaces[i].fd == fd)
- break;
- }
- if (i == interface_max_connections)
- return -1;
- }
-
- /* if fd isn't found or interfaces is going to be closed, do nothing */
- if (interfaces[i].expired)
- return 0;
-
- interface = interfaces + i;
-
- while (buflen > 0 && !interface->expired) {
- size_t left;
-
- assert(interface->send_buf_size >= interface->send_buf_used);
- left = interface->send_buf_size - interface->send_buf_used;
-
- copylen = buflen > left ? left : buflen;
- memcpy(interface->send_buf + interface->send_buf_used, buffer,
- copylen);
- buflen -= copylen;
- interface->send_buf_used += copylen;
- buffer += copylen;
- if (interface->send_buf_used >= interface->send_buf_size)
- printInterfaceOutBuffer(interface);
- }
-
- return 0;
-}
-
-static void printInterfaceOutBuffer(Interface * interface)
-{
- ssize_t ret;
- struct sllnode *buf;
-
- if (interface->fd < 0 || interface->expired ||
- !interface->send_buf_used)
- return;
-
- if ((buf = interface->deferred_send)) {
- interface->deferred_bytes += sizeof(struct sllnode)
- + interface->send_buf_used;
- if (interface->deferred_bytes >
- interface_max_output_buffer_size) {
- ERROR("interface %i: output buffer size (%lu) is "
- "larger than the max (%lu)\n",
- interface->num,
- (unsigned long)interface->deferred_bytes,
- (unsigned long)interface_max_output_buffer_size);
- /* cause interface to close */
- interface->expired = 1;
- do {
- struct sllnode *prev = buf;
- buf = buf->next;
- free(prev);
- } while (buf);
- interface->deferred_send = NULL;
- interface->deferred_bytes = 0;
- } else {
- while (buf->next)
- buf = buf->next;
- buf->next = new_sllnode(interface->send_buf,
- interface->send_buf_used);
- }
- } else {
- if ((ret = write(interface->fd, interface->send_buf,
- interface->send_buf_used)) < 0) {
- if (errno == EAGAIN || errno == EINTR) {
- interface->deferred_send =
- new_sllnode(interface->send_buf,
- interface->send_buf_used);
- } else {
- DEBUG("interface %i: problems writing\n",
- interface->num);
- interface->expired = 1;
- return;
- }
- } else if ((size_t)ret < interface->send_buf_used) {
- interface->deferred_send =
- new_sllnode(interface->send_buf + ret,
- interface->send_buf_used - ret);
- }
- if (interface->deferred_send) {
- DEBUG("interface %i: buffer created\n", interface->num);
- interface->deferred_bytes =
- interface->deferred_send->size
- + sizeof(struct sllnode);
- }
- }
-
- interface->send_buf_used = 0;
-}
-
diff --git a/src/listen.c b/src/listen.c
index 2b9b38619..c40035279 100644
--- a/src/listen.c
+++ b/src/listen.c
@@ -17,7 +17,7 @@
*/
#include "listen.h"
-#include "interface.h"
+#include "client.h"
#include "conf.h"
#include "log.h"
#include "utils.h"
@@ -297,7 +297,7 @@ void getConnections(fd_set * fds)
if (FD_ISSET(listenSockets[i], fds)) {
if ((fd = accept(listenSockets[i], &sockAddr, &socklen))
>= 0) {
- openAInterface(fd, &sockAddr);
+ client_new(fd, &sockAddr);
} else if (fd < 0
&& (errno != EAGAIN && errno != EINTR)) {
ERROR("Problems accept()'ing\n");
diff --git a/src/main.c b/src/main.c
index 236b3bbe1..a5941b848 100644
--- a/src/main.c
+++ b/src/main.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "interface.h"
+#include "client.h"
#include "command.h"
#include "playlist.h"
#include "directory.h"
@@ -415,7 +415,7 @@ int main(int argc, char *argv[])
initAudioConfig();
initAudioDriver();
initVolume();
- initInterfaces();
+ client_manager_init();
initReplayGainState();
initNormalization();
initInputStream();
@@ -435,17 +435,17 @@ int main(int argc, char *argv[])
decoder_init();
read_state_file();
- while (COMMAND_RETURN_KILL != doIOForInterfaces() &&
+ while (COMMAND_RETURN_KILL != client_manager_io() &&
COMMAND_RETURN_KILL != handlePendingSignals()) {
syncPlayerAndPlaylist();
- closeOldInterfaces();
+ client_manager_expire();
readDirectoryDBIfUpdateIsFinished();
}
write_state_file();
ob_trigger_action(OB_ACTION_PAUSE_SET);
finishZeroconf();
- freeAllInterfaces();
+ client_manager_deinit();
closeAllListenSockets();
finishPlaylist();
diff --git a/src/myfprintf.c b/src/myfprintf.c
index 7e4f4678d..200c80334 100644
--- a/src/myfprintf.c
+++ b/src/myfprintf.c
@@ -17,7 +17,7 @@
*/
#include "myfprintf.h"
-#include "interface.h"
+#include "client.h"
#include "path.h"
#include "utils.h"
#include "os_compat.h"
@@ -49,7 +49,7 @@ void vfdprintf(const int fd, const char *fmt, va_list args)
len = strlen(buf);
if (fd == STDERR_FILENO ||
fd == STDOUT_FILENO ||
- interfacePrintWithFD(fd, buf, len) < 0)
+ client_print(fd, buf, len) < 0)
blockingWrite(fd, buf, len);
}
diff --git a/src/pcm_utils.c b/src/pcm_utils.c
index f716c279d..90856fa1d 100644
--- a/src/pcm_utils.c
+++ b/src/pcm_utils.c
@@ -149,6 +149,7 @@ static int pcm_getSampleRateConverter(void)
const char *conf = getConfigParamValue(CONF_SAMPLERATE_CONVERTER);
long convalgo;
char *test;
+ const char *test2;
size_t len;
if (!conf) {
@@ -162,12 +163,12 @@ static int pcm_getSampleRateConverter(void)
len = strlen(conf);
for (convalgo = 0 ; ; convalgo++) {
- test = (char *)src_get_name(convalgo);
- if (!test) {
+ test2 = src_get_name(convalgo);
+ if (!test2) {
convalgo = SRC_SINC_FASTEST;
break;
}
- if (strncasecmp(test, conf, len) == 0)
+ if (strncasecmp(test2, conf, len) == 0)
goto out;
}
@@ -239,7 +240,7 @@ static size_t pcm_convertSampleRate(mpd_sint8 channels, mpd_uint32 inSampleRate,
data->data_out = xrealloc(data->data_out, dataOutSize);
}
- src_short_to_float_array((short *)inBuffer, data->data_in,
+ src_short_to_float_array((const short *)inBuffer, data->data_in,
data->input_frames * channels);
error = src_process(convState->state, data);
@@ -305,7 +306,7 @@ static char *pcm_convertChannels(mpd_sint8 channels, const char *inBuffer,
static char *buf;
static size_t len;
char *outBuffer = NULL;
- mpd_sint16 *in;
+ const mpd_sint16 *in;
mpd_sint16 *out;
int inSamples, i;
@@ -320,7 +321,7 @@ static char *pcm_convertChannels(mpd_sint8 channels, const char *inBuffer,
outBuffer = buf;
inSamples = inSize >> 1;
- in = (mpd_sint16 *)inBuffer;
+ in = (const mpd_sint16 *)inBuffer;
out = (mpd_sint16 *)outBuffer;
for (i = 0; i < inSamples; i++) {
*out++ = *in;
@@ -338,7 +339,7 @@ static char *pcm_convertChannels(mpd_sint8 channels, const char *inBuffer,
outBuffer = buf;
inSamples = inSize >> 2;
- in = (mpd_sint16 *)inBuffer;
+ in = (const mpd_sint16 *)inBuffer;
out = (mpd_sint16 *)outBuffer;
for (i = 0; i < inSamples; i++) {
*out = (*in++) / 2;
@@ -359,7 +360,7 @@ static const char *pcm_convertTo16bit(mpd_sint8 bits, const char *inBuffer,
static char *buf;
static size_t len;
char *outBuffer = NULL;
- mpd_sint8 *in;
+ const mpd_sint8 *in;
mpd_sint16 *out;
size_t i;
@@ -372,7 +373,7 @@ static const char *pcm_convertTo16bit(mpd_sint8 bits, const char *inBuffer,
}
outBuffer = buf;
- in = (mpd_sint8 *)inBuffer;
+ in = (const mpd_sint8 *)inBuffer;
out = (mpd_sint16 *)outBuffer;
for (i = 0; i < inSize; i++)
*out++ = (*in++) << 8;
diff --git a/src/playlist.c b/src/playlist.c
index 89b4fdd99..ca79393b0 100644
--- a/src/playlist.c
+++ b/src/playlist.c
@@ -238,12 +238,12 @@ void clearPlaylist(void)
incrPlaylistVersion();
}
-int clearStoredPlaylist(int fd, char *utf8file)
+int clearStoredPlaylist(const char *utf8file)
{
- return removeAllFromStoredPlaylistByPath(fd, utf8file);
+ return removeAllFromStoredPlaylistByPath(utf8file);
}
-int showPlaylist(int fd)
+void showPlaylist(int fd)
{
int i;
char path_max_tmp[MPD_PATH_MAX];
@@ -252,8 +252,6 @@ int showPlaylist(int fd)
fdprintf(fd, "%i:%s\n", i,
get_song_url(path_max_tmp, playlist.songs[i]));
}
-
- return 0;
}
void savePlaylistState(FILE *fp)
@@ -303,13 +301,12 @@ static void loadPlaylistFromStateFile(FILE *fp, char *buffer,
song = atoi(temp);
if (!(temp = strtok(NULL, "")))
state_file_fatal();
- if (!addToPlaylist(STDERR_FILENO, temp, NULL)
+ if (addToPlaylist(temp, NULL) == PLAYLIST_RESULT_SUCCESS
&& current == song) {
if (state == OB_STATE_PAUSE)
ob_trigger_action(OB_ACTION_PAUSE_SET);
if (state != OB_STATE_STOP) {
- seekSongInPlaylist(STDERR_FILENO,
- playlist.length - 1,
+ seekSongInPlaylist(playlist.length - 1,
seek_time);
}
}
@@ -349,9 +346,9 @@ void readPlaylistState(FILE *fp)
if (strcmp
(&(buffer[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
"1") == 0) {
- setPlaylistRepeatStatus(STDERR_FILENO, 1);
+ setPlaylistRepeatStatus(1);
} else
- setPlaylistRepeatStatus(STDERR_FILENO, 0);
+ setPlaylistRepeatStatus(0);
} else
if (strncmp
(buffer, PLAYLIST_STATE_FILE_CROSSFADE,
@@ -368,9 +365,9 @@ void readPlaylistState(FILE *fp)
(buffer
[strlen(PLAYLIST_STATE_FILE_RANDOM)]),
"1") == 0) {
- setPlaylistRandomStatus(STDERR_FILENO, 1);
+ setPlaylistRandomStatus(1);
} else
- setPlaylistRandomStatus(STDERR_FILENO, 0);
+ setPlaylistRandomStatus(0);
} else if (strncmp(buffer, PLAYLIST_STATE_FILE_CURRENT,
strlen(PLAYLIST_STATE_FILE_CURRENT))
== 0) {
@@ -430,7 +427,7 @@ int playlistChangesPosId(int fd, mpd_uint32 version)
return 0;
}
-int playlistInfo(int fd, int song)
+enum playlist_result playlistInfo(int fd, int song)
{
int i;
int begin = 0;
@@ -440,36 +437,31 @@ int playlistInfo(int fd, int song)
begin = song;
end = song + 1;
}
- if (song >= playlist.length) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "song doesn't exist: \"%i\"", song);
- return -1;
- }
+ if (song >= playlist.length)
+ return PLAYLIST_RESULT_BAD_RANGE;
for (i = begin; i < end; i++)
printPlaylistSongInfo(fd, i);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-# define checkSongId(id) { \
- if(id < 0 || id >= PLAYLIST_HASH_MULT*playlist_max_length || \
- playlist.idToPosition[id] == -1 ) \
- { \
- commandError(fd, ACK_ERROR_NO_EXIST, \
- "song id doesn't exist: \"%i\"", id); \
- return -1; \
- } \
+static int song_id_exists(int id)
+{
+ return id >= 0 && id < PLAYLIST_HASH_MULT*playlist_max_length &&
+ playlist.idToPosition[id] != -1;
}
-int playlistId(int fd, int id)
+enum playlist_result playlistId(int fd, int id)
{
int i;
int begin = 0;
int end = playlist.length;
if (id >= 0) {
- checkSongId(id);
+ if (!song_id_exists(id))
+ return PLAYLIST_RESULT_NO_SUCH_SONG;
+
begin = playlist.idToPosition[id];
end = begin + 1;
}
@@ -477,7 +469,7 @@ int playlistId(int fd, int id)
for (i = begin; i < end; i++)
printPlaylistSongInfo(fd, i);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
static void swapSongs(int song1, int song2)
@@ -597,7 +589,7 @@ static int clear_queue(void)
return playlist.queued;
}
-int addToPlaylist(int fd, char *url, int *added_id)
+enum playlist_result addToPlaylist(const char *url, int *added_id)
{
Song *song;
@@ -606,52 +598,41 @@ int addToPlaylist(int fd, char *url, int *added_id)
if ((song = getSongFromDB(url))) {
} else if (!(isValidRemoteUtf8Url(url) &&
(song = newSong(url, SONG_TYPE_URL, NULL)))) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "\"%s\" is not in the music db or is "
- "not a valid url", url);
- return -1;
+ return PLAYLIST_RESULT_NO_SUCH_SONG;
}
- return addSongToPlaylist(fd, song, added_id);
+ return addSongToPlaylist(song, added_id);
}
-int addToStoredPlaylist(int fd, char *url, char *utf8file)
+int addToStoredPlaylist(const char *url, const char *utf8file)
{
Song *song;
DEBUG("add to stored playlist: %s\n", url);
song = getSongFromDB(url);
- if (song) {
- appendSongToStoredPlaylistByPath(fd, utf8file, song);
- return 0;
- }
+ if (song)
+ return appendSongToStoredPlaylistByPath(utf8file, song);
if (!isValidRemoteUtf8Url(url))
- goto fail;
+ return ACK_ERROR_NO_EXIST;
song = newSong(url, SONG_TYPE_URL, NULL);
if (song) {
- appendSongToStoredPlaylistByPath(fd, utf8file, song);
+ int ret = appendSongToStoredPlaylistByPath(utf8file, song);
freeJustSong(song);
- return 0;
+ return ret;
}
-fail:
- commandError(fd, ACK_ERROR_NO_EXIST, "\"%s\" is not in the music db"
- "or is not a valid url", url);
- return -1;
+ return ACK_ERROR_NO_EXIST;
}
-int addSongToPlaylist(int fd, Song * song, int *added_id)
+enum playlist_result addSongToPlaylist(Song * song, int *added_id)
{
int id;
- if (playlist.length == playlist_max_length) {
- commandError(fd, ACK_ERROR_PLAYLIST_MAX,
- "playlist is at the max size");
- return -1;
- }
+ if (playlist.length == playlist_max_length)
+ return PLAYLIST_RESULT_TOO_LARGE;
if (playlist_state == PLAYLIST_STATE_PLAY) {
if (playlist.queued >= 0
@@ -694,24 +675,17 @@ int addSongToPlaylist(int fd, Song * song, int *added_id)
if (added_id)
*added_id = id;
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-int swapSongsInPlaylist(int fd, int song1, int song2)
+enum playlist_result swapSongsInPlaylist(int song1, int song2)
{
int queuedSong = -1;
int currentSong;
- if (song1 < 0 || song1 >= playlist.length) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "song doesn't exist: \"%i\"", song1);
- return -1;
- }
- if (song2 < 0 || song2 >= playlist.length) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "song doesn't exist: \"%i\"", song2);
- return -1;
- }
+ if (song1 < 0 || song1 >= playlist.length ||
+ song2 < 0 || song2 >= playlist.length)
+ return PLAYLIST_RESULT_BAD_RANGE;
if (playlist_state == PLAYLIST_STATE_PLAY) {
if (playlist.queued >= 0) {
@@ -749,15 +723,15 @@ int swapSongsInPlaylist(int fd, int song1, int song2)
incrPlaylistVersion();
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-int swapSongsInPlaylistById(int fd, int id1, int id2)
+enum playlist_result swapSongsInPlaylistById(int id1, int id2)
{
- checkSongId(id1);
- checkSongId(id2);
+ if (!song_id_exists(id1) || !song_id_exists(id2))
+ return PLAYLIST_RESULT_NO_SUCH_SONG;
- return swapSongsInPlaylist(fd, playlist.idToPosition[id1],
+ return swapSongsInPlaylist(playlist.idToPosition[id1],
playlist.idToPosition[id2]);
}
@@ -768,18 +742,15 @@ int swapSongsInPlaylistById(int fd, int id1, int id2)
playlist.songMod[to] = playlist.version; \
}
-int deleteFromPlaylist(int fd, int song)
+enum playlist_result deleteFromPlaylist(int song)
{
int i;
int songOrder;
int stop_current = 0;
int prev_queued = playlist.queued;
- if (song < 0 || song >= playlist.length) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "song doesn't exist: \"%i\"", song);
- return -1;
- }
+ if (song < 0 || song >= playlist.length)
+ return PLAYLIST_RESULT_BAD_RANGE;
if (playlist_state == PLAYLIST_STATE_PLAY) {
if (prev_queued >= 0
@@ -844,14 +815,15 @@ int deleteFromPlaylist(int fd, int song)
queueNextSongInPlaylist();
}
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-int deleteFromPlaylistById(int fd, int id)
+enum playlist_result deleteFromPlaylistById(int id)
{
- checkSongId(id);
+ if (!song_id_exists(id))
+ return PLAYLIST_RESULT_NO_SUCH_SONG;
- return deleteFromPlaylist(fd, playlist.idToPosition[id]);
+ return deleteFromPlaylist(playlist.idToPosition[id]);
}
void deleteASongFromPlaylist(Song * song)
@@ -863,7 +835,7 @@ void deleteASongFromPlaylist(Song * song)
for (i = 0; i < playlist.length; i++) {
if (song == playlist.songs[i]) {
- deleteFromPlaylist(STDERR_FILENO, i);
+ deleteFromPlaylist(i);
}
}
}
@@ -909,7 +881,7 @@ static void play_order_num(int order_num, float seek_time)
playlist.current = order_num;
}
-int playPlaylist(int fd, int song, int stopOnError)
+enum playlist_result playPlaylist(int song, int stopOnError)
{
int i = song;
@@ -919,11 +891,11 @@ int playPlaylist(int fd, int song, int stopOnError)
if (song == -1) {
if (playlist.length == 0)
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
if (playlist_state == PLAYLIST_STATE_PLAY) {
ob_trigger_action(OB_ACTION_PAUSE_UNSET);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
if (playlist.current >= 0 && playlist.current < playlist.length) {
i = playlist.current;
@@ -931,9 +903,7 @@ int playPlaylist(int fd, int song, int stopOnError)
i = 0;
}
} else if (song < 0 || song >= playlist.length) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "song doesn't exist: \"%i\"", song);
- return -1;
+ return PLAYLIST_RESULT_BAD_RANGE;
}
if (playlist.random) {
@@ -955,18 +925,19 @@ int playPlaylist(int fd, int song, int stopOnError)
ERROR(__FILE__ ": %d current:%d\n", __LINE__, playlist.current);
ob_trigger_action(OB_ACTION_PAUSE_UNSET);
play_order_num(i, 0);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-int playPlaylistById(int fd, int id, int stopOnError)
+enum playlist_result playPlaylistById(int id, int stopOnError)
{
if (id == -1) {
- return playPlaylist(fd, id, stopOnError);
+ return playPlaylist(id, stopOnError);
}
- checkSongId(id);
+ if (!song_id_exists(id))
+ return PLAYLIST_RESULT_NO_SUCH_SONG;
- return playPlaylist(fd, playlist.idToPosition[id], stopOnError);
+ return playPlaylist(playlist.idToPosition[id], stopOnError);
}
/* This is used when we stream data out to shout while playing static files */
@@ -1043,24 +1014,17 @@ int getPlaylistRandomStatus(void)
return playlist.random;
}
-int setPlaylistRepeatStatus(int fd, int status)
+void setPlaylistRepeatStatus(int status)
{
- if (status != 0 && status != 1) {
- commandError(fd, ACK_ERROR_ARG, "\"%i\" is not 0 or 1", status);
- return -1;
- }
-
if (playlist_state == PLAYLIST_STATE_PLAY) {
if (playlist.repeat && !status && playlist.queued == 0)
clear_queue();
}
playlist.repeat = status;
-
- return 0;
}
-int moveSongInPlaylist(int fd, int from, int to)
+enum playlist_result moveSongInPlaylist(int from, int to)
{
int i;
Song *tmpSong;
@@ -1068,21 +1032,15 @@ int moveSongInPlaylist(int fd, int from, int to)
int currentSong;
int queued_is_current = (playlist.queued == playlist.current);
- if (from < 0 || from >= playlist.length) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "song doesn't exist: \"%i\"", from);
- return -1;
- }
+ if (from < 0 || from >= playlist.length)
+ return PLAYLIST_RESULT_BAD_RANGE;
if ((to >= 0 && to >= playlist.length) ||
- (to < 0 && abs(to) > playlist.length)) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "song doesn't exist: \"%i\"", to);
- return -1;
- }
+ (to < 0 && abs(to) > playlist.length))
+ return PLAYLIST_RESULT_BAD_RANGE;
if (from == to) /* no-op */
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
/*
* (to < 0) => move to offset from current song
@@ -1092,7 +1050,7 @@ int moveSongInPlaylist(int fd, int from, int to)
if (to < 0 && playlist.current >= 0) {
if (currentSong == from)
/* no-op, can't be moved to offset of itself */
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
to = (currentSong + abs(to)) % playlist.length;
}
@@ -1147,14 +1105,15 @@ int moveSongInPlaylist(int fd, int from, int to)
queueNextSongInPlaylist();
incrPlaylistVersion();
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-int moveSongInPlaylistById(int fd, int id1, int to)
+enum playlist_result moveSongInPlaylistById(int id1, int to)
{
- checkSongId(id1);
+ if (!song_id_exists(id1))
+ return PLAYLIST_RESULT_NO_SUCH_SONG;
- return moveSongInPlaylist(fd, playlist.idToPosition[id1], to);
+ return moveSongInPlaylist(playlist.idToPosition[id1], to);
}
static void orderPlaylist(void)
@@ -1217,15 +1176,10 @@ static void randomizeOrder(int start, int end)
DEBUG("%s:%d current: %d\n", __func__, __LINE__, playlist.current);
}
-int setPlaylistRandomStatus(int fd, int status)
+void setPlaylistRandomStatus(int status)
{
int statusWas = playlist.random;
- if (status != 0 && status != 1) {
- commandError(fd, ACK_ERROR_ARG, "\"%i\" is not 0 or 1", status);
- return -1;
- }
-
playlist.random = status;
if (status != statusWas) {
@@ -1239,8 +1193,6 @@ int setPlaylistRandomStatus(int fd, int status)
__func__,__LINE__,playlist.queued);
}
}
-
- return 0;
}
void previousSongInPlaylist(void)
@@ -1270,7 +1222,7 @@ void previousSongInPlaylist(void)
play_order_num(prev_order_num, 0);
}
-int shufflePlaylist(mpd_unused int fd)
+void shufflePlaylist(void)
{
int i;
int ri;
@@ -1307,54 +1259,41 @@ int shufflePlaylist(mpd_unused int fd)
if (playlist_state == PLAYLIST_STATE_PLAY)
queueNextSongInPlaylist();
}
-
- return 0;
}
-int deletePlaylist(int fd, char *utf8file)
+enum playlist_result deletePlaylist(const char *utf8file)
{
char path_max_tmp[MPD_PATH_MAX];
utf8_to_fs_playlist_path(path_max_tmp, utf8file);
- if (!isPlaylist(path_max_tmp)) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "playlist \"%s\" not found", utf8file);
- return -1;
- }
+ if (!isPlaylist(path_max_tmp))
+ return PLAYLIST_RESULT_NO_SUCH_LIST;
- if (unlink(path_max_tmp) < 0) {
- commandError(fd, ACK_ERROR_SYSTEM,
- "problems deleting file");
- return -1;
- }
+ if (unlink(path_max_tmp) < 0)
+ return PLAYLIST_RESULT_ERRNO;
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-int savePlaylist(int fd, char *utf8file)
+enum playlist_result savePlaylist(const char *utf8file)
{
FILE *fp;
int i;
struct stat sb;
char path_max_tmp[MPD_PATH_MAX];
- if (!valid_playlist_name(fd, utf8file))
- return -1;
+ if (!is_valid_playlist_name(utf8file))
+ return PLAYLIST_RESULT_BAD_NAME;
utf8_to_fs_playlist_path(path_max_tmp, utf8file);
- if (!stat(path_max_tmp, &sb)) {
- commandError(fd, ACK_ERROR_EXIST, "a file or directory already "
- "exists with the name \"%s\"", utf8file);
- return -1;
- }
+ if (!stat(path_max_tmp, &sb))
+ return PLAYLIST_RESULT_LIST_EXISTS;
while (!(fp = fopen(path_max_tmp, "w")) && errno == EINTR);
- if (fp == NULL) {
- commandError(fd, ACK_ERROR_SYSTEM, "failed to create file");
- return -1;
- }
+ if (fp == NULL)
+ return PLAYLIST_RESULT_ERRNO;
for (i = 0; i < playlist.length; i++) {
char tmp[MPD_PATH_MAX];
@@ -1371,7 +1310,7 @@ int savePlaylist(int fd, char *utf8file)
while (fclose(fp) && errno == EINTR) ;
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
int getPlaylistCurrentSong(void)
@@ -1398,16 +1337,13 @@ int getPlaylistLength(void)
* This command will always return 0 regardless of whether or
* not the seek succeeded (it's always been the case, apparently)
*/
-int seekSongInPlaylist(int fd, int song, float seek_time)
+enum playlist_result seekSongInPlaylist(int song, float seek_time)
{
int i = song;
char path[MPD_PATH_MAX];
- if (song < 0 || song >= playlist.length) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "song doesn't exist: \"%i\"", song);
- return -1;
- }
+ if (song < 0 || song >= playlist.length)
+ return PLAYLIST_RESULT_BAD_RANGE;
if (playlist.random)
for (i = 0; song != playlist.order[i]; i++) ;
@@ -1420,7 +1356,7 @@ int seekSongInPlaylist(int fd, int song, float seek_time)
(playlist.current == i && playlist.queued == i)) {
dc_trigger_action(DC_ACTION_SEEK, seek_time);
if (dc.seek_where != DC_SEEK_MISMATCH)
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
/*
* if near end of decoding can cause seek to fail (since we're
* already on another song) (leading to DC_SEEK_MISMATCH),
@@ -1430,14 +1366,15 @@ int seekSongInPlaylist(int fd, int song, float seek_time)
DEBUG("playlist: seek %i:\"%s\"\n", i, get_song_url(path, song_at(i)));
play_order_num(i, seek_time);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-int seekSongInPlaylistById(int fd, int id, float seek_time)
+enum playlist_result seekSongInPlaylistById(int id, float seek_time)
{
- checkSongId(id);
+ if (!song_id_exists(id))
+ return PLAYLIST_RESULT_NO_SUCH_SONG;
- return seekSongInPlaylist(fd, playlist.idToPosition[id], seek_time);
+ return seekSongInPlaylist(playlist.idToPosition[id], seek_time);
}
int getPlaylistSongId(int song)
@@ -1445,12 +1382,12 @@ int getPlaylistSongId(int song)
return playlist.positionToId[song];
}
-int PlaylistInfo(int fd, char *utf8file, int detail)
+int PlaylistInfo(int fd, const char *utf8file, int detail)
{
ListNode *node;
List *list;
- if (!(list = loadStoredPlaylist(fd, utf8file)))
+ if (!(list = loadStoredPlaylist(utf8file)))
return -1;
node = list->firstNode;
@@ -1477,18 +1414,18 @@ int PlaylistInfo(int fd, char *utf8file, int detail)
return 0;
}
-int loadPlaylist(int fd, char *utf8file)
+enum playlist_result loadPlaylist(int fd, const char *utf8file)
{
ListNode *node;
List *list;
- if (!(list = loadStoredPlaylist(fd, utf8file)))
- return -1;
+ if (!(list = loadStoredPlaylist(utf8file)))
+ return PLAYLIST_RESULT_NO_SUCH_LIST;
node = list->firstNode;
while (node != NULL) {
char *temp = node->data;
- if ((addToPlaylist(STDERR_FILENO, temp, NULL)) < 0) {
+ if ((addToPlaylist(temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
/* for windows compatibility, convert slashes */
char *temp2 = xstrdup(temp);
char *p = temp2;
@@ -1497,7 +1434,7 @@ int loadPlaylist(int fd, char *utf8file)
*p = '/';
p++;
}
- if ((addToPlaylist(STDERR_FILENO, temp2, NULL)) < 0) {
+ if ((addToPlaylist(temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
commandError(fd, ACK_ERROR_PLAYLIST_LOAD,
"can't add file \"%s\"", temp2);
}
@@ -1508,7 +1445,7 @@ int loadPlaylist(int fd, char *utf8file)
}
freeList(list);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
void searchForSongsInPlaylist(int fd, int numItems, LocateTagItem * items)
@@ -1553,18 +1490,11 @@ void findSongsInPlaylist(int fd, int numItems, LocateTagItem * items)
* protocol (and compatibility with all clients) to support idiots who
* put '\r' and '\n' in filenames isn't going to happen, either.
*/
-int valid_playlist_name(int err_fd, const char *utf8path)
-{
- if (strchr(utf8path, '/') ||
- strchr(utf8path, '\n') ||
- strchr(utf8path, '\r')) {
- commandError(err_fd, ACK_ERROR_ARG, "playlist name \"%s\" is "
- "invalid: playlist names may not contain slashes,"
- " newlines or carriage returns",
- utf8path);
- return 0;
- }
- return 1;
+int is_valid_playlist_name(const char *utf8path)
+{
+ return strchr(utf8path, '/') == NULL &&
+ strchr(utf8path, '\n') == NULL &&
+ strchr(utf8path, '\r') == NULL;
}
int playlist_playing(void)
diff --git a/src/playlist.h b/src/playlist.h
index 629bfa057..2d8d43ec6 100644
--- a/src/playlist.h
+++ b/src/playlist.h
@@ -24,6 +24,18 @@
#define PLAYLIST_FILE_SUFFIX "m3u"
#define PLAYLIST_COMMENT '#'
+enum playlist_result {
+ PLAYLIST_RESULT_SUCCESS,
+ PLAYLIST_RESULT_ERRNO,
+ PLAYLIST_RESULT_NO_SUCH_SONG,
+ PLAYLIST_RESULT_NO_SUCH_LIST,
+ PLAYLIST_RESULT_LIST_EXISTS,
+ PLAYLIST_RESULT_BAD_NAME,
+ PLAYLIST_RESULT_BAD_RANGE,
+ PLAYLIST_RESULT_NOT_PLAYING,
+ PLAYLIST_RESULT_TOO_LARGE
+};
+
extern int playlist_saveAbsolutePaths;
extern int playlist_max_length;
@@ -38,23 +50,23 @@ void savePlaylistState(FILE *);
void clearPlaylist(void);
-int clearStoredPlaylist(int fd, char *utf8file);
+int clearStoredPlaylist(const char *utf8file);
-int addToPlaylist(int fd, char *file, int *added_id);
+enum playlist_result addToPlaylist(const char *file, int *added_id);
-int addToStoredPlaylist(int fd, char *file, char *utf8file);
+int addToStoredPlaylist(const char *file, const char *utf8file);
-int addSongToPlaylist(int fd, Song * song, int *added_id);
+enum playlist_result addSongToPlaylist(Song * song, int *added_id);
-int showPlaylist(int fd);
+void showPlaylist(int fd);
-int deleteFromPlaylist(int fd, int song);
+enum playlist_result deleteFromPlaylist(int song);
-int deleteFromPlaylistById(int fd, int song);
+enum playlist_result deleteFromPlaylistById(int song);
-int playlistInfo(int fd, int song);
+enum playlist_result playlistInfo(int fd, int song);
-int playlistId(int fd, int song);
+enum playlist_result playlistId(int fd, int song);
Song *playlist_queued_song(void);
@@ -64,9 +76,9 @@ int playlist_playing(void);
void stopPlaylist(void);
-int playPlaylist(int fd, int song, int stopOnError);
+enum playlist_result playPlaylist(int song, int stopOnError);
-int playPlaylistById(int fd, int song, int stopOnError);
+enum playlist_result playPlaylistById(int song, int stopOnError);
void nextSongInPlaylist(void);
@@ -74,33 +86,31 @@ void syncPlayerAndPlaylist(void);
void previousSongInPlaylist(void);
-int shufflePlaylist(int fd);
-
-int savePlaylist(int fd, char *utf8file);
+void shufflePlaylist(void);
-int deletePlaylist(int fd, char *utf8file);
+enum playlist_result savePlaylist(const char *utf8file);
-int deletePlaylistById(int fd, char *utf8file);
+enum playlist_result deletePlaylist(const char *utf8file);
void deleteASongFromPlaylist(Song * song);
-int moveSongInPlaylist(int fd, int from, int to);
+enum playlist_result moveSongInPlaylist(int from, int to);
-int moveSongInPlaylistById(int fd, int id, int to);
+enum playlist_result moveSongInPlaylistById(int id, int to);
-int swapSongsInPlaylist(int fd, int song1, int song2);
+enum playlist_result swapSongsInPlaylist(int song1, int song2);
-int swapSongsInPlaylistById(int fd, int id1, int id2);
+enum playlist_result swapSongsInPlaylistById(int id1, int id2);
-int loadPlaylist(int fd, char *utf8file);
+enum playlist_result loadPlaylist(int fd, const char *utf8file);
int getPlaylistRepeatStatus(void);
-int setPlaylistRepeatStatus(int fd, int status);
+void setPlaylistRepeatStatus(int status);
int getPlaylistRandomStatus(void);
-int setPlaylistRandomStatus(int fd, int status);
+void setPlaylistRandomStatus(int status);
int getPlaylistCurrentSong(void);
@@ -110,9 +120,9 @@ int getPlaylistLength(void);
unsigned long getPlaylistVersion(void);
-int seekSongInPlaylist(int fd, int song, float seek_time);
+enum playlist_result seekSongInPlaylist(int song, float seek_time);
-int seekSongInPlaylistById(int fd, int id, float seek_time);
+enum playlist_result seekSongInPlaylistById(int id, float seek_time);
void playlistVersionChange(void);
@@ -120,13 +130,13 @@ int playlistChanges(int fd, mpd_uint32 version);
int playlistChangesPosId(int fd, mpd_uint32 version);
-int PlaylistInfo(int fd, char *utf8file, int detail);
+int PlaylistInfo(int fd, const char *utf8file, int detail);
void searchForSongsInPlaylist(int fd, int numItems, LocateTagItem * items);
void findSongsInPlaylist(int fd, int numItems, LocateTagItem * items);
-int valid_playlist_name(int err_fd, const char *utf8path);
+int is_valid_playlist_name(const char *utf8path);
struct mpd_tag *playlist_current_tag(void);
diff --git a/src/stats.c b/src/stats.c
index c576d2870..4555907db 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -40,7 +40,7 @@ struct visit_data {
struct strset *set;
};
-static int visit_tag_items(mpd_unused int fd, Song *song, void *_data)
+static int visit_tag_items(Song *song, void *_data)
{
const struct visit_data *data = _data;
unsigned i;
@@ -65,7 +65,7 @@ static unsigned int getNumberOfTagItems(int type)
data.type = type;
data.set = strset_new();
- traverseAllIn(STDERR_FILENO, NULL, visit_tag_items, NULL, &data);
+ traverseAllIn(NULL, visit_tag_items, NULL, &data);
ret = strset_size(data.set);
strset_free(data.set);
diff --git a/src/storedPlaylist.c b/src/storedPlaylist.c
index 332f99456..c1452ddb9 100644
--- a/src/storedPlaylist.c
+++ b/src/storedPlaylist.c
@@ -19,8 +19,6 @@
#include "storedPlaylist.h"
#include "path.h"
#include "utils.h"
-#include "ack.h"
-#include "command.h"
#include "ls.h"
#include "directory.h"
#include "os_compat.h"
@@ -60,24 +58,24 @@ static ListNode *nodeOfStoredPlaylist(List *list, int idx)
return NULL;
}
-static int writeStoredPlaylistToPath(int fd, List *list, const char *utf8path)
+static enum playlist_result
+writeStoredPlaylistToPath(List *list, const char *utf8path)
{
ListNode *node;
FILE *file;
char *s;
char path_max_tmp[MPD_PATH_MAX];
- if (!utf8path || !valid_playlist_name(fd, utf8path))
- return -1;
+ assert(utf8path);
+
+ if (!is_valid_playlist_name(utf8path))
+ return PLAYLIST_RESULT_BAD_NAME;
utf8_to_fs_playlist_path(path_max_tmp, utf8path);
while (!(file = fopen(path_max_tmp, "w")) && errno == EINTR);
- if (file == NULL) {
- commandError(fd, ACK_ERROR_NO_EXIST, "could not open file "
- "\"%s\": %s", path_max_tmp, strerror(errno));
- return -1;
- }
+ if (file == NULL)
+ return PLAYLIST_RESULT_ERRNO;
node = list->firstNode;
while (node != NULL) {
@@ -89,10 +87,10 @@ static int writeStoredPlaylistToPath(int fd, List *list, const char *utf8path)
}
while (fclose(file) != 0 && errno == EINTR);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-List *loadStoredPlaylist(int fd, const char *utf8path)
+List *loadStoredPlaylist(const char *utf8path)
{
List *list;
FILE *file;
@@ -100,16 +98,13 @@ List *loadStoredPlaylist(int fd, const char *utf8path)
char path_max_tmp[MPD_PATH_MAX];
const size_t musicDir_len = strlen(musicDir);
- if (!valid_playlist_name(fd, utf8path))
+ if (!is_valid_playlist_name(utf8path))
return NULL;
utf8_to_fs_playlist_path(path_max_tmp, utf8path);
while (!(file = fopen(path_max_tmp, "r")) && errno == EINTR);
- if (file == NULL) {
- commandError(fd, ACK_ERROR_NO_EXIST, "could not open file "
- "\"%s\": %s", path_max_tmp, strerror(errno));
+ if (file == NULL)
return NULL;
- }
list = makeList(DEFAULT_FREE_DATA_FUNC, 0);
@@ -137,15 +132,13 @@ List *loadStoredPlaylist(int fd, const char *utf8path)
return list;
}
-static int moveSongInStoredPlaylist(int fd, List *list, int src, int dest)
+static int moveSongInStoredPlaylist(List *list, int src, int dest)
{
ListNode *srcNode, *destNode;
if (src >= list->numberOfNodes || dest >= list->numberOfNodes ||
- src < 0 || dest < 0 || src == dest) {
- commandError(fd, ACK_ERROR_ARG, "argument out of range");
+ src < 0 || dest < 0 || src == dest)
return -1;
- }
srcNode = nodeOfStoredPlaylist(list, src);
if (!srcNode)
@@ -199,90 +192,78 @@ static int moveSongInStoredPlaylist(int fd, List *list, int src, int dest)
return 0;
}
-int moveSongInStoredPlaylistByPath(int fd, const char *utf8path,
- int src, int dest)
+enum playlist_result
+moveSongInStoredPlaylistByPath(const char *utf8path, int src, int dest)
{
List *list;
+ enum playlist_result result;
- if (!(list = loadStoredPlaylist(fd, utf8path))) {
- commandError(fd, ACK_ERROR_UNKNOWN, "could not open playlist");
- return -1;
- }
+ if (!(list = loadStoredPlaylist(utf8path)))
+ return PLAYLIST_RESULT_NO_SUCH_LIST;
- if (moveSongInStoredPlaylist(fd, list, src, dest) != 0) {
+ if (moveSongInStoredPlaylist(list, src, dest) != 0) {
freeList(list);
- return -1;
+ return PLAYLIST_RESULT_BAD_RANGE;
}
- if (writeStoredPlaylistToPath(fd, list, utf8path) != 0) {
- commandError(fd, ACK_ERROR_UNKNOWN, "failed to save playlist");
- freeList(list);
- return -1;
- }
+ result = writeStoredPlaylistToPath(list, utf8path);
freeList(list);
- return 0;
+ return result;
}
-int removeAllFromStoredPlaylistByPath(int fd, const char *utf8path)
+enum playlist_result
+removeAllFromStoredPlaylistByPath(const char *utf8path)
{
char filename[MPD_PATH_MAX];
FILE *file;
- if (!valid_playlist_name(fd, utf8path))
- return -1;
+ if (!is_valid_playlist_name(utf8path))
+ return PLAYLIST_RESULT_BAD_NAME;
+
utf8_to_fs_playlist_path(filename, utf8path);
while (!(file = fopen(filename, "w")) && errno == EINTR);
- if (file == NULL) {
- commandError(fd, ACK_ERROR_NO_EXIST, "could not open file "
- "\"%s\": %s", filename, strerror(errno));
- return -1;
- }
+ if (file == NULL)
+ return PLAYLIST_RESULT_ERRNO;
while (fclose(file) != 0 && errno == EINTR);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-static int removeOneSongFromStoredPlaylist(int fd, List *list, int pos)
+static int removeOneSongFromStoredPlaylist(List *list, int pos)
{
ListNode *node = nodeOfStoredPlaylist(list, pos);
- if (!node) {
- commandError(fd, ACK_ERROR_ARG,
- "could not find song at position");
+ if (!node)
return -1;
- }
deleteNodeFromList(list, node);
return 0;
}
-int removeOneSongFromStoredPlaylistByPath(int fd, const char *utf8path, int pos)
+enum playlist_result
+removeOneSongFromStoredPlaylistByPath(const char *utf8path, int pos)
{
List *list;
+ enum playlist_result result;
- if (!(list = loadStoredPlaylist(fd, utf8path))) {
- commandError(fd, ACK_ERROR_UNKNOWN, "could not open playlist");
- return -1;
- }
+ if (!(list = loadStoredPlaylist(utf8path)))
+ return PLAYLIST_RESULT_NO_SUCH_LIST;
- if (removeOneSongFromStoredPlaylist(fd, list, pos) != 0) {
+ if (removeOneSongFromStoredPlaylist(list, pos) != 0) {
freeList(list);
- return -1;
+ return PLAYLIST_RESULT_BAD_RANGE;
}
- if (writeStoredPlaylistToPath(fd, list, utf8path) != 0) {
- commandError(fd, ACK_ERROR_UNKNOWN, "failed to save playlist");
- freeList(list);
- return -1;
- }
+ result = writeStoredPlaylistToPath(list, utf8path);
freeList(list);
- return 0;
+ return result;
}
-int appendSongToStoredPlaylistByPath(int fd, const char *utf8path, Song *song)
+enum playlist_result
+appendSongToStoredPlaylistByPath(const char *utf8path, Song *song)
{
FILE *file;
char *s;
@@ -290,25 +271,28 @@ int appendSongToStoredPlaylistByPath(int fd, const char *utf8path, Song *song)
char path_max_tmp[MPD_PATH_MAX];
char path_max_tmp2[MPD_PATH_MAX];
- if (!valid_playlist_name(fd, utf8path))
- return -1;
+ if (!is_valid_playlist_name(utf8path))
+ return PLAYLIST_RESULT_BAD_NAME;
utf8_to_fs_playlist_path(path_max_tmp, utf8path);
while (!(file = fopen(path_max_tmp, "a")) && errno == EINTR);
if (file == NULL) {
- commandError(fd, ACK_ERROR_NO_EXIST, "could not open file "
- "\"%s\": %s", path_max_tmp, strerror(errno));
- return -1;
+ int save_errno = errno;
+ while (fclose(file) != 0 && errno == EINTR);
+ errno = save_errno;
+ return PLAYLIST_RESULT_ERRNO;
}
+
if (fstat(fileno(file), &st) < 0) {
- commandError(fd, ACK_ERROR_NO_EXIST, "could not stat file "
- "\"%s\": %s", path_max_tmp, strerror(errno));
- return -1;
+ int save_errno = errno;
+ while (fclose(file) != 0 && errno == EINTR);
+ errno = save_errno;
+ return PLAYLIST_RESULT_ERRNO;
}
+
if (st.st_size >= ((MPD_PATH_MAX+1) * playlist_max_length)) {
- commandError(fd, ACK_ERROR_PLAYLIST_MAX,
- "playlist is at the max size");
- return -1;
+ while (fclose(file) != 0 && errno == EINTR);
+ return PLAYLIST_RESULT_TOO_LARGE;
}
s = utf8_to_fs_charset(path_max_tmp2, get_song_url(path_max_tmp, song));
@@ -319,40 +303,31 @@ int appendSongToStoredPlaylistByPath(int fd, const char *utf8path, Song *song)
fprintf(file, "%s\n", s);
while (fclose(file) != 0 && errno == EINTR);
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
-int renameStoredPlaylist(int fd, const char *utf8from, const char *utf8to)
+enum playlist_result
+renameStoredPlaylist(const char *utf8from, const char *utf8to)
{
struct stat st;
char from[MPD_PATH_MAX];
char to[MPD_PATH_MAX];
- if (!valid_playlist_name(fd, utf8from) ||
- !valid_playlist_name(fd, utf8to))
- return -1;
+ if (!is_valid_playlist_name(utf8from) ||
+ !is_valid_playlist_name(utf8to))
+ return PLAYLIST_RESULT_BAD_NAME;
utf8_to_fs_playlist_path(from, utf8from);
utf8_to_fs_playlist_path(to, utf8to);
- if (stat(from, &st) != 0) {
- commandError(fd, ACK_ERROR_NO_EXIST,
- "no playlist named \"%s\"", utf8from);
- return -1;
- }
+ if (stat(from, &st) != 0)
+ return PLAYLIST_RESULT_NO_SUCH_LIST;
- if (stat(to, &st) == 0) {
- commandError(fd, ACK_ERROR_EXIST, "a file or directory "
- "already exists with the name \"%s\"", utf8to);
- return -1;
- }
+ if (stat(to, &st) == 0)
+ return PLAYLIST_RESULT_LIST_EXISTS;
- if (rename(from, to) < 0) {
- commandError(fd, ACK_ERROR_UNKNOWN,
- "could not rename playlist \"%s\" to \"%s\": %s",
- utf8from, utf8to, strerror(errno));
- return -1;
- }
+ if (rename(from, to) < 0)
+ return PLAYLIST_RESULT_ERRNO;
- return 0;
+ return PLAYLIST_RESULT_SUCCESS;
}
diff --git a/src/storedPlaylist.h b/src/storedPlaylist.h
index a7806386b..964669d35 100644
--- a/src/storedPlaylist.h
+++ b/src/storedPlaylist.h
@@ -23,14 +23,21 @@
#include "list.h"
#include "playlist.h"
-List *loadStoredPlaylist(int fd, const char *utf8path);
+List *loadStoredPlaylist(const char *utf8path);
-int moveSongInStoredPlaylistByPath(int fd, const char *utf8path, int src, int dest);
-int removeAllFromStoredPlaylistByPath(int fd, const char *utf8path);
-int removeOneSongFromStoredPlaylistByPath(int fd, const char *utf8path, int pos);
+enum playlist_result
+moveSongInStoredPlaylistByPath(const char *utf8path, int src, int dest);
-int appendSongToStoredPlaylistByPath(int fd, const char *utf8path, Song *song);
+enum playlist_result
+removeAllFromStoredPlaylistByPath(const char *utf8path);
-int renameStoredPlaylist(int fd, const char *utf8from, const char *utf8to);
+enum playlist_result
+removeOneSongFromStoredPlaylistByPath(const char *utf8path, int pos);
+
+enum playlist_result
+appendSongToStoredPlaylistByPath(const char *utf8path, Song *song);
+
+enum playlist_result
+renameStoredPlaylist(const char *utf8from, const char *utf8to);
#endif
diff --git a/src/volume.c b/src/volume.c
index cf2b8eff8..428c3b8a1 100644
--- a/src/volume.c
+++ b/src/volume.c
@@ -17,12 +17,10 @@
*/
#include "volume.h"
-#include "command.h"
#include "conf.h"
#include "log.h"
#include "gcc.h"
#include "utils.h"
-#include "ack.h"
#include "os_compat.h"
#include "outputBuffer.h"
@@ -169,18 +167,15 @@ static int getOssVolumeLevel(void)
return left;
}
-static int changeOssVolumeLevel(int fd, int change, int rel)
+static int changeOssVolumeLevel(int change, int rel)
{
int current;
int new;
int level;
if (rel) {
- if ((current = getOssVolumeLevel()) < 0) {
- commandError(fd, ACK_ERROR_SYSTEM,
- "problem getting current volume");
+ if ((current = getOssVolumeLevel()) < 0)
return -1;
- }
new = current + change;
} else {
@@ -198,7 +193,6 @@ static int changeOssVolumeLevel(int fd, int change, int rel)
if (ioctl(volume_ossFd, MIXER_WRITE(volume_ossControl), &level) < 0) {
closeOssMixer();
- commandError(fd, ACK_ERROR_SYSTEM, "problems setting volume");
return -1;
}
@@ -328,7 +322,7 @@ static int getAlsaVolumeLevel(void)
return ret;
}
-static int changeAlsaVolumeLevel(int fd, int change, int rel)
+static int changeAlsaVolumeLevel(int change, int rel)
{
float vol;
long level;
@@ -361,7 +355,6 @@ static int changeAlsaVolumeLevel(int fd, int change, int rel)
if ((err =
snd_mixer_selem_set_playback_volume_all(volume_alsaElem,
level)) < 0) {
- commandError(fd, ACK_ERROR_SYSTEM, "problems setting volume");
WARNING("problems setting alsa volume: %s\n",
snd_strerror(err));
closeAlsaMixer();
@@ -469,7 +462,7 @@ int getVolumeLevel(void)
}
}
-static int changeSoftwareVolume(mpd_unused int fd, int change, int rel)
+static int changeSoftwareVolume(int change, int rel)
{
int new = change;
@@ -497,19 +490,19 @@ static int changeSoftwareVolume(mpd_unused int fd, int change, int rel)
return 0;
}
-int changeVolumeLevel(int fd, int change, int rel)
+int changeVolumeLevel(int change, int rel)
{
switch (volume_mixerType) {
#ifdef HAVE_ALSA
case VOLUME_MIXER_TYPE_ALSA:
- return changeAlsaVolumeLevel(fd, change, rel);
+ return changeAlsaVolumeLevel(change, rel);
#endif
#ifdef HAVE_OSS
case VOLUME_MIXER_TYPE_OSS:
- return changeOssVolumeLevel(fd, change, rel);
+ return changeOssVolumeLevel(change, rel);
#endif
case VOLUME_MIXER_TYPE_SOFTWARE:
- return changeSoftwareVolume(fd, change, rel);
+ return changeSoftwareVolume(change, rel);
default:
return 0;
}
@@ -531,7 +524,7 @@ void read_sw_volume_state(FILE *fp)
continue;
sv = strtol(buf + len, &end, 10);
if (mpd_likely(!*end))
- changeSoftwareVolume(STDERR_FILENO, sv, 0);
+ changeSoftwareVolume(sv, 0);
else
ERROR("Can't parse software volume: %s\n", buf);
return;
diff --git a/src/volume.h b/src/volume.h
index 85a9eefa8..a92cdd8bb 100644
--- a/src/volume.h
+++ b/src/volume.h
@@ -33,7 +33,7 @@ void finishVolume(void);
int getVolumeLevel(void);
-int changeVolumeLevel(int fd, int change, int rel);
+int changeVolumeLevel(int change, int rel);
void read_sw_volume_state(FILE *fp);