2 * Copyright (C) 2003-2009 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.
21 #include "player_control.h"
23 #include "playlist_print.h"
24 #include "playlist_save.h"
25 #include "queue_print.h"
28 #include "directory.h"
29 #include "directory_print.h"
34 #include "permission.h"
35 #include "tokenizer.h"
36 #include "stored_playlist.h"
38 #include "output_command.h"
39 #include "output_print.h"
44 #include "tag_print.h"
51 #include "sticker_print.h"
52 #include "song_sticker.h"
53 #include "song_print.h"
61 #define COMMAND_STATUS_STATE "state"
62 #define COMMAND_STATUS_REPEAT "repeat"
63 #define COMMAND_STATUS_SINGLE "single"
64 #define COMMAND_STATUS_CONSUME "consume"
65 #define COMMAND_STATUS_RANDOM "random"
66 #define COMMAND_STATUS_PLAYLIST "playlist"
67 #define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength"
68 #define COMMAND_STATUS_SONG "song"
69 #define COMMAND_STATUS_SONGID "songid"
70 #define COMMAND_STATUS_NEXTSONG "nextsong"
71 #define COMMAND_STATUS_NEXTSONGID "nextsongid"
72 #define COMMAND_STATUS_TIME "time"
73 #define COMMAND_STATUS_BITRATE "bitrate"
74 #define COMMAND_STATUS_ERROR "error"
75 #define COMMAND_STATUS_CROSSFADE "xfade"
76 #define COMMAND_STATUS_AUDIO "audio"
77 #define COMMAND_STATUS_UPDATING_DB "updating_db"
80 * The most we ever use is for search/find, and that limits it to the
81 * number of tags we can have. Add one for the command, and one extra
82 * to catch errors clients may send us
84 #define COMMAND_ARGV_MAX (2+(TAG_NUM_OF_ITEM_TYPES*2))
86 /* if min: -1 don't check args *
87 * if max: -1 no max args */
93 enum command_return (*handler
)(struct client
*client
, int argc
, char **argv
);
96 /* this should really be "need a non-negative integer": */
97 static const char need_positive
[] = "need a positive integer"; /* no-op */
98 static const char need_range
[] = "need a range";
100 /* FIXME: redundant error messages */
101 static const char check_integer
[] = "\"%s\" is not a integer";
102 static const char need_integer
[] = "need an integer";
104 static const char *current_command
;
105 static int command_list_num
;
107 void command_success(struct client
*client
)
109 client_puts(client
, "OK\n");
112 static void command_error_v(struct client
*client
, enum ack error
,
113 const char *fmt
, va_list args
)
115 assert(client
!= NULL
);
116 assert(current_command
!= NULL
);
118 client_printf(client
, "ACK [%i@%i] {%s} ",
119 (int)error
, command_list_num
, current_command
);
120 client_vprintf(client
, fmt
, args
);
121 client_puts(client
, "\n");
123 current_command
= NULL
;
126 G_GNUC_PRINTF(3, 4) static void command_error(struct client
*client
, enum ack error
,
127 const char *fmt
, ...)
131 command_error_v(client
, error
, fmt
, args
);
135 static bool G_GNUC_PRINTF(4, 5)
136 check_uint32(struct client
*client
, uint32_t *dst
,
137 const char *s
, const char *fmt
, ...)
141 *dst
= strtoul(s
, &test
, 10);
145 command_error_v(client
, ACK_ERROR_ARG
, fmt
, args
);
152 static bool G_GNUC_PRINTF(4, 5)
153 check_int(struct client
*client
, int *value_r
,
154 const char *s
, const char *fmt
, ...)
159 value
= strtol(s
, &test
, 10);
163 command_error_v(client
, ACK_ERROR_ARG
, fmt
, args
);
168 #if LONG_MAX > INT_MAX
169 if (value
< INT_MIN
|| value
> INT_MAX
) {
170 command_error(client
, ACK_ERROR_ARG
,
171 "Number too large: %s", s
);
176 *value_r
= (int)value
;
180 static bool G_GNUC_PRINTF(5, 6)
181 check_range(struct client
*client
, unsigned *value_r1
, unsigned *value_r2
,
182 const char *s
, const char *fmt
, ...)
187 value
= strtol(s
, &test
, 10);
188 if (*test
!= '\0' && *test
!= ':') {
191 command_error_v(client
, ACK_ERROR_ARG
, fmt
, args
);
196 if (value
== -1 && *test
== 0) {
197 /* compatibility with older MPD versions: specifying
198 "-1" makes MPD display the whole list */
200 *value_r2
= UINT_MAX
;
205 command_error(client
, ACK_ERROR_ARG
,
206 "Number is negative: %s", s
);
210 #if LONG_MAX > UINT_MAX
211 if (value
> UINT_MAX
) {
212 command_error(client
, ACK_ERROR_ARG
,
213 "Number too large: %s", s
);
218 *value_r1
= (unsigned)value
;
221 value
= strtol(++test
, &test2
, 10);
222 if (*test2
!= '\0' || test
== test2
) {
225 command_error_v(client
, ACK_ERROR_ARG
, fmt
, args
);
231 command_error(client
, ACK_ERROR_ARG
,
232 "Number is negative: %s", s
);
236 #if LONG_MAX > UINT_MAX
237 if (value
> UINT_MAX
) {
238 command_error(client
, ACK_ERROR_ARG
,
239 "Number too large: %s", s
);
243 *value_r2
= (unsigned)value
;
245 *value_r2
= (unsigned)value
+ 1;
252 check_unsigned(struct client
*client
, unsigned *value_r
, const char *s
)
257 value
= strtoul(s
, &endptr
, 10);
259 command_error(client
, ACK_ERROR_ARG
,
260 "Integer expected: %s", s
);
264 if (value
> UINT_MAX
) {
265 command_error(client
, ACK_ERROR_ARG
,
266 "Number too large: %s", s
);
270 *value_r
= (unsigned)value
;
275 check_bool(struct client
*client
, bool *value_r
, const char *s
)
280 value
= strtol(s
, &endptr
, 10);
281 if (*endptr
!= 0 || (value
!= 0 && value
!= 1)) {
282 command_error(client
, ACK_ERROR_ARG
,
283 "Boolean (0/1) expected: %s", s
);
291 static enum command_return
292 print_playlist_result(struct client
*client
,
293 enum playlist_result result
)
296 case PLAYLIST_RESULT_SUCCESS
:
297 return COMMAND_RETURN_OK
;
299 case PLAYLIST_RESULT_ERRNO
:
300 command_error(client
, ACK_ERROR_SYSTEM
, "%s", strerror(errno
));
301 return COMMAND_RETURN_ERROR
;
303 case PLAYLIST_RESULT_DENIED
:
304 command_error(client
, ACK_ERROR_NO_EXIST
, "Access denied");
305 return COMMAND_RETURN_ERROR
;
307 case PLAYLIST_RESULT_NO_SUCH_SONG
:
308 command_error(client
, ACK_ERROR_NO_EXIST
, "No such song");
309 return COMMAND_RETURN_ERROR
;
311 case PLAYLIST_RESULT_NO_SUCH_LIST
:
312 command_error(client
, ACK_ERROR_NO_EXIST
, "No such playlist");
313 return COMMAND_RETURN_ERROR
;
315 case PLAYLIST_RESULT_LIST_EXISTS
:
316 command_error(client
, ACK_ERROR_EXIST
,
317 "Playlist already exists");
318 return COMMAND_RETURN_ERROR
;
320 case PLAYLIST_RESULT_BAD_NAME
:
321 command_error(client
, ACK_ERROR_ARG
,
322 "playlist name is invalid: "
323 "playlist names may not contain slashes,"
324 " newlines or carriage returns");
325 return COMMAND_RETURN_ERROR
;
327 case PLAYLIST_RESULT_BAD_RANGE
:
328 command_error(client
, ACK_ERROR_ARG
, "Bad song index");
329 return COMMAND_RETURN_ERROR
;
331 case PLAYLIST_RESULT_NOT_PLAYING
:
332 command_error(client
, ACK_ERROR_PLAYER_SYNC
, "Not playing");
333 return COMMAND_RETURN_ERROR
;
335 case PLAYLIST_RESULT_TOO_LARGE
:
336 command_error(client
, ACK_ERROR_PLAYLIST_MAX
,
337 "playlist is at the max size");
338 return COMMAND_RETURN_ERROR
;
340 case PLAYLIST_RESULT_DISABLED
:
341 command_error(client
, ACK_ERROR_UNKNOWN
,
342 "stored playlist support is disabled");
343 return COMMAND_RETURN_ERROR
;
347 return COMMAND_RETURN_ERROR
;
351 print_spl_list(struct client
*client
, GPtrArray
*list
)
353 for (unsigned i
= 0; i
< list
->len
; ++i
) {
354 struct stored_playlist_info
*playlist
=
355 g_ptr_array_index(list
, i
);
362 client_printf(client
, "playlist: %s\n", playlist
->name
);
365 strftime(timestamp
, sizeof(timestamp
), "%FT%TZ",
372 client_printf(client
, "Last-Modified: %s\n", timestamp
);
376 static enum command_return
377 handle_urlhandlers(struct client
*client
,
378 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
380 if (client_get_uid(client
) > 0)
381 client_puts(client
, "handler: file://\n");
382 print_supported_uri_schemes(client
);
383 return COMMAND_RETURN_OK
;
386 static enum command_return
387 handle_tagtypes(struct client
*client
,
388 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
390 tag_print_types(client
);
391 return COMMAND_RETURN_OK
;
394 static enum command_return
395 handle_play(struct client
*client
, int argc
, char *argv
[])
398 enum playlist_result result
;
400 if (argc
== 2 && !check_int(client
, &song
, argv
[1], need_positive
))
401 return COMMAND_RETURN_ERROR
;
402 result
= playlist_play(&g_playlist
, song
);
403 return print_playlist_result(client
, result
);
406 static enum command_return
407 handle_playid(struct client
*client
, int argc
, char *argv
[])
410 enum playlist_result result
;
412 if (argc
== 2 && !check_int(client
, &id
, argv
[1], need_positive
))
413 return COMMAND_RETURN_ERROR
;
415 result
= playlist_play_id(&g_playlist
, id
);
416 return print_playlist_result(client
, result
);
419 static enum command_return
420 handle_stop(G_GNUC_UNUSED
struct client
*client
,
421 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
423 playlist_stop(&g_playlist
);
424 return COMMAND_RETURN_OK
;
427 static enum command_return
428 handle_currentsong(struct client
*client
,
429 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
431 playlist_print_current(client
, &g_playlist
);
432 return PLAYLIST_RESULT_SUCCESS
;
435 static enum command_return
436 handle_pause(struct client
*client
,
437 int argc
, char *argv
[])
441 if (!check_bool(client
, &pause_flag
, argv
[1]))
442 return COMMAND_RETURN_ERROR
;
443 playerSetPause(pause_flag
);
444 return COMMAND_RETURN_OK
;
448 return COMMAND_RETURN_OK
;
451 static enum command_return
452 handle_status(struct client
*client
,
453 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
455 const char *state
= NULL
;
459 switch (getPlayerState()) {
460 case PLAYER_STATE_STOP
:
463 case PLAYER_STATE_PAUSE
:
466 case PLAYER_STATE_PLAY
:
471 client_printf(client
,
473 COMMAND_STATUS_REPEAT
": %i\n"
474 COMMAND_STATUS_RANDOM
": %i\n"
475 COMMAND_STATUS_SINGLE
": %i\n"
476 COMMAND_STATUS_CONSUME
": %i\n"
477 COMMAND_STATUS_PLAYLIST
": %li\n"
478 COMMAND_STATUS_PLAYLIST_LENGTH
": %i\n"
479 COMMAND_STATUS_CROSSFADE
": %i\n"
480 COMMAND_STATUS_STATE
": %s\n",
482 playlist_get_repeat(&g_playlist
),
483 playlist_get_random(&g_playlist
),
484 playlist_get_single(&g_playlist
),
485 playlist_get_consume(&g_playlist
),
486 playlist_get_version(&g_playlist
),
487 playlist_get_length(&g_playlist
),
488 (int)(getPlayerCrossFade() + 0.5),
491 song
= playlist_get_current_song(&g_playlist
);
493 client_printf(client
,
494 COMMAND_STATUS_SONG
": %i\n"
495 COMMAND_STATUS_SONGID
": %u\n",
496 song
, playlist_get_song_id(&g_playlist
, song
));
499 if (getPlayerState() != PLAYER_STATE_STOP
) {
500 const struct audio_format
*af
= player_get_audio_format();
501 client_printf(client
,
502 COMMAND_STATUS_TIME
": %i:%i\n"
504 COMMAND_STATUS_BITRATE
": %li\n"
505 COMMAND_STATUS_AUDIO
": %u:%u:%u\n",
506 getPlayerElapsedTime(), getPlayerTotalTime(),
509 af
->sample_rate
, af
->bits
, af
->channels
);
512 if ((updateJobId
= isUpdatingDB())) {
513 client_printf(client
,
514 COMMAND_STATUS_UPDATING_DB
": %i\n",
518 if (getPlayerError() != PLAYER_ERROR_NOERROR
) {
519 client_printf(client
,
520 COMMAND_STATUS_ERROR
": %s\n",
521 getPlayerErrorStr());
524 song
= playlist_get_next_song(&g_playlist
);
526 client_printf(client
,
527 COMMAND_STATUS_NEXTSONG
": %i\n"
528 COMMAND_STATUS_NEXTSONGID
": %u\n",
529 song
, playlist_get_song_id(&g_playlist
, song
));
532 return COMMAND_RETURN_OK
;
535 static enum command_return
536 handle_kill(G_GNUC_UNUSED
struct client
*client
,
537 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
539 return COMMAND_RETURN_KILL
;
542 static enum command_return
543 handle_close(G_GNUC_UNUSED
struct client
*client
,
544 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
546 return COMMAND_RETURN_CLOSE
;
549 static enum command_return
550 handle_add(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
553 enum playlist_result result
;
555 if (strncmp(uri
, "file:///", 8) == 0) {
557 result
= PLAYLIST_RESULT_DENIED
;
559 result
= playlist_append_file(&g_playlist
,
560 uri
+ 7, client_get_uid(client
),
563 return print_playlist_result(client
, result
);
566 if (uri_has_scheme(uri
)) {
567 if (!uri_supported_scheme(uri
)) {
568 command_error(client
, ACK_ERROR_NO_EXIST
,
569 "unsupported URI scheme");
570 return COMMAND_RETURN_ERROR
;
573 result
= playlist_append_uri(&g_playlist
, uri
, NULL
);
574 return print_playlist_result(client
, result
);
577 result
= addAllIn(uri
);
578 if (result
== (enum playlist_result
)-1) {
579 command_error(client
, ACK_ERROR_NO_EXIST
,
580 "directory or file not found");
581 return COMMAND_RETURN_ERROR
;
584 return print_playlist_result(client
, result
);
587 static enum command_return
588 handle_addid(struct client
*client
, int argc
, char *argv
[])
592 enum playlist_result result
;
594 if (strncmp(uri
, "file:///", 8) == 0) {
596 result
= PLAYLIST_RESULT_DENIED
;
598 result
= playlist_append_file(&g_playlist
, uri
+ 7,
599 client_get_uid(client
),
603 if (uri_has_scheme(uri
) && !uri_supported_scheme(uri
)) {
604 command_error(client
, ACK_ERROR_NO_EXIST
,
605 "unsupported URI scheme");
606 return COMMAND_RETURN_ERROR
;
609 result
= playlist_append_uri(&g_playlist
, uri
, &added_id
);
612 if (result
!= PLAYLIST_RESULT_SUCCESS
)
613 return print_playlist_result(client
, result
);
617 if (!check_int(client
, &to
, argv
[2], check_integer
, argv
[2]))
618 return COMMAND_RETURN_ERROR
;
619 result
= playlist_move_id(&g_playlist
, added_id
, to
);
620 if (result
!= PLAYLIST_RESULT_SUCCESS
) {
621 enum command_return ret
=
622 print_playlist_result(client
, result
);
623 playlist_delete_id(&g_playlist
, added_id
);
628 client_printf(client
, "Id: %u\n", added_id
);
629 return COMMAND_RETURN_OK
;
632 static enum command_return
633 handle_delete(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
636 enum playlist_result result
;
638 if (!check_int(client
, &song
, argv
[1], need_positive
))
639 return COMMAND_RETURN_ERROR
;
641 result
= playlist_delete(&g_playlist
, song
);
642 return print_playlist_result(client
, result
);
645 static enum command_return
646 handle_deleteid(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
649 enum playlist_result result
;
651 if (!check_int(client
, &id
, argv
[1], need_positive
))
652 return COMMAND_RETURN_ERROR
;
654 result
= playlist_delete_id(&g_playlist
, id
);
655 return print_playlist_result(client
, result
);
658 static enum command_return
659 handle_playlist(struct client
*client
,
660 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
662 playlist_print_uris(client
, &g_playlist
);
663 return COMMAND_RETURN_OK
;
666 static enum command_return
667 handle_shuffle(G_GNUC_UNUSED
struct client
*client
,
668 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
670 unsigned start
= 0, end
= queue_length(&g_playlist
.queue
);
671 if (argc
== 2 && !check_range(client
, &start
, &end
,
672 argv
[1], need_range
))
673 return COMMAND_RETURN_ERROR
;
675 playlist_shuffle(&g_playlist
, start
, end
);
676 return COMMAND_RETURN_OK
;
679 static enum command_return
680 handle_clear(G_GNUC_UNUSED
struct client
*client
,
681 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
683 playlist_clear(&g_playlist
);
684 return COMMAND_RETURN_OK
;
687 static enum command_return
688 handle_save(struct client
*client
,
689 G_GNUC_UNUSED
int argc
, char *argv
[])
691 enum playlist_result result
;
693 result
= spl_save_playlist(argv
[1], &g_playlist
);
694 return print_playlist_result(client
, result
);
697 static enum command_return
698 handle_load(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
700 enum playlist_result result
;
702 result
= playlist_load_spl(&g_playlist
, argv
[1]);
703 return print_playlist_result(client
, result
);
706 static enum command_return
707 handle_listplaylist(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
711 ret
= spl_print(client
, argv
[1], false);
713 command_error(client
, ACK_ERROR_NO_EXIST
, "No such playlist");
714 return COMMAND_RETURN_ERROR
;
717 return COMMAND_RETURN_OK
;
720 static enum command_return
721 handle_listplaylistinfo(struct client
*client
,
722 G_GNUC_UNUSED
int argc
, char *argv
[])
726 ret
= spl_print(client
, argv
[1], true);
728 command_error(client
, ACK_ERROR_NO_EXIST
, "No such playlist");
729 return COMMAND_RETURN_ERROR
;
732 return COMMAND_RETURN_OK
;
735 static enum command_return
736 handle_lsinfo(struct client
*client
, int argc
, char *argv
[])
739 const struct directory
*directory
;
744 /* default is root directory */
747 directory
= db_get_directory(uri
);
748 if (directory
== NULL
) {
749 command_error(client
, ACK_ERROR_NO_EXIST
,
750 "directory not found");
751 return COMMAND_RETURN_ERROR
;
754 directory_print(client
, directory
);
756 if (isRootDirectory(uri
)) {
757 GPtrArray
*list
= spl_list();
759 print_spl_list(client
, list
);
764 return COMMAND_RETURN_OK
;
767 static enum command_return
768 handle_rm(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
770 enum playlist_result result
;
772 result
= spl_delete(argv
[1]);
773 return print_playlist_result(client
, result
);
776 static enum command_return
777 handle_rename(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
779 enum playlist_result result
;
781 result
= spl_rename(argv
[1], argv
[2]);
782 return print_playlist_result(client
, result
);
785 static enum command_return
786 handle_plchanges(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
790 if (!check_uint32(client
, &version
, argv
[1], need_positive
))
791 return COMMAND_RETURN_ERROR
;
793 playlist_print_changes_info(client
, &g_playlist
, version
);
794 return COMMAND_RETURN_OK
;
797 static enum command_return
798 handle_plchangesposid(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
802 if (!check_uint32(client
, &version
, argv
[1], need_positive
))
803 return COMMAND_RETURN_ERROR
;
805 playlist_print_changes_position(client
, &g_playlist
, version
);
806 return COMMAND_RETURN_OK
;
809 static enum command_return
810 handle_playlistinfo(struct client
*client
, int argc
, char *argv
[])
812 unsigned start
= 0, end
= UINT_MAX
;
815 if (argc
== 2 && !check_range(client
, &start
, &end
,
816 argv
[1], need_range
))
817 return COMMAND_RETURN_ERROR
;
819 ret
= playlist_print_info(client
, &g_playlist
, start
, end
);
821 return print_playlist_result(client
,
822 PLAYLIST_RESULT_BAD_RANGE
);
824 return COMMAND_RETURN_OK
;
827 static enum command_return
828 handle_playlistid(struct client
*client
, int argc
, char *argv
[])
832 if (argc
== 2 && !check_int(client
, &id
, argv
[1], need_positive
))
833 return COMMAND_RETURN_ERROR
;
836 bool ret
= playlist_print_id(client
, &g_playlist
, id
);
838 return print_playlist_result(client
,
839 PLAYLIST_RESULT_NO_SUCH_SONG
);
841 playlist_print_info(client
, &g_playlist
, 0, UINT_MAX
);
844 return COMMAND_RETURN_OK
;
847 static enum command_return
848 handle_find(struct client
*client
, int argc
, char *argv
[])
851 struct locate_item_list
*list
=
852 locate_item_list_parse(argv
+ 1, argc
- 1);
854 if (list
== NULL
|| list
->length
== 0) {
856 locate_item_list_free(list
);
858 command_error(client
, ACK_ERROR_ARG
, "incorrect arguments");
859 return COMMAND_RETURN_ERROR
;
862 ret
= findSongsIn(client
, NULL
, list
);
864 command_error(client
, ACK_ERROR_NO_EXIST
,
865 "directory or file not found");
867 locate_item_list_free(list
);
872 static enum command_return
873 handle_findadd(struct client
*client
, int argc
, char *argv
[])
876 struct locate_item_list
*list
=
877 locate_item_list_parse(argv
+ 1, argc
- 1);
878 if (list
== NULL
|| list
->length
== 0) {
880 locate_item_list_free(list
);
882 command_error(client
, ACK_ERROR_ARG
, "incorrect arguments");
883 return COMMAND_RETURN_ERROR
;
886 ret
= findAddIn(client
, NULL
, list
);
888 command_error(client
, ACK_ERROR_NO_EXIST
,
889 "directory or file not found");
891 locate_item_list_free(list
);
896 static enum command_return
897 handle_search(struct client
*client
, int argc
, char *argv
[])
900 struct locate_item_list
*list
=
901 locate_item_list_parse(argv
+ 1, argc
- 1);
903 if (list
== NULL
|| list
->length
== 0) {
905 locate_item_list_free(list
);
907 command_error(client
, ACK_ERROR_ARG
, "incorrect arguments");
908 return COMMAND_RETURN_ERROR
;
911 ret
= searchForSongsIn(client
, NULL
, list
);
913 command_error(client
, ACK_ERROR_NO_EXIST
,
914 "directory or file not found");
916 locate_item_list_free(list
);
921 static enum command_return
922 handle_count(struct client
*client
, int argc
, char *argv
[])
925 struct locate_item_list
*list
=
926 locate_item_list_parse(argv
+ 1, argc
- 1);
928 if (list
== NULL
|| list
->length
== 0) {
930 locate_item_list_free(list
);
932 command_error(client
, ACK_ERROR_ARG
, "incorrect arguments");
933 return COMMAND_RETURN_ERROR
;
936 ret
= searchStatsForSongsIn(client
, NULL
, list
);
938 command_error(client
, ACK_ERROR_NO_EXIST
,
939 "directory or file not found");
941 locate_item_list_free(list
);
946 static enum command_return
947 handle_playlistfind(struct client
*client
, int argc
, char *argv
[])
949 struct locate_item_list
*list
=
950 locate_item_list_parse(argv
+ 1, argc
- 1);
952 if (list
== NULL
|| list
->length
== 0) {
954 locate_item_list_free(list
);
956 command_error(client
, ACK_ERROR_ARG
, "incorrect arguments");
957 return COMMAND_RETURN_ERROR
;
960 playlist_print_find(client
, &g_playlist
, list
);
962 locate_item_list_free(list
);
964 return COMMAND_RETURN_OK
;
967 static enum command_return
968 handle_playlistsearch(struct client
*client
, int argc
, char *argv
[])
970 struct locate_item_list
*list
=
971 locate_item_list_parse(argv
+ 1, argc
- 1);
973 if (list
== NULL
|| list
->length
== 0) {
975 locate_item_list_free(list
);
977 command_error(client
, ACK_ERROR_ARG
, "incorrect arguments");
978 return COMMAND_RETURN_ERROR
;
981 playlist_print_search(client
, &g_playlist
, list
);
983 locate_item_list_free(list
);
985 return COMMAND_RETURN_OK
;
988 static enum command_return
989 handle_playlistdelete(struct client
*client
,
990 G_GNUC_UNUSED
int argc
, char *argv
[]) {
991 char *playlist
= argv
[1];
993 enum playlist_result result
;
995 if (!check_int(client
, &from
, argv
[2], check_integer
, argv
[2]))
996 return COMMAND_RETURN_ERROR
;
998 result
= spl_remove_index(playlist
, from
);
999 return print_playlist_result(client
, result
);
1002 static enum command_return
1003 handle_playlistmove(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1005 char *playlist
= argv
[1];
1007 enum playlist_result result
;
1009 if (!check_int(client
, &from
, argv
[2], check_integer
, argv
[2]))
1010 return COMMAND_RETURN_ERROR
;
1011 if (!check_int(client
, &to
, argv
[3], check_integer
, argv
[3]))
1012 return COMMAND_RETURN_ERROR
;
1014 result
= spl_move_index(playlist
, from
, to
);
1015 return print_playlist_result(client
, result
);
1018 static enum command_return
1019 handle_update(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1026 path
= g_strdup(argv
[1]);
1028 ret
= directory_update_init(path
);
1030 client_printf(client
, "updating_db: %i\n", ret
);
1031 return COMMAND_RETURN_OK
;
1033 command_error(client
, ACK_ERROR_UPDATE_ALREADY
,
1034 "already updating");
1035 return COMMAND_RETURN_ERROR
;
1039 static enum command_return
1040 handle_next(G_GNUC_UNUSED
struct client
*client
,
1041 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1043 /* single mode is not considered when this is user who
1044 * wants to change song. */
1045 int single
= g_playlist
.queue
.single
;
1046 g_playlist
.queue
.single
= false;
1048 playlist_next(&g_playlist
);
1050 g_playlist
.queue
.single
= single
;
1051 return COMMAND_RETURN_OK
;
1054 static enum command_return
1055 handle_previous(G_GNUC_UNUSED
struct client
*client
,
1056 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1058 playlist_previous(&g_playlist
);
1059 return COMMAND_RETURN_OK
;
1062 static enum command_return
1063 handle_listall(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1065 char *directory
= NULL
;
1069 directory
= argv
[1];
1071 ret
= printAllIn(client
, directory
);
1073 command_error(client
, ACK_ERROR_NO_EXIST
,
1074 "directory or file not found");
1079 static enum command_return
1080 handle_setvol(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1085 if (!check_int(client
, &level
, argv
[1], need_integer
))
1086 return COMMAND_RETURN_ERROR
;
1088 if (level
< 0 || level
> 100) {
1089 command_error(client
, ACK_ERROR_ARG
, "Invalid volume value");
1090 return COMMAND_RETURN_ERROR
;
1093 success
= volume_level_change(level
);
1095 command_error(client
, ACK_ERROR_SYSTEM
,
1096 "problems setting volume");
1097 return COMMAND_RETURN_ERROR
;
1100 return COMMAND_RETURN_OK
;
1103 static enum command_return
1104 handle_repeat(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1108 if (!check_int(client
, &status
, argv
[1], need_integer
))
1109 return COMMAND_RETURN_ERROR
;
1111 if (status
!= 0 && status
!= 1) {
1112 command_error(client
, ACK_ERROR_ARG
,
1113 "\"%i\" is not 0 or 1", status
);
1114 return COMMAND_RETURN_ERROR
;
1117 playlist_set_repeat(&g_playlist
, status
);
1118 return COMMAND_RETURN_OK
;
1121 static enum command_return
1122 handle_single(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1126 if (!check_int(client
, &status
, argv
[1], need_integer
))
1127 return COMMAND_RETURN_ERROR
;
1129 if (status
!= 0 && status
!= 1) {
1130 command_error(client
, ACK_ERROR_ARG
,
1131 "\"%i\" is not 0 or 1", status
);
1132 return COMMAND_RETURN_ERROR
;
1135 playlist_set_single(&g_playlist
, status
);
1136 return COMMAND_RETURN_OK
;
1139 static enum command_return
1140 handle_consume(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1144 if (!check_int(client
, &status
, argv
[1], need_integer
))
1145 return COMMAND_RETURN_ERROR
;
1147 if (status
!= 0 && status
!= 1) {
1148 command_error(client
, ACK_ERROR_ARG
,
1149 "\"%i\" is not 0 or 1", status
);
1150 return COMMAND_RETURN_ERROR
;
1153 playlist_set_consume(&g_playlist
, status
);
1154 return COMMAND_RETURN_OK
;
1157 static enum command_return
1158 handle_random(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1162 if (!check_int(client
, &status
, argv
[1], need_integer
))
1163 return COMMAND_RETURN_ERROR
;
1165 if (status
!= 0 && status
!= 1) {
1166 command_error(client
, ACK_ERROR_ARG
,
1167 "\"%i\" is not 0 or 1", status
);
1168 return COMMAND_RETURN_ERROR
;
1171 playlist_set_random(&g_playlist
, status
);
1172 return COMMAND_RETURN_OK
;
1175 static enum command_return
1176 handle_stats(struct client
*client
,
1177 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1179 return stats_print(client
);
1182 static enum command_return
1183 handle_clearerror(G_GNUC_UNUSED
struct client
*client
,
1184 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1187 return COMMAND_RETURN_OK
;
1190 static enum command_return
1191 handle_list(struct client
*client
, int argc
, char *argv
[])
1193 struct locate_item_list
*conditionals
;
1194 int tagType
= locate_parse_type(argv
[1]);
1198 command_error(client
, ACK_ERROR_ARG
, "\"%s\" is not known", argv
[1]);
1199 return COMMAND_RETURN_ERROR
;
1202 if (tagType
== LOCATE_TAG_ANY_TYPE
) {
1203 command_error(client
, ACK_ERROR_ARG
,
1204 "\"any\" is not a valid return tag type");
1205 return COMMAND_RETURN_ERROR
;
1208 /* for compatibility with < 0.12.0 */
1210 if (tagType
!= TAG_ITEM_ALBUM
) {
1211 command_error(client
, ACK_ERROR_ARG
,
1212 "should be \"%s\" for 3 arguments",
1213 tag_item_names
[TAG_ITEM_ALBUM
]);
1214 return COMMAND_RETURN_ERROR
;
1217 locate_item_list_parse(argv
+ 1, argc
- 1);
1219 conditionals
= locate_item_list_new(1);
1220 conditionals
->items
[0].tag
= TAG_ITEM_ARTIST
;
1221 conditionals
->items
[0].needle
= g_strdup(argv
[2]);
1224 locate_item_list_parse(argv
+ 2, argc
- 2);
1225 if (conditionals
== NULL
) {
1226 command_error(client
, ACK_ERROR_ARG
,
1227 "not able to parse args");
1228 return COMMAND_RETURN_ERROR
;
1232 ret
= listAllUniqueTags(client
, tagType
, conditionals
);
1234 locate_item_list_free(conditionals
);
1237 command_error(client
, ACK_ERROR_NO_EXIST
,
1238 "directory or file not found");
1243 static enum command_return
1244 handle_move(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1246 unsigned start
, end
;
1248 enum playlist_result result
;
1250 if (!check_range(client
, &start
, &end
,
1251 argv
[1], need_range
))
1252 return COMMAND_RETURN_ERROR
;
1253 if (!check_int(client
, &to
, argv
[2], check_integer
, argv
[2]))
1254 return COMMAND_RETURN_ERROR
;
1255 result
= playlist_move_range(&g_playlist
, start
, end
, to
);
1256 return print_playlist_result(client
, result
);
1259 static enum command_return
1260 handle_moveid(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1263 enum playlist_result result
;
1265 if (!check_int(client
, &id
, argv
[1], check_integer
, argv
[1]))
1266 return COMMAND_RETURN_ERROR
;
1267 if (!check_int(client
, &to
, argv
[2], check_integer
, argv
[2]))
1268 return COMMAND_RETURN_ERROR
;
1269 result
= playlist_move_id(&g_playlist
, id
, to
);
1270 return print_playlist_result(client
, result
);
1273 static enum command_return
1274 handle_swap(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1277 enum playlist_result result
;
1279 if (!check_int(client
, &song1
, argv
[1], check_integer
, argv
[1]))
1280 return COMMAND_RETURN_ERROR
;
1281 if (!check_int(client
, &song2
, argv
[2], check_integer
, argv
[2]))
1282 return COMMAND_RETURN_ERROR
;
1283 result
= playlist_swap_songs(&g_playlist
, song1
, song2
);
1284 return print_playlist_result(client
, result
);
1287 static enum command_return
1288 handle_swapid(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1291 enum playlist_result result
;
1293 if (!check_int(client
, &id1
, argv
[1], check_integer
, argv
[1]))
1294 return COMMAND_RETURN_ERROR
;
1295 if (!check_int(client
, &id2
, argv
[2], check_integer
, argv
[2]))
1296 return COMMAND_RETURN_ERROR
;
1297 result
= playlist_swap_songs_id(&g_playlist
, id1
, id2
);
1298 return print_playlist_result(client
, result
);
1301 static enum command_return
1302 handle_seek(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1304 int song
, seek_time
;
1305 enum playlist_result result
;
1307 if (!check_int(client
, &song
, argv
[1], check_integer
, argv
[1]))
1308 return COMMAND_RETURN_ERROR
;
1309 if (!check_int(client
, &seek_time
, argv
[2], check_integer
, argv
[2]))
1310 return COMMAND_RETURN_ERROR
;
1312 result
= playlist_seek_song(&g_playlist
, song
, seek_time
);
1313 return print_playlist_result(client
, result
);
1316 static enum command_return
1317 handle_seekid(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1320 enum playlist_result result
;
1322 if (!check_int(client
, &id
, argv
[1], check_integer
, argv
[1]))
1323 return COMMAND_RETURN_ERROR
;
1324 if (!check_int(client
, &seek_time
, argv
[2], check_integer
, argv
[2]))
1325 return COMMAND_RETURN_ERROR
;
1327 result
= playlist_seek_song_id(&g_playlist
, id
, seek_time
);
1328 return print_playlist_result(client
, result
);
1331 static enum command_return
1332 handle_listallinfo(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1334 char *directory
= NULL
;
1338 directory
= argv
[1];
1340 ret
= printInfoForAllIn(client
, directory
);
1342 command_error(client
, ACK_ERROR_NO_EXIST
,
1343 "directory or file not found");
1348 static enum command_return
1349 handle_ping(G_GNUC_UNUSED
struct client
*client
,
1350 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1352 return COMMAND_RETURN_OK
;
1355 static enum command_return
1356 handle_password(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1358 unsigned permission
= 0;
1360 if (getPermissionFromPassword(argv
[1], &permission
) < 0) {
1361 command_error(client
, ACK_ERROR_PASSWORD
, "incorrect password");
1362 return COMMAND_RETURN_ERROR
;
1365 client_set_permission(client
, permission
);
1367 return COMMAND_RETURN_OK
;
1370 static enum command_return
1371 handle_crossfade(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1373 unsigned xfade_time
;
1375 if (!check_unsigned(client
, &xfade_time
, argv
[1]))
1376 return COMMAND_RETURN_ERROR
;
1377 setPlayerCrossFade(xfade_time
);
1379 return COMMAND_RETURN_OK
;
1382 static enum command_return
1383 handle_enableoutput(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1388 if (!check_unsigned(client
, &device
, argv
[1]))
1389 return COMMAND_RETURN_ERROR
;
1391 ret
= audio_output_enable_index(device
);
1393 command_error(client
, ACK_ERROR_NO_EXIST
,
1394 "No such audio output");
1395 return COMMAND_RETURN_ERROR
;
1398 return COMMAND_RETURN_OK
;
1401 static enum command_return
1402 handle_disableoutput(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1407 if (!check_unsigned(client
, &device
, argv
[1]))
1408 return COMMAND_RETURN_ERROR
;
1410 ret
= audio_output_disable_index(device
);
1412 command_error(client
, ACK_ERROR_NO_EXIST
,
1413 "No such audio output");
1414 return COMMAND_RETURN_ERROR
;
1417 return COMMAND_RETURN_OK
;
1420 static enum command_return
1421 handle_devices(struct client
*client
,
1422 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1424 printAudioDevices(client
);
1426 return COMMAND_RETURN_OK
;
1429 /* don't be fooled, this is the command handler for "commands" command */
1430 static enum command_return
1431 handle_commands(struct client
*client
,
1432 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[]);
1434 static enum command_return
1435 handle_not_commands(struct client
*client
,
1436 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[]);
1438 static enum command_return
1439 handle_playlistclear(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1441 enum playlist_result result
;
1443 result
= spl_clear(argv
[1]);
1444 return print_playlist_result(client
, result
);
1447 static enum command_return
1448 handle_playlistadd(struct client
*client
, G_GNUC_UNUSED
int argc
, char *argv
[])
1450 char *playlist
= argv
[1];
1451 char *uri
= argv
[2];
1452 enum playlist_result result
;
1454 if (uri_has_scheme(uri
)) {
1455 if (!uri_supported_scheme(uri
)) {
1456 command_error(client
, ACK_ERROR_NO_EXIST
,
1457 "unsupported URI scheme");
1458 return COMMAND_RETURN_ERROR
;
1461 result
= spl_append_uri(uri
, playlist
);
1463 result
= addAllInToStoredPlaylist(uri
, playlist
);
1465 if (result
== (enum playlist_result
)-1) {
1466 command_error(client
, ACK_ERROR_NO_EXIST
,
1467 "directory or file not found");
1468 return COMMAND_RETURN_ERROR
;
1471 return print_playlist_result(client
, result
);
1474 static enum command_return
1475 handle_listplaylists(struct client
*client
,
1476 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1478 GPtrArray
*list
= spl_list();
1480 command_error(client
, ACK_ERROR_SYSTEM
,
1481 "failed to get list of stored playlists");
1482 return COMMAND_RETURN_ERROR
;
1485 print_spl_list(client
, list
);
1486 spl_list_free(list
);
1487 return COMMAND_RETURN_OK
;
1490 static enum command_return
1491 handle_idle(struct client
*client
,
1492 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1494 unsigned flags
= 0, j
;
1496 const char *const* idle_names
;
1498 idle_names
= idle_get_names();
1499 for (i
= 1; i
< argc
; ++i
) {
1503 for (j
= 0; idle_names
[j
]; ++j
) {
1504 if (!g_ascii_strcasecmp(argv
[i
], idle_names
[j
])) {
1510 /* No argument means that the client wants to receive everything */
1514 /* enable "idle" mode on this client */
1515 client_idle_wait(client
, flags
);
1517 /* return value is "1" so the caller won't print "OK" */
1521 #ifdef ENABLE_SQLITE
1522 struct sticker_song_find_data
{
1523 struct client
*client
;
1528 sticker_song_find_print_cb(struct song
*song
, const char *value
,
1531 struct sticker_song_find_data
*data
= user_data
;
1533 song_print_url(data
->client
, song
);
1534 sticker_print_value(data
->client
, data
->name
, value
);
1537 static enum command_return
1538 handle_sticker_song(struct client
*client
, int argc
, char *argv
[])
1540 if (argc
== 5 && strcmp(argv
[1], "get") == 0) {
1544 song
= db_get_song(argv
[3]);
1546 command_error(client
, ACK_ERROR_NO_EXIST
,
1548 return COMMAND_RETURN_ERROR
;
1551 value
= sticker_song_get_value(song
, argv
[4]);
1552 if (value
== NULL
) {
1553 command_error(client
, ACK_ERROR_NO_EXIST
,
1555 return COMMAND_RETURN_ERROR
;
1558 sticker_print_value(client
, argv
[4], value
);
1561 return COMMAND_RETURN_OK
;
1562 } else if (argc
== 4 && strcmp(argv
[1], "list") == 0) {
1564 struct sticker
*sticker
;
1566 song
= db_get_song(argv
[3]);
1568 command_error(client
, ACK_ERROR_NO_EXIST
,
1570 return COMMAND_RETURN_ERROR
;
1573 sticker
= sticker_song_get(song
);
1574 if (NULL
== sticker
) {
1575 command_error(client
, ACK_ERROR_NO_EXIST
,
1576 "no stickers found");
1577 return COMMAND_RETURN_ERROR
;
1580 sticker_print(client
, sticker
);
1581 sticker_free(sticker
);
1583 return COMMAND_RETURN_OK
;
1584 } else if (argc
== 6 && strcmp(argv
[1], "set") == 0) {
1588 song
= db_get_song(argv
[3]);
1590 command_error(client
, ACK_ERROR_NO_EXIST
,
1592 return COMMAND_RETURN_ERROR
;
1595 ret
= sticker_song_set_value(song
, argv
[4], argv
[5]);
1597 command_error(client
, ACK_ERROR_SYSTEM
,
1598 "failed to set sticker value");
1599 return COMMAND_RETURN_ERROR
;
1602 return COMMAND_RETURN_OK
;
1603 } else if ((argc
== 4 || argc
== 5) &&
1604 strcmp(argv
[1], "delete") == 0) {
1608 song
= db_get_song(argv
[3]);
1610 command_error(client
, ACK_ERROR_NO_EXIST
,
1612 return COMMAND_RETURN_ERROR
;
1616 ? sticker_song_delete(song
)
1617 : sticker_song_delete_value(song
, argv
[4]);
1619 command_error(client
, ACK_ERROR_SYSTEM
,
1621 return COMMAND_RETURN_ERROR
;
1624 return COMMAND_RETURN_OK
;
1625 } else if (argc
== 5 && strcmp(argv
[1], "find") == 0) {
1626 /* "sticker find song a/directory name" */
1627 struct directory
*directory
;
1629 struct sticker_song_find_data data
= {
1634 directory
= db_get_directory(argv
[3]);
1635 if (directory
== NULL
) {
1636 command_error(client
, ACK_ERROR_NO_EXIST
,
1637 "no such directory");
1638 return COMMAND_RETURN_ERROR
;
1641 success
= sticker_song_find(directory
, data
.name
,
1642 sticker_song_find_print_cb
, &data
);
1644 command_error(client
, ACK_ERROR_SYSTEM
,
1645 "failed to set search sticker database");
1646 return COMMAND_RETURN_ERROR
;
1649 return COMMAND_RETURN_OK
;
1651 command_error(client
, ACK_ERROR_ARG
, "bad request");
1652 return COMMAND_RETURN_ERROR
;
1656 static enum command_return
1657 handle_sticker(struct client
*client
, int argc
, char *argv
[])
1661 if (!sticker_enabled()) {
1662 command_error(client
, ACK_ERROR_UNKNOWN
,
1663 "sticker database is disabled");
1664 return COMMAND_RETURN_ERROR
;
1667 if (strcmp(argv
[2], "song") == 0)
1668 return handle_sticker_song(client
, argc
, argv
);
1670 command_error(client
, ACK_ERROR_ARG
,
1671 "unknown sticker domain");
1672 return COMMAND_RETURN_ERROR
;
1678 * The command registry.
1680 * This array must be sorted!
1682 static const struct command commands
[] = {
1683 { "add", PERMISSION_ADD
, 1, 1, handle_add
},
1684 { "addid", PERMISSION_ADD
, 1, 2, handle_addid
},
1685 { "clear", PERMISSION_CONTROL
, 0, 0, handle_clear
},
1686 { "clearerror", PERMISSION_CONTROL
, 0, 0, handle_clearerror
},
1687 { "close", PERMISSION_NONE
, -1, -1, handle_close
},
1688 { "commands", PERMISSION_NONE
, 0, 0, handle_commands
},
1689 { "consume", PERMISSION_CONTROL
, 1, 1, handle_consume
},
1690 { "count", PERMISSION_READ
, 2, -1, handle_count
},
1691 { "crossfade", PERMISSION_CONTROL
, 1, 1, handle_crossfade
},
1692 { "currentsong", PERMISSION_READ
, 0, 0, handle_currentsong
},
1693 { "delete", PERMISSION_CONTROL
, 1, 1, handle_delete
},
1694 { "deleteid", PERMISSION_CONTROL
, 1, 1, handle_deleteid
},
1695 { "disableoutput", PERMISSION_ADMIN
, 1, 1, handle_disableoutput
},
1696 { "enableoutput", PERMISSION_ADMIN
, 1, 1, handle_enableoutput
},
1697 { "find", PERMISSION_READ
, 2, -1, handle_find
},
1698 { "findadd", PERMISSION_READ
, 2, -1, handle_findadd
},
1699 { "idle", PERMISSION_READ
, 0, -1, handle_idle
},
1700 { "kill", PERMISSION_ADMIN
, -1, -1, handle_kill
},
1701 { "list", PERMISSION_READ
, 1, -1, handle_list
},
1702 { "listall", PERMISSION_READ
, 0, 1, handle_listall
},
1703 { "listallinfo", PERMISSION_READ
, 0, 1, handle_listallinfo
},
1704 { "listplaylist", PERMISSION_READ
, 1, 1, handle_listplaylist
},
1705 { "listplaylistinfo", PERMISSION_READ
, 1, 1, handle_listplaylistinfo
},
1706 { "listplaylists", PERMISSION_READ
, 0, 0, handle_listplaylists
},
1707 { "load", PERMISSION_ADD
, 1, 1, handle_load
},
1708 { "lsinfo", PERMISSION_READ
, 0, 1, handle_lsinfo
},
1709 { "move", PERMISSION_CONTROL
, 2, 2, handle_move
},
1710 { "moveid", PERMISSION_CONTROL
, 2, 2, handle_moveid
},
1711 { "next", PERMISSION_CONTROL
, 0, 0, handle_next
},
1712 { "notcommands", PERMISSION_NONE
, 0, 0, handle_not_commands
},
1713 { "outputs", PERMISSION_READ
, 0, 0, handle_devices
},
1714 { "password", PERMISSION_NONE
, 1, 1, handle_password
},
1715 { "pause", PERMISSION_CONTROL
, 0, 1, handle_pause
},
1716 { "ping", PERMISSION_NONE
, 0, 0, handle_ping
},
1717 { "play", PERMISSION_CONTROL
, 0, 1, handle_play
},
1718 { "playid", PERMISSION_CONTROL
, 0, 1, handle_playid
},
1719 { "playlist", PERMISSION_READ
, 0, 0, handle_playlist
},
1720 { "playlistadd", PERMISSION_CONTROL
, 2, 2, handle_playlistadd
},
1721 { "playlistclear", PERMISSION_CONTROL
, 1, 1, handle_playlistclear
},
1722 { "playlistdelete", PERMISSION_CONTROL
, 2, 2, handle_playlistdelete
},
1723 { "playlistfind", PERMISSION_READ
, 2, -1, handle_playlistfind
},
1724 { "playlistid", PERMISSION_READ
, 0, 1, handle_playlistid
},
1725 { "playlistinfo", PERMISSION_READ
, 0, 1, handle_playlistinfo
},
1726 { "playlistmove", PERMISSION_CONTROL
, 3, 3, handle_playlistmove
},
1727 { "playlistsearch", PERMISSION_READ
, 2, -1, handle_playlistsearch
},
1728 { "plchanges", PERMISSION_READ
, 1, 1, handle_plchanges
},
1729 { "plchangesposid", PERMISSION_READ
, 1, 1, handle_plchangesposid
},
1730 { "previous", PERMISSION_CONTROL
, 0, 0, handle_previous
},
1731 { "random", PERMISSION_CONTROL
, 1, 1, handle_random
},
1732 { "rename", PERMISSION_CONTROL
, 2, 2, handle_rename
},
1733 { "repeat", PERMISSION_CONTROL
, 1, 1, handle_repeat
},
1734 { "rm", PERMISSION_CONTROL
, 1, 1, handle_rm
},
1735 { "save", PERMISSION_CONTROL
, 1, 1, handle_save
},
1736 { "search", PERMISSION_READ
, 2, -1, handle_search
},
1737 { "seek", PERMISSION_CONTROL
, 2, 2, handle_seek
},
1738 { "seekid", PERMISSION_CONTROL
, 2, 2, handle_seekid
},
1739 { "setvol", PERMISSION_CONTROL
, 1, 1, handle_setvol
},
1740 { "shuffle", PERMISSION_CONTROL
, 0, 1, handle_shuffle
},
1741 { "single", PERMISSION_CONTROL
, 1, 1, handle_single
},
1742 { "stats", PERMISSION_READ
, 0, 0, handle_stats
},
1743 { "status", PERMISSION_READ
, 0, 0, handle_status
},
1744 #ifdef ENABLE_SQLITE
1745 { "sticker", PERMISSION_ADMIN
, 3, -1, handle_sticker
},
1747 { "stop", PERMISSION_CONTROL
, 0, 0, handle_stop
},
1748 { "swap", PERMISSION_CONTROL
, 2, 2, handle_swap
},
1749 { "swapid", PERMISSION_CONTROL
, 2, 2, handle_swapid
},
1750 { "tagtypes", PERMISSION_READ
, 0, 0, handle_tagtypes
},
1751 { "update", PERMISSION_ADMIN
, 0, 1, handle_update
},
1752 { "urlhandlers", PERMISSION_READ
, 0, 0, handle_urlhandlers
},
1755 static const unsigned num_commands
= sizeof(commands
) / sizeof(commands
[0]);
1758 command_available(G_GNUC_UNUSED
const struct command
*cmd
)
1760 #ifdef ENABLE_SQLITE
1761 if (strcmp(cmd
->cmd
, "sticker") == 0)
1762 return sticker_enabled();
1768 /* don't be fooled, this is the command handler for "commands" command */
1769 static enum command_return
1770 handle_commands(struct client
*client
,
1771 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1773 const unsigned permission
= client_get_permission(client
);
1774 const struct command
*cmd
;
1776 for (unsigned i
= 0; i
< num_commands
; ++i
) {
1779 if (cmd
->permission
== (permission
& cmd
->permission
) &&
1780 command_available(cmd
))
1781 client_printf(client
, "command: %s\n", cmd
->cmd
);
1784 return COMMAND_RETURN_OK
;
1787 static enum command_return
1788 handle_not_commands(struct client
*client
,
1789 G_GNUC_UNUSED
int argc
, G_GNUC_UNUSED
char *argv
[])
1791 const unsigned permission
= client_get_permission(client
);
1792 const struct command
*cmd
;
1794 for (unsigned i
= 0; i
< num_commands
; ++i
) {
1797 if (cmd
->permission
!= (permission
& cmd
->permission
))
1798 client_printf(client
, "command: %s\n", cmd
->cmd
);
1801 return COMMAND_RETURN_OK
;
1804 void command_init(void)
1807 /* ensure that the command list is sorted */
1808 for (unsigned i
= 0; i
< num_commands
- 1; ++i
)
1809 assert(strcmp(commands
[i
].cmd
, commands
[i
+ 1].cmd
) < 0);
1813 void command_finish(void)
1817 static const struct command
*
1818 command_lookup(const char *name
)
1820 unsigned a
= 0, b
= num_commands
, i
;
1827 cmp
= strcmp(name
, commands
[i
].cmd
);
1829 return &commands
[i
];
1840 command_check_request(const struct command
*cmd
, struct client
*client
,
1841 unsigned permission
, int argc
, char *argv
[])
1843 int min
= cmd
->min
+ 1;
1844 int max
= cmd
->max
+ 1;
1846 if (cmd
->permission
!= (permission
& cmd
->permission
)) {
1848 command_error(client
, ACK_ERROR_PERMISSION
,
1849 "you don't have permission for \"%s\"",
1857 if (min
== max
&& max
!= argc
) {
1859 command_error(client
, ACK_ERROR_ARG
,
1860 "wrong number of arguments for \"%s\"",
1863 } else if (argc
< min
) {
1865 command_error(client
, ACK_ERROR_ARG
,
1866 "too few arguments for \"%s\"", argv
[0]);
1868 } else if (argc
> max
&& max
/* != 0 */ ) {
1870 command_error(client
, ACK_ERROR_ARG
,
1871 "too many arguments for \"%s\"", argv
[0]);
1877 static const struct command
*
1878 command_checked_lookup(struct client
*client
, unsigned permission
,
1879 int argc
, char *argv
[])
1881 static char unknown
[] = "";
1882 const struct command
*cmd
;
1884 current_command
= unknown
;
1889 cmd
= command_lookup(argv
[0]);
1892 command_error(client
, ACK_ERROR_UNKNOWN
,
1893 "unknown command \"%s\"", argv
[0]);
1897 current_command
= cmd
->cmd
;
1899 if (!command_check_request(cmd
, client
, permission
, argc
, argv
))
1906 command_process(struct client
*client
, unsigned num
, char *line
)
1908 GError
*error
= NULL
;
1910 char *argv
[COMMAND_ARGV_MAX
] = { NULL
};
1911 const struct command
*cmd
;
1912 enum command_return ret
= COMMAND_RETURN_ERROR
;
1914 command_list_num
= num
;
1916 /* get the command name (first word on the line) */
1918 argv
[0] = tokenizer_next_word(&line
, &error
);
1919 if (argv
[0] == NULL
) {
1920 current_command
= "";
1922 command_error(client
, ACK_ERROR_UNKNOWN
,
1923 "No command given");
1925 command_error(client
, ACK_ERROR_UNKNOWN
,
1926 "%s", error
->message
);
1927 g_error_free(error
);
1929 current_command
= NULL
;
1931 return COMMAND_RETURN_ERROR
;
1936 /* now parse the arguments (quoted or unquoted) */
1938 while (argc
< (int)G_N_ELEMENTS(argv
) &&
1940 tokenizer_next_word_or_string(&line
, &error
)) != NULL
)
1943 /* some error checks; we have to set current_command because
1944 command_error() expects it to be set */
1946 current_command
= argv
[0];
1948 if (argc
>= (int)G_N_ELEMENTS(argv
)) {
1949 command_error(client
, ACK_ERROR_ARG
, "Too many arguments");
1950 current_command
= NULL
;
1951 return COMMAND_RETURN_ERROR
;
1955 command_error(client
, ACK_ERROR_ARG
,
1956 "%s", error
->message
);
1957 current_command
= NULL
;
1958 g_error_free(error
);
1959 return COMMAND_RETURN_ERROR
;
1962 /* look up and invoke the command handler */
1964 cmd
= command_checked_lookup(client
, client_get_permission(client
),
1967 ret
= cmd
->handler(client
, argc
, argv
);
1969 current_command
= NULL
;
1970 command_list_num
= 0;