Browse files

send: new sub-library for sending commands with arguments

send.c provides functionos for sending commands to the MPD server.
Its arguments are escaped properly.
  • Loading branch information...
1 parent 72ec143 commit 30a4727d0594871a4e5aaef2df27214edfa77a6c @MaxKellermann MaxKellermann committed Jan 13, 2009
Showing with 234 additions and 0 deletions.
  1. +2 −0 Makefile.am
  2. +1 −0 include/mpd/client.h
  3. +59 −0 include/mpd/send.h
  4. +4 −0 libmpdclient.ld
  5. +168 −0 src/send.c
View
2 Makefile.am
@@ -13,6 +13,7 @@ mpdinclude_HEADERS = \
include/mpd/error.h \
include/mpd/idle.h \
include/mpd/protocol.h \
+ include/mpd/send.h \
include/mpd/status.h \
include/mpd/stats.h \
include/mpd/output.h \
@@ -34,6 +35,7 @@ src_libmpdclient_la_SOURCES = \
src/return_element.c \
src/entity.c \
src/idle.c \
+ src/send.c \
src/socket.c src/socket.h \
src/song.c \
src/status.c \
View
1 include/mpd/client.h
@@ -34,6 +34,7 @@
#define MPD_CLIENT_H
#include <mpd/connection.h>
+#include <mpd/send.h>
#include <mpd/song.h>
#include <mpd/directory.h>
View
59 include/mpd/send.h
@@ -0,0 +1,59 @@
+/* libmpdclient
+ (c) 2003-2009 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.
+*/
+
+#ifndef LIBMPDCLIENT_SEND_H
+#define LIBMPDCLIENT_SEND_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct mpd_connection;
+
+/**
+ * Sends a buffer to the MPD server.
+ *
+ * @param connection the connection to the MPD server
+ * @param p a pointer to the first byte of the buffer
+ * @param length the length of the buffer
+ * @return true on success
+ */
+bool
+mpd_send(struct mpd_connection *connection, const void *p, size_t length);
+
+/**
+ * Sends a command with arguments to the MPD server. The argument
+ * list must be terminated with a NULL.
+ *
+ * @param connection the connection to the MPD server
+ * @param command the command to be sent
+ * @return true on success
+ */
+bool
+mpd_send_command(struct mpd_connection *connection, const char *command, ...);
+
+#endif
View
4 libmpdclient.ld
@@ -1,4 +1,8 @@
libmpdclient2 {
global:
+ /* mpd/send.h */
+ mpd_send;
+ mpd_send_command;
+
*;
};
View
168 src/send.c
@@ -0,0 +1,168 @@
+/* libmpdclient
+ (c) 2003-2009 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/send.h>
+#include "internal.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+static bool
+mpd_can_send(struct mpd_connection *connection)
+{
+ if (!mpd_socket_defined(&connection->socket)) {
+ mpd_error_code(&connection->error, MPD_ERROR_CONNCLOSED);
+ mpd_error_message(&connection->error, "connection closed");
+ return false;
+ }
+
+ if (!connection->doneProcessing && !connection->commandList) {
+ mpd_error_code(&connection->error, MPD_ERROR_STATE);
+ mpd_error_message(&connection->error,
+ "not done processing current command");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+mpd_send(struct mpd_connection *connection, const void *p, size_t length)
+{
+ if (!mpd_can_send(connection))
+ return false;
+
+ mpd_clearError(connection);
+
+ return mpd_socket_send(&connection->socket, p, length,
+ &connection->error);
+}
+
+/**
+ * Append a string to the buffer, and escape special characters.
+ */
+static char *
+escape(char *dest, char *end, const char *value)
+{
+ while (*value != 0) {
+ char ch = *value++;
+
+ if (dest >= end)
+ return NULL;
+
+ if (ch == '"' || ch == '\\') {
+ *dest++ = '\\';
+
+ if (dest >= end)
+ return NULL;
+ }
+
+ *dest++ = ch;
+ }
+
+ return dest;
+}
+
+/**
+ * Enclose a string in double quotes, and escape special characters.
+ */
+static char *
+quote(char *dest, char *end, const char *value)
+{
+ if (dest >= end)
+ return NULL;
+
+ *dest++ = '"';
+
+ dest = escape(dest, end, value);
+
+ if (dest == NULL || dest >= end)
+ return NULL;
+
+ *dest++ = '"';
+
+ return dest;
+}
+
+bool
+mpd_send_command(struct mpd_connection *connection, const char *command, ...)
+{
+ char buffer[1024];
+ size_t length;
+ va_list ap;
+ const char *p;
+ bool ret;
+
+ if (!mpd_can_send(connection))
+ return false;
+
+ length = strlen(command);
+ if (length + 1 >= sizeof(buffer)) {
+ mpd_error_code(&connection->error, MPD_ERROR_ARG);
+ mpd_error_message(&connection->error, "command too long");
+ return false;
+ }
+
+ memcpy(buffer, command, length);
+
+ va_start(ap, command);
+
+ while ((p = va_arg(ap, const char *)) != NULL) {
+ assert(length < sizeof(buffer));
+
+ buffer[length++] = ' ';
+
+ p = quote(buffer + length, buffer + sizeof(buffer), p);
+ assert(p == NULL ||
+ (p >= buffer && p <= buffer + sizeof(buffer)));
+ if (p == NULL || p >= buffer + sizeof(buffer)) {
+ mpd_error_code(&connection->error, MPD_ERROR_ARG);
+ mpd_error_message(&connection->error,
+ "argument list too long");
+ return false;
+ }
+
+ length = p - buffer;
+ }
+
+ va_end(ap);
+
+ assert(length < sizeof(buffer));
+ buffer[length++] = '\n';
+
+ ret = mpd_send(connection, buffer, length);
+ if (!ret)
+ return false;
+
+ if (!connection->commandList)
+ connection->doneProcessing = false;
+ else if (connection->commandList == COMMAND_LIST_OK)
+ connection->listOks++;
+
+ return true;
+}

0 comments on commit 30a4727

Please sign in to comment.