configure.ac: Move OggVorbis Encoder to Encoder Plugins.
[mpd-mk.git] / src / command.c
blobd514d069892245962b90535e6b28e106c408c0c1
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "config.h"
21 #include "command.h"
22 #include "player_control.h"
23 #include "playlist.h"
24 #include "playlist_print.h"
25 #include "playlist_save.h"
26 #include "playlist_queue.h"
27 #include "queue_print.h"
28 #include "ls.h"
29 #include "uri.h"
30 #include "decoder_print.h"
31 #include "directory.h"
32 #include "directory_print.h"
33 #include "database.h"
34 #include "update.h"
35 #include "volume.h"
36 #include "stats.h"
37 #include "permission.h"
38 #include "tokenizer.h"
39 #include "stored_playlist.h"
40 #include "ack.h"
41 #include "output_command.h"
42 #include "output_print.h"
43 #include "locate.h"
44 #include "dbUtils.h"
45 #include "tag.h"
46 #include "client.h"
47 #include "tag_print.h"
48 #include "path.h"
49 #include "replay_gain_config.h"
50 #include "idle.h"
52 #ifdef ENABLE_SQLITE
53 #include "sticker.h"
54 #include "sticker_print.h"
55 #include "song_sticker.h"
56 #include "song_print.h"
57 #endif
59 #include <assert.h>
60 #include <time.h>
61 #include <stdlib.h>
62 #include <errno.h>
64 #define COMMAND_STATUS_STATE "state"
65 #define COMMAND_STATUS_REPEAT "repeat"
66 #define COMMAND_STATUS_SINGLE "single"
67 #define COMMAND_STATUS_CONSUME "consume"
68 #define COMMAND_STATUS_RANDOM "random"
69 #define COMMAND_STATUS_PLAYLIST "playlist"
70 #define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength"
71 #define COMMAND_STATUS_SONG "song"
72 #define COMMAND_STATUS_SONGID "songid"
73 #define COMMAND_STATUS_NEXTSONG "nextsong"
74 #define COMMAND_STATUS_NEXTSONGID "nextsongid"
75 #define COMMAND_STATUS_TIME "time"
76 #define COMMAND_STATUS_BITRATE "bitrate"
77 #define COMMAND_STATUS_ERROR "error"
78 #define COMMAND_STATUS_CROSSFADE "xfade"
79 #define COMMAND_STATUS_MIXRAMPDB "mixrampdb"
80 #define COMMAND_STATUS_MIXRAMPDELAY "mixrampdelay"
81 #define COMMAND_STATUS_AUDIO "audio"
82 #define COMMAND_STATUS_UPDATING_DB "updating_db"
85 * The most we ever use is for search/find, and that limits it to the
86 * number of tags we can have. Add one for the command, and one extra
87 * to catch errors clients may send us
89 #define COMMAND_ARGV_MAX (2+(TAG_NUM_OF_ITEM_TYPES*2))
91 /* if min: -1 don't check args *
92 * if max: -1 no max args */
93 struct command {
94 const char *cmd;
95 unsigned permission;
96 int min;
97 int max;
98 enum command_return (*handler)(struct client *client, int argc, char **argv);
101 /* this should really be "need a non-negative integer": */
102 static const char need_positive[] = "need a positive integer"; /* no-op */
103 static const char need_range[] = "need a range";
105 /* FIXME: redundant error messages */
106 static const char check_integer[] = "\"%s\" is not a integer";
107 static const char need_integer[] = "need an integer";
109 static const char *current_command;
110 static int command_list_num;
112 void command_success(struct client *client)
114 client_puts(client, "OK\n");
117 static void command_error_v(struct client *client, enum ack error,
118 const char *fmt, va_list args)
120 assert(client != NULL);
121 assert(current_command != NULL);
123 client_printf(client, "ACK [%i@%i] {%s} ",
124 (int)error, command_list_num, current_command);
125 client_vprintf(client, fmt, args);
126 client_puts(client, "\n");
128 current_command = NULL;
131 G_GNUC_PRINTF(3, 4) static void command_error(struct client *client, enum ack error,
132 const char *fmt, ...)
134 va_list args;
135 va_start(args, fmt);
136 command_error_v(client, error, fmt, args);
137 va_end(args);
140 static bool G_GNUC_PRINTF(4, 5)
141 check_uint32(struct client *client, uint32_t *dst,
142 const char *s, const char *fmt, ...)
144 char *test;
146 *dst = strtoul(s, &test, 10);
147 if (*test != '\0') {
148 va_list args;
149 va_start(args, fmt);
150 command_error_v(client, ACK_ERROR_ARG, fmt, args);
151 va_end(args);
152 return false;
154 return true;
157 static bool G_GNUC_PRINTF(4, 5)
158 check_int(struct client *client, int *value_r,
159 const char *s, const char *fmt, ...)
161 char *test;
162 long value;
164 value = strtol(s, &test, 10);
165 if (*test != '\0') {
166 va_list args;
167 va_start(args, fmt);
168 command_error_v(client, ACK_ERROR_ARG, fmt, args);
169 va_end(args);
170 return false;
173 #if G_MAXLONG > G_MAXINT
174 if (value < G_MININT || value > G_MAXINT) {
175 command_error(client, ACK_ERROR_ARG,
176 "Number too large: %s", s);
177 return false;
179 #endif
181 *value_r = (int)value;
182 return true;
185 static bool G_GNUC_PRINTF(5, 6)
186 check_range(struct client *client, unsigned *value_r1, unsigned *value_r2,
187 const char *s, const char *fmt, ...)
189 char *test, *test2;
190 long value;
192 value = strtol(s, &test, 10);
193 if (*test != '\0' && *test != ':') {
194 va_list args;
195 va_start(args, fmt);
196 command_error_v(client, ACK_ERROR_ARG, fmt, args);
197 va_end(args);
198 return false;
201 if (value == -1 && *test == 0) {
202 /* compatibility with older MPD versions: specifying
203 "-1" makes MPD display the whole list */
204 *value_r1 = 0;
205 *value_r2 = G_MAXUINT;
206 return true;
209 if (value < 0) {
210 command_error(client, ACK_ERROR_ARG,
211 "Number is negative: %s", s);
212 return false;
215 #if G_MAXLONG > G_MAXUINT
216 if (value > G_MAXUINT) {
217 command_error(client, ACK_ERROR_ARG,
218 "Number too large: %s", s);
219 return false;
221 #endif
223 *value_r1 = (unsigned)value;
225 if (*test == ':') {
226 value = strtol(++test, &test2, 10);
227 if (*test2 != '\0') {
228 va_list args;
229 va_start(args, fmt);
230 command_error_v(client, ACK_ERROR_ARG, fmt, args);
231 va_end(args);
232 return false;
235 if (test == test2)
236 value = G_MAXUINT;
238 if (value < 0) {
239 command_error(client, ACK_ERROR_ARG,
240 "Number is negative: %s", s);
241 return false;
244 #if G_MAXLONG > G_MAXUINT
245 if (value > G_MAXUINT) {
246 command_error(client, ACK_ERROR_ARG,
247 "Number too large: %s", s);
248 return false;
250 #endif
251 *value_r2 = (unsigned)value;
252 } else {
253 *value_r2 = (unsigned)value + 1;
256 return true;
259 static bool
260 check_unsigned(struct client *client, unsigned *value_r, const char *s)
262 unsigned long value;
263 char *endptr;
265 value = strtoul(s, &endptr, 10);
266 if (*endptr != 0) {
267 command_error(client, ACK_ERROR_ARG,
268 "Integer expected: %s", s);
269 return false;
272 if (value > G_MAXUINT) {
273 command_error(client, ACK_ERROR_ARG,
274 "Number too large: %s", s);
275 return false;
278 *value_r = (unsigned)value;
279 return true;
282 static bool
283 check_bool(struct client *client, bool *value_r, const char *s)
285 long value;
286 char *endptr;
288 value = strtol(s, &endptr, 10);
289 if (*endptr != 0 || (value != 0 && value != 1)) {
290 command_error(client, ACK_ERROR_ARG,
291 "Boolean (0/1) expected: %s", s);
292 return false;
295 *value_r = !!value;
296 return true;
299 static bool
300 check_float(struct client *client, float *value_r, const char *s)
302 float value;
303 char *endptr;
305 value = strtof(s, &endptr);
306 if (*endptr != 0 && endptr == s) {
307 command_error(client, ACK_ERROR_ARG,
308 "Float expected: %s", s);
309 return false;
312 *value_r = value;
313 return true;
316 static enum command_return
317 print_playlist_result(struct client *client,
318 enum playlist_result result)
320 switch (result) {
321 case PLAYLIST_RESULT_SUCCESS:
322 return COMMAND_RETURN_OK;
324 case PLAYLIST_RESULT_ERRNO:
325 command_error(client, ACK_ERROR_SYSTEM, "%s", strerror(errno));
326 return COMMAND_RETURN_ERROR;
328 case PLAYLIST_RESULT_DENIED:
329 command_error(client, ACK_ERROR_NO_EXIST, "Access denied");
330 return COMMAND_RETURN_ERROR;
332 case PLAYLIST_RESULT_NO_SUCH_SONG:
333 command_error(client, ACK_ERROR_NO_EXIST, "No such song");
334 return COMMAND_RETURN_ERROR;
336 case PLAYLIST_RESULT_NO_SUCH_LIST:
337 command_error(client, ACK_ERROR_NO_EXIST, "No such playlist");
338 return COMMAND_RETURN_ERROR;
340 case PLAYLIST_RESULT_LIST_EXISTS:
341 command_error(client, ACK_ERROR_EXIST,
342 "Playlist already exists");
343 return COMMAND_RETURN_ERROR;
345 case PLAYLIST_RESULT_BAD_NAME:
346 command_error(client, ACK_ERROR_ARG,
347 "playlist name is invalid: "
348 "playlist names may not contain slashes,"
349 " newlines or carriage returns");
350 return COMMAND_RETURN_ERROR;
352 case PLAYLIST_RESULT_BAD_RANGE:
353 command_error(client, ACK_ERROR_ARG, "Bad song index");
354 return COMMAND_RETURN_ERROR;
356 case PLAYLIST_RESULT_NOT_PLAYING:
357 command_error(client, ACK_ERROR_PLAYER_SYNC, "Not playing");
358 return COMMAND_RETURN_ERROR;
360 case PLAYLIST_RESULT_TOO_LARGE:
361 command_error(client, ACK_ERROR_PLAYLIST_MAX,
362 "playlist is at the max size");
363 return COMMAND_RETURN_ERROR;
365 case PLAYLIST_RESULT_DISABLED:
366 command_error(client, ACK_ERROR_UNKNOWN,
367 "stored playlist support is disabled");
368 return COMMAND_RETURN_ERROR;
371 assert(0);
372 return COMMAND_RETURN_ERROR;
375 static void
376 print_spl_list(struct client *client, GPtrArray *list)
378 for (unsigned i = 0; i < list->len; ++i) {
379 struct stored_playlist_info *playlist =
380 g_ptr_array_index(list, i);
381 time_t t;
382 #ifndef WIN32
383 struct tm tm;
384 #endif
385 char timestamp[32];
387 client_printf(client, "playlist: %s\n", playlist->name);
389 t = playlist->mtime;
390 strftime(timestamp, sizeof(timestamp), "%FT%TZ",
391 #ifdef WIN32
392 gmtime(&t)
393 #else
394 gmtime_r(&t, &tm)
395 #endif
397 client_printf(client, "Last-Modified: %s\n", timestamp);
401 static enum command_return
402 handle_urlhandlers(struct client *client,
403 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
405 if (client_get_uid(client) > 0)
406 client_puts(client, "handler: file://\n");
407 print_supported_uri_schemes(client);
408 return COMMAND_RETURN_OK;
411 static enum command_return
412 handle_decoders(struct client *client,
413 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
415 decoder_list_print(client);
416 return COMMAND_RETURN_OK;
419 static enum command_return
420 handle_tagtypes(struct client *client,
421 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
423 tag_print_types(client);
424 return COMMAND_RETURN_OK;
427 static enum command_return
428 handle_play(struct client *client, int argc, char *argv[])
430 int song = -1;
431 enum playlist_result result;
433 if (argc == 2 && !check_int(client, &song, argv[1], need_positive))
434 return COMMAND_RETURN_ERROR;
435 result = playlist_play(&g_playlist, song);
436 return print_playlist_result(client, result);
439 static enum command_return
440 handle_playid(struct client *client, int argc, char *argv[])
442 int id = -1;
443 enum playlist_result result;
445 if (argc == 2 && !check_int(client, &id, argv[1], need_positive))
446 return COMMAND_RETURN_ERROR;
448 result = playlist_play_id(&g_playlist, id);
449 return print_playlist_result(client, result);
452 static enum command_return
453 handle_stop(G_GNUC_UNUSED struct client *client,
454 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
456 playlist_stop(&g_playlist);
457 return COMMAND_RETURN_OK;
460 static enum command_return
461 handle_currentsong(struct client *client,
462 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
464 playlist_print_current(client, &g_playlist);
465 return PLAYLIST_RESULT_SUCCESS;
468 static enum command_return
469 handle_pause(struct client *client,
470 int argc, char *argv[])
472 if (argc == 2) {
473 bool pause_flag;
474 if (!check_bool(client, &pause_flag, argv[1]))
475 return COMMAND_RETURN_ERROR;
477 pc_set_pause(pause_flag);
478 } else
479 pc_pause();
481 return COMMAND_RETURN_OK;
484 static enum command_return
485 handle_status(struct client *client,
486 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
488 const char *state = NULL;
489 struct player_status player_status;
490 int updateJobId;
491 char *error;
492 int song;
494 pc_get_status(&player_status);
496 switch (player_status.state) {
497 case PLAYER_STATE_STOP:
498 state = "stop";
499 break;
500 case PLAYER_STATE_PAUSE:
501 state = "pause";
502 break;
503 case PLAYER_STATE_PLAY:
504 state = "play";
505 break;
508 client_printf(client,
509 "volume: %i\n"
510 COMMAND_STATUS_REPEAT ": %i\n"
511 COMMAND_STATUS_RANDOM ": %i\n"
512 COMMAND_STATUS_SINGLE ": %i\n"
513 COMMAND_STATUS_CONSUME ": %i\n"
514 COMMAND_STATUS_PLAYLIST ": %li\n"
515 COMMAND_STATUS_PLAYLIST_LENGTH ": %i\n"
516 COMMAND_STATUS_CROSSFADE ": %i\n"
517 COMMAND_STATUS_MIXRAMPDB ": %f\n"
518 COMMAND_STATUS_MIXRAMPDELAY ": %f\n"
519 COMMAND_STATUS_STATE ": %s\n",
520 volume_level_get(),
521 playlist_get_repeat(&g_playlist),
522 playlist_get_random(&g_playlist),
523 playlist_get_single(&g_playlist),
524 playlist_get_consume(&g_playlist),
525 playlist_get_version(&g_playlist),
526 playlist_get_length(&g_playlist),
527 (int)(pc_get_cross_fade() + 0.5),
528 pc_get_mixramp_db(),
529 pc_get_mixramp_delay(),
530 state);
532 song = playlist_get_current_song(&g_playlist);
533 if (song >= 0) {
534 client_printf(client,
535 COMMAND_STATUS_SONG ": %i\n"
536 COMMAND_STATUS_SONGID ": %u\n",
537 song, playlist_get_song_id(&g_playlist, song));
540 if (player_status.state != PLAYER_STATE_STOP) {
541 struct audio_format_string af_string;
543 client_printf(client,
544 COMMAND_STATUS_TIME ": %i:%i\n"
545 "elapsed: %1.3f\n"
546 COMMAND_STATUS_BITRATE ": %u\n"
547 COMMAND_STATUS_AUDIO ": %s\n",
548 (int)(player_status.elapsed_time + 0.5),
549 (int)(player_status.total_time + 0.5),
550 player_status.elapsed_time,
551 player_status.bit_rate,
552 audio_format_to_string(&player_status.audio_format,
553 &af_string));
556 if ((updateJobId = isUpdatingDB())) {
557 client_printf(client,
558 COMMAND_STATUS_UPDATING_DB ": %i\n",
559 updateJobId);
562 error = pc_get_error_message();
563 if (error != NULL) {
564 client_printf(client,
565 COMMAND_STATUS_ERROR ": %s\n",
566 error);
567 g_free(error);
570 song = playlist_get_next_song(&g_playlist);
571 if (song >= 0) {
572 client_printf(client,
573 COMMAND_STATUS_NEXTSONG ": %i\n"
574 COMMAND_STATUS_NEXTSONGID ": %u\n",
575 song, playlist_get_song_id(&g_playlist, song));
578 return COMMAND_RETURN_OK;
581 static enum command_return
582 handle_kill(G_GNUC_UNUSED struct client *client,
583 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
585 return COMMAND_RETURN_KILL;
588 static enum command_return
589 handle_close(G_GNUC_UNUSED struct client *client,
590 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
592 return COMMAND_RETURN_CLOSE;
595 static enum command_return
596 handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
598 char *uri = argv[1];
599 enum playlist_result result;
601 if (strncmp(uri, "file:///", 8) == 0) {
602 #ifdef WIN32
603 result = PLAYLIST_RESULT_DENIED;
604 #else
605 result = playlist_append_file(&g_playlist,
606 uri + 7, client_get_uid(client),
607 NULL);
608 #endif
609 return print_playlist_result(client, result);
612 if (uri_has_scheme(uri)) {
613 if (!uri_supported_scheme(uri)) {
614 command_error(client, ACK_ERROR_NO_EXIST,
615 "unsupported URI scheme");
616 return COMMAND_RETURN_ERROR;
619 result = playlist_append_uri(&g_playlist, uri, NULL);
620 return print_playlist_result(client, result);
623 result = addAllIn(uri);
624 if (result == (enum playlist_result)-1) {
625 command_error(client, ACK_ERROR_NO_EXIST,
626 "directory or file not found");
627 return COMMAND_RETURN_ERROR;
630 return print_playlist_result(client, result);
633 static enum command_return
634 handle_addid(struct client *client, int argc, char *argv[])
636 char *uri = argv[1];
637 unsigned added_id;
638 enum playlist_result result;
640 if (strncmp(uri, "file:///", 8) == 0) {
641 #ifdef WIN32
642 result = PLAYLIST_RESULT_DENIED;
643 #else
644 result = playlist_append_file(&g_playlist, uri + 7,
645 client_get_uid(client),
646 &added_id);
647 #endif
648 } else {
649 if (uri_has_scheme(uri) && !uri_supported_scheme(uri)) {
650 command_error(client, ACK_ERROR_NO_EXIST,
651 "unsupported URI scheme");
652 return COMMAND_RETURN_ERROR;
655 result = playlist_append_uri(&g_playlist, uri, &added_id);
658 if (result != PLAYLIST_RESULT_SUCCESS)
659 return print_playlist_result(client, result);
661 if (argc == 3) {
662 int to;
663 if (!check_int(client, &to, argv[2], check_integer, argv[2]))
664 return COMMAND_RETURN_ERROR;
665 result = playlist_move_id(&g_playlist, added_id, to);
666 if (result != PLAYLIST_RESULT_SUCCESS) {
667 enum command_return ret =
668 print_playlist_result(client, result);
669 playlist_delete_id(&g_playlist, added_id);
670 return ret;
674 client_printf(client, "Id: %u\n", added_id);
675 return COMMAND_RETURN_OK;
678 static enum command_return
679 handle_delete(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
681 unsigned start, end;
682 enum playlist_result result;
684 if (!check_range(client, &start, &end, argv[1], need_range))
685 return COMMAND_RETURN_ERROR;
687 result = playlist_delete_range(&g_playlist, start, end);
688 return print_playlist_result(client, result);
691 static enum command_return
692 handle_deleteid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
694 int id;
695 enum playlist_result result;
697 if (!check_int(client, &id, argv[1], need_positive))
698 return COMMAND_RETURN_ERROR;
700 result = playlist_delete_id(&g_playlist, id);
701 return print_playlist_result(client, result);
704 static enum command_return
705 handle_playlist(struct client *client,
706 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
708 playlist_print_uris(client, &g_playlist);
709 return COMMAND_RETURN_OK;
712 static enum command_return
713 handle_shuffle(G_GNUC_UNUSED struct client *client,
714 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
716 unsigned start = 0, end = queue_length(&g_playlist.queue);
717 if (argc == 2 && !check_range(client, &start, &end,
718 argv[1], need_range))
719 return COMMAND_RETURN_ERROR;
721 playlist_shuffle(&g_playlist, start, end);
722 return COMMAND_RETURN_OK;
725 static enum command_return
726 handle_clear(G_GNUC_UNUSED struct client *client,
727 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
729 playlist_clear(&g_playlist);
730 return COMMAND_RETURN_OK;
733 static enum command_return
734 handle_save(struct client *client,
735 G_GNUC_UNUSED int argc, char *argv[])
737 enum playlist_result result;
739 result = spl_save_playlist(argv[1], &g_playlist);
740 return print_playlist_result(client, result);
743 static enum command_return
744 handle_load(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
746 enum playlist_result result;
748 result = playlist_open_into_queue(argv[1], &g_playlist);
749 if (result != PLAYLIST_RESULT_NO_SUCH_LIST)
750 return result;
752 result = playlist_load_spl(&g_playlist, argv[1]);
753 return print_playlist_result(client, result);
756 static enum command_return
757 handle_listplaylist(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
759 if (playlist_file_print(client, argv[1], false))
760 return COMMAND_RETURN_OK;
762 bool ret;
764 ret = spl_print(client, argv[1], false);
765 if (!ret) {
766 command_error(client, ACK_ERROR_NO_EXIST, "No such playlist");
767 return COMMAND_RETURN_ERROR;
770 return COMMAND_RETURN_OK;
773 static enum command_return
774 handle_listplaylistinfo(struct client *client,
775 G_GNUC_UNUSED int argc, char *argv[])
777 if (playlist_file_print(client, argv[1], true))
778 return COMMAND_RETURN_OK;
780 bool ret;
782 ret = spl_print(client, argv[1], true);
783 if (!ret) {
784 command_error(client, ACK_ERROR_NO_EXIST, "No such playlist");
785 return COMMAND_RETURN_ERROR;
788 return COMMAND_RETURN_OK;
791 static enum command_return
792 handle_lsinfo(struct client *client, int argc, char *argv[])
794 const char *uri;
795 const struct directory *directory;
797 if (argc == 2)
798 uri = argv[1];
799 else
800 /* default is root directory */
801 uri = "";
803 directory = db_get_directory(uri);
804 if (directory == NULL) {
805 command_error(client, ACK_ERROR_NO_EXIST,
806 "directory not found");
807 return COMMAND_RETURN_ERROR;
810 directory_print(client, directory);
812 if (isRootDirectory(uri)) {
813 GPtrArray *list = spl_list();
814 if (list != NULL) {
815 print_spl_list(client, list);
816 spl_list_free(list);
820 return COMMAND_RETURN_OK;
823 static enum command_return
824 handle_rm(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
826 enum playlist_result result;
828 result = spl_delete(argv[1]);
829 return print_playlist_result(client, result);
832 static enum command_return
833 handle_rename(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
835 enum playlist_result result;
837 result = spl_rename(argv[1], argv[2]);
838 return print_playlist_result(client, result);
841 static enum command_return
842 handle_plchanges(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
844 uint32_t version;
846 if (!check_uint32(client, &version, argv[1], need_positive))
847 return COMMAND_RETURN_ERROR;
849 playlist_print_changes_info(client, &g_playlist, version);
850 return COMMAND_RETURN_OK;
853 static enum command_return
854 handle_plchangesposid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
856 uint32_t version;
858 if (!check_uint32(client, &version, argv[1], need_positive))
859 return COMMAND_RETURN_ERROR;
861 playlist_print_changes_position(client, &g_playlist, version);
862 return COMMAND_RETURN_OK;
865 static enum command_return
866 handle_playlistinfo(struct client *client, int argc, char *argv[])
868 unsigned start = 0, end = G_MAXUINT;
869 bool ret;
871 if (argc == 2 && !check_range(client, &start, &end,
872 argv[1], need_range))
873 return COMMAND_RETURN_ERROR;
875 ret = playlist_print_info(client, &g_playlist, start, end);
876 if (!ret)
877 return print_playlist_result(client,
878 PLAYLIST_RESULT_BAD_RANGE);
880 return COMMAND_RETURN_OK;
883 static enum command_return
884 handle_playlistid(struct client *client, int argc, char *argv[])
886 int id = -1;
888 if (argc == 2 && !check_int(client, &id, argv[1], need_positive))
889 return COMMAND_RETURN_ERROR;
891 if (id >= 0) {
892 bool ret = playlist_print_id(client, &g_playlist, id);
893 if (!ret)
894 return print_playlist_result(client,
895 PLAYLIST_RESULT_NO_SUCH_SONG);
896 } else {
897 playlist_print_info(client, &g_playlist, 0, G_MAXUINT);
900 return COMMAND_RETURN_OK;
903 static enum command_return
904 handle_find(struct client *client, int argc, char *argv[])
906 int ret;
907 struct locate_item_list *list =
908 locate_item_list_parse(argv + 1, argc - 1);
910 if (list == NULL || list->length == 0) {
911 if (list != NULL)
912 locate_item_list_free(list);
914 command_error(client, ACK_ERROR_ARG, "incorrect arguments");
915 return COMMAND_RETURN_ERROR;
918 ret = findSongsIn(client, NULL, list);
919 if (ret == -1)
920 command_error(client, ACK_ERROR_NO_EXIST,
921 "directory or file not found");
923 locate_item_list_free(list);
925 return ret;
928 static enum command_return
929 handle_findadd(struct client *client, int argc, char *argv[])
931 int ret;
932 struct locate_item_list *list =
933 locate_item_list_parse(argv + 1, argc - 1);
934 if (list == NULL || list->length == 0) {
935 if (list != NULL)
936 locate_item_list_free(list);
938 command_error(client, ACK_ERROR_ARG, "incorrect arguments");
939 return COMMAND_RETURN_ERROR;
942 ret = findAddIn(client, NULL, list);
943 if (ret == -1)
944 command_error(client, ACK_ERROR_NO_EXIST,
945 "directory or file not found");
947 locate_item_list_free(list);
949 return ret;
952 static enum command_return
953 handle_search(struct client *client, int argc, char *argv[])
955 int ret;
956 struct locate_item_list *list =
957 locate_item_list_parse(argv + 1, argc - 1);
959 if (list == NULL || list->length == 0) {
960 if (list != NULL)
961 locate_item_list_free(list);
963 command_error(client, ACK_ERROR_ARG, "incorrect arguments");
964 return COMMAND_RETURN_ERROR;
967 ret = searchForSongsIn(client, NULL, list);
968 if (ret == -1)
969 command_error(client, ACK_ERROR_NO_EXIST,
970 "directory or file not found");
972 locate_item_list_free(list);
974 return ret;
977 static enum command_return
978 handle_count(struct client *client, int argc, char *argv[])
980 int ret;
981 struct locate_item_list *list =
982 locate_item_list_parse(argv + 1, argc - 1);
984 if (list == NULL || list->length == 0) {
985 if (list != NULL)
986 locate_item_list_free(list);
988 command_error(client, ACK_ERROR_ARG, "incorrect arguments");
989 return COMMAND_RETURN_ERROR;
992 ret = searchStatsForSongsIn(client, NULL, list);
993 if (ret == -1)
994 command_error(client, ACK_ERROR_NO_EXIST,
995 "directory or file not found");
997 locate_item_list_free(list);
999 return ret;
1002 static enum command_return
1003 handle_playlistfind(struct client *client, int argc, char *argv[])
1005 struct locate_item_list *list =
1006 locate_item_list_parse(argv + 1, argc - 1);
1008 if (list == NULL || list->length == 0) {
1009 if (list != NULL)
1010 locate_item_list_free(list);
1012 command_error(client, ACK_ERROR_ARG, "incorrect arguments");
1013 return COMMAND_RETURN_ERROR;
1016 playlist_print_find(client, &g_playlist, list);
1018 locate_item_list_free(list);
1020 return COMMAND_RETURN_OK;
1023 static enum command_return
1024 handle_playlistsearch(struct client *client, int argc, char *argv[])
1026 struct locate_item_list *list =
1027 locate_item_list_parse(argv + 1, argc - 1);
1029 if (list == NULL || list->length == 0) {
1030 if (list != NULL)
1031 locate_item_list_free(list);
1033 command_error(client, ACK_ERROR_ARG, "incorrect arguments");
1034 return COMMAND_RETURN_ERROR;
1037 playlist_print_search(client, &g_playlist, list);
1039 locate_item_list_free(list);
1041 return COMMAND_RETURN_OK;
1044 static enum command_return
1045 handle_playlistdelete(struct client *client,
1046 G_GNUC_UNUSED int argc, char *argv[]) {
1047 char *playlist = argv[1];
1048 int from;
1049 enum playlist_result result;
1051 if (!check_int(client, &from, argv[2], check_integer, argv[2]))
1052 return COMMAND_RETURN_ERROR;
1054 result = spl_remove_index(playlist, from);
1055 return print_playlist_result(client, result);
1058 static enum command_return
1059 handle_playlistmove(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1061 char *playlist = argv[1];
1062 int from, to;
1063 enum playlist_result result;
1065 if (!check_int(client, &from, argv[2], check_integer, argv[2]))
1066 return COMMAND_RETURN_ERROR;
1067 if (!check_int(client, &to, argv[3], check_integer, argv[3]))
1068 return COMMAND_RETURN_ERROR;
1070 result = spl_move_index(playlist, from, to);
1071 return print_playlist_result(client, result);
1074 static enum command_return
1075 handle_update(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1077 const char *path = NULL;
1078 unsigned ret;
1080 assert(argc <= 2);
1081 if (argc == 2) {
1082 path = argv[1];
1084 if (*path == 0 || strcmp(path, "/") == 0)
1085 /* backwards compatibility with MPD 0.15 */
1086 path = NULL;
1087 else if (!uri_safe_local(path)) {
1088 command_error(client, ACK_ERROR_ARG,
1089 "Malformed path");
1090 return COMMAND_RETURN_ERROR;
1094 ret = update_enqueue(path, false);
1095 if (ret > 0) {
1096 client_printf(client, "updating_db: %i\n", ret);
1097 return COMMAND_RETURN_OK;
1098 } else {
1099 command_error(client, ACK_ERROR_UPDATE_ALREADY,
1100 "already updating");
1101 return COMMAND_RETURN_ERROR;
1105 static enum command_return
1106 handle_rescan(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1108 const char *path = NULL;
1109 unsigned ret;
1111 assert(argc <= 2);
1112 if (argc == 2) {
1113 path = argv[1];
1115 if (!uri_safe_local(path)) {
1116 command_error(client, ACK_ERROR_ARG,
1117 "Malformed path");
1118 return COMMAND_RETURN_ERROR;
1122 ret = update_enqueue(path, true);
1123 if (ret > 0) {
1124 client_printf(client, "updating_db: %i\n", ret);
1125 return COMMAND_RETURN_OK;
1126 } else {
1127 command_error(client, ACK_ERROR_UPDATE_ALREADY,
1128 "already updating");
1129 return COMMAND_RETURN_ERROR;
1133 static enum command_return
1134 handle_next(G_GNUC_UNUSED struct client *client,
1135 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1137 /* single mode is not considered when this is user who
1138 * wants to change song. */
1139 int single = g_playlist.queue.single;
1140 g_playlist.queue.single = false;
1142 playlist_next(&g_playlist);
1144 g_playlist.queue.single = single;
1145 return COMMAND_RETURN_OK;
1148 static enum command_return
1149 handle_previous(G_GNUC_UNUSED struct client *client,
1150 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1152 playlist_previous(&g_playlist);
1153 return COMMAND_RETURN_OK;
1156 static enum command_return
1157 handle_listall(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1159 char *directory = NULL;
1160 int ret;
1162 if (argc == 2)
1163 directory = argv[1];
1165 ret = printAllIn(client, directory);
1166 if (ret == -1)
1167 command_error(client, ACK_ERROR_NO_EXIST,
1168 "directory or file not found");
1170 return ret;
1173 static enum command_return
1174 handle_setvol(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1176 int level;
1177 bool success;
1179 if (!check_int(client, &level, argv[1], need_integer))
1180 return COMMAND_RETURN_ERROR;
1182 if (level < 0 || level > 100) {
1183 command_error(client, ACK_ERROR_ARG, "Invalid volume value");
1184 return COMMAND_RETURN_ERROR;
1187 success = volume_level_change(level);
1188 if (!success) {
1189 command_error(client, ACK_ERROR_SYSTEM,
1190 "problems setting volume");
1191 return COMMAND_RETURN_ERROR;
1194 return COMMAND_RETURN_OK;
1197 static enum command_return
1198 handle_repeat(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1200 int status;
1202 if (!check_int(client, &status, argv[1], need_integer))
1203 return COMMAND_RETURN_ERROR;
1205 if (status != 0 && status != 1) {
1206 command_error(client, ACK_ERROR_ARG,
1207 "\"%i\" is not 0 or 1", status);
1208 return COMMAND_RETURN_ERROR;
1211 playlist_set_repeat(&g_playlist, status);
1212 return COMMAND_RETURN_OK;
1215 static enum command_return
1216 handle_single(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1218 int status;
1220 if (!check_int(client, &status, argv[1], need_integer))
1221 return COMMAND_RETURN_ERROR;
1223 if (status != 0 && status != 1) {
1224 command_error(client, ACK_ERROR_ARG,
1225 "\"%i\" is not 0 or 1", status);
1226 return COMMAND_RETURN_ERROR;
1229 playlist_set_single(&g_playlist, status);
1230 return COMMAND_RETURN_OK;
1233 static enum command_return
1234 handle_consume(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1236 int status;
1238 if (!check_int(client, &status, argv[1], need_integer))
1239 return COMMAND_RETURN_ERROR;
1241 if (status != 0 && status != 1) {
1242 command_error(client, ACK_ERROR_ARG,
1243 "\"%i\" is not 0 or 1", status);
1244 return COMMAND_RETURN_ERROR;
1247 playlist_set_consume(&g_playlist, status);
1248 return COMMAND_RETURN_OK;
1251 static enum command_return
1252 handle_random(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1254 int status;
1256 if (!check_int(client, &status, argv[1], need_integer))
1257 return COMMAND_RETURN_ERROR;
1259 if (status != 0 && status != 1) {
1260 command_error(client, ACK_ERROR_ARG,
1261 "\"%i\" is not 0 or 1", status);
1262 return COMMAND_RETURN_ERROR;
1265 playlist_set_random(&g_playlist, status);
1266 return COMMAND_RETURN_OK;
1269 static enum command_return
1270 handle_stats(struct client *client,
1271 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1273 return stats_print(client);
1276 static enum command_return
1277 handle_clearerror(G_GNUC_UNUSED struct client *client,
1278 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1280 pc_clear_error();
1281 return COMMAND_RETURN_OK;
1284 static enum command_return
1285 handle_list(struct client *client, int argc, char *argv[])
1287 struct locate_item_list *conditionals;
1288 int tagType = locate_parse_type(argv[1]);
1289 int ret;
1291 if (tagType < 0) {
1292 command_error(client, ACK_ERROR_ARG, "\"%s\" is not known", argv[1]);
1293 return COMMAND_RETURN_ERROR;
1296 if (tagType == LOCATE_TAG_ANY_TYPE) {
1297 command_error(client, ACK_ERROR_ARG,
1298 "\"any\" is not a valid return tag type");
1299 return COMMAND_RETURN_ERROR;
1302 /* for compatibility with < 0.12.0 */
1303 if (argc == 3) {
1304 if (tagType != TAG_ALBUM) {
1305 command_error(client, ACK_ERROR_ARG,
1306 "should be \"%s\" for 3 arguments",
1307 tag_item_names[TAG_ALBUM]);
1308 return COMMAND_RETURN_ERROR;
1311 locate_item_list_parse(argv + 1, argc - 1);
1313 conditionals = locate_item_list_new(1);
1314 conditionals->items[0].tag = TAG_ARTIST;
1315 conditionals->items[0].needle = g_strdup(argv[2]);
1316 } else {
1317 conditionals =
1318 locate_item_list_parse(argv + 2, argc - 2);
1319 if (conditionals == NULL) {
1320 command_error(client, ACK_ERROR_ARG,
1321 "not able to parse args");
1322 return COMMAND_RETURN_ERROR;
1326 ret = listAllUniqueTags(client, tagType, conditionals);
1328 locate_item_list_free(conditionals);
1330 if (ret == -1)
1331 command_error(client, ACK_ERROR_NO_EXIST,
1332 "directory or file not found");
1334 return ret;
1337 static enum command_return
1338 handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1340 unsigned start, end;
1341 int to;
1342 enum playlist_result result;
1344 if (!check_range(client, &start, &end,
1345 argv[1], need_range))
1346 return COMMAND_RETURN_ERROR;
1347 if (!check_int(client, &to, argv[2], check_integer, argv[2]))
1348 return COMMAND_RETURN_ERROR;
1349 result = playlist_move_range(&g_playlist, start, end, to);
1350 return print_playlist_result(client, result);
1353 static enum command_return
1354 handle_moveid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1356 int id, to;
1357 enum playlist_result result;
1359 if (!check_int(client, &id, argv[1], check_integer, argv[1]))
1360 return COMMAND_RETURN_ERROR;
1361 if (!check_int(client, &to, argv[2], check_integer, argv[2]))
1362 return COMMAND_RETURN_ERROR;
1363 result = playlist_move_id(&g_playlist, id, to);
1364 return print_playlist_result(client, result);
1367 static enum command_return
1368 handle_swap(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1370 int song1, song2;
1371 enum playlist_result result;
1373 if (!check_int(client, &song1, argv[1], check_integer, argv[1]))
1374 return COMMAND_RETURN_ERROR;
1375 if (!check_int(client, &song2, argv[2], check_integer, argv[2]))
1376 return COMMAND_RETURN_ERROR;
1377 result = playlist_swap_songs(&g_playlist, song1, song2);
1378 return print_playlist_result(client, result);
1381 static enum command_return
1382 handle_swapid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1384 int id1, id2;
1385 enum playlist_result result;
1387 if (!check_int(client, &id1, argv[1], check_integer, argv[1]))
1388 return COMMAND_RETURN_ERROR;
1389 if (!check_int(client, &id2, argv[2], check_integer, argv[2]))
1390 return COMMAND_RETURN_ERROR;
1391 result = playlist_swap_songs_id(&g_playlist, id1, id2);
1392 return print_playlist_result(client, result);
1395 static enum command_return
1396 handle_seek(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1398 int song, seek_time;
1399 enum playlist_result result;
1401 if (!check_int(client, &song, argv[1], check_integer, argv[1]))
1402 return COMMAND_RETURN_ERROR;
1403 if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
1404 return COMMAND_RETURN_ERROR;
1406 result = playlist_seek_song(&g_playlist, song, seek_time);
1407 return print_playlist_result(client, result);
1410 static enum command_return
1411 handle_seekid(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1413 int id, seek_time;
1414 enum playlist_result result;
1416 if (!check_int(client, &id, argv[1], check_integer, argv[1]))
1417 return COMMAND_RETURN_ERROR;
1418 if (!check_int(client, &seek_time, argv[2], check_integer, argv[2]))
1419 return COMMAND_RETURN_ERROR;
1421 result = playlist_seek_song_id(&g_playlist, id, seek_time);
1422 return print_playlist_result(client, result);
1425 static enum command_return
1426 handle_listallinfo(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1428 char *directory = NULL;
1429 int ret;
1431 if (argc == 2)
1432 directory = argv[1];
1434 ret = printInfoForAllIn(client, directory);
1435 if (ret == -1)
1436 command_error(client, ACK_ERROR_NO_EXIST,
1437 "directory or file not found");
1439 return ret;
1442 static enum command_return
1443 handle_ping(G_GNUC_UNUSED struct client *client,
1444 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1446 return COMMAND_RETURN_OK;
1449 static enum command_return
1450 handle_password(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1452 unsigned permission = 0;
1454 if (getPermissionFromPassword(argv[1], &permission) < 0) {
1455 command_error(client, ACK_ERROR_PASSWORD, "incorrect password");
1456 return COMMAND_RETURN_ERROR;
1459 client_set_permission(client, permission);
1461 return COMMAND_RETURN_OK;
1464 static enum command_return
1465 handle_crossfade(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1467 unsigned xfade_time;
1469 if (!check_unsigned(client, &xfade_time, argv[1]))
1470 return COMMAND_RETURN_ERROR;
1471 pc_set_cross_fade(xfade_time);
1473 return COMMAND_RETURN_OK;
1476 static enum command_return
1477 handle_mixrampdb(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1479 float db;
1481 if (!check_float(client, &db, argv[1]))
1482 return COMMAND_RETURN_ERROR;
1483 pc_set_mixramp_db(db);
1485 return COMMAND_RETURN_OK;
1488 static enum command_return
1489 handle_mixrampdelay(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1491 float delay_secs;
1493 if (!check_float(client, &delay_secs, argv[1]))
1494 return COMMAND_RETURN_ERROR;
1495 pc_set_mixramp_delay(delay_secs);
1497 return COMMAND_RETURN_OK;
1500 static enum command_return
1501 handle_enableoutput(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1503 unsigned device;
1504 bool ret;
1506 if (!check_unsigned(client, &device, argv[1]))
1507 return COMMAND_RETURN_ERROR;
1509 ret = audio_output_enable_index(device);
1510 if (!ret) {
1511 command_error(client, ACK_ERROR_NO_EXIST,
1512 "No such audio output");
1513 return COMMAND_RETURN_ERROR;
1516 return COMMAND_RETURN_OK;
1519 static enum command_return
1520 handle_disableoutput(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1522 unsigned device;
1523 bool ret;
1525 if (!check_unsigned(client, &device, argv[1]))
1526 return COMMAND_RETURN_ERROR;
1528 ret = audio_output_disable_index(device);
1529 if (!ret) {
1530 command_error(client, ACK_ERROR_NO_EXIST,
1531 "No such audio output");
1532 return COMMAND_RETURN_ERROR;
1535 return COMMAND_RETURN_OK;
1538 static enum command_return
1539 handle_devices(struct client *client,
1540 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1542 printAudioDevices(client);
1544 return COMMAND_RETURN_OK;
1547 /* don't be fooled, this is the command handler for "commands" command */
1548 static enum command_return
1549 handle_commands(struct client *client,
1550 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]);
1552 static enum command_return
1553 handle_not_commands(struct client *client,
1554 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]);
1556 static enum command_return
1557 handle_playlistclear(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1559 enum playlist_result result;
1561 result = spl_clear(argv[1]);
1562 return print_playlist_result(client, result);
1565 static enum command_return
1566 handle_playlistadd(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
1568 char *playlist = argv[1];
1569 char *uri = argv[2];
1570 enum playlist_result result;
1572 if (uri_has_scheme(uri)) {
1573 if (!uri_supported_scheme(uri)) {
1574 command_error(client, ACK_ERROR_NO_EXIST,
1575 "unsupported URI scheme");
1576 return COMMAND_RETURN_ERROR;
1579 result = spl_append_uri(uri, playlist);
1580 } else
1581 result = addAllInToStoredPlaylist(uri, playlist);
1583 if (result == (enum playlist_result)-1) {
1584 command_error(client, ACK_ERROR_NO_EXIST,
1585 "directory or file not found");
1586 return COMMAND_RETURN_ERROR;
1589 return print_playlist_result(client, result);
1592 static enum command_return
1593 handle_listplaylists(struct client *client,
1594 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1596 GPtrArray *list = spl_list();
1597 if (list == NULL) {
1598 command_error(client, ACK_ERROR_SYSTEM,
1599 "failed to get list of stored playlists");
1600 return COMMAND_RETURN_ERROR;
1603 print_spl_list(client, list);
1604 spl_list_free(list);
1605 return COMMAND_RETURN_OK;
1608 static enum command_return
1609 handle_replay_gain_mode(struct client *client,
1610 G_GNUC_UNUSED int argc, char *argv[])
1612 if (!replay_gain_set_mode_string(argv[1])) {
1613 command_error(client, ACK_ERROR_ARG,
1614 "Unrecognized replay gain mode");
1615 return COMMAND_RETURN_ERROR;
1618 return COMMAND_RETURN_OK;
1621 static enum command_return
1622 handle_replay_gain_status(struct client *client,
1623 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1625 client_printf(client, "replay_gain_mode: %s\n",
1626 replay_gain_get_mode_string());
1627 return COMMAND_RETURN_OK;
1630 static enum command_return
1631 handle_idle(struct client *client,
1632 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1634 unsigned flags = 0, j;
1635 int i;
1636 const char *const* idle_names;
1638 idle_names = idle_get_names();
1639 for (i = 1; i < argc; ++i) {
1640 if (!argv[i])
1641 continue;
1643 for (j = 0; idle_names[j]; ++j) {
1644 if (!g_ascii_strcasecmp(argv[i], idle_names[j])) {
1645 flags |= (1 << j);
1650 /* No argument means that the client wants to receive everything */
1651 if (flags == 0)
1652 flags = ~0;
1654 /* enable "idle" mode on this client */
1655 client_idle_wait(client, flags);
1657 /* return value is "1" so the caller won't print "OK" */
1658 return 1;
1661 #ifdef ENABLE_SQLITE
1662 struct sticker_song_find_data {
1663 struct client *client;
1664 const char *name;
1667 static void
1668 sticker_song_find_print_cb(struct song *song, const char *value,
1669 gpointer user_data)
1671 struct sticker_song_find_data *data = user_data;
1673 song_print_uri(data->client, song);
1674 sticker_print_value(data->client, data->name, value);
1677 static enum command_return
1678 handle_sticker_song(struct client *client, int argc, char *argv[])
1680 /* get song song_id key */
1681 if (argc == 5 && strcmp(argv[1], "get") == 0) {
1682 struct song *song;
1683 char *value;
1685 song = db_get_song(argv[3]);
1686 if (song == NULL) {
1687 command_error(client, ACK_ERROR_NO_EXIST,
1688 "no such song");
1689 return COMMAND_RETURN_ERROR;
1692 value = sticker_song_get_value(song, argv[4]);
1693 if (value == NULL) {
1694 command_error(client, ACK_ERROR_NO_EXIST,
1695 "no such sticker");
1696 return COMMAND_RETURN_ERROR;
1699 sticker_print_value(client, argv[4], value);
1700 g_free(value);
1702 return COMMAND_RETURN_OK;
1703 /* list song song_id */
1704 } else if (argc == 4 && strcmp(argv[1], "list") == 0) {
1705 struct song *song;
1706 struct sticker *sticker;
1708 song = db_get_song(argv[3]);
1709 if (song == NULL) {
1710 command_error(client, ACK_ERROR_NO_EXIST,
1711 "no such song");
1712 return COMMAND_RETURN_ERROR;
1715 sticker = sticker_song_get(song);
1716 if (NULL == sticker) {
1717 command_error(client, ACK_ERROR_NO_EXIST,
1718 "no stickers found");
1719 return COMMAND_RETURN_ERROR;
1722 sticker_print(client, sticker);
1723 sticker_free(sticker);
1725 return COMMAND_RETURN_OK;
1726 /* set song song_id id key */
1727 } else if (argc == 6 && strcmp(argv[1], "set") == 0) {
1728 struct song *song;
1729 bool ret;
1731 song = db_get_song(argv[3]);
1732 if (song == NULL) {
1733 command_error(client, ACK_ERROR_NO_EXIST,
1734 "no such song");
1735 return COMMAND_RETURN_ERROR;
1738 ret = sticker_song_set_value(song, argv[4], argv[5]);
1739 if (!ret) {
1740 command_error(client, ACK_ERROR_SYSTEM,
1741 "failed to set sticker value");
1742 return COMMAND_RETURN_ERROR;
1745 return COMMAND_RETURN_OK;
1746 /* delete song song_id [key] */
1747 } else if ((argc == 4 || argc == 5) &&
1748 strcmp(argv[1], "delete") == 0) {
1749 struct song *song;
1750 bool ret;
1752 song = db_get_song(argv[3]);
1753 if (song == NULL) {
1754 command_error(client, ACK_ERROR_NO_EXIST,
1755 "no such song");
1756 return COMMAND_RETURN_ERROR;
1759 ret = argc == 4
1760 ? sticker_song_delete(song)
1761 : sticker_song_delete_value(song, argv[4]);
1762 if (!ret) {
1763 command_error(client, ACK_ERROR_SYSTEM,
1764 "no such sticker");
1765 return COMMAND_RETURN_ERROR;
1768 return COMMAND_RETURN_OK;
1769 /* find song dir key */
1770 } else if (argc == 5 && strcmp(argv[1], "find") == 0) {
1771 /* "sticker find song a/directory name" */
1772 struct directory *directory;
1773 bool success;
1774 struct sticker_song_find_data data = {
1775 .client = client,
1776 .name = argv[4],
1779 directory = db_get_directory(argv[3]);
1780 if (directory == NULL) {
1781 command_error(client, ACK_ERROR_NO_EXIST,
1782 "no such directory");
1783 return COMMAND_RETURN_ERROR;
1786 success = sticker_song_find(directory, data.name,
1787 sticker_song_find_print_cb, &data);
1788 if (!success) {
1789 command_error(client, ACK_ERROR_SYSTEM,
1790 "failed to set search sticker database");
1791 return COMMAND_RETURN_ERROR;
1794 return COMMAND_RETURN_OK;
1795 } else {
1796 command_error(client, ACK_ERROR_ARG, "bad request");
1797 return COMMAND_RETURN_ERROR;
1801 static enum command_return
1802 handle_sticker(struct client *client, int argc, char *argv[])
1804 assert(argc >= 4);
1806 if (!sticker_enabled()) {
1807 command_error(client, ACK_ERROR_UNKNOWN,
1808 "sticker database is disabled");
1809 return COMMAND_RETURN_ERROR;
1812 if (strcmp(argv[2], "song") == 0)
1813 return handle_sticker_song(client, argc, argv);
1814 else {
1815 command_error(client, ACK_ERROR_ARG,
1816 "unknown sticker domain");
1817 return COMMAND_RETURN_ERROR;
1820 #endif
1823 * The command registry.
1825 * This array must be sorted!
1827 static const struct command commands[] = {
1828 { "add", PERMISSION_ADD, 1, 1, handle_add },
1829 { "addid", PERMISSION_ADD, 1, 2, handle_addid },
1830 { "clear", PERMISSION_CONTROL, 0, 0, handle_clear },
1831 { "clearerror", PERMISSION_CONTROL, 0, 0, handle_clearerror },
1832 { "close", PERMISSION_NONE, -1, -1, handle_close },
1833 { "commands", PERMISSION_NONE, 0, 0, handle_commands },
1834 { "consume", PERMISSION_CONTROL, 1, 1, handle_consume },
1835 { "count", PERMISSION_READ, 2, -1, handle_count },
1836 { "crossfade", PERMISSION_CONTROL, 1, 1, handle_crossfade },
1837 { "currentsong", PERMISSION_READ, 0, 0, handle_currentsong },
1838 { "decoders", PERMISSION_READ, 0, 0, handle_decoders },
1839 { "delete", PERMISSION_CONTROL, 1, 1, handle_delete },
1840 { "deleteid", PERMISSION_CONTROL, 1, 1, handle_deleteid },
1841 { "disableoutput", PERMISSION_ADMIN, 1, 1, handle_disableoutput },
1842 { "enableoutput", PERMISSION_ADMIN, 1, 1, handle_enableoutput },
1843 { "find", PERMISSION_READ, 2, -1, handle_find },
1844 { "findadd", PERMISSION_READ, 2, -1, handle_findadd},
1845 { "idle", PERMISSION_READ, 0, -1, handle_idle },
1846 { "kill", PERMISSION_ADMIN, -1, -1, handle_kill },
1847 { "list", PERMISSION_READ, 1, -1, handle_list },
1848 { "listall", PERMISSION_READ, 0, 1, handle_listall },
1849 { "listallinfo", PERMISSION_READ, 0, 1, handle_listallinfo },
1850 { "listplaylist", PERMISSION_READ, 1, 1, handle_listplaylist },
1851 { "listplaylistinfo", PERMISSION_READ, 1, 1, handle_listplaylistinfo },
1852 { "listplaylists", PERMISSION_READ, 0, 0, handle_listplaylists },
1853 { "load", PERMISSION_ADD, 1, 1, handle_load },
1854 { "lsinfo", PERMISSION_READ, 0, 1, handle_lsinfo },
1855 { "mixrampdb", PERMISSION_CONTROL, 1, 1, handle_mixrampdb },
1856 { "mixrampdelay", PERMISSION_CONTROL, 1, 1, handle_mixrampdelay },
1857 { "move", PERMISSION_CONTROL, 2, 2, handle_move },
1858 { "moveid", PERMISSION_CONTROL, 2, 2, handle_moveid },
1859 { "next", PERMISSION_CONTROL, 0, 0, handle_next },
1860 { "notcommands", PERMISSION_NONE, 0, 0, handle_not_commands },
1861 { "outputs", PERMISSION_READ, 0, 0, handle_devices },
1862 { "password", PERMISSION_NONE, 1, 1, handle_password },
1863 { "pause", PERMISSION_CONTROL, 0, 1, handle_pause },
1864 { "ping", PERMISSION_NONE, 0, 0, handle_ping },
1865 { "play", PERMISSION_CONTROL, 0, 1, handle_play },
1866 { "playid", PERMISSION_CONTROL, 0, 1, handle_playid },
1867 { "playlist", PERMISSION_READ, 0, 0, handle_playlist },
1868 { "playlistadd", PERMISSION_CONTROL, 2, 2, handle_playlistadd },
1869 { "playlistclear", PERMISSION_CONTROL, 1, 1, handle_playlistclear },
1870 { "playlistdelete", PERMISSION_CONTROL, 2, 2, handle_playlistdelete },
1871 { "playlistfind", PERMISSION_READ, 2, -1, handle_playlistfind },
1872 { "playlistid", PERMISSION_READ, 0, 1, handle_playlistid },
1873 { "playlistinfo", PERMISSION_READ, 0, 1, handle_playlistinfo },
1874 { "playlistmove", PERMISSION_CONTROL, 3, 3, handle_playlistmove },
1875 { "playlistsearch", PERMISSION_READ, 2, -1, handle_playlistsearch },
1876 { "plchanges", PERMISSION_READ, 1, 1, handle_plchanges },
1877 { "plchangesposid", PERMISSION_READ, 1, 1, handle_plchangesposid },
1878 { "previous", PERMISSION_CONTROL, 0, 0, handle_previous },
1879 { "random", PERMISSION_CONTROL, 1, 1, handle_random },
1880 { "rename", PERMISSION_CONTROL, 2, 2, handle_rename },
1881 { "repeat", PERMISSION_CONTROL, 1, 1, handle_repeat },
1882 { "replay_gain_mode", PERMISSION_CONTROL, 1, 1,
1883 handle_replay_gain_mode },
1884 { "replay_gain_status", PERMISSION_READ, 0, 0,
1885 handle_replay_gain_status },
1886 { "rescan", PERMISSION_ADMIN, 0, 1, handle_rescan },
1887 { "rm", PERMISSION_CONTROL, 1, 1, handle_rm },
1888 { "save", PERMISSION_CONTROL, 1, 1, handle_save },
1889 { "search", PERMISSION_READ, 2, -1, handle_search },
1890 { "seek", PERMISSION_CONTROL, 2, 2, handle_seek },
1891 { "seekid", PERMISSION_CONTROL, 2, 2, handle_seekid },
1892 { "setvol", PERMISSION_CONTROL, 1, 1, handle_setvol },
1893 { "shuffle", PERMISSION_CONTROL, 0, 1, handle_shuffle },
1894 { "single", PERMISSION_CONTROL, 1, 1, handle_single },
1895 { "stats", PERMISSION_READ, 0, 0, handle_stats },
1896 { "status", PERMISSION_READ, 0, 0, handle_status },
1897 #ifdef ENABLE_SQLITE
1898 { "sticker", PERMISSION_ADMIN, 3, -1, handle_sticker },
1899 #endif
1900 { "stop", PERMISSION_CONTROL, 0, 0, handle_stop },
1901 { "swap", PERMISSION_CONTROL, 2, 2, handle_swap },
1902 { "swapid", PERMISSION_CONTROL, 2, 2, handle_swapid },
1903 { "tagtypes", PERMISSION_READ, 0, 0, handle_tagtypes },
1904 { "update", PERMISSION_ADMIN, 0, 1, handle_update },
1905 { "urlhandlers", PERMISSION_READ, 0, 0, handle_urlhandlers },
1908 static const unsigned num_commands = sizeof(commands) / sizeof(commands[0]);
1910 static bool
1911 command_available(G_GNUC_UNUSED const struct command *cmd)
1913 #ifdef ENABLE_SQLITE
1914 if (strcmp(cmd->cmd, "sticker") == 0)
1915 return sticker_enabled();
1916 #endif
1918 return true;
1921 /* don't be fooled, this is the command handler for "commands" command */
1922 static enum command_return
1923 handle_commands(struct client *client,
1924 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1926 const unsigned permission = client_get_permission(client);
1927 const struct command *cmd;
1929 for (unsigned i = 0; i < num_commands; ++i) {
1930 cmd = &commands[i];
1932 if (cmd->permission == (permission & cmd->permission) &&
1933 command_available(cmd))
1934 client_printf(client, "command: %s\n", cmd->cmd);
1937 return COMMAND_RETURN_OK;
1940 static enum command_return
1941 handle_not_commands(struct client *client,
1942 G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
1944 const unsigned permission = client_get_permission(client);
1945 const struct command *cmd;
1947 for (unsigned i = 0; i < num_commands; ++i) {
1948 cmd = &commands[i];
1950 if (cmd->permission != (permission & cmd->permission))
1951 client_printf(client, "command: %s\n", cmd->cmd);
1954 return COMMAND_RETURN_OK;
1957 void command_init(void)
1959 #ifndef NDEBUG
1960 /* ensure that the command list is sorted */
1961 for (unsigned i = 0; i < num_commands - 1; ++i)
1962 assert(strcmp(commands[i].cmd, commands[i + 1].cmd) < 0);
1963 #endif
1966 void command_finish(void)
1970 static const struct command *
1971 command_lookup(const char *name)
1973 unsigned a = 0, b = num_commands, i;
1974 int cmp;
1976 /* binary search */
1977 do {
1978 i = (a + b) / 2;
1980 cmp = strcmp(name, commands[i].cmd);
1981 if (cmp == 0)
1982 return &commands[i];
1983 else if (cmp < 0)
1984 b = i;
1985 else if (cmp > 0)
1986 a = i + 1;
1987 } while (a < b);
1989 return NULL;
1992 static bool
1993 command_check_request(const struct command *cmd, struct client *client,
1994 unsigned permission, int argc, char *argv[])
1996 int min = cmd->min + 1;
1997 int max = cmd->max + 1;
1999 if (cmd->permission != (permission & cmd->permission)) {
2000 if (client != NULL)
2001 command_error(client, ACK_ERROR_PERMISSION,
2002 "you don't have permission for \"%s\"",
2003 cmd->cmd);
2004 return false;
2007 if (min == 0)
2008 return true;
2010 if (min == max && max != argc) {
2011 if (client != NULL)
2012 command_error(client, ACK_ERROR_ARG,
2013 "wrong number of arguments for \"%s\"",
2014 argv[0]);
2015 return false;
2016 } else if (argc < min) {
2017 if (client != NULL)
2018 command_error(client, ACK_ERROR_ARG,
2019 "too few arguments for \"%s\"", argv[0]);
2020 return false;
2021 } else if (argc > max && max /* != 0 */ ) {
2022 if (client != NULL)
2023 command_error(client, ACK_ERROR_ARG,
2024 "too many arguments for \"%s\"", argv[0]);
2025 return false;
2026 } else
2027 return true;
2030 static const struct command *
2031 command_checked_lookup(struct client *client, unsigned permission,
2032 int argc, char *argv[])
2034 static char unknown[] = "";
2035 const struct command *cmd;
2037 current_command = unknown;
2039 if (argc == 0)
2040 return NULL;
2042 cmd = command_lookup(argv[0]);
2043 if (cmd == NULL) {
2044 if (client != NULL)
2045 command_error(client, ACK_ERROR_UNKNOWN,
2046 "unknown command \"%s\"", argv[0]);
2047 return NULL;
2050 current_command = cmd->cmd;
2052 if (!command_check_request(cmd, client, permission, argc, argv))
2053 return NULL;
2055 return cmd;
2058 enum command_return
2059 command_process(struct client *client, unsigned num, char *line)
2061 GError *error = NULL;
2062 int argc;
2063 char *argv[COMMAND_ARGV_MAX] = { NULL };
2064 const struct command *cmd;
2065 enum command_return ret = COMMAND_RETURN_ERROR;
2067 command_list_num = num;
2069 /* get the command name (first word on the line) */
2071 argv[0] = tokenizer_next_word(&line, &error);
2072 if (argv[0] == NULL) {
2073 current_command = "";
2074 if (*line == 0)
2075 command_error(client, ACK_ERROR_UNKNOWN,
2076 "No command given");
2077 else {
2078 command_error(client, ACK_ERROR_UNKNOWN,
2079 "%s", error->message);
2080 g_error_free(error);
2082 current_command = NULL;
2084 return COMMAND_RETURN_ERROR;
2087 argc = 1;
2089 /* now parse the arguments (quoted or unquoted) */
2091 while (argc < (int)G_N_ELEMENTS(argv) &&
2092 (argv[argc] =
2093 tokenizer_next_param(&line, &error)) != NULL)
2094 ++argc;
2096 /* some error checks; we have to set current_command because
2097 command_error() expects it to be set */
2099 current_command = argv[0];
2101 if (argc >= (int)G_N_ELEMENTS(argv)) {
2102 command_error(client, ACK_ERROR_ARG, "Too many arguments");
2103 current_command = NULL;
2104 return COMMAND_RETURN_ERROR;
2107 if (*line != 0) {
2108 command_error(client, ACK_ERROR_ARG,
2109 "%s", error->message);
2110 current_command = NULL;
2111 g_error_free(error);
2112 return COMMAND_RETURN_ERROR;
2115 /* look up and invoke the command handler */
2117 cmd = command_checked_lookup(client, client_get_permission(client),
2118 argc, argv);
2119 if (cmd)
2120 ret = cmd->handler(client, argc, argv);
2122 current_command = NULL;
2123 command_list_num = 0;
2125 return ret;