aboutsummaryrefslogtreecommitdiffstats
path: root/src/command
diff options
context:
space:
mode:
Diffstat (limited to 'src/command')
-rw-r--r--src/command/AllCommands.cxx199
-rw-r--r--src/command/AllCommands.hxx8
-rw-r--r--src/command/CommandError.cxx61
-rw-r--r--src/command/CommandError.hxx8
-rw-r--r--src/command/CommandListBuilder.cxx3
-rw-r--r--src/command/CommandListBuilder.hxx5
-rw-r--r--src/command/CommandResult.hxx2
-rw-r--r--src/command/DatabaseCommands.cxx145
-rw-r--r--src/command/DatabaseCommands.hxx26
-rw-r--r--src/command/FileCommands.cxx183
-rw-r--r--src/command/FileCommands.hxx10
-rw-r--r--src/command/MessageCommands.cxx66
-rw-r--r--src/command/MessageCommands.hxx14
-rw-r--r--src/command/NeighborCommands.cxx21
-rw-r--r--src/command/NeighborCommands.hxx6
-rw-r--r--src/command/OtherCommands.cxx336
-rw-r--r--src/command/OtherCommands.hxx36
-rw-r--r--src/command/OutputCommands.cxx37
-rw-r--r--src/command/OutputCommands.hxx12
-rw-r--r--src/command/PlayerCommands.cxx232
-rw-r--r--src/command/PlayerCommands.hxx46
-rw-r--r--src/command/PlaylistCommands.cxx140
-rw-r--r--src/command/PlaylistCommands.hxx31
-rw-r--r--src/command/QueueCommands.cxx305
-rw-r--r--src/command/QueueCommands.hxx44
-rw-r--r--src/command/Request.hxx74
-rw-r--r--src/command/StickerCommands.cxx152
-rw-r--r--src/command/StickerCommands.hxx6
-rw-r--r--src/command/StorageCommands.cxx96
-rw-r--r--src/command/StorageCommands.hxx14
-rw-r--r--src/command/TagCommands.cxx32
-rw-r--r--src/command/TagCommands.hxx8
32 files changed, 1241 insertions, 1117 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;
}
diff --git a/src/command/AllCommands.hxx b/src/command/AllCommands.hxx
index b7834a8de..e3405b034 100644
--- a/src/command/AllCommands.hxx
+++ b/src/command/AllCommands.hxx
@@ -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
@@ -24,9 +24,11 @@
class Client;
-void command_init(void);
+void
+command_init();
-void command_finish(void);
+void
+command_finish();
CommandResult
command_process(Client &client, unsigned num, char *line);
diff --git a/src/command/CommandError.cxx b/src/command/CommandError.cxx
index 89085fc68..9f06431b4 100644
--- a/src/command/CommandError.cxx
+++ b/src/command/CommandError.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
@@ -20,7 +20,8 @@
#include "config.h"
#include "CommandError.hxx"
#include "db/DatabaseError.hxx"
-#include "protocol/Result.hxx"
+#include "LocateUri.hxx"
+#include "client/Response.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
@@ -29,57 +30,55 @@
#include <errno.h>
CommandResult
-print_playlist_result(Client &client, PlaylistResult result)
+print_playlist_result(Response &r, PlaylistResult result)
{
switch (result) {
case PlaylistResult::SUCCESS:
return CommandResult::OK;
case PlaylistResult::ERRNO:
- command_error(client, ACK_ERROR_SYSTEM, "%s",
- strerror(errno));
+ r.Error(ACK_ERROR_SYSTEM, strerror(errno));
return CommandResult::ERROR;
case PlaylistResult::DENIED:
- command_error(client, ACK_ERROR_PERMISSION, "Access denied");
+ r.Error(ACK_ERROR_PERMISSION, "Access denied");
return CommandResult::ERROR;
case PlaylistResult::NO_SUCH_SONG:
- command_error(client, ACK_ERROR_NO_EXIST, "No such song");
+ r.Error(ACK_ERROR_NO_EXIST, "No such song");
return CommandResult::ERROR;
case PlaylistResult::NO_SUCH_LIST:
- command_error(client, ACK_ERROR_NO_EXIST, "No such playlist");
+ r.Error(ACK_ERROR_NO_EXIST, "No such playlist");
return CommandResult::ERROR;
case PlaylistResult::LIST_EXISTS:
- command_error(client, ACK_ERROR_EXIST,
- "Playlist already exists");
+ r.Error(ACK_ERROR_EXIST, "Playlist already exists");
return CommandResult::ERROR;
case PlaylistResult::BAD_NAME:
- command_error(client, ACK_ERROR_ARG,
- "playlist name is invalid: "
- "playlist names may not contain slashes,"
- " newlines or carriage returns");
+ r.Error(ACK_ERROR_ARG,
+ "playlist name is invalid: "
+ "playlist names may not contain slashes,"
+ " newlines or carriage returns");
return CommandResult::ERROR;
case PlaylistResult::BAD_RANGE:
- command_error(client, ACK_ERROR_ARG, "Bad song index");
+ r.Error(ACK_ERROR_ARG, "Bad song index");
return CommandResult::ERROR;
case PlaylistResult::NOT_PLAYING:
- command_error(client, ACK_ERROR_PLAYER_SYNC, "Not playing");
+ r.Error(ACK_ERROR_PLAYER_SYNC, "Not playing");
return CommandResult::ERROR;
case PlaylistResult::TOO_LARGE:
- command_error(client, ACK_ERROR_PLAYLIST_MAX,
- "playlist is at the max size");
+ r.Error(ACK_ERROR_PLAYLIST_MAX,
+ "playlist is at the max size");
return CommandResult::ERROR;
case PlaylistResult::DISABLED:
- command_error(client, ACK_ERROR_UNKNOWN,
- "stored playlist support is disabled");
+ r.Error(ACK_ERROR_UNKNOWN,
+ "stored playlist support is disabled");
return CommandResult::ERROR;
}
@@ -88,42 +87,42 @@ print_playlist_result(Client &client, PlaylistResult result)
}
CommandResult
-print_error(Client &client, const Error &error)
+print_error(Response &r, const Error &error)
{
assert(error.IsDefined());
LogError(error);
if (error.IsDomain(playlist_domain)) {
- return print_playlist_result(client,
+ return print_playlist_result(r,
PlaylistResult(error.GetCode()));
} else if (error.IsDomain(ack_domain)) {
- command_error(client, (ack)error.GetCode(),
- "%s", error.GetMessage());
+ r.Error((ack)error.GetCode(), error.GetMessage());
return CommandResult::ERROR;
#ifdef ENABLE_DATABASE
} else if (error.IsDomain(db_domain)) {
switch ((enum db_error)error.GetCode()) {
case DB_DISABLED:
- command_error(client, ACK_ERROR_NO_EXIST, "%s",
- error.GetMessage());
+ r.Error(ACK_ERROR_NO_EXIST, error.GetMessage());
return CommandResult::ERROR;
case DB_NOT_FOUND:
- command_error(client, ACK_ERROR_NO_EXIST, "Not found");
+ r.Error(ACK_ERROR_NO_EXIST, "Not found");
return CommandResult::ERROR;
case DB_CONFLICT:
- command_error(client, ACK_ERROR_ARG, "Conflict");
+ r.Error(ACK_ERROR_ARG, "Conflict");
return CommandResult::ERROR;
}
#endif
+ } else if (error.IsDomain(locate_uri_domain)) {
+ r.Error(ACK_ERROR_ARG, error.GetMessage());
+ return CommandResult::ERROR;
} else if (error.IsDomain(errno_domain)) {
- command_error(client, ACK_ERROR_SYSTEM, "%s",
- strerror(error.GetCode()));
+ r.Error(ACK_ERROR_SYSTEM, strerror(error.GetCode()));
return CommandResult::ERROR;
}
- command_error(client, ACK_ERROR_UNKNOWN, "error");
+ r.Error(ACK_ERROR_UNKNOWN, "error");
return CommandResult::ERROR;
}
diff --git a/src/command/CommandError.hxx b/src/command/CommandError.hxx
index b48baa5bf..e33386078 100644
--- a/src/command/CommandError.hxx
+++ b/src/command/CommandError.hxx
@@ -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
@@ -23,16 +23,16 @@
#include "CommandResult.hxx"
#include "PlaylistError.hxx"
-class Client;
+class Response;
class Error;
CommandResult
-print_playlist_result(Client &client, PlaylistResult result);
+print_playlist_result(Response &r, PlaylistResult result);
/**
* Send the #Error to the client.
*/
CommandResult
-print_error(Client &client, const Error &error);
+print_error(Response &r, const Error &error);
#endif
diff --git a/src/command/CommandListBuilder.cxx b/src/command/CommandListBuilder.cxx
index 477c246ff..4abb3ad16 100644
--- a/src/command/CommandListBuilder.cxx
+++ b/src/command/CommandListBuilder.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
@@ -27,7 +27,6 @@ void
CommandListBuilder::Reset()
{
list.clear();
- size = 0;
mode = Mode::DISABLED;
}
diff --git a/src/command/CommandListBuilder.hxx b/src/command/CommandListBuilder.hxx
index 0747c4697..9908121d6 100644
--- a/src/command/CommandListBuilder.hxx
+++ b/src/command/CommandListBuilder.hxx
@@ -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
@@ -58,7 +58,7 @@ class CommandListBuilder {
public:
CommandListBuilder()
- :mode(Mode::DISABLED), size(0) {}
+ :mode(Mode::DISABLED) {}
/**
* Is a command list currently being built?
@@ -89,6 +89,7 @@ public:
assert(mode == Mode::DISABLED);
mode = (Mode)ok;
+ size = 0;
}
/**
diff --git a/src/command/CommandResult.hxx b/src/command/CommandResult.hxx
index a2e968fb6..13641ec39 100644
--- a/src/command/CommandResult.hxx
+++ b/src/command/CommandResult.hxx
@@ -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
diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx
index a3ea8d0ae..bfcf3aa54 100644
--- a/src/command/DatabaseCommands.cxx
+++ b/src/command/DatabaseCommands.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 "DatabaseCommands.hxx"
+#include "Request.hxx"
#include "db/DatabaseGlue.hxx"
#include "db/DatabaseQueue.hxx"
#include "db/DatabasePlaylist.hxx"
@@ -27,83 +28,89 @@
#include "db/Selection.hxx"
#include "CommandError.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "tag/Tag.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
+#include "util/StringAPI.hxx"
#include "SongFilter.hxx"
-#include "protocol/Result.hxx"
#include "BulkEdit.hxx"
#include <string.h>
CommandResult
-handle_listfiles_db(Client &client, const char *uri)
+handle_listfiles_db(Client &client, Response &r, const char *uri)
{
const DatabaseSelection selection(uri, false);
Error error;
- if (!db_selection_print(client, selection, false, true, error))
- return print_error(client, error);
+ if (!db_selection_print(r, client.partition,
+ selection, false, true, error))
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_lsinfo2(Client &client, unsigned argc, char *argv[])
+handle_lsinfo2(Client &client, const char *uri, Response &r)
{
- const char *const uri = argc == 2
- ? argv[1]
- /* default is root directory */
- : "";
-
const DatabaseSelection selection(uri, false);
Error error;
- if (!db_selection_print(client, selection, true, false, error))
- return print_error(client, error);
+ if (!db_selection_print(r, client.partition,
+ selection, true, false, error))
+ return print_error(r, error);
return CommandResult::OK;
}
static CommandResult
-handle_match(Client &client, unsigned argc, char *argv[], bool fold_case)
+handle_match(Client &client, Request args, Response &r, bool fold_case)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
+ RangeArg window;
+ if (args.size >= 2 && StringIsEqual(args[args.size - 2], "window")) {
+ if (!args.Parse(args.size - 1, window, r))
+ return CommandResult::ERROR;
+
+ args.pop_back();
+ args.pop_back();
+ } else
+ window.SetAll();
SongFilter filter;
if (!filter.Parse(args, fold_case)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
const DatabaseSelection selection("", true, &filter);
Error error;
- return db_selection_print(client, selection, true, false, error)
+ return db_selection_print(r, client.partition,
+ selection, true, false,
+ window.start, window.end, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_find(Client &client, unsigned argc, char *argv[])
+handle_find(Client &client, Request args, Response &r)
{
- return handle_match(client, argc, argv, false);
+ return handle_match(client, args, r, false);
}
CommandResult
-handle_search(Client &client, unsigned argc, char *argv[])
+handle_search(Client &client, Request args, Response &r)
{
- return handle_match(client, argc, argv, true);
+ return handle_match(client, args, r, true);
}
static CommandResult
-handle_match_add(Client &client, unsigned argc, char *argv[], bool fold_case)
+handle_match_add(Client &client, Request args, Response &r, bool fold_case)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
-
SongFilter filter;
if (!filter.Parse(args, fold_case)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
@@ -113,55 +120,52 @@ handle_match_add(Client &client, unsigned argc, char *argv[], bool fold_case)
Error error;
return AddFromDatabase(client.partition, selection, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_findadd(Client &client, unsigned argc, char *argv[])
+handle_findadd(Client &client, Request args, Response &r)
{
- return handle_match_add(client, argc, argv, false);
+ return handle_match_add(client, args, r, false);
}
CommandResult
-handle_searchadd(Client &client, unsigned argc, char *argv[])
+handle_searchadd(Client &client, Request args, Response &r)
{
- return handle_match_add(client, argc, argv, true);
+ return handle_match_add(client, args, r, true);
}
CommandResult
-handle_searchaddpl(Client &client, unsigned argc, char *argv[])
+handle_searchaddpl(Client &client, Request args, Response &r)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
const char *playlist = args.shift();
SongFilter filter;
if (!filter.Parse(args, true)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
Error error;
const Database *db = client.GetDatabase(error);
if (db == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
return search_add_to_playlist(*db, *client.GetStorage(),
"", playlist, &filter, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_count(Client &client, unsigned argc, char *argv[])
+handle_count(Client &client, Request args, Response &r)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
-
TagType group = TAG_NUM_OF_ITEM_TYPES;
- if (args.size >= 2 && strcmp(args[args.size - 2], "group") == 0) {
+ if (args.size >= 2 && StringIsEqual(args[args.size - 2], "group")) {
const char *s = args[args.size - 1];
group = tag_name_parse_i(s);
if (group == TAG_NUM_OF_ITEM_TYPES) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Unknown tag type: %s", s);
return CommandResult::ERROR;
}
@@ -172,52 +176,50 @@ handle_count(Client &client, unsigned argc, char *argv[])
SongFilter filter;
if (!args.IsEmpty() && !filter.Parse(args, false)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
Error error;
- return PrintSongCount(client, "", &filter, group, error)
+ return PrintSongCount(r, client.partition, "", &filter, group, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_listall(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_listall(Client &client, Request args, Response &r)
{
- const char *directory = "";
-
- if (argc == 2)
- directory = argv[1];
+ /* default is root directory */
+ const auto uri = args.GetOptional(0, "");
Error error;
- return db_selection_print(client, DatabaseSelection(directory, true),
+ return db_selection_print(r, client.partition,
+ DatabaseSelection(uri, true),
false, false, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_list(Client &client, unsigned argc, char *argv[])
+handle_list(Client &client, Request args, Response &r)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
const char *tag_name = args.shift();
unsigned tagType = locate_parse_type(tag_name);
if (tagType >= TAG_NUM_OF_ITEM_TYPES &&
tagType != LOCATE_TAG_FILE_TYPE) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Unknown tag type: %s", tag_name);
return CommandResult::ERROR;
}
SongFilter *filter = nullptr;
- uint32_t group_mask = 0;
+ tag_mask_t group_mask = 0;
if (args.size == 1) {
/* for compatibility with < 0.12.0 */
if (tagType != TAG_ALBUM) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"should be \"%s\" for 3 arguments",
tag_item_names[TAG_ALBUM]);
return CommandResult::ERROR;
@@ -227,16 +229,16 @@ handle_list(Client &client, unsigned argc, char *argv[])
}
while (args.size >= 2 &&
- strcmp(args[args.size - 2], "group") == 0) {
+ StringIsEqual(args[args.size - 2], "group")) {
const char *s = args[args.size - 1];
TagType gt = tag_name_parse_i(s);
if (gt == TAG_NUM_OF_ITEM_TYPES) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Unknown tag type: %s", s);
return CommandResult::ERROR;
}
- group_mask |= 1u << unsigned(gt);
+ group_mask |= tag_mask_t(1) << unsigned(gt);
args.pop_back();
args.pop_back();
@@ -246,24 +248,24 @@ handle_list(Client &client, unsigned argc, char *argv[])
filter = new SongFilter();
if (!filter->Parse(args, false)) {
delete filter;
- command_error(client, ACK_ERROR_ARG,
- "not able to parse args");
+ r.Error(ACK_ERROR_ARG, "not able to parse args");
return CommandResult::ERROR;
}
}
if (tagType < TAG_NUM_OF_ITEM_TYPES &&
- group_mask & (1u << tagType)) {
+ group_mask & (tag_mask_t(1) << tagType)) {
delete filter;
- command_error(client, ACK_ERROR_ARG, "Conflicting group");
+ r.Error(ACK_ERROR_ARG, "Conflicting group");
return CommandResult::ERROR;
}
Error error;
CommandResult ret =
- PrintUniqueTags(client, tagType, group_mask, filter, error)
+ PrintUniqueTags(r, client.partition,
+ tagType, group_mask, filter, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
delete filter;
@@ -271,16 +273,15 @@ handle_list(Client &client, unsigned argc, char *argv[])
}
CommandResult
-handle_listallinfo(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_listallinfo(Client &client, Request args, Response &r)
{
- const char *directory = "";
-
- if (argc == 2)
- directory = argv[1];
+ /* default is root directory */
+ const auto uri = args.GetOptional(0, "");
Error error;
- return db_selection_print(client, DatabaseSelection(directory, true),
+ return db_selection_print(r, client.partition,
+ DatabaseSelection(uri, true),
true, false, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
diff --git a/src/command/DatabaseCommands.hxx b/src/command/DatabaseCommands.hxx
index 7abf89e0c..660e147db 100644
--- a/src/command/DatabaseCommands.hxx
+++ b/src/command/DatabaseCommands.hxx
@@ -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
@@ -23,38 +23,40 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_listfiles_db(Client &client, const char *uri);
+handle_listfiles_db(Client &client, Response &r, const char *uri);
CommandResult
-handle_lsinfo2(Client &client, unsigned argc, char *argv[]);
+handle_lsinfo2(Client &client, const char *uri, Response &response);
CommandResult
-handle_find(Client &client, unsigned argc, char *argv[]);
+handle_find(Client &client, Request request, Response &response);
CommandResult
-handle_findadd(Client &client, unsigned argc, char *argv[]);
+handle_findadd(Client &client, Request request, Response &response);
CommandResult
-handle_search(Client &client, unsigned argc, char *argv[]);
+handle_search(Client &client, Request request, Response &response);
CommandResult
-handle_searchadd(Client &client, unsigned argc, char *argv[]);
+handle_searchadd(Client &client, Request request, Response &response);
CommandResult
-handle_searchaddpl(Client &client, unsigned argc, char *argv[]);
+handle_searchaddpl(Client &client, Request request, Response &response);
CommandResult
-handle_count(Client &client, unsigned argc, char *argv[]);
+handle_count(Client &client, Request request, Response &response);
CommandResult
-handle_listall(Client &client, unsigned argc, char *argv[]);
+handle_listall(Client &client, Request request, Response &response);
CommandResult
-handle_list(Client &client, unsigned argc, char *argv[]);
+handle_list(Client &client, Request request, Response &response);
CommandResult
-handle_listallinfo(Client &client, unsigned argc, char *argv[]);
+handle_listallinfo(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx
index 1b6a11cf5..486c00d89 100644
--- a/src/command/FileCommands.cxx
+++ b/src/command/FileCommands.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
@@ -21,10 +21,12 @@
#include "config.h"
#include "FileCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
#include "protocol/Ack.hxx"
-#include "protocol/Result.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
+#include "util/ConstBuffer.hxx"
#include "util/CharUtil.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
@@ -35,10 +37,10 @@
#include "TagFile.hxx"
#include "storage/StorageInterface.hxx"
#include "fs/AllocatedPath.hxx"
-#include "fs/FileSystem.hxx"
+#include "fs/FileInfo.hxx"
#include "fs/DirectoryReader.hxx"
+#include "LocateUri.hxx"
#include "TimePrint.hxx"
-#include "ls.hxx"
#include <assert.h>
#include <sys/stat.h>
@@ -46,7 +48,7 @@
gcc_pure
static bool
-SkipNameFS(const char *name_fs)
+SkipNameFS(PathTraitsFS::const_pointer name_fs)
{
return name_fs[0] == '.' &&
(name_fs[1] == 0 ||
@@ -55,9 +57,9 @@ SkipNameFS(const char *name_fs)
gcc_pure
static bool
-skip_path(const char *name_fs)
+skip_path(Path name_fs)
{
- return strchr(name_fs, '\n') != nullptr;
+ return name_fs.HasNewline();
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
@@ -68,28 +70,19 @@ skip_path(const char *name_fs)
#endif
CommandResult
-handle_listfiles_local(Client &client, const char *path_utf8)
+handle_listfiles_local(Response &r,
+ const char *path_utf8, Path path_fs)
{
- const auto path_fs = AllocatedPath::FromUTF8(path_utf8);
- if (path_fs.IsNull()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported file name");
- return CommandResult::ERROR;
- }
-
- Error error;
- if (!client.AllowFile(path_fs, error))
- return print_error(client, error);
-
DirectoryReader reader(path_fs);
if (reader.HasFailed()) {
+ Error error;
error.FormatErrno("Failed to open '%s'", path_utf8);
- return print_error(client, error);
+ return print_error(r, error);
}
while (reader.ReadEntry()) {
const Path name_fs = reader.GetEntry();
- if (SkipNameFS(name_fs.c_str()) || skip_path(name_fs.c_str()))
+ if (SkipNameFS(name_fs.c_str()) || skip_path(name_fs))
continue;
std::string name_utf8 = name_fs.ToUTF8();
@@ -98,20 +91,21 @@ handle_listfiles_local(Client &client, const char *path_utf8)
const AllocatedPath full_fs =
AllocatedPath::Build(path_fs, name_fs);
- struct stat st;
- if (!StatFile(full_fs, st, false))
+ FileInfo fi;
+ if (!GetFileInfo(full_fs, fi, false))
continue;
- if (S_ISREG(st.st_mode)) {
- client_printf(client, "file: %s\n"
- "size: %" PRIu64 "\n",
- name_utf8.c_str(),
- uint64_t(st.st_size));
- } else if (S_ISDIR(st.st_mode))
- client_printf(client, "directory: %s\n",
- name_utf8.c_str());
+ if (fi.IsRegular())
+ r.Format("file: %s\n"
+ "size: %" PRIu64 "\n",
+ name_utf8.c_str(),
+ fi.GetSize());
+ else if (fi.IsDirectory())
+ r.Format("directory: %s\n", name_utf8.c_str());
+ else
+ continue;
- time_print(client, "Last-Modified", st.st_mtime);
+ time_print(r, "Last-Modified", fi.GetModificationTime());
}
return CommandResult::OK;
@@ -154,10 +148,10 @@ IsValidValue(const char *p)
static void
print_pair(const char *key, const char *value, void *ctx)
{
- Client &client = *(Client *)ctx;
+ auto &r = *(Response *)ctx;
if (IsValidName(key) && IsValidValue(value))
- client_printf(client, "%s: %s\n", key, value);
+ r.Format("%s: %s\n", key, value);
}
static constexpr tag_handler print_comment_handler = {
@@ -167,93 +161,90 @@ static constexpr tag_handler print_comment_handler = {
};
static CommandResult
-read_stream_comments(Client &client, const char *uri)
+read_stream_comments(Response &r, const char *uri)
{
- if (!uri_supported_scheme(uri)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported URI scheme");
+ if (!tag_stream_scan(uri, print_comment_handler, &r)) {
+ r.Error(ACK_ERROR_NO_EXIST, "Failed to load file");
return CommandResult::ERROR;
}
- if (!tag_stream_scan(uri, print_comment_handler, &client)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "Failed to load file");
+ return CommandResult::OK;
+
+}
+
+static CommandResult
+read_file_comments(Response &r, const Path path_fs)
+{
+ if (!tag_file_scan(path_fs, print_comment_handler, &r)) {
+ r.Error(ACK_ERROR_NO_EXIST, "Failed to load file");
return CommandResult::ERROR;
}
+ tag_ape_scan2(path_fs, &print_comment_handler, &r);
+ tag_id3_scan(path_fs, &print_comment_handler, &r);
+
return CommandResult::OK;
}
static CommandResult
-read_file_comments(Client &client, const Path path_fs)
+read_db_comments(Client &client, Response &r, const char *uri)
{
- if (!tag_file_scan(path_fs, print_comment_handler, &client)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "Failed to load file");
+#ifdef ENABLE_DATABASE
+ const Storage *storage = client.GetStorage();
+ if (storage == nullptr) {
+#else
+ (void)client;
+ (void)uri;
+#endif
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
+#ifdef ENABLE_DATABASE
}
- tag_ape_scan2(path_fs, &print_comment_handler, &client);
- tag_id3_scan(path_fs, &print_comment_handler, &client);
+ {
+ AllocatedPath path_fs = storage->MapFS(uri);
+ if (!path_fs.IsNull())
+ return read_file_comments(r, path_fs);
+ }
- return CommandResult::OK;
+ {
+ const std::string uri2 = storage->MapUTF8(uri);
+ if (uri_has_scheme(uri2.c_str()))
+ return read_stream_comments(r, uri2.c_str());
+ }
+ r.Error(ACK_ERROR_NO_EXIST, "No such file");
+ return CommandResult::ERROR;
+#endif
}
CommandResult
-handle_read_comments(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_read_comments(Client &client, Request args, Response &r)
{
- assert(argc == 2);
+ assert(args.size == 1);
- const char *const uri = argv[1];
+ const char *const uri = args.front();
- if (memcmp(uri, "file:///", 8) == 0) {
- /* read comments from arbitrary local file */
- const char *path_utf8 = uri + 7;
- AllocatedPath path_fs = AllocatedPath::FromUTF8(path_utf8);
- if (path_fs.IsNull()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported file name");
- return CommandResult::ERROR;
- }
-
- Error error;
- if (!client.AllowFile(path_fs, error))
- return print_error(client, error);
-
- return read_file_comments(client, path_fs);
- } else if (uri_has_scheme(uri)) {
- return read_stream_comments(client, uri);
- } else if (!PathTraitsUTF8::IsAbsolute(uri)) {
-#ifdef ENABLE_DATABASE
- const Storage *storage = client.GetStorage();
- if (storage == nullptr) {
-#endif
- command_error(client, ACK_ERROR_NO_EXIST,
- "No database");
- return CommandResult::ERROR;
+ Error error;
+ const auto located_uri = LocateUri(uri, &client,
#ifdef ENABLE_DATABASE
- }
-
- {
- AllocatedPath path_fs = storage->MapFS(uri);
- if (!path_fs.IsNull())
- return read_file_comments(client, path_fs);
- }
-
- {
- const std::string uri2 = storage->MapUTF8(uri);
- if (uri_has_scheme(uri2.c_str()))
- return read_stream_comments(client,
- uri2.c_str());
- }
-
- command_error(client, ACK_ERROR_NO_EXIST, "No such file");
- return CommandResult::ERROR;
+ nullptr,
#endif
- } else {
- command_error(client, ACK_ERROR_NO_EXIST, "No such file");
- return CommandResult::ERROR;
+ error);
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ return print_error(r, error);
+
+ case LocatedUri::Type::ABSOLUTE:
+ return read_stream_comments(r, located_uri.canonical_uri);
+
+ case LocatedUri::Type::RELATIVE:
+ return read_db_comments(client, r, located_uri.canonical_uri);
+
+ case LocatedUri::Type::PATH:
+ return read_file_comments(r, located_uri.path);
}
+
+ gcc_unreachable();
}
diff --git a/src/command/FileCommands.hxx b/src/command/FileCommands.hxx
index 62835a82c..9c6631df5 100644
--- a/src/command/FileCommands.hxx
+++ b/src/command/FileCommands.hxx
@@ -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
@@ -23,11 +23,15 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
+class Path;
CommandResult
-handle_listfiles_local(Client &client, const char *path_utf8);
+handle_listfiles_local(Response &response,
+ const char *path_utf8, Path path_fs);
CommandResult
-handle_read_comments(Client &client, unsigned argc, char *argv[]);
+handle_read_comments(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/MessageCommands.cxx b/src/command/MessageCommands.cxx
index a86bdf30c..28f97a52f 100644
--- a/src/command/MessageCommands.cxx
+++ b/src/command/MessageCommands.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,11 +19,13 @@
#include "config.h"
#include "MessageCommands.hxx"
+#include "Request.hxx"
#include "client/Client.hxx"
#include "client/ClientList.hxx"
+#include "client/Response.hxx"
#include "Instance.hxx"
#include "Partition.hxx"
-#include "protocol/Result.hxx"
+#include "util/ConstBuffer.hxx"
#include <set>
#include <string>
@@ -31,27 +33,25 @@
#include <assert.h>
CommandResult
-handle_subscribe(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_subscribe(Client &client, Request args, Response &r)
{
- assert(argc == 2);
+ assert(args.size == 1);
+ const char *const channel_name = args[0];
- switch (client.Subscribe(argv[1])) {
+ switch (client.Subscribe(channel_name)) {
case Client::SubscribeResult::OK:
return CommandResult::OK;
case Client::SubscribeResult::INVALID:
- command_error(client, ACK_ERROR_ARG,
- "invalid channel name");
+ r.Error(ACK_ERROR_ARG, "invalid channel name");
return CommandResult::ERROR;
case Client::SubscribeResult::ALREADY:
- command_error(client, ACK_ERROR_EXIST,
- "already subscribed to this channel");
+ r.Error(ACK_ERROR_EXIST, "already subscribed to this channel");
return CommandResult::ERROR;
case Client::SubscribeResult::FULL:
- command_error(client, ACK_ERROR_EXIST,
- "subscription list is full");
+ r.Error(ACK_ERROR_EXIST, "subscription list is full");
return CommandResult::ERROR;
}
@@ -61,24 +61,23 @@ handle_subscribe(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_unsubscribe(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_unsubscribe(Client &client, Request args, Response &r)
{
- assert(argc == 2);
+ assert(args.size == 1);
+ const char *const channel_name = args[0];
- if (client.Unsubscribe(argv[1]))
+ if (client.Unsubscribe(channel_name))
return CommandResult::OK;
else {
- command_error(client, ACK_ERROR_NO_EXIST,
- "not subscribed to this channel");
+ r.Error(ACK_ERROR_NO_EXIST, "not subscribed to this channel");
return CommandResult::ERROR;
}
}
CommandResult
-handle_channels(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_channels(Client &client, gcc_unused Request args, Response &r)
{
- assert(argc == 1);
+ assert(args.IsEmpty());
std::set<std::string> channels;
for (const auto &c : *client.partition.instance.client_list)
@@ -86,22 +85,22 @@ handle_channels(Client &client,
c.subscriptions.end());
for (const auto &channel : channels)
- client_printf(client, "channel: %s\n", channel.c_str());
+ r.Format("channel: %s\n", channel.c_str());
return CommandResult::OK;
}
CommandResult
handle_read_messages(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+ gcc_unused Request args, Response &r)
{
- assert(argc == 1);
+ assert(args.IsEmpty());
while (!client.messages.empty()) {
const ClientMessage &msg = client.messages.front();
- client_printf(client, "channel: %s\nmessage: %s\n",
- msg.GetChannel(), msg.GetMessage());
+ r.Format("channel: %s\nmessage: %s\n",
+ msg.GetChannel(), msg.GetMessage());
client.messages.pop_front();
}
@@ -109,19 +108,20 @@ handle_read_messages(Client &client,
}
CommandResult
-handle_send_message(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_send_message(Client &client, Request args, Response &r)
{
- assert(argc == 3);
+ assert(args.size == 2);
- if (!client_message_valid_channel_name(argv[1])) {
- command_error(client, ACK_ERROR_ARG,
- "invalid channel name");
+ const char *const channel_name = args[0];
+ const char *const message_text = args[1];
+
+ if (!client_message_valid_channel_name(channel_name)) {
+ r.Error(ACK_ERROR_ARG, "invalid channel name");
return CommandResult::ERROR;
}
bool sent = false;
- const ClientMessage msg(argv[1], argv[2]);
+ const ClientMessage msg(channel_name, message_text);
for (auto &c : *client.partition.instance.client_list)
if (c.PushMessage(msg))
sent = true;
@@ -129,8 +129,8 @@ handle_send_message(Client &client,
if (sent)
return CommandResult::OK;
else {
- command_error(client, ACK_ERROR_NO_EXIST,
- "nobody is subscribed to this channel");
+ r.Error(ACK_ERROR_NO_EXIST,
+ "nobody is subscribed to this channel");
return CommandResult::ERROR;
}
}
diff --git a/src/command/MessageCommands.hxx b/src/command/MessageCommands.hxx
index ac8afe2fb..986c7cf6a 100644
--- a/src/command/MessageCommands.hxx
+++ b/src/command/MessageCommands.hxx
@@ -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
@@ -23,20 +23,22 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_subscribe(Client &client, unsigned argc, char *argv[]);
+handle_subscribe(Client &client, Request request, Response &response);
CommandResult
-handle_unsubscribe(Client &client, unsigned argc, char *argv[]);
+handle_unsubscribe(Client &client, Request request, Response &response);
CommandResult
-handle_channels(Client &client, unsigned argc, char *argv[]);
+handle_channels(Client &client, Request request, Response &response);
CommandResult
-handle_read_messages(Client &client, unsigned argc, char *argv[]);
+handle_read_messages(Client &client, Request request, Response &response);
CommandResult
-handle_send_message(Client &client, unsigned argc, char *argv[]);
+handle_send_message(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/NeighborCommands.cxx b/src/command/NeighborCommands.cxx
index 22e8adf9e..254f7a346 100644
--- a/src/command/NeighborCommands.cxx
+++ b/src/command/NeighborCommands.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,12 +19,14 @@
#include "config.h"
#include "NeighborCommands.hxx"
+#include "Request.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Instance.hxx"
#include "Partition.hxx"
-#include "protocol/Result.hxx"
#include "neighbor/Glue.hxx"
#include "neighbor/Info.hxx"
+#include "util/ConstBuffer.hxx"
#include <set>
#include <string>
@@ -38,22 +40,19 @@ neighbor_commands_available(const Instance &instance)
}
CommandResult
-handle_listneighbors(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_listneighbors(Client &client, gcc_unused Request args, Response &r)
{
const NeighborGlue *const neighbors =
client.partition.instance.neighbors;
if (neighbors == nullptr) {
- command_error(client, ACK_ERROR_UNKNOWN,
- "No neighbor plugin configured");
+ r.Error(ACK_ERROR_UNKNOWN, "No neighbor plugin configured");
return CommandResult::ERROR;
}
for (const auto &i : neighbors->GetList())
- client_printf(client,
- "neighbor: %s\n"
- "name: %s\n",
- i.uri.c_str(),
- i.display_name.c_str());
+ r.Format("neighbor: %s\n"
+ "name: %s\n",
+ i.uri.c_str(),
+ i.display_name.c_str());
return CommandResult::OK;
}
diff --git a/src/command/NeighborCommands.hxx b/src/command/NeighborCommands.hxx
index 7fb309aeb..efe05c5ae 100644
--- a/src/command/NeighborCommands.hxx
+++ b/src/command/NeighborCommands.hxx
@@ -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
@@ -25,12 +25,14 @@
struct Instance;
class Client;
+class Request;
+class Response;
gcc_pure
bool
neighbor_commands_available(const Instance &instance);
CommandResult
-handle_listneighbors(Client &client, unsigned argc, char *argv[]);
+handle_listneighbors(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/OtherCommands.cxx b/src/command/OtherCommands.cxx
index a924f77b5..b4a23fe4b 100644
--- a/src/command/OtherCommands.cxx
+++ b/src/command/OtherCommands.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,11 +19,13 @@
#include "config.h"
#include "OtherCommands.hxx"
+#include "Request.hxx"
#include "FileCommands.hxx"
#include "StorageCommands.hxx"
#include "CommandError.hxx"
#include "db/Uri.hxx"
#include "storage/StorageInterface.hxx"
+#include "LocateUri.hxx"
#include "DetachedSong.hxx"
#include "SongPrint.hxx"
#include "TagPrint.hxx"
@@ -31,18 +33,19 @@
#include "tag/TagHandler.hxx"
#include "TimePrint.hxx"
#include "decoder/DecoderPrint.hxx"
-#include "protocol/ArgParser.hxx"
-#include "protocol/Result.hxx"
#include "ls.hxx"
#include "mixer/Volume.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
+#include "util/StringAPI.hxx"
#include "fs/AllocatedPath.hxx"
#include "Stats.hxx"
#include "Permission.hxx"
#include "PlaylistFile.hxx"
#include "db/PlaylistVector.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "Idle.hxx"
@@ -57,52 +60,51 @@
#include <string.h>
static void
-print_spl_list(Client &client, const PlaylistVector &list)
+print_spl_list(Response &r, const PlaylistVector &list)
{
for (const auto &i : list) {
- client_printf(client, "playlist: %s\n", i.name.c_str());
+ r.Format("playlist: %s\n", i.name.c_str());
if (i.mtime > 0)
- time_print(client, "Last-Modified", i.mtime);
+ time_print(r, "Last-Modified", i.mtime);
}
}
CommandResult
-handle_urlhandlers(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_urlhandlers(Client &client, gcc_unused Request args, Response &r)
{
if (client.IsLocal())
- client_puts(client, "handler: file://\n");
- print_supported_uri_schemes(client);
+ r.Format("handler: file://\n");
+ print_supported_uri_schemes(r);
return CommandResult::OK;
}
CommandResult
-handle_decoders(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_decoders(gcc_unused Client &client, gcc_unused Request args,
+ Response &r)
{
- decoder_list_print(client);
+ decoder_list_print(r);
return CommandResult::OK;
}
CommandResult
-handle_tagtypes(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_tagtypes(gcc_unused Client &client, gcc_unused Request request,
+ Response &r)
{
- tag_print_types(client);
+ tag_print_types(r);
return CommandResult::OK;
}
CommandResult
-handle_kill(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_kill(gcc_unused Client &client, gcc_unused Request request,
+ gcc_unused Response &r)
{
return CommandResult::KILL;
}
CommandResult
-handle_close(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_close(gcc_unused Client &client, gcc_unused Request args,
+ gcc_unused Response &r)
{
return CommandResult::FINISH;
}
@@ -110,44 +112,60 @@ handle_close(gcc_unused Client &client,
static void
print_tag(TagType type, const char *value, void *ctx)
{
- Client &client = *(Client *)ctx;
+ auto &r = *(Response *)ctx;
- tag_print(client, type, value);
+ tag_print(r, type, value);
}
CommandResult
-handle_listfiles(Client &client, unsigned argc, char *argv[])
+handle_listfiles(Client &client, Request args, Response &r)
{
- const char *const uri = argc == 2
- ? argv[1]
- /* default is root directory */
- : "";
-
- if (memcmp(uri, "file:///", 8) == 0)
- /* list local directory */
- return handle_listfiles_local(client, uri + 7);
+ /* default is root directory */
+ const auto uri = args.GetOptional(0, "");
+ Error error;
+ const auto located_uri = LocateUri(uri, &client,
#ifdef ENABLE_DATABASE
- if (uri_has_scheme(uri))
- /* use storage plugin to list remote directory */
- return handle_listfiles_storage(client, uri);
+ nullptr,
+#endif
+ error);
- /* must be a path relative to the configured
- music_directory */
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ return print_error(r, error);
- if (client.partition.instance.storage != nullptr)
- /* if we have a storage instance, obtain a list of
- files from it */
- return handle_listfiles_storage(client,
- *client.partition.instance.storage,
- uri);
+ case LocatedUri::Type::ABSOLUTE:
+#ifdef ENABLE_DATABASE
+ /* use storage plugin to list remote directory */
+ return handle_listfiles_storage(r, located_uri.canonical_uri);
+#else
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
+#endif
- /* fall back to entries from database if we have no storage */
- return handle_listfiles_db(client, uri);
+ case LocatedUri::Type::RELATIVE:
+#ifdef ENABLE_DATABASE
+ if (client.partition.instance.storage != nullptr)
+ /* if we have a storage instance, obtain a list of
+ files from it */
+ return handle_listfiles_storage(r,
+ *client.partition.instance.storage,
+ uri);
+
+ /* fall back to entries from database if we have no storage */
+ return handle_listfiles_db(client, r, uri);
#else
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
- return CommandResult::ERROR;
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
#endif
+
+ case LocatedUri::Type::PATH:
+ /* list local directory */
+ return handle_listfiles_local(r, located_uri.canonical_uri,
+ located_uri.path);
+ }
+
+ gcc_unreachable();
}
static constexpr tag_handler print_tag_handler = {
@@ -156,69 +174,35 @@ static constexpr tag_handler print_tag_handler = {
nullptr,
};
-CommandResult
-handle_lsinfo(Client &client, unsigned argc, char *argv[])
+static CommandResult
+handle_lsinfo_absolute(Response &r, const char *uri)
{
- const char *const uri = argc == 2
- ? argv[1]
- /* default is root directory */
- : "";
-
- if (memcmp(uri, "file:///", 8) == 0) {
- /* print information about an arbitrary local file */
- const char *path_utf8 = uri + 7;
- const auto path_fs = AllocatedPath::FromUTF8(path_utf8);
-
- if (path_fs.IsNull()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported file name");
- return CommandResult::ERROR;
- }
-
- Error error;
- if (!client.AllowFile(path_fs, error))
- return print_error(client, error);
-
- DetachedSong song(path_utf8);
- if (!song.Update()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such file");
- return CommandResult::ERROR;
- }
-
- song_print_info(client, song);
- return CommandResult::OK;
+ if (!tag_stream_scan(uri, print_tag_handler, &r)) {
+ r.Error(ACK_ERROR_NO_EXIST, "No such file");
+ return CommandResult::ERROR;
}
- if (uri_has_scheme(uri)) {
- if (!uri_supported_scheme(uri)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported URI scheme");
- return CommandResult::ERROR;
- }
-
- if (!tag_stream_scan(uri, print_tag_handler, &client)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such file");
- return CommandResult::ERROR;
- }
-
- return CommandResult::OK;
- }
+ return CommandResult::OK;
+}
+static CommandResult
+handle_lsinfo_relative(Client &client, Response &r, const char *uri)
+{
#ifdef ENABLE_DATABASE
- CommandResult result = handle_lsinfo2(client, argc, argv);
+ CommandResult result = handle_lsinfo2(client, uri, r);
if (result != CommandResult::OK)
return result;
+#else
+ (void)client;
#endif
if (isRootDirectory(uri)) {
Error error;
const auto &list = ListPlaylistFiles(error);
- print_spl_list(client, list);
+ print_spl_list(r, list);
} else {
#ifndef ENABLE_DATABASE
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
#endif
}
@@ -226,38 +210,84 @@ handle_lsinfo(Client &client, unsigned argc, char *argv[])
return CommandResult::OK;
}
+static CommandResult
+handle_lsinfo_path(Client &client, Response &r,
+ const char *path_utf8, Path path_fs)
+{
+ DetachedSong song(path_utf8);
+ if (!song.LoadFile(path_fs)) {
+ r.Error(ACK_ERROR_NO_EXIST, "No such file");
+ return CommandResult::ERROR;
+ }
+
+ song_print_info(r, client.partition, song);
+ return CommandResult::OK;
+}
+
+CommandResult
+handle_lsinfo(Client &client, Request args, Response &r)
+{
+ /* default is root directory */
+ const auto uri = args.GetOptional(0, "");
+
+ Error error;
+ const auto located_uri = LocateUri(uri, &client,
+#ifdef ENABLE_DATABASE
+ nullptr,
+#endif
+ error);
+
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ return print_error(r, error);
+
+ case LocatedUri::Type::ABSOLUTE:
+ return handle_lsinfo_absolute(r, located_uri.canonical_uri);
+
+ case LocatedUri::Type::RELATIVE:
+ return handle_lsinfo_relative(client, r,
+ located_uri.canonical_uri);
+
+ case LocatedUri::Type::PATH:
+ /* print information about an arbitrary local file */
+ return handle_lsinfo_path(client, r, located_uri.canonical_uri,
+ located_uri.path);
+ }
+
+ gcc_unreachable();
+}
+
#ifdef ENABLE_DATABASE
static CommandResult
-handle_update(Client &client, UpdateService &update,
+handle_update(Response &r, UpdateService &update,
const char *uri_utf8, bool discard)
{
unsigned ret = update.Enqueue(uri_utf8, discard);
if (ret > 0) {
- client_printf(client, "updating_db: %i\n", ret);
+ r.Format("updating_db: %i\n", ret);
return CommandResult::OK;
} else {
- command_error(client, ACK_ERROR_UPDATE_ALREADY,
- "already updating");
+ r.Error(ACK_ERROR_UPDATE_ALREADY, "already updating");
return CommandResult::ERROR;
}
}
static CommandResult
-handle_update(Client &client, Database &db,
+handle_update(Response &r, Database &db,
const char *uri_utf8, bool discard)
{
Error error;
unsigned id = db.Update(uri_utf8, discard, error);
if (id > 0) {
- client_printf(client, "updating_db: %i\n", id);
+ r.Format("updating_db: %i\n", id);
return CommandResult::OK;
} else if (error.IsDefined()) {
- return print_error(client, error);
+ return print_error(r, error);
} else {
/* Database::Update() has returned 0 without setting
the Error: the method is not implemented */
- command_error(client, ACK_ERROR_NO_EXIST, "Not implemented");
+ r.Error(ACK_ERROR_NO_EXIST, "Not implemented");
return CommandResult::ERROR;
}
}
@@ -265,72 +295,62 @@ handle_update(Client &client, Database &db,
#endif
static CommandResult
-handle_update(Client &client, unsigned argc, char *argv[], bool discard)
+handle_update(Client &client, Request args, Response &r, bool discard)
{
#ifdef ENABLE_DATABASE
const char *path = "";
- assert(argc <= 2);
- if (argc == 2) {
- path = argv[1];
+ assert(args.size <= 1);
+ if (!args.IsEmpty()) {
+ path = args.front();
- if (*path == 0 || strcmp(path, "/") == 0)
+ if (*path == 0 || StringIsEqual(path, "/"))
/* backwards compatibility with MPD 0.15 */
path = "";
else if (!uri_safe_local(path)) {
- command_error(client, ACK_ERROR_ARG,
- "Malformed path");
+ r.Error(ACK_ERROR_ARG, "Malformed path");
return CommandResult::ERROR;
}
}
UpdateService *update = client.partition.instance.update;
if (update != nullptr)
- return handle_update(client, *update, path, discard);
+ return handle_update(r, *update, path, discard);
Database *db = client.partition.instance.database;
if (db != nullptr)
- return handle_update(client, *db, path, discard);
+ return handle_update(r, *db, path, discard);
#else
- (void)argc;
- (void)argv;
+ (void)client;
+ (void)args;
(void)discard;
#endif
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
}
CommandResult
-handle_update(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_update(Client &client, Request args, gcc_unused Response &r)
{
- return handle_update(client, argc, argv, false);
+ return handle_update(client, args, r, false);
}
CommandResult
-handle_rescan(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_rescan(Client &client, Request args, Response &r)
{
- return handle_update(client, argc, argv, true);
+ return handle_update(client, args, r, true);
}
CommandResult
-handle_setvol(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_setvol(Client &client, Request args, Response &r)
{
unsigned level;
- bool success;
-
- if (!check_unsigned(client, &level, argv[1]))
+ if (!args.Parse(0, level, r, 100))
return CommandResult::ERROR;
- if (level > 100) {
- command_error(client, ACK_ERROR_ARG, "Invalid volume value");
- return CommandResult::ERROR;
- }
-
- success = volume_level_change(client.partition.outputs, level);
- if (!success) {
- command_error(client, ACK_ERROR_SYSTEM,
- "problems setting volume");
+ if (!volume_level_change(client.partition.outputs, level)) {
+ r.Error(ACK_ERROR_SYSTEM, "problems setting volume");
return CommandResult::ERROR;
}
@@ -338,20 +358,15 @@ handle_setvol(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_volume(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_volume(Client &client, Request args, Response &r)
{
int relative;
- if (!check_int(client, &relative, argv[1]))
+ if (!args.Parse(0, relative, r, -100, 100))
return CommandResult::ERROR;
- if (relative < -100 || relative > 100) {
- command_error(client, ACK_ERROR_ARG, "Invalid volume value");
- return CommandResult::ERROR;
- }
-
const int old_volume = volume_level_get(client.partition.outputs);
if (old_volume < 0) {
- command_error(client, ACK_ERROR_SYSTEM, "No mixer");
+ r.Error(ACK_ERROR_SYSTEM, "No mixer");
return CommandResult::ERROR;
}
@@ -363,8 +378,7 @@ handle_volume(Client &client, gcc_unused unsigned argc, char *argv[])
if (new_volume != old_volume &&
!volume_level_change(client.partition.outputs, new_volume)) {
- command_error(client, ACK_ERROR_SYSTEM,
- "problems setting volume");
+ r.Error(ACK_ERROR_SYSTEM, "problems setting volume");
return CommandResult::ERROR;
}
@@ -372,27 +386,25 @@ handle_volume(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_stats(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_stats(Client &client, gcc_unused Request args, Response &r)
{
- stats_print(client);
+ stats_print(r, client.partition);
return CommandResult::OK;
}
CommandResult
-handle_ping(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_ping(gcc_unused Client &client, gcc_unused Request args,
+ gcc_unused Response &r)
{
return CommandResult::OK;
}
CommandResult
-handle_password(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_password(Client &client, Request args, Response &r)
{
unsigned permission = 0;
-
- if (getPermissionFromPassword(argv[1], &permission) < 0) {
- command_error(client, ACK_ERROR_PASSWORD, "incorrect password");
+ if (getPermissionFromPassword(args.front(), &permission) < 0) {
+ r.Error(ACK_ERROR_PASSWORD, "incorrect password");
return CommandResult::ERROR;
}
@@ -402,12 +414,11 @@ handle_password(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_config(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_config(Client &client, gcc_unused Request args, Response &r)
{
if (!client.IsLocal()) {
- command_error(client, ACK_ERROR_PERMISSION,
- "Command only permitted to local clients");
+ r.Error(ACK_ERROR_PERMISSION,
+ "Command only permitted to local clients");
return CommandResult::ERROR;
}
@@ -415,7 +426,7 @@ handle_config(Client &client,
const Storage *storage = client.GetStorage();
if (storage != nullptr) {
const auto path = storage->MapUTF8("");
- client_printf(client, "music_directory: %s\n", path.c_str());
+ r.Format("music_directory: %s\n", path.c_str());
}
#endif
@@ -423,17 +434,14 @@ handle_config(Client &client,
}
CommandResult
-handle_idle(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_idle(Client &client, Request args, Response &r)
{
unsigned flags = 0;
-
- for (unsigned i = 1; i < argc; ++i) {
- unsigned event = idle_parse_name(argv[i]);
+ for (const char *i : args) {
+ unsigned event = idle_parse_name(i);
if (event == 0) {
- command_error(client, ACK_ERROR_ARG,
- "Unrecognized idle event: %s",
- argv[i]);
+ r.FormatError(ACK_ERROR_ARG,
+ "Unrecognized idle event: %s", i);
return CommandResult::ERROR;
}
diff --git a/src/command/OtherCommands.hxx b/src/command/OtherCommands.hxx
index 7cfa35dfb..2a918df97 100644
--- a/src/command/OtherCommands.hxx
+++ b/src/command/OtherCommands.hxx
@@ -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
@@ -23,53 +23,55 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_urlhandlers(Client &client, unsigned argc, char *argv[]);
+handle_urlhandlers(Client &client, Request request, Response &response);
CommandResult
-handle_decoders(Client &client, unsigned argc, char *argv[]);
+handle_decoders(Client &client, Request request, Response &response);
CommandResult
-handle_tagtypes(Client &client, unsigned argc, char *argv[]);
+handle_tagtypes(Client &client, Request request, Response &response);
CommandResult
-handle_kill(Client &client, unsigned argc, char *argv[]);
+handle_kill(Client &client, Request request, Response &response);
CommandResult
-handle_close(Client &client, unsigned argc, char *argv[]);
+handle_close(Client &client, Request request, Response &response);
CommandResult
-handle_listfiles(Client &client, unsigned argc, char *argv[]);
+handle_listfiles(Client &client, Request request, Response &response);
CommandResult
-handle_lsinfo(Client &client, unsigned argc, char *argv[]);
+handle_lsinfo(Client &client, Request request, Response &response);
CommandResult
-handle_update(Client &client, unsigned argc, char *argv[]);
+handle_update(Client &client, Request request, Response &response);
CommandResult
-handle_rescan(Client &client, unsigned argc, char *argv[]);
+handle_rescan(Client &client, Request request, Response &response);
CommandResult
-handle_setvol(Client &client, unsigned argc, char *argv[]);
+handle_setvol(Client &client, Request request, Response &response);
CommandResult
-handle_volume(Client &client, unsigned argc, char *argv[]);
+handle_volume(Client &client, Request request, Response &response);
CommandResult
-handle_stats(Client &client, unsigned argc, char *argv[]);
+handle_stats(Client &client, Request request, Response &response);
CommandResult
-handle_ping(Client &client, unsigned argc, char *argv[]);
+handle_ping(Client &client, Request request, Response &response);
CommandResult
-handle_password(Client &client, unsigned argc, char *argv[]);
+handle_password(Client &client, Request request, Response &response);
CommandResult
-handle_config(Client &client, unsigned argc, char *argv[]);
+handle_config(Client &client, Request request, Response &response);
CommandResult
-handle_idle(Client &client, unsigned argc, char *argv[]);
+handle_idle(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/OutputCommands.cxx b/src/command/OutputCommands.cxx
index c69a0dd65..7bbe5f905 100644
--- a/src/command/OutputCommands.cxx
+++ b/src/command/OutputCommands.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,23 +19,24 @@
#include "config.h"
#include "OutputCommands.hxx"
+#include "Request.hxx"
#include "output/OutputPrint.hxx"
#include "output/OutputCommand.hxx"
-#include "protocol/Result.hxx"
-#include "protocol/ArgParser.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
+#include "util/ConstBuffer.hxx"
CommandResult
-handle_enableoutput(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_enableoutput(Client &client, Request args, Response &r)
{
+ assert(args.size == 1);
unsigned device;
- if (!check_unsigned(client, &device, argv[1]))
+ if (!args.Parse(0, device, r))
return CommandResult::ERROR;
if (!audio_output_enable_index(client.partition.outputs, device)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such audio output");
+ r.Error(ACK_ERROR_NO_EXIST, "No such audio output");
return CommandResult::ERROR;
}
@@ -43,15 +44,15 @@ handle_enableoutput(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_disableoutput(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_disableoutput(Client &client, Request args, Response &r)
{
+ assert(args.size == 1);
unsigned device;
- if (!check_unsigned(client, &device, argv[1]))
+ if (!args.Parse(0, device, r))
return CommandResult::ERROR;
if (!audio_output_disable_index(client.partition.outputs, device)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such audio output");
+ r.Error(ACK_ERROR_NO_EXIST, "No such audio output");
return CommandResult::ERROR;
}
@@ -59,15 +60,15 @@ handle_disableoutput(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_toggleoutput(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_toggleoutput(Client &client, Request args, Response &r)
{
+ assert(args.size == 1);
unsigned device;
- if (!check_unsigned(client, &device, argv[1]))
+ if (!args.Parse(0, device, r))
return CommandResult::ERROR;
if (!audio_output_toggle_index(client.partition.outputs, device)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such audio output");
+ r.Error(ACK_ERROR_NO_EXIST, "No such audio output");
return CommandResult::ERROR;
}
@@ -75,10 +76,10 @@ handle_toggleoutput(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_devices(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_devices(Client &client, gcc_unused Request args, Response &r)
{
- printAudioDevices(client, client.partition.outputs);
+ assert(args.IsEmpty());
+ printAudioDevices(r, client.partition.outputs);
return CommandResult::OK;
}
diff --git a/src/command/OutputCommands.hxx b/src/command/OutputCommands.hxx
index 8d6be0511..3dd81bc23 100644
--- a/src/command/OutputCommands.hxx
+++ b/src/command/OutputCommands.hxx
@@ -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
@@ -23,17 +23,19 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_enableoutput(Client &client, unsigned argc, char *argv[]);
+handle_enableoutput(Client &client, Request request, Response &response);
CommandResult
-handle_disableoutput(Client &client, unsigned argc, char *argv[]);
+handle_disableoutput(Client &client, Request request, Response &response);
CommandResult
-handle_toggleoutput(Client &client, unsigned argc, char *argv[]);
+handle_toggleoutput(Client &client, Request request, Response &response);
CommandResult
-handle_devices(Client &client, unsigned argc, char *argv[]);
+handle_devices(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx
index cd7f42289..11cde2e98 100644
--- a/src/command/PlayerCommands.cxx
+++ b/src/command/PlayerCommands.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,17 +19,18 @@
#include "config.h"
#include "PlayerCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
#include "queue/Playlist.hxx"
#include "PlaylistPrint.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "mixer/Volume.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
-#include "protocol/Result.hxx"
-#include "protocol/ArgParser.hxx"
#include "AudioFormat.hxx"
#include "ReplayGainConfig.hxx"
+#include "util/ConstBuffer.hxx"
#ifdef ENABLE_DATABASE
#include "db/update/Service.hxx"
@@ -56,51 +57,47 @@
#define COMMAND_STATUS_UPDATING_DB "updating_db"
CommandResult
-handle_play(Client &client, unsigned argc, char *argv[])
+handle_play(Client &client, Request args, Response &r)
{
int song = -1;
-
- if (argc == 2 && !check_int(client, &song, argv[1]))
+ if (!args.ParseOptional(0, song, r))
return CommandResult::ERROR;
+
PlaylistResult result = client.partition.PlayPosition(song);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_playid(Client &client, unsigned argc, char *argv[])
+handle_playid(Client &client, Request args, Response &r)
{
int id = -1;
-
- if (argc == 2 && !check_int(client, &id, argv[1]))
+ if (!args.ParseOptional(0, id, r))
return CommandResult::ERROR;
PlaylistResult result = client.partition.PlayId(id);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_stop(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_stop(Client &client, gcc_unused Request args, gcc_unused Response &r)
{
client.partition.Stop();
return CommandResult::OK;
}
CommandResult
-handle_currentsong(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_currentsong(Client &client, gcc_unused Request args, Response &r)
{
- playlist_print_current(client, client.playlist);
+ playlist_print_current(r, client.partition, client.playlist);
return CommandResult::OK;
}
CommandResult
-handle_pause(Client &client,
- unsigned argc, char *argv[])
+handle_pause(Client &client, Request args, Response &r)
{
- if (argc == 2) {
+ if (!args.IsEmpty()) {
bool pause_flag;
- if (!check_bool(client, &pause_flag, argv[1]))
+ if (!args.Parse(0, pause_flag, r))
return CommandResult::ERROR;
client.player_control.SetPause(pause_flag);
@@ -111,8 +108,7 @@ handle_pause(Client &client,
}
CommandResult
-handle_status(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_status(Client &client, gcc_unused Request args, Response &r)
{
const char *state = nullptr;
int song;
@@ -132,63 +128,61 @@ handle_status(Client &client,
}
const playlist &playlist = client.playlist;
- client_printf(client,
- "volume: %i\n"
- COMMAND_STATUS_REPEAT ": %i\n"
- COMMAND_STATUS_RANDOM ": %i\n"
- COMMAND_STATUS_SINGLE ": %i\n"
- COMMAND_STATUS_CONSUME ": %i\n"
- COMMAND_STATUS_PLAYLIST ": %li\n"
- COMMAND_STATUS_PLAYLIST_LENGTH ": %i\n"
- COMMAND_STATUS_MIXRAMPDB ": %f\n"
- COMMAND_STATUS_STATE ": %s\n",
- volume_level_get(client.partition.outputs),
- playlist.GetRepeat(),
- playlist.GetRandom(),
- playlist.GetSingle(),
- playlist.GetConsume(),
- (unsigned long)playlist.GetVersion(),
- playlist.GetLength(),
- client.player_control.GetMixRampDb(),
- state);
+ r.Format("volume: %i\n"
+ COMMAND_STATUS_REPEAT ": %i\n"
+ COMMAND_STATUS_RANDOM ": %i\n"
+ COMMAND_STATUS_SINGLE ": %i\n"
+ COMMAND_STATUS_CONSUME ": %i\n"
+ COMMAND_STATUS_PLAYLIST ": %li\n"
+ COMMAND_STATUS_PLAYLIST_LENGTH ": %i\n"
+ COMMAND_STATUS_MIXRAMPDB ": %f\n"
+ COMMAND_STATUS_STATE ": %s\n",
+ volume_level_get(client.partition.outputs),
+ playlist.GetRepeat(),
+ playlist.GetRandom(),
+ playlist.GetSingle(),
+ playlist.GetConsume(),
+ (unsigned long)playlist.GetVersion(),
+ playlist.GetLength(),
+ client.player_control.GetMixRampDb(),
+ state);
if (client.player_control.GetCrossFade() > 0)
- client_printf(client,
- COMMAND_STATUS_CROSSFADE ": %i\n",
- int(client.player_control.GetCrossFade() + 0.5));
+ r.Format(COMMAND_STATUS_CROSSFADE ": %i\n",
+ int(client.player_control.GetCrossFade() + 0.5));
if (client.player_control.GetMixRampDelay() > 0)
- client_printf(client,
- COMMAND_STATUS_MIXRAMPDELAY ": %f\n",
- client.player_control.GetMixRampDelay());
+ r.Format(COMMAND_STATUS_MIXRAMPDELAY ": %f\n",
+ client.player_control.GetMixRampDelay());
song = playlist.GetCurrentPosition();
if (song >= 0) {
- client_printf(client,
- COMMAND_STATUS_SONG ": %i\n"
- COMMAND_STATUS_SONGID ": %u\n",
- song, playlist.PositionToId(song));
+ r.Format(COMMAND_STATUS_SONG ": %i\n"
+ COMMAND_STATUS_SONGID ": %u\n",
+ song, playlist.PositionToId(song));
}
if (player_status.state != PlayerState::STOP) {
- client_printf(client,
- COMMAND_STATUS_TIME ": %i:%i\n"
- "elapsed: %1.3f\n"
- COMMAND_STATUS_BITRATE ": %u\n",
- player_status.elapsed_time.RoundS(),
- player_status.total_time.IsNegative()
- ? 0u
- : unsigned(player_status.total_time.RoundS()),
- player_status.elapsed_time.ToDoubleS(),
- player_status.bit_rate);
+ r.Format(COMMAND_STATUS_TIME ": %i:%i\n"
+ "elapsed: %1.3f\n"
+ COMMAND_STATUS_BITRATE ": %u\n",
+ player_status.elapsed_time.RoundS(),
+ player_status.total_time.IsNegative()
+ ? 0u
+ : unsigned(player_status.total_time.RoundS()),
+ player_status.elapsed_time.ToDoubleS(),
+ player_status.bit_rate);
+
+ if (!player_status.total_time.IsNegative())
+ r.Format("duration: %1.3f\n",
+ player_status.total_time.ToDoubleS());
if (player_status.audio_format.IsDefined()) {
struct audio_format_string af_string;
- client_printf(client,
- COMMAND_STATUS_AUDIO ": %s\n",
- audio_format_to_string(player_status.audio_format,
- &af_string));
+ r.Format(COMMAND_STATUS_AUDIO ": %s\n",
+ audio_format_to_string(player_status.audio_format,
+ &af_string));
}
}
@@ -198,32 +192,27 @@ handle_status(Client &client,
? update_service->GetId()
: 0;
if (updateJobId != 0) {
- client_printf(client,
- COMMAND_STATUS_UPDATING_DB ": %i\n",
- updateJobId);
+ r.Format(COMMAND_STATUS_UPDATING_DB ": %i\n",
+ updateJobId);
}
#endif
Error error = client.player_control.LockGetError();
if (error.IsDefined())
- client_printf(client,
- COMMAND_STATUS_ERROR ": %s\n",
- error.GetMessage());
+ r.Format(COMMAND_STATUS_ERROR ": %s\n",
+ error.GetMessage());
song = playlist.GetNextPosition();
- if (song >= 0) {
- client_printf(client,
- COMMAND_STATUS_NEXTSONG ": %i\n"
- COMMAND_STATUS_NEXTSONGID ": %u\n",
- song, playlist.PositionToId(song));
- }
+ if (song >= 0)
+ r.Format(COMMAND_STATUS_NEXTSONG ": %i\n"
+ COMMAND_STATUS_NEXTSONGID ": %u\n",
+ song, playlist.PositionToId(song));
return CommandResult::OK;
}
CommandResult
-handle_next(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_next(Client &client, gcc_unused Request args, gcc_unused Response &r)
{
playlist &playlist = client.playlist;
@@ -239,18 +228,18 @@ handle_next(Client &client,
}
CommandResult
-handle_previous(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_previous(Client &client, gcc_unused Request args,
+ gcc_unused Response &r)
{
client.partition.PlayPrevious();
return CommandResult::OK;
}
CommandResult
-handle_repeat(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_repeat(Client &client, Request args, Response &r)
{
bool status;
- if (!check_bool(client, &status, argv[1]))
+ if (!args.Parse(0, status, r))
return CommandResult::ERROR;
client.partition.SetRepeat(status);
@@ -258,10 +247,10 @@ handle_repeat(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_single(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_single(Client &client, Request args, Response &r)
{
bool status;
- if (!check_bool(client, &status, argv[1]))
+ if (!args.Parse(0, status, r))
return CommandResult::ERROR;
client.partition.SetSingle(status);
@@ -269,10 +258,10 @@ handle_single(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_consume(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_consume(Client &client, Request args, Response &r)
{
bool status;
- if (!check_bool(client, &status, argv[1]))
+ if (!args.Parse(0, status, r))
return CommandResult::ERROR;
client.partition.SetConsume(status);
@@ -280,10 +269,10 @@ handle_consume(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_random(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_random(Client &client, Request args, Response &r)
{
bool status;
- if (!check_bool(client, &status, argv[1]))
+ if (!args.Parse(0, status, r))
return CommandResult::ERROR;
client.partition.SetRandom(status);
@@ -292,102 +281,94 @@ handle_random(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_clearerror(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_clearerror(Client &client, gcc_unused Request args,
+ gcc_unused Response &r)
{
client.player_control.ClearError();
return CommandResult::OK;
}
CommandResult
-handle_seek(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_seek(Client &client, Request args, Response &r)
{
unsigned song;
SongTime seek_time;
-
- if (!check_unsigned(client, &song, argv[1]))
- return CommandResult::ERROR;
- if (!ParseCommandArg(client, seek_time, argv[2]))
+ if (!args.Parse(0, song, r) || !args.Parse(1, seek_time, r))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SeekSongPosition(song, seek_time);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_seekid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_seekid(Client &client, Request args, Response &r)
{
unsigned id;
SongTime seek_time;
-
- if (!check_unsigned(client, &id, argv[1]))
+ if (!args.Parse(0, id, r))
return CommandResult::ERROR;
- if (!ParseCommandArg(client, seek_time, argv[2]))
+ if (!args.Parse(1, seek_time, r))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SeekSongId(id, seek_time);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_seekcur(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_seekcur(Client &client, Request args, Response &r)
{
- const char *p = argv[1];
+ const char *p = args.front();
bool relative = *p == '+' || *p == '-';
SignedSongTime seek_time;
- if (!ParseCommandArg(client, seek_time, p))
+ if (!ParseCommandArg(r, seek_time, p))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SeekCurrent(seek_time, relative);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_crossfade(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_crossfade(Client &client, Request args, Response &r)
{
unsigned xfade_time;
-
- if (!check_unsigned(client, &xfade_time, argv[1]))
+ if (!args.Parse(0, xfade_time, r))
return CommandResult::ERROR;
- client.player_control.SetCrossFade(xfade_time);
+ client.player_control.SetCrossFade(xfade_time);
return CommandResult::OK;
}
CommandResult
-handle_mixrampdb(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_mixrampdb(Client &client, Request args, Response &r)
{
float db;
-
- if (!check_float(client, &db, argv[1]))
+ if (!args.Parse(0, db, r))
return CommandResult::ERROR;
- client.player_control.SetMixRampDb(db);
+ client.player_control.SetMixRampDb(db);
return CommandResult::OK;
}
CommandResult
-handle_mixrampdelay(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_mixrampdelay(Client &client, Request args, Response &r)
{
float delay_secs;
-
- if (!check_float(client, &delay_secs, argv[1]))
+ if (!args.Parse(0, delay_secs, r))
return CommandResult::ERROR;
+
client.player_control.SetMixRampDelay(delay_secs);
return CommandResult::OK;
}
CommandResult
-handle_replay_gain_mode(Client &client,
- gcc_unused unsigned argc, char *argv[])
+handle_replay_gain_mode(Client &client, Request args, Response &r)
{
- if (!replay_gain_set_mode_string(argv[1])) {
- command_error(client, ACK_ERROR_ARG,
- "Unrecognized replay gain mode");
+ if (!replay_gain_set_mode_string(args.front())) {
+ r.Error(ACK_ERROR_ARG, "Unrecognized replay gain mode");
return CommandResult::ERROR;
}
@@ -396,10 +377,9 @@ handle_replay_gain_mode(Client &client,
}
CommandResult
-handle_replay_gain_status(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_replay_gain_status(gcc_unused Client &client, gcc_unused Request args,
+ Response &r)
{
- client_printf(client, "replay_gain_mode: %s\n",
- replay_gain_get_mode_string());
+ r.Format("replay_gain_mode: %s\n", replay_gain_get_mode_string());
return CommandResult::OK;
}
diff --git a/src/command/PlayerCommands.hxx b/src/command/PlayerCommands.hxx
index da7083f1e..76ce51ef5 100644
--- a/src/command/PlayerCommands.hxx
+++ b/src/command/PlayerCommands.hxx
@@ -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
@@ -23,68 +23,70 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_play(Client &client, unsigned argc, char *argv[]);
+handle_play(Client &client, Request request, Response &response);
CommandResult
-handle_playid(Client &client, unsigned argc, char *argv[]);
+handle_playid(Client &client, Request request, Response &response);
CommandResult
-handle_stop(Client &client, unsigned argc, char *argv[]);
+handle_stop(Client &client, Request request, Response &response);
CommandResult
-handle_currentsong(Client &client, unsigned argc, char *argv[]);
+handle_currentsong(Client &client, Request request, Response &response);
CommandResult
-handle_pause(Client &client, unsigned argc, char *argv[]);
+handle_pause(Client &client, Request request, Response &response);
CommandResult
-handle_status(Client &client, unsigned argc, char *argv[]);
+handle_status(Client &client, Request request, Response &response);
CommandResult
-handle_next(Client &client, unsigned argc, char *argv[]);
+handle_next(Client &client, Request request, Response &response);
CommandResult
-handle_previous(Client &client, unsigned argc, char *avg[]);
+handle_previous(Client &client, Request request, Response &response);
CommandResult
-handle_repeat(Client &client, unsigned argc, char *argv[]);
+handle_repeat(Client &client, Request request, Response &response);
CommandResult
-handle_single(Client &client, unsigned argc, char *argv[]);
+handle_single(Client &client, Request request, Response &response);
CommandResult
-handle_consume(Client &client, unsigned argc, char *argv[]);
+handle_consume(Client &client, Request request, Response &response);
CommandResult
-handle_random(Client &client, unsigned argc, char *argv[]);
+handle_random(Client &client, Request request, Response &response);
CommandResult
-handle_clearerror(Client &client, unsigned argc, char *argv[]);
+handle_clearerror(Client &client, Request request, Response &response);
CommandResult
-handle_seek(Client &client, unsigned argc, char *argv[]);
+handle_seek(Client &client, Request request, Response &response);
CommandResult
-handle_seekid(Client &client, unsigned argc, char *argv[]);
+handle_seekid(Client &client, Request request, Response &response);
CommandResult
-handle_seekcur(Client &client, unsigned argc, char *argv[]);
+handle_seekcur(Client &client, Request request, Response &response);
CommandResult
-handle_crossfade(Client &client, unsigned argc, char *argv[]);
+handle_crossfade(Client &client, Request request, Response &response);
CommandResult
-handle_mixrampdb(Client &client, unsigned argc, char *argv[]);
+handle_mixrampdb(Client &client, Request request, Response &response);
CommandResult
-handle_mixrampdelay(Client &client, unsigned argc, char *argv[]);
+handle_mixrampdelay(Client &client, Request request, Response &response);
CommandResult
-handle_replay_gain_mode(Client &client, unsigned argc, char *argv[]);
+handle_replay_gain_mode(Client &client, Request request, Response &response);
CommandResult
-handle_replay_gain_status(Client &client, unsigned argc, char *argv[]);
+handle_replay_gain_status(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx
index c2b18064c..625e82055 100644
--- a/src/command/PlaylistCommands.cxx
+++ b/src/command/PlaylistCommands.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 "PlaylistCommands.hxx"
+#include "Request.hxx"
#include "db/DatabasePlaylist.hxx"
#include "CommandError.hxx"
#include "PlaylistPrint.hxx"
@@ -32,143 +33,157 @@
#include "queue/Playlist.hxx"
#include "TimePrint.hxx"
#include "client/Client.hxx"
-#include "protocol/ArgParser.hxx"
-#include "protocol/Result.hxx"
+#include "client/Response.hxx"
#include "ls.hxx"
+#include "Mapper.hxx"
+#include "fs/AllocatedPath.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
+
+bool
+playlist_commands_available()
+{
+ return !map_spl_path().IsNull();
+}
static void
-print_spl_list(Client &client, const PlaylistVector &list)
+print_spl_list(Response &r, const PlaylistVector &list)
{
for (const auto &i : list) {
- client_printf(client, "playlist: %s\n", i.name.c_str());
+ r.Format("playlist: %s\n", i.name.c_str());
if (i.mtime > 0)
- time_print(client, "Last-Modified", i.mtime);
+ time_print(r, "Last-Modified", i.mtime);
}
}
CommandResult
-handle_save(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_save(Client &client, Request args, Response &r)
{
- PlaylistResult result = spl_save_playlist(argv[1], client.playlist);
- return print_playlist_result(client, result);
+ Error error;
+ return spl_save_playlist(args.front(), client.playlist, error)
+ ? CommandResult::OK
+ : print_error(r, error);
}
CommandResult
-handle_load(Client &client, unsigned argc, char *argv[])
+handle_load(Client &client, Request args, Response &r)
{
- unsigned start_index, end_index;
-
- if (argc < 3) {
- start_index = 0;
- end_index = unsigned(-1);
- } else if (!check_range(client, &start_index, &end_index, argv[2]))
+ RangeArg range = RangeArg::All();
+ if (!args.ParseOptional(1, range, r))
return CommandResult::ERROR;
const ScopeBulkEdit bulk_edit(client.partition);
Error error;
const SongLoader loader(client);
- if (!playlist_open_into_queue(argv[1],
- start_index, end_index,
+ if (!playlist_open_into_queue(args.front(),
+ range.start, range.end,
client.playlist,
client.player_control, loader, error))
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_listplaylist(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_listplaylist(Client &client, Request args, Response &r)
{
- if (playlist_file_print(client, argv[1], false))
+ const char *const name = args.front();
+
+ if (playlist_file_print(r, client.partition, SongLoader(client),
+ name, false))
return CommandResult::OK;
Error error;
- return spl_print(client, argv[1], false, error)
+ return spl_print(r, client.partition, name, false, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_listplaylistinfo(Client &client,
- gcc_unused unsigned argc, char *argv[])
+handle_listplaylistinfo(Client &client, Request args, Response &r)
{
- if (playlist_file_print(client, argv[1], true))
+ const char *const name = args.front();
+
+ if (playlist_file_print(r, client.partition, SongLoader(client),
+ name, true))
return CommandResult::OK;
Error error;
- return spl_print(client, argv[1], true, error)
+ return spl_print(r, client.partition, name, true, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_rm(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_rm(gcc_unused Client &client, Request args, Response &r)
{
+ const char *const name = args.front();
+
Error error;
- return spl_delete(argv[1], error)
+ return spl_delete(name, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_rename(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_rename(gcc_unused Client &client, Request args, Response &r)
{
+ const char *const old_name = args[0];
+ const char *const new_name = args[1];
+
Error error;
- return spl_rename(argv[1], argv[2], error)
+ return spl_rename(old_name, new_name, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_playlistdelete(Client &client,
- gcc_unused unsigned argc, char *argv[]) {
- char *playlist = argv[1];
+handle_playlistdelete(gcc_unused Client &client, Request args, Response &r)
+{
+ const char *const name = args[0];
unsigned from;
-
- if (!check_unsigned(client, &from, argv[2]))
+ if (!args.Parse(1, from, r))
return CommandResult::ERROR;
Error error;
- return spl_remove_index(playlist, from, error)
+ return spl_remove_index(name, from, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_playlistmove(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_playlistmove(gcc_unused Client &client, Request args, Response &r)
{
- char *playlist = argv[1];
+ const char *const name = args.front();
unsigned from, to;
-
- if (!check_unsigned(client, &from, argv[2]))
- return CommandResult::ERROR;
- if (!check_unsigned(client, &to, argv[3]))
+ if (!args.Parse(1, from, r) || !args.Parse(2, to, r))
return CommandResult::ERROR;
Error error;
- return spl_move_index(playlist, from, to, error)
+ return spl_move_index(name, from, to, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_playlistclear(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_playlistclear(gcc_unused Client &client, Request args, Response &r)
{
+ const char *const name = args.front();
+
Error error;
- return spl_clear(argv[1], error)
+ return spl_clear(name, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_playlistadd(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_playlistadd(Client &client, Request args, Response &r)
{
- char *playlist = argv[1];
- char *uri = argv[2];
+ const char *const playlist = args[0];
+ const char *const uri = args[1];
bool success;
Error error;
@@ -179,7 +194,7 @@ handle_playlistadd(Client &client, gcc_unused unsigned argc, char *argv[])
#ifdef ENABLE_DATABASE
const Database *db = client.GetDatabase(error);
if (db == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
success = search_add_to_playlist(*db, *client.GetStorage(),
uri, playlist, nullptr,
@@ -190,23 +205,22 @@ handle_playlistadd(Client &client, gcc_unused unsigned argc, char *argv[])
}
if (!success && !error.IsDefined()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
+ r.Error(ACK_ERROR_NO_EXIST, "directory or file not found");
return CommandResult::ERROR;
}
- return success ? CommandResult::OK : print_error(client, error);
+ return success ? CommandResult::OK : print_error(r, error);
}
CommandResult
-handle_listplaylists(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_listplaylists(gcc_unused Client &client, gcc_unused Request args,
+ Response &r)
{
Error error;
const auto list = ListPlaylistFiles(error);
if (list.empty() && error.IsDefined())
- return print_error(client, error);
+ return print_error(r, error);
- print_spl_list(client, list);
+ print_spl_list(r, list);
return CommandResult::OK;
}
diff --git a/src/command/PlaylistCommands.hxx b/src/command/PlaylistCommands.hxx
index fba4e1318..9f263df62 100644
--- a/src/command/PlaylistCommands.hxx
+++ b/src/command/PlaylistCommands.hxx
@@ -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
@@ -21,40 +21,47 @@
#define MPD_PLAYLIST_COMMANDS_HXX
#include "CommandResult.hxx"
+#include "Compiler.h"
class Client;
+class Request;
+class Response;
+
+gcc_const
+bool
+playlist_commands_available();
CommandResult
-handle_save(Client &client, unsigned argc, char *argv[]);
+handle_save(Client &client, Request request, Response &response);
CommandResult
-handle_load(Client &client, unsigned argc, char *argv[]);
+handle_load(Client &client, Request request, Response &response);
CommandResult
-handle_listplaylist(Client &client, unsigned argc, char *argv[]);
+handle_listplaylist(Client &client, Request request, Response &response);
CommandResult
-handle_listplaylistinfo(Client &client, unsigned argc, char *argv[]);
+handle_listplaylistinfo(Client &client, Request request, Response &response);
CommandResult
-handle_rm(Client &client, unsigned argc, char *argv[]);
+handle_rm(Client &client, Request request, Response &response);
CommandResult
-handle_rename(Client &client, unsigned argc, char *argv[]);
+handle_rename(Client &client, Request request, Response &response);
CommandResult
-handle_playlistdelete(Client &client, unsigned argc, char *argv[]);
+handle_playlistdelete(Client &client, Request request, Response &response);
CommandResult
-handle_playlistmove(Client &client, unsigned argc, char *argv[]);
+handle_playlistmove(Client &client, Request request, Response &response);
CommandResult
-handle_playlistclear(Client &client, unsigned argc, char *argv[]);
+handle_playlistclear(Client &client, Request request, Response &response);
CommandResult
-handle_playlistadd(Client &client, unsigned argc, char *argv[]);
+handle_playlistadd(Client &client, Request request, Response &response);
CommandResult
-handle_listplaylists(Client &client, unsigned argc, char *argv[]);
+handle_listplaylists(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx
index d0b789eb1..7751aa26d 100644
--- a/src/command/QueueCommands.cxx
+++ b/src/command/QueueCommands.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,19 +19,20 @@
#include "config.h"
#include "QueueCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
#include "db/DatabaseQueue.hxx"
#include "db/Selection.hxx"
#include "SongFilter.hxx"
#include "SongLoader.hxx"
+#include "DetachedSong.hxx"
+#include "LocateUri.hxx"
#include "queue/Playlist.hxx"
#include "PlaylistPrint.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "BulkEdit.hxx"
-#include "protocol/ArgParser.hxx"
-#include "protocol/Result.hxx"
-#include "ls.hxx"
#include "util/ConstBuffer.hxx"
#include "util/UriUtil.hxx"
#include "util/NumberParser.hxx"
@@ -42,26 +43,48 @@
#include <string.h>
-static const char *
-translate_uri(Client &client, const char *uri)
+static CommandResult
+AddUri(Client &client, const LocatedUri &uri, Response &r)
{
- if (memcmp(uri, "file:///", 8) == 0)
- /* drop the "file://", leave only an absolute path
- (starting with a slash) */
- return uri + 7;
-
- if (PathTraitsUTF8::IsAbsolute(uri)) {
- command_error(client, ACK_ERROR_NO_EXIST, "Malformed URI");
- return nullptr;
- }
+ Error error;
+ DetachedSong *song = SongLoader(client).LoadSong(uri, error);
+ if (song == nullptr)
+ return print_error(r, error);
+
+ auto &partition = client.partition;
+ unsigned id = partition.playlist.AppendSong(partition.pc,
+ std::move(*song), error);
+ delete song;
+ if (id == 0)
+ return print_error(r, error);
+
+ return CommandResult::OK;
+}
+
+static CommandResult
+AddDatabaseSelection(Client &client, const char *uri, Response &r)
+{
+#ifdef ENABLE_DATABASE
+ const ScopeBulkEdit bulk_edit(client.partition);
+
+ const DatabaseSelection selection(uri, true);
+ Error error;
+ return AddFromDatabase(client.partition, selection, error)
+ ? CommandResult::OK
+ : print_error(r, error);
+#else
+ (void)client;
+ (void)uri;
- return uri;
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
+#endif
}
CommandResult
-handle_add(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_add(Client &client, Request args, Response &r)
{
- const char *uri = argv[1];
+ const char *uri = args.front();
if (memcmp(uri, "/", 2) == 0)
/* this URI is malformed, but some clients are buggy
and use "add /" to add the whole database, which
@@ -70,61 +93,54 @@ handle_add(Client &client, gcc_unused unsigned argc, char *argv[])
here */
uri = "";
- uri = translate_uri(client, uri);
- if (uri == nullptr)
- return CommandResult::ERROR;
-
- if (uri_has_scheme(uri) || PathTraitsUTF8::IsAbsolute(uri)) {
- const SongLoader loader(client);
- Error error;
- unsigned id = client.partition.AppendURI(loader, uri, error);
- if (id == 0)
- return print_error(client, error);
-
- return CommandResult::OK;
- }
-
-#ifdef ENABLE_DATABASE
- const ScopeBulkEdit bulk_edit(client.partition);
-
- const DatabaseSelection selection(uri, true);
Error error;
- return AddFromDatabase(client.partition, selection, error)
- ? CommandResult::OK
- : print_error(client, error);
-#else
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
- return CommandResult::ERROR;
+ const auto located_uri = LocateUri(uri, &client,
+#ifdef ENABLE_DATABASE
+ nullptr,
#endif
+ error);
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ return print_error(r, error);
+
+ case LocatedUri::Type::ABSOLUTE:
+ case LocatedUri::Type::PATH:
+ return AddUri(client, located_uri, r);
+
+ case LocatedUri::Type::RELATIVE:
+ return AddDatabaseSelection(client, located_uri.canonical_uri,
+ r);
+ }
+
+ gcc_unreachable();
}
CommandResult
-handle_addid(Client &client, unsigned argc, char *argv[])
+handle_addid(Client &client, Request args, Response &r)
{
- const char *const uri = translate_uri(client, argv[1]);
- if (uri == nullptr)
- return CommandResult::ERROR;
+ const char *const uri = args.front();
const SongLoader loader(client);
Error error;
unsigned added_id = client.partition.AppendURI(loader, uri, error);
if (added_id == 0)
- return print_error(client, error);
+ return print_error(r, error);
- if (argc == 3) {
+ if (args.size == 2) {
unsigned to;
- if (!check_unsigned(client, &to, argv[2]))
+ if (!args.Parse(1, to, r))
return CommandResult::ERROR;
+
PlaylistResult result = client.partition.MoveId(added_id, to);
if (result != PlaylistResult::SUCCESS) {
CommandResult ret =
- print_playlist_result(client, result);
+ print_playlist_result(r, result);
client.partition.DeleteId(added_id);
return ret;
}
}
- client_printf(client, "Id: %u\n", added_id);
+ r.Format("Id: %u\n", added_id);
return CommandResult::OK;
}
@@ -160,15 +176,15 @@ parse_time_range(const char *p, SongTime &start_r, SongTime &end_r)
}
CommandResult
-handle_rangeid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_rangeid(Client &client, Request args, Response &r)
{
unsigned id;
- if (!check_unsigned(client, &id, argv[1]))
+ if (!args.Parse(0, id, r))
return CommandResult::ERROR;
SongTime start, end;
- if (!parse_time_range(argv[2], start, end)) {
- command_error(client, ACK_ERROR_ARG, "Bad range");
+ if (!parse_time_range(args[1], start, end)) {
+ r.Error(ACK_ERROR_ARG, "Bad range");
return CommandResult::ERROR;
}
@@ -176,118 +192,110 @@ handle_rangeid(Client &client, gcc_unused unsigned argc, char *argv[])
if (!client.partition.playlist.SetSongIdRange(client.partition.pc,
id, start, end,
error))
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_delete(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_delete(Client &client, Request args, Response &r)
{
- unsigned start, end;
-
- if (!check_range(client, &start, &end, argv[1]))
+ RangeArg range;
+ if (!args.Parse(0, range, r))
return CommandResult::ERROR;
- PlaylistResult result = client.partition.DeleteRange(start, end);
- return print_playlist_result(client, result);
+ auto result = client.partition.DeleteRange(range.start, range.end);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_deleteid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_deleteid(Client &client, Request args, Response &r)
{
unsigned id;
-
- if (!check_unsigned(client, &id, argv[1]))
+ if (!args.Parse(0, id, r))
return CommandResult::ERROR;
PlaylistResult result = client.partition.DeleteId(id);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_playlist(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_playlist(Client &client, gcc_unused Request args, Response &r)
{
- playlist_print_uris(client, client.playlist);
+ playlist_print_uris(r, client.partition, client.playlist);
return CommandResult::OK;
}
CommandResult
-handle_shuffle(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_shuffle(gcc_unused Client &client, Request args, Response &r)
{
- unsigned start = 0, end = client.playlist.queue.GetLength();
- if (argc == 2 && !check_range(client, &start, &end, argv[1]))
+ RangeArg range = RangeArg::All();
+ if (!args.ParseOptional(0, range, r))
return CommandResult::ERROR;
- client.partition.Shuffle(start, end);
+ client.partition.Shuffle(range.start, range.end);
return CommandResult::OK;
}
CommandResult
-handle_clear(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_clear(Client &client, gcc_unused Request args, gcc_unused Response &r)
{
client.partition.ClearQueue();
return CommandResult::OK;
}
CommandResult
-handle_plchanges(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_plchanges(Client &client, Request args, Response &r)
{
uint32_t version;
-
- if (!check_uint32(client, &version, argv[1]))
+ if (!ParseCommandArg32(r, version, args.front()))
return CommandResult::ERROR;
- playlist_print_changes_info(client, client.playlist, version);
+ playlist_print_changes_info(r, client.partition,
+ client.playlist, version);
return CommandResult::OK;
}
CommandResult
-handle_plchangesposid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_plchangesposid(Client &client, Request args, Response &r)
{
uint32_t version;
-
- if (!check_uint32(client, &version, argv[1]))
+ if (!ParseCommandArg32(r, version, args.front()))
return CommandResult::ERROR;
- playlist_print_changes_position(client, client.playlist, version);
+ playlist_print_changes_position(r, client.playlist, version);
return CommandResult::OK;
}
CommandResult
-handle_playlistinfo(Client &client, unsigned argc, char *argv[])
+handle_playlistinfo(Client &client, Request args, Response &r)
{
- unsigned start = 0, end = std::numeric_limits<unsigned>::max();
- bool ret;
-
- if (argc == 2 && !check_range(client, &start, &end, argv[1]))
+ RangeArg range = RangeArg::All();
+ if (!args.ParseOptional(0, range, r))
return CommandResult::ERROR;
- ret = playlist_print_info(client, client.playlist, start, end);
- if (!ret)
- return print_playlist_result(client,
+ if (!playlist_print_info(r, client.partition, client.playlist,
+ range.start, range.end))
+ return print_playlist_result(r,
PlaylistResult::BAD_RANGE);
return CommandResult::OK;
}
CommandResult
-handle_playlistid(Client &client, unsigned argc, char *argv[])
+handle_playlistid(Client &client, Request args, Response &r)
{
- if (argc >= 2) {
+ if (!args.IsEmpty()) {
unsigned id;
- if (!check_unsigned(client, &id, argv[1]))
+ if (!args.Parse(0, id, r))
return CommandResult::ERROR;
- bool ret = playlist_print_id(client, client.playlist, id);
+ bool ret = playlist_print_id(r, client.partition,
+ client.playlist, id);
if (!ret)
- return print_playlist_result(client,
- PlaylistResult::NO_SUCH_SONG);
+ return print_playlist_result(r, PlaylistResult::NO_SUCH_SONG);
} else {
- playlist_print_info(client, client.playlist,
+ playlist_print_info(r, client.partition, client.playlist,
0, std::numeric_limits<unsigned>::max());
}
@@ -295,147 +303,120 @@ handle_playlistid(Client &client, unsigned argc, char *argv[])
}
static CommandResult
-handle_playlist_match(Client &client, unsigned argc, char *argv[],
+handle_playlist_match(Client &client, Request args, Response &r,
bool fold_case)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
-
SongFilter filter;
if (!filter.Parse(args, fold_case)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
- playlist_print_find(client, client.playlist, filter);
+ playlist_print_find(r, client.partition, client.playlist, filter);
return CommandResult::OK;
}
CommandResult
-handle_playlistfind(Client &client, unsigned argc, char *argv[])
+handle_playlistfind(Client &client, Request args, Response &r)
{
- return handle_playlist_match(client, argc, argv, false);
+ return handle_playlist_match(client, args, r, false);
}
CommandResult
-handle_playlistsearch(Client &client, unsigned argc, char *argv[])
+handle_playlistsearch(Client &client, Request args, Response &r)
{
- return handle_playlist_match(client, argc, argv, true);
+ return handle_playlist_match(client, args, r, true);
}
CommandResult
-handle_prio(Client &client, unsigned argc, char *argv[])
+handle_prio(Client &client, Request args, Response &r)
{
unsigned priority;
-
- if (!check_unsigned(client, &priority, argv[1]))
+ if (!args.ParseShift(0, priority, r, 0xff))
return CommandResult::ERROR;
- if (priority > 0xff) {
- command_error(client, ACK_ERROR_ARG,
- "Priority out of range: %s", argv[1]);
- return CommandResult::ERROR;
- }
-
- for (unsigned i = 2; i < argc; ++i) {
- unsigned start_position, end_position;
- if (!check_range(client, &start_position, &end_position,
- argv[i]))
+ for (const char *i : args) {
+ RangeArg range;
+ if (!ParseCommandArg(r, range, i))
return CommandResult::ERROR;
PlaylistResult result =
- client.partition.SetPriorityRange(start_position,
- end_position,
- priority);
+ client.partition.SetPriorityRange(range.start,
+ range.end,
+ priority);
if (result != PlaylistResult::SUCCESS)
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
return CommandResult::OK;
}
CommandResult
-handle_prioid(Client &client, unsigned argc, char *argv[])
+handle_prioid(Client &client, Request args, Response &r)
{
unsigned priority;
-
- if (!check_unsigned(client, &priority, argv[1]))
+ if (!args.ParseShift(0, priority, r, 0xff))
return CommandResult::ERROR;
- if (priority > 0xff) {
- command_error(client, ACK_ERROR_ARG,
- "Priority out of range: %s", argv[1]);
- return CommandResult::ERROR;
- }
-
- for (unsigned i = 2; i < argc; ++i) {
+ for (const char *i : args) {
unsigned song_id;
- if (!check_unsigned(client, &song_id, argv[i]))
+ if (!ParseCommandArg(r, song_id, i))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SetPriorityId(song_id, priority);
if (result != PlaylistResult::SUCCESS)
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
return CommandResult::OK;
}
CommandResult
-handle_move(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_move(Client &client, Request args, Response &r)
{
- unsigned start, end;
+ RangeArg range;
int to;
- if (!check_range(client, &start, &end, argv[1]))
- return CommandResult::ERROR;
- if (!check_int(client, &to, argv[2]))
+ if (!args.Parse(0, range, r) || !args.Parse(1, to, r))
return CommandResult::ERROR;
PlaylistResult result =
- client.partition.MoveRange(start, end, to);
- return print_playlist_result(client, result);
+ client.partition.MoveRange(range.start, range.end, to);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_moveid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_moveid(Client &client, Request args, Response &r)
{
unsigned id;
int to;
-
- if (!check_unsigned(client, &id, argv[1]))
- return CommandResult::ERROR;
- if (!check_int(client, &to, argv[2]))
+ if (!args.Parse(0, id, r) || !args.Parse(1, to, r))
return CommandResult::ERROR;
+
PlaylistResult result = client.partition.MoveId(id, to);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_swap(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_swap(Client &client, Request args, Response &r)
{
unsigned song1, song2;
-
- if (!check_unsigned(client, &song1, argv[1]))
- return CommandResult::ERROR;
- if (!check_unsigned(client, &song2, argv[2]))
+ if (!args.Parse(0, song1, r) || !args.Parse(1, song2, r))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SwapPositions(song1, song2);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_swapid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_swapid(Client &client, Request args, Response &r)
{
unsigned id1, id2;
-
- if (!check_unsigned(client, &id1, argv[1]))
- return CommandResult::ERROR;
- if (!check_unsigned(client, &id2, argv[2]))
+ if (!args.Parse(0, id1, r) || !args.Parse(1, id2, r))
return CommandResult::ERROR;
PlaylistResult result = client.partition.SwapIds(id1, id2);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
diff --git a/src/command/QueueCommands.hxx b/src/command/QueueCommands.hxx
index f98f7bad2..49499d8ea 100644
--- a/src/command/QueueCommands.hxx
+++ b/src/command/QueueCommands.hxx
@@ -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
@@ -23,65 +23,67 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_add(Client &client, unsigned argc, char *argv[]);
+handle_add(Client &client, Request request, Response &response);
CommandResult
-handle_addid(Client &client, unsigned argc, char *argv[]);
+handle_addid(Client &client, Request request, Response &response);
CommandResult
-handle_rangeid(Client &client, unsigned argc, char *argv[]);
+handle_rangeid(Client &client, Request request, Response &response);
CommandResult
-handle_delete(Client &client, unsigned argc, char *argv[]);
+handle_delete(Client &client, Request request, Response &response);
CommandResult
-handle_deleteid(Client &client, unsigned argc, char *argv[]);
+handle_deleteid(Client &client, Request request, Response &response);
CommandResult
-handle_playlist(Client &client, unsigned argc, char *argv[]);
+handle_playlist(Client &client, Request request, Response &response);
CommandResult
-handle_shuffle(Client &client, unsigned argc, char *argv[]);
+handle_shuffle(Client &client, Request request, Response &response);
CommandResult
-handle_clear(Client &client, unsigned argc, char *argv[]);
+handle_clear(Client &client, Request request, Response &response);
CommandResult
-handle_plchanges(Client &client, unsigned argc, char *argv[]);
+handle_plchanges(Client &client, Request request, Response &response);
CommandResult
-handle_plchangesposid(Client &client, unsigned argc, char *argv[]);
+handle_plchangesposid(Client &client, Request request, Response &response);
CommandResult
-handle_playlistinfo(Client &client, unsigned argc, char *argv[]);
+handle_playlistinfo(Client &client, Request request, Response &response);
CommandResult
-handle_playlistid(Client &client, unsigned argc, char *argv[]);
+handle_playlistid(Client &client, Request request, Response &response);
CommandResult
-handle_playlistfind(Client &client, unsigned argc, char *argv[]);
+handle_playlistfind(Client &client, Request request, Response &response);
CommandResult
-handle_playlistsearch(Client &client, unsigned argc, char *argv[]);
+handle_playlistsearch(Client &client, Request request, Response &response);
CommandResult
-handle_prio(Client &client, unsigned argc, char *argv[]);
+handle_prio(Client &client, Request request, Response &response);
CommandResult
-handle_prioid(Client &client, unsigned argc, char *argv[]);
+handle_prioid(Client &client, Request request, Response &response);
CommandResult
-handle_move(Client &client, unsigned argc, char *argv[]);
+handle_move(Client &client, Request request, Response &response);
CommandResult
-handle_moveid(Client &client, unsigned argc, char *argv[]);
+handle_moveid(Client &client, Request request, Response &response);
CommandResult
-handle_swap(Client &client, unsigned argc, char *argv[]);
+handle_swap(Client &client, Request request, Response &response);
CommandResult
-handle_swapid(Client &client, unsigned argc, char *argv[]);
+handle_swapid(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/Request.hxx b/src/command/Request.hxx
new file mode 100644
index 000000000..1616b7045
--- /dev/null
+++ b/src/command/Request.hxx
@@ -0,0 +1,74 @@
+/*
+ * 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
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_REQUEST_HXX
+#define MPD_REQUEST_HXX
+
+#include "check.h"
+#include "protocol/ArgParser.hxx"
+#include "util/ConstBuffer.hxx"
+
+#include <utility>
+
+#include <assert.h>
+
+class Response;
+
+class Request : public ConstBuffer<const char *> {
+ typedef ConstBuffer<const char *> Base;
+
+public:
+ constexpr Request(const char *const*argv, size_type n)
+ :Base(argv, n) {}
+
+ constexpr const char *GetOptional(unsigned idx,
+ const char *default_value=nullptr) const {
+ return idx < size
+ ? data[idx]
+ : default_value;
+ }
+
+ template<typename T, typename... Args>
+ bool Parse(unsigned idx, T &value_r, Response &r,
+ Args&&... args) {
+ assert(idx < size);
+
+ return ParseCommandArg(r, value_r, data[idx],
+ std::forward<Args>(args)...);
+ }
+
+ template<typename T, typename... Args>
+ bool ParseOptional(unsigned idx, T &value_r, Response &r,
+ Args&&... args) {
+ return idx >= size ||
+ Parse(idx, value_r, r,
+ std::forward<Args>(args)...);
+ }
+
+ template<typename T, typename... Args>
+ bool ParseShift(unsigned idx, T &value_r, Response &r,
+ Args&&... args) {
+ bool success = Parse(idx, value_r, r,
+ std::forward<Args>(args)...);
+ shift();
+ return success;
+ }
+};
+
+#endif
diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx
index 37506d51b..d5d7ab1f8 100644
--- a/src/command/StickerCommands.cxx
+++ b/src/command/StickerCommands.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 "StickerCommands.hxx"
+#include "Request.hxx"
#include "SongPrint.hxx"
#include "db/Interface.hxx"
#include "db/DatabaseGlue.hxx"
@@ -26,16 +27,17 @@
#include "sticker/StickerPrint.hxx"
#include "sticker/StickerDatabase.hxx"
#include "CommandError.hxx"
-#include "protocol/Result.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "util/Error.hxx"
-
-#include <string.h>
+#include "util/ConstBuffer.hxx"
+#include "util/StringAPI.hxx"
struct sticker_song_find_data {
- Client &client;
+ Response &r;
+ Partition &partition;
const char *name;
};
@@ -46,125 +48,161 @@ sticker_song_find_print_cb(const LightSong &song, const char *value,
struct sticker_song_find_data *data =
(struct sticker_song_find_data *)user_data;
- song_print_uri(data->client, song);
- sticker_print_value(data->client, data->name, value);
+ song_print_uri(data->r, data->partition, song);
+ sticker_print_value(data->r, data->name, value);
}
static CommandResult
-handle_sticker_song(Client &client, unsigned argc, char *argv[])
+handle_sticker_song(Response &r, Partition &partition, Request args)
{
Error error;
- const Database *db = client.GetDatabase(error);
+ const Database *db = partition.GetDatabase(error);
if (db == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
+
+ const char *const cmd = args.front();
/* get song song_id key */
- if (argc == 5 && strcmp(argv[1], "get") == 0) {
- const LightSong *song = db->GetSong(argv[3], error);
+ if (args.size == 4 && StringIsEqual(cmd, "get")) {
+ const LightSong *song = db->GetSong(args[2], error);
if (song == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
- const auto value = sticker_song_get_value(*song, argv[4]);
+ const auto value = sticker_song_get_value(*song, args[3],
+ error);
db->ReturnSong(song);
if (value.empty()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "no such sticker");
+ if (error.IsDefined())
+ return print_error(r, error);
+
+ r.Error(ACK_ERROR_NO_EXIST, "no such sticker");
return CommandResult::ERROR;
}
- sticker_print_value(client, argv[4], value.c_str());
+ sticker_print_value(r, args[3], value.c_str());
return CommandResult::OK;
/* list song song_id */
- } else if (argc == 4 && strcmp(argv[1], "list") == 0) {
- const LightSong *song = db->GetSong(argv[3], error);
+ } else if (args.size == 3 && StringIsEqual(cmd, "list")) {
+ const LightSong *song = db->GetSong(args[2], error);
if (song == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
- sticker *sticker = sticker_song_get(*song);
+ Sticker *sticker = sticker_song_get(*song, error);
db->ReturnSong(song);
if (sticker) {
- sticker_print(client, *sticker);
+ sticker_print(r, *sticker);
sticker_free(sticker);
- }
+ } else if (error.IsDefined())
+ return print_error(r, error);
return CommandResult::OK;
/* set song song_id id key */
- } else if (argc == 6 && strcmp(argv[1], "set") == 0) {
- const LightSong *song = db->GetSong(argv[3], error);
+ } else if (args.size == 5 && StringIsEqual(cmd, "set")) {
+ const LightSong *song = db->GetSong(args[2], error);
if (song == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
- bool ret = sticker_song_set_value(*song, argv[4], argv[5]);
+ bool ret = sticker_song_set_value(*song, args[3], args[4],
+ error);
db->ReturnSong(song);
if (!ret) {
- command_error(client, ACK_ERROR_SYSTEM,
- "failed to set sticker value");
+ if (error.IsDefined())
+ return print_error(r, error);
+
+ r.Error(ACK_ERROR_SYSTEM,
+ "failed to set sticker value");
return CommandResult::ERROR;
}
return CommandResult::OK;
/* delete song song_id [key] */
- } else if ((argc == 4 || argc == 5) &&
- strcmp(argv[1], "delete") == 0) {
- const LightSong *song = db->GetSong(argv[3], error);
+ } else if ((args.size == 3 || args.size == 4) &&
+ StringIsEqual(cmd, "delete")) {
+ const LightSong *song = db->GetSong(args[2], error);
if (song == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
- bool ret = argc == 4
- ? sticker_song_delete(*song)
- : sticker_song_delete_value(*song, argv[4]);
+ bool ret = args.size == 3
+ ? sticker_song_delete(*song, error)
+ : sticker_song_delete_value(*song, args[3], error);
db->ReturnSong(song);
if (!ret) {
- command_error(client, ACK_ERROR_SYSTEM,
- "no such sticker");
+ if (error.IsDefined())
+ return print_error(r, error);
+
+ r.Error(ACK_ERROR_SYSTEM, "no such sticker");
return CommandResult::ERROR;
}
return CommandResult::OK;
/* find song dir key */
- } else if (argc == 5 && strcmp(argv[1], "find") == 0) {
+ } else if ((args.size == 4 || args.size == 6) &&
+ StringIsEqual(cmd, "find")) {
/* "sticker find song a/directory name" */
- const char *const base_uri = argv[3];
+ const char *const base_uri = args[2];
+
+ StickerOperator op = StickerOperator::EXISTS;
+ const char *value = nullptr;
+
+ if (args.size == 6) {
+ /* match the value */
+
+ const char *op_s = args[4];
+ value = args[5];
+
+ if (StringIsEqual(op_s, "="))
+ op = StickerOperator::EQUALS;
+ else if (StringIsEqual(op_s, "<"))
+ op = StickerOperator::LESS_THAN;
+ else if (StringIsEqual(op_s, ">"))
+ op = StickerOperator::GREATER_THAN;
+ else {
+ r.Error(ACK_ERROR_ARG, "bad operator");
+ return CommandResult::ERROR;
+ }
+ }
- bool success;
struct sticker_song_find_data data = {
- client,
- argv[4],
+ r,
+ partition,
+ args[3],
};
- success = sticker_song_find(*db, base_uri, data.name,
- sticker_song_find_print_cb, &data);
- if (!success) {
- command_error(client, ACK_ERROR_SYSTEM,
- "failed to set search sticker database");
+ if (!sticker_song_find(*db, base_uri, data.name,
+ op, value,
+ sticker_song_find_print_cb, &data,
+ error)) {
+ if (error.IsDefined())
+ return print_error(r, error);
+
+ r.Error(ACK_ERROR_SYSTEM,
+ "failed to set search sticker database");
return CommandResult::ERROR;
}
return CommandResult::OK;
} else {
- command_error(client, ACK_ERROR_ARG, "bad request");
+ r.Error(ACK_ERROR_ARG, "bad request");
return CommandResult::ERROR;
}
}
CommandResult
-handle_sticker(Client &client, unsigned argc, char *argv[])
+handle_sticker(Client &client, Request args, Response &r)
{
- assert(argc >= 4);
+ assert(args.size >= 3);
if (!sticker_enabled()) {
- command_error(client, ACK_ERROR_UNKNOWN,
- "sticker database is disabled");
+ r.Error(ACK_ERROR_UNKNOWN, "sticker database is disabled");
return CommandResult::ERROR;
}
- if (strcmp(argv[2], "song") == 0)
- return handle_sticker_song(client, argc, argv);
+ if (StringIsEqual(args[1], "song"))
+ return handle_sticker_song(r, client.partition, args);
else {
- command_error(client, ACK_ERROR_ARG,
- "unknown sticker domain");
+ r.Error(ACK_ERROR_ARG, "unknown sticker domain");
return CommandResult::ERROR;
}
}
diff --git a/src/command/StickerCommands.hxx b/src/command/StickerCommands.hxx
index cf46cd034..5bb9cc426 100644
--- a/src/command/StickerCommands.hxx
+++ b/src/command/StickerCommands.hxx
@@ -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
@@ -23,8 +23,10 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_sticker(Client &client, unsigned argc, char *argv[]);
+handle_sticker(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/StorageCommands.cxx b/src/command/StorageCommands.cxx
index ee51c573e..3c11eb0d7 100644
--- a/src/command/StorageCommands.cxx
+++ b/src/command/StorageCommands.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
@@ -21,12 +21,14 @@
#include "config.h"
#include "StorageCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
-#include "protocol/Result.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
#include "fs/Traits.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "storage/Registry.hxx"
@@ -55,7 +57,7 @@ skip_path(const char *name_utf8)
#endif
static bool
-handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
+handle_listfiles_storage(Response &r, StorageDirectoryReader &reader,
Error &error)
{
const char *name_utf8;
@@ -63,29 +65,29 @@ handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
if (skip_path(name_utf8))
continue;
- FileInfo info;
+ StorageFileInfo info;
if (!reader.GetInfo(false, info, error))
continue;
switch (info.type) {
- case FileInfo::Type::OTHER:
+ case StorageFileInfo::Type::OTHER:
/* ignore */
continue;
- case FileInfo::Type::REGULAR:
- client_printf(client, "file: %s\n"
- "size: %" PRIu64 "\n",
- name_utf8,
- info.size);
+ case StorageFileInfo::Type::REGULAR:
+ r.Format("file: %s\n"
+ "size: %" PRIu64 "\n",
+ name_utf8,
+ info.size);
break;
- case FileInfo::Type::DIRECTORY:
- client_printf(client, "directory: %s\n", name_utf8);
+ case StorageFileInfo::Type::DIRECTORY:
+ r.Format("directory: %s\n", name_utf8);
break;
}
if (info.mtime != 0)
- time_print(client, "Last-Modified", info.mtime);
+ time_print(r, "Last-Modified", info.mtime);
}
return true;
@@ -96,58 +98,57 @@ handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
#endif
static bool
-handle_listfiles_storage(Client &client, Storage &storage, const char *uri,
+handle_listfiles_storage(Response &r, Storage &storage, const char *uri,
Error &error)
{
auto reader = storage.OpenDirectory(uri, error);
if (reader == nullptr)
return false;
- bool success = handle_listfiles_storage(client, *reader, error);
+ bool success = handle_listfiles_storage(r, *reader, error);
delete reader;
return success;
}
CommandResult
-handle_listfiles_storage(Client &client, Storage &storage, const char *uri)
+handle_listfiles_storage(Response &r, Storage &storage, const char *uri)
{
Error error;
- if (!handle_listfiles_storage(client, storage, uri, error))
- return print_error(client, error);
+ if (!handle_listfiles_storage(r, storage, uri, error))
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_listfiles_storage(Client &client, const char *uri)
+handle_listfiles_storage(Response &r, const char *uri)
{
Error error;
Storage *storage = CreateStorageURI(io_thread_get(), uri, error);
if (storage == nullptr) {
if (error.IsDefined())
- return print_error(client, error);
+ return print_error(r, error);
- command_error(client, ACK_ERROR_ARG,
- "Unrecognized storage URI");
+ r.Error(ACK_ERROR_ARG, "Unrecognized storage URI");
return CommandResult::ERROR;
}
- bool success = handle_listfiles_storage(client, *storage, "", error);
+ bool success = handle_listfiles_storage(r, *storage, "", error);
delete storage;
if (!success)
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
static void
-print_storage_uri(Client &client, const Storage &storage)
+print_storage_uri(Client &client, Response &r, const Storage &storage)
{
std::string uri = storage.MapUTF8("");
if (uri.empty())
return;
- if (PathTraitsFS::IsAbsolute(uri.c_str())) {
+ if (PathTraitsUTF8::IsAbsolute(uri.c_str())) {
/* storage points to local directory */
if (!client.IsLocal())
@@ -163,24 +164,24 @@ print_storage_uri(Client &client, const Storage &storage)
uri = std::move(allocated);
}
- client_printf(client, "storage: %s\n", uri.c_str());
+ r.Format("storage: %s\n", uri.c_str());
}
CommandResult
-handle_listmounts(Client &client, gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_listmounts(Client &client, gcc_unused Request args, Response &r)
{
Storage *_composite = client.partition.instance.storage;
if (_composite == nullptr) {
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
}
CompositeStorage &composite = *(CompositeStorage *)_composite;
- const auto visitor = [&client](const char *mount_uri,
- const Storage &storage){
- client_printf(client, "mount: %s\n", mount_uri);
- print_storage_uri(client, storage);
+ const auto visitor = [&client, &r](const char *mount_uri,
+ const Storage &storage){
+ r.Format("mount: %s\n", mount_uri);
+ print_storage_uri(client, r, storage);
};
composite.VisitMounts(visitor);
@@ -189,21 +190,21 @@ handle_listmounts(Client &client, gcc_unused unsigned argc, gcc_unused char *arg
}
CommandResult
-handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_mount(Client &client, Request args, Response &r)
{
Storage *_composite = client.partition.instance.storage;
if (_composite == nullptr) {
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
}
CompositeStorage &composite = *(CompositeStorage *)_composite;
- const char *const local_uri = argv[1];
- const char *const remote_uri = argv[2];
+ const char *const local_uri = args[0];
+ const char *const remote_uri = args[1];
if (*local_uri == 0) {
- command_error(client, ACK_ERROR_ARG, "Bad mount point");
+ r.Error(ACK_ERROR_ARG, "Bad mount point");
return CommandResult::ERROR;
}
@@ -213,7 +214,7 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
UpdateQueue::Erase() really gets called for every
unmount, and no Directory disappears recursively
during database update */
- command_error(client, ACK_ERROR_ARG, "Bad mount point");
+ r.Error(ACK_ERROR_ARG, "Bad mount point");
return CommandResult::ERROR;
}
@@ -222,10 +223,9 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
error);
if (storage == nullptr) {
if (error.IsDefined())
- return print_error(client, error);
+ return print_error(r, error);
- command_error(client, ACK_ERROR_ARG,
- "Unrecognized storage URI");
+ r.Error(ACK_ERROR_ARG, "Unrecognized storage URI");
return CommandResult::ERROR;
}
@@ -239,7 +239,7 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
if (!db.Mount(local_uri, remote_uri, error)) {
composite.Unmount(local_uri);
- return print_error(client, error);
+ return print_error(r, error);
}
// TODO: call Instance::OnDatabaseModified()?
@@ -252,20 +252,20 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_unmount(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_unmount(Client &client, Request args, Response &r)
{
Storage *_composite = client.partition.instance.storage;
if (_composite == nullptr) {
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
}
CompositeStorage &composite = *(CompositeStorage *)_composite;
- const char *const local_uri = argv[1];
+ const char *const local_uri = args.front();
if (*local_uri == 0) {
- command_error(client, ACK_ERROR_ARG, "Bad mount point");
+ r.Error(ACK_ERROR_ARG, "Bad mount point");
return CommandResult::ERROR;
}
@@ -287,7 +287,7 @@ handle_unmount(Client &client, gcc_unused unsigned argc, char *argv[])
#endif
if (!composite.Unmount(local_uri)) {
- command_error(client, ACK_ERROR_ARG, "Not a mount point");
+ r.Error(ACK_ERROR_ARG, "Not a mount point");
return CommandResult::ERROR;
}
diff --git a/src/command/StorageCommands.hxx b/src/command/StorageCommands.hxx
index a3636d54a..7d3c552f6 100644
--- a/src/command/StorageCommands.hxx
+++ b/src/command/StorageCommands.hxx
@@ -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
@@ -24,20 +24,22 @@
class Client;
class Storage;
+class Request;
+class Response;
CommandResult
-handle_listfiles_storage(Client &client, Storage &storage, const char *uri);
+handle_listfiles_storage(Response &r, Storage &storage, const char *uri);
CommandResult
-handle_listfiles_storage(Client &client, const char *uri);
+handle_listfiles_storage(Response &r, const char *uri);
CommandResult
-handle_listmounts(Client &client, unsigned argc, char *argv[]);
+handle_listmounts(Client &client, Request request, Response &response);
CommandResult
-handle_mount(Client &client, unsigned argc, char *argv[]);
+handle_mount(Client &client, Request request, Response &response);
CommandResult
-handle_unmount(Client &client, unsigned argc, char *argv[]);
+handle_unmount(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/TagCommands.cxx b/src/command/TagCommands.cxx
index 2d537671c..2a7076bdc 100644
--- a/src/command/TagCommands.cxx
+++ b/src/command/TagCommands.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,51 +19,51 @@
#include "config.h"
#include "TagCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
#include "client/Client.hxx"
-#include "protocol/ArgParser.hxx"
-#include "protocol/Result.hxx"
+#include "client/Response.hxx"
#include "tag/Tag.hxx"
#include "Partition.hxx"
+#include "util/ConstBuffer.hxx"
CommandResult
-handle_addtagid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_addtagid(Client &client, Request args, Response &r)
{
unsigned song_id;
- if (!check_unsigned(client, &song_id, argv[1]))
+ if (!args.Parse(0, song_id, r))
return CommandResult::ERROR;
- const char *const tag_name = argv[2];
+ const char *const tag_name = args[1];
const TagType tag_type = tag_name_parse_i(tag_name);
if (tag_type == TAG_NUM_OF_ITEM_TYPES) {
- command_error(client, ACK_ERROR_ARG,
- "Unknown tag type: %s", tag_name);
+ r.FormatError(ACK_ERROR_ARG, "Unknown tag type: %s", tag_name);
return CommandResult::ERROR;
}
- const char *const value = argv[3];
+ const char *const value = args[2];
Error error;
if (!client.partition.playlist.AddSongIdTag(song_id, tag_type, value,
error))
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_cleartagid(Client &client, unsigned argc, char *argv[])
+handle_cleartagid(Client &client, Request args, Response &r)
{
unsigned song_id;
- if (!check_unsigned(client, &song_id, argv[1]))
+ if (!args.Parse(0, song_id, r))
return CommandResult::ERROR;
TagType tag_type = TAG_NUM_OF_ITEM_TYPES;
- if (argc >= 3) {
- const char *const tag_name = argv[2];
+ if (args.size >= 2) {
+ const char *const tag_name = args[1];
tag_type = tag_name_parse_i(tag_name);
if (tag_type == TAG_NUM_OF_ITEM_TYPES) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Unknown tag type: %s", tag_name);
return CommandResult::ERROR;
}
@@ -72,7 +72,7 @@ handle_cleartagid(Client &client, unsigned argc, char *argv[])
Error error;
if (!client.partition.playlist.ClearSongIdTag(song_id, tag_type,
error))
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
diff --git a/src/command/TagCommands.hxx b/src/command/TagCommands.hxx
index 748838e68..868d6d783 100644
--- a/src/command/TagCommands.hxx
+++ b/src/command/TagCommands.hxx
@@ -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
@@ -23,11 +23,13 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_addtagid(Client &client, unsigned argc, char *argv[]);
+handle_addtagid(Client &client, Request request, Response &response);
CommandResult
-handle_cleartagid(Client &client, unsigned argc, char *argv[]);
+handle_cleartagid(Client &client, Request request, Response &response);
#endif