diff options
Diffstat (limited to '')
-rw-r--r-- | src/command/QueueCommands.cxx | 305 |
1 files changed, 143 insertions, 162 deletions
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); } |