diff options
author | Max Kellermann <max@duempel.org> | 2015-08-06 22:10:25 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2015-08-12 08:41:05 +0200 |
commit | 7652a2986b0d0ad55b2776685130f1c68d7108c7 (patch) | |
tree | b4d45e60e97757454f1ff8e4dc793a1e7d852c36 /src/command | |
parent | b1480167be487d09ff46bb86ad02041fb28acff1 (diff) | |
download | mpd-7652a2986b0d0ad55b2776685130f1c68d7108c7.tar.gz mpd-7652a2986b0d0ad55b2776685130f1c68d7108c7.tar.xz mpd-7652a2986b0d0ad55b2776685130f1c68d7108c7.zip |
client/Response: new Client wrapper class for writing responses
Diffstat (limited to 'src/command')
-rw-r--r-- | src/command/AllCommands.cxx | 65 | ||||
-rw-r--r-- | src/command/CommandError.cxx | 55 | ||||
-rw-r--r-- | src/command/CommandError.hxx | 6 | ||||
-rw-r--r-- | src/command/DatabaseCommands.cxx | 82 | ||||
-rw-r--r-- | src/command/FileCommands.cxx | 72 | ||||
-rw-r--r-- | src/command/MessageCommands.cxx | 34 | ||||
-rw-r--r-- | src/command/NeighborCommands.cxx | 16 | ||||
-rw-r--r-- | src/command/OtherCommands.cxx | 117 | ||||
-rw-r--r-- | src/command/OutputCommands.cxx | 29 | ||||
-rw-r--r-- | src/command/PlayerCommands.cxx | 187 | ||||
-rw-r--r-- | src/command/PlaylistCommands.cxx | 75 | ||||
-rw-r--r-- | src/command/QueueCommands.cxx | 132 | ||||
-rw-r--r-- | src/command/Request.hxx | 14 | ||||
-rw-r--r-- | src/command/StickerCommands.cxx | 69 | ||||
-rw-r--r-- | src/command/StorageCommands.cxx | 76 | ||||
-rw-r--r-- | src/command/StorageCommands.hxx | 5 | ||||
-rw-r--r-- | src/command/TagCommands.cxx | 19 |
17 files changed, 588 insertions, 465 deletions
diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx index 9f0b0a606..57d4db983 100644 --- a/src/command/AllCommands.cxx +++ b/src/command/AllCommands.cxx @@ -36,6 +36,7 @@ #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" @@ -226,38 +227,50 @@ command_available(gcc_unused const Partition &partition, return true; } -/* don't be fooled, this is the command handler for "commands" command */ static CommandResult -handle_commands(Client &client, gcc_unused Request args) +PrintAvailableCommands(Response &r, const Partition &partition, + unsigned permission) { - const unsigned permission = client.GetPermission(); - for (unsigned i = 0; i < num_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 Request args) +PrintUnavailableCommands(Response &r, unsigned permission) { - const unsigned permission = client.GetPermission(); - for (unsigned i = 0; i < num_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; } +/* don't be fooled, this is the command handler for "commands" command */ +static CommandResult +handle_commands(Client &client, gcc_unused Request args) +{ + Response r(client); + return PrintAvailableCommands(r, client.partition, + client.GetPermission()); +} + +static CommandResult +handle_not_commands(Client &client, gcc_unused Request args) +{ + Response r(client); + return PrintUnavailableCommands(r, client.GetPermission()); +} + void command_init() { @@ -299,7 +312,8 @@ command_check_request(const struct command *cmd, Client &client, unsigned permission, Request args) { if (cmd->permission != (permission & cmd->permission)) { - command_error(client, ACK_ERROR_PERMISSION, + Response r(client); + r.FormatError(ACK_ERROR_PERMISSION, "you don't have permission for \"%s\"", cmd->cmd); return false; @@ -312,16 +326,19 @@ command_check_request(const struct command *cmd, Client &client, return true; if (min == max && unsigned(max) != args.size) { - command_error(client, ACK_ERROR_ARG, + Response r(client); + r.FormatError(ACK_ERROR_ARG, "wrong number of arguments for \"%s\"", cmd->cmd); return false; } else if (args.size < unsigned(min)) { - command_error(client, ACK_ERROR_ARG, + Response r(client); + r.FormatError(ACK_ERROR_ARG, "too few arguments for \"%s\"", cmd->cmd); return false; } else if (max >= 0 && args.size > unsigned(max)) { - command_error(client, ACK_ERROR_ARG, + Response r(client); + r.FormatError(ACK_ERROR_ARG, "too many arguments for \"%s\"", cmd->cmd); return false; } else @@ -336,7 +353,8 @@ command_checked_lookup(Client &client, unsigned permission, const struct command *cmd = command_lookup(cmd_name); if (cmd == nullptr) { - command_error(client, ACK_ERROR_UNKNOWN, + Response r(client); + r.FormatError(ACK_ERROR_UNKNOWN, "unknown command \"%s\"", cmd_name); return nullptr; } @@ -357,7 +375,7 @@ command_process(Client &client, unsigned num, char *line) command_list_num = num; /* get the command name (first word on the line) */ - /* we have to set current_command because command_error() + /* we have to set current_command because Response::Error() expects it to be set */ Tokenizer tokenizer(line); @@ -366,12 +384,12 @@ command_process(Client &client, unsigned num, char *line) tokenizer.NextWord(error); if (cmd_name == nullptr) { current_command = ""; + + Response r(client); 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()); + r.Error(ACK_ERROR_UNKNOWN, error.GetMessage()); current_command = nullptr; @@ -387,8 +405,8 @@ command_process(Client &client, unsigned num, char *line) while (true) { if (args.size == COMMAND_ARGV_MAX) { - command_error(client, ACK_ERROR_ARG, - "Too many arguments"); + Response r(client); + r.Error(ACK_ERROR_ARG, "Too many arguments"); current_command = nullptr; return CommandResult::ERROR; } @@ -398,7 +416,8 @@ command_process(Client &client, unsigned num, char *line) if (tokenizer.IsEnd()) break; - command_error(client, ACK_ERROR_ARG, "%s", error.GetMessage()); + Response r(client); + r.Error(ACK_ERROR_UNKNOWN, error.GetMessage()); current_command = nullptr; return CommandResult::ERROR; } diff --git a/src/command/CommandError.cxx b/src/command/CommandError.cxx index da0571295..d95722c3b 100644 --- a/src/command/CommandError.cxx +++ b/src/command/CommandError.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "CommandError.hxx" #include "db/DatabaseError.hxx" -#include "protocol/Result.hxx" +#include "client/Response.hxx" #include "util/Error.hxx" #include "Log.hxx" @@ -29,57 +29,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 +86,39 @@ 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(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 6c42ed960..e33386078 100644 --- a/src/command/CommandError.hxx +++ b/src/command/CommandError.hxx @@ -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/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx index 6e6f3399b..62764139e 100644 --- a/src/command/DatabaseCommands.cxx +++ b/src/command/DatabaseCommands.cxx @@ -28,11 +28,11 @@ #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 "SongFilter.hxx" -#include "protocol/Result.hxx" #include "BulkEdit.hxx" #include <string.h> @@ -40,11 +40,13 @@ CommandResult handle_listfiles_db(Client &client, const char *uri) { + Response r(client); 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; } @@ -52,14 +54,17 @@ handle_listfiles_db(Client &client, const char *uri) CommandResult handle_lsinfo2(Client &client, Request args) { + Response r(client); + /* default is root directory */ const auto uri = args.GetOptional(0, ""); 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; } @@ -67,9 +72,11 @@ handle_lsinfo2(Client &client, Request args) static CommandResult handle_match(Client &client, Request args, bool fold_case) { + Response r(client); + RangeArg window; if (args.size >= 2 && strcmp(args[args.size - 2], "window") == 0) { - if (!args.Parse(args.size - 1, window, client)) + if (!args.Parse(args.size - 1, window, r)) return CommandResult::ERROR; args.pop_back(); @@ -79,17 +86,18 @@ handle_match(Client &client, Request args, bool fold_case) 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, + 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 @@ -107,9 +115,11 @@ handle_search(Client &client, Request args) static CommandResult handle_match_add(Client &client, Request args, bool fold_case) { + Response r(client); + 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; } @@ -119,7 +129,7 @@ handle_match_add(Client &client, Request args, bool fold_case) Error error; return AddFromDatabase(client.partition, selection, error) ? CommandResult::OK - : print_error(client, error); + : print_error(r, error); } CommandResult @@ -137,34 +147,38 @@ handle_searchadd(Client &client, Request args) CommandResult handle_searchaddpl(Client &client, Request args) { + Response r(client); + 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, Request args) { + Response r(client); + TagType group = TAG_NUM_OF_ITEM_TYPES; if (args.size >= 2 && strcmp(args[args.size - 2], "group") == 0) { 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; } @@ -175,38 +189,43 @@ handle_count(Client &client, Request args) 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, Request args) { + Response r(client); + /* default is root directory */ const auto uri = args.GetOptional(0, ""); Error error; - return db_selection_print(client, DatabaseSelection(uri, 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, Request args) { + Response r(client); + 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; } @@ -217,7 +236,7 @@ handle_list(Client &client, Request args) 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; @@ -231,7 +250,7 @@ handle_list(Client &client, Request args) 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; } @@ -246,8 +265,7 @@ handle_list(Client &client, Request args) 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; } } @@ -255,15 +273,16 @@ handle_list(Client &client, Request args) if (tagType < TAG_NUM_OF_ITEM_TYPES && group_mask & (1u << 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; @@ -273,12 +292,15 @@ handle_list(Client &client, Request args) CommandResult handle_listallinfo(Client &client, Request args) { + Response r(client); + /* default is root directory */ const auto uri = args.GetOptional(0, ""); Error error; - return db_selection_print(client, DatabaseSelection(uri, 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/FileCommands.cxx b/src/command/FileCommands.cxx index 574254d7a..c30dad8c8 100644 --- a/src/command/FileCommands.cxx +++ b/src/command/FileCommands.cxx @@ -24,8 +24,8 @@ #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" @@ -72,21 +72,22 @@ skip_path(Path name_fs) CommandResult handle_listfiles_local(Client &client, const char *path_utf8) { + Response r(client); + const auto path_fs = AllocatedPath::FromUTF8(path_utf8); if (path_fs.IsNull()) { - command_error(client, ACK_ERROR_NO_EXIST, - "unsupported file name"); + r.Error(ACK_ERROR_NO_EXIST, "unsupported file name"); return CommandResult::ERROR; } Error error; if (!client.AllowFile(path_fs, error)) - return print_error(client, error); + return print_error(r, error); DirectoryReader reader(path_fs); if (reader.HasFailed()) { error.FormatErrno("Failed to open '%s'", path_utf8); - return print_error(client, error); + return print_error(r, error); } while (reader.ReadEntry()) { @@ -105,17 +106,16 @@ handle_listfiles_local(Client &client, const char *path_utf8) continue; if (fi.IsRegular()) - client_printf(client, "file: %s\n" - "size: %" PRIu64 "\n", - name_utf8.c_str(), - fi.GetSize()); + r.Format("file: %s\n" + "size: %" PRIu64 "\n", + name_utf8.c_str(), + fi.GetSize()); else if (fi.IsDirectory()) - client_printf(client, "directory: %s\n", - name_utf8.c_str()); + r.Format("directory: %s\n", name_utf8.c_str()); else continue; - time_print(client, "Last-Modified", fi.GetModificationTime()); + time_print(r, "Last-Modified", fi.GetModificationTime()); } return CommandResult::OK; @@ -158,10 +158,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 = { @@ -171,17 +171,15 @@ 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"); + r.Error(ACK_ERROR_NO_EXIST, "unsupported URI scheme"); return CommandResult::ERROR; } - if (!tag_stream_scan(uri, print_comment_handler, &client)) { - command_error(client, ACK_ERROR_NO_EXIST, - "Failed to load file"); + if (!tag_stream_scan(uri, print_comment_handler, &r)) { + r.Error(ACK_ERROR_NO_EXIST, "Failed to load file"); return CommandResult::ERROR; } @@ -190,16 +188,15 @@ read_stream_comments(Client &client, const char *uri) } static CommandResult -read_file_comments(Client &client, const Path path_fs) +read_file_comments(Response &r, const Path path_fs) { - if (!tag_file_scan(path_fs, print_comment_handler, &client)) { - command_error(client, ACK_ERROR_NO_EXIST, - "Failed to load file"); + 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, &client); - tag_id3_scan(path_fs, &print_comment_handler, &client); + tag_ape_scan2(path_fs, &print_comment_handler, &r); + tag_id3_scan(path_fs, &print_comment_handler, &r); return CommandResult::OK; @@ -219,6 +216,8 @@ translate_uri(const char *uri) CommandResult handle_read_comments(Client &client, Request args) { + Response r(client); + assert(args.size == 1); const char *const uri = translate_uri(args.front()); @@ -227,25 +226,23 @@ handle_read_comments(Client &client, Request args) 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"); + r.Error(ACK_ERROR_NO_EXIST, "unsupported file name"); return CommandResult::ERROR; } Error error; if (!client.AllowFile(path_fs, error)) - return print_error(client, error); + return print_error(r, error); - return read_file_comments(client, path_fs); + return read_file_comments(r, path_fs); } else if (uri_has_scheme(uri)) { - return read_stream_comments(client, uri); + return read_stream_comments(r, 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"); + r.Error(ACK_ERROR_NO_EXIST, "No database"); return CommandResult::ERROR; #ifdef ENABLE_DATABASE } @@ -253,21 +250,20 @@ handle_read_comments(Client &client, Request args) { AllocatedPath path_fs = storage->MapFS(uri); if (!path_fs.IsNull()) - return read_file_comments(client, path_fs); + return read_file_comments(r, path_fs); } { const std::string uri2 = storage->MapUTF8(uri); if (uri_has_scheme(uri2.c_str())) - return read_stream_comments(client, - uri2.c_str()); + return read_stream_comments(r, uri2.c_str()); } - command_error(client, ACK_ERROR_NO_EXIST, "No such file"); + r.Error(ACK_ERROR_NO_EXIST, "No such file"); return CommandResult::ERROR; #endif } else { - command_error(client, ACK_ERROR_NO_EXIST, "No such file"); + r.Error(ACK_ERROR_NO_EXIST, "No such file"); return CommandResult::ERROR; } } diff --git a/src/command/MessageCommands.cxx b/src/command/MessageCommands.cxx index 24c9ddf2d..62d47ff0e 100644 --- a/src/command/MessageCommands.cxx +++ b/src/command/MessageCommands.cxx @@ -22,9 +22,9 @@ #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> @@ -35,6 +35,8 @@ CommandResult handle_subscribe(Client &client, Request args) { + Response r(client); + assert(args.size == 1); const char *const channel_name = args[0]; @@ -43,18 +45,15 @@ handle_subscribe(Client &client, Request args) 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; } @@ -66,14 +65,15 @@ handle_subscribe(Client &client, Request args) CommandResult handle_unsubscribe(Client &client, Request args) { + Response r(client); + assert(args.size == 1); const char *const channel_name = args[0]; 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; } } @@ -88,8 +88,9 @@ handle_channels(Client &client, gcc_unused Request args) channels.insert(c.subscriptions.begin(), c.subscriptions.end()); + Response r(client); 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; } @@ -100,11 +101,12 @@ handle_read_messages(Client &client, { assert(args.IsEmpty()); + Response r(client); 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(); } @@ -119,9 +121,9 @@ handle_send_message(Client &client, Request args) const char *const channel_name = args[0]; const char *const message_text = args[1]; + Response r(client); if (!client_message_valid_channel_name(channel_name)) { - command_error(client, ACK_ERROR_ARG, - "invalid channel name"); + r.Error(ACK_ERROR_ARG, "invalid channel name"); return CommandResult::ERROR; } @@ -134,8 +136,8 @@ handle_send_message(Client &client, Request args) 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/NeighborCommands.cxx b/src/command/NeighborCommands.cxx index 10dbe3074..d1b2ec7c7 100644 --- a/src/command/NeighborCommands.cxx +++ b/src/command/NeighborCommands.cxx @@ -21,9 +21,9 @@ #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" @@ -42,19 +42,19 @@ neighbor_commands_available(const Instance &instance) CommandResult handle_listneighbors(Client &client, gcc_unused Request args) { + Response r(client); + 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/OtherCommands.cxx b/src/command/OtherCommands.cxx index 2e20d8dd5..c1346ca44 100644 --- a/src/command/OtherCommands.cxx +++ b/src/command/OtherCommands.cxx @@ -32,7 +32,6 @@ #include "tag/TagHandler.hxx" #include "TimePrint.hxx" #include "decoder/DecoderPrint.hxx" -#include "protocol/Result.hxx" #include "ls.hxx" #include "mixer/Volume.hxx" #include "util/UriUtil.hxx" @@ -44,6 +43,7 @@ #include "PlaylistFile.hxx" #include "db/PlaylistVector.hxx" #include "client/Client.hxx" +#include "client/Response.hxx" #include "Partition.hxx" #include "Instance.hxx" #include "Idle.hxx" @@ -58,36 +58,39 @@ #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 Request args) { + Response r(client); 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 Request args) { - decoder_list_print(client); + Response r(client); + decoder_list_print(r); return CommandResult::OK; } CommandResult handle_tagtypes(Client &client, gcc_unused Request args) { - tag_print_types(client); + Response r(client); + tag_print_types(r); return CommandResult::OK; } @@ -106,14 +109,16 @@ handle_close(gcc_unused Client &client, gcc_unused Request args) 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, Request args) { + Response r(client); + /* default is root directory */ const auto uri = args.GetOptional(0, ""); @@ -124,7 +129,7 @@ handle_listfiles(Client &client, Request args) #ifdef ENABLE_DATABASE if (uri_has_scheme(uri)) /* use storage plugin to list remote directory */ - return handle_listfiles_storage(client, uri); + return handle_listfiles_storage(r, uri); /* must be a path relative to the configured music_directory */ @@ -132,14 +137,14 @@ handle_listfiles(Client &client, Request args) if (client.partition.instance.storage != nullptr) /* if we have a storage instance, obtain a list of files from it */ - return handle_listfiles_storage(client, + 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, uri); #else - command_error(client, ACK_ERROR_NO_EXIST, "No database"); + r.Error(ACK_ERROR_NO_EXIST, "No database"); return CommandResult::ERROR; #endif } @@ -156,42 +161,40 @@ handle_lsinfo(Client &client, Request args) /* default is root directory */ const auto uri = args.GetOptional(0, ""); + Response r(client); + 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"); + r.Error(ACK_ERROR_NO_EXIST, "unsupported file name"); return CommandResult::ERROR; } Error error; if (!client.AllowFile(path_fs, error)) - return print_error(client, error); + return print_error(r, error); DetachedSong song(path_utf8); if (!song.Update()) { - command_error(client, ACK_ERROR_NO_EXIST, - "No such file"); + r.Error(ACK_ERROR_NO_EXIST, "No such file"); return CommandResult::ERROR; } - song_print_info(client, song); + song_print_info(r, client.partition, song); return CommandResult::OK; } if (uri_has_scheme(uri)) { if (!uri_supported_scheme(uri)) { - command_error(client, ACK_ERROR_NO_EXIST, - "unsupported URI scheme"); + r.Error(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"); + if (!tag_stream_scan(uri, print_tag_handler, &r)) { + r.Error(ACK_ERROR_NO_EXIST, "No such file"); return CommandResult::ERROR; } @@ -207,10 +210,10 @@ handle_lsinfo(Client &client, Request args) 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 } @@ -224,13 +227,14 @@ static CommandResult handle_update(Client &client, UpdateService &update, const char *uri_utf8, bool discard) { + Response r(client); + 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; } } @@ -239,17 +243,19 @@ static CommandResult handle_update(Client &client, Database &db, const char *uri_utf8, bool discard) { + Response r(client); + 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; } } @@ -259,6 +265,8 @@ handle_update(Client &client, Database &db, static CommandResult handle_update(Client &client, Request args, bool discard) { + Response r(client); + #ifdef ENABLE_DATABASE const char *path = ""; @@ -270,8 +278,7 @@ handle_update(Client &client, Request args, bool discard) /* 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; } } @@ -288,7 +295,7 @@ handle_update(Client &client, Request args, bool discard) (void)discard; #endif - command_error(client, ACK_ERROR_NO_EXIST, "No database"); + r.Error(ACK_ERROR_NO_EXIST, "No database"); return CommandResult::ERROR; } @@ -307,13 +314,14 @@ handle_rescan(Client &client, gcc_unused Request args) CommandResult handle_setvol(Client &client, Request args) { + Response r(client); + unsigned level; - if (!args.Parse(0, level, client, 100)) + if (!args.Parse(0, level, r, 100)) return CommandResult::ERROR; if (!volume_level_change(client.partition.outputs, level)) { - command_error(client, ACK_ERROR_SYSTEM, - "problems setting volume"); + r.Error(ACK_ERROR_SYSTEM, "problems setting volume"); return CommandResult::ERROR; } @@ -323,13 +331,15 @@ handle_setvol(Client &client, Request args) CommandResult handle_volume(Client &client, Request args) { + Response r(client); + int relative; - if (!args.Parse(0, relative, client, -100, 100)) + if (!args.Parse(0, relative, r, -100, 100)) 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; } @@ -341,8 +351,7 @@ handle_volume(Client &client, Request args) 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; } @@ -352,7 +361,8 @@ handle_volume(Client &client, Request args) CommandResult handle_stats(Client &client, gcc_unused Request args) { - stats_print(client); + Response r(client); + stats_print(r, client.partition); return CommandResult::OK; } @@ -365,10 +375,11 @@ handle_ping(gcc_unused Client &client, gcc_unused Request args) CommandResult handle_password(Client &client, Request args) { - unsigned permission = 0; + Response r(client); + unsigned permission = 0; if (getPermissionFromPassword(args.front(), &permission) < 0) { - command_error(client, ACK_ERROR_PASSWORD, "incorrect password"); + r.Error(ACK_ERROR_PASSWORD, "incorrect password"); return CommandResult::ERROR; } @@ -380,9 +391,11 @@ handle_password(Client &client, Request args) CommandResult handle_config(Client &client, gcc_unused Request args) { + Response r(client); + 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; } @@ -390,7 +403,7 @@ handle_config(Client &client, gcc_unused Request args) 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 @@ -400,14 +413,14 @@ handle_config(Client &client, gcc_unused Request args) CommandResult handle_idle(Client &client, Request args) { - unsigned flags = 0; + Response r(client); + unsigned flags = 0; for (const char *i : args) { unsigned event = idle_parse_name(i); if (event == 0) { - command_error(client, ACK_ERROR_ARG, - "Unrecognized idle event: %s", - i); + r.FormatError(ACK_ERROR_ARG, + "Unrecognized idle event: %s", i); return CommandResult::ERROR; } diff --git a/src/command/OutputCommands.cxx b/src/command/OutputCommands.cxx index 39602aba8..472516860 100644 --- a/src/command/OutputCommands.cxx +++ b/src/command/OutputCommands.cxx @@ -22,23 +22,23 @@ #include "Request.hxx" #include "output/OutputPrint.hxx" #include "output/OutputCommand.hxx" -#include "protocol/Result.hxx" #include "client/Client.hxx" +#include "client/Response.hxx" #include "Partition.hxx" #include "util/ConstBuffer.hxx" CommandResult handle_enableoutput(Client &client, Request args) { - assert(args.size == 1); + Response r(client); + assert(args.size == 1); unsigned device; - if (!args.Parse(0, device, client)) + 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; } @@ -48,15 +48,15 @@ handle_enableoutput(Client &client, Request args) CommandResult handle_disableoutput(Client &client, Request args) { - assert(args.size == 1); + Response r(client); + assert(args.size == 1); unsigned device; - if (!args.Parse(0, device, client)) + 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; } @@ -66,15 +66,15 @@ handle_disableoutput(Client &client, Request args) CommandResult handle_toggleoutput(Client &client, Request args) { - assert(args.size == 1); + Response r(client); + assert(args.size == 1); unsigned device; - if (!args.Parse(0, device, client)) + 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; } @@ -86,7 +86,8 @@ handle_devices(Client &client, gcc_unused Request args) { assert(args.IsEmpty()); - printAudioDevices(client, client.partition.outputs); + Response r(client); + printAudioDevices(r, client.partition.outputs); return CommandResult::OK; } diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx index e0c0f61a8..3e58cecb1 100644 --- a/src/command/PlayerCommands.cxx +++ b/src/command/PlayerCommands.cxx @@ -24,10 +24,10 @@ #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 "AudioFormat.hxx" #include "ReplayGainConfig.hxx" #include "util/ConstBuffer.hxx" @@ -59,23 +59,27 @@ CommandResult handle_play(Client &client, Request args) { + Response r(client); + int song = -1; - if (!args.ParseOptional(0, song, client)) + 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, Request args) { + Response r(client); + int id = -1; - if (!args.ParseOptional(0, id, client)) + 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 @@ -88,16 +92,19 @@ handle_stop(Client &client, gcc_unused Request args) CommandResult handle_currentsong(Client &client, gcc_unused Request args) { - playlist_print_current(client, client.playlist); + Response r(client); + playlist_print_current(r, client.partition, client.playlist); return CommandResult::OK; } CommandResult handle_pause(Client &client, Request args) { + Response r(client); + if (!args.IsEmpty()) { bool pause_flag; - if (!args.Parse(0, pause_flag, client)) + if (!args.Parse(0, pause_flag, r)) return CommandResult::ERROR; client.player_control.SetPause(pause_flag); @@ -127,68 +134,64 @@ handle_status(Client &client, gcc_unused Request args) break; } + Response r(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()) - client_printf(client, "duration: %1.3f\n", - player_status.total_time.ToDoubleS()); + 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,25 +201,21 @@ handle_status(Client &client, gcc_unused Request args) ? 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; } @@ -247,8 +246,10 @@ handle_previous(Client &client, gcc_unused Request args) CommandResult handle_repeat(Client &client, Request args) { + Response r(client); + bool status; - if (!args.Parse(0, status, client)) + if (!args.Parse(0, status, r)) return CommandResult::ERROR; client.partition.SetRepeat(status); @@ -258,8 +259,10 @@ handle_repeat(Client &client, Request args) CommandResult handle_single(Client &client, Request args) { + Response r(client); + bool status; - if (!args.Parse(0, status, client)) + if (!args.Parse(0, status, r)) return CommandResult::ERROR; client.partition.SetSingle(status); @@ -269,8 +272,10 @@ handle_single(Client &client, Request args) CommandResult handle_consume(Client &client, Request args) { + Response r(client); + bool status; - if (!args.Parse(0, status, client)) + if (!args.Parse(0, status, r)) return CommandResult::ERROR; client.partition.SetConsume(status); @@ -280,8 +285,10 @@ handle_consume(Client &client, Request args) CommandResult handle_random(Client &client, Request args) { + Response r(client); + bool status; - if (!args.Parse(0, status, client)) + if (!args.Parse(0, status, r)) return CommandResult::ERROR; client.partition.SetRandom(status); @@ -299,53 +306,58 @@ handle_clearerror(gcc_unused Client &client, gcc_unused Request args) CommandResult handle_seek(Client &client, Request args) { + Response r(client); + unsigned song; SongTime seek_time; - - if (!args.Parse(0, song, client)) - return CommandResult::ERROR; - if (!args.Parse(1, seek_time, client)) + 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, Request args) { + Response r(client); + unsigned id; SongTime seek_time; - if (!args.Parse(0, id, client)) + if (!args.Parse(0, id, r)) return CommandResult::ERROR; - if (!args.Parse(1, seek_time, client)) + 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, Request args) { + Response r(client); + 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, Request args) { + Response r(client); + unsigned xfade_time; - if (!args.Parse(0, xfade_time, client)) + if (!args.Parse(0, xfade_time, r)) return CommandResult::ERROR; client.player_control.SetCrossFade(xfade_time); @@ -355,8 +367,10 @@ handle_crossfade(Client &client, Request args) CommandResult handle_mixrampdb(Client &client, Request args) { + Response r(client); + float db; - if (!args.Parse(0, db, client)) + if (!args.Parse(0, db, r)) return CommandResult::ERROR; client.player_control.SetMixRampDb(db); @@ -366,8 +380,10 @@ handle_mixrampdb(Client &client, Request args) CommandResult handle_mixrampdelay(Client &client, Request args) { + Response r(client); + float delay_secs; - if (!args.Parse(0, delay_secs, client)) + if (!args.Parse(0, delay_secs, r)) return CommandResult::ERROR; client.player_control.SetMixRampDelay(delay_secs); @@ -378,9 +394,10 @@ handle_mixrampdelay(Client &client, Request args) CommandResult handle_replay_gain_mode(Client &client, Request args) { + Response r(client); + if (!replay_gain_set_mode_string(args.front())) { - command_error(client, ACK_ERROR_ARG, - "Unrecognized replay gain mode"); + r.Error(ACK_ERROR_ARG, "Unrecognized replay gain mode"); return CommandResult::ERROR; } @@ -391,7 +408,7 @@ handle_replay_gain_mode(Client &client, Request args) CommandResult handle_replay_gain_status(Client &client, gcc_unused Request args) { - client_printf(client, "replay_gain_mode: %s\n", - replay_gain_get_mode_string()); + Response r(client); + r.Format("replay_gain_mode: %s\n", replay_gain_get_mode_string()); return CommandResult::OK; } diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx index 0122cecbd..1e075e088 100644 --- a/src/command/PlaylistCommands.cxx +++ b/src/command/PlaylistCommands.cxx @@ -33,7 +33,7 @@ #include "queue/Playlist.hxx" #include "TimePrint.hxx" #include "client/Client.hxx" -#include "protocol/Result.hxx" +#include "client/Response.hxx" #include "ls.hxx" #include "Mapper.hxx" #include "fs/AllocatedPath.hxx" @@ -48,30 +48,33 @@ playlist_commands_available() } 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, Request args) { + Response r(client); Error error; return spl_save_playlist(args.front(), client.playlist, error) ? CommandResult::OK - : print_error(client, error); + : print_error(r, error); } CommandResult handle_load(Client &client, Request args) { + Response r(client); + RangeArg range = RangeArg::All(); - if (!args.ParseOptional(1, range, client)) + if (!args.ParseOptional(1, range, r)) return CommandResult::ERROR; const ScopeBulkEdit bulk_edit(client.partition); @@ -82,7 +85,7 @@ handle_load(Client &client, Request args) range.start, range.end, client.playlist, client.player_control, loader, error)) - return print_error(client, error); + return print_error(r, error); return CommandResult::OK; } @@ -90,97 +93,114 @@ handle_load(Client &client, Request args) CommandResult handle_listplaylist(Client &client, Request args) { + Response r(client); + const char *const name = args.front(); - if (playlist_file_print(client, name, false)) + if (playlist_file_print(r, client.partition, SongLoader(client), + name, false)) return CommandResult::OK; Error error; - return spl_print(client, name, 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, Request args) { + Response r(client); + const char *const name = args.front(); - if (playlist_file_print(client, name, true)) + if (playlist_file_print(r, client.partition, SongLoader(client), + name, true)) return CommandResult::OK; Error error; - return spl_print(client, name, 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, Request args) { + Response r(client); + const char *const name = args.front(); Error error; return spl_delete(name, error) ? CommandResult::OK - : print_error(client, error); + : print_error(r, error); } CommandResult handle_rename(Client &client, Request args) { + Response r(client); + const char *const old_name = args[0]; const char *const new_name = args[1]; Error error; return spl_rename(old_name, new_name, error) ? CommandResult::OK - : print_error(client, error); + : print_error(r, error); } CommandResult handle_playlistdelete(Client &client, Request args) { + Response r(client); + const char *const name = args[0]; unsigned from; - if (!args.Parse(1, from, client)) + if (!args.Parse(1, from, r)) return CommandResult::ERROR; Error error; return spl_remove_index(name, from, error) ? CommandResult::OK - : print_error(client, error); + : print_error(r, error); } CommandResult handle_playlistmove(Client &client, Request args) { + Response r(client); + const char *const name = args.front(); unsigned from, to; - if (!args.Parse(1, from, client) || - !args.Parse(2, to, client)) + if (!args.Parse(1, from, r) || !args.Parse(2, to, r)) return CommandResult::ERROR; Error error; return spl_move_index(name, from, to, error) ? CommandResult::OK - : print_error(client, error); + : print_error(r, error); } CommandResult handle_playlistclear(Client &client, Request args) { + Response r(client); + const char *const name = args.front(); Error error; return spl_clear(name, error) ? CommandResult::OK - : print_error(client, error); + : print_error(r, error); } CommandResult handle_playlistadd(Client &client, Request args) { + Response r(client); + const char *const playlist = args[0]; const char *const uri = args[1]; @@ -193,7 +213,7 @@ handle_playlistadd(Client &client, Request args) #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, @@ -204,22 +224,23 @@ handle_playlistadd(Client &client, Request args) } 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 Request args) { + Response r(client); + 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/QueueCommands.cxx b/src/command/QueueCommands.cxx index 1413a68c9..850631ded 100644 --- a/src/command/QueueCommands.cxx +++ b/src/command/QueueCommands.cxx @@ -28,9 +28,9 @@ #include "queue/Playlist.hxx" #include "PlaylistPrint.hxx" #include "client/Client.hxx" +#include "client/Response.hxx" #include "Partition.hxx" #include "BulkEdit.hxx" -#include "protocol/Result.hxx" #include "ls.hxx" #include "util/ConstBuffer.hxx" #include "util/UriUtil.hxx" @@ -56,6 +56,8 @@ translate_uri(const char *uri) CommandResult handle_add(Client &client, Request args) { + Response r(client); + const char *uri = args.front(); if (memcmp(uri, "/", 2) == 0) /* this URI is malformed, but some clients are buggy @@ -72,7 +74,7 @@ handle_add(Client &client, Request args) Error error; unsigned id = client.partition.AppendURI(loader, uri, error); if (id == 0) - return print_error(client, error); + return print_error(r, error); return CommandResult::OK; } @@ -84,9 +86,9 @@ handle_add(Client &client, Request args) Error error; return AddFromDatabase(client.partition, selection, error) ? CommandResult::OK - : print_error(client, error); + : print_error(r, error); #else - command_error(client, ACK_ERROR_NO_EXIST, "No database"); + r.Error(ACK_ERROR_NO_EXIST, "No database"); return CommandResult::ERROR; #endif } @@ -94,29 +96,31 @@ handle_add(Client &client, Request args) CommandResult handle_addid(Client &client, Request args) { + Response r(client); + const char *const uri = translate_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 (args.size == 2) { unsigned to; - if (!args.Parse(1, to, client)) + 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; } @@ -154,13 +158,15 @@ parse_time_range(const char *p, SongTime &start_r, SongTime &end_r) CommandResult handle_rangeid(Client &client, Request args) { + Response r(client); + unsigned id; - if (!args.Parse(0, id, client)) + if (!args.Parse(0, id, r)) return CommandResult::ERROR; SongTime start, end; if (!parse_time_range(args[1], start, end)) { - command_error(client, ACK_ERROR_ARG, "Bad range"); + r.Error(ACK_ERROR_ARG, "Bad range"); return CommandResult::ERROR; } @@ -168,7 +174,7 @@ handle_rangeid(Client &client, Request args) 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; } @@ -176,37 +182,44 @@ handle_rangeid(Client &client, Request args) CommandResult handle_delete(Client &client, Request args) { + Response r(client); + RangeArg range; - if (!args.Parse(0, range, client)) + if (!args.Parse(0, range, r)) return CommandResult::ERROR; auto result = client.partition.DeleteRange(range.start, range.end); - return print_playlist_result(client, result); + return print_playlist_result(r, result); } CommandResult handle_deleteid(Client &client, Request args) { + Response r(client); + unsigned id; - if (!args.Parse(0, id, client)) + 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 Request args) { - playlist_print_uris(client, client.playlist); + Response r(client); + playlist_print_uris(r, client.partition, client.playlist); return CommandResult::OK; } CommandResult handle_shuffle(gcc_unused Client &client, Request args) { + Response r(client); + RangeArg range = RangeArg::All(); - if (!args.ParseOptional(0, range, client)) + if (!args.ParseOptional(0, range, r)) return CommandResult::ERROR; client.partition.Shuffle(range.start, range.end); @@ -223,37 +236,42 @@ handle_clear(gcc_unused Client &client, gcc_unused Request args) CommandResult handle_plchanges(Client &client, Request args) { - uint32_t version; + Response r(client); - if (!check_uint32(client, &version, args.front())) + uint32_t version; + 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, Request args) { - uint32_t version; + Response r(client); - if (!check_uint32(client, &version, args.front())) + uint32_t version; + 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, Request args) { + Response r(client); + RangeArg range = RangeArg::All(); - if (!args.ParseOptional(0, range, client)) + if (!args.ParseOptional(0, range, r)) return CommandResult::ERROR; - if (!playlist_print_info(client, client.playlist, + if (!playlist_print_info(r, client.partition, client.playlist, range.start, range.end)) - return print_playlist_result(client, + return print_playlist_result(r, PlaylistResult::BAD_RANGE); return CommandResult::OK; @@ -262,17 +280,19 @@ handle_playlistinfo(Client &client, Request args) CommandResult handle_playlistid(Client &client, Request args) { + Response r(client); + if (!args.IsEmpty()) { unsigned id; - if (!args.Parse(0, id, client)) + 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()); } @@ -283,13 +303,15 @@ static CommandResult handle_playlist_match(Client &client, Request args, bool fold_case) { + Response r(client); + 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; } @@ -308,13 +330,15 @@ handle_playlistsearch(Client &client, Request args) CommandResult handle_prio(Client &client, Request args) { + Response r(client); + unsigned priority; - if (!args.ParseShift(0, priority, client, 0xff)) + if (!args.ParseShift(0, priority, r, 0xff)) return CommandResult::ERROR; for (const char *i : args) { RangeArg range; - if (!ParseCommandArg(client, range, i)) + if (!ParseCommandArg(r, range, i)) return CommandResult::ERROR; PlaylistResult result = @@ -322,7 +346,7 @@ handle_prio(Client &client, Request args) range.end, priority); if (result != PlaylistResult::SUCCESS) - return print_playlist_result(client, result); + return print_playlist_result(r, result); } return CommandResult::OK; @@ -331,19 +355,21 @@ handle_prio(Client &client, Request args) CommandResult handle_prioid(Client &client, Request args) { + Response r(client); + unsigned priority; - if (!args.ParseShift(0, priority, client, 0xff)) + if (!args.ParseShift(0, priority, r, 0xff)) return CommandResult::ERROR; for (const char *i : args) { unsigned song_id; - if (!ParseCommandArg(client, song_id, 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; @@ -352,52 +378,56 @@ handle_prioid(Client &client, Request args) CommandResult handle_move(Client &client, Request args) { + Response r(client); + RangeArg range; int to; - if (!args.Parse(0, range, client) || - !args.Parse(1, to, client)) + if (!args.Parse(0, range, r) || !args.Parse(1, to, r)) return CommandResult::ERROR; PlaylistResult result = client.partition.MoveRange(range.start, range.end, to); - return print_playlist_result(client, result); + return print_playlist_result(r, result); } CommandResult handle_moveid(Client &client, Request args) { + Response r(client); + unsigned id; int to; - if (!args.Parse(0, id, client) || - !args.Parse(1, to, client)) + 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, Request args) { + Response r(client); + unsigned song1, song2; - if (!args.Parse(0, song1, client) || - !args.Parse(1, song2, client)) + 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, Request args) { + Response r(client); + unsigned id1, id2; - if (!args.Parse(0, id1, client) || - !args.Parse(1, id2, client)) + 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/Request.hxx b/src/command/Request.hxx index 38b3c584c..1616b7045 100644 --- a/src/command/Request.hxx +++ b/src/command/Request.hxx @@ -28,7 +28,7 @@ #include <assert.h> -class Client; +class Response; class Request : public ConstBuffer<const char *> { typedef ConstBuffer<const char *> Base; @@ -45,26 +45,26 @@ public: } template<typename T, typename... Args> - bool Parse(unsigned idx, T &value_r, Client &client, + bool Parse(unsigned idx, T &value_r, Response &r, Args&&... args) { assert(idx < size); - return ParseCommandArg(client, value_r, data[idx], + return ParseCommandArg(r, value_r, data[idx], std::forward<Args>(args)...); } template<typename T, typename... Args> - bool ParseOptional(unsigned idx, T &value_r, Client &client, + bool ParseOptional(unsigned idx, T &value_r, Response &r, Args&&... args) { return idx >= size || - Parse(idx, value_r, client, + Parse(idx, value_r, r, std::forward<Args>(args)...); } template<typename T, typename... Args> - bool ParseShift(unsigned idx, T &value_r, Client &client, + bool ParseShift(unsigned idx, T &value_r, Response &r, Args&&... args) { - bool success = Parse(idx, value_r, client, + bool success = Parse(idx, value_r, r, std::forward<Args>(args)...); shift(); return success; diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx index a28408547..25d354b2e 100644 --- a/src/command/StickerCommands.cxx +++ b/src/command/StickerCommands.cxx @@ -27,8 +27,8 @@ #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" @@ -37,7 +37,8 @@ #include <string.h> struct sticker_song_find_data { - Client &client; + Response &r; + Partition &partition; const char *name; }; @@ -48,17 +49,17 @@ 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, Request args) +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(); @@ -66,53 +67,52 @@ handle_sticker_song(Client &client, Request args) if (args.size == 4 && strcmp(cmd, "get") == 0) { 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, args[3], error); db->ReturnSong(song); if (value.empty()) { if (error.IsDefined()) - return print_error(client, error); + return print_error(r, error); - command_error(client, ACK_ERROR_NO_EXIST, - "no such sticker"); + r.Error(ACK_ERROR_NO_EXIST, "no such sticker"); return CommandResult::ERROR; } - sticker_print_value(client, args[3], value.c_str()); + sticker_print_value(r, args[3], value.c_str()); return CommandResult::OK; /* list song song_id */ } else if (args.size == 3 && strcmp(cmd, "list") == 0) { 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, error); db->ReturnSong(song); if (sticker) { - sticker_print(client, *sticker); + sticker_print(r, *sticker); sticker_free(sticker); } else if (error.IsDefined()) - return print_error(client, error); + return print_error(r, error); return CommandResult::OK; /* set song song_id id key */ } else if (args.size == 5 && strcmp(cmd, "set") == 0) { 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, args[3], args[4], error); db->ReturnSong(song); if (!ret) { if (error.IsDefined()) - return print_error(client, error); + return print_error(r, error); - command_error(client, ACK_ERROR_SYSTEM, - "failed to set sticker value"); + r.Error(ACK_ERROR_SYSTEM, + "failed to set sticker value"); return CommandResult::ERROR; } @@ -122,7 +122,7 @@ handle_sticker_song(Client &client, Request args) strcmp(cmd, "delete") == 0) { const LightSong *song = db->GetSong(args[2], error); if (song == nullptr) - return print_error(client, error); + return print_error(r, error); bool ret = args.size == 3 ? sticker_song_delete(*song, error) @@ -130,10 +130,9 @@ handle_sticker_song(Client &client, Request args) db->ReturnSong(song); if (!ret) { if (error.IsDefined()) - return print_error(client, error); + return print_error(r, error); - command_error(client, ACK_ERROR_SYSTEM, - "no such sticker"); + r.Error(ACK_ERROR_SYSTEM, "no such sticker"); return CommandResult::ERROR; } @@ -161,14 +160,14 @@ handle_sticker_song(Client &client, Request args) else if (strcmp(op_s, ">") == 0) op = StickerOperator::GREATER_THAN; else { - command_error(client, ACK_ERROR_ARG, - "bad operator"); + r.Error(ACK_ERROR_ARG, "bad operator"); return CommandResult::ERROR; } } struct sticker_song_find_data data = { - client, + r, + partition, args[3], }; @@ -177,16 +176,16 @@ handle_sticker_song(Client &client, Request args) sticker_song_find_print_cb, &data, error)) { if (error.IsDefined()) - return print_error(client, error); + return print_error(r, error); - command_error(client, ACK_ERROR_SYSTEM, - "failed to set search sticker database"); + 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; } } @@ -194,19 +193,19 @@ handle_sticker_song(Client &client, Request args) CommandResult handle_sticker(Client &client, Request args) { + Response r(client); + 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(args[1], "song") == 0) - return handle_sticker_song(client, args); + 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/StorageCommands.cxx b/src/command/StorageCommands.cxx index 3f1e5f321..edf2f60b8 100644 --- a/src/command/StorageCommands.cxx +++ b/src/command/StorageCommands.cxx @@ -23,12 +23,12 @@ #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" @@ -57,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; @@ -75,19 +75,19 @@ handle_listfiles_storage(Client &client, StorageDirectoryReader &reader, continue; case StorageFileInfo::Type::REGULAR: - client_printf(client, "file: %s\n" - "size: %" PRIu64 "\n", - name_utf8, - info.size); + r.Format("file: %s\n" + "size: %" PRIu64 "\n", + name_utf8, + info.size); break; case StorageFileInfo::Type::DIRECTORY: - client_printf(client, "directory: %s\n", name_utf8); + 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; @@ -98,52 +98,51 @@ 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()) @@ -165,24 +164,26 @@ 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 Request args) { + Response r(client); + 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); @@ -193,9 +194,11 @@ handle_listmounts(Client &client, gcc_unused Request args) CommandResult handle_mount(Client &client, Request args) { + Response r(client); + 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; } @@ -205,7 +208,7 @@ handle_mount(Client &client, Request args) 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; } @@ -215,7 +218,7 @@ handle_mount(Client &client, Request args) 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; } @@ -224,10 +227,9 @@ handle_mount(Client &client, Request args) 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; } @@ -241,7 +243,7 @@ handle_mount(Client &client, Request args) 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()? @@ -256,9 +258,11 @@ handle_mount(Client &client, Request args) CommandResult handle_unmount(Client &client, Request args) { + Response r(client); + 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; } @@ -267,7 +271,7 @@ handle_unmount(Client &client, Request args) 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; } @@ -289,7 +293,7 @@ handle_unmount(Client &client, Request args) #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 f5f962042..bbc0149bd 100644 --- a/src/command/StorageCommands.hxx +++ b/src/command/StorageCommands.hxx @@ -25,12 +25,13 @@ 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, Request args); diff --git a/src/command/TagCommands.cxx b/src/command/TagCommands.cxx index 2690f39bf..35efa5859 100644 --- a/src/command/TagCommands.cxx +++ b/src/command/TagCommands.cxx @@ -22,7 +22,7 @@ #include "Request.hxx" #include "CommandError.hxx" #include "client/Client.hxx" -#include "protocol/Result.hxx" +#include "client/Response.hxx" #include "tag/Tag.hxx" #include "Partition.hxx" #include "util/ConstBuffer.hxx" @@ -30,15 +30,16 @@ CommandResult handle_addtagid(Client &client, Request args) { + Response r(client); + unsigned song_id; - if (!args.Parse(0, song_id, client)) + if (!args.Parse(0, song_id, r)) return CommandResult::ERROR; 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; } @@ -47,7 +48,7 @@ handle_addtagid(Client &client, Request args) 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; } @@ -55,8 +56,10 @@ handle_addtagid(Client &client, Request args) CommandResult handle_cleartagid(Client &client, Request args) { + Response r(client); + unsigned song_id; - if (!args.Parse(0, song_id, client)) + if (!args.Parse(0, song_id, r)) return CommandResult::ERROR; TagType tag_type = TAG_NUM_OF_ITEM_TYPES; @@ -64,7 +67,7 @@ handle_cleartagid(Client &client, Request args) 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; } @@ -73,7 +76,7 @@ handle_cleartagid(Client &client, Request args) 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; } |