1 /* the Music Player Daemon (MPD)
2 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3 * This project's homepage is: 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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "directory.h"
26 #include "myfprintf.h"
28 #include "permission.h"
29 #include "buffer2array.h"
33 #include "storedPlaylist.h"
41 #define COMMAND_PLAY "play"
42 #define COMMAND_PLAYID "playid"
43 #define COMMAND_STOP "stop"
44 #define COMMAND_PAUSE "pause"
45 #define COMMAND_STATUS "status"
46 #define COMMAND_KILL "kill"
47 #define COMMAND_CLOSE "close"
48 #define COMMAND_ADD "add"
49 #define COMMAND_ADDID "addid"
50 #define COMMAND_DELETE "delete"
51 #define COMMAND_DELETEID "deleteid"
52 #define COMMAND_PLAYLIST "playlist"
53 #define COMMAND_SHUFFLE "shuffle"
54 #define COMMAND_CLEAR "clear"
55 #define COMMAND_SAVE "save"
56 #define COMMAND_LOAD "load"
57 #define COMMAND_LISTPLAYLIST "listplaylist"
58 #define COMMAND_LISTPLAYLISTINFO "listplaylistinfo"
59 #define COMMAND_LSINFO "lsinfo"
60 #define COMMAND_RM "rm"
61 #define COMMAND_PLAYLISTINFO "playlistinfo"
62 #define COMMAND_PLAYLISTID "playlistid"
63 #define COMMAND_FIND "find"
64 #define COMMAND_SEARCH "search"
65 #define COMMAND_UPDATE "update"
66 #define COMMAND_NEXT "next"
67 #define COMMAND_PREVIOUS "previous"
68 #define COMMAND_LISTALL "listall"
69 #define COMMAND_VOLUME "volume"
70 #define COMMAND_REPEAT "repeat"
71 #define COMMAND_RANDOM "random"
72 #define COMMAND_STATS "stats"
73 #define COMMAND_CLEAR_ERROR "clearerror"
74 #define COMMAND_LIST "list"
75 #define COMMAND_MOVE "move"
76 #define COMMAND_MOVEID "moveid"
77 #define COMMAND_SWAP "swap"
78 #define COMMAND_SWAPID "swapid"
79 #define COMMAND_SEEK "seek"
80 #define COMMAND_SEEKID "seekid"
81 #define COMMAND_LISTALLINFO "listallinfo"
82 #define COMMAND_PING "ping"
83 #define COMMAND_SETVOL "setvol"
84 #define COMMAND_PASSWORD "password"
85 #define COMMAND_CROSSFADE "crossfade"
86 #define COMMAND_URL_HANDLERS "urlhandlers"
87 #define COMMAND_PLCHANGES "plchanges"
88 #define COMMAND_PLCHANGESPOSID "plchangesposid"
89 #define COMMAND_CURRENTSONG "currentsong"
90 #define COMMAND_ENABLE_DEV "enableoutput"
91 #define COMMAND_DISABLE_DEV "disableoutput"
92 #define COMMAND_DEVICES "outputs"
93 #define COMMAND_COMMANDS "commands"
94 #define COMMAND_NOTCOMMANDS "notcommands"
95 #define COMMAND_PLAYLISTCLEAR "playlistclear"
96 #define COMMAND_PLAYLISTADD "playlistadd"
97 #define COMMAND_PLAYLISTFIND "playlistfind"
98 #define COMMAND_PLAYLISTSEARCH "playlistsearch"
99 #define COMMAND_PLAYLISTMOVE "playlistmove"
100 #define COMMAND_PLAYLISTDELETE "playlistdelete"
101 #define COMMAND_QUEUEID "queueid"
102 #define COMMAND_DEQUEUE "dequeue"
103 #define COMMAND_QUEUEINFO "queueinfo"
104 #define COMMAND_TAGTYPES "tagtypes"
105 #define COMMAND_COUNT "count"
106 #define COMMAND_RENAME "rename"
108 #define COMMAND_STATUS_VOLUME "volume"
109 #define COMMAND_STATUS_STATE "state"
110 #define COMMAND_STATUS_REPEAT "repeat"
111 #define COMMAND_STATUS_RANDOM "random"
112 #define COMMAND_STATUS_PLAYLIST "playlist"
113 #define COMMAND_STATUS_PLAYLIST_QUEUE "playlistqueue"
114 #define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength"
115 #define COMMAND_STATUS_SONG "song"
116 #define COMMAND_STATUS_SONGID "songid"
117 #define COMMAND_STATUS_TIME "time"
118 #define COMMAND_STATUS_BITRATE "bitrate"
119 #define COMMAND_STATUS_ERROR "error"
120 #define COMMAND_STATUS_CROSSFADE "xfade"
121 #define COMMAND_STATUS_AUDIO "audio"
122 #define COMMAND_STATUS_UPDATING_DB "updating_db"
125 * The most we ever use is for search/find, and that limits it to the
126 * number of tags we can have. Add one for the command, and one extra
127 * to catch errors clients may send us
129 #define COMMAND_ARGV_MAX (2+(TAG_NUM_OF_ITEM_TYPES*2))
131 typedef struct _CommandEntry CommandEntry
;
133 typedef int (*CommandHandlerFunction
) (int, int *, int, char **);
134 typedef int (*CommandListHandlerFunction
)
135 (int, int *, int, char **, struct strnode
*, CommandEntry
*);
137 /* if min: -1 don't check args *
138 * if max: -1 no max args */
139 struct _CommandEntry
{
144 CommandHandlerFunction handler
;
145 CommandListHandlerFunction listHandler
;
148 static char *current_command
;
149 static int command_listNum
;
151 static CommandEntry
*getCommandEntryFromString(char *string
, int *permission
);
153 static List
*commandList
;
155 static CommandEntry
*newCommandEntry(void)
157 CommandEntry
*cmd
= xmalloc(sizeof(CommandEntry
));
162 cmd
->listHandler
= NULL
;
163 cmd
->reqPermission
= 0;
167 static void addCommand(char *name
,
171 CommandHandlerFunction handler_func
,
172 CommandListHandlerFunction listHandler_func
)
174 CommandEntry
*cmd
= newCommandEntry();
178 cmd
->handler
= handler_func
;
179 cmd
->listHandler
= listHandler_func
;
180 cmd
->reqPermission
= reqPermission
;
182 insertInList(commandList
, cmd
->cmd
, cmd
);
185 static int handleUrlHandlers(int fd
, int *permission
, int argc
, char *argv
[])
187 return printRemoteUrlHandlers(fd
);
190 static int handleTagTypes(int fd
, int *permission
, int argc
, char *argv
[])
196 static int handlePlay(int fd
, int *permission
, int argc
, char *argv
[])
202 song
= strtol(argv
[1], &test
, 10);
204 commandError(fd
, ACK_ERROR_ARG
,
205 "need a positive integer");
209 return playPlaylist(fd
, song
, 0);
212 static int handlePlayId(int fd
, int *permission
, int argc
, char *argv
[])
218 id
= strtol(argv
[1], &test
, 10);
220 commandError(fd
, ACK_ERROR_ARG
,
221 "need a positive integer");
225 return playPlaylistById(fd
, id
, 0);
228 static int handleStop(int fd
, int *permission
, int argc
, char *argv
[])
230 return stopPlaylist(fd
);
233 static int handleCurrentSong(int fd
, int *permission
, int argc
, char *argv
[])
235 int song
= getPlaylistCurrentSong();
238 return playlistInfo(fd
, song
);
243 static int handlePause(int fd
, int *permission
, int argc
, char *argv
[])
247 int pause
= strtol(argv
[1], &test
, 10);
248 if (*test
!= '\0' || (pause
!= 0 && pause
!= 1)) {
249 commandError(fd
, ACK_ERROR_ARG
, "\"%s\" is not 0 or 1",
253 return playerSetPause(fd
, pause
);
255 return playerPause(fd
);
258 static int commandStatus(int fd
, int *permission
, int argc
, char *argv
[])
264 /*syncPlayerAndPlaylist(); */
265 playPlaylistIfPlayerStopped();
266 switch (getPlayerState()) {
267 case PLAYER_STATE_STOP
:
268 state
= COMMAND_STOP
;
270 case PLAYER_STATE_PAUSE
:
271 state
= COMMAND_PAUSE
;
273 case PLAYER_STATE_PLAY
:
274 state
= COMMAND_PLAY
;
278 fdprintf(fd
, "%s: %i\n", COMMAND_STATUS_VOLUME
, getVolumeLevel());
279 fdprintf(fd
, "%s: %i\n", COMMAND_STATUS_REPEAT
,
280 getPlaylistRepeatStatus());
281 fdprintf(fd
, "%s: %i\n", COMMAND_STATUS_RANDOM
,
282 getPlaylistRandomStatus());
283 fdprintf(fd
, "%s: %li\n", COMMAND_STATUS_PLAYLIST
,
284 getPlaylistVersion());
285 fdprintf(fd
, "%s: %li\n", COMMAND_STATUS_PLAYLIST_QUEUE
,
286 getPlaylistQueueVersion());
287 fdprintf(fd
, "%s: %i\n", COMMAND_STATUS_PLAYLIST_LENGTH
,
288 getPlaylistLength());
289 fdprintf(fd
, "%s: %i\n", COMMAND_STATUS_CROSSFADE
,
290 (int)(getPlayerCrossFade() + 0.5));
292 fdprintf(fd
, "%s: %s\n", COMMAND_STATUS_STATE
, state
);
294 song
= getPlaylistCurrentSong();
296 fdprintf(fd
, "%s: %i\n", COMMAND_STATUS_SONG
, song
);
297 fdprintf(fd
, "%s: %i\n", COMMAND_STATUS_SONGID
,
298 getPlaylistSongId(song
));
300 if (getPlayerState() != PLAYER_STATE_STOP
) {
301 fdprintf(fd
, "%s: %i:%i\n", COMMAND_STATUS_TIME
,
302 getPlayerElapsedTime(), getPlayerTotalTime());
303 fdprintf(fd
, "%s: %li\n", COMMAND_STATUS_BITRATE
,
305 fdprintf(fd
, "%s: %u:%i:%i\n", COMMAND_STATUS_AUDIO
,
306 getPlayerSampleRate(), getPlayerBits(),
307 getPlayerChannels());
310 if ((updateJobId
= isUpdatingDB())) {
311 fdprintf(fd
, "%s: %i\n", COMMAND_STATUS_UPDATING_DB
,
315 if (getPlayerError() != PLAYER_ERROR_NOERROR
) {
316 fdprintf(fd
, "%s: %s\n", COMMAND_STATUS_ERROR
,
317 getPlayerErrorStr());
323 static int handleKill(int fd
, int *permission
, int argc
, char *argv
[])
325 return COMMAND_RETURN_KILL
;
328 static int handleClose(int fd
, int *permission
, int argc
, char *argv
[])
330 return COMMAND_RETURN_CLOSE
;
333 static int handleAdd(int fd
, int *permission
, int argc
, char *argv
[])
335 char *path
= argv
[1];
337 if (isRemoteUrl(path
))
338 return addToPlaylist(fd
, path
, 0);
340 return addAllIn(fd
, path
);
343 static int handleAddId(int fd
, int *permission
, int argc
, char *argv
[])
345 return addToPlaylist(fd
, argv
[1], 1);
348 static int handleDelete(int fd
, int *permission
, int argc
, char *argv
[])
353 song
= strtol(argv
[1], &test
, 10);
355 commandError(fd
, ACK_ERROR_ARG
, "need a positive integer");
358 return deleteFromPlaylist(fd
, song
);
361 static int handleDeleteId(int fd
, int *permission
, int argc
, char *argv
[])
366 id
= strtol(argv
[1], &test
, 10);
368 commandError(fd
, ACK_ERROR_ARG
, "need a positive integer");
371 return deleteFromPlaylistById(fd
, id
);
374 static int handlePlaylist(int fd
, int *permission
, int argc
, char *argv
[])
376 return showPlaylist(fd
);
379 static int handleShuffle(int fd
, int *permission
, int argc
, char *argv
[])
381 return shufflePlaylist(fd
);
384 static int handleClear(int fd
, int *permission
, int argc
, char *argv
[])
386 return clearPlaylist(fd
);
389 static int handleSave(int fd
, int *permission
, int argc
, char *argv
[])
391 return savePlaylist(fd
, argv
[1]);
394 static int handleLoad(int fd
, int *permission
, int argc
, char *argv
[])
396 return loadPlaylist(fd
, argv
[1]);
399 static int handleListPlaylist(int fd
, int *permission
, int argc
, char *argv
[])
401 return PlaylistInfo(fd
, argv
[1], 0);
404 static int handleListPlaylistInfo(int fd
, int *permission
,
405 int argc
, char *argv
[])
407 return PlaylistInfo(fd
, argv
[1], 1);
410 static int handleLsInfo(int fd
, int *permission
, int argc
, char *argv
[])
417 if (printDirectoryInfo(fd
, path
) < 0)
420 if (isRootDirectory(path
))
421 return lsPlaylists(fd
, path
);
426 static int handleRm(int fd
, int *permission
, int argc
, char *argv
[])
428 return deletePlaylist(fd
, argv
[1]);
431 static int handleRename(int fd
, int *permission
, int argc
, char *argv
[])
433 return renameStoredPlaylist(fd
, argv
[1], argv
[2]);
436 static int handlePlaylistChanges(int fd
, int *permission
,
437 int argc
, char *argv
[])
439 unsigned long version
;
442 version
= strtoul(argv
[1], &test
, 10);
444 commandError(fd
, ACK_ERROR_ARG
, "need a positive integer");
447 return playlistChanges(fd
, version
);
450 static int handlePlaylistChangesPosId(int fd
, int *permission
,
451 int argc
, char *argv
[])
453 unsigned long version
;
456 version
= strtoul(argv
[1], &test
, 10);
458 commandError(fd
, ACK_ERROR_ARG
, "need a positive integer");
461 return playlistChangesPosId(fd
, version
);
464 static int handlePlaylistInfo(int fd
, int *permission
, int argc
, char *argv
[])
470 song
= strtol(argv
[1], &test
, 10);
472 commandError(fd
, ACK_ERROR_ARG
,
473 "need a positive integer");
477 return playlistInfo(fd
, song
);
480 static int handlePlaylistId(int fd
, int *permission
, int argc
, char *argv
[])
486 id
= strtol(argv
[1], &test
, 10);
488 commandError(fd
, ACK_ERROR_ARG
,
489 "need a positive integer");
493 return playlistId(fd
, id
);
496 static int handleFind(int fd
, int *permission
, int argc
, char *argv
[])
500 LocateTagItem
*items
;
501 int numItems
= newLocateTagItemArrayFromArgArray(argv
+ 1,
506 commandError(fd
, ACK_ERROR_ARG
, "incorrect arguments");
510 ret
= findSongsIn(fd
, NULL
, numItems
, items
);
512 freeLocateTagItemArray(numItems
, items
);
517 static int handleSearch(int fd
, int *permission
, int argc
, char *argv
[])
521 LocateTagItem
*items
;
522 int numItems
= newLocateTagItemArrayFromArgArray(argv
+ 1,
527 commandError(fd
, ACK_ERROR_ARG
, "incorrect arguments");
531 ret
= searchForSongsIn(fd
, NULL
, numItems
, items
);
533 freeLocateTagItemArray(numItems
, items
);
538 static int handleCount(int fd
, int *permission
, int argc
, char *argv
[])
542 LocateTagItem
*items
;
543 int numItems
= newLocateTagItemArrayFromArgArray(argv
+ 1,
548 commandError(fd
, ACK_ERROR_ARG
, "incorrect arguments");
552 ret
= searchStatsForSongsIn(fd
, NULL
, numItems
, items
);
554 freeLocateTagItemArray(numItems
, items
);
559 static int handlePlaylistFind(int fd
, int *permission
, int argc
, char *argv
[])
561 LocateTagItem
*items
;
562 int numItems
= newLocateTagItemArrayFromArgArray(argv
+ 1,
567 commandError(fd
, ACK_ERROR_ARG
, "incorrect arguments");
571 findSongsInPlaylist(fd
, numItems
, items
);
573 freeLocateTagItemArray(numItems
, items
);
578 static int handlePlaylistSearch(int fd
, int *permission
, int argc
, char *argv
[])
580 LocateTagItem
*items
;
581 int numItems
= newLocateTagItemArrayFromArgArray(argv
+ 1,
586 commandError(fd
, ACK_ERROR_ARG
, "incorrect arguments");
590 searchForSongsInPlaylist(fd
, numItems
, items
);
592 freeLocateTagItemArray(numItems
, items
);
597 static int handlePlaylistDelete(int fd
, int *permission
, int argc
, char *argv
[]) {
598 char *playlist
= argv
[1];
602 from
= strtol(argv
[2], &test
, 10);
604 commandError(fd
, ACK_ERROR_ARG
,
605 "\"%s\" is not a integer", argv
[2]);
609 return removeOneSongFromStoredPlaylistByPath(fd
, playlist
, from
);
612 static int handlePlaylistMove(int fd
, int *permission
, int argc
, char *argv
[])
614 char *playlist
= argv
[1];
618 from
= strtol(argv
[2], &test
, 10);
620 commandError(fd
, ACK_ERROR_ARG
,
621 "\"%s\" is not a integer", argv
[2]);
624 to
= strtol(argv
[3], &test
, 10);
626 commandError(fd
, ACK_ERROR_ARG
,
627 "\"%s\" is not a integer", argv
[3]);
631 return moveSongInStoredPlaylistByPath(fd
, playlist
, from
, to
);
634 static int handleQueueInfo(int fd
, int *permission
, int argc
, char *argv
[])
636 return playlistQueueInfo(fd
);
639 static int handleQueueId(int fd
, int *permission
, int argc
, char *argv
[])
641 int id
, position
= -1;
644 id
= strtol(argv
[1], &test
, 10);
646 commandError(fd
, ACK_ERROR_ARG
,
647 "\"%s\" is not a integer", argv
[1]);
651 position
= strtol(argv
[2], &test
, 10);
653 commandError(fd
, ACK_ERROR_ARG
,
654 "\"%s\" is not a integer", argv
[2]);
658 return addToPlaylistQueueById(fd
, id
, position
);
661 static int handleDequeue(int fd
, int *permission
, int argc
, char *argv
[])
666 pos
= strtol(argv
[1], &test
, 10);
668 commandError(fd
, ACK_ERROR_ARG
,
669 "\"%s\" is not a integer", argv
[1]);
672 return deleteFromPlaylistQueue(fd
, pos
);
675 static int listHandleUpdate(int fd
,
679 struct strnode
*cmdnode
, CommandEntry
* cmd
)
681 static List
*pathList
;
682 CommandEntry
*nextCmd
= NULL
;
683 struct strnode
*next
= cmdnode
->next
;
686 pathList
= makeList(NULL
, 1);
689 insertInList(pathList
, argv
[1], NULL
);
691 insertInList(pathList
, "", NULL
);
694 nextCmd
= getCommandEntryFromString(next
->data
, permission
);
696 if (cmd
!= nextCmd
) {
697 int ret
= updateInit(fd
, pathList
);
706 static int handleUpdate(int fd
, int *permission
, int argc
, char *argv
[])
710 List
*pathList
= makeList(NULL
, 1);
711 insertInList(pathList
, argv
[1], NULL
);
712 ret
= updateInit(fd
, pathList
);
716 return updateInit(fd
, NULL
);
719 static int handleNext(int fd
, int *permission
, int argc
, char *argv
[])
721 return nextSongInPlaylist(fd
);
724 static int handlePrevious(int fd
, int *permission
, int argc
, char *argv
[])
726 return previousSongInPlaylist(fd
);
729 static int handleListAll(int fd
, int *permission
, int argc
, char *argv
[])
731 char *directory
= NULL
;
735 return printAllIn(fd
, directory
);
738 static int handleVolume(int fd
, int *permission
, int argc
, char *argv
[])
743 change
= strtol(argv
[1], &test
, 10);
745 commandError(fd
, ACK_ERROR_ARG
, "need an integer");
748 return changeVolumeLevel(fd
, change
, 1);
751 static int handleSetVol(int fd
, int *permission
, int argc
, char *argv
[])
756 level
= strtol(argv
[1], &test
, 10);
758 commandError(fd
, ACK_ERROR_ARG
, "need an integer");
761 return changeVolumeLevel(fd
, level
, 0);
764 static int handleRepeat(int fd
, int *permission
, int argc
, char *argv
[])
769 status
= strtol(argv
[1], &test
, 10);
771 commandError(fd
, ACK_ERROR_ARG
, "need an integer");
774 return setPlaylistRepeatStatus(fd
, status
);
777 static int handleRandom(int fd
, int *permission
, int argc
, char *argv
[])
782 status
= strtol(argv
[1], &test
, 10);
784 commandError(fd
, ACK_ERROR_ARG
, "need an integer");
787 return setPlaylistRandomStatus(fd
, status
);
790 static int handleStats(int fd
, int *permission
, int argc
, char *argv
[])
792 return printStats(fd
);
795 static int handleClearError(int fd
, int *permission
, int argc
, char *argv
[])
801 static int handleList(int fd
, int *permission
, int argc
, char *argv
[])
803 int numConditionals
= 0;
804 LocateTagItem
*conditionals
= NULL
;
805 int tagType
= getLocateTagItemType(argv
[1]);
809 commandError(fd
, ACK_ERROR_ARG
, "\"%s\" is not known", argv
[1]);
813 if (tagType
== LOCATE_TAG_ANY_TYPE
) {
814 commandError(fd
, ACK_ERROR_ARG
,
815 "\"any\" is not a valid return tag type");
819 /* for compatibility with < 0.12.0 */
821 if (tagType
!= TAG_ITEM_ALBUM
) {
822 commandError(fd
, ACK_ERROR_ARG
,
823 "should be \"%s\" for 3 arguments",
824 mpdTagItemKeys
[TAG_ITEM_ALBUM
]);
827 conditionals
= newLocateTagItem(mpdTagItemKeys
[TAG_ITEM_ARTIST
],
832 newLocateTagItemArrayFromArgArray(argv
+ 2,
833 argc
- 2, &conditionals
);
835 if (numConditionals
< 0) {
836 commandError(fd
, ACK_ERROR_ARG
,
837 "not able to parse args");
842 ret
= listAllUniqueTags(fd
, tagType
, numConditionals
, conditionals
);
845 freeLocateTagItemArray(numConditionals
, conditionals
);
850 static int handleMove(int fd
, int *permission
, int argc
, char *argv
[])
856 from
= strtol(argv
[1], &test
, 10);
858 commandError(fd
, ACK_ERROR_ARG
,
859 "\"%s\" is not a integer", argv
[1]);
862 to
= strtol(argv
[2], &test
, 10);
864 commandError(fd
, ACK_ERROR_ARG
,
865 "\"%s\" is not a integer", argv
[2]);
868 return moveSongInPlaylist(fd
, from
, to
);
871 static int handleMoveId(int fd
, int *permission
, int argc
, char *argv
[])
877 id
= strtol(argv
[1], &test
, 10);
879 commandError(fd
, ACK_ERROR_ARG
,
880 "\"%s\" is not a integer", argv
[1]);
883 to
= strtol(argv
[2], &test
, 10);
885 commandError(fd
, ACK_ERROR_ARG
,
886 "\"%s\" is not a integer", argv
[2]);
889 return moveSongInPlaylistById(fd
, id
, to
);
892 static int handleSwap(int fd
, int *permission
, int argc
, char *argv
[])
898 song1
= strtol(argv
[1], &test
, 10);
900 commandError(fd
, ACK_ERROR_ARG
,
901 "\"%s\" is not a integer", argv
[1]);
904 song2
= strtol(argv
[2], &test
, 10);
906 commandError(fd
, ACK_ERROR_ARG
, "\"%s\" is not a integer",
910 return swapSongsInPlaylist(fd
, song1
, song2
);
913 static int handleSwapId(int fd
, int *permission
, int argc
, char *argv
[])
919 id1
= strtol(argv
[1], &test
, 10);
921 commandError(fd
, ACK_ERROR_ARG
,
922 "\"%s\" is not a integer", argv
[1]);
925 id2
= strtol(argv
[2], &test
, 10);
927 commandError(fd
, ACK_ERROR_ARG
, "\"%s\" is not a integer",
931 return swapSongsInPlaylistById(fd
, id1
, id2
);
934 static int handleSeek(int fd
, int *permission
, int argc
, char *argv
[])
940 song
= strtol(argv
[1], &test
, 10);
942 commandError(fd
, ACK_ERROR_ARG
,
943 "\"%s\" is not a integer", argv
[1]);
946 time
= strtol(argv
[2], &test
, 10);
948 commandError(fd
, ACK_ERROR_ARG
,
949 "\"%s\" is not a integer", argv
[2]);
952 return seekSongInPlaylist(fd
, song
, time
);
955 static int handleSeekId(int fd
, int *permission
, int argc
, char *argv
[])
961 id
= strtol(argv
[1], &test
, 10);
963 commandError(fd
, ACK_ERROR_ARG
,
964 "\"%s\" is not a integer", argv
[1]);
967 time
= strtol(argv
[2], &test
, 10);
969 commandError(fd
, ACK_ERROR_ARG
,
970 "\"%s\" is not a integer", argv
[2]);
973 return seekSongInPlaylistById(fd
, id
, time
);
976 static int handleListAllInfo(int fd
, int *permission
, int argc
, char *argv
[])
978 char *directory
= NULL
;
982 return printInfoForAllIn(fd
, directory
);
985 static int handlePing(int fd
, int *permission
, int argc
, char *argv
[])
990 static int handlePassword(int fd
, int *permission
, int argc
, char *argv
[])
992 if (getPermissionFromPassword(argv
[1], permission
) < 0) {
993 commandError(fd
, ACK_ERROR_PASSWORD
, "incorrect password");
1000 static int handleCrossfade(int fd
, int *permission
, int argc
, char *argv
[])
1005 time
= strtol(argv
[1], &test
, 10);
1006 if (*test
!= '\0' || time
< 0) {
1007 commandError(fd
, ACK_ERROR_ARG
,
1008 "\"%s\" is not a integer >= 0", argv
[1]);
1012 setPlayerCrossFade(time
);
1017 static int handleEnableDevice(int fd
, int *permission
, int argc
, char *argv
[])
1022 device
= strtol(argv
[1], &test
, 10);
1023 if (*test
!= '\0' || device
< 0) {
1024 commandError(fd
, ACK_ERROR_ARG
,
1025 "\"%s\" is not a integer >= 0", argv
[1]);
1029 return enableAudioDevice(fd
, device
);
1032 static int handleDisableDevice(int fd
, int *permission
, int argc
, char *argv
[])
1037 device
= strtol(argv
[1], &test
, 10);
1038 if (*test
!= '\0' || device
< 0) {
1039 commandError(fd
, ACK_ERROR_ARG
,
1040 "\"%s\" is not a integer >= 0", argv
[1]);
1044 return disableAudioDevice(fd
, device
);
1047 static int handleDevices(int fd
, int *permission
, int argc
, char *argv
[])
1049 printAudioDevices(fd
);
1054 /* don't be fooled, this is the command handler for "commands" command */
1055 static int handleCommands(int fd
, int *permission
, int argc
, char *argv
[])
1057 ListNode
*node
= commandList
->firstNode
;
1060 while (node
!= NULL
) {
1061 cmd
= (CommandEntry
*) node
->data
;
1062 if (cmd
->reqPermission
== (*permission
& cmd
->reqPermission
)) {
1063 fdprintf(fd
, "command: %s\n", cmd
->cmd
);
1066 node
= node
->nextNode
;
1072 static int handleNotcommands(int fd
, int *permission
, int argc
, char *argv
[])
1074 ListNode
*node
= commandList
->firstNode
;
1077 while (node
!= NULL
) {
1078 cmd
= (CommandEntry
*) node
->data
;
1080 if (cmd
->reqPermission
!= (*permission
& cmd
->reqPermission
)) {
1081 fdprintf(fd
, "command: %s\n", cmd
->cmd
);
1084 node
= node
->nextNode
;
1090 static int handlePlaylistClear(int fd
, int *permission
, int argc
, char *argv
[])
1092 return clearStoredPlaylist(fd
, argv
[1]);
1095 static int handlePlaylistAdd(int fd
, int *permission
, int argc
, char *argv
[])
1097 char *playlist
= argv
[1];
1098 char *path
= argv
[2];
1100 if (isRemoteUrl(path
))
1101 return addToStoredPlaylist(fd
, path
, playlist
);
1103 return addAllInToStoredPlaylist(fd
, path
, playlist
);
1106 void initCommands(void)
1108 commandList
= makeList(free
, 1);
1110 /* addCommand(name, permission, min, max, handler, list handler); */
1111 addCommand(COMMAND_PLAY
, PERMISSION_CONTROL
, 0, 1, handlePlay
, NULL
);
1112 addCommand(COMMAND_PLAYID
, PERMISSION_CONTROL
, 0, 1, handlePlayId
, NULL
);
1113 addCommand(COMMAND_STOP
, PERMISSION_CONTROL
, 0, 0, handleStop
, NULL
);
1114 addCommand(COMMAND_CURRENTSONG
, PERMISSION_READ
, 0, 0, handleCurrentSong
, NULL
);
1115 addCommand(COMMAND_PAUSE
, PERMISSION_CONTROL
, 0, 1, handlePause
, NULL
);
1116 addCommand(COMMAND_STATUS
, PERMISSION_READ
, 0, 0, commandStatus
, NULL
);
1117 addCommand(COMMAND_KILL
, PERMISSION_ADMIN
, -1, -1, handleKill
, NULL
);
1118 addCommand(COMMAND_CLOSE
, PERMISSION_NONE
, -1, -1, handleClose
, NULL
);
1119 addCommand(COMMAND_ADD
, PERMISSION_ADD
, 1, 1, handleAdd
, NULL
);
1120 addCommand(COMMAND_ADDID
, PERMISSION_ADD
, 1, 1, handleAddId
, NULL
);
1121 addCommand(COMMAND_DELETE
, PERMISSION_CONTROL
, 1, 1, handleDelete
, NULL
);
1122 addCommand(COMMAND_DELETEID
, PERMISSION_CONTROL
, 1, 1, handleDeleteId
, NULL
);
1123 addCommand(COMMAND_PLAYLIST
, PERMISSION_READ
, 0, 0, handlePlaylist
, NULL
);
1124 addCommand(COMMAND_PLAYLISTID
, PERMISSION_READ
, 0, 1, handlePlaylistId
, NULL
);
1125 addCommand(COMMAND_SHUFFLE
, PERMISSION_CONTROL
, 0, 0, handleShuffle
, NULL
);
1126 addCommand(COMMAND_CLEAR
, PERMISSION_CONTROL
, 0, 0, handleClear
, NULL
);
1127 addCommand(COMMAND_SAVE
, PERMISSION_CONTROL
, 1, 1, handleSave
, NULL
);
1128 addCommand(COMMAND_LOAD
, PERMISSION_ADD
, 1, 1, handleLoad
, NULL
);
1129 addCommand(COMMAND_LISTPLAYLIST
, PERMISSION_READ
, 1, 1, handleListPlaylist
, NULL
);
1130 addCommand(COMMAND_LISTPLAYLISTINFO
, PERMISSION_READ
, 1, 1, handleListPlaylistInfo
, NULL
);
1131 addCommand(COMMAND_LSINFO
, PERMISSION_READ
, 0, 1, handleLsInfo
, NULL
);
1132 addCommand(COMMAND_RM
, PERMISSION_CONTROL
, 1, 1, handleRm
, NULL
);
1133 addCommand(COMMAND_PLAYLISTINFO
, PERMISSION_READ
, 0, 1, handlePlaylistInfo
, NULL
);
1134 addCommand(COMMAND_FIND
, PERMISSION_READ
, 2, -1, handleFind
, NULL
);
1135 addCommand(COMMAND_SEARCH
, PERMISSION_READ
, 2, -1, handleSearch
, NULL
);
1136 addCommand(COMMAND_UPDATE
, PERMISSION_ADMIN
, 0, 1, handleUpdate
, listHandleUpdate
);
1137 addCommand(COMMAND_NEXT
, PERMISSION_CONTROL
, 0, 0, handleNext
, NULL
);
1138 addCommand(COMMAND_PREVIOUS
, PERMISSION_CONTROL
, 0, 0, handlePrevious
, NULL
);
1139 addCommand(COMMAND_LISTALL
, PERMISSION_READ
, 0, 1, handleListAll
, NULL
);
1140 addCommand(COMMAND_VOLUME
, PERMISSION_CONTROL
, 1, 1, handleVolume
, NULL
);
1141 addCommand(COMMAND_REPEAT
, PERMISSION_CONTROL
, 1, 1, handleRepeat
, NULL
);
1142 addCommand(COMMAND_RANDOM
, PERMISSION_CONTROL
, 1, 1, handleRandom
, NULL
);
1143 addCommand(COMMAND_STATS
, PERMISSION_READ
, 0, 0, handleStats
, NULL
);
1144 addCommand(COMMAND_CLEAR_ERROR
, PERMISSION_CONTROL
, 0, 0, handleClearError
, NULL
);
1145 addCommand(COMMAND_LIST
, PERMISSION_READ
, 1, -1, handleList
, NULL
);
1146 addCommand(COMMAND_MOVE
, PERMISSION_CONTROL
, 2, 2, handleMove
, NULL
);
1147 addCommand(COMMAND_MOVEID
, PERMISSION_CONTROL
, 2, 2, handleMoveId
, NULL
);
1148 addCommand(COMMAND_SWAP
, PERMISSION_CONTROL
, 2, 2, handleSwap
, NULL
);
1149 addCommand(COMMAND_SWAPID
, PERMISSION_CONTROL
, 2, 2, handleSwapId
, NULL
);
1150 addCommand(COMMAND_SEEK
, PERMISSION_CONTROL
, 2, 2, handleSeek
, NULL
);
1151 addCommand(COMMAND_SEEKID
, PERMISSION_CONTROL
, 2, 2, handleSeekId
, NULL
);
1152 addCommand(COMMAND_LISTALLINFO
, PERMISSION_READ
, 0, 1, handleListAllInfo
, NULL
);
1153 addCommand(COMMAND_PING
, PERMISSION_NONE
, 0, 0, handlePing
, NULL
);
1154 addCommand(COMMAND_SETVOL
, PERMISSION_CONTROL
, 1, 1, handleSetVol
, NULL
);
1155 addCommand(COMMAND_PASSWORD
, PERMISSION_NONE
, 1, 1, handlePassword
, NULL
);
1156 addCommand(COMMAND_CROSSFADE
, PERMISSION_CONTROL
, 1, 1, handleCrossfade
, NULL
);
1157 addCommand(COMMAND_URL_HANDLERS
, PERMISSION_READ
, 0, 0, handleUrlHandlers
, NULL
);
1158 addCommand(COMMAND_PLCHANGES
, PERMISSION_READ
, 1, 1, handlePlaylistChanges
, NULL
);
1159 addCommand(COMMAND_PLCHANGESPOSID
, PERMISSION_READ
, 1, 1, handlePlaylistChangesPosId
, NULL
);
1160 addCommand(COMMAND_ENABLE_DEV
, PERMISSION_ADMIN
, 1, 1, handleEnableDevice
, NULL
);
1161 addCommand(COMMAND_DISABLE_DEV
, PERMISSION_ADMIN
, 1, 1, handleDisableDevice
, NULL
);
1162 addCommand(COMMAND_DEVICES
, PERMISSION_READ
, 0, 0, handleDevices
, NULL
);
1163 addCommand(COMMAND_COMMANDS
, PERMISSION_NONE
, 0, 0, handleCommands
, NULL
);
1164 addCommand(COMMAND_NOTCOMMANDS
, PERMISSION_NONE
, 0, 0, handleNotcommands
, NULL
);
1165 addCommand(COMMAND_PLAYLISTCLEAR
, PERMISSION_CONTROL
, 1, 1, handlePlaylistClear
, NULL
);
1166 addCommand(COMMAND_PLAYLISTADD
, PERMISSION_CONTROL
, 2, 2, handlePlaylistAdd
, NULL
);
1167 addCommand(COMMAND_PLAYLISTFIND
, PERMISSION_READ
, 2, -1, handlePlaylistFind
, NULL
);
1168 addCommand(COMMAND_PLAYLISTSEARCH
, PERMISSION_READ
, 2, -1, handlePlaylistSearch
, NULL
);
1169 addCommand(COMMAND_PLAYLISTMOVE
, PERMISSION_CONTROL
, 3, 3, handlePlaylistMove
, NULL
);
1170 addCommand(COMMAND_PLAYLISTDELETE
, PERMISSION_CONTROL
, 2, 2, handlePlaylistDelete
, NULL
);
1171 addCommand(COMMAND_QUEUEINFO
, PERMISSION_CONTROL
, 0, 0, handleQueueInfo
, NULL
);
1172 addCommand(COMMAND_QUEUEID
, PERMISSION_CONTROL
, 1, 2, handleQueueId
, NULL
);
1173 addCommand(COMMAND_DEQUEUE
, PERMISSION_CONTROL
, 1, 1, handleDequeue
, NULL
);
1174 addCommand(COMMAND_TAGTYPES
, PERMISSION_READ
, 0, 0, handleTagTypes
, NULL
);
1175 addCommand(COMMAND_COUNT
, PERMISSION_READ
, 2, -1, handleCount
, NULL
);
1176 addCommand(COMMAND_RENAME
, PERMISSION_CONTROL
, 2, 2, handleRename
, NULL
);
1178 sortList(commandList
);
1181 void finishCommands(void)
1183 freeList(commandList
);
1186 static int checkArgcAndPermission(CommandEntry
* cmd
, int fd
,
1187 int permission
, int argc
, char *argv
[])
1189 int min
= cmd
->min
+ 1;
1190 int max
= cmd
->max
+ 1;
1192 if (cmd
->reqPermission
!= (permission
& cmd
->reqPermission
)) {
1194 commandError(fd
, ACK_ERROR_PERMISSION
,
1195 "you don't have permission for \"%s\"",
1204 if (min
== max
&& max
!= argc
) {
1206 commandError(fd
, ACK_ERROR_ARG
,
1207 "wrong number of arguments for \"%s\"",
1211 } else if (argc
< min
) {
1213 commandError(fd
, ACK_ERROR_ARG
,
1214 "too few arguments for \"%s\"", argv
[0]);
1217 } else if (argc
> max
&& max
/* != 0 */ ) {
1219 commandError(fd
, ACK_ERROR_ARG
,
1220 "too many arguments for \"%s\"", argv
[0]);
1227 static CommandEntry
*getCommandEntryAndCheckArgcAndPermission(int fd
,
1232 static char unknown
[] = "";
1235 current_command
= unknown
;
1240 if (!findInList(commandList
, argv
[0], (void *)&cmd
)) {
1242 commandError(fd
, ACK_ERROR_UNKNOWN
,
1243 "unknown command \"%s\"", argv
[0]);
1248 current_command
= cmd
->cmd
;
1250 if (checkArgcAndPermission(cmd
, fd
, *permission
, argc
, argv
) < 0) {
1257 static CommandEntry
*getCommandEntryFromString(char *string
, int *permission
)
1259 CommandEntry
*cmd
= NULL
;
1260 char *argv
[COMMAND_ARGV_MAX
] = { NULL
};
1261 int argc
= buffer2array(string
, argv
, COMMAND_ARGV_MAX
);
1266 cmd
= getCommandEntryAndCheckArgcAndPermission(0, permission
,
1272 static int processCommandInternal(int fd
, int *permission
,
1273 char *commandString
, struct strnode
*cmdnode
)
1276 char *argv
[COMMAND_ARGV_MAX
] = { NULL
};
1280 argc
= buffer2array(commandString
, argv
, COMMAND_ARGV_MAX
);
1285 if ((cmd
= getCommandEntryAndCheckArgcAndPermission(fd
, permission
,
1287 if (!cmdnode
|| !cmd
->listHandler
) {
1288 ret
= cmd
->handler(fd
, permission
, argc
, argv
);
1290 ret
= cmd
->listHandler(fd
, permission
, argc
, argv
,
1295 current_command
= NULL
;
1300 int processListOfCommands(int fd
, int *permission
, int *expired
,
1301 int listOK
, struct strnode
*list
)
1303 struct strnode
*cur
= list
;
1306 command_listNum
= 0;
1309 DEBUG("processListOfCommands: process command \"%s\"\n",
1311 ret
= processCommandInternal(fd
, permission
, cur
->data
, cur
);
1312 DEBUG("processListOfCommands: command returned %i\n", ret
);
1313 if (ret
!= 0 || (*expired
) != 0)
1316 fdprintf(fd
, "list_OK\n");
1321 command_listNum
= 0;
1325 int processCommand(int fd
, int *permission
, char *commandString
)
1327 return processCommandInternal(fd
, permission
, commandString
, NULL
);
1330 mpd_fprintf_
void commandError(int fd
, int error
, const char *fmt
, ...)
1333 va_start(args
, fmt
);
1335 if (current_command
&& fd
!= STDERR_FILENO
) {
1336 fdprintf(fd
, "ACK [%i@%i] {%s} ",
1337 (int)error
, command_listNum
, current_command
);
1338 vfdprintf(fd
, fmt
, args
);
1340 current_command
= NULL
;
1342 fdprintf(STDERR_FILENO
, "ACK [%i@%i] ",
1343 (int)error
, command_listNum
);
1344 vfdprintf(STDERR_FILENO
, fmt
, args
);
1345 fdprintf(STDERR_FILENO
, "\n");