QueueCommands.cxx 9.51 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2013 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"
#include "QueueCommands.hxx"
22
#include "CommandError.hxx"
23
#include "DatabaseQueue.hxx"
24
#include "SongFilter.hxx"
25
#include "DatabaseSelection.hxx"
26
#include "Playlist.hxx"
27
#include "PlaylistPrint.hxx"
Max Kellermann's avatar
Max Kellermann committed
28 29
#include "ClientFile.hxx"
#include "ClientInternal.hxx"
30
#include "Partition.hxx"
Max Kellermann's avatar
Max Kellermann committed
31 32
#include "protocol/ArgParser.hxx"
#include "protocol/Result.hxx"
Max Kellermann's avatar
Max Kellermann committed
33
#include "ls.hxx"
34 35 36 37 38 39 40 41

extern "C" {
#include "uri.h"
}

#include <string.h>

enum command_return
42
handle_add(Client *client, G_GNUC_UNUSED int argc, char *argv[])
43 44 45 46 47 48 49 50 51 52 53
{
	char *uri = argv[1];
	enum playlist_result result;

	if (strncmp(uri, "file:///", 8) == 0) {
		const char *path = uri + 7;

		GError *error = NULL;
		if (!client_allow_file(client, path, &error))
			return print_error(client, error);

54
		result = client->partition.AppendFile(path);
55 56 57 58 59 60 61 62 63 64
		return print_playlist_result(client, result);
	}

	if (uri_has_scheme(uri)) {
		if (!uri_supported_scheme(uri)) {
			command_error(client, ACK_ERROR_NO_EXIST,
				      "unsupported URI scheme");
			return COMMAND_RETURN_ERROR;
		}

65
		result = client->partition.AppendURI(uri);
66 67 68
		return print_playlist_result(client, result);
	}

69
	const DatabaseSelection selection(uri, true);
70
	GError *error = NULL;
71
	return AddFromDatabase(client->partition, selection, &error)
72 73 74 75 76
		? COMMAND_RETURN_OK
		: print_error(client, error);
}

enum command_return
77
handle_addid(Client *client, int argc, char *argv[])
78 79 80 81 82 83 84 85 86 87 88 89
{
	char *uri = argv[1];
	unsigned added_id;
	enum playlist_result result;

	if (strncmp(uri, "file:///", 8) == 0) {
		const char *path = uri + 7;

		GError *error = NULL;
		if (!client_allow_file(client, path, &error))
			return print_error(client, error);

90
		result = client->partition.AppendFile(path, &added_id);
91 92 93 94 95 96 97
	} else {
		if (uri_has_scheme(uri) && !uri_supported_scheme(uri)) {
			command_error(client, ACK_ERROR_NO_EXIST,
				      "unsupported URI scheme");
			return COMMAND_RETURN_ERROR;
		}

98
		result = client->partition.AppendURI(uri, &added_id);
99 100 101 102 103 104 105 106 107
	}

	if (result != PLAYLIST_RESULT_SUCCESS)
		return print_playlist_result(client, result);

	if (argc == 3) {
		unsigned to;
		if (!check_unsigned(client, &to, argv[2]))
			return COMMAND_RETURN_ERROR;
108
		result = client->partition.MoveId(added_id, to);
109 110 111
		if (result != PLAYLIST_RESULT_SUCCESS) {
			enum command_return ret =
				print_playlist_result(client, result);
112
			client->partition.DeleteId(added_id);
113 114 115 116 117 118 119 120 121
			return ret;
		}
	}

	client_printf(client, "Id: %u\n", added_id);
	return COMMAND_RETURN_OK;
}

enum command_return
122
handle_delete(Client *client, G_GNUC_UNUSED int argc, char *argv[])
123 124 125 126 127 128
{
	unsigned start, end;

	if (!check_range(client, &start, &end, argv[1]))
		return COMMAND_RETURN_ERROR;

129
	enum playlist_result result = client->partition.DeleteRange(start, end);
130 131 132 133
	return print_playlist_result(client, result);
}

