aboutsummaryrefslogtreecommitdiffstats
path: root/src/command/QueueCommands.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/command/QueueCommands.cxx305
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);
}