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.
22 #include "player_control.h"
24 #include "playlist_print.h"
25 #include "playlist_save.h"
26 #include "playlist_queue.h"
27 #include "queue_print.h"
30 #include "decoder_print.h"
31 #include "directory.h"
32 #include "directory_print.h"
37 #include "permission.h"
38 #include "tokenizer.h"
39 #include "stored_playlist.h"
41 #include "output_command.h"
42 #include "output_print.h"
47 #include "tag_print.h"
49 #include "replay_gain_config.h"
54 #include "sticker_print.h"
55 #include "song_sticker.h"
56 #include "song_print.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 */
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
, ...)
136 command_error_v(client
, error
, fmt
, 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
, ...)
146 *dst
= strtoul(s
, &test
, 10);
150 command_error_v(client
, ACK_ERROR_ARG
, fmt
, args
);
157 static bool G_GNUC_PRINTF(4, 5)
158 check_int(struct client
*client
, int *value_r
,
159 const char *s
, const char *fmt
, ...)
164 value
= strtol(s
, &test
, 10);
168 command_error_v(client
, ACK_ERROR_ARG
, fmt
, args
);
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
);
181 *value_r
= (int)value
;
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
, ...)
192 value
= strtol(s
, &test
, 10);
193 if (*test
!= '\0' && *test
!= ':') {
196 command_error_v(client
, ACK_ERROR_ARG
, fmt
, args
);
201 if (value
== -1 && *test
== 0) {
202 /* compatibility with older MPD versions: specifying
203 "-1" makes MPD display the whole list */
205 *value_r2
= G_MAXUINT
;
210 command_error(client
, ACK_ERROR_ARG
,
211 "Number is negative: %s", s
);
215 #if G_MAXLONG > G_MAXUINT
216 if (value
> G_MAXUINT
) {
217 command_error(client
, ACK_ERROR_ARG
,
218 "Number too large: %s", s
);
223 *value_r1
= (unsigned)value
;
226 value
= strtol(++test
, &test2
, 10);
227 if (*test2
!= '\0') {
230 command_error_v(client
, ACK_ERROR_ARG
, fmt
, args
);
239 command_error(client
, ACK_ERROR_ARG
,
240 "Number is negative: %s", s
);
244 #if G_MAXLONG > G_MAXUINT
245 if (value
> G_MAXUINT
) {
246 command_error(client
, ACK_ERROR_ARG
,
247 "Number too large: %s", s
);
251 *value_r2
= (unsigned)value
;
253 *value_r2
= (unsigned)value
+ 1;
260 check_unsigned(struct client
*client
, unsigned *value_r
, const char *s
)
265 value
= strtoul(s
, &endptr
, 10);
267 command_error(client
, ACK_ERROR_ARG
,
268 "Integer expected: %s", s
);
272 if (value
> G_MAXUINT
) {
273 command_error(client
, ACK_ERROR_ARG
,
274 "Number too large: %s", s
);
278 *value_r
= (unsigned)value
;
283 check_bool(struct client
*client
, bool *value_r
, const char *s
)
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
);
300 check_float(struct client
*client
, float *value_r
, const char *s
)
305 value
= strtof(s
, &endptr
);
306 if (*endptr
!= 0 && endptr
== s
) {
307 command_error(client
, ACK_ERROR_ARG
,
308 "Float expected: %s", s
);
316 static enum command_return
317 print_playlist_result(struct client
*client
,
318 enum playlist_result 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
;
372 return COMMAND_RETURN_ERROR
;
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
);
387 client_printf(client
, "playlist: %s\n", playlist
->name
);
390 strftime(timestamp
, sizeof(timestamp
), "%FT%TZ",
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
[])
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
[])
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
[])
474 if (!check_bool(client
, &pause_flag
, argv
[1]))
475 return COMMAND_RETURN_ERROR
;
477 pc_set_pause(pause_flag
);
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
;
494 pc_get_status(&player_status
);
496 switch (player_status
.state
) {
497 case PLAYER_STATE_STOP
:
500 case PLAYER_STATE_PAUSE
:
503 case PLAYER_STATE_PLAY
:
508 client_printf(client
,
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",
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),
529 pc_get_mixramp_delay(),
532 song
= playlist_get_current_song(&g_playlist
);
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"
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
,
556 if ((updateJobId
= isUpdatingDB())) {
557 client_printf(client
,
558 COMMAND_STATUS_UPDATING_DB
": %i\n",
562 error
= pc_get_error_message();
564 client_printf(client
,
565 COMMAND_STATUS_ERROR
": %s\n",
570 song
= playlist_get_next_song(&g_playlist
);
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
[])
599 enum playlist_result result
;
601 if (strncmp(uri
, "file:///", 8) == 0) {
603 result
= PLAYLIST_RESULT_DENIED
;
605 result
= playlist_append_file(&g_playlist
,
606 uri
+ 7, client_get_uid(client
),
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
[])
638 enum playlist_result result
;
640 if (strncmp(uri
, "file:///", 8) == 0) {
642 result
= PLAYLIST_RESULT_DENIED
;
644 result
= playlist_append_file(&g_playlist
, uri
+ 7,
645 client_get_uid(client
),
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
);
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
);
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
[])
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
[])
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
)
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
;
764 ret
= spl_print(client
, argv
[1], false);
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
;
782 ret
= spl_print(client
, argv
[1], true);
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
[])
795 const struct directory
*directory
;
800 /* default is root directory */
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();
815 print_spl_list(client
, 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
[])
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
[])
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
;
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
);
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
[])
888 if (argc
== 2 && !check_int(client
, &id
, argv
[1], need_positive
))
889 return COMMAND_RETURN_ERROR
;
892 bool ret
= playlist_print_id(client
, &g_playlist
, id
);
894 return print_playlist_result(client
,
895 PLAYLIST_RESULT_NO_SUCH_SONG
);
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
[])
907 struct locate_item_list
*list
=
908 locate_item_list_parse(argv
+ 1, argc
- 1);
910 if (list
== NULL
|| list
->length
== 0) {
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
);
920 command_error(client
, ACK_ERROR_NO_EXIST
,
921 "directory or file not found");
923 locate_item_list_free(list
);
928 static enum command_return
929 handle_findadd(struct client
*client
, int argc
, char *argv
[])
932 struct locate_item_list
*list
=
933 locate_item_list_parse(argv
+ 1, argc
- 1);
934 if (list
== NULL
|| list
->length
== 0) {
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
);
944 command_error(client
, ACK_ERROR_NO_EXIST
,
945 "directory or file not found");
947 locate_item_list_free(list
);
952 static enum command_return
953 handle_search(struct client
*client
, int argc
, char *argv
[])
956 struct locate_item_list
*list
=
957 locate_item_list_parse(argv
+ 1, argc
- 1);
959 if (list
== NULL
|| list
->length
== 0) {
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
);
969 command_error(client
, ACK_ERROR_NO_EXIST
,
970 "directory or file not found");
972 locate_item_list_free(list
);
977 static enum command_return
978 handle_count(struct client
*client
, int argc
, char *argv
[])
981 struct locate_item_list
*list
=
982 locate_item_list_parse(argv
+ 1, argc
- 1);
984 if (list
== NULL
|| list
->length
== 0) {
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
);
994 command_error(client
, ACK_ERROR_NO_EXIST
,
995 "directory or file not found");
997 locate_item_list_free(list
);
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) {
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) {
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];
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];
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
;
1084 if (*path
== 0 || strcmp(path
, "/") == 0)
1085 /* backwards compatibility with MPD 0.15 */
1087 else if (!uri_safe_local(path
)) {
1088 command_error(client
, ACK_ERROR_ARG
,
1090 return COMMAND_RETURN_ERROR
;
1094 ret
= update_enqueue(path
, false);
1096 client_printf(client
, "updating_db: %i\n", ret
);
1097 return COMMAND_RETURN_OK
;
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
;
1115 if (!uri_safe_local(path
)) {
1116 command_error(client
, ACK_ERROR_ARG
,
1118 return COMMAND_RETURN_ERROR
;
1122 ret
= update_enqueue(path
, true);
1124 client_printf(client
, "updating_db: %i\n", ret
);
1125 return COMMAND_RETURN_OK
;
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
;
1163 directory
= argv
[1];
1165 ret
= printAllIn(client
, directory
);
1167 command_error(client
, ACK_ERROR_NO_EXIST
,
1168 "directory or file not found");
1173 static enum command_return
1174 handle_setvol(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
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
);
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
[])
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
[])
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
[])
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
[])
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
[])
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]);
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 */
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]);
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
);
1331 command_error(client
, ACK_ERROR_NO_EXIST
,
1332 "directory or file not found");
1337 static enum command_return
1338 handle_move(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1340 unsigned start
, end
;
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
[])
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
[])
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
[])
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
[])
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
;
1432 directory
= argv
[1];
1434 ret
= printInfoForAllIn(client
, directory
);
1436 command_error(client
, ACK_ERROR_NO_EXIST
,
1437 "directory or file not found");
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
[])
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
[])
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
[])
1506 if (!check_unsigned(client
, &device
, argv
[1]))
1507 return COMMAND_RETURN_ERROR
;
1509 ret
= audio_output_enable_index(device
);
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
[])
1525 if (!check_unsigned(client
, &device
, argv
[1]))
1526 return COMMAND_RETURN_ERROR
;
1528 ret
= audio_output_disable_index(device
);
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
);
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();
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
;
1636 const char *const* idle_names
;
1638 idle_names
= idle_get_names();
1639 for (i
= 1; i
< argc
; ++i
) {
1643 for (j
= 0; idle_names
[j
]; ++j
) {
1644 if (!g_ascii_strcasecmp(argv
[i
], idle_names
[j
])) {
1650 /* No argument means that the client wants to receive everything */
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" */
1661 #ifdef ENABLE_SQLITE
1662 struct sticker_song_find_data
{
1663 struct client
*client
;
1668 sticker_song_find_print_cb(struct song
*song
, const char *value
,
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) {
1685 song
= db_get_song(argv
[3]);
1687 command_error(client
, ACK_ERROR_NO_EXIST
,
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
,
1696 return COMMAND_RETURN_ERROR
;
1699 sticker_print_value(client
, argv
[4], value
);
1702 return COMMAND_RETURN_OK
;
1703 /* list song song_id */
1704 } else if (argc
== 4 && strcmp(argv
[1], "list") == 0) {
1706 struct sticker
*sticker
;
1708 song
= db_get_song(argv
[3]);
1710 command_error(client
, ACK_ERROR_NO_EXIST
,
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) {
1731 song
= db_get_song(argv
[3]);
1733 command_error(client
, ACK_ERROR_NO_EXIST
,
1735 return COMMAND_RETURN_ERROR
;
1738 ret
= sticker_song_set_value(song
, argv
[4], argv
[5]);
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) {
1752 song
= db_get_song(argv
[3]);
1754 command_error(client
, ACK_ERROR_NO_EXIST
,
1756 return COMMAND_RETURN_ERROR
;
1760 ? sticker_song_delete(song
)
1761 : sticker_song_delete_value(song
, argv
[4]);
1763 command_error(client
, ACK_ERROR_SYSTEM
,
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
;
1774 struct sticker_song_find_data data
= {
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
);
1789 command_error(client
, ACK_ERROR_SYSTEM
,
1790 "failed to set search sticker database");
1791 return COMMAND_RETURN_ERROR
;
1794 return COMMAND_RETURN_OK
;
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
[])
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
);
1815 command_error(client
, ACK_ERROR_ARG
,
1816 "unknown sticker domain");
1817 return COMMAND_RETURN_ERROR
;
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
},
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]);
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();
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
) {
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
) {
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)
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);
1966 void command_finish(void)
1970 static const struct command
*
1971 command_lookup(const char *name
)
1973 unsigned a
= 0, b
= num_commands
, i
;
1980 cmp
= strcmp(name
, commands
[i
].cmd
);
1982 return &commands
[i
];
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
)) {
2001 command_error(client
, ACK_ERROR_PERMISSION
,
2002 "you don't have permission for \"%s\"",
2010 if (min
== max
&& max
!= argc
) {
2012 command_error(client
, ACK_ERROR_ARG
,
2013 "wrong number of arguments for \"%s\"",
2016 } else if (argc
< min
) {
2018 command_error(client
, ACK_ERROR_ARG
,
2019 "too few arguments for \"%s\"", argv
[0]);
2021 } else if (argc
> max
&& max
/* != 0 */ ) {
2023 command_error(client
, ACK_ERROR_ARG
,
2024 "too many arguments for \"%s\"", argv
[0]);
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
;
2042 cmd
= command_lookup(argv
[0]);
2045 command_error(client
, ACK_ERROR_UNKNOWN
,
2046 "unknown command \"%s\"", argv
[0]);
2050 current_command
= cmd
->cmd
;
2052 if (!command_check_request(cmd
, client
, permission
, argc
, argv
))
2059 command_process(struct client
*client
, unsigned num
, char *line
)
2061 GError
*error
= NULL
;
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
= "";
2075 command_error(client
, ACK_ERROR_UNKNOWN
,
2076 "No command given");
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
;
2089 /* now parse the arguments (quoted or unquoted) */
2091 while (argc
< (int)G_N_ELEMENTS(argv
) &&
2093 tokenizer_next_param(&line
, &error
)) != NULL
)
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
;
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
),
2120 ret
= cmd
->handler(client
, argc
, argv
);
2122 current_command
= NULL
;
2123 command_list_num
= 0;