Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

support the client-to-client protocol

Implemented in MPD 0.17.
  • Loading branch information...
commit 721bc25416311ea8b201ec56cb821c0c48d8c18d 1 parent 0fe3b92
@MaxKellermann MaxKellermann authored
View
3  Makefile.am
@@ -34,6 +34,7 @@ mpdinclude_HEADERS = \
include/mpd/song.h \
include/mpd/sticker.h \
include/mpd/settings.h \
+ include/mpd/message.h \
include/mpd/version.h
AM_CPPFLAGS += -I$(srcdir)/include -Iinclude
@@ -84,6 +85,8 @@ src_libmpdclient_la_SOURCES = \
src/tag.c \
src/sticker.c \
src/settings.c \
+ src/message.c \
+ src/cmessage.c \
src/uri.h
src_libmpdclient_la_LDFLAGS = -version-info @LIBMPDCLIENT_LIBTOOL_VERSION@ \
View
1  NEWS
@@ -1,6 +1,7 @@
libmpdclient 2.5 (2010/??/??)
* playlist: implement the command "listplaylists"
* idle: support event "sticker"
+* support the client-to-client protocol (MPD 0.17)
libmpdclient 2.4 (2011/01/03)
View
6 include/mpd/idle.h
@@ -80,6 +80,12 @@ enum mpd_idle {
/** a sticker has been modified. */
MPD_IDLE_STICKER = 0x100,
+
+ /** a client has subscribed or unsubscribed to/from a channel */
+ MPD_IDLE_SUBSCRIPTION = 0x200,
+
+ /** a message on the subscribed channel was receivedd */
+ MPD_IDLE_MESSAGE = 0x400,
};
#ifdef __cplusplus
View
210 include/mpd/message.h
@@ -0,0 +1,210 @@
+/* libmpdclient
+ (c) 2003-2010 The Music Player Daemon Project
+ This project's homepage is: http://www.musicpd.org
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*! \file
+ * \brief MPD client library
+ *
+ * Do not include this header directly. Use mpd/client.h instead.
+ */
+
+#ifndef MPD_MESSAGE_H
+#define MPD_MESSAGE_H
+
+#include <mpd/recv.h>
+#include <mpd/compiler.h>
+
+#include <stdbool.h>
+
+struct mpd_pair;
+struct mpd_message;
+struct mpd_connection;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Begins parsing a new message.
+ *
+ * @param pair the first pair in this message (name must be "channel")
+ * @return the new #mpd_entity object, or NULL on error (out of
+ * memory, or pair name is not "channel")
+ */
+mpd_malloc
+struct mpd_message *
+mpd_message_begin(const struct mpd_pair *pair);
+
+/**
+ * Parses the pair, adding its information to the specified
+ * #mpd_message object.
+ *
+ * @return true if the pair was parsed and added to the message (or if
+ * the pair was not understood and ignored), false if this pair is the
+ * beginning of the next message
+ */
+bool
+mpd_message_feed(struct mpd_message *output, const struct mpd_pair *pair);
+
+/**
+ * Frees a #mpd_message object.
+ */
+void
+mpd_message_free(struct mpd_message *message);
+
+/**
+ * Returns the channel name.
+ */
+mpd_pure
+const char *
+mpd_message_get_channel(const struct mpd_message *message);
+
+/**
+ * Returns the message text.
+ */
+mpd_pure
+const char *
+mpd_message_get_text(const struct mpd_message *message);
+
+/**
+ * Sends the "subscribe" command: subscribe to a message channel.
+ *
+ * @param connection the connection to MPD
+ * @param channel the channel name
+ * @return true on success
+ */
+bool
+mpd_send_subscribe(struct mpd_connection *connection, const char *channel);
+
+/**
+ * Shortcut for mpd_send_subscribe() and mpd_response_finish().
+ *
+ * @param connection the connection to MPD
+ * @param channel the channel name
+ * @return true on success
+ */
+bool
+mpd_run_subscribe(struct mpd_connection *connection, const char *channel);
+
+/**
+ * Sends the "unsubscribe" command: unsubscribe from a message
+ * channel.
+ *
+ * @param connection the connection to MPD
+ * @param channel the channel name
+ * @return true on success
+ */
+bool
+mpd_send_unsubscribe(struct mpd_connection *connection, const char *channel);
+
+/**
+ * Shortcut for mpd_send_unsubscribe() and mpd_response_finish().
+ *
+ * @param connection the connection to MPD
+ * @param channel the channel name
+ * @return true on success
+ */
+bool
+mpd_run_unsubscribe(struct mpd_connection *connection, const char *channel);
+
+/**
+ * Sends the "sendmessage" command: send a message to a channel.
+ *
+ * @param connection the connection to MPD
+ * @param channel the channel name
+ * @param text the message text
+ * @return true on success
+ */
+bool
+mpd_send_send_message(struct mpd_connection *connection,
+ const char *channel, const char *text);
+
+/**
+ * Shortcut for mpd_send_send_message() and mpd_response_finish().
+ *
+ * @param connection the connection to MPD
+ * @param channel the channel name
+ * @param text the message text
+ * @return true on success
+ */
+bool
+mpd_run_send_message(struct mpd_connection *connection,
+ const char *channel, const char *text);
+
+/**
+ * Sends the "readmessages" command: send a message to a channel.
+ *
+ * @param connection the connection to MPD
+ * @param channel the channel name
+ * @param message the message text
+ * @return true on success
+ */
+bool
+mpd_send_read_messages(struct mpd_connection *connection);
+
+/**
+ * Reads the next mpd_message from the MPD response. Free the return
+ * value with mpd_message_free().
+ *
+ * @return a mpd_message object on success, NULL on error or
+ * end-of-response
+ */
+mpd_malloc
+struct mpd_message *
+mpd_recv_message(struct mpd_connection *connection);
+
+/**
+ * Sends the "channels" command: get a list of all channels.
+ *
+ * @param connection the connection to MPD
+ * @return true on success
+ */
+bool
+mpd_send_channels(struct mpd_connection *connection);
+
+/**
+ * Receives the next channel name. Call this in a loop after
+ * mpd_send_channels().
+ *
+ * Free the return value with mpd_return_pair().
+ *
+ * @param connection a #mpd_connection
+ * @returns a "channel" pair, or NULL on error or if the end of the
+ * response is reached
+ */
+mpd_malloc
+static inline struct mpd_pair *
+mpd_recv_channel_pair(struct mpd_connection *connection)
+{
+ return mpd_recv_pair_named(connection, "channel");
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
View
16 libmpdclient.ld
@@ -80,6 +80,22 @@ global:
mpd_command_list_begin;
mpd_command_list_end;
+ /* mpd/message.h */
+ mpd_message_begin;
+ mpd_message_feed;
+ mpd_message_free;
+ mpd_message_get_channel;
+ mpd_message_get_text;
+ mpd_send_subscribe;
+ mpd_run_subscribe;
+ mpd_send_unsubscribe;
+ mpd_run_unsubscribe;
+ mpd_send_send_message;
+ mpd_run_send_message;
+ mpd_send_read_messages;
+ mpd_recv_message;
+ mpd_send_channels;
+
/* mpd/mixer.h */
mpd_send_set_volume;
mpd_run_set_volume;
View
134 src/cmessage.c
@@ -0,0 +1,134 @@
+/* libmpdclient
+ (c) 2003-2010 The Music Player Daemon Project
+ This project's homepage is: http://www.musicpd.org
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <mpd/message.h>
+#include <mpd/send.h>
+#include <mpd/response.h>
+#include "internal.h"
+#include "run.h"
+
+#include <assert.h>
+#include <stddef.h>
+
+bool
+mpd_send_subscribe(struct mpd_connection *connection, const char *channel)
+{
+ return mpd_send_command(connection, "subscribe", channel, NULL);
+}
+
+bool
+mpd_run_subscribe(struct mpd_connection *connection, const char *channel)
+{
+ return mpd_run_check(connection) &&
+ mpd_send_subscribe(connection, channel) &&
+ mpd_response_finish(connection);
+}
+
+bool
+mpd_send_unsubscribe(struct mpd_connection *connection, const char *channel)
+{
+ return mpd_send_command(connection, "unsubscribe", channel, NULL);
+}
+
+bool
+mpd_run_unsubscribe(struct mpd_connection *connection, const char *channel)
+{
+ return mpd_run_check(connection) &&
+ mpd_send_unsubscribe(connection, channel) &&
+ mpd_response_finish(connection);
+}
+
+bool
+mpd_send_send_message(struct mpd_connection *connection,
+ const char *channel, const char *text)
+{
+ return mpd_send_command(connection, "sendmessage", channel, text,
+ NULL);
+}
+
+bool
+mpd_run_send_message(struct mpd_connection *connection,
+ const char *channel, const char *text)
+{
+ return mpd_run_check(connection) &&
+ mpd_send_send_message(connection, channel, text) &&
+ mpd_response_finish(connection);
+}
+
+bool
+mpd_send_read_messages(struct mpd_connection *connection)
+{
+ return mpd_send_command(connection, "readmessages", NULL);
+}
+
+struct mpd_message *
+mpd_recv_message(struct mpd_connection *connection)
+{
+ struct mpd_message *message;
+ struct mpd_pair *pair;
+
+ pair = mpd_recv_pair_named(connection, "channel");
+ if (pair == NULL)
+ return NULL;
+
+ message = mpd_message_begin(pair);
+ mpd_return_pair(connection, pair);
+ if (message == NULL) {
+ mpd_error_code(&connection->error, MPD_ERROR_OOM);
+ return NULL;
+ }
+
+ while ((pair = mpd_recv_pair(connection)) != NULL &&
+ mpd_message_feed(message, pair))
+ mpd_return_pair(connection, pair);
+
+ if (mpd_error_is_defined(&connection->error)) {
+ assert(pair == NULL);
+
+ mpd_message_free(message);
+ return NULL;
+ }
+
+ mpd_enqueue_pair(connection, pair);
+
+ if (mpd_message_get_text(message) == NULL) {
+ mpd_error_code(&connection->error, MPD_ERROR_MALFORMED);
+ mpd_error_message(&connection->error,
+ "No 'message' line received");
+ mpd_message_free(message);
+ return NULL;
+ }
+
+ return message;
+}
+
+bool
+mpd_send_channels(struct mpd_connection *connection)
+{
+ return mpd_send_command(connection, "channels", NULL);
+}
View
43 src/example.c
@@ -35,6 +35,7 @@
#include <mpd/entity.h>
#include <mpd/search.h>
#include <mpd/tag.h>
+#include <mpd/message.h>
#include <assert.h>
#include <stdio.h>
@@ -234,6 +235,48 @@ int main(int argc, char ** argv) {
if (idle & i)
printf("%s\n", name);
}
+ } else if (argc == 3 && strcmp(argv[1], "subscribe") == 0) {
+ /* subscribe to a channel and print all messages */
+
+ if (!mpd_run_subscribe(conn, argv[2]))
+ return handle_error(conn);
+
+ while (mpd_run_idle_mask(conn, MPD_IDLE_MESSAGE) != 0) {
+ if (!mpd_send_read_messages(conn))
+ return handle_error(conn);
+
+ struct mpd_message *msg;
+ while ((msg = mpd_recv_message(conn)) != NULL) {
+ printf("%s\n", mpd_message_get_text(msg));
+ mpd_message_free(msg);
+ }
+
+ if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS ||
+ !mpd_response_finish(conn))
+ return handle_error(conn);
+ }
+
+ return handle_error(conn);
+ } else if (argc == 2 && strcmp(argv[1], "channels") == 0) {
+ /* print a list of channels */
+
+ if (!mpd_send_channels(conn))
+ return handle_error(conn);
+
+ struct mpd_pair *pair;
+ while ((pair = mpd_recv_channel_pair(conn)) != NULL) {
+ printf("%s\n", pair->value);
+ mpd_return_pair(conn, pair);
+ }
+
+ if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS ||
+ !mpd_response_finish(conn))
+ return handle_error(conn);
+ } else if (argc == 4 && strcmp(argv[1], "message") == 0) {
+ /* send a message to a channel */
+
+ if (!mpd_run_send_message(conn, argv[2], argv[3]))
+ return handle_error(conn);
}
mpd_connection_free(conn);
View
2  src/idle.c
@@ -52,6 +52,8 @@ static const char *const idle_names[] = {
"options",
"update",
"sticker",
+ "subscription",
+ "message",
NULL
};
View
103 src/message.c
@@ -0,0 +1,103 @@
+/* libmpdclient
+ (c) 2003-2010 The Music Player Daemon Project
+ This project's homepage is: http://www.musicpd.org
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <mpd/message.h>
+#include <mpd/pair.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct mpd_message {
+ char *channel;
+
+ char *text;
+};
+
+struct mpd_message *
+mpd_message_begin(const struct mpd_pair *pair)
+{
+ struct mpd_message *output;
+
+ assert(pair != NULL);
+
+ if (strcmp(pair->name, "channel") != 0)
+ return NULL;
+
+ output = malloc(sizeof(*output));
+ if (output == NULL)
+ return NULL;
+
+ output->channel = strdup(pair->value);
+ output->text = NULL;
+
+ return output;
+}
+
+bool
+mpd_message_feed(struct mpd_message *output, const struct mpd_pair *pair)
+{
+ if (strcmp(pair->name, "channel") == 0)
+ return false;
+
+ if (strcmp(pair->name, "message") == 0) {
+ if (output->text != NULL)
+ free(output->text);
+
+ output->text = strdup(pair->value);
+ }
+
+ return true;
+}
+
+void
+mpd_message_free(struct mpd_message *message)
+{
+ assert(message != NULL);
+
+ free(message->channel);
+ free(message->text);
+ free(message);
+}
+
+const char *
+mpd_message_get_channel(const struct mpd_message *message)
+{
+ assert(message != NULL);
+
+ return message->channel;
+}
+
+const char *
+mpd_message_get_text(const struct mpd_message *message)
+{
+ assert(message != NULL);
+
+ return message->text;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.