aboutsummaryrefslogtreecommitdiffstats
path: root/src/command/AllCommands.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/command/AllCommands.cxx')
-rw-r--r--src/command/AllCommands.cxx199
1 files changed, 102 insertions, 97 deletions
diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx
index 6a4b18198..8e8865ff3 100644
--- a/src/command/AllCommands.cxx
+++ b/src/command/AllCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "AllCommands.hxx"
+#include "Request.hxx"
#include "QueueCommands.hxx"
#include "TagCommands.hxx"
#include "PlayerCommands.hxx"
@@ -32,11 +33,14 @@
#include "OtherCommands.hxx"
#include "Permission.hxx"
#include "tag/TagType.h"
-#include "protocol/Result.hxx"
#include "Partition.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
+#include "util/Macros.hxx"
#include "util/Tokenizer.hxx"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
+#include "util/StringAPI.hxx"
#ifdef ENABLE_SQLITE
#include "StickerCommands.hxx"
@@ -60,22 +64,22 @@ struct command {
unsigned permission;
int min;
int max;
- CommandResult (*handler)(Client &client, unsigned argc, char **argv);
+ CommandResult (*handler)(Client &client, Request request, Response &response);
};
/* don't be fooled, this is the command handler for "commands" command */
static CommandResult
-handle_commands(Client &client, unsigned argc, char *argv[]);
+handle_commands(Client &client, Request request, Response &response);
static CommandResult
-handle_not_commands(Client &client, unsigned argc, char *argv[]);
+handle_not_commands(Client &client, Request request, Response &response);
/**
* The command registry.
*
* This array must be sorted!
*/
-static const struct command commands[] = {
+static constexpr struct command commands[] = {
{ "add", PERMISSION_ADD, 1, 1, handle_add },
{ "addid", PERMISSION_ADD, 1, 2, handle_addid },
{ "addtagid", PERMISSION_ADD, 3, 3, handle_addtagid },
@@ -194,62 +198,79 @@ static const struct command commands[] = {
{ "volume", PERMISSION_CONTROL, 1, 1, handle_volume },
};
-static const unsigned num_commands = sizeof(commands) / sizeof(commands[0]);
+static constexpr unsigned num_commands = ARRAY_SIZE(commands);
static bool
command_available(gcc_unused const Partition &partition,
gcc_unused const struct command *cmd)
{
#ifdef ENABLE_SQLITE
- if (strcmp(cmd->cmd, "sticker") == 0)
+ if (StringIsEqual(cmd->cmd, "sticker"))
return sticker_enabled();
#endif
#ifdef ENABLE_NEIGHBOR_PLUGINS
- if (strcmp(cmd->cmd, "listneighbors") == 0)
+ if (StringIsEqual(cmd->cmd, "listneighbors"))
return neighbor_commands_available(partition.instance);
#endif
+ if (StringIsEqual(cmd->cmd, "save") ||
+ StringIsEqual(cmd->cmd, "rm") ||
+ StringIsEqual(cmd->cmd, "rename") ||
+ StringIsEqual(cmd->cmd, "playlistdelete") ||
+ StringIsEqual(cmd->cmd, "playlistmove") ||
+ StringIsEqual(cmd->cmd, "playlistclear") ||
+ StringIsEqual(cmd->cmd, "playlistadd") ||
+ StringIsEqual(cmd->cmd, "listplaylists"))
+ return playlist_commands_available();
+
return true;
}
-/* don't be fooled, this is the command handler for "commands" command */
static CommandResult
-handle_commands(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+PrintAvailableCommands(Response &r, const Partition &partition,
+ unsigned permission)
{
- const unsigned permission = client.GetPermission();
- const struct command *cmd;
-
for (unsigned i = 0; i < num_commands; ++i) {
- cmd = &commands[i];
+ const struct command *cmd = &commands[i];
if (cmd->permission == (permission & cmd->permission) &&
- command_available(client.partition, cmd))
- client_printf(client, "command: %s\n", cmd->cmd);
+ command_available(partition, cmd))
+ r.Format("command: %s\n", cmd->cmd);
}
return CommandResult::OK;
}
static CommandResult
-handle_not_commands(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+PrintUnavailableCommands(Response &r, unsigned permission)
{
- const unsigned permission = client.GetPermission();
- const struct command *cmd;
-
for (unsigned i = 0; i < num_commands; ++i) {
- cmd = &commands[i];
+ const struct command *cmd = &commands[i];
if (cmd->permission != (permission & cmd->permission))
- client_printf(client, "command: %s\n", cmd->cmd);
+ r.Format("command: %s\n", cmd->cmd);
}
return CommandResult::OK;
}
-void command_init(void)
+/* don't be fooled, this is the command handler for "commands" command */
+static CommandResult
+handle_commands(Client &client, gcc_unused Request request, Response &r)
+{
+ return PrintAvailableCommands(r, client.partition,
+ client.GetPermission());
+}
+
+static CommandResult
+handle_not_commands(Client &client, gcc_unused Request request, Response &r)
+{
+ return PrintUnavailableCommands(r, client.GetPermission());
+}
+
+void
+command_init()
{
#ifndef NDEBUG
/* ensure that the command list is sorted */
@@ -258,7 +279,8 @@ void command_init(void)
#endif
}
-void command_finish(void)
+void
+command_finish()
{
}
@@ -266,13 +288,12 @@ static const struct command *
command_lookup(const char *name)
{
unsigned a = 0, b = num_commands, i;
- int cmp;
/* binary search */
do {
i = (a + b) / 2;
- cmp = strcmp(name, commands[i].cmd);
+ const auto cmp = strcmp(name, commands[i].cmd);
if (cmp == 0)
return &commands[i];
else if (cmp < 0)
@@ -285,60 +306,53 @@ command_lookup(const char *name)
}
static bool
-command_check_request(const struct command *cmd, Client &client,
- unsigned permission, unsigned argc, char *argv[])
+command_check_request(const struct command *cmd, Response &r,
+ unsigned permission, Request args)
{
- const unsigned min = cmd->min + 1;
- const unsigned max = cmd->max + 1;
-
if (cmd->permission != (permission & cmd->permission)) {
- command_error(client, ACK_ERROR_PERMISSION,
+ r.FormatError(ACK_ERROR_PERMISSION,
"you don't have permission for \"%s\"",
cmd->cmd);
return false;
}
- if (min == 0)
+ const int min = cmd->min;
+ const int max = cmd->max;
+
+ if (min < 0)
return true;
- if (min == max && max != argc) {
- command_error(client, ACK_ERROR_ARG,
+ if (min == max && unsigned(max) != args.size) {
+ r.FormatError(ACK_ERROR_ARG,
"wrong number of arguments for \"%s\"",
- argv[0]);
+ cmd->cmd);
return false;
- } else if (argc < min) {
- command_error(client, ACK_ERROR_ARG,
- "too few arguments for \"%s\"", argv[0]);
+ } else if (args.size < unsigned(min)) {
+ r.FormatError(ACK_ERROR_ARG,
+ "too few arguments for \"%s\"", cmd->cmd);
return false;
- } else if (argc > max && max /* != 0 */ ) {
- command_error(client, ACK_ERROR_ARG,
- "too many arguments for \"%s\"", argv[0]);
+ } else if (max >= 0 && args.size > unsigned(max)) {
+ r.FormatError(ACK_ERROR_ARG,
+ "too many arguments for \"%s\"", cmd->cmd);
return false;
} else
return true;
}
static const struct command *
-command_checked_lookup(Client &client, unsigned permission,
- unsigned argc, char *argv[])
+command_checked_lookup(Response &r, unsigned permission,
+ const char *cmd_name, Request args)
{
- const struct command *cmd;
-
- current_command = "";
-
- if (argc == 0)
- return nullptr;
-
- cmd = command_lookup(argv[0]);
+ const struct command *cmd = command_lookup(cmd_name);
if (cmd == nullptr) {
- command_error(client, ACK_ERROR_UNKNOWN,
- "unknown command \"%s\"", argv[0]);
+ r.FormatError(ACK_ERROR_UNKNOWN,
+ "unknown command \"%s\"", cmd_name);
return nullptr;
}
- current_command = cmd->cmd;
+ r.SetCommand(cmd->cmd);
- if (!command_check_request(cmd, client, permission, argc, argv))
+ if (!command_check_request(cmd, r, permission, args))
return nullptr;
return cmd;
@@ -347,68 +361,59 @@ command_checked_lookup(Client &client, unsigned permission,
CommandResult
command_process(Client &client, unsigned num, char *line)
{
+ Response r(client, num);
Error error;
- char *argv[COMMAND_ARGV_MAX] = { nullptr };
- const struct command *cmd;
- CommandResult ret = CommandResult::ERROR;
-
- command_list_num = num;
/* get the command name (first word on the line) */
+ /* we have to set current_command because Response::Error()
+ expects it to be set */
Tokenizer tokenizer(line);
- argv[0] = tokenizer.NextWord(error);
- if (argv[0] == nullptr) {
- current_command = "";
+
+ const char *const cmd_name = tokenizer.NextWord(error);
+ if (cmd_name == nullptr) {
if (tokenizer.IsEnd())
- command_error(client, ACK_ERROR_UNKNOWN,
- "No command given");
+ r.FormatError(ACK_ERROR_UNKNOWN, "No command given");
else
- command_error(client, ACK_ERROR_UNKNOWN,
- "%s", error.GetMessage());
-
- current_command = nullptr;
+ r.Error(ACK_ERROR_UNKNOWN, error.GetMessage());
/* this client does not speak the MPD protocol; kick
the connection */
return CommandResult::FINISH;
}
- unsigned argc = 1;
+ char *argv[COMMAND_ARGV_MAX];
+ Request args(argv, 0);
/* now parse the arguments (quoted or unquoted) */
- while (argc < COMMAND_ARGV_MAX &&
- (argv[argc] =
- tokenizer.NextParam(error)) != nullptr)
- ++argc;
-
- /* some error checks; we have to set current_command because
- command_error() expects it to be set */
+ while (true) {
+ if (args.size == COMMAND_ARGV_MAX) {
+ r.Error(ACK_ERROR_ARG, "Too many arguments");
+ return CommandResult::ERROR;
+ }
- current_command = argv[0];
+ char *a = tokenizer.NextParam(error);
+ if (a == nullptr) {
+ if (tokenizer.IsEnd())
+ break;
- if (argc >= COMMAND_ARGV_MAX) {
- command_error(client, ACK_ERROR_ARG, "Too many arguments");
- current_command = nullptr;
- return CommandResult::ERROR;
- }
+ r.Error(ACK_ERROR_UNKNOWN, error.GetMessage());
+ return CommandResult::ERROR;
+ }
- if (!tokenizer.IsEnd()) {
- command_error(client, ACK_ERROR_ARG, "%s", error.GetMessage());
- current_command = nullptr;
- return CommandResult::ERROR;
+ argv[args.size++] = a;
}
/* look up and invoke the command handler */
- cmd = command_checked_lookup(client, client.GetPermission(),
- argc, argv);
- if (cmd)
- ret = cmd->handler(client, argc, argv);
+ const struct command *cmd =
+ command_checked_lookup(r, client.GetPermission(),
+ cmd_name, args);
- current_command = nullptr;
- command_list_num = 0;
+ CommandResult ret = cmd
+ ? cmd->handler(client, args, r)
+ : CommandResult::ERROR;
return ret;
}