diff options
Diffstat (limited to '')
-rw-r--r-- | src/MessageCommands.cxx | 197 | ||||
-rw-r--r-- | src/MessageCommands.hxx | 44 | ||||
-rw-r--r-- | src/OutputCommands.cxx | 77 | ||||
-rw-r--r-- | src/OutputCommands.hxx | 38 | ||||
-rw-r--r-- | src/PlayerCommands.cxx | 391 | ||||
-rw-r--r-- | src/PlayerCommands.hxx | 92 | ||||
-rw-r--r-- | src/PlaylistCommands.cxx | 227 | ||||
-rw-r--r-- | src/PlaylistCommands.hxx | 62 | ||||
-rw-r--r-- | src/QueueCommands.cxx | 398 | ||||
-rw-r--r-- | src/QueueCommands.hxx | 86 | ||||
-rw-r--r-- | src/StickerCommands.cxx | 196 | ||||
-rw-r--r-- | src/StickerCommands.hxx | 32 | ||||
-rw-r--r-- | src/command.c | 1297 |
13 files changed, 1848 insertions, 1289 deletions
diff --git a/src/MessageCommands.cxx b/src/MessageCommands.cxx new file mode 100644 index 000000000..428470e60 --- /dev/null +++ b/src/MessageCommands.cxx @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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 "MessageCommands.hxx" + +extern "C" { +#include "protocol/argparser.h" +#include "protocol/result.h" +#include "client_internal.h" +#include "client_subscribe.h" +} + +#include <assert.h> + +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; +} + +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 = + (struct channels_context *)user_data; + const struct client *client = (const struct client *)data; + + for (GSList *i = client->subscriptions; i != NULL; + i = g_slist_next(i)) { + const char *channel = (const char *)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 = (struct client *)user_data; + const char *channel = (const char *)key; + + client_printf(client, "channel: %s\n", channel); +} + +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 = { + g_string_chunk_new(1024), + 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; +} + +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 = (struct client_message *)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 = + (struct send_message_context *)user_data; + struct client *client = (struct client *)data; + + if (client_push_message(client, &context->msg)) + context->sent = true; +} + +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; + 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; + } +} diff --git a/src/MessageCommands.hxx b/src/MessageCommands.hxx new file mode 100644 index 000000000..4fc10bf24 --- /dev/null +++ b/src/MessageCommands.hxx @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_MESSAGE_COMMANDS_HXX +#define MPD_MESSAGE_COMMANDS_HXX + +#include "command.h" + +G_BEGIN_DECLS + +enum command_return +handle_subscribe(struct client *client, int argc, char *argv[]); + +enum command_return +handle_unsubscribe(struct client *client, int argc, char *argv[]); + +enum command_return +handle_channels(struct client *client, int argc, char *argv[]); + +enum command_return +handle_read_messages(struct client *client, int argc, char *argv[]); + +enum command_return +handle_send_message(struct client *client, int argc, char *argv[]); + +G_END_DECLS + +#endif diff --git a/src/OutputCommands.cxx b/src/OutputCommands.cxx new file mode 100644 index 000000000..88cb95ac4 --- /dev/null +++ b/src/OutputCommands.cxx @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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 "OutputCommands.hxx" + +extern "C" { +#include "protocol/argparser.h" +#include "protocol/result.h" +#include "output_command.h" +#include "output_print.h" +} + +#include <string.h> + +enum command_return +handle_enableoutput(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned device; + bool ret; + + if (!check_unsigned(client, &device, argv[1])) + return COMMAND_RETURN_ERROR; + + ret = audio_output_enable_index(device); + if (!ret) { + command_error(client, ACK_ERROR_NO_EXIST, + "No such audio output"); + return COMMAND_RETURN_ERROR; + } + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_disableoutput(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned device; + bool ret; + + if (!check_unsigned(client, &device, argv[1])) + return COMMAND_RETURN_ERROR; + + ret = audio_output_disable_index(device); + if (!ret) { + command_error(client, ACK_ERROR_NO_EXIST, + "No such audio output"); + return COMMAND_RETURN_ERROR; + } + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_devices(struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + printAudioDevices(client); + + return COMMAND_RETURN_OK; +} diff --git a/src/OutputCommands.hxx b/src/OutputCommands.hxx new file mode 100644 index 000000000..e0d28c975 --- /dev/null +++ b/src/OutputCommands.hxx @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_OUTPUT_COMMANDS_HXX +#define MPD_OUTPUT_COMMANDS_HXX + +#include "command.h" + +G_BEGIN_DECLS + +enum command_return +handle_enableoutput(struct client *client, int argc, char *argv[]); + +enum command_return +handle_disableoutput(struct client *client, int argc, char *argv[]); + +enum command_return +handle_devices(struct client *client, int argc, char *argv[]); + +G_END_DECLS + +#endif diff --git a/src/PlayerCommands.cxx b/src/PlayerCommands.cxx new file mode 100644 index 000000000..6413b1aba --- /dev/null +++ b/src/PlayerCommands.cxx @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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 "PlayerCommands.hxx" +#include "CommandError.h" + +extern "C" { +#include "protocol/argparser.h" +#include "protocol/result.h" +#include "player_control.h" +#include "playlist.h" +#include "playlist_print.h" +#include "update.h" +#include "volume.h" +#include "client.h" +#include "client_internal.h" +#include "replay_gain_config.h" +} + +#include <errno.h> + +#define COMMAND_STATUS_STATE "state" +#define COMMAND_STATUS_REPEAT "repeat" +#define COMMAND_STATUS_SINGLE "single" +#define COMMAND_STATUS_CONSUME "consume" +#define COMMAND_STATUS_RANDOM "random" +#define COMMAND_STATUS_PLAYLIST "playlist" +#define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength" +#define COMMAND_STATUS_SONG "song" +#define COMMAND_STATUS_SONGID "songid" +#define COMMAND_STATUS_NEXTSONG "nextsong" +#define COMMAND_STATUS_NEXTSONGID "nextsongid" +#define COMMAND_STATUS_TIME "time" +#define COMMAND_STATUS_BITRATE "bitrate" +#define COMMAND_STATUS_ERROR "error" +#define COMMAND_STATUS_CROSSFADE "xfade" +#define COMMAND_STATUS_MIXRAMPDB "mixrampdb" +#define COMMAND_STATUS_MIXRAMPDELAY "mixrampdelay" +#define COMMAND_STATUS_AUDIO "audio" +#define COMMAND_STATUS_UPDATING_DB "updating_db" + +enum command_return +handle_play(struct client *client, int argc, char *argv[]) +{ + int song = -1; + enum playlist_result result; + + if (argc == 2 && !check_int(client, &song, argv[1])) + return COMMAND_RETURN_ERROR; + result = playlist_play(&g_playlist, client->player_control, song); + return print_playlist_result(client, result); +} + +enum command_return +handle_playid(struct client *client, int argc, char *argv[]) +{ + int id = -1; + enum playlist_result result; + + if (argc == 2 && !check_int(client, &id, argv[1])) + return COMMAND_RETURN_ERROR; + + result = playlist_play_id(&g_playlist, client->player_control, id); + return print_playlist_result(client, result); +} + +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, client->player_control); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_currentsong(struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + playlist_print_current(client, &g_playlist); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_pause(struct client *client, + int argc, char *argv[]) +{ + if (argc == 2) { + bool pause_flag; + if (!check_bool(client, &pause_flag, argv[1])) + return COMMAND_RETURN_ERROR; + + pc_set_pause(client->player_control, pause_flag); + } else + pc_pause(client->player_control); + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_status(struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + const char *state = NULL; + struct player_status player_status; + int updateJobId; + char *error; + int song; + + pc_get_status(client->player_control, &player_status); + + switch (player_status.state) { + case PLAYER_STATE_STOP: + state = "stop"; + break; + case PLAYER_STATE_PAUSE: + state = "pause"; + break; + case PLAYER_STATE_PLAY: + state = "play"; + break; + } + + 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_CROSSFADE ": %i\n" + COMMAND_STATUS_MIXRAMPDB ": %f\n" + COMMAND_STATUS_MIXRAMPDELAY ": %f\n" + COMMAND_STATUS_STATE ": %s\n", + volume_level_get(), + playlist_get_repeat(&g_playlist), + playlist_get_random(&g_playlist), + playlist_get_single(&g_playlist), + playlist_get_consume(&g_playlist), + playlist_get_version(&g_playlist), + playlist_get_length(&g_playlist), + (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); + if (song >= 0) { + client_printf(client, + COMMAND_STATUS_SONG ": %i\n" + COMMAND_STATUS_SONGID ": %u\n", + song, playlist_get_song_id(&g_playlist, song)); + } + + if (player_status.state != PLAYER_STATE_STOP) { + struct audio_format_string af_string; + + client_printf(client, + COMMAND_STATUS_TIME ": %i:%i\n" + "elapsed: %1.3f\n" + COMMAND_STATUS_BITRATE ": %u\n" + COMMAND_STATUS_AUDIO ": %s\n", + (int)(player_status.elapsed_time + 0.5), + (int)(player_status.total_time + 0.5), + player_status.elapsed_time, + player_status.bit_rate, + audio_format_to_string(&player_status.audio_format, + &af_string)); + } + + if ((updateJobId = isUpdatingDB())) { + client_printf(client, + COMMAND_STATUS_UPDATING_DB ": %i\n", + updateJobId); + } + + error = pc_get_error_message(client->player_control); + if (error != NULL) { + client_printf(client, + COMMAND_STATUS_ERROR ": %s\n", + error); + g_free(error); + } + + song = playlist_get_next_song(&g_playlist); + if (song >= 0) { + client_printf(client, + COMMAND_STATUS_NEXTSONG ": %i\n" + COMMAND_STATUS_NEXTSONGID ": %u\n", + song, playlist_get_song_id(&g_playlist, song)); + } + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_next(G_GNUC_UNUSED struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + /* single mode is not considered when this is user who + * wants to change song. */ + const bool single = g_playlist.queue.single; + g_playlist.queue.single = false; + + playlist_next(&g_playlist, client->player_control); + + g_playlist.queue.single = single; + return COMMAND_RETURN_OK; +} + +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, client->player_control); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_repeat(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + bool status; + if (!check_bool(client, &status, argv[1])) + return COMMAND_RETURN_ERROR; + + playlist_set_repeat(&g_playlist, client->player_control, status); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_single(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + bool status; + if (!check_bool(client, &status, argv[1])) + return COMMAND_RETURN_ERROR; + + playlist_set_single(&g_playlist, client->player_control, status); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_consume(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + bool status; + if (!check_bool(client, &status, argv[1])) + return COMMAND_RETURN_ERROR; + + playlist_set_consume(&g_playlist, status); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_random(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + bool status; + if (!check_bool(client, &status, argv[1])) + return COMMAND_RETURN_ERROR; + + playlist_set_random(&g_playlist, client->player_control, status); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_clearerror(G_GNUC_UNUSED struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + pc_clear_error(client->player_control); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_seek(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned song, seek_time; + enum playlist_result result; + + if (!check_unsigned(client, &song, argv[1])) + return COMMAND_RETURN_ERROR; + if (!check_unsigned(client, &seek_time, argv[2])) + return COMMAND_RETURN_ERROR; + + result = playlist_seek_song(&g_playlist, client->player_control, + song, seek_time); + return print_playlist_result(client, result); +} + +enum command_return +handle_seekid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned id, seek_time; + enum playlist_result result; + + if (!check_unsigned(client, &id, argv[1])) + return COMMAND_RETURN_ERROR; + if (!check_unsigned(client, &seek_time, argv[2])) + return COMMAND_RETURN_ERROR; + + result = playlist_seek_song_id(&g_playlist, client->player_control, + id, seek_time); + return print_playlist_result(client, result); +} + +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)) + 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); +} + +enum command_return +handle_crossfade(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned xfade_time; + + if (!check_unsigned(client, &xfade_time, argv[1])) + return COMMAND_RETURN_ERROR; + pc_set_cross_fade(client->player_control, xfade_time); + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_mixrampdb(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + float db; + + if (!check_float(client, &db, argv[1])) + return COMMAND_RETURN_ERROR; + pc_set_mixramp_db(client->player_control, db); + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_mixrampdelay(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + float delay_secs; + + if (!check_float(client, &delay_secs, argv[1])) + return COMMAND_RETURN_ERROR; + pc_set_mixramp_delay(client->player_control, delay_secs); + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_replay_gain_mode(struct client *client, + G_GNUC_UNUSED int argc, char *argv[]) +{ + if (!replay_gain_set_mode_string(argv[1])) { + command_error(client, ACK_ERROR_ARG, + "Unrecognized replay gain mode"); + return COMMAND_RETURN_ERROR; + } + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_replay_gain_status(struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + client_printf(client, "replay_gain_mode: %s\n", + replay_gain_get_mode_string()); + return COMMAND_RETURN_OK; +} diff --git a/src/PlayerCommands.hxx b/src/PlayerCommands.hxx new file mode 100644 index 000000000..8abc147fa --- /dev/null +++ b/src/PlayerCommands.hxx @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_PLAYER_COMMANDS_HXX +#define MPD_PLAYER_COMMANDS_HXX + +#include "command.h" + +G_BEGIN_DECLS + +enum command_return +handle_play(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playid(struct client *client, int argc, char *argv[]); + +enum command_return +handle_stop(struct client *client, int argc, char *argv[]); + +enum command_return +handle_currentsong(struct client *client, int argc, char *argv[]); + +enum command_return +handle_pause(struct client *client, int argc, char *argv[]); + +enum command_return +handle_status(struct client *client, int argc, char *argv[]); + +enum command_return +handle_next(struct client *client, int argc, char *argv[]); + +enum command_return +handle_previous(struct client *client, int argc, char *avg[]); + +enum command_return +handle_repeat(struct client *client, int argc, char *argv[]); + +enum command_return +handle_single(struct client *client, int argc, char *argv[]); + +enum command_return +handle_consume(struct client *client, int argc, char *argv[]); + +enum command_return +handle_random(struct client *client, int argc, char *argv[]); + +enum command_return +handle_clearerror(struct client *client, int argc, char *argv[]); + +enum command_return +handle_seek(struct client *client, int argc, char *argv[]); + +enum command_return +handle_seekid(struct client *client, int argc, char *argv[]); + +enum command_return +handle_seekcur(struct client *client, int argc, char *argv[]); + +enum command_return +handle_crossfade(struct client *client, int argc, char *argv[]); + +enum command_return +handle_mixrampdb(struct client *client, int argc, char *argv[]); + +enum command_return +handle_mixrampdelay(struct client *client, int argc, char *argv[]); + +enum command_return +handle_replay_gain_mode(struct client *client, int argc, char *argv[]); + +enum command_return +handle_replay_gain_status(struct client *client, int argc, char *argv[]); + +G_END_DECLS + +#endif diff --git a/src/PlaylistCommands.cxx b/src/PlaylistCommands.cxx new file mode 100644 index 000000000..aa2e8654a --- /dev/null +++ b/src/PlaylistCommands.cxx @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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 "PlaylistCommands.hxx" +#include "CommandError.h" + +extern "C" { +#include "protocol/argparser.h" +#include "protocol/result.h" +#include "playlist.h" +#include "playlist_print.h" +#include "playlist_save.h" +#include "playlist_queue.h" +#include "time_print.h" +#include "ls.h" +#include "uri.h" +#include "stored_playlist.h" +#include "dbUtils.h" +#include "client_internal.h" +} + +#include <assert.h> +#include <stdlib.h> + +static void +print_spl_list(struct client *client, GPtrArray *list) +{ + for (unsigned i = 0; i < list->len; ++i) { + struct stored_playlist_info *playlist = + (struct stored_playlist_info *) + g_ptr_array_index(list, i); + + client_printf(client, "playlist: %s\n", playlist->name); + + if (playlist->mtime > 0) + time_print(client, "Last-Modified", playlist->mtime); + } +} + +enum command_return +handle_save(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + enum playlist_result result; + + result = spl_save_playlist(argv[1], &g_playlist); + return print_playlist_result(client, result); +} + +enum command_return +handle_load(struct client *client, int argc, char *argv[]) +{ + unsigned start_index, end_index; + + if (argc < 3) { + start_index = 0; + end_index = G_MAXUINT; + } else if (!check_range(client, &start_index, &end_index, argv[2])) + return COMMAND_RETURN_ERROR; + + enum playlist_result result; + + result = playlist_open_into_queue(argv[1], + start_index, end_index, + &g_playlist, + client->player_control, true); + if (result != PLAYLIST_RESULT_NO_SUCH_LIST) + return print_playlist_result(client, result); + + GError *error = NULL; + if (playlist_load_spl(&g_playlist, client->player_control, + argv[1], start_index, end_index, + &error)) + return COMMAND_RETURN_OK; + + if (error->domain == playlist_quark() && + error->code == PLAYLIST_RESULT_BAD_NAME) + /* the message for BAD_NAME is confusing when the + client wants to load a playlist file from the music + directory; patch the GError object to show "no such + playlist" instead */ + error->code = PLAYLIST_RESULT_NO_SUCH_LIST; + + return print_error(client, error); +} + +enum command_return +handle_listplaylist(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + if (playlist_file_print(client, argv[1], false)) + return COMMAND_RETURN_OK; + + GError *error = NULL; + return spl_print(client, argv[1], false, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); +} + +enum command_return +handle_listplaylistinfo(struct client *client, + G_GNUC_UNUSED int argc, char *argv[]) +{ + if (playlist_file_print(client, argv[1], true)) + return COMMAND_RETURN_OK; + + GError *error = NULL; + return spl_print(client, argv[1], true, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); +} + +enum command_return +handle_rm(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + GError *error = NULL; + return spl_delete(argv[1], &error) + ? COMMAND_RETURN_OK + : print_error(client, error); +} + +enum command_return +handle_rename(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + GError *error = NULL; + return spl_rename(argv[1], argv[2], &error) + ? COMMAND_RETURN_OK + : print_error(client, error); +} + +enum command_return +handle_playlistdelete(struct client *client, + G_GNUC_UNUSED int argc, char *argv[]) { + char *playlist = argv[1]; + unsigned from; + + if (!check_unsigned(client, &from, argv[2])) + return COMMAND_RETURN_ERROR; + + GError *error = NULL; + return spl_remove_index(playlist, from, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); +} + +enum command_return +handle_playlistmove(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + char *playlist = argv[1]; + unsigned from, to; + + if (!check_unsigned(client, &from, argv[2])) + return COMMAND_RETURN_ERROR; + if (!check_unsigned(client, &to, argv[3])) + return COMMAND_RETURN_ERROR; + + GError *error = NULL; + return spl_move_index(playlist, from, to, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); +} + +enum command_return +handle_playlistclear(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + GError *error = NULL; + return spl_clear(argv[1], &error) + ? COMMAND_RETURN_OK + : print_error(client, error); +} + +enum command_return +handle_playlistadd(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + char *playlist = argv[1]; + char *uri = argv[2]; + + bool success; + GError *error = NULL; + if (uri_has_scheme(uri)) { + if (!uri_supported_scheme(uri)) { + command_error(client, ACK_ERROR_NO_EXIST, + "unsupported URI scheme"); + return COMMAND_RETURN_ERROR; + } + + success = spl_append_uri(argv[1], playlist, &error); + } else + success = addAllInToStoredPlaylist(uri, playlist, &error); + + if (!success && error == NULL) { + command_error(client, ACK_ERROR_NO_EXIST, + "directory or file not found"); + return COMMAND_RETURN_ERROR; + } + + return success ? COMMAND_RETURN_OK : print_error(client, error); +} + +enum command_return +handle_listplaylists(struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + 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); + return COMMAND_RETURN_OK; +} diff --git a/src/PlaylistCommands.hxx b/src/PlaylistCommands.hxx new file mode 100644 index 000000000..8f83f6557 --- /dev/null +++ b/src/PlaylistCommands.hxx @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_PLAYLIST_COMMANDS_HXX +#define MPD_PLAYLIST_COMMANDS_HXX + +#include "command.h" + +G_BEGIN_DECLS + +enum command_return +handle_save(struct client *client, int argc, char *argv[]); + +enum command_return +handle_load(struct client *client, int argc, char *argv[]); + +enum command_return +handle_listplaylist(struct client *client, int argc, char *argv[]); + +enum command_return +handle_listplaylistinfo(struct client *client, int argc, char *argv[]); + +enum command_return +handle_rm(struct client *client, int argc, char *argv[]); + +enum command_return +handle_rename(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlistdelete(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlistmove(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlistclear(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlistadd(struct client *client, int argc, char *argv[]); + +enum command_return +handle_listplaylists(struct client *client, int argc, char *argv[]); + +G_END_DECLS + +#endif diff --git a/src/QueueCommands.cxx b/src/QueueCommands.cxx new file mode 100644 index 000000000..8083cc96f --- /dev/null +++ b/src/QueueCommands.cxx @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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" +#include "CommandError.h" + +extern "C" { +#include "protocol/argparser.h" +#include "protocol/result.h" +#include "playlist.h" +#include "playlist_print.h" +#include "ls.h" +#include "uri.h" +#include "locate.h" +#include "dbUtils.h" +#include "client_internal.h" +#include "client_file.h" +} + +#include <string.h> + +enum command_return +handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + 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); + + result = playlist_append_file(&g_playlist, + client->player_control, + path, + NULL); + 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; + } + + result = playlist_append_uri(&g_playlist, + client->player_control, + uri, NULL); + return print_playlist_result(client, result); + } + + GError *error = NULL; + return addAllIn(client->player_control, uri, &error) + ? COMMAND_RETURN_OK + : print_error(client, error); +} + +enum command_return +handle_addid(struct client *client, int argc, char *argv[]) +{ + 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); + + result = playlist_append_file(&g_playlist, + client->player_control, + path, + &added_id); + } else { + if (uri_has_scheme(uri) && !uri_supported_scheme(uri)) { + command_error(client, ACK_ERROR_NO_EXIST, + "unsupported URI scheme"); + return COMMAND_RETURN_ERROR; + } + + result = playlist_append_uri(&g_playlist, + client->player_control, + uri, &added_id); + } + + 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; + 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, client->player_control, + added_id); + return ret; + } + } + + client_printf(client, "Id: %u\n", added_id); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_delete(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned start, end; + enum playlist_result result; + + if (!check_range(client, &start, &end, argv[1])) + return COMMAND_RETURN_ERROR; + + result = playlist_delete_range(&g_playlist, client->player_control, + start, end); + return print_playlist_result(client, result); +} + +enum command_return +handle_deleteid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned id; + enum playlist_result result; + + if (!check_unsigned(client, &id, argv[1])) + return COMMAND_RETURN_ERROR; + + result = playlist_delete_id(&g_playlist, client->player_control, id); + return print_playlist_result(client, result); +} + +enum command_return +handle_playlist(struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + playlist_print_uris(client, &g_playlist); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_shuffle(G_GNUC_UNUSED struct client *client, + G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) +{ + unsigned start = 0, end = queue_length(&g_playlist.queue); + if (argc == 2 && !check_range(client, &start, &end, argv[1])) + return COMMAND_RETURN_ERROR; + + playlist_shuffle(&g_playlist, client->player_control, start, end); + return COMMAND_RETURN_OK; +} + +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, client->player_control); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_plchanges(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + uint32_t version; + + if (!check_uint32(client, &version, argv[1])) + return COMMAND_RETURN_ERROR; + + playlist_print_changes_info(client, &g_playlist, version); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_plchangesposid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + uint32_t version; + + if (!check_uint32(client, &version, argv[1])) + return COMMAND_RETURN_ERROR; + + playlist_print_changes_position(client, &g_playlist, version); + return COMMAND_RETURN_OK; +} + +enum command_return +handle_playlistinfo(struct client *client, int argc, char *argv[]) +{ + unsigned start = 0, end = G_MAXUINT; + bool ret; + + if (argc == 2 && !check_range(client, &start, &end, argv[1])) + return COMMAND_RETURN_ERROR; + + ret = playlist_print_info(client, &g_playlist, start, end); + if (!ret) + return print_playlist_result(client, + PLAYLIST_RESULT_BAD_RANGE); + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_playlistid(struct client *client, int argc, char *argv[]) +{ + if (argc >= 2) { + unsigned id; + if (!check_unsigned(client, &id, argv[1])) + return COMMAND_RETURN_ERROR; + + bool ret = playlist_print_id(client, &g_playlist, id); + if (!ret) + return print_playlist_result(client, + PLAYLIST_RESULT_NO_SUCH_SONG); + } else { + playlist_print_info(client, &g_playlist, 0, G_MAXUINT); + } + + return COMMAND_RETURN_OK; +} + +static enum command_return +handle_playlist_match(struct client *client, int argc, char *argv[], + bool fold_case) +{ + struct locate_item_list *list = + locate_item_list_parse(argv + 1, argc - 1, fold_case); + + if (list == NULL) { + command_error(client, ACK_ERROR_ARG, "incorrect arguments"); + return COMMAND_RETURN_ERROR; + } + + playlist_print_find(client, &g_playlist, list); + + locate_item_list_free(list); + + return COMMAND_RETURN_OK; +} + +enum command_return +handle_playlistfind(struct client *client, int argc, char *argv[]) +{ + return handle_playlist_match(client, argc, argv, false); +} + +enum command_return +handle_playlistsearch(struct client *client, int argc, char *argv[]) +{ + return handle_playlist_match(client, argc, argv, true); +} + +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])) + 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; +} + +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; +} + +enum command_return +handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned start, end; + int to; + enum playlist_result result; + + if (!check_range(client, &start, &end, argv[1])) + return COMMAND_RETURN_ERROR; + if (!check_int(client, &to, argv[2])) + return COMMAND_RETURN_ERROR; + result = playlist_move_range(&g_playlist, client->player_control, + start, end, to); + return print_playlist_result(client, result); +} + +enum command_return +handle_moveid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned id; + int to; + enum playlist_result result; + + if (!check_unsigned(client, &id, argv[1])) + return COMMAND_RETURN_ERROR; + if (!check_int(client, &to, argv[2])) + return COMMAND_RETURN_ERROR; + result = playlist_move_id(&g_playlist, client->player_control, + id, to); + return print_playlist_result(client, result); +} + +enum command_return +handle_swap(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned song1, song2; + enum playlist_result result; + + if (!check_unsigned(client, &song1, argv[1])) + return COMMAND_RETURN_ERROR; + if (!check_unsigned(client, &song2, argv[2])) + return COMMAND_RETURN_ERROR; + result = playlist_swap_songs(&g_playlist, client->player_control, + song1, song2); + return print_playlist_result(client, result); +} + +enum command_return +handle_swapid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) +{ + unsigned id1, id2; + enum playlist_result result; + + if (!check_unsigned(client, &id1, argv[1])) + return COMMAND_RETURN_ERROR; + if (!check_unsigned(client, &id2, argv[2])) + return COMMAND_RETURN_ERROR; + result = playlist_swap_songs_id(&g_playlist, client->player_control, + id1, id2); + return print_playlist_result(client, result); +} diff --git a/src/QueueCommands.hxx b/src/QueueCommands.hxx new file mode 100644 index 000000000..ec3230f7f --- /dev/null +++ b/src/QueueCommands.hxx @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_QUEUE_COMMANDS_HXX +#define MPD_QUEUE_COMMANDS_HXX + +#include "command.h" + +G_BEGIN_DECLS + +enum command_return +handle_add(struct client *client, int argc, char *argv[]); + +enum command_return +handle_addid(struct client *client, int argc, char *argv[]); + +enum command_return +handle_delete(struct client *client, int argc, char *argv[]); + +enum command_return +handle_deleteid(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlist(struct client *client, int argc, char *argv[]); + +enum command_return +handle_shuffle(struct client *client, int argc, char *argv[]); + +enum command_return +handle_clear(struct client *client, int argc, char *argv[]); + +enum command_return +handle_plchanges(struct client *client, int argc, char *argv[]); + +enum command_return +handle_plchangesposid(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlistinfo(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlistid(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlistfind(struct client *client, int argc, char *argv[]); + +enum command_return +handle_playlistsearch(struct client *client, int argc, char *argv[]); + +enum command_return +handle_prio(struct client *client, int argc, char *argv[]); + +enum command_return +handle_prioid(struct client *client, int argc, char *argv[]); + +enum command_return +handle_move(struct client *client, int argc, char *argv[]); + +enum command_return +handle_moveid(struct client *client, int argc, char *argv[]); + +enum command_return +handle_swap(struct client *client, int argc, char *argv[]); + +enum command_return +handle_swapid(struct client *client, int argc, char *argv[]); + +G_END_DECLS + +#endif diff --git a/src/StickerCommands.cxx b/src/StickerCommands.cxx new file mode 100644 index 000000000..ccf18fea6 --- /dev/null +++ b/src/StickerCommands.cxx @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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 "StickerCommands.hxx" + +extern "C" { +#include "protocol/result.h" +#include "sticker.h" +#include "sticker_print.h" +#include "song_print.h" +#include "song_sticker.h" +#include "database.h" +#include "db_lock.h" +} + +#include <string.h> + +struct sticker_song_find_data { + struct client *client; + const char *name; +}; + +static void +sticker_song_find_print_cb(struct song *song, const char *value, + gpointer user_data) +{ + 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); +} + +static enum command_return +handle_sticker_song(struct client *client, int argc, char *argv[]) +{ + /* get song song_id key */ + if (argc == 5 && strcmp(argv[1], "get") == 0) { + struct song *song; + char *value; + + song = db_get_song(argv[3]); + if (song == NULL) { + command_error(client, ACK_ERROR_NO_EXIST, + "no such song"); + return COMMAND_RETURN_ERROR; + } + + value = sticker_song_get_value(song, argv[4]); + db_return_song(song); + if (value == NULL) { + command_error(client, ACK_ERROR_NO_EXIST, + "no such sticker"); + return COMMAND_RETURN_ERROR; + } + + sticker_print_value(client, argv[4], value); + g_free(value); + + return COMMAND_RETURN_OK; + /* list song song_id */ + } else if (argc == 4 && strcmp(argv[1], "list") == 0) { + struct song *song; + struct sticker *sticker; + + song = db_get_song(argv[3]); + if (song == NULL) { + command_error(client, ACK_ERROR_NO_EXIST, + "no such song"); + return COMMAND_RETURN_ERROR; + } + + sticker = sticker_song_get(song); + db_return_song(song); + if (sticker) { + sticker_print(client, sticker); + sticker_free(sticker); + } + + return COMMAND_RETURN_OK; + /* set song song_id id key */ + } else if (argc == 6 && strcmp(argv[1], "set") == 0) { + struct song *song; + bool ret; + + song = db_get_song(argv[3]); + if (song == NULL) { + command_error(client, ACK_ERROR_NO_EXIST, + "no such song"); + return COMMAND_RETURN_ERROR; + } + + ret = sticker_song_set_value(song, argv[4], argv[5]); + db_return_song(song); + if (!ret) { + command_error(client, ACK_ERROR_SYSTEM, + "failed to set sticker value"); + return COMMAND_RETURN_ERROR; + } + + return COMMAND_RETURN_OK; + /* delete song song_id [key] */ + } else if ((argc == 4 || argc == 5) && + strcmp(argv[1], "delete") == 0) { + struct song *song; + bool ret; + + song = db_get_song(argv[3]); + if (song == NULL) { + command_error(client, ACK_ERROR_NO_EXIST, + "no such song"); + return COMMAND_RETURN_ERROR; + } + + ret = argc == 4 + ? sticker_song_delete(song) + : sticker_song_delete_value(song, argv[4]); + db_return_song(song); + if (!ret) { + command_error(client, ACK_ERROR_SYSTEM, + "no such sticker"); + return COMMAND_RETURN_ERROR; + } + + return COMMAND_RETURN_OK; + /* find song dir key */ + } else if (argc == 5 && strcmp(argv[1], "find") == 0) { + /* "sticker find song a/directory name" */ + struct directory *directory; + bool success; + struct sticker_song_find_data data = { + client, + argv[4], + }; + + db_lock(); + directory = db_get_directory(argv[3]); + if (directory == NULL) { + db_unlock(); + command_error(client, ACK_ERROR_NO_EXIST, + "no such directory"); + return COMMAND_RETURN_ERROR; + } + + success = sticker_song_find(directory, data.name, + sticker_song_find_print_cb, &data); + db_unlock(); + if (!success) { + command_error(client, ACK_ERROR_SYSTEM, + "failed to set search sticker database"); + return COMMAND_RETURN_ERROR; + } + + return COMMAND_RETURN_OK; + } else { + command_error(client, ACK_ERROR_ARG, "bad request"); + return COMMAND_RETURN_ERROR; + } +} + +enum command_return +handle_sticker(struct client *client, int argc, char *argv[]) +{ + assert(argc >= 4); + + if (!sticker_enabled()) { + command_error(client, ACK_ERROR_UNKNOWN, + "sticker database is disabled"); + return COMMAND_RETURN_ERROR; + } + + if (strcmp(argv[2], "song") == 0) + return handle_sticker_song(client, argc, argv); + else { + command_error(client, ACK_ERROR_ARG, + "unknown sticker domain"); + return COMMAND_RETURN_ERROR; + } +} diff --git a/src/StickerCommands.hxx b/src/StickerCommands.hxx new file mode 100644 index 000000000..f4dff7755 --- /dev/null +++ b/src/StickerCommands.hxx @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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. + */ + +#ifndef MPD_STICKER_COMMANDS_HXX +#define MPD_STICKER_COMMANDS_HXX + +#include "command.h" + +G_BEGIN_DECLS + +enum command_return +handle_sticker(struct client *client, int argc, char *argv[]); + +G_END_DECLS + +#endif diff --git a/src/command.c b/src/command.c index 9a9cd5b12..88ce72405 100644 --- a/src/command.c +++ b/src/command.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * Copyright (C) 2003-2012 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,44 +19,32 @@ #include "config.h" #include "command.h" +#include "QueueCommands.hxx" +#include "PlayerCommands.hxx" +#include "PlaylistCommands.hxx" #include "DatabaseCommands.hxx" +#include "OutputCommands.hxx" +#include "StickerCommands.hxx" +#include "MessageCommands.hxx" #include "CommandError.h" #include "protocol/argparser.h" #include "protocol/result.h" -#include "player_control.h" -#include "playlist.h" -#include "playlist_print.h" -#include "playlist_save.h" -#include "playlist_queue.h" -#include "playlist_error.h" -#include "queue_print.h" #include "time_print.h" #include "ls.h" #include "uri.h" #include "decoder_print.h" #include "directory.h" -#include "database.h" #include "update.h" #include "volume.h" #include "stats.h" #include "permission.h" #include "tokenizer.h" #include "stored_playlist.h" -#include "ack.h" -#include "output_command.h" -#include "output_print.h" -#include "locate.h" -#include "dbUtils.h" -#include "db_lock.h" #include "tag.h" #include "client.h" #include "client_idle.h" -#include "client_internal.h" -#include "client_subscribe.h" #include "client_file.h" #include "tag_print.h" -#include "path.h" -#include "replay_gain_config.h" #include "idle.h" #include "mapper.h" #include "song.h" @@ -64,34 +52,10 @@ #ifdef ENABLE_SQLITE #include "sticker.h" -#include "sticker_print.h" -#include "song_sticker.h" #endif #include <assert.h> -#include <time.h> -#include <stdlib.h> -#include <errno.h> - -#define COMMAND_STATUS_STATE "state" -#define COMMAND_STATUS_REPEAT "repeat" -#define COMMAND_STATUS_SINGLE "single" -#define COMMAND_STATUS_CONSUME "consume" -#define COMMAND_STATUS_RANDOM "random" -#define COMMAND_STATUS_PLAYLIST "playlist" -#define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength" -#define COMMAND_STATUS_SONG "song" -#define COMMAND_STATUS_SONGID "songid" -#define COMMAND_STATUS_NEXTSONG "nextsong" -#define COMMAND_STATUS_NEXTSONGID "nextsongid" -#define COMMAND_STATUS_TIME "time" -#define COMMAND_STATUS_BITRATE "bitrate" -#define COMMAND_STATUS_ERROR "error" -#define COMMAND_STATUS_CROSSFADE "xfade" -#define COMMAND_STATUS_MIXRAMPDB "mixrampdb" -#define COMMAND_STATUS_MIXRAMPDELAY "mixrampdelay" -#define COMMAND_STATUS_AUDIO "audio" -#define COMMAND_STATUS_UPDATING_DB "updating_db" +#include <string.h> /* * The most we ever use is for search/find, and that limits it to the @@ -151,160 +115,6 @@ handle_tagtypes(struct client *client, } static enum command_return -handle_play(struct client *client, int argc, char *argv[]) -{ - int song = -1; - enum playlist_result result; - - if (argc == 2 && !check_int(client, &song, argv[1])) - return COMMAND_RETURN_ERROR; - result = playlist_play(&g_playlist, client->player_control, song); - return print_playlist_result(client, result); -} - -static enum command_return -handle_playid(struct client *client, int argc, char *argv[]) -{ - int id = -1; - enum playlist_result result; - - if (argc == 2 && !check_int(client, &id, argv[1])) - return COMMAND_RETURN_ERROR; - - result = playlist_play_id(&g_playlist, client->player_control, id); - return print_playlist_result(client, result); -} - -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, client->player_control); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_currentsong(struct client *client, - G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) -{ - playlist_print_current(client, &g_playlist); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_pause(struct client *client, - int argc, char *argv[]) -{ - if (argc == 2) { - bool pause_flag; - if (!check_bool(client, &pause_flag, argv[1])) - return COMMAND_RETURN_ERROR; - - pc_set_pause(client->player_control, pause_flag); - } else - pc_pause(client->player_control); - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_status(struct client *client, - G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) -{ - const char *state = NULL; - struct player_status player_status; - int updateJobId; - char *error; - int song; - - pc_get_status(client->player_control, &player_status); - - switch (player_status.state) { - case PLAYER_STATE_STOP: - state = "stop"; - break; - case PLAYER_STATE_PAUSE: - state = "pause"; - break; - case PLAYER_STATE_PLAY: - state = "play"; - break; - } - - 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_CROSSFADE ": %i\n" - COMMAND_STATUS_MIXRAMPDB ": %f\n" - COMMAND_STATUS_MIXRAMPDELAY ": %f\n" - COMMAND_STATUS_STATE ": %s\n", - volume_level_get(), - playlist_get_repeat(&g_playlist), - playlist_get_random(&g_playlist), - playlist_get_single(&g_playlist), - playlist_get_consume(&g_playlist), - playlist_get_version(&g_playlist), - playlist_get_length(&g_playlist), - (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); - if (song >= 0) { - client_printf(client, - COMMAND_STATUS_SONG ": %i\n" - COMMAND_STATUS_SONGID ": %u\n", - song, playlist_get_song_id(&g_playlist, song)); - } - - if (player_status.state != PLAYER_STATE_STOP) { - struct audio_format_string af_string; - - client_printf(client, - COMMAND_STATUS_TIME ": %i:%i\n" - "elapsed: %1.3f\n" - COMMAND_STATUS_BITRATE ": %u\n" - COMMAND_STATUS_AUDIO ": %s\n", - (int)(player_status.elapsed_time + 0.5), - (int)(player_status.total_time + 0.5), - player_status.elapsed_time, - player_status.bit_rate, - audio_format_to_string(&player_status.audio_format, - &af_string)); - } - - if ((updateJobId = isUpdatingDB())) { - client_printf(client, - COMMAND_STATUS_UPDATING_DB ": %i\n", - updateJobId); - } - - error = pc_get_error_message(client->player_control); - if (error != NULL) { - client_printf(client, - COMMAND_STATUS_ERROR ": %s\n", - error); - g_free(error); - } - - song = playlist_get_next_song(&g_playlist); - if (song >= 0) { - client_printf(client, - COMMAND_STATUS_NEXTSONG ": %i\n" - COMMAND_STATUS_NEXTSONGID ": %u\n", - song, playlist_get_song_id(&g_playlist, song)); - } - - return COMMAND_RETURN_OK; -} - -static enum command_return handle_kill(G_GNUC_UNUSED struct client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { @@ -319,224 +129,6 @@ handle_close(G_GNUC_UNUSED struct client *client, } static enum command_return -handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - 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); - - result = playlist_append_file(&g_playlist, - client->player_control, - path, - NULL); - 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; - } - - result = playlist_append_uri(&g_playlist, - client->player_control, - uri, NULL); - 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 -handle_addid(struct client *client, int argc, char *argv[]) -{ - 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); - - result = playlist_append_file(&g_playlist, - client->player_control, - path, - &added_id); - } else { - if (uri_has_scheme(uri) && !uri_supported_scheme(uri)) { - command_error(client, ACK_ERROR_NO_EXIST, - "unsupported URI scheme"); - return COMMAND_RETURN_ERROR; - } - - result = playlist_append_uri(&g_playlist, - client->player_control, - uri, &added_id); - } - - 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; - 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, client->player_control, - added_id); - return ret; - } - } - - client_printf(client, "Id: %u\n", added_id); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_delete(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned start, end; - enum playlist_result result; - - if (!check_range(client, &start, &end, argv[1])) - return COMMAND_RETURN_ERROR; - - result = playlist_delete_range(&g_playlist, client->player_control, - start, end); - return print_playlist_result(client, result); -} - -static enum command_return -handle_deleteid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned id; - enum playlist_result result; - - if (!check_unsigned(client, &id, argv[1])) - return COMMAND_RETURN_ERROR; - - result = playlist_delete_id(&g_playlist, client->player_control, id); - return print_playlist_result(client, result); -} - -static enum command_return -handle_playlist(struct client *client, - G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) -{ - playlist_print_uris(client, &g_playlist); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_shuffle(G_GNUC_UNUSED struct client *client, - G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) -{ - unsigned start = 0, end = queue_length(&g_playlist.queue); - if (argc == 2 && !check_range(client, &start, &end, argv[1])) - return COMMAND_RETURN_ERROR; - - playlist_shuffle(&g_playlist, client->player_control, start, end); - return COMMAND_RETURN_OK; -} - -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, client->player_control); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_save(struct client *client, - G_GNUC_UNUSED int argc, char *argv[]) -{ - enum playlist_result result; - - result = spl_save_playlist(argv[1], &g_playlist); - return print_playlist_result(client, result); -} - -static enum command_return -handle_load(struct client *client, int argc, char *argv[]) -{ - unsigned start_index, end_index; - - if (argc < 3) { - start_index = 0; - end_index = G_MAXUINT; - } else if (!check_range(client, &start_index, &end_index, argv[2])) - return COMMAND_RETURN_ERROR; - - enum playlist_result result; - - result = playlist_open_into_queue(argv[1], - start_index, end_index, - &g_playlist, - client->player_control, true); - if (result != PLAYLIST_RESULT_NO_SUCH_LIST) - return print_playlist_result(client, result); - - GError *error = NULL; - if (playlist_load_spl(&g_playlist, client->player_control, - argv[1], start_index, end_index, - &error)) - return COMMAND_RETURN_OK; - - if (error->domain == playlist_quark() && - error->code == PLAYLIST_RESULT_BAD_NAME) - /* the message for BAD_NAME is confusing when the - client wants to load a playlist file from the music - directory; patch the GError object to show "no such - playlist" instead */ - error->code = PLAYLIST_RESULT_NO_SUCH_LIST; - - return print_error(client, error); -} - -static enum command_return -handle_listplaylist(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - if (playlist_file_print(client, argv[1], false)) - 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 -handle_listplaylistinfo(struct client *client, - G_GNUC_UNUSED int argc, char *argv[]) -{ - if (playlist_file_print(client, argv[1], true)) - 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; @@ -583,147 +175,6 @@ 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[]) -{ - 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[]) -{ - GError *error = NULL; - return spl_rename(argv[1], argv[2], &error) - ? COMMAND_RETURN_OK - : print_error(client, error); -} - -static enum command_return -handle_plchanges(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - uint32_t version; - - if (!check_uint32(client, &version, argv[1])) - return COMMAND_RETURN_ERROR; - - playlist_print_changes_info(client, &g_playlist, version); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_plchangesposid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - uint32_t version; - - if (!check_uint32(client, &version, argv[1])) - return COMMAND_RETURN_ERROR; - - playlist_print_changes_position(client, &g_playlist, version); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_playlistinfo(struct client *client, int argc, char *argv[]) -{ - unsigned start = 0, end = G_MAXUINT; - bool ret; - - if (argc == 2 && !check_range(client, &start, &end, argv[1])) - return COMMAND_RETURN_ERROR; - - ret = playlist_print_info(client, &g_playlist, start, end); - if (!ret) - return print_playlist_result(client, - PLAYLIST_RESULT_BAD_RANGE); - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_playlistid(struct client *client, int argc, char *argv[]) -{ - if (argc >= 2) { - unsigned id; - if (!check_unsigned(client, &id, argv[1])) - return COMMAND_RETURN_ERROR; - - bool ret = playlist_print_id(client, &g_playlist, id); - if (!ret) - return print_playlist_result(client, - PLAYLIST_RESULT_NO_SUCH_SONG); - } else { - playlist_print_info(client, &g_playlist, 0, G_MAXUINT); - } - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_playlist_match(struct client *client, int argc, char *argv[], - bool fold_case) -{ - struct locate_item_list *list = - locate_item_list_parse(argv + 1, argc - 1, fold_case); - - if (list == NULL) { - command_error(client, ACK_ERROR_ARG, "incorrect arguments"); - return COMMAND_RETURN_ERROR; - } - - playlist_print_find(client, &g_playlist, list); - - locate_item_list_free(list); - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_playlistfind(struct client *client, int argc, char *argv[]) -{ - return handle_playlist_match(client, argc, argv, false); -} - -static enum command_return -handle_playlistsearch(struct client *client, int argc, char *argv[]) -{ - return handle_playlist_match(client, argc, argv, true); -} - -static enum command_return -handle_playlistdelete(struct client *client, - G_GNUC_UNUSED int argc, char *argv[]) { - char *playlist = argv[1]; - unsigned from; - - if (!check_unsigned(client, &from, argv[2])) - return COMMAND_RETURN_ERROR; - - GError *error = NULL; - return spl_remove_index(playlist, from, &error) - ? COMMAND_RETURN_OK - : print_error(client, error); -} - -static enum command_return -handle_playlistmove(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - char *playlist = argv[1]; - unsigned from, to; - - if (!check_unsigned(client, &from, argv[2])) - return COMMAND_RETURN_ERROR; - if (!check_unsigned(client, &to, argv[3])) - return COMMAND_RETURN_ERROR; - - GError *error = NULL; - return spl_move_index(playlist, from, to, &error) - ? COMMAND_RETURN_OK - : print_error(client, error); -} - -static enum command_return handle_update(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) { const char *path = NULL; @@ -783,91 +234,6 @@ handle_rescan(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) } static enum command_return -handle_next(G_GNUC_UNUSED struct client *client, - G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) -{ - /* single mode is not considered when this is user who - * wants to change song. */ - const bool single = g_playlist.queue.single; - g_playlist.queue.single = false; - - playlist_next(&g_playlist, client->player_control); - - g_playlist.queue.single = single; - return COMMAND_RETURN_OK; -} - -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, 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])) - 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_setvol(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned level; @@ -892,50 +258,6 @@ handle_setvol(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) } static enum command_return -handle_repeat(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - bool status; - if (!check_bool(client, &status, argv[1])) - return COMMAND_RETURN_ERROR; - - playlist_set_repeat(&g_playlist, client->player_control, status); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_single(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - bool status; - if (!check_bool(client, &status, argv[1])) - return COMMAND_RETURN_ERROR; - - playlist_set_single(&g_playlist, client->player_control, status); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_consume(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - bool status; - if (!check_bool(client, &status, argv[1])) - return COMMAND_RETURN_ERROR; - - playlist_set_consume(&g_playlist, status); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_random(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - bool status; - if (!check_bool(client, &status, argv[1])) - return COMMAND_RETURN_ERROR; - - playlist_set_random(&g_playlist, client->player_control, status); - return COMMAND_RETURN_OK; -} - -static enum command_return handle_stats(struct client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { @@ -944,123 +266,6 @@ handle_stats(struct client *client, } 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(client->player_control); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned start, end; - int to; - enum playlist_result result; - - if (!check_range(client, &start, &end, argv[1])) - return COMMAND_RETURN_ERROR; - if (!check_int(client, &to, argv[2])) - return COMMAND_RETURN_ERROR; - result = playlist_move_range(&g_playlist, client->player_control, - start, end, to); - return print_playlist_result(client, result); -} - -static enum command_return -handle_moveid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned id; - int to; - enum playlist_result result; - - if (!check_unsigned(client, &id, argv[1])) - return COMMAND_RETURN_ERROR; - if (!check_int(client, &to, argv[2])) - return COMMAND_RETURN_ERROR; - result = playlist_move_id(&g_playlist, client->player_control, - id, to); - return print_playlist_result(client, result); -} - -static enum command_return -handle_swap(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned song1, song2; - enum playlist_result result; - - if (!check_unsigned(client, &song1, argv[1])) - return COMMAND_RETURN_ERROR; - if (!check_unsigned(client, &song2, argv[2])) - return COMMAND_RETURN_ERROR; - result = playlist_swap_songs(&g_playlist, client->player_control, - song1, song2); - return print_playlist_result(client, result); -} - -static enum command_return -handle_swapid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned id1, id2; - enum playlist_result result; - - if (!check_unsigned(client, &id1, argv[1])) - return COMMAND_RETURN_ERROR; - if (!check_unsigned(client, &id2, argv[2])) - return COMMAND_RETURN_ERROR; - result = playlist_swap_songs_id(&g_playlist, client->player_control, - id1, id2); - return print_playlist_result(client, result); -} - -static enum command_return -handle_seek(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned song, seek_time; - enum playlist_result result; - - if (!check_unsigned(client, &song, argv[1])) - return COMMAND_RETURN_ERROR; - if (!check_unsigned(client, &seek_time, argv[2])) - return COMMAND_RETURN_ERROR; - - result = playlist_seek_song(&g_playlist, client->player_control, - song, seek_time); - return print_playlist_result(client, result); -} - -static enum command_return -handle_seekid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned id, seek_time; - enum playlist_result result; - - if (!check_unsigned(client, &id, argv[1])) - return COMMAND_RETURN_ERROR; - if (!check_unsigned(client, &seek_time, argv[2])) - return COMMAND_RETURN_ERROR; - - 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)) - 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_ping(G_GNUC_UNUSED struct client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { @@ -1082,89 +287,6 @@ handle_password(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_OK; } -static enum command_return -handle_crossfade(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned xfade_time; - - if (!check_unsigned(client, &xfade_time, argv[1])) - return COMMAND_RETURN_ERROR; - pc_set_cross_fade(client->player_control, xfade_time); - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_mixrampdb(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - float db; - - if (!check_float(client, &db, argv[1])) - return COMMAND_RETURN_ERROR; - pc_set_mixramp_db(client->player_control, db); - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_mixrampdelay(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - float delay_secs; - - if (!check_float(client, &delay_secs, argv[1])) - return COMMAND_RETURN_ERROR; - pc_set_mixramp_delay(client->player_control, delay_secs); - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_enableoutput(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned device; - bool ret; - - if (!check_unsigned(client, &device, argv[1])) - return COMMAND_RETURN_ERROR; - - ret = audio_output_enable_index(device); - if (!ret) { - command_error(client, ACK_ERROR_NO_EXIST, - "No such audio output"); - return COMMAND_RETURN_ERROR; - } - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_disableoutput(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - unsigned device; - bool ret; - - if (!check_unsigned(client, &device, argv[1])) - return COMMAND_RETURN_ERROR; - - ret = audio_output_disable_index(device); - if (!ret) { - command_error(client, ACK_ERROR_NO_EXIST, - "No such audio output"); - return COMMAND_RETURN_ERROR; - } - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_devices(struct client *client, - G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) -{ - printAudioDevices(client); - - return COMMAND_RETURN_OK; -} - /* don't be fooled, this is the command handler for "commands" command */ static enum command_return handle_commands(struct client *client, @@ -1192,79 +314,6 @@ handle_config(struct client *client, } static enum command_return -handle_playlistclear(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - GError *error = NULL; - return spl_clear(argv[1], &error) - ? COMMAND_RETURN_OK - : print_error(client, error); -} - -static enum command_return -handle_playlistadd(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) -{ - char *playlist = argv[1]; - char *uri = argv[2]; - - bool success; - GError *error = NULL; - if (uri_has_scheme(uri)) { - if (!uri_supported_scheme(uri)) { - command_error(client, ACK_ERROR_NO_EXIST, - "unsupported URI scheme"); - return COMMAND_RETURN_ERROR; - } - - success = spl_append_uri(argv[1], playlist, &error); - } else - success = addAllInToStoredPlaylist(uri, playlist, &error); - - if (!success && error == NULL) { - command_error(client, ACK_ERROR_NO_EXIST, - "directory or file not found"); - return COMMAND_RETURN_ERROR; - } - - 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[]) -{ - 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); - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_replay_gain_mode(struct client *client, - G_GNUC_UNUSED int argc, char *argv[]) -{ - if (!replay_gain_set_mode_string(argv[1])) { - command_error(client, ACK_ERROR_ARG, - "Unrecognized replay gain mode"); - return COMMAND_RETURN_ERROR; - } - - return COMMAND_RETURN_OK; -} - -static enum command_return -handle_replay_gain_status(struct client *client, - G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) -{ - client_printf(client, "replay_gain_mode: %s\n", - replay_gain_get_mode_string()); - return COMMAND_RETURN_OK; -} - -static enum command_return handle_idle(struct client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { @@ -1295,336 +344,6 @@ handle_idle(struct client *client, return 1; } -#ifdef ENABLE_SQLITE -struct sticker_song_find_data { - struct client *client; - const char *name; -}; - -static void -sticker_song_find_print_cb(struct song *song, const char *value, - gpointer user_data) -{ - struct sticker_song_find_data *data = user_data; - - song_print_uri(data->client, song); - sticker_print_value(data->client, data->name, value); -} - -static enum command_return -handle_sticker_song(struct client *client, int argc, char *argv[]) -{ - /* get song song_id key */ - if (argc == 5 && strcmp(argv[1], "get") == 0) { - struct song *song; - char *value; - - song = db_get_song(argv[3]); - if (song == NULL) { - command_error(client, ACK_ERROR_NO_EXIST, - "no such song"); - return COMMAND_RETURN_ERROR; - } - - value = sticker_song_get_value(song, argv[4]); - db_return_song(song); - if (value == NULL) { - command_error(client, ACK_ERROR_NO_EXIST, - "no such sticker"); - return COMMAND_RETURN_ERROR; - } - - sticker_print_value(client, argv[4], value); - g_free(value); - - return COMMAND_RETURN_OK; - /* list song song_id */ - } else if (argc == 4 && strcmp(argv[1], "list") == 0) { - struct song *song; - struct sticker *sticker; - - song = db_get_song(argv[3]); - if (song == NULL) { - command_error(client, ACK_ERROR_NO_EXIST, - "no such song"); - return COMMAND_RETURN_ERROR; - } - - sticker = sticker_song_get(song); - db_return_song(song); - if (sticker) { - sticker_print(client, sticker); - sticker_free(sticker); - } - - return COMMAND_RETURN_OK; - /* set song song_id id key */ - } else if (argc == 6 && strcmp(argv[1], "set") == 0) { - struct song *song; - bool ret; - - song = db_get_song(argv[3]); - if (song == NULL) { - command_error(client, ACK_ERROR_NO_EXIST, - "no such song"); - return COMMAND_RETURN_ERROR; - } - - ret = sticker_song_set_value(song, argv[4], argv[5]); - db_return_song(song); - if (!ret) { - command_error(client, ACK_ERROR_SYSTEM, - "failed to set sticker value"); - return COMMAND_RETURN_ERROR; - } - - return COMMAND_RETURN_OK; - /* delete song song_id [key] */ - } else if ((argc == 4 || argc == 5) && - strcmp(argv[1], "delete") == 0) { - struct song *song; - bool ret; - - song = db_get_song(argv[3]); - if (song == NULL) { - command_error(client, ACK_ERROR_NO_EXIST, - "no such song"); - return COMMAND_RETURN_ERROR; - } - - ret = argc == 4 - ? sticker_song_delete(song) - : sticker_song_delete_value(song, argv[4]); - db_return_song(song); - if (!ret) { - command_error(client, ACK_ERROR_SYSTEM, - "no such sticker"); - return COMMAND_RETURN_ERROR; - } - - return COMMAND_RETURN_OK; - /* find song dir key */ - } else if (argc == 5 && strcmp(argv[1], "find") == 0) { - /* "sticker find song a/directory name" */ - struct directory *directory; - bool success; - struct sticker_song_find_data data = { - .client = client, - .name = argv[4], - }; - - db_lock(); - directory = db_get_directory(argv[3]); - if (directory == NULL) { - db_unlock(); - command_error(client, ACK_ERROR_NO_EXIST, - "no such directory"); - return COMMAND_RETURN_ERROR; - } - - success = sticker_song_find(directory, data.name, - sticker_song_find_print_cb, &data); - db_unlock(); - if (!success) { - command_error(client, ACK_ERROR_SYSTEM, - "failed to set search sticker database"); - return COMMAND_RETURN_ERROR; - } - - return COMMAND_RETURN_OK; - } else { - command_error(client, ACK_ERROR_ARG, "bad request"); - return COMMAND_RETURN_ERROR; - } -} - -static enum command_return -handle_sticker(struct client *client, int argc, char *argv[]) -{ - assert(argc >= 4); - - if (!sticker_enabled()) { - command_error(client, ACK_ERROR_UNKNOWN, - "sticker database is disabled"); - return COMMAND_RETURN_ERROR; - } - - if (strcmp(argv[2], "song") == 0) - return handle_sticker_song(client, argc, argv); - else { - command_error(client, ACK_ERROR_ARG, - "unknown sticker domain"); - return COMMAND_RETURN_ERROR; - } -} -#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. * |