enum command_return
134
handle_deleteid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
135 136 137 138 139 140
{
	unsigned id;

	if (!check_unsigned(client, &id, argv[1]))
		return COMMAND_RETURN_ERROR;

141
	enum playlist_result result = client->partition.DeleteId(id);
142 143 144 145
	return print_playlist_result(client, result);
}

enum command_return
146
handle_playlist(Client *client,
147 148
	        G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
149
	playlist_print_uris(client, &client->playlist);
150 151 152 153
	return COMMAND_RETURN_OK;
}

enum command_return
154
handle_shuffle(G_GNUC_UNUSED Client *client,
155 156
	       G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
157
	unsigned start = 0, end = client->playlist.queue.GetLength();
158 159 160
	if (argc == 2 && !check_range(client, &start, &end, argv[1]))
		return COMMAND_RETURN_ERROR;

161
	client->partition.Shuffle(start, end);
162 163 164 165
	return COMMAND_RETURN_OK;
}

enum command_return
166
handle_clear(G_GNUC_UNUSED Client *client,
167 168
	     G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
169
	client->partition.ClearQueue();
170 171 172 173
	return COMMAND_RETURN_OK;
}

enum command_return
174
handle_plchanges(Client *client, G_GNUC_UNUSED int argc, char *argv[])
175 176 177 178 179 180
{
	uint32_t version;

	if (!check_uint32(client, &version, argv[1]))
		return COMMAND_RETURN_ERROR;

181
	playlist_print_changes_info(client, &client->playlist, version);
182 183 184 185
	return COMMAND_RETURN_OK;
}

enum command_return
186
handle_plchangesposid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
187 188 189 190 191 192
{
	uint32_t version;

	if (!check_uint32(client, &version, argv[1]))
		return COMMAND_RETURN_ERROR;

193
	playlist_print_changes_position(client, &client->playlist, version);
194 195 196 197
	return COMMAND_RETURN_OK;
}

enum command_return
198
handle_playlistinfo(Client *client, int argc, char *argv[])
199 200 201 202 203 204 205
{
	unsigned start = 0, end = G_MAXUINT;
	bool ret;

	if (argc == 2 && !check_range(client, &start, &end, argv[1]))
		return COMMAND_RETURN_ERROR;

206
	ret = playlist_print_info(client, &client->playlist, start, end);
207 208 209 210 211 212 213 214
	if (!ret)
		return print_playlist_result(client,
					     PLAYLIST_RESULT_BAD_RANGE);

	return COMMAND_RETURN_OK;
}

enum command_return
215
handle_playlistid(Client *client, int argc, char *argv[])
216 217 218 219 220 221
{
	if (argc >= 2) {
		unsigned id;
		if (!check_unsigned(client, &id, argv[1]))
			return COMMAND_RETURN_ERROR;

222
		bool ret = playlist_print_id(client, &client->playlist, id);
223 224 225 226
		if (!ret)
			return print_playlist_result(client,
						     PLAYLIST_RESULT_NO_SUCH_SONG);
	} else {
227
		playlist_print_info(client, &client->playlist, 0, G_MAXUINT);
228 229 230 231 232 233
	}

	return COMMAND_RETURN_OK;
}

static enum command_return
234
handle_playlist_match(Client *client, int argc, char *argv[],
235 236
		      bool fold_case)
{
237 238
	SongFilter filter;
	if (!filter.Parse(argc - 1, argv + 1, fold_case)) {
239 240 241 242
		command_error(client, ACK_ERROR_ARG, "incorrect arguments");
		return COMMAND_RETURN_ERROR;
	}

243
	playlist_print_find(client, &client->playlist, filter);
244 245 246 247
	return COMMAND_RETURN_OK;
}

enum command_return
248
handle_playlistfind(Client *client, int argc, char *argv[])
249 250 251 252 253
{
	return handle_playlist_match(client, argc, argv, false);
}

