aboutsummaryrefslogtreecommitdiffstats
path: root/src/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/command.c')
-rw-r--r--src/command.c586
1 files changed, 439 insertions, 147 deletions
diff --git a/src/command.c b/src/command.c
index 64f161805..e6bf36ac9 100644
--- a/src/command.c
+++ b/src/command.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,12 +24,12 @@
#include "playlist_print.h"
#include "playlist_save.h"
#include "playlist_queue.h"
+#include "playlist_error.h"
#include "queue_print.h"
#include "ls.h"
#include "uri.h"
#include "decoder_print.h"
#include "directory.h"
-#include "directory_print.h"
#include "database.h"
#include "update.h"
#include "volume.h"
@@ -42,8 +42,14 @@
#include "output_print.h"
#include "locate.h"
#include "dbUtils.h"
+#include "db_error.h"
+#include "db_print.h"
+#include "db_selection.h"
#include "tag.h"
#include "client.h"
+#include "client_idle.h"
+#include "client_internal.h"
+#include "client_subscribe.h"
#include "tag_print.h"
#include "path.h"
#include "replay_gain_config.h"
@@ -372,6 +378,46 @@ print_playlist_result(struct client *client,
return COMMAND_RETURN_ERROR;
}
+/**
+ * Send the GError to the client and free the GError.
+ */
+static enum command_return
+print_error(struct client *client, GError *error)
+{
+ assert(client != NULL);
+ assert(error != NULL);
+
+ g_warning("%s", error->message);
+
+ if (error->domain == playlist_quark()) {
+ enum playlist_result result = error->code;
+ g_error_free(error);
+ return print_playlist_result(client, result);
+ } else if (error->domain == db_quark()) {
+ switch ((enum db_error)error->code) {
+ case DB_DISABLED:
+ command_error(client, ACK_ERROR_NO_EXIST, "%s",
+ error->message);
+ g_error_free(error);
+ return COMMAND_RETURN_ERROR;
+
+ case DB_NOT_FOUND:
+ g_error_free(error);
+ command_error(client, ACK_ERROR_NO_EXIST, "Not found");
+ return COMMAND_RETURN_ERROR;
+ }
+ } else if (error->domain == g_file_error_quark()) {
+ command_error(client, ACK_ERROR_SYSTEM, "%s",
+ g_strerror(error->code));
+ g_error_free(error);
+ return COMMAND_RETURN_ERROR;
+ }
+
+ g_error_free(error);
+ command_error(client, ACK_ERROR_UNKNOWN, "error");
+ return COMMAND_RETURN_ERROR;
+}
+
static void
print_spl_list(struct client *client, GPtrArray *list)
{
@@ -434,7 +480,7 @@ handle_play(struct client *client, int argc, char *argv[])
if (argc == 2 && !check_int(client, &song, argv[1], need_positive))
return COMMAND_RETURN_ERROR;
- result = playlist_play(&g_playlist, song);
+ result = playlist_play(&g_playlist, client->player_control, song);
return print_playlist_result(client, result);
}
@@ -447,7 +493,7 @@ handle_playid(struct client *client, int argc, char *argv[])
if (argc == 2 && !check_int(client, &id, argv[1], need_positive))
return COMMAND_RETURN_ERROR;
- result = playlist_play_id(&g_playlist, id);
+ result = playlist_play_id(&g_playlist, client->player_control, id);
return print_playlist_result(client, result);
}
@@ -455,7 +501,7 @@ static enum command_return
handle_stop(G_GNUC_UNUSED struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- playlist_stop(&g_playlist);
+ playlist_stop(&g_playlist, client->player_control);
return COMMAND_RETURN_OK;
}
@@ -476,9 +522,9 @@ handle_pause(struct client *client,
if (!check_bool(client, &pause_flag, argv[1]))
return COMMAND_RETURN_ERROR;
- pc_set_pause(pause_flag);
+ pc_set_pause(client->player_control, pause_flag);
} else
- pc_pause();
+ pc_pause(client->player_control);
return COMMAND_RETURN_OK;
}
@@ -493,7 +539,7 @@ handle_status(struct client *client,
char *error;
int song;
- pc_get_status(&player_status);
+ pc_get_status(client->player_control, &player_status);
switch (player_status.state) {
case PLAYER_STATE_STOP:
@@ -526,9 +572,9 @@ handle_status(struct client *client,
playlist_get_consume(&g_playlist),
playlist_get_version(&g_playlist),
playlist_get_length(&g_playlist),
- (int)(pc_get_cross_fade() + 0.5),
- pc_get_mixramp_db(),
- pc_get_mixramp_delay(),
+ (int)(pc_get_cross_fade(client->player_control) + 0.5),
+ pc_get_mixramp_db(client->player_control),
+ pc_get_mixramp_delay(client->player_control),
state);
song = playlist_get_current_song(&g_playlist);
@@ -561,7 +607,7 @@ handle_status(struct client *client,
updateJobId);
}
- error = pc_get_error_message();
+ error = pc_get_error_message(client->player_control);
if (error != NULL) {
client_printf(client,
COMMAND_STATUS_ERROR ": %s\n",
@@ -605,6 +651,7 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
result = PLAYLIST_RESULT_DENIED;
#else
result = playlist_append_file(&g_playlist,
+ client->player_control,
uri + 7, client_get_uid(client),
NULL);
#endif
@@ -618,18 +665,16 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- result = playlist_append_uri(&g_playlist, uri, NULL);
+ result = playlist_append_uri(&g_playlist,
+ client->player_control,
+ uri, NULL);
return print_playlist_result(client, result);
}
- result = addAllIn(uri);
- if (result == (enum playlist_result)-1) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
- return COMMAND_RETURN_ERROR;
- }
-
- return print_playlist_result(client, result);
+ GError *error = NULL;
+ return addAllIn(client->player_control, uri, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -643,7 +688,9 @@ handle_addid(struct client *client, int argc, char *argv[])
#ifdef WIN32
result = PLAYLIST_RESULT_DENIED;
#else
- result = playlist_append_file(&g_playlist, uri + 7,
+ result = playlist_append_file(&g_playlist,
+ client->player_control,
+ uri + 7,
client_get_uid(client),
&added_id);
#endif
@@ -654,7 +701,9 @@ handle_addid(struct client *client, int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- result = playlist_append_uri(&g_playlist, uri, &added_id);
+ result = playlist_append_uri(&g_playlist,
+ client->player_control,
+ uri, &added_id);
}
if (result != PLAYLIST_RESULT_SUCCESS)
@@ -664,11 +713,13 @@ handle_addid(struct client *client, int argc, char *argv[])
int to;
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_move_id(&g_playlist, added_id, to);
+ result = playlist_move_id(&g_playlist, client->player_control,
+ added_id, to);
if (result != PLAYLIST_RESULT_SUCCESS) {
enum command_return ret =
print_playlist_result(client, result);
- playlist_delete_id(&g_playlist, added_id);
+ playlist_delete_id(&g_playlist, client->player_control,
+ added_id);
return ret;
}
}
@@ -686,7 +737,8 @@ handle_delete(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_range(client, &start, &end, argv[1], need_range))
return COMMAND_RETURN_ERROR;
- result = playlist_delete_range(&g_playlist, start, end);
+ result = playlist_delete_range(&g_playlist, client->player_control,
+ start, end);
return print_playlist_result(client, result);
}
@@ -699,7 +751,7 @@ handle_deleteid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_int(client, &id, argv[1], need_positive))
return COMMAND_RETURN_ERROR;
- result = playlist_delete_id(&g_playlist, id);
+ result = playlist_delete_id(&g_playlist, client->player_control, id);
return print_playlist_result(client, result);
}
@@ -720,7 +772,7 @@ handle_shuffle(G_GNUC_UNUSED struct client *client,
argv[1], need_range))
return COMMAND_RETURN_ERROR;
- playlist_shuffle(&g_playlist, start, end);
+ playlist_shuffle(&g_playlist, client->player_control, start, end);
return COMMAND_RETURN_OK;
}
@@ -728,7 +780,7 @@ static enum command_return
handle_clear(G_GNUC_UNUSED struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- playlist_clear(&g_playlist);
+ playlist_clear(&g_playlist, client->player_control);
return COMMAND_RETURN_OK;
}
@@ -747,12 +799,16 @@ handle_load(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
enum playlist_result result;
- result = playlist_open_into_queue(argv[1], &g_playlist);
+ result = playlist_open_into_queue(argv[1], &g_playlist,
+ client->player_control, true);
if (result != PLAYLIST_RESULT_NO_SUCH_LIST)
return print_playlist_result(client, result);
- result = playlist_load_spl(&g_playlist, argv[1]);
- return print_playlist_result(client, result);
+ GError *error = NULL;
+ return playlist_load_spl(&g_playlist, client->player_control,
+ argv[1], &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -761,15 +817,10 @@ handle_listplaylist(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (playlist_file_print(client, argv[1], false))
return COMMAND_RETURN_OK;
- bool ret;
-
- ret = spl_print(client, argv[1], false);
- if (!ret) {
- command_error(client, ACK_ERROR_NO_EXIST, "No such playlist");
- return COMMAND_RETURN_ERROR;
- }
-
- return COMMAND_RETURN_OK;
+ GError *error = NULL;
+ return spl_print(client, argv[1], false, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -779,22 +830,16 @@ handle_listplaylistinfo(struct client *client,
if (playlist_file_print(client, argv[1], true))
return COMMAND_RETURN_OK;
- bool ret;
-
- ret = spl_print(client, argv[1], true);
- if (!ret) {
- command_error(client, ACK_ERROR_NO_EXIST, "No such playlist");
- return COMMAND_RETURN_ERROR;
- }
-
- return COMMAND_RETURN_OK;
+ GError *error = NULL;
+ return spl_print(client, argv[1], true, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
handle_lsinfo(struct client *client, int argc, char *argv[])
{
const char *uri;
- const struct directory *directory;
if (argc == 2)
uri = argv[1];
@@ -802,17 +847,15 @@ handle_lsinfo(struct client *client, int argc, char *argv[])
/* default is root directory */
uri = "";
- directory = db_get_directory(uri);
- if (directory == NULL) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory not found");
- return COMMAND_RETURN_ERROR;
- }
+ struct db_selection selection;
+ db_selection_init(&selection, uri, false);
- directory_print(client, directory);
+ GError *error = NULL;
+ if (!db_selection_print(client, &selection, true, &error))
+ return print_error(client, error);
if (isRootDirectory(uri)) {
- GPtrArray *list = spl_list();
+ GPtrArray *list = spl_list(NULL);
if (list != NULL) {
print_spl_list(client, list);
spl_list_free(list);
@@ -825,19 +868,19 @@ handle_lsinfo(struct client *client, int argc, char *argv[])
static enum command_return
handle_rm(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
- enum playlist_result result;
-
- result = spl_delete(argv[1]);
- return print_playlist_result(client, result);
+ GError *error = NULL;
+ return spl_delete(argv[1], &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
handle_rename(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
- enum playlist_result result;
-
- result = spl_rename(argv[1], argv[2]);
- return print_playlist_result(client, result);
+ GError *error = NULL;
+ return spl_rename(argv[1], argv[2], &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -905,7 +948,6 @@ handle_playlistid(struct client *client, int argc, char *argv[])
static enum command_return
handle_find(struct client *client, int argc, char *argv[])
{
- int ret;
struct locate_item_list *list =
locate_item_list_parse(argv + 1, argc - 1);
@@ -917,10 +959,10 @@ handle_find(struct client *client, int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- ret = findSongsIn(client, NULL, list);
- if (ret == -1)
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
+ GError *error = NULL;
+ enum command_return ret = findSongsIn(client, "", list, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
locate_item_list_free(list);
@@ -930,7 +972,6 @@ handle_find(struct client *client, int argc, char *argv[])
static enum command_return
handle_findadd(struct client *client, int argc, char *argv[])
{
- int ret;
struct locate_item_list *list =
locate_item_list_parse(argv + 1, argc - 1);
if (list == NULL || list->length == 0) {
@@ -941,10 +982,11 @@ handle_findadd(struct client *client, int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- ret = findAddIn(client, NULL, list);
- if (ret == -1)
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
+ GError *error = NULL;
+ enum command_return ret =
+ findAddIn(client->player_control, "", list, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
locate_item_list_free(list);
@@ -954,7 +996,6 @@ handle_findadd(struct client *client, int argc, char *argv[])
static enum command_return
handle_search(struct client *client, int argc, char *argv[])
{
- int ret;
struct locate_item_list *list =
locate_item_list_parse(argv + 1, argc - 1);
@@ -966,10 +1007,10 @@ handle_search(struct client *client, int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- ret = searchForSongsIn(client, NULL, list);
- if (ret == -1)
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
+ GError *error = NULL;
+ enum command_return ret = searchForSongsIn(client, "", list, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
locate_item_list_free(list);
@@ -979,7 +1020,6 @@ handle_search(struct client *client, int argc, char *argv[])
static enum command_return
handle_count(struct client *client, int argc, char *argv[])
{
- int ret;
struct locate_item_list *list =
locate_item_list_parse(argv + 1, argc - 1);
@@ -991,10 +1031,11 @@ handle_count(struct client *client, int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- ret = searchStatsForSongsIn(client, NULL, list);
- if (ret == -1)
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
+ GError *error = NULL;
+ enum command_return ret =
+ searchStatsForSongsIn(client, "", list, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
locate_item_list_free(list);
@@ -1048,13 +1089,14 @@ handle_playlistdelete(struct client *client,
G_GNUC_UNUSED int argc, char *argv[]) {
char *playlist = argv[1];
int from;
- enum playlist_result result;
if (!check_int(client, &from, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = spl_remove_index(playlist, from);
- return print_playlist_result(client, result);
+ GError *error = NULL;
+ return spl_remove_index(playlist, from, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -1062,15 +1104,16 @@ handle_playlistmove(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
char *playlist = argv[1];
int from, to;
- enum playlist_result result;
if (!check_int(client, &from, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
if (!check_int(client, &to, argv[3], check_integer, argv[3]))
return COMMAND_RETURN_ERROR;
- result = spl_move_index(playlist, from, to);
- return print_playlist_result(client, result);
+ GError *error = NULL;
+ return spl_move_index(playlist, from, to, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -1141,7 +1184,7 @@ handle_next(G_GNUC_UNUSED struct client *client,
int single = g_playlist.queue.single;
g_playlist.queue.single = false;
- playlist_next(&g_playlist);
+ playlist_next(&g_playlist, client->player_control);
g_playlist.queue.single = single;
return COMMAND_RETURN_OK;
@@ -1151,25 +1194,84 @@ static enum command_return
handle_previous(G_GNUC_UNUSED struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- playlist_previous(&g_playlist);
+ playlist_previous(&g_playlist, client->player_control);
+ return COMMAND_RETURN_OK;
+}
+
+static enum command_return
+handle_prio(struct client *client, int argc, char *argv[])
+{
+ 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], need_range))
+ return COMMAND_RETURN_ERROR;
+
+ enum playlist_result result =
+ playlist_set_priority(&g_playlist,
+ client->player_control,
+ start_position, end_position,
+ priority);
+ if (result != PLAYLIST_RESULT_SUCCESS)
+ return print_playlist_result(client, result);
+ }
+
+ return COMMAND_RETURN_OK;
+}
+
+static enum command_return
+handle_prioid(struct client *client, int argc, char *argv[])
+{
+ 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 =
+ playlist_set_priority_id(&g_playlist,
+ client->player_control,
+ song_id, priority);
+ if (result != PLAYLIST_RESULT_SUCCESS)
+ return print_playlist_result(client, result);
+ }
+
return COMMAND_RETURN_OK;
}
static enum command_return
handle_listall(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
- char *directory = NULL;
- int ret;
+ const char *directory = "";
if (argc == 2)
directory = argv[1];
- ret = printAllIn(client, directory);
- if (ret == -1)
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
-
- return ret;
+ GError *error = NULL;
+ return printAllIn(client, directory, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -1210,7 +1312,7 @@ handle_repeat(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- playlist_set_repeat(&g_playlist, status);
+ playlist_set_repeat(&g_playlist, client->player_control, status);
return COMMAND_RETURN_OK;
}
@@ -1228,7 +1330,7 @@ handle_single(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- playlist_set_single(&g_playlist, status);
+ playlist_set_single(&g_playlist, client->player_control, status);
return COMMAND_RETURN_OK;
}
@@ -1264,7 +1366,7 @@ handle_random(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- playlist_set_random(&g_playlist, status);
+ playlist_set_random(&g_playlist, client->player_control, status);
return COMMAND_RETURN_OK;
}
@@ -1279,7 +1381,7 @@ static enum command_return
handle_clearerror(G_GNUC_UNUSED struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- pc_clear_error();
+ pc_clear_error(client->player_control);
return COMMAND_RETURN_OK;
}
@@ -1288,7 +1390,6 @@ handle_list(struct client *client, int argc, char *argv[])
{
struct locate_item_list *conditionals;
int tagType = locate_parse_type(argv[1]);
- int ret;
if (tagType < 0) {
command_error(client, ACK_ERROR_ARG, "\"%s\" is not known", argv[1]);
@@ -1325,14 +1426,14 @@ handle_list(struct client *client, int argc, char *argv[])
}
}
- ret = listAllUniqueTags(client, tagType, conditionals);
+ GError *error = NULL;
+ enum command_return ret =
+ listAllUniqueTags(client, tagType, conditionals, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
locate_item_list_free(conditionals);
- if (ret == -1)
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
-
return ret;
}
@@ -1348,7 +1449,8 @@ handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_move_range(&g_playlist, start, end, to);
+ result = playlist_move_range(&g_playlist, client->player_control,
+ start, end, to);
return print_playlist_result(client, result);
}
@@ -1362,7 +1464,8 @@ handle_moveid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
if (!check_int(client, &to, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_move_id(&g_playlist, id, to);
+ result = playlist_move_id(&g_playlist, client->player_control,
+ id, to);
return print_playlist_result(client, result);
}
@@ -1376,7 +1479,8 @@ handle_swap(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
if (!check_int(client, &song2, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_swap_songs(&g_playlist, song1, song2);
+ result = playlist_swap_songs(&g_playlist, client->player_control,
+ song1, song2);
return print_playlist_result(client, result);
}
@@ -1390,7 +1494,8 @@ handle_swapid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
if (!check_int(client, &id2, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_swap_songs_id(&g_playlist, id1, id2);
+ result = playlist_swap_songs_id(&g_playlist, client->player_control,
+ id1, id2);
return print_playlist_result(client, result);
}
@@ -1405,7 +1510,8 @@ handle_seek(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_seek_song(&g_playlist, song, seek_time);
+ result = playlist_seek_song(&g_playlist, client->player_control,
+ song, seek_time);
return print_playlist_result(client, result);
}
@@ -1420,25 +1526,38 @@ handle_seekid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
return COMMAND_RETURN_ERROR;
- result = playlist_seek_song_id(&g_playlist, id, seek_time);
+ result = playlist_seek_song_id(&g_playlist, client->player_control,
+ id, seek_time);
+ return print_playlist_result(client, result);
+}
+
+static enum command_return
+handle_seekcur(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
+{
+ const char *p = argv[1];
+ bool relative = *p == '+' || *p == '-';
+ int seek_time;
+ if (!check_int(client, &seek_time, p, check_integer, p))
+ return COMMAND_RETURN_ERROR;
+
+ enum playlist_result result =
+ playlist_seek_current(&g_playlist, client->player_control,
+ seek_time, relative);
return print_playlist_result(client, result);
}
static enum command_return
handle_listallinfo(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
- char *directory = NULL;
- int ret;
+ const char *directory = "";
if (argc == 2)
directory = argv[1];
- ret = printInfoForAllIn(client, directory);
- if (ret == -1)
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
-
- return ret;
+ GError *error = NULL;
+ return printInfoForAllIn(client, directory, &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -1470,7 +1589,7 @@ handle_crossfade(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_unsigned(client, &xfade_time, argv[1]))
return COMMAND_RETURN_ERROR;
- pc_set_cross_fade(xfade_time);
+ pc_set_cross_fade(client->player_control, xfade_time);
return COMMAND_RETURN_OK;
}
@@ -1482,7 +1601,7 @@ handle_mixrampdb(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_float(client, &db, argv[1]))
return COMMAND_RETURN_ERROR;
- pc_set_mixramp_db(db);
+ pc_set_mixramp_db(client->player_control, db);
return COMMAND_RETURN_OK;
}
@@ -1494,7 +1613,7 @@ handle_mixrampdelay(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
if (!check_float(client, &delay_secs, argv[1]))
return COMMAND_RETURN_ERROR;
- pc_set_mixramp_delay(delay_secs);
+ pc_set_mixramp_delay(client->player_control, delay_secs);
return COMMAND_RETURN_OK;
}
@@ -1558,10 +1677,10 @@ handle_not_commands(struct client *client,
static enum command_return
handle_playlistclear(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
- enum playlist_result result;
-
- result = spl_clear(argv[1]);
- return print_playlist_result(client, result);
+ GError *error = NULL;
+ return spl_clear(argv[1], &error)
+ ? COMMAND_RETURN_OK
+ : print_error(client, error);
}
static enum command_return
@@ -1569,8 +1688,9 @@ handle_playlistadd(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
{
char *playlist = argv[1];
char *uri = argv[2];
- enum playlist_result result;
+ bool success;
+ GError *error = NULL;
if (uri_has_scheme(uri)) {
if (!uri_supported_scheme(uri)) {
command_error(client, ACK_ERROR_NO_EXIST,
@@ -1578,29 +1698,27 @@ handle_playlistadd(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
return COMMAND_RETURN_ERROR;
}
- result = spl_append_uri(uri, playlist);
+ success = spl_append_uri(argv[1], playlist, &error);
} else
- result = addAllInToStoredPlaylist(uri, playlist);
+ success = addAllInToStoredPlaylist(uri, playlist, &error);
- if (result == (enum playlist_result)-1) {
+ if (!success && error == NULL) {
command_error(client, ACK_ERROR_NO_EXIST,
"directory or file not found");
return COMMAND_RETURN_ERROR;
}
- return print_playlist_result(client, result);
+ return success ? COMMAND_RETURN_OK : print_error(client, error);
}
static enum command_return
handle_listplaylists(struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
- GPtrArray *list = spl_list();
- if (list == NULL) {
- command_error(client, ACK_ERROR_SYSTEM,
- "failed to get list of stored playlists");
- return COMMAND_RETURN_ERROR;
- }
+ GError *error = NULL;
+ GPtrArray *list = spl_list(&error);
+ if (list == NULL)
+ return print_error(client, error);
print_spl_list(client, list);
spl_list_free(list);
@@ -1817,6 +1935,172 @@ handle_sticker(struct client *client, int argc, char *argv[])
}
#endif
+static enum command_return
+handle_subscribe(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
+{
+ assert(argc == 2);
+
+ switch (client_subscribe(client, argv[1])) {
+ case CLIENT_SUBSCRIBE_OK:
+ return COMMAND_RETURN_OK;
+
+ case CLIENT_SUBSCRIBE_INVALID:
+ command_error(client, ACK_ERROR_ARG,
+ "invalid channel name");
+ return COMMAND_RETURN_ERROR;
+
+ case CLIENT_SUBSCRIBE_ALREADY:
+ command_error(client, ACK_ERROR_EXIST,
+ "already subscribed to this channel");
+ return COMMAND_RETURN_ERROR;
+
+ case CLIENT_SUBSCRIBE_FULL:
+ command_error(client, ACK_ERROR_EXIST,
+ "subscription list is full");
+ return COMMAND_RETURN_ERROR;
+ }
+
+ /* unreachable */
+ return COMMAND_RETURN_OK;
+}
+
+static enum command_return
+handle_unsubscribe(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
+{
+ assert(argc == 2);
+
+ if (client_unsubscribe(client, argv[1]))
+ return COMMAND_RETURN_OK;
+ else {
+ command_error(client, ACK_ERROR_NO_EXIST,
+ "not subscribed to this channel");
+ return COMMAND_RETURN_ERROR;
+ }
+}
+
+struct channels_context {
+ GStringChunk *chunk;
+
+ GHashTable *channels;
+};
+
+static void
+collect_channels(gpointer data, gpointer user_data)
+{
+ struct channels_context *context = user_data;
+ const struct client *client = data;
+
+ for (GSList *i = client->subscriptions; i != NULL;
+ i = g_slist_next(i)) {
+ const char *channel = i->data;
+
+ if (g_hash_table_lookup(context->channels, channel) == NULL) {
+ char *channel2 = g_string_chunk_insert(context->chunk,
+ channel);
+ g_hash_table_insert(context->channels, channel2,
+ context);
+ }
+ }
+}
+
+static void
+print_channel(gpointer key, G_GNUC_UNUSED gpointer value, gpointer user_data)
+{
+ struct client *client = user_data;
+ const char *channel = key;
+
+ client_printf(client, "channel: %s\n", channel);
+}
+
+static enum command_return
+handle_channels(struct client *client,
+ G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
+{
+ assert(argc == 1);
+
+ struct channels_context context = {
+ .chunk = g_string_chunk_new(1024),
+ .channels = g_hash_table_new(g_str_hash, g_str_equal),
+ };
+
+ client_list_foreach(collect_channels, &context);
+
+ g_hash_table_foreach(context.channels, print_channel, client);
+
+ g_hash_table_destroy(context.channels);
+ g_string_chunk_free(context.chunk);
+
+ return COMMAND_RETURN_OK;
+}
+
+static enum command_return
+handle_read_messages(struct client *client,
+ G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
+{
+ assert(argc == 1);
+
+ GSList *messages = client_read_messages(client);
+
+ for (GSList *i = messages; i != NULL; i = g_slist_next(i)) {
+ struct client_message *msg = i->data;
+
+ client_printf(client, "channel: %s\nmessage: %s\n",
+ msg->channel, msg->message);
+ client_message_free(msg);
+ }
+
+ g_slist_free(messages);
+
+ return COMMAND_RETURN_OK;
+}
+
+struct send_message_context {
+ struct client_message msg;
+
+ bool sent;
+};
+
+static void
+send_message(gpointer data, gpointer user_data)
+{
+ struct send_message_context *context = user_data;
+ struct client *client = data;
+
+ if (client_push_message(client, &context->msg))
+ context->sent = true;
+}
+
+static enum command_return
+handle_send_message(struct client *client,
+ G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
+{
+ assert(argc == 3);
+
+ if (!client_message_valid_channel_name(argv[1])) {
+ command_error(client, ACK_ERROR_ARG,
+ "invalid channel name");
+ return COMMAND_RETURN_ERROR;
+ }
+
+ struct send_message_context context = {
+ .sent = false,
+ };
+
+ client_message_init(&context.msg, argv[1], argv[2]);
+
+ client_list_foreach(send_message, &context);
+
+ client_message_deinit(&context.msg);
+
+ if (context.sent)
+ return COMMAND_RETURN_OK;
+ else {
+ command_error(client, ACK_ERROR_NO_EXIST,
+ "nobody is subscribed to this channel");
+ return COMMAND_RETURN_ERROR;
+ }
+}
+
/**
* The command registry.
*
@@ -1825,6 +2109,7 @@ handle_sticker(struct client *client, int argc, char *argv[])
static const struct command commands[] = {
{ "add", PERMISSION_ADD, 1, 1, handle_add },
{ "addid", PERMISSION_ADD, 1, 2, handle_addid },
+ { "channels", PERMISSION_READ, 0, 0, handle_channels },
{ "clear", PERMISSION_CONTROL, 0, 0, handle_clear },
{ "clearerror", PERMISSION_CONTROL, 0, 0, handle_clearerror },
{ "close", PERMISSION_NONE, -1, -1, handle_close },
@@ -1874,19 +2159,24 @@ static const struct command commands[] = {
{ "plchanges", PERMISSION_READ, 1, 1, handle_plchanges },
{ "plchangesposid", PERMISSION_READ, 1, 1, handle_plchangesposid },
{ "previous", PERMISSION_CONTROL, 0, 0, handle_previous },
+ { "prio", PERMISSION_CONTROL, 2, -1, handle_prio },
+ { "prioid", PERMISSION_CONTROL, 2, -1, handle_prioid },
{ "random", PERMISSION_CONTROL, 1, 1, handle_random },
+ { "readmessages", PERMISSION_READ, 0, 0, handle_read_messages },
{ "rename", PERMISSION_CONTROL, 2, 2, handle_rename },
{ "repeat", PERMISSION_CONTROL, 1, 1, handle_repeat },
{ "replay_gain_mode", PERMISSION_CONTROL, 1, 1,
handle_replay_gain_mode },
{ "replay_gain_status", PERMISSION_READ, 0, 0,
handle_replay_gain_status },
- { "rescan", PERMISSION_ADMIN, 0, 1, handle_rescan },
+ { "rescan", PERMISSION_CONTROL, 0, 1, handle_rescan },
{ "rm", PERMISSION_CONTROL, 1, 1, handle_rm },
{ "save", PERMISSION_CONTROL, 1, 1, handle_save },
{ "search", PERMISSION_READ, 2, -1, handle_search },
{ "seek", PERMISSION_CONTROL, 2, 2, handle_seek },
+ { "seekcur", PERMISSION_CONTROL, 1, 1, handle_seekcur },
{ "seekid", PERMISSION_CONTROL, 2, 2, handle_seekid },
+ { "sendmessage", PERMISSION_CONTROL, 2, 2, handle_send_message },
{ "setvol", PERMISSION_CONTROL, 1, 1, handle_setvol },
{ "shuffle", PERMISSION_CONTROL, 0, 1, handle_shuffle },
{ "single", PERMISSION_CONTROL, 1, 1, handle_single },
@@ -1896,10 +2186,12 @@ static const struct command commands[] = {
{ "sticker", PERMISSION_ADMIN, 3, -1, handle_sticker },
#endif
{ "stop", PERMISSION_CONTROL, 0, 0, handle_stop },
+ { "subscribe", PERMISSION_READ, 1, 1, handle_subscribe },
{ "swap", PERMISSION_CONTROL, 2, 2, handle_swap },
{ "swapid", PERMISSION_CONTROL, 2, 2, handle_swapid },
{ "tagtypes", PERMISSION_READ, 0, 0, handle_tagtypes },
- { "update", PERMISSION_ADMIN, 0, 1, handle_update },
+ { "unsubscribe", PERMISSION_READ, 1, 1, handle_unsubscribe },
+ { "update", PERMISSION_CONTROL, 0, 1, handle_update },
{ "urlhandlers", PERMISSION_READ, 0, 0, handle_urlhandlers },
};