enum command_return
254
handle_playlistsearch(Client *client, int argc, char *argv[])
255 256 257 258 259
{
	return handle_playlist_match(client, argc, argv, true);
}

enum command_return
260
handle_prio(Client *client, int argc, char *argv[])
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
{
	unsigned priority;

	if (!check_unsigned(client, &priority, argv[1]))
		return COMMAND_RETURN_ERROR;

	if (priority > 0xff) {
		command_error(client, ACK_ERROR_ARG,
			      "Priority out of range: %s", argv[1]);
		return COMMAND_RETURN_ERROR;
	}

	for (int i = 2; i < argc; ++i) {
		unsigned start_position, end_position;
		if (!check_range(client, &start_position, &end_position,
				 argv[i]))
			return COMMAND_RETURN_ERROR;

		enum playlist_result result =
280 281 282
			client->partition.SetPriorityRange(start_position,
							   end_position,
							   priority);
283 284 285 286 287 288 289 290
		if (result != PLAYLIST_RESULT_SUCCESS)
			return print_playlist_result(client, result);
	}

	return COMMAND_RETURN_OK;
}

enum command_return
291
handle_prioid(Client *client, int argc, char *argv[])
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
{
	unsigned priority;

	if (!check_unsigned(client, &priority, argv[1]))
		return COMMAND_RETURN_ERROR;

	if (priority > 0xff) {
		command_error(client, ACK_ERROR_ARG,
			      "Priority out of range: %s", argv[1]);
		return COMMAND_RETURN_ERROR;
	}

	for (int i = 2; i < argc; ++i) {
		unsigned song_id;
		if (!check_unsigned(client, &song_id, argv[i]))
			return COMMAND_RETURN_ERROR;

		enum playlist_result result =
310
			client->partition.SetPriorityId(song_id, priority);
311 312 313 314 315 316 317 318
		if (result != PLAYLIST_RESULT_SUCCESS)
			return print_playlist_result(client, result);
	}

	return COMMAND_RETURN_OK;
}

enum command_return
319
handle_move(Client *client, G_GNUC_UNUSED int argc, char *argv[])
320 321 322 323 324 325 326 327
{
	unsigned start, end;
	int to;

	if (!check_range(client, &start, &end, argv[1]))
		return COMMAND_RETURN_ERROR;
	if (!check_int(client, &to, argv[2]))
		return COMMAND_RETURN_ERROR;
328 329 330

	enum playlist_result result =
		client->partition.MoveRange(start, end, to);
331 332 333 334
	return print_playlist_result(client, result);
}

enum command_return
335
handle_moveid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
336 337 338 339 340 341 342 343
{
	unsigned id;
	int to;

	if (!check_unsigned(client, &id, argv[1]))
		return COMMAND_RETURN_ERROR;
	if (!check_int(client, &to, argv[2]))
		return COMMAND_RETURN_ERROR;
344
	enum playlist_result result = client->partition.MoveId(id, to);
345 346 347 348
	return print_playlist_result(client, result);
}

enum command_return
349
handle_swap(Client *client, G_GNUC_UNUSED int argc, char *argv[])
350 351 352 353 354 355 356
{
	unsigned song1, song2;

	if (!check_unsigned(client, &song1, argv[1]))
		return COMMAND_RETURN_ERROR;
	if (!check_unsigned(client, &song2, argv[2]))
		return COMMAND_RETURN_ERROR;
357 358 359

	enum playlist_result result =
		client->partition.SwapPositions(song1, song2);
360 361 362 363
	return print_playlist_result(client, result);
}

enum command_return
364
handle_swapid(Client *client, G_GNUC_UNUSED int argc, char *argv[])
365 366 367 368 369 370 371
{
	unsigned id1, id2;

	if (!check_unsigned(client, &id1, argv[1]))
		return COMMAND_RETURN_ERROR;
	if (!check_unsigned(client, &id2, argv[2]))
		return COMMAND_RETURN_ERROR;
372 373

	enum playlist_result result = client->partition.SwapIds(id1, id2);
374 375
	return print_playlist_result(client, result);
}