Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
mpd
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
mpd
Commits
7652a298
Commit
7652a298
authored
Aug 06, 2015
by
Max Kellermann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
client/Response: new Client wrapper class for writing responses
parent
b1480167
Hide whitespace changes
Inline
Side-by-side
Showing
49 changed files
with
1067 additions
and
779 deletions
+1067
-779
Makefile.am
Makefile.am
+1
-0
PlaylistPrint.cxx
src/PlaylistPrint.cxx
+28
-21
PlaylistPrint.hxx
src/PlaylistPrint.hxx
+16
-9
SongPrint.cxx
src/SongPrint.cxx
+47
-40
SongPrint.hxx
src/SongPrint.hxx
+10
-5
Stats.cxx
src/Stats.cxx
+20
-23
Stats.hxx
src/Stats.hxx
+3
-2
TagPrint.cxx
src/TagPrint.cxx
+15
-15
TagPrint.hxx
src/TagPrint.hxx
+6
-5
TimePrint.cxx
src/TimePrint.cxx
+3
-3
TimePrint.hxx
src/TimePrint.hxx
+2
-2
Response.cxx
src/client/Response.cxx
+72
-0
Response.hxx
src/client/Response.hxx
+49
-0
AllCommands.cxx
src/command/AllCommands.cxx
+42
-23
CommandError.cxx
src/command/CommandError.cxx
+25
-30
CommandError.hxx
src/command/CommandError.hxx
+3
-3
DatabaseCommands.cxx
src/command/DatabaseCommands.cxx
+52
-30
FileCommands.cxx
src/command/FileCommands.cxx
+34
-38
MessageCommands.cxx
src/command/MessageCommands.cxx
+18
-16
NeighborCommands.cxx
src/command/NeighborCommands.cxx
+8
-8
OtherCommands.cxx
src/command/OtherCommands.cxx
+65
-52
OutputCommands.cxx
src/command/OutputCommands.cxx
+15
-14
PlayerCommands.cxx
src/command/PlayerCommands.cxx
+102
-85
PlaylistCommands.cxx
src/command/PlaylistCommands.cxx
+48
-27
QueueCommands.cxx
src/command/QueueCommands.cxx
+81
-51
Request.hxx
src/command/Request.hxx
+7
-7
StickerCommands.cxx
src/command/StickerCommands.cxx
+34
-35
StorageCommands.cxx
src/command/StorageCommands.cxx
+40
-36
StorageCommands.hxx
src/command/StorageCommands.hxx
+3
-2
TagCommands.cxx
src/command/TagCommands.cxx
+11
-8
Count.cxx
src/db/Count.cxx
+13
-14
Count.hxx
src/db/Count.hxx
+4
-3
DatabasePrint.cxx
src/db/DatabasePrint.cxx
+52
-45
DatabasePrint.hxx
src/db/DatabasePrint.hxx
+8
-3
DecoderPrint.cxx
src/decoder/DecoderPrint.cxx
+7
-7
DecoderPrint.hxx
src/decoder/DecoderPrint.hxx
+2
-2
ls.cxx
src/ls.cxx
+4
-3
ls.hxx
src/ls.hxx
+2
-2
OutputPrint.cxx
src/output/OutputPrint.cxx
+6
-7
OutputPrint.hxx
src/output/OutputPrint.hxx
+2
-2
Print.cxx
src/playlist/Print.cxx
+12
-9
Print.hxx
src/playlist/Print.hxx
+6
-3
ArgParser.cxx
src/protocol/ArgParser.cxx
+29
-36
ArgParser.hxx
src/protocol/ArgParser.hxx
+11
-11
QueuePrint.cxx
src/queue/QueuePrint.cxx
+18
-18
QueuePrint.hxx
src/queue/QueuePrint.hxx
+7
-6
StickerPrint.cxx
src/sticker/StickerPrint.cxx
+7
-7
StickerPrint.hxx
src/sticker/StickerPrint.hxx
+3
-3
test_protocol.cxx
test/test_protocol.cxx
+14
-8
No files found.
Makefile.am
View file @
7652a298
...
...
@@ -122,6 +122,7 @@ libmpd_a_SOURCES = \
src/client/ClientMessage.cxx src/client/ClientMessage.hxx
\
src/client/ClientSubscribe.cxx
\
src/client/ClientFile.cxx
\
src/client/Response.cxx src/client/Response.hxx
\
src/Listen.cxx src/Listen.hxx
\
src/LogInit.cxx src/LogInit.hxx
\
src/LogBackend.cxx src/LogBackend.hxx
\
...
...
src/PlaylistPrint.cxx
View file @
7652a298
...
...
@@ -27,6 +27,7 @@
#include "Instance.hxx"
#include "db/Interface.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "input/InputStream.hxx"
#include "DetachedSong.hxx"
#include "fs/Traits.hxx"
...
...
@@ -37,15 +38,17 @@
#define SONG_TIME "Time: "
void
playlist_print_uris
(
Client
&
client
,
const
playlist
&
playlist
)
playlist_print_uris
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
)
{
const
Queue
&
queue
=
playlist
.
queue
;
queue_print_uris
(
client
,
queue
,
0
,
queue
.
GetLength
());
queue_print_uris
(
r
,
partition
,
queue
,
0
,
queue
.
GetLength
());
}
bool
playlist_print_info
(
Client
&
client
,
const
playlist
&
playlist
,
playlist_print_info
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
,
unsigned
start
,
unsigned
end
)
{
const
Queue
&
queue
=
playlist
.
queue
;
...
...
@@ -58,12 +61,12 @@ playlist_print_info(Client &client, const playlist &playlist,
/* an invalid "start" offset is fatal */
return
false
;
queue_print_info
(
client
,
queue
,
start
,
end
);
queue_print_info
(
r
,
partition
,
queue
,
start
,
end
);
return
true
;
}
bool
playlist_print_id
(
Client
&
client
,
const
playlist
&
playlist
,
playlist_print_id
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
,
unsigned
id
)
{
int
position
;
...
...
@@ -73,50 +76,53 @@ playlist_print_id(Client &client, const playlist &playlist,
/* no such song */
return
false
;
return
playlist_print_info
(
client
,
playlist
,
position
,
position
+
1
);
return
playlist_print_info
(
r
,
partition
,
playlist
,
position
,
position
+
1
);
}
bool
playlist_print_current
(
Client
&
client
,
const
playlist
&
playlist
)
playlist_print_current
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
)
{
int
current_position
=
playlist
.
GetCurrentPosition
();
if
(
current_position
<
0
)
return
false
;
queue_print_info
(
client
,
playlist
.
queue
,
queue_print_info
(
r
,
partition
,
playlist
.
queue
,
current_position
,
current_position
+
1
);
return
true
;
}
void
playlist_print_find
(
Client
&
client
,
const
playlist
&
playlist
,
playlist_print_find
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
,
const
SongFilter
&
filter
)
{
queue_find
(
client
,
playlist
.
queue
,
filter
);
queue_find
(
r
,
partition
,
playlist
.
queue
,
filter
);
}
void
playlist_print_changes_info
(
Client
&
client
,
playlist_print_changes_info
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
,
uint32_t
version
)
{
queue_print_changes_info
(
client
,
playlist
.
queue
,
version
);
queue_print_changes_info
(
r
,
partition
,
playlist
.
queue
,
version
);
}
void
playlist_print_changes_position
(
Client
&
client
,
playlist_print_changes_position
(
Response
&
r
,
const
playlist
&
playlist
,
uint32_t
version
)
{
queue_print_changes_position
(
client
,
playlist
.
queue
,
version
);
queue_print_changes_position
(
r
,
playlist
.
queue
,
version
);
}
#ifdef ENABLE_DATABASE
static
bool
PrintSongDetails
(
Client
&
client
,
const
char
*
uri_utf8
)
PrintSongDetails
(
Response
&
r
,
Partition
&
partition
,
const
char
*
uri_utf8
)
{
const
Database
*
db
=
client
.
partition
.
instance
.
database
;
const
Database
*
db
=
partition
.
instance
.
database
;
if
(
db
==
nullptr
)
return
false
;
...
...
@@ -124,7 +130,7 @@ PrintSongDetails(Client &client, const char *uri_utf8)
if
(
song
==
nullptr
)
return
false
;
song_print_info
(
client
,
*
song
);
song_print_info
(
r
,
partition
,
*
song
);
db
->
ReturnSong
(
song
);
return
true
;
}
...
...
@@ -132,7 +138,8 @@ PrintSongDetails(Client &client, const char *uri_utf8)
#endif
bool
spl_print
(
Client
&
client
,
const
char
*
name_utf8
,
bool
detail
,
spl_print
(
Response
&
r
,
Partition
&
partition
,
const
char
*
name_utf8
,
bool
detail
,
Error
&
error
)
{
#ifndef ENABLE_DATABASE
...
...
@@ -145,10 +152,10 @@ spl_print(Client &client, const char *name_utf8, bool detail,
for
(
const
auto
&
uri_utf8
:
contents
)
{
#ifdef ENABLE_DATABASE
if
(
!
detail
||
!
PrintSongDetails
(
client
,
uri_utf8
.
c_str
()))
if
(
!
detail
||
!
PrintSongDetails
(
r
,
partition
,
uri_utf8
.
c_str
()))
#endif
client_printf
(
client
,
SONG_FILE
"%s
\n
"
,
uri_utf8
.
c_str
());
r
.
Format
(
SONG_FILE
"%s
\n
"
,
uri_utf8
.
c_str
());
}
return
true
;
...
...
src/PlaylistPrint.hxx
View file @
7652a298
...
...
@@ -23,15 +23,18 @@
#include <stdint.h>
struct
playlist
;
struct
Partition
;
class
SongFilter
;
class
Client
;
class
Response
;
class
Error
;
/**
* Sends the whole playlist to the client, song URIs only.
*/
void
playlist_print_uris
(
Client
&
client
,
const
playlist
&
playlist
);
playlist_print_uris
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
);
/**
* Sends a range of the playlist to the client, including all known
...
...
@@ -40,7 +43,8 @@ playlist_print_uris(Client &client, const playlist &playlist);
* This function however fails when the start offset is invalid.
*/
bool
playlist_print_info
(
Client
&
client
,
const
playlist
&
playlist
,
playlist_print_info
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
,
unsigned
start
,
unsigned
end
);
/**
...
...
@@ -49,8 +53,8 @@ playlist_print_info(Client &client, const playlist &playlist,
* @return true on suite, false if there is no such song
*/
bool
playlist_print_id
(
Client
&
client
,
const
playlist
&
playlist
,
unsigned
id
);
playlist_print_id
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
,
unsigned
id
);
/**
* Sends the current song to the client.
...
...
@@ -58,20 +62,22 @@ playlist_print_id(Client &client, const playlist &playlist,
* @return true on success, false if there is no current song
*/
bool
playlist_print_current
(
Client
&
client
,
const
playlist
&
playlist
);
playlist_print_current
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
);
/**
* Find songs in the playlist.
*/
void
playlist_print_find
(
Client
&
client
,
const
playlist
&
playlist
,
playlist_print_find
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
,
const
SongFilter
&
filter
);
/**
* Print detailed changes since the specified playlist version.
*/
void
playlist_print_changes_info
(
Client
&
client
,
playlist_print_changes_info
(
Response
&
r
,
Partition
&
partition
,
const
playlist
&
playlist
,
uint32_t
version
);
...
...
@@ -79,7 +85,7 @@ playlist_print_changes_info(Client &client,
* Print changes since the specified playlist version, position only.
*/
void
playlist_print_changes_position
(
Client
&
client
,
playlist_print_changes_position
(
Response
&
r
,
const
playlist
&
playlist
,
uint32_t
version
);
...
...
@@ -92,7 +98,8 @@ playlist_print_changes_position(Client &client,
* @return true on success, false if the playlist does not exist
*/
bool
spl_print
(
Client
&
client
,
const
char
*
name_utf8
,
bool
detail
,
spl_print
(
Response
&
r
,
Partition
&
partition
,
const
char
*
name_utf8
,
bool
detail
,
Error
&
error
);
#endif
src/SongPrint.cxx
View file @
7652a298
...
...
@@ -20,18 +20,20 @@
#include "config.h"
#include "SongPrint.hxx"
#include "db/LightSong.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "storage/StorageInterface.hxx"
#include "DetachedSong.hxx"
#include "TimePrint.hxx"
#include "TagPrint.hxx"
#include "client/
Client
.hxx"
#include "client/
Response
.hxx"
#include "fs/Traits.hxx"
#include "util/UriUtil.hxx"
#define SONG_FILE "file: "
static
void
song_print_uri
(
Client
&
client
,
const
char
*
uri
,
bool
base
)
song_print_uri
(
Response
&
r
,
Partition
&
partition
,
const
char
*
uri
,
bool
base
)
{
std
::
string
allocated
;
...
...
@@ -39,12 +41,14 @@ song_print_uri(Client &client, const char *uri, bool base)
uri
=
PathTraitsUTF8
::
GetBase
(
uri
);
}
else
{
#ifdef ENABLE_DATABASE
const
Storage
*
storage
=
client
.
GetStorage
()
;
const
Storage
*
storage
=
partition
.
instance
.
storage
;
if
(
storage
!=
nullptr
)
{
const
char
*
suffix
=
storage
->
MapToRelativeUTF8
(
uri
);
if
(
suffix
!=
nullptr
)
uri
=
suffix
;
}
#else
(
void
)
partition
;
#endif
allocated
=
uri_remove_auth
(
uri
);
...
...
@@ -52,78 +56,81 @@ song_print_uri(Client &client, const char *uri, bool base)
uri
=
allocated
.
c_str
();
}
client_printf
(
client
,
SONG_FILE
"%s
\n
"
,
uri
);
r
.
Format
(
SONG_FILE
"%s
\n
"
,
uri
);
}
void
song_print_uri
(
Client
&
client
,
const
LightSong
&
song
,
bool
base
)
song_print_uri
(
Response
&
r
,
Partition
&
partition
,
const
LightSong
&
song
,
bool
base
)
{
if
(
!
base
&&
song
.
directory
!=
nullptr
)
{
client_printf
(
client
,
SONG_FILE
"%s/%s
\n
"
,
song
.
directory
,
song
.
uri
);
}
else
song_print_uri
(
client
,
song
.
uri
,
base
);
if
(
!
base
&&
song
.
directory
!=
nullptr
)
r
.
Format
(
SONG_FILE
"%s/%s
\n
"
,
song
.
directory
,
song
.
uri
);
else
song_print_uri
(
r
,
partition
,
song
.
uri
,
base
);
}
void
song_print_uri
(
Client
&
client
,
const
DetachedSong
&
song
,
bool
base
)
song_print_uri
(
Response
&
r
,
Partition
&
partition
,
const
DetachedSong
&
song
,
bool
base
)
{
song_print_uri
(
client
,
song
.
GetURI
(),
base
);
song_print_uri
(
r
,
partition
,
song
.
GetURI
(),
base
);
}
void
song_print_info
(
Client
&
client
,
const
LightSong
&
song
,
bool
base
)
song_print_info
(
Response
&
r
,
Partition
&
partition
,
const
LightSong
&
song
,
bool
base
)
{
song_print_uri
(
client
,
song
,
base
);
song_print_uri
(
r
,
partition
,
song
,
base
);
const
unsigned
start_ms
=
song
.
start_time
.
ToMS
();
const
unsigned
end_ms
=
song
.
end_time
.
ToMS
();
if
(
end_ms
>
0
)
client_printf
(
client
,
"Range: %u.%03u-%u.%03u
\n
"
,
start_ms
/
1000
,
start_ms
%
1000
,
end_ms
/
1000
,
end_ms
%
1000
);
r
.
Format
(
"Range: %u.%03u-%u.%03u
\n
"
,
start_ms
/
1000
,
start_ms
%
1000
,
end_ms
/
1000
,
end_ms
%
1000
);
else
if
(
start_ms
>
0
)
client_printf
(
client
,
"Range: %u.%03u-
\n
"
,
start_ms
/
1000
,
start_ms
%
1000
);
r
.
Format
(
"Range: %u.%03u-
\n
"
,
start_ms
/
1000
,
start_ms
%
1000
);
if
(
song
.
mtime
>
0
)
time_print
(
client
,
"Last-Modified"
,
song
.
mtime
);
time_print
(
r
,
"Last-Modified"
,
song
.
mtime
);
tag_print
(
client
,
*
song
.
tag
);
tag_print
(
r
,
*
song
.
tag
);
}
void
song_print_info
(
Client
&
client
,
const
DetachedSong
&
song
,
bool
base
)
song_print_info
(
Response
&
r
,
Partition
&
partition
,
const
DetachedSong
&
song
,
bool
base
)
{
song_print_uri
(
client
,
song
,
base
);
song_print_uri
(
r
,
partition
,
song
,
base
);
const
unsigned
start_ms
=
song
.
GetStartTime
().
ToMS
();
const
unsigned
end_ms
=
song
.
GetEndTime
().
ToMS
();
if
(
end_ms
>
0
)
client_printf
(
client
,
"Range: %u.%03u-%u.%03u
\n
"
,
start_ms
/
1000
,
start_ms
%
1000
,
end_ms
/
1000
,
end_ms
%
1000
);
r
.
Format
(
"Range: %u.%03u-%u.%03u
\n
"
,
start_ms
/
1000
,
start_ms
%
1000
,
end_ms
/
1000
,
end_ms
%
1000
);
else
if
(
start_ms
>
0
)
client_printf
(
client
,
"Range: %u.%03u-
\n
"
,
start_ms
/
1000
,
start_ms
%
1000
);
r
.
Format
(
"Range: %u.%03u-
\n
"
,
start_ms
/
1000
,
start_ms
%
1000
);
if
(
song
.
GetLastModified
()
>
0
)
time_print
(
client
,
"Last-Modified"
,
song
.
GetLastModified
());
time_print
(
r
,
"Last-Modified"
,
song
.
GetLastModified
());
tag_print_values
(
client
,
song
.
GetTag
());
tag_print_values
(
r
,
song
.
GetTag
());
const
auto
duration
=
song
.
GetDuration
();
if
(
!
duration
.
IsNegative
())
client_printf
(
client
,
"Time: %i
\n
"
"duration: %1.3f
\n
"
,
duration
.
RoundS
(),
duration
.
ToDoubleS
());
r
.
Format
(
"Time: %i
\n
"
"duration: %1.3f
\n
"
,
duration
.
RoundS
(),
duration
.
ToDoubleS
());
}
src/SongPrint.hxx
View file @
7652a298
...
...
@@ -22,18 +22,23 @@
struct
LightSong
;
class
DetachedSong
;
class
Client
;
class
Response
;
struct
Partition
;
void
song_print_info
(
Client
&
client
,
const
DetachedSong
&
song
,
bool
base
=
false
);
song_print_info
(
Response
&
r
,
Partition
&
partition
,
const
DetachedSong
&
song
,
bool
base
=
false
);
void
song_print_info
(
Client
&
client
,
const
LightSong
&
song
,
bool
base
=
false
);
song_print_info
(
Response
&
r
,
Partition
&
partition
,
const
LightSong
&
song
,
bool
base
=
false
);
void
song_print_uri
(
Client
&
client
,
const
LightSong
&
song
,
bool
base
=
false
);
song_print_uri
(
Response
&
r
,
Partition
&
partition
,
const
LightSong
&
song
,
bool
base
=
false
);
void
song_print_uri
(
Client
&
client
,
const
DetachedSong
&
song
,
bool
base
=
false
);
song_print_uri
(
Response
&
r
,
Partition
&
partition
,
const
DetachedSong
&
song
,
bool
base
=
false
);
#endif
src/Stats.cxx
View file @
7652a298
...
...
@@ -20,7 +20,7 @@
#include "config.h"
#include "Stats.hxx"
#include "PlayerControl.hxx"
#include "client/
Client
.hxx"
#include "client/
Response
.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "db/Selection.hxx"
...
...
@@ -94,7 +94,7 @@ stats_update(const Database &db)
}
static
void
db_stats_print
(
Client
&
client
,
const
Database
&
db
)
db_stats_print
(
Response
&
r
,
const
Database
&
db
)
{
if
(
!
stats_update
(
db
))
return
;
...
...
@@ -102,41 +102,38 @@ db_stats_print(Client &client, const Database &db)
unsigned
total_duration_s
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
seconds
>
(
stats
.
total_duration
).
count
();
client_printf
(
client
,
"artists: %u
\n
"
"albums: %u
\n
"
"songs: %u
\n
"
"db_playtime: %u
\n
"
,
stats
.
artist_count
,
stats
.
album_count
,
stats
.
song_count
,
total_duration_s
);
r
.
Format
(
"artists: %u
\n
"
"albums: %u
\n
"
"songs: %u
\n
"
"db_playtime: %u
\n
"
,
stats
.
artist_count
,
stats
.
album_count
,
stats
.
song_count
,
total_duration_s
);
const
time_t
update_stamp
=
db
.
GetUpdateStamp
();
if
(
update_stamp
>
0
)
client_printf
(
client
,
"db_update: %lu
\n
"
,
(
unsigned
long
)
update_stamp
);
r
.
Format
(
"db_update: %lu
\n
"
,
(
unsigned
long
)
update_stamp
);
}
#endif
void
stats_print
(
Client
&
client
)
stats_print
(
Response
&
r
,
const
Partition
&
partition
)
{
client_printf
(
client
,
"uptime: %u
\n
"
"playtime: %lu
\n
"
,
r
.
Format
(
"uptime: %u
\n
"
"playtime: %lu
\n
"
,
#ifdef WIN32
GetProcessUptimeS
(),
GetProcessUptimeS
(),
#else
MonotonicClockS
()
-
start_time
,
MonotonicClockS
()
-
start_time
,
#endif
(
unsigned
long
)(
client
.
player_control
.
GetTotalPlayTime
()
+
0.5
));
(
unsigned
long
)(
partition
.
pc
.
GetTotalPlayTime
()
+
0.5
));
#ifdef ENABLE_DATABASE
const
Database
*
db
=
client
.
partition
.
instance
.
database
;
const
Database
*
db
=
partition
.
instance
.
database
;
if
(
db
!=
nullptr
)
db_stats_print
(
client
,
*
db
);
db_stats_print
(
r
,
*
db
);
#endif
}
src/Stats.hxx
View file @
7652a298
...
...
@@ -20,7 +20,8 @@
#ifndef MPD_STATS_HXX
#define MPD_STATS_HXX
class
Client
;
class
Response
;
struct
Partition
;
void
stats_global_init
();
...
...
@@ -29,6 +30,6 @@ void
stats_invalidate
();
void
stats_print
(
Client
&
client
);
stats_print
(
Response
&
r
,
const
Partition
&
partition
);
#endif
src/TagPrint.cxx
View file @
7652a298
...
...
@@ -21,40 +21,40 @@
#include "TagPrint.hxx"
#include "tag/Tag.hxx"
#include "tag/TagSettings.h"
#include "client/
Client
.hxx"
#include "client/
Response
.hxx"
void
tag_print_types
(
Client
&
client
)
void
tag_print_types
(
Response
&
r
)
{
int
i
;
for
(
i
=
0
;
i
<
TAG_NUM_OF_ITEM_TYPES
;
i
++
)
{
if
(
!
ignore_tag_items
[
i
])
client_printf
(
client
,
"tagtype: %s
\n
"
,
tag_item_names
[
i
]);
r
.
Format
(
"tagtype: %s
\n
"
,
tag_item_names
[
i
]);
}
}
void
tag_print
(
Client
&
client
,
TagType
type
,
const
char
*
value
)
tag_print
(
Response
&
r
,
TagType
type
,
const
char
*
value
)
{
client_printf
(
client
,
"%s: %s
\n
"
,
tag_item_names
[
type
],
value
);
r
.
Format
(
"%s: %s
\n
"
,
tag_item_names
[
type
],
value
);
}
void
tag_print_values
(
Client
&
client
,
const
Tag
&
tag
)
tag_print_values
(
Response
&
r
,
const
Tag
&
tag
)
{
for
(
const
auto
&
i
:
tag
)
client_printf
(
client
,
"%s: %s
\n
"
,
tag_item_names
[
i
.
type
],
i
.
value
);
r
.
Format
(
"%s: %s
\n
"
,
tag_item_names
[
i
.
type
],
i
.
value
);
}
void
tag_print
(
Client
&
client
,
const
Tag
&
tag
)
void
tag_print
(
Response
&
r
,
const
Tag
&
tag
)
{
if
(
!
tag
.
duration
.
IsNegative
())
client_printf
(
client
,
"Time: %i
\n
"
"duration: %1.3f
\n
"
,
tag
.
duration
.
RoundS
(),
tag
.
duration
.
ToDoubleS
());
r
.
Format
(
"Time: %i
\n
"
"duration: %1.3f
\n
"
,
tag
.
duration
.
RoundS
(),
tag
.
duration
.
ToDoubleS
());
tag_print_values
(
client
,
tag
);
tag_print_values
(
r
,
tag
);
}
src/TagPrint.hxx
View file @
7652a298
...
...
@@ -25,17 +25,18 @@
enum
TagType
:
uint8_t
;
struct
Tag
;
class
Client
;
class
Response
;
void
tag_print_types
(
Client
&
client
);
void
tag_print_types
(
Response
&
response
);
void
tag_print
(
Client
&
client
,
TagType
type
,
const
char
*
value
);
tag_print
(
Response
&
response
,
TagType
type
,
const
char
*
value
);
void
tag_print_values
(
Client
&
client
,
const
Tag
&
tag
);
tag_print_values
(
Response
&
response
,
const
Tag
&
tag
);
void
tag_print
(
Client
&
client
,
const
Tag
&
tag
);
tag_print
(
Response
&
response
,
const
Tag
&
tag
);
#endif
src/TimePrint.cxx
View file @
7652a298
...
...
@@ -19,10 +19,10 @@
#include "config.h"
#include "TimePrint.hxx"
#include "client/
Client
.hxx"
#include "client/
Response
.hxx"
void
time_print
(
Client
&
client
,
const
char
*
name
,
time_t
t
)
time_print
(
Response
&
r
,
const
char
*
name
,
time_t
t
)
{
#ifdef WIN32
const
struct
tm
*
tm2
=
gmtime
(
&
t
);
...
...
@@ -41,5 +41,5 @@ time_print(Client &client, const char *name, time_t t)
"%FT%TZ"
,
#endif
tm2
);
client_printf
(
client
,
"%s: %s
\n
"
,
name
,
buffer
);
r
.
Format
(
"%s: %s
\n
"
,
name
,
buffer
);
}
src/TimePrint.hxx
View file @
7652a298
...
...
@@ -22,12 +22,12 @@
#include <time.h>
class
Client
;
class
Response
;
/**
* Write a line with a time stamp to the client.
*/
void
time_print
(
Client
&
client
,
const
char
*
name
,
time_t
t
);
time_print
(
Response
&
r
,
const
char
*
name
,
time_t
t
);
#endif
src/client/Response.cxx
0 → 100644
View file @
7652a298
/*
* Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "Response.hxx"
#include "Client.hxx"
#include "protocol/Result.hxx"
#include "util/FormatString.hxx"
#include <string.h>
bool
Response
::
Write
(
const
void
*
data
,
size_t
length
)
{
return
client
.
Write
(
data
,
length
);
}
bool
Response
::
Write
(
const
char
*
data
)
{
return
Write
(
data
,
strlen
(
data
));
}
bool
Response
::
FormatV
(
const
char
*
fmt
,
va_list
args
)
{
char
*
p
=
FormatNewV
(
fmt
,
args
);
bool
success
=
Write
(
p
);
delete
[]
p
;
return
success
;
}
bool
Response
::
Format
(
const
char
*
fmt
,
...)
{
va_list
args
;
va_start
(
args
,
fmt
);
bool
success
=
FormatV
(
fmt
,
args
);
va_end
(
args
);
return
success
;
}
void
Response
::
Error
(
enum
ack
code
,
const
char
*
msg
)
{
command_error
(
client
,
code
,
"%s"
,
msg
);
}
void
Response
::
FormatError
(
enum
ack
code
,
const
char
*
fmt
,
...)
{
va_list
args
;
va_start
(
args
,
fmt
);
command_error_v
(
client
,
code
,
fmt
,
args
);
va_end
(
args
);
}
src/client/Response.hxx
0 → 100644
View file @
7652a298
/*
* Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_RESPONSE_HXX
#define MPD_RESPONSE_HXX
#include "check.h"
#include "protocol/Ack.hxx"
#include <stddef.h>
#include <stdarg.h>
class
Client
;
class
Response
{
Client
&
client
;
public
:
explicit
Response
(
Client
&
_client
)
:
client
(
_client
)
{}
Response
(
const
Response
&
)
=
delete
;
Response
&
operator
=
(
const
Response
&
)
=
delete
;
bool
Write
(
const
void
*
data
,
size_t
length
);
bool
Write
(
const
char
*
data
);
bool
FormatV
(
const
char
*
fmt
,
va_list
args
);
bool
Format
(
const
char
*
fmt
,
...);
void
Error
(
enum
ack
code
,
const
char
*
msg
);
void
FormatError
(
enum
ack
code
,
const
char
*
fmt
,
...);
};
#endif
src/command/AllCommands.cxx
View file @
7652a298
...
...
@@ -36,6 +36,7 @@
#include "protocol/Result.hxx"
#include "Partition.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "util/Macros.hxx"
#include "util/Tokenizer.hxx"
#include "util/Error.hxx"
...
...
@@ -226,38 +227,50 @@ command_available(gcc_unused const Partition &partition,
return
true
;
}
/* don't be fooled, this is the command handler for "commands" command */
static
CommandResult
handle_commands
(
Client
&
client
,
gcc_unused
Request
args
)
PrintAvailableCommands
(
Response
&
r
,
const
Partition
&
partition
,
unsigned
permission
)
{
const
unsigned
permission
=
client
.
GetPermission
();
for
(
unsigned
i
=
0
;
i
<
num_commands
;
++
i
)
{
const
struct
command
*
cmd
=
&
commands
[
i
];
if
(
cmd
->
permission
==
(
permission
&
cmd
->
permission
)
&&
command_available
(
client
.
partition
,
cmd
))
client_printf
(
client
,
"command: %s
\n
"
,
cmd
->
cmd
);
command_available
(
partition
,
cmd
))
r
.
Format
(
"command: %s
\n
"
,
cmd
->
cmd
);
}
return
CommandResult
::
OK
;
}
static
CommandResult
handle_not_commands
(
Client
&
client
,
gcc_unused
Request
args
)
PrintUnavailableCommands
(
Response
&
r
,
unsigned
permission
)
{
const
unsigned
permission
=
client
.
GetPermission
();
for
(
unsigned
i
=
0
;
i
<
num_commands
;
++
i
)
{
const
struct
command
*
cmd
=
&
commands
[
i
];
if
(
cmd
->
permission
!=
(
permission
&
cmd
->
permission
))
client_printf
(
client
,
"command: %s
\n
"
,
cmd
->
cmd
);
r
.
Format
(
"command: %s
\n
"
,
cmd
->
cmd
);
}
return
CommandResult
::
OK
;
}
/* don't be fooled, this is the command handler for "commands" command */
static
CommandResult
handle_commands
(
Client
&
client
,
gcc_unused
Request
args
)
{
Response
r
(
client
);
return
PrintAvailableCommands
(
r
,
client
.
partition
,
client
.
GetPermission
());
}
static
CommandResult
handle_not_commands
(
Client
&
client
,
gcc_unused
Request
args
)
{
Response
r
(
client
);
return
PrintUnavailableCommands
(
r
,
client
.
GetPermission
());
}
void
command_init
()
{
...
...
@@ -299,7 +312,8 @@ command_check_request(const struct command *cmd, Client &client,
unsigned
permission
,
Request
args
)
{
if
(
cmd
->
permission
!=
(
permission
&
cmd
->
permission
))
{
command_error
(
client
,
ACK_ERROR_PERMISSION
,
Response
r
(
client
);
r
.
FormatError
(
ACK_ERROR_PERMISSION
,
"you don't have permission for
\"
%s
\"
"
,
cmd
->
cmd
);
return
false
;
...
...
@@ -312,16 +326,19 @@ command_check_request(const struct command *cmd, Client &client,
return
true
;
if
(
min
==
max
&&
unsigned
(
max
)
!=
args
.
size
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
Response
r
(
client
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"wrong number of arguments for
\"
%s
\"
"
,
cmd
->
cmd
);
return
false
;
}
else
if
(
args
.
size
<
unsigned
(
min
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
Response
r
(
client
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"too few arguments for
\"
%s
\"
"
,
cmd
->
cmd
);
return
false
;
}
else
if
(
max
>=
0
&&
args
.
size
>
unsigned
(
max
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
Response
r
(
client
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"too many arguments for
\"
%s
\"
"
,
cmd
->
cmd
);
return
false
;
}
else
...
...
@@ -336,7 +353,8 @@ command_checked_lookup(Client &client, unsigned permission,
const
struct
command
*
cmd
=
command_lookup
(
cmd_name
);
if
(
cmd
==
nullptr
)
{
command_error
(
client
,
ACK_ERROR_UNKNOWN
,
Response
r
(
client
);
r
.
FormatError
(
ACK_ERROR_UNKNOWN
,
"unknown command
\"
%s
\"
"
,
cmd_name
);
return
nullptr
;
}
...
...
@@ -357,7 +375,7 @@ command_process(Client &client, unsigned num, char *line)
command_list_num
=
num
;
/* get the command name (first word on the line) */
/* we have to set current_command because
command_e
rror()
/* we have to set current_command because
Response::E
rror()
expects it to be set */
Tokenizer
tokenizer
(
line
);
...
...
@@ -366,12 +384,12 @@ command_process(Client &client, unsigned num, char *line)
tokenizer
.
NextWord
(
error
);
if
(
cmd_name
==
nullptr
)
{
current_command
=
""
;
Response
r
(
client
);
if
(
tokenizer
.
IsEnd
())
command_error
(
client
,
ACK_ERROR_UNKNOWN
,
"No command given"
);
r
.
FormatError
(
ACK_ERROR_UNKNOWN
,
"No command given"
);
else
command_error
(
client
,
ACK_ERROR_UNKNOWN
,
"%s"
,
error
.
GetMessage
());
r
.
Error
(
ACK_ERROR_UNKNOWN
,
error
.
GetMessage
());
current_command
=
nullptr
;
...
...
@@ -387,8 +405,8 @@ command_process(Client &client, unsigned num, char *line)
while
(
true
)
{
if
(
args
.
size
==
COMMAND_ARGV_MAX
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Too many arguments"
);
Response
r
(
client
);
r
.
Error
(
ACK_ERROR_ARG
,
"Too many arguments"
);
current_command
=
nullptr
;
return
CommandResult
::
ERROR
;
}
...
...
@@ -398,7 +416,8 @@ command_process(Client &client, unsigned num, char *line)
if
(
tokenizer
.
IsEnd
())
break
;
command_error
(
client
,
ACK_ERROR_ARG
,
"%s"
,
error
.
GetMessage
());
Response
r
(
client
);
r
.
Error
(
ACK_ERROR_UNKNOWN
,
error
.
GetMessage
());
current_command
=
nullptr
;
return
CommandResult
::
ERROR
;
}
...
...
src/command/CommandError.cxx
View file @
7652a298
...
...
@@ -20,7 +20,7 @@
#include "config.h"
#include "CommandError.hxx"
#include "db/DatabaseError.hxx"
#include "
protocol/Result
.hxx"
#include "
client/Response
.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
...
...
@@ -29,57 +29,55 @@
#include <errno.h>
CommandResult
print_playlist_result
(
Client
&
client
,
PlaylistResult
result
)
print_playlist_result
(
Response
&
r
,
PlaylistResult
result
)
{
switch
(
result
)
{
case
PlaylistResult
:
:
SUCCESS
:
return
CommandResult
::
OK
;
case
PlaylistResult
:
:
ERRNO
:
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"%s"
,
strerror
(
errno
));
r
.
Error
(
ACK_ERROR_SYSTEM
,
strerror
(
errno
));
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
DENIED
:
command_error
(
client
,
ACK_ERROR_PERMISSION
,
"Access denied"
);
r
.
Error
(
ACK_ERROR_PERMISSION
,
"Access denied"
);
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
NO_SUCH_SONG
:
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such song"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such song"
);
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
NO_SUCH_LIST
:
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such playlist"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such playlist"
);
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
LIST_EXISTS
:
command_error
(
client
,
ACK_ERROR_EXIST
,
"Playlist already exists"
);
r
.
Error
(
ACK_ERROR_EXIST
,
"Playlist already exists"
);
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
BAD_NAME
:
command_error
(
client
,
ACK_ERROR_ARG
,
"playlist name is invalid: "
"playlist names may not contain slashes,"
" newlines or carriage returns"
);
r
.
Error
(
ACK_ERROR_ARG
,
"playlist name is invalid: "
"playlist names may not contain slashes,"
" newlines or carriage returns"
);
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
BAD_RANGE
:
command_error
(
client
,
ACK_ERROR_ARG
,
"Bad song index"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Bad song index"
);
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
NOT_PLAYING
:
command_error
(
client
,
ACK_ERROR_PLAYER_SYNC
,
"Not playing"
);
r
.
Error
(
ACK_ERROR_PLAYER_SYNC
,
"Not playing"
);
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
TOO_LARGE
:
command_error
(
client
,
ACK_ERROR_PLAYLIST_MAX
,
"playlist is at the max size"
);
r
.
Error
(
ACK_ERROR_PLAYLIST_MAX
,
"playlist is at the max size"
);
return
CommandResult
::
ERROR
;
case
PlaylistResult
:
:
DISABLED
:
command_error
(
client
,
ACK_ERROR_UNKNOWN
,
"stored playlist support is disabled"
);
r
.
Error
(
ACK_ERROR_UNKNOWN
,
"stored playlist support is disabled"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -88,42 +86,39 @@ print_playlist_result(Client &client, PlaylistResult result)
}
CommandResult
print_error
(
Client
&
client
,
const
Error
&
error
)
print_error
(
Response
&
r
,
const
Error
&
error
)
{
assert
(
error
.
IsDefined
());
LogError
(
error
);
if
(
error
.
IsDomain
(
playlist_domain
))
{
return
print_playlist_result
(
client
,
return
print_playlist_result
(
r
,
PlaylistResult
(
error
.
GetCode
()));
}
else
if
(
error
.
IsDomain
(
ack_domain
))
{
command_error
(
client
,
(
ack
)
error
.
GetCode
(),
"%s"
,
error
.
GetMessage
());
r
.
Error
((
ack
)
error
.
GetCode
(),
error
.
GetMessage
());
return
CommandResult
::
ERROR
;
#ifdef ENABLE_DATABASE
}
else
if
(
error
.
IsDomain
(
db_domain
))
{
switch
((
enum
db_error
)
error
.
GetCode
())
{
case
DB_DISABLED
:
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"%s"
,
error
.
GetMessage
());
r
.
Error
(
ACK_ERROR_NO_EXIST
,
error
.
GetMessage
());
return
CommandResult
::
ERROR
;
case
DB_NOT_FOUND
:
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"Not found"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"Not found"
);
return
CommandResult
::
ERROR
;
case
DB_CONFLICT
:
command_error
(
client
,
ACK_ERROR_ARG
,
"Conflict"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Conflict"
);
return
CommandResult
::
ERROR
;
}
#endif
}
else
if
(
error
.
IsDomain
(
errno_domain
))
{
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"%s"
,
strerror
(
error
.
GetCode
()));
r
.
Error
(
ACK_ERROR_SYSTEM
,
strerror
(
error
.
GetCode
()));
return
CommandResult
::
ERROR
;
}
command_error
(
client
,
ACK_ERROR_UNKNOWN
,
"error"
);
r
.
Error
(
ACK_ERROR_UNKNOWN
,
"error"
);
return
CommandResult
::
ERROR
;
}
src/command/CommandError.hxx
View file @
7652a298
...
...
@@ -23,16 +23,16 @@
#include "CommandResult.hxx"
#include "PlaylistError.hxx"
class
Client
;
class
Response
;
class
Error
;
CommandResult
print_playlist_result
(
Client
&
client
,
PlaylistResult
result
);
print_playlist_result
(
Response
&
r
,
PlaylistResult
result
);
/**
* Send the #Error to the client.
*/
CommandResult
print_error
(
Client
&
client
,
const
Error
&
error
);
print_error
(
Response
&
r
,
const
Error
&
error
);
#endif
src/command/DatabaseCommands.cxx
View file @
7652a298
...
...
@@ -28,11 +28,11 @@
#include "db/Selection.hxx"
#include "CommandError.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "tag/Tag.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
#include "SongFilter.hxx"
#include "protocol/Result.hxx"
#include "BulkEdit.hxx"
#include <string.h>
...
...
@@ -40,11 +40,13 @@
CommandResult
handle_listfiles_db
(
Client
&
client
,
const
char
*
uri
)
{
Response
r
(
client
);
const
DatabaseSelection
selection
(
uri
,
false
);
Error
error
;
if
(
!
db_selection_print
(
client
,
selection
,
false
,
true
,
error
))
return
print_error
(
client
,
error
);
if
(
!
db_selection_print
(
r
,
client
.
partition
,
selection
,
false
,
true
,
error
))
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
...
...
@@ -52,14 +54,17 @@ handle_listfiles_db(Client &client, const char *uri)
CommandResult
handle_lsinfo2
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
/* default is root directory */
const
auto
uri
=
args
.
GetOptional
(
0
,
""
);
const
DatabaseSelection
selection
(
uri
,
false
);
Error
error
;
if
(
!
db_selection_print
(
client
,
selection
,
true
,
false
,
error
))
return
print_error
(
client
,
error
);
if
(
!
db_selection_print
(
r
,
client
.
partition
,
selection
,
true
,
false
,
error
))
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
...
...
@@ -67,9 +72,11 @@ handle_lsinfo2(Client &client, Request args)
static
CommandResult
handle_match
(
Client
&
client
,
Request
args
,
bool
fold_case
)
{
Response
r
(
client
);
RangeArg
window
;
if
(
args
.
size
>=
2
&&
strcmp
(
args
[
args
.
size
-
2
],
"window"
)
==
0
)
{
if
(
!
args
.
Parse
(
args
.
size
-
1
,
window
,
client
))
if
(
!
args
.
Parse
(
args
.
size
-
1
,
window
,
r
))
return
CommandResult
::
ERROR
;
args
.
pop_back
();
...
...
@@ -79,17 +86,18 @@ handle_match(Client &client, Request args, bool fold_case)
SongFilter
filter
;
if
(
!
filter
.
Parse
(
args
,
fold_case
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"incorrect arguments"
);
r
.
Error
(
ACK_ERROR_ARG
,
"incorrect arguments"
);
return
CommandResult
::
ERROR
;
}
const
DatabaseSelection
selection
(
""
,
true
,
&
filter
);
Error
error
;
return
db_selection_print
(
client
,
selection
,
true
,
false
,
return
db_selection_print
(
r
,
client
.
partition
,
selection
,
true
,
false
,
window
.
start
,
window
.
end
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
...
...
@@ -107,9 +115,11 @@ handle_search(Client &client, Request args)
static
CommandResult
handle_match_add
(
Client
&
client
,
Request
args
,
bool
fold_case
)
{
Response
r
(
client
);
SongFilter
filter
;
if
(
!
filter
.
Parse
(
args
,
fold_case
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"incorrect arguments"
);
r
.
Error
(
ACK_ERROR_ARG
,
"incorrect arguments"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -119,7 +129,7 @@ handle_match_add(Client &client, Request args, bool fold_case)
Error
error
;
return
AddFromDatabase
(
client
.
partition
,
selection
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
...
...
@@ -137,34 +147,38 @@ handle_searchadd(Client &client, Request args)
CommandResult
handle_searchaddpl
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
playlist
=
args
.
shift
();
SongFilter
filter
;
if
(
!
filter
.
Parse
(
args
,
true
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"incorrect arguments"
);
r
.
Error
(
ACK_ERROR_ARG
,
"incorrect arguments"
);
return
CommandResult
::
ERROR
;
}
Error
error
;
const
Database
*
db
=
client
.
GetDatabase
(
error
);
if
(
db
==
nullptr
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
search_add_to_playlist
(
*
db
,
*
client
.
GetStorage
(),
""
,
playlist
,
&
filter
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_count
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
TagType
group
=
TAG_NUM_OF_ITEM_TYPES
;
if
(
args
.
size
>=
2
&&
strcmp
(
args
[
args
.
size
-
2
],
"group"
)
==
0
)
{
const
char
*
s
=
args
[
args
.
size
-
1
];
group
=
tag_name_parse_i
(
s
);
if
(
group
==
TAG_NUM_OF_ITEM_TYPES
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Unknown tag type: %s"
,
s
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -175,38 +189,43 @@ handle_count(Client &client, Request args)
SongFilter
filter
;
if
(
!
args
.
IsEmpty
()
&&
!
filter
.
Parse
(
args
,
false
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"incorrect arguments"
);
r
.
Error
(
ACK_ERROR_ARG
,
"incorrect arguments"
);
return
CommandResult
::
ERROR
;
}
Error
error
;
return
PrintSongCount
(
client
,
""
,
&
filter
,
group
,
error
)
return
PrintSongCount
(
r
,
client
.
partition
,
""
,
&
filter
,
group
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_listall
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
/* default is root directory */
const
auto
uri
=
args
.
GetOptional
(
0
,
""
);
Error
error
;
return
db_selection_print
(
client
,
DatabaseSelection
(
uri
,
true
),
return
db_selection_print
(
r
,
client
.
partition
,
DatabaseSelection
(
uri
,
true
),
false
,
false
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_list
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
tag_name
=
args
.
shift
();
unsigned
tagType
=
locate_parse_type
(
tag_name
);
if
(
tagType
>=
TAG_NUM_OF_ITEM_TYPES
&&
tagType
!=
LOCATE_TAG_FILE_TYPE
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Unknown tag type: %s"
,
tag_name
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -217,7 +236,7 @@ handle_list(Client &client, Request args)
if
(
args
.
size
==
1
)
{
/* for compatibility with < 0.12.0 */
if
(
tagType
!=
TAG_ALBUM
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"should be
\"
%s
\"
for 3 arguments"
,
tag_item_names
[
TAG_ALBUM
]);
return
CommandResult
::
ERROR
;
...
...
@@ -231,7 +250,7 @@ handle_list(Client &client, Request args)
const
char
*
s
=
args
[
args
.
size
-
1
];
TagType
gt
=
tag_name_parse_i
(
s
);
if
(
gt
==
TAG_NUM_OF_ITEM_TYPES
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Unknown tag type: %s"
,
s
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -246,8 +265,7 @@ handle_list(Client &client, Request args)
filter
=
new
SongFilter
();
if
(
!
filter
->
Parse
(
args
,
false
))
{
delete
filter
;
command_error
(
client
,
ACK_ERROR_ARG
,
"not able to parse args"
);
r
.
Error
(
ACK_ERROR_ARG
,
"not able to parse args"
);
return
CommandResult
::
ERROR
;
}
}
...
...
@@ -255,15 +273,16 @@ handle_list(Client &client, Request args)
if
(
tagType
<
TAG_NUM_OF_ITEM_TYPES
&&
group_mask
&
(
1u
<<
tagType
))
{
delete
filter
;
command_error
(
client
,
ACK_ERROR_ARG
,
"Conflicting group"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Conflicting group"
);
return
CommandResult
::
ERROR
;
}
Error
error
;
CommandResult
ret
=
PrintUniqueTags
(
client
,
tagType
,
group_mask
,
filter
,
error
)
PrintUniqueTags
(
r
,
client
.
partition
,
tagType
,
group_mask
,
filter
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
delete
filter
;
...
...
@@ -273,12 +292,15 @@ handle_list(Client &client, Request args)
CommandResult
handle_listallinfo
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
/* default is root directory */
const
auto
uri
=
args
.
GetOptional
(
0
,
""
);
Error
error
;
return
db_selection_print
(
client
,
DatabaseSelection
(
uri
,
true
),
return
db_selection_print
(
r
,
client
.
partition
,
DatabaseSelection
(
uri
,
true
),
true
,
false
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
src/command/FileCommands.cxx
View file @
7652a298
...
...
@@ -24,8 +24,8 @@
#include "Request.hxx"
#include "CommandError.hxx"
#include "protocol/Ack.hxx"
#include "protocol/Result.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "util/ConstBuffer.hxx"
#include "util/CharUtil.hxx"
#include "util/UriUtil.hxx"
...
...
@@ -72,21 +72,22 @@ skip_path(Path name_fs)
CommandResult
handle_listfiles_local
(
Client
&
client
,
const
char
*
path_utf8
)
{
Response
r
(
client
);
const
auto
path_fs
=
AllocatedPath
::
FromUTF8
(
path_utf8
);
if
(
path_fs
.
IsNull
())
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"unsupported file name"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"unsupported file name"
);
return
CommandResult
::
ERROR
;
}
Error
error
;
if
(
!
client
.
AllowFile
(
path_fs
,
error
))
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
DirectoryReader
reader
(
path_fs
);
if
(
reader
.
HasFailed
())
{
error
.
FormatErrno
(
"Failed to open '%s'"
,
path_utf8
);
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
}
while
(
reader
.
ReadEntry
())
{
...
...
@@ -105,17 +106,16 @@ handle_listfiles_local(Client &client, const char *path_utf8)
continue
;
if
(
fi
.
IsRegular
())
client_printf
(
client
,
"file: %s
\n
"
"size: %"
PRIu64
"
\n
"
,
name_utf8
.
c_str
(),
fi
.
GetSize
());
r
.
Format
(
"file: %s
\n
"
"size: %"
PRIu64
"
\n
"
,
name_utf8
.
c_str
(),
fi
.
GetSize
());
else
if
(
fi
.
IsDirectory
())
client_printf
(
client
,
"directory: %s
\n
"
,
name_utf8
.
c_str
());
r
.
Format
(
"directory: %s
\n
"
,
name_utf8
.
c_str
());
else
continue
;
time_print
(
client
,
"Last-Modified"
,
fi
.
GetModificationTime
());
time_print
(
r
,
"Last-Modified"
,
fi
.
GetModificationTime
());
}
return
CommandResult
::
OK
;
...
...
@@ -158,10 +158,10 @@ IsValidValue(const char *p)
static
void
print_pair
(
const
char
*
key
,
const
char
*
value
,
void
*
ctx
)
{
Client
&
client
=
*
(
Client
*
)
ctx
;
auto
&
r
=
*
(
Response
*
)
ctx
;
if
(
IsValidName
(
key
)
&&
IsValidValue
(
value
))
client_printf
(
client
,
"%s: %s
\n
"
,
key
,
value
);
r
.
Format
(
"%s: %s
\n
"
,
key
,
value
);
}
static
constexpr
tag_handler
print_comment_handler
=
{
...
...
@@ -171,17 +171,15 @@ static constexpr tag_handler print_comment_handler = {
};
static
CommandResult
read_stream_comments
(
Client
&
client
,
const
char
*
uri
)
read_stream_comments
(
Response
&
r
,
const
char
*
uri
)
{
if
(
!
uri_supported_scheme
(
uri
))
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"unsupported URI scheme"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"unsupported URI scheme"
);
return
CommandResult
::
ERROR
;
}
if
(
!
tag_stream_scan
(
uri
,
print_comment_handler
,
&
client
))
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"Failed to load file"
);
if
(
!
tag_stream_scan
(
uri
,
print_comment_handler
,
&
r
))
{
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"Failed to load file"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -190,16 +188,15 @@ read_stream_comments(Client &client, const char *uri)
}
static
CommandResult
read_file_comments
(
Client
&
client
,
const
Path
path_fs
)
read_file_comments
(
Response
&
r
,
const
Path
path_fs
)
{
if
(
!
tag_file_scan
(
path_fs
,
print_comment_handler
,
&
client
))
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"Failed to load file"
);
if
(
!
tag_file_scan
(
path_fs
,
print_comment_handler
,
&
r
))
{
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"Failed to load file"
);
return
CommandResult
::
ERROR
;
}
tag_ape_scan2
(
path_fs
,
&
print_comment_handler
,
&
client
);
tag_id3_scan
(
path_fs
,
&
print_comment_handler
,
&
client
);
tag_ape_scan2
(
path_fs
,
&
print_comment_handler
,
&
r
);
tag_id3_scan
(
path_fs
,
&
print_comment_handler
,
&
r
);
return
CommandResult
::
OK
;
...
...
@@ -219,6 +216,8 @@ translate_uri(const char *uri)
CommandResult
handle_read_comments
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
assert
(
args
.
size
==
1
);
const
char
*
const
uri
=
translate_uri
(
args
.
front
());
...
...
@@ -227,25 +226,23 @@ handle_read_comments(Client &client, Request args)
const
char
*
path_utf8
=
uri
+
7
;
AllocatedPath
path_fs
=
AllocatedPath
::
FromUTF8
(
path_utf8
);
if
(
path_fs
.
IsNull
())
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"unsupported file name"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"unsupported file name"
);
return
CommandResult
::
ERROR
;
}
Error
error
;
if
(
!
client
.
AllowFile
(
path_fs
,
error
))
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
read_file_comments
(
client
,
path_fs
);
return
read_file_comments
(
r
,
path_fs
);
}
else
if
(
uri_has_scheme
(
uri
))
{
return
read_stream_comments
(
client
,
uri
);
return
read_stream_comments
(
r
,
uri
);
}
else
if
(
!
PathTraitsUTF8
::
IsAbsolute
(
uri
))
{
#ifdef ENABLE_DATABASE
const
Storage
*
storage
=
client
.
GetStorage
();
if
(
storage
==
nullptr
)
{
#endif
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No database"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No database"
);
return
CommandResult
::
ERROR
;
#ifdef ENABLE_DATABASE
}
...
...
@@ -253,21 +250,20 @@ handle_read_comments(Client &client, Request args)
{
AllocatedPath
path_fs
=
storage
->
MapFS
(
uri
);
if
(
!
path_fs
.
IsNull
())
return
read_file_comments
(
client
,
path_fs
);
return
read_file_comments
(
r
,
path_fs
);
}
{
const
std
::
string
uri2
=
storage
->
MapUTF8
(
uri
);
if
(
uri_has_scheme
(
uri2
.
c_str
()))
return
read_stream_comments
(
client
,
uri2
.
c_str
());
return
read_stream_comments
(
r
,
uri2
.
c_str
());
}
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such file"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such file"
);
return
CommandResult
::
ERROR
;
#endif
}
else
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such file"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such file"
);
return
CommandResult
::
ERROR
;
}
}
src/command/MessageCommands.cxx
View file @
7652a298
...
...
@@ -22,9 +22,9 @@
#include "Request.hxx"
#include "client/Client.hxx"
#include "client/ClientList.hxx"
#include "client/Response.hxx"
#include "Instance.hxx"
#include "Partition.hxx"
#include "protocol/Result.hxx"
#include "util/ConstBuffer.hxx"
#include <set>
...
...
@@ -35,6 +35,8 @@
CommandResult
handle_subscribe
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
assert
(
args
.
size
==
1
);
const
char
*
const
channel_name
=
args
[
0
];
...
...
@@ -43,18 +45,15 @@ handle_subscribe(Client &client, Request args)
return
CommandResult
::
OK
;
case
Client
:
:
SubscribeResult
::
INVALID
:
command_error
(
client
,
ACK_ERROR_ARG
,
"invalid channel name"
);
r
.
Error
(
ACK_ERROR_ARG
,
"invalid channel name"
);
return
CommandResult
::
ERROR
;
case
Client
:
:
SubscribeResult
::
ALREADY
:
command_error
(
client
,
ACK_ERROR_EXIST
,
"already subscribed to this channel"
);
r
.
Error
(
ACK_ERROR_EXIST
,
"already subscribed to this channel"
);
return
CommandResult
::
ERROR
;
case
Client
:
:
SubscribeResult
::
FULL
:
command_error
(
client
,
ACK_ERROR_EXIST
,
"subscription list is full"
);
r
.
Error
(
ACK_ERROR_EXIST
,
"subscription list is full"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -66,14 +65,15 @@ handle_subscribe(Client &client, Request args)
CommandResult
handle_unsubscribe
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
assert
(
args
.
size
==
1
);
const
char
*
const
channel_name
=
args
[
0
];
if
(
client
.
Unsubscribe
(
channel_name
))
return
CommandResult
::
OK
;
else
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"not subscribed to this channel"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"not subscribed to this channel"
);
return
CommandResult
::
ERROR
;
}
}
...
...
@@ -88,8 +88,9 @@ handle_channels(Client &client, gcc_unused Request args)
channels
.
insert
(
c
.
subscriptions
.
begin
(),
c
.
subscriptions
.
end
());
Response
r
(
client
);
for
(
const
auto
&
channel
:
channels
)
client_printf
(
client
,
"channel: %s
\n
"
,
channel
.
c_str
());
r
.
Format
(
"channel: %s
\n
"
,
channel
.
c_str
());
return
CommandResult
::
OK
;
}
...
...
@@ -100,11 +101,12 @@ handle_read_messages(Client &client,
{
assert
(
args
.
IsEmpty
());
Response
r
(
client
);
while
(
!
client
.
messages
.
empty
())
{
const
ClientMessage
&
msg
=
client
.
messages
.
front
();
client_printf
(
client
,
"channel: %s
\n
message: %s
\n
"
,
msg
.
GetChannel
(),
msg
.
GetMessage
());
r
.
Format
(
"channel: %s
\n
message: %s
\n
"
,
msg
.
GetChannel
(),
msg
.
GetMessage
());
client
.
messages
.
pop_front
();
}
...
...
@@ -119,9 +121,9 @@ handle_send_message(Client &client, Request args)
const
char
*
const
channel_name
=
args
[
0
];
const
char
*
const
message_text
=
args
[
1
];
Response
r
(
client
);
if
(
!
client_message_valid_channel_name
(
channel_name
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"invalid channel name"
);
r
.
Error
(
ACK_ERROR_ARG
,
"invalid channel name"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -134,8 +136,8 @@ handle_send_message(Client &client, Request args)
if
(
sent
)
return
CommandResult
::
OK
;
else
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"nobody is subscribed to this channel"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"nobody is subscribed to this channel"
);
return
CommandResult
::
ERROR
;
}
}
src/command/NeighborCommands.cxx
View file @
7652a298
...
...
@@ -21,9 +21,9 @@
#include "NeighborCommands.hxx"
#include "Request.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "Instance.hxx"
#include "Partition.hxx"
#include "protocol/Result.hxx"
#include "neighbor/Glue.hxx"
#include "neighbor/Info.hxx"
#include "util/ConstBuffer.hxx"
...
...
@@ -42,19 +42,19 @@ neighbor_commands_available(const Instance &instance)
CommandResult
handle_listneighbors
(
Client
&
client
,
gcc_unused
Request
args
)
{
Response
r
(
client
);
const
NeighborGlue
*
const
neighbors
=
client
.
partition
.
instance
.
neighbors
;
if
(
neighbors
==
nullptr
)
{
command_error
(
client
,
ACK_ERROR_UNKNOWN
,
"No neighbor plugin configured"
);
r
.
Error
(
ACK_ERROR_UNKNOWN
,
"No neighbor plugin configured"
);
return
CommandResult
::
ERROR
;
}
for
(
const
auto
&
i
:
neighbors
->
GetList
())
client_printf
(
client
,
"neighbor: %s
\n
"
"name: %s
\n
"
,
i
.
uri
.
c_str
(),
i
.
display_name
.
c_str
());
r
.
Format
(
"neighbor: %s
\n
"
"name: %s
\n
"
,
i
.
uri
.
c_str
(),
i
.
display_name
.
c_str
());
return
CommandResult
::
OK
;
}
src/command/OtherCommands.cxx
View file @
7652a298
...
...
@@ -32,7 +32,6 @@
#include "tag/TagHandler.hxx"
#include "TimePrint.hxx"
#include "decoder/DecoderPrint.hxx"
#include "protocol/Result.hxx"
#include "ls.hxx"
#include "mixer/Volume.hxx"
#include "util/UriUtil.hxx"
...
...
@@ -44,6 +43,7 @@
#include "PlaylistFile.hxx"
#include "db/PlaylistVector.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "Idle.hxx"
...
...
@@ -58,36 +58,39 @@
#include <string.h>
static
void
print_spl_list
(
Client
&
client
,
const
PlaylistVector
&
list
)
print_spl_list
(
Response
&
r
,
const
PlaylistVector
&
list
)
{
for
(
const
auto
&
i
:
list
)
{
client_printf
(
client
,
"playlist: %s
\n
"
,
i
.
name
.
c_str
());
r
.
Format
(
"playlist: %s
\n
"
,
i
.
name
.
c_str
());
if
(
i
.
mtime
>
0
)
time_print
(
client
,
"Last-Modified"
,
i
.
mtime
);
time_print
(
r
,
"Last-Modified"
,
i
.
mtime
);
}
}
CommandResult
handle_urlhandlers
(
Client
&
client
,
gcc_unused
Request
args
)
{
Response
r
(
client
);
if
(
client
.
IsLocal
())
client_puts
(
client
,
"handler: file://
\n
"
);
print_supported_uri_schemes
(
client
);
r
.
Format
(
"handler: file://
\n
"
);
print_supported_uri_schemes
(
r
);
return
CommandResult
::
OK
;
}
CommandResult
handle_decoders
(
Client
&
client
,
gcc_unused
Request
args
)
{
decoder_list_print
(
client
);
Response
r
(
client
);
decoder_list_print
(
r
);
return
CommandResult
::
OK
;
}
CommandResult
handle_tagtypes
(
Client
&
client
,
gcc_unused
Request
args
)
{
tag_print_types
(
client
);
Response
r
(
client
);
tag_print_types
(
r
);
return
CommandResult
::
OK
;
}
...
...
@@ -106,14 +109,16 @@ handle_close(gcc_unused Client &client, gcc_unused Request args)
static
void
print_tag
(
TagType
type
,
const
char
*
value
,
void
*
ctx
)
{
Client
&
client
=
*
(
Client
*
)
ctx
;
auto
&
r
=
*
(
Response
*
)
ctx
;
tag_print
(
client
,
type
,
value
);
tag_print
(
r
,
type
,
value
);
}
CommandResult
handle_listfiles
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
/* default is root directory */
const
auto
uri
=
args
.
GetOptional
(
0
,
""
);
...
...
@@ -124,7 +129,7 @@ handle_listfiles(Client &client, Request args)
#ifdef ENABLE_DATABASE
if
(
uri_has_scheme
(
uri
))
/* use storage plugin to list remote directory */
return
handle_listfiles_storage
(
client
,
uri
);
return
handle_listfiles_storage
(
r
,
uri
);
/* must be a path relative to the configured
music_directory */
...
...
@@ -132,14 +137,14 @@ handle_listfiles(Client &client, Request args)
if
(
client
.
partition
.
instance
.
storage
!=
nullptr
)
/* if we have a storage instance, obtain a list of
files from it */
return
handle_listfiles_storage
(
client
,
return
handle_listfiles_storage
(
r
,
*
client
.
partition
.
instance
.
storage
,
uri
);
/* fall back to entries from database if we have no storage */
return
handle_listfiles_db
(
client
,
uri
);
#else
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No database"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No database"
);
return
CommandResult
::
ERROR
;
#endif
}
...
...
@@ -156,42 +161,40 @@ handle_lsinfo(Client &client, Request args)
/* default is root directory */
const
auto
uri
=
args
.
GetOptional
(
0
,
""
);
Response
r
(
client
);
if
(
memcmp
(
uri
,
"file:///"
,
8
)
==
0
)
{
/* print information about an arbitrary local file */
const
char
*
path_utf8
=
uri
+
7
;
const
auto
path_fs
=
AllocatedPath
::
FromUTF8
(
path_utf8
);
if
(
path_fs
.
IsNull
())
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"unsupported file name"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"unsupported file name"
);
return
CommandResult
::
ERROR
;
}
Error
error
;
if
(
!
client
.
AllowFile
(
path_fs
,
error
))
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
DetachedSong
song
(
path_utf8
);
if
(
!
song
.
Update
())
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such file"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such file"
);
return
CommandResult
::
ERROR
;
}
song_print_info
(
client
,
song
);
song_print_info
(
r
,
client
.
partition
,
song
);
return
CommandResult
::
OK
;
}
if
(
uri_has_scheme
(
uri
))
{
if
(
!
uri_supported_scheme
(
uri
))
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"unsupported URI scheme"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"unsupported URI scheme"
);
return
CommandResult
::
ERROR
;
}
if
(
!
tag_stream_scan
(
uri
,
print_tag_handler
,
&
client
))
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such file"
);
if
(
!
tag_stream_scan
(
uri
,
print_tag_handler
,
&
r
))
{
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such file"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -207,10 +210,10 @@ handle_lsinfo(Client &client, Request args)
if
(
isRootDirectory
(
uri
))
{
Error
error
;
const
auto
&
list
=
ListPlaylistFiles
(
error
);
print_spl_list
(
client
,
list
);
print_spl_list
(
r
,
list
);
}
else
{
#ifndef ENABLE_DATABASE
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No database"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No database"
);
return
CommandResult
::
ERROR
;
#endif
}
...
...
@@ -224,13 +227,14 @@ static CommandResult
handle_update
(
Client
&
client
,
UpdateService
&
update
,
const
char
*
uri_utf8
,
bool
discard
)
{
Response
r
(
client
);
unsigned
ret
=
update
.
Enqueue
(
uri_utf8
,
discard
);
if
(
ret
>
0
)
{
client_printf
(
client
,
"updating_db: %i
\n
"
,
ret
);
r
.
Format
(
"updating_db: %i
\n
"
,
ret
);
return
CommandResult
::
OK
;
}
else
{
command_error
(
client
,
ACK_ERROR_UPDATE_ALREADY
,
"already updating"
);
r
.
Error
(
ACK_ERROR_UPDATE_ALREADY
,
"already updating"
);
return
CommandResult
::
ERROR
;
}
}
...
...
@@ -239,17 +243,19 @@ static CommandResult
handle_update
(
Client
&
client
,
Database
&
db
,
const
char
*
uri_utf8
,
bool
discard
)
{
Response
r
(
client
);
Error
error
;
unsigned
id
=
db
.
Update
(
uri_utf8
,
discard
,
error
);
if
(
id
>
0
)
{
client_printf
(
client
,
"updating_db: %i
\n
"
,
id
);
r
.
Format
(
"updating_db: %i
\n
"
,
id
);
return
CommandResult
::
OK
;
}
else
if
(
error
.
IsDefined
())
{
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
}
else
{
/* Database::Update() has returned 0 without setting
the Error: the method is not implemented */
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"Not implemented"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"Not implemented"
);
return
CommandResult
::
ERROR
;
}
}
...
...
@@ -259,6 +265,8 @@ handle_update(Client &client, Database &db,
static
CommandResult
handle_update
(
Client
&
client
,
Request
args
,
bool
discard
)
{
Response
r
(
client
);
#ifdef ENABLE_DATABASE
const
char
*
path
=
""
;
...
...
@@ -270,8 +278,7 @@ handle_update(Client &client, Request args, bool discard)
/* backwards compatibility with MPD 0.15 */
path
=
""
;
else
if
(
!
uri_safe_local
(
path
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Malformed path"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Malformed path"
);
return
CommandResult
::
ERROR
;
}
}
...
...
@@ -288,7 +295,7 @@ handle_update(Client &client, Request args, bool discard)
(
void
)
discard
;
#endif
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No database"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No database"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -307,13 +314,14 @@ handle_rescan(Client &client, gcc_unused Request args)
CommandResult
handle_setvol
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
level
;
if
(
!
args
.
Parse
(
0
,
level
,
client
,
100
))
if
(
!
args
.
Parse
(
0
,
level
,
r
,
100
))
return
CommandResult
::
ERROR
;
if
(
!
volume_level_change
(
client
.
partition
.
outputs
,
level
))
{
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"problems setting volume"
);
r
.
Error
(
ACK_ERROR_SYSTEM
,
"problems setting volume"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -323,13 +331,15 @@ handle_setvol(Client &client, Request args)
CommandResult
handle_volume
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
int
relative
;
if
(
!
args
.
Parse
(
0
,
relative
,
client
,
-
100
,
100
))
if
(
!
args
.
Parse
(
0
,
relative
,
r
,
-
100
,
100
))
return
CommandResult
::
ERROR
;
const
int
old_volume
=
volume_level_get
(
client
.
partition
.
outputs
);
if
(
old_volume
<
0
)
{
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"No mixer"
);
r
.
Error
(
ACK_ERROR_SYSTEM
,
"No mixer"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -341,8 +351,7 @@ handle_volume(Client &client, Request args)
if
(
new_volume
!=
old_volume
&&
!
volume_level_change
(
client
.
partition
.
outputs
,
new_volume
))
{
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"problems setting volume"
);
r
.
Error
(
ACK_ERROR_SYSTEM
,
"problems setting volume"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -352,7 +361,8 @@ handle_volume(Client &client, Request args)
CommandResult
handle_stats
(
Client
&
client
,
gcc_unused
Request
args
)
{
stats_print
(
client
);
Response
r
(
client
);
stats_print
(
r
,
client
.
partition
);
return
CommandResult
::
OK
;
}
...
...
@@ -365,10 +375,11 @@ handle_ping(gcc_unused Client &client, gcc_unused Request args)
CommandResult
handle_password
(
Client
&
client
,
Request
args
)
{
unsigned
permission
=
0
;
Response
r
(
client
)
;
unsigned
permission
=
0
;
if
(
getPermissionFromPassword
(
args
.
front
(),
&
permission
)
<
0
)
{
command_error
(
client
,
ACK_ERROR_PASSWORD
,
"incorrect password"
);
r
.
Error
(
ACK_ERROR_PASSWORD
,
"incorrect password"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -380,9 +391,11 @@ handle_password(Client &client, Request args)
CommandResult
handle_config
(
Client
&
client
,
gcc_unused
Request
args
)
{
Response
r
(
client
);
if
(
!
client
.
IsLocal
())
{
command_error
(
client
,
ACK_ERROR_PERMISSION
,
"Command only permitted to local clients"
);
r
.
Error
(
ACK_ERROR_PERMISSION
,
"Command only permitted to local clients"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -390,7 +403,7 @@ handle_config(Client &client, gcc_unused Request args)
const
Storage
*
storage
=
client
.
GetStorage
();
if
(
storage
!=
nullptr
)
{
const
auto
path
=
storage
->
MapUTF8
(
""
);
client_printf
(
client
,
"music_directory: %s
\n
"
,
path
.
c_str
());
r
.
Format
(
"music_directory: %s
\n
"
,
path
.
c_str
());
}
#endif
...
...
@@ -400,14 +413,14 @@ handle_config(Client &client, gcc_unused Request args)
CommandResult
handle_idle
(
Client
&
client
,
Request
args
)
{
unsigned
flags
=
0
;
Response
r
(
client
)
;
unsigned
flags
=
0
;
for
(
const
char
*
i
:
args
)
{
unsigned
event
=
idle_parse_name
(
i
);
if
(
event
==
0
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Unrecognized idle event: %s"
,
i
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Unrecognized idle event: %s"
,
i
);
return
CommandResult
::
ERROR
;
}
...
...
src/command/OutputCommands.cxx
View file @
7652a298
...
...
@@ -22,23 +22,23 @@
#include "Request.hxx"
#include "output/OutputPrint.hxx"
#include "output/OutputCommand.hxx"
#include "protocol/Result.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "Partition.hxx"
#include "util/ConstBuffer.hxx"
CommandResult
handle_enableoutput
(
Client
&
client
,
Request
args
)
{
assert
(
args
.
size
==
1
);
Response
r
(
client
);
assert
(
args
.
size
==
1
);
unsigned
device
;
if
(
!
args
.
Parse
(
0
,
device
,
client
))
if
(
!
args
.
Parse
(
0
,
device
,
r
))
return
CommandResult
::
ERROR
;
if
(
!
audio_output_enable_index
(
client
.
partition
.
outputs
,
device
))
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such audio output"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such audio output"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -48,15 +48,15 @@ handle_enableoutput(Client &client, Request args)
CommandResult
handle_disableoutput
(
Client
&
client
,
Request
args
)
{
assert
(
args
.
size
==
1
);
Response
r
(
client
);
assert
(
args
.
size
==
1
);
unsigned
device
;
if
(
!
args
.
Parse
(
0
,
device
,
client
))
if
(
!
args
.
Parse
(
0
,
device
,
r
))
return
CommandResult
::
ERROR
;
if
(
!
audio_output_disable_index
(
client
.
partition
.
outputs
,
device
))
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such audio output"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such audio output"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -66,15 +66,15 @@ handle_disableoutput(Client &client, Request args)
CommandResult
handle_toggleoutput
(
Client
&
client
,
Request
args
)
{
assert
(
args
.
size
==
1
);
Response
r
(
client
);
assert
(
args
.
size
==
1
);
unsigned
device
;
if
(
!
args
.
Parse
(
0
,
device
,
client
))
if
(
!
args
.
Parse
(
0
,
device
,
r
))
return
CommandResult
::
ERROR
;
if
(
!
audio_output_toggle_index
(
client
.
partition
.
outputs
,
device
))
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No such audio output"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No such audio output"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -86,7 +86,8 @@ handle_devices(Client &client, gcc_unused Request args)
{
assert
(
args
.
IsEmpty
());
printAudioDevices
(
client
,
client
.
partition
.
outputs
);
Response
r
(
client
);
printAudioDevices
(
r
,
client
.
partition
.
outputs
);
return
CommandResult
::
OK
;
}
src/command/PlayerCommands.cxx
View file @
7652a298
...
...
@@ -24,10 +24,10 @@
#include "queue/Playlist.hxx"
#include "PlaylistPrint.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "mixer/Volume.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "protocol/Result.hxx"
#include "AudioFormat.hxx"
#include "ReplayGainConfig.hxx"
#include "util/ConstBuffer.hxx"
...
...
@@ -59,23 +59,27 @@
CommandResult
handle_play
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
int
song
=
-
1
;
if
(
!
args
.
ParseOptional
(
0
,
song
,
client
))
if
(
!
args
.
ParseOptional
(
0
,
song
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
PlayPosition
(
song
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_playid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
int
id
=
-
1
;
if
(
!
args
.
ParseOptional
(
0
,
id
,
client
))
if
(
!
args
.
ParseOptional
(
0
,
id
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
PlayId
(
id
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
...
...
@@ -88,16 +92,19 @@ handle_stop(Client &client, gcc_unused Request args)
CommandResult
handle_currentsong
(
Client
&
client
,
gcc_unused
Request
args
)
{
playlist_print_current
(
client
,
client
.
playlist
);
Response
r
(
client
);
playlist_print_current
(
r
,
client
.
partition
,
client
.
playlist
);
return
CommandResult
::
OK
;
}
CommandResult
handle_pause
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
if
(
!
args
.
IsEmpty
())
{
bool
pause_flag
;
if
(
!
args
.
Parse
(
0
,
pause_flag
,
client
))
if
(
!
args
.
Parse
(
0
,
pause_flag
,
r
))
return
CommandResult
::
ERROR
;
client
.
player_control
.
SetPause
(
pause_flag
);
...
...
@@ -127,68 +134,64 @@ handle_status(Client &client, gcc_unused Request args)
break
;
}
Response
r
(
client
);
const
playlist
&
playlist
=
client
.
playlist
;
client_printf
(
client
,
"volume: %i
\n
"
COMMAND_STATUS_REPEAT
": %i
\n
"
COMMAND_STATUS_RANDOM
": %i
\n
"
COMMAND_STATUS_SINGLE
": %i
\n
"
COMMAND_STATUS_CONSUME
": %i
\n
"
COMMAND_STATUS_PLAYLIST
": %li
\n
"
COMMAND_STATUS_PLAYLIST_LENGTH
": %i
\n
"
COMMAND_STATUS_MIXRAMPDB
": %f
\n
"
COMMAND_STATUS_STATE
": %s
\n
"
,
volume_level_get
(
client
.
partition
.
outputs
),
playlist
.
GetRepeat
(),
playlist
.
GetRandom
(),
playlist
.
GetSingle
(),
playlist
.
GetConsume
(),
(
unsigned
long
)
playlist
.
GetVersion
(),
playlist
.
GetLength
(),
client
.
player_control
.
GetMixRampDb
(),
state
);
r
.
Format
(
"volume: %i
\n
"
COMMAND_STATUS_REPEAT
": %i
\n
"
COMMAND_STATUS_RANDOM
": %i
\n
"
COMMAND_STATUS_SINGLE
": %i
\n
"
COMMAND_STATUS_CONSUME
": %i
\n
"
COMMAND_STATUS_PLAYLIST
": %li
\n
"
COMMAND_STATUS_PLAYLIST_LENGTH
": %i
\n
"
COMMAND_STATUS_MIXRAMPDB
": %f
\n
"
COMMAND_STATUS_STATE
": %s
\n
"
,
volume_level_get
(
client
.
partition
.
outputs
),
playlist
.
GetRepeat
(),
playlist
.
GetRandom
(),
playlist
.
GetSingle
(),
playlist
.
GetConsume
(),
(
unsigned
long
)
playlist
.
GetVersion
(),
playlist
.
GetLength
(),
client
.
player_control
.
GetMixRampDb
(),
state
);
if
(
client
.
player_control
.
GetCrossFade
()
>
0
)
client_printf
(
client
,
COMMAND_STATUS_CROSSFADE
": %i
\n
"
,
int
(
client
.
player_control
.
GetCrossFade
()
+
0.5
));
r
.
Format
(
COMMAND_STATUS_CROSSFADE
": %i
\n
"
,
int
(
client
.
player_control
.
GetCrossFade
()
+
0.5
));
if
(
client
.
player_control
.
GetMixRampDelay
()
>
0
)
client_printf
(
client
,
COMMAND_STATUS_MIXRAMPDELAY
": %f
\n
"
,
client
.
player_control
.
GetMixRampDelay
());
r
.
Format
(
COMMAND_STATUS_MIXRAMPDELAY
": %f
\n
"
,
client
.
player_control
.
GetMixRampDelay
());
song
=
playlist
.
GetCurrentPosition
();
if
(
song
>=
0
)
{
client_printf
(
client
,
COMMAND_STATUS_SONG
": %i
\n
"
COMMAND_STATUS_SONGID
": %u
\n
"
,
song
,
playlist
.
PositionToId
(
song
));
r
.
Format
(
COMMAND_STATUS_SONG
": %i
\n
"
COMMAND_STATUS_SONGID
": %u
\n
"
,
song
,
playlist
.
PositionToId
(
song
));
}
if
(
player_status
.
state
!=
PlayerState
::
STOP
)
{
client_printf
(
client
,
COMMAND_STATUS_TIME
": %i:%i
\n
"
"elapsed: %1.3f
\n
"
COMMAND_STATUS_BITRATE
": %u
\n
"
,
player_status
.
elapsed_time
.
RoundS
(),
player_status
.
total_time
.
IsNegative
()
?
0u
:
unsigned
(
player_status
.
total_time
.
RoundS
()),
player_status
.
elapsed_time
.
ToDoubleS
(),
player_status
.
bit_rate
);
r
.
Format
(
COMMAND_STATUS_TIME
": %i:%i
\n
"
"elapsed: %1.3f
\n
"
COMMAND_STATUS_BITRATE
": %u
\n
"
,
player_status
.
elapsed_time
.
RoundS
(),
player_status
.
total_time
.
IsNegative
()
?
0u
:
unsigned
(
player_status
.
total_time
.
RoundS
()),
player_status
.
elapsed_time
.
ToDoubleS
(),
player_status
.
bit_rate
);
if
(
!
player_status
.
total_time
.
IsNegative
())
client_printf
(
client
,
"duration: %1.3f
\n
"
,
player_status
.
total_time
.
ToDoubleS
());
r
.
Format
(
"duration: %1.3f
\n
"
,
player_status
.
total_time
.
ToDoubleS
());
if
(
player_status
.
audio_format
.
IsDefined
())
{
struct
audio_format_string
af_string
;
client_printf
(
client
,
COMMAND_STATUS_AUDIO
": %s
\n
"
,
audio_format_to_string
(
player_status
.
audio_format
,
&
af_string
));
r
.
Format
(
COMMAND_STATUS_AUDIO
": %s
\n
"
,
audio_format_to_string
(
player_status
.
audio_format
,
&
af_string
));
}
}
...
...
@@ -198,25 +201,21 @@ handle_status(Client &client, gcc_unused Request args)
?
update_service
->
GetId
()
:
0
;
if
(
updateJobId
!=
0
)
{
client_printf
(
client
,
COMMAND_STATUS_UPDATING_DB
": %i
\n
"
,
updateJobId
);
r
.
Format
(
COMMAND_STATUS_UPDATING_DB
": %i
\n
"
,
updateJobId
);
}
#endif
Error
error
=
client
.
player_control
.
LockGetError
();
if
(
error
.
IsDefined
())
client_printf
(
client
,
COMMAND_STATUS_ERROR
": %s
\n
"
,
error
.
GetMessage
());
r
.
Format
(
COMMAND_STATUS_ERROR
": %s
\n
"
,
error
.
GetMessage
());
song
=
playlist
.
GetNextPosition
();
if
(
song
>=
0
)
{
client_printf
(
client
,
COMMAND_STATUS_NEXTSONG
": %i
\n
"
COMMAND_STATUS_NEXTSONGID
": %u
\n
"
,
song
,
playlist
.
PositionToId
(
song
));
}
if
(
song
>=
0
)
r
.
Format
(
COMMAND_STATUS_NEXTSONG
": %i
\n
"
COMMAND_STATUS_NEXTSONGID
": %u
\n
"
,
song
,
playlist
.
PositionToId
(
song
));
return
CommandResult
::
OK
;
}
...
...
@@ -247,8 +246,10 @@ handle_previous(Client &client, gcc_unused Request args)
CommandResult
handle_repeat
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
bool
status
;
if
(
!
args
.
Parse
(
0
,
status
,
client
))
if
(
!
args
.
Parse
(
0
,
status
,
r
))
return
CommandResult
::
ERROR
;
client
.
partition
.
SetRepeat
(
status
);
...
...
@@ -258,8 +259,10 @@ handle_repeat(Client &client, Request args)
CommandResult
handle_single
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
bool
status
;
if
(
!
args
.
Parse
(
0
,
status
,
client
))
if
(
!
args
.
Parse
(
0
,
status
,
r
))
return
CommandResult
::
ERROR
;
client
.
partition
.
SetSingle
(
status
);
...
...
@@ -269,8 +272,10 @@ handle_single(Client &client, Request args)
CommandResult
handle_consume
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
bool
status
;
if
(
!
args
.
Parse
(
0
,
status
,
client
))
if
(
!
args
.
Parse
(
0
,
status
,
r
))
return
CommandResult
::
ERROR
;
client
.
partition
.
SetConsume
(
status
);
...
...
@@ -280,8 +285,10 @@ handle_consume(Client &client, Request args)
CommandResult
handle_random
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
bool
status
;
if
(
!
args
.
Parse
(
0
,
status
,
client
))
if
(
!
args
.
Parse
(
0
,
status
,
r
))
return
CommandResult
::
ERROR
;
client
.
partition
.
SetRandom
(
status
);
...
...
@@ -299,53 +306,58 @@ handle_clearerror(gcc_unused Client &client, gcc_unused Request args)
CommandResult
handle_seek
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
song
;
SongTime
seek_time
;
if
(
!
args
.
Parse
(
0
,
song
,
client
))
return
CommandResult
::
ERROR
;
if
(
!
args
.
Parse
(
1
,
seek_time
,
client
))
if
(
!
args
.
Parse
(
0
,
song
,
r
)
||
!
args
.
Parse
(
1
,
seek_time
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
SeekSongPosition
(
song
,
seek_time
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_seekid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
id
;
SongTime
seek_time
;
if
(
!
args
.
Parse
(
0
,
id
,
client
))
if
(
!
args
.
Parse
(
0
,
id
,
r
))
return
CommandResult
::
ERROR
;
if
(
!
args
.
Parse
(
1
,
seek_time
,
client
))
if
(
!
args
.
Parse
(
1
,
seek_time
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
SeekSongId
(
id
,
seek_time
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_seekcur
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
p
=
args
.
front
();
bool
relative
=
*
p
==
'+'
||
*
p
==
'-'
;
SignedSongTime
seek_time
;
if
(
!
ParseCommandArg
(
client
,
seek_time
,
p
))
if
(
!
ParseCommandArg
(
r
,
seek_time
,
p
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
SeekCurrent
(
seek_time
,
relative
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_crossfade
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
xfade_time
;
if
(
!
args
.
Parse
(
0
,
xfade_time
,
client
))
if
(
!
args
.
Parse
(
0
,
xfade_time
,
r
))
return
CommandResult
::
ERROR
;
client
.
player_control
.
SetCrossFade
(
xfade_time
);
...
...
@@ -355,8 +367,10 @@ handle_crossfade(Client &client, Request args)
CommandResult
handle_mixrampdb
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
float
db
;
if
(
!
args
.
Parse
(
0
,
db
,
client
))
if
(
!
args
.
Parse
(
0
,
db
,
r
))
return
CommandResult
::
ERROR
;
client
.
player_control
.
SetMixRampDb
(
db
);
...
...
@@ -366,8 +380,10 @@ handle_mixrampdb(Client &client, Request args)
CommandResult
handle_mixrampdelay
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
float
delay_secs
;
if
(
!
args
.
Parse
(
0
,
delay_secs
,
client
))
if
(
!
args
.
Parse
(
0
,
delay_secs
,
r
))
return
CommandResult
::
ERROR
;
client
.
player_control
.
SetMixRampDelay
(
delay_secs
);
...
...
@@ -378,9 +394,10 @@ handle_mixrampdelay(Client &client, Request args)
CommandResult
handle_replay_gain_mode
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
if
(
!
replay_gain_set_mode_string
(
args
.
front
()))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Unrecognized replay gain mode"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Unrecognized replay gain mode"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -391,7 +408,7 @@ handle_replay_gain_mode(Client &client, Request args)
CommandResult
handle_replay_gain_status
(
Client
&
client
,
gcc_unused
Request
args
)
{
client_printf
(
client
,
"replay_gain_mode: %s
\n
"
,
replay_gain_get_mode_string
());
Response
r
(
client
);
r
.
Format
(
"replay_gain_mode: %s
\n
"
,
replay_gain_get_mode_string
());
return
CommandResult
::
OK
;
}
src/command/PlaylistCommands.cxx
View file @
7652a298
...
...
@@ -33,7 +33,7 @@
#include "queue/Playlist.hxx"
#include "TimePrint.hxx"
#include "client/Client.hxx"
#include "
protocol/Result
.hxx"
#include "
client/Response
.hxx"
#include "ls.hxx"
#include "Mapper.hxx"
#include "fs/AllocatedPath.hxx"
...
...
@@ -48,30 +48,33 @@ playlist_commands_available()
}
static
void
print_spl_list
(
Client
&
client
,
const
PlaylistVector
&
list
)
print_spl_list
(
Response
&
r
,
const
PlaylistVector
&
list
)
{
for
(
const
auto
&
i
:
list
)
{
client_printf
(
client
,
"playlist: %s
\n
"
,
i
.
name
.
c_str
());
r
.
Format
(
"playlist: %s
\n
"
,
i
.
name
.
c_str
());
if
(
i
.
mtime
>
0
)
time_print
(
client
,
"Last-Modified"
,
i
.
mtime
);
time_print
(
r
,
"Last-Modified"
,
i
.
mtime
);
}
}
CommandResult
handle_save
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
Error
error
;
return
spl_save_playlist
(
args
.
front
(),
client
.
playlist
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_load
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
RangeArg
range
=
RangeArg
::
All
();
if
(
!
args
.
ParseOptional
(
1
,
range
,
client
))
if
(
!
args
.
ParseOptional
(
1
,
range
,
r
))
return
CommandResult
::
ERROR
;
const
ScopeBulkEdit
bulk_edit
(
client
.
partition
);
...
...
@@ -82,7 +85,7 @@ handle_load(Client &client, Request args)
range
.
start
,
range
.
end
,
client
.
playlist
,
client
.
player_control
,
loader
,
error
))
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
...
...
@@ -90,97 +93,114 @@ handle_load(Client &client, Request args)
CommandResult
handle_listplaylist
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
name
=
args
.
front
();
if
(
playlist_file_print
(
client
,
name
,
false
))
if
(
playlist_file_print
(
r
,
client
.
partition
,
SongLoader
(
client
),
name
,
false
))
return
CommandResult
::
OK
;
Error
error
;
return
spl_print
(
client
,
name
,
false
,
error
)
return
spl_print
(
r
,
client
.
partition
,
name
,
false
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_listplaylistinfo
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
name
=
args
.
front
();
if
(
playlist_file_print
(
client
,
name
,
true
))
if
(
playlist_file_print
(
r
,
client
.
partition
,
SongLoader
(
client
),
name
,
true
))
return
CommandResult
::
OK
;
Error
error
;
return
spl_print
(
client
,
name
,
true
,
error
)
return
spl_print
(
r
,
client
.
partition
,
name
,
true
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_rm
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
name
=
args
.
front
();
Error
error
;
return
spl_delete
(
name
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_rename
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
old_name
=
args
[
0
];
const
char
*
const
new_name
=
args
[
1
];
Error
error
;
return
spl_rename
(
old_name
,
new_name
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_playlistdelete
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
name
=
args
[
0
];
unsigned
from
;
if
(
!
args
.
Parse
(
1
,
from
,
client
))
if
(
!
args
.
Parse
(
1
,
from
,
r
))
return
CommandResult
::
ERROR
;
Error
error
;
return
spl_remove_index
(
name
,
from
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_playlistmove
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
name
=
args
.
front
();
unsigned
from
,
to
;
if
(
!
args
.
Parse
(
1
,
from
,
client
)
||
!
args
.
Parse
(
2
,
to
,
client
))
if
(
!
args
.
Parse
(
1
,
from
,
r
)
||
!
args
.
Parse
(
2
,
to
,
r
))
return
CommandResult
::
ERROR
;
Error
error
;
return
spl_move_index
(
name
,
from
,
to
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_playlistclear
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
name
=
args
.
front
();
Error
error
;
return
spl_clear
(
name
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
}
CommandResult
handle_playlistadd
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
playlist
=
args
[
0
];
const
char
*
const
uri
=
args
[
1
];
...
...
@@ -193,7 +213,7 @@ handle_playlistadd(Client &client, Request args)
#ifdef ENABLE_DATABASE
const
Database
*
db
=
client
.
GetDatabase
(
error
);
if
(
db
==
nullptr
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
success
=
search_add_to_playlist
(
*
db
,
*
client
.
GetStorage
(),
uri
,
playlist
,
nullptr
,
...
...
@@ -204,22 +224,23 @@ handle_playlistadd(Client &client, Request args)
}
if
(
!
success
&&
!
error
.
IsDefined
())
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"directory or file not found"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"directory or file not found"
);
return
CommandResult
::
ERROR
;
}
return
success
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
return
success
?
CommandResult
::
OK
:
print_error
(
r
,
error
);
}
CommandResult
handle_listplaylists
(
Client
&
client
,
gcc_unused
Request
args
)
{
Response
r
(
client
);
Error
error
;
const
auto
list
=
ListPlaylistFiles
(
error
);
if
(
list
.
empty
()
&&
error
.
IsDefined
())
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
print_spl_list
(
client
,
list
);
print_spl_list
(
r
,
list
);
return
CommandResult
::
OK
;
}
src/command/QueueCommands.cxx
View file @
7652a298
...
...
@@ -28,9 +28,9 @@
#include "queue/Playlist.hxx"
#include "PlaylistPrint.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "Partition.hxx"
#include "BulkEdit.hxx"
#include "protocol/Result.hxx"
#include "ls.hxx"
#include "util/ConstBuffer.hxx"
#include "util/UriUtil.hxx"
...
...
@@ -56,6 +56,8 @@ translate_uri(const char *uri)
CommandResult
handle_add
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
uri
=
args
.
front
();
if
(
memcmp
(
uri
,
"/"
,
2
)
==
0
)
/* this URI is malformed, but some clients are buggy
...
...
@@ -72,7 +74,7 @@ handle_add(Client &client, Request args)
Error
error
;
unsigned
id
=
client
.
partition
.
AppendURI
(
loader
,
uri
,
error
);
if
(
id
==
0
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
...
...
@@ -84,9 +86,9 @@ handle_add(Client &client, Request args)
Error
error
;
return
AddFromDatabase
(
client
.
partition
,
selection
,
error
)
?
CommandResult
::
OK
:
print_error
(
client
,
error
);
:
print_error
(
r
,
error
);
#else
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No database"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No database"
);
return
CommandResult
::
ERROR
;
#endif
}
...
...
@@ -94,29 +96,31 @@ handle_add(Client &client, Request args)
CommandResult
handle_addid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
const
char
*
const
uri
=
translate_uri
(
args
.
front
());
const
SongLoader
loader
(
client
);
Error
error
;
unsigned
added_id
=
client
.
partition
.
AppendURI
(
loader
,
uri
,
error
);
if
(
added_id
==
0
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
if
(
args
.
size
==
2
)
{
unsigned
to
;
if
(
!
args
.
Parse
(
1
,
to
,
client
))
if
(
!
args
.
Parse
(
1
,
to
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
MoveId
(
added_id
,
to
);
if
(
result
!=
PlaylistResult
::
SUCCESS
)
{
CommandResult
ret
=
print_playlist_result
(
client
,
result
);
print_playlist_result
(
r
,
result
);
client
.
partition
.
DeleteId
(
added_id
);
return
ret
;
}
}
client_printf
(
client
,
"Id: %u
\n
"
,
added_id
);
r
.
Format
(
"Id: %u
\n
"
,
added_id
);
return
CommandResult
::
OK
;
}
...
...
@@ -154,13 +158,15 @@ parse_time_range(const char *p, SongTime &start_r, SongTime &end_r)
CommandResult
handle_rangeid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
id
;
if
(
!
args
.
Parse
(
0
,
id
,
client
))
if
(
!
args
.
Parse
(
0
,
id
,
r
))
return
CommandResult
::
ERROR
;
SongTime
start
,
end
;
if
(
!
parse_time_range
(
args
[
1
],
start
,
end
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Bad range"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Bad range"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -168,7 +174,7 @@ handle_rangeid(Client &client, Request args)
if
(
!
client
.
partition
.
playlist
.
SetSongIdRange
(
client
.
partition
.
pc
,
id
,
start
,
end
,
error
))
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
...
...
@@ -176,37 +182,44 @@ handle_rangeid(Client &client, Request args)
CommandResult
handle_delete
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
RangeArg
range
;
if
(
!
args
.
Parse
(
0
,
range
,
client
))
if
(
!
args
.
Parse
(
0
,
range
,
r
))
return
CommandResult
::
ERROR
;
auto
result
=
client
.
partition
.
DeleteRange
(
range
.
start
,
range
.
end
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_deleteid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
id
;
if
(
!
args
.
Parse
(
0
,
id
,
client
))
if
(
!
args
.
Parse
(
0
,
id
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
DeleteId
(
id
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_playlist
(
Client
&
client
,
gcc_unused
Request
args
)
{
playlist_print_uris
(
client
,
client
.
playlist
);
Response
r
(
client
);
playlist_print_uris
(
r
,
client
.
partition
,
client
.
playlist
);
return
CommandResult
::
OK
;
}
CommandResult
handle_shuffle
(
gcc_unused
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
RangeArg
range
=
RangeArg
::
All
();
if
(
!
args
.
ParseOptional
(
0
,
range
,
client
))
if
(
!
args
.
ParseOptional
(
0
,
range
,
r
))
return
CommandResult
::
ERROR
;
client
.
partition
.
Shuffle
(
range
.
start
,
range
.
end
);
...
...
@@ -223,37 +236,42 @@ handle_clear(gcc_unused Client &client, gcc_unused Request args)
CommandResult
handle_plchanges
(
Client
&
client
,
Request
args
)
{
uint32_t
version
;
Response
r
(
client
)
;
if
(
!
check_uint32
(
client
,
&
version
,
args
.
front
()))
uint32_t
version
;
if
(
!
ParseCommandArg32
(
r
,
version
,
args
.
front
()))
return
CommandResult
::
ERROR
;
playlist_print_changes_info
(
client
,
client
.
playlist
,
version
);
playlist_print_changes_info
(
r
,
client
.
partition
,
client
.
playlist
,
version
);
return
CommandResult
::
OK
;
}
CommandResult
handle_plchangesposid
(
Client
&
client
,
Request
args
)
{
uint32_t
version
;
Response
r
(
client
)
;
if
(
!
check_uint32
(
client
,
&
version
,
args
.
front
()))
uint32_t
version
;
if
(
!
ParseCommandArg32
(
r
,
version
,
args
.
front
()))
return
CommandResult
::
ERROR
;
playlist_print_changes_position
(
client
,
client
.
playlist
,
version
);
playlist_print_changes_position
(
r
,
client
.
playlist
,
version
);
return
CommandResult
::
OK
;
}
CommandResult
handle_playlistinfo
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
RangeArg
range
=
RangeArg
::
All
();
if
(
!
args
.
ParseOptional
(
0
,
range
,
client
))
if
(
!
args
.
ParseOptional
(
0
,
range
,
r
))
return
CommandResult
::
ERROR
;
if
(
!
playlist_print_info
(
client
,
client
.
playlist
,
if
(
!
playlist_print_info
(
r
,
client
.
partition
,
client
.
playlist
,
range
.
start
,
range
.
end
))
return
print_playlist_result
(
client
,
return
print_playlist_result
(
r
,
PlaylistResult
::
BAD_RANGE
);
return
CommandResult
::
OK
;
...
...
@@ -262,17 +280,19 @@ handle_playlistinfo(Client &client, Request args)
CommandResult
handle_playlistid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
if
(
!
args
.
IsEmpty
())
{
unsigned
id
;
if
(
!
args
.
Parse
(
0
,
id
,
client
))
if
(
!
args
.
Parse
(
0
,
id
,
r
))
return
CommandResult
::
ERROR
;
bool
ret
=
playlist_print_id
(
client
,
client
.
playlist
,
id
);
bool
ret
=
playlist_print_id
(
r
,
client
.
partition
,
client
.
playlist
,
id
);
if
(
!
ret
)
return
print_playlist_result
(
client
,
PlaylistResult
::
NO_SUCH_SONG
);
return
print_playlist_result
(
r
,
PlaylistResult
::
NO_SUCH_SONG
);
}
else
{
playlist_print_info
(
client
,
client
.
playlist
,
playlist_print_info
(
r
,
client
.
partition
,
client
.
playlist
,
0
,
std
::
numeric_limits
<
unsigned
>::
max
());
}
...
...
@@ -283,13 +303,15 @@ static CommandResult
handle_playlist_match
(
Client
&
client
,
Request
args
,
bool
fold_case
)
{
Response
r
(
client
);
SongFilter
filter
;
if
(
!
filter
.
Parse
(
args
,
fold_case
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"incorrect arguments"
);
r
.
Error
(
ACK_ERROR_ARG
,
"incorrect arguments"
);
return
CommandResult
::
ERROR
;
}
playlist_print_find
(
client
,
client
.
playlist
,
filter
);
playlist_print_find
(
r
,
client
.
partition
,
client
.
playlist
,
filter
);
return
CommandResult
::
OK
;
}
...
...
@@ -308,13 +330,15 @@ handle_playlistsearch(Client &client, Request args)
CommandResult
handle_prio
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
priority
;
if
(
!
args
.
ParseShift
(
0
,
priority
,
client
,
0xff
))
if
(
!
args
.
ParseShift
(
0
,
priority
,
r
,
0xff
))
return
CommandResult
::
ERROR
;
for
(
const
char
*
i
:
args
)
{
RangeArg
range
;
if
(
!
ParseCommandArg
(
client
,
range
,
i
))
if
(
!
ParseCommandArg
(
r
,
range
,
i
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
...
...
@@ -322,7 +346,7 @@ handle_prio(Client &client, Request args)
range
.
end
,
priority
);
if
(
result
!=
PlaylistResult
::
SUCCESS
)
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
return
CommandResult
::
OK
;
...
...
@@ -331,19 +355,21 @@ handle_prio(Client &client, Request args)
CommandResult
handle_prioid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
priority
;
if
(
!
args
.
ParseShift
(
0
,
priority
,
client
,
0xff
))
if
(
!
args
.
ParseShift
(
0
,
priority
,
r
,
0xff
))
return
CommandResult
::
ERROR
;
for
(
const
char
*
i
:
args
)
{
unsigned
song_id
;
if
(
!
ParseCommandArg
(
client
,
song_id
,
i
))
if
(
!
ParseCommandArg
(
r
,
song_id
,
i
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
SetPriorityId
(
song_id
,
priority
);
if
(
result
!=
PlaylistResult
::
SUCCESS
)
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
return
CommandResult
::
OK
;
...
...
@@ -352,52 +378,56 @@ handle_prioid(Client &client, Request args)
CommandResult
handle_move
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
RangeArg
range
;
int
to
;
if
(
!
args
.
Parse
(
0
,
range
,
client
)
||
!
args
.
Parse
(
1
,
to
,
client
))
if
(
!
args
.
Parse
(
0
,
range
,
r
)
||
!
args
.
Parse
(
1
,
to
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
MoveRange
(
range
.
start
,
range
.
end
,
to
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_moveid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
id
;
int
to
;
if
(
!
args
.
Parse
(
0
,
id
,
client
)
||
!
args
.
Parse
(
1
,
to
,
client
))
if
(
!
args
.
Parse
(
0
,
id
,
r
)
||
!
args
.
Parse
(
1
,
to
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
MoveId
(
id
,
to
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_swap
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
song1
,
song2
;
if
(
!
args
.
Parse
(
0
,
song1
,
client
)
||
!
args
.
Parse
(
1
,
song2
,
client
))
if
(
!
args
.
Parse
(
0
,
song1
,
r
)
||
!
args
.
Parse
(
1
,
song2
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
SwapPositions
(
song1
,
song2
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
CommandResult
handle_swapid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
id1
,
id2
;
if
(
!
args
.
Parse
(
0
,
id1
,
client
)
||
!
args
.
Parse
(
1
,
id2
,
client
))
if
(
!
args
.
Parse
(
0
,
id1
,
r
)
||
!
args
.
Parse
(
1
,
id2
,
r
))
return
CommandResult
::
ERROR
;
PlaylistResult
result
=
client
.
partition
.
SwapIds
(
id1
,
id2
);
return
print_playlist_result
(
client
,
result
);
return
print_playlist_result
(
r
,
result
);
}
src/command/Request.hxx
View file @
7652a298
...
...
@@ -28,7 +28,7 @@
#include <assert.h>
class
Client
;
class
Response
;
class
Request
:
public
ConstBuffer
<
const
char
*>
{
typedef
ConstBuffer
<
const
char
*>
Base
;
...
...
@@ -45,26 +45,26 @@ public:
}
template
<
typename
T
,
typename
...
Args
>
bool
Parse
(
unsigned
idx
,
T
&
value_r
,
Client
&
client
,
bool
Parse
(
unsigned
idx
,
T
&
value_r
,
Response
&
r
,
Args
&&
...
args
)
{
assert
(
idx
<
size
);
return
ParseCommandArg
(
client
,
value_r
,
data
[
idx
],
return
ParseCommandArg
(
r
,
value_r
,
data
[
idx
],
std
::
forward
<
Args
>
(
args
)...);
}
template
<
typename
T
,
typename
...
Args
>
bool
ParseOptional
(
unsigned
idx
,
T
&
value_r
,
Client
&
client
,
bool
ParseOptional
(
unsigned
idx
,
T
&
value_r
,
Response
&
r
,
Args
&&
...
args
)
{
return
idx
>=
size
||
Parse
(
idx
,
value_r
,
client
,
Parse
(
idx
,
value_r
,
r
,
std
::
forward
<
Args
>
(
args
)...);
}
template
<
typename
T
,
typename
...
Args
>
bool
ParseShift
(
unsigned
idx
,
T
&
value_r
,
Client
&
client
,
bool
ParseShift
(
unsigned
idx
,
T
&
value_r
,
Response
&
r
,
Args
&&
...
args
)
{
bool
success
=
Parse
(
idx
,
value_r
,
client
,
bool
success
=
Parse
(
idx
,
value_r
,
r
,
std
::
forward
<
Args
>
(
args
)...);
shift
();
return
success
;
...
...
src/command/StickerCommands.cxx
View file @
7652a298
...
...
@@ -27,8 +27,8 @@
#include "sticker/StickerPrint.hxx"
#include "sticker/StickerDatabase.hxx"
#include "CommandError.hxx"
#include "protocol/Result.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "util/Error.hxx"
...
...
@@ -37,7 +37,8 @@
#include <string.h>
struct
sticker_song_find_data
{
Client
&
client
;
Response
&
r
;
Partition
&
partition
;
const
char
*
name
;
};
...
...
@@ -48,17 +49,17 @@ sticker_song_find_print_cb(const LightSong &song, const char *value,
struct
sticker_song_find_data
*
data
=
(
struct
sticker_song_find_data
*
)
user_data
;
song_print_uri
(
data
->
client
,
song
);
sticker_print_value
(
data
->
client
,
data
->
name
,
value
);
song_print_uri
(
data
->
r
,
data
->
partition
,
song
);
sticker_print_value
(
data
->
r
,
data
->
name
,
value
);
}
static
CommandResult
handle_sticker_song
(
Client
&
client
,
Request
args
)
handle_sticker_song
(
Response
&
r
,
Partition
&
partition
,
Request
args
)
{
Error
error
;
const
Database
*
db
=
client
.
GetDatabase
(
error
);
const
Database
*
db
=
partition
.
GetDatabase
(
error
);
if
(
db
==
nullptr
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
const
char
*
const
cmd
=
args
.
front
();
...
...
@@ -66,53 +67,52 @@ handle_sticker_song(Client &client, Request args)
if
(
args
.
size
==
4
&&
strcmp
(
cmd
,
"get"
)
==
0
)
{
const
LightSong
*
song
=
db
->
GetSong
(
args
[
2
],
error
);
if
(
song
==
nullptr
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
const
auto
value
=
sticker_song_get_value
(
*
song
,
args
[
3
],
error
);
db
->
ReturnSong
(
song
);
if
(
value
.
empty
())
{
if
(
error
.
IsDefined
())
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"no such sticker"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"no such sticker"
);
return
CommandResult
::
ERROR
;
}
sticker_print_value
(
client
,
args
[
3
],
value
.
c_str
());
sticker_print_value
(
r
,
args
[
3
],
value
.
c_str
());
return
CommandResult
::
OK
;
/* list song song_id */
}
else
if
(
args
.
size
==
3
&&
strcmp
(
cmd
,
"list"
)
==
0
)
{
const
LightSong
*
song
=
db
->
GetSong
(
args
[
2
],
error
);
if
(
song
==
nullptr
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
Sticker
*
sticker
=
sticker_song_get
(
*
song
,
error
);
db
->
ReturnSong
(
song
);
if
(
sticker
)
{
sticker_print
(
client
,
*
sticker
);
sticker_print
(
r
,
*
sticker
);
sticker_free
(
sticker
);
}
else
if
(
error
.
IsDefined
())
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
/* set song song_id id key */
}
else
if
(
args
.
size
==
5
&&
strcmp
(
cmd
,
"set"
)
==
0
)
{
const
LightSong
*
song
=
db
->
GetSong
(
args
[
2
],
error
);
if
(
song
==
nullptr
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
bool
ret
=
sticker_song_set_value
(
*
song
,
args
[
3
],
args
[
4
],
error
);
db
->
ReturnSong
(
song
);
if
(
!
ret
)
{
if
(
error
.
IsDefined
())
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"failed to set sticker value"
);
r
.
Error
(
ACK_ERROR_SYSTEM
,
"failed to set sticker value"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -122,7 +122,7 @@ handle_sticker_song(Client &client, Request args)
strcmp
(
cmd
,
"delete"
)
==
0
)
{
const
LightSong
*
song
=
db
->
GetSong
(
args
[
2
],
error
);
if
(
song
==
nullptr
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
bool
ret
=
args
.
size
==
3
?
sticker_song_delete
(
*
song
,
error
)
...
...
@@ -130,10 +130,9 @@ handle_sticker_song(Client &client, Request args)
db
->
ReturnSong
(
song
);
if
(
!
ret
)
{
if
(
error
.
IsDefined
())
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"no such sticker"
);
r
.
Error
(
ACK_ERROR_SYSTEM
,
"no such sticker"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -161,14 +160,14 @@ handle_sticker_song(Client &client, Request args)
else
if
(
strcmp
(
op_s
,
">"
)
==
0
)
op
=
StickerOperator
::
GREATER_THAN
;
else
{
command_error
(
client
,
ACK_ERROR_ARG
,
"bad operator"
);
r
.
Error
(
ACK_ERROR_ARG
,
"bad operator"
);
return
CommandResult
::
ERROR
;
}
}
struct
sticker_song_find_data
data
=
{
client
,
r
,
partition
,
args
[
3
],
};
...
...
@@ -177,16 +176,16 @@ handle_sticker_song(Client &client, Request args)
sticker_song_find_print_cb
,
&
data
,
error
))
{
if
(
error
.
IsDefined
())
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
command_error
(
client
,
ACK_ERROR_SYSTEM
,
"failed to set search sticker database"
);
r
.
Error
(
ACK_ERROR_SYSTEM
,
"failed to set search sticker database"
);
return
CommandResult
::
ERROR
;
}
return
CommandResult
::
OK
;
}
else
{
command_error
(
client
,
ACK_ERROR_ARG
,
"bad request"
);
r
.
Error
(
ACK_ERROR_ARG
,
"bad request"
);
return
CommandResult
::
ERROR
;
}
}
...
...
@@ -194,19 +193,19 @@ handle_sticker_song(Client &client, Request args)
CommandResult
handle_sticker
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
assert
(
args
.
size
>=
3
);
if
(
!
sticker_enabled
())
{
command_error
(
client
,
ACK_ERROR_UNKNOWN
,
"sticker database is disabled"
);
r
.
Error
(
ACK_ERROR_UNKNOWN
,
"sticker database is disabled"
);
return
CommandResult
::
ERROR
;
}
if
(
strcmp
(
args
[
1
],
"song"
)
==
0
)
return
handle_sticker_song
(
client
,
args
);
return
handle_sticker_song
(
r
,
client
.
partition
,
args
);
else
{
command_error
(
client
,
ACK_ERROR_ARG
,
"unknown sticker domain"
);
r
.
Error
(
ACK_ERROR_ARG
,
"unknown sticker domain"
);
return
CommandResult
::
ERROR
;
}
}
src/command/StorageCommands.cxx
View file @
7652a298
...
...
@@ -23,12 +23,12 @@
#include "StorageCommands.hxx"
#include "Request.hxx"
#include "CommandError.hxx"
#include "protocol/Result.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
#include "util/ConstBuffer.hxx"
#include "fs/Traits.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "storage/Registry.hxx"
...
...
@@ -57,7 +57,7 @@ skip_path(const char *name_utf8)
#endif
static
bool
handle_listfiles_storage
(
Client
&
client
,
StorageDirectoryReader
&
reader
,
handle_listfiles_storage
(
Response
&
r
,
StorageDirectoryReader
&
reader
,
Error
&
error
)
{
const
char
*
name_utf8
;
...
...
@@ -75,19 +75,19 @@ handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
continue
;
case
StorageFileInfo
:
:
Type
::
REGULAR
:
client_printf
(
client
,
"file: %s
\n
"
"size: %"
PRIu64
"
\n
"
,
name_utf8
,
info
.
size
);
r
.
Format
(
"file: %s
\n
"
"size: %"
PRIu64
"
\n
"
,
name_utf8
,
info
.
size
);
break
;
case
StorageFileInfo
:
:
Type
::
DIRECTORY
:
client_printf
(
client
,
"directory: %s
\n
"
,
name_utf8
);
r
.
Format
(
"directory: %s
\n
"
,
name_utf8
);
break
;
}
if
(
info
.
mtime
!=
0
)
time_print
(
client
,
"Last-Modified"
,
info
.
mtime
);
time_print
(
r
,
"Last-Modified"
,
info
.
mtime
);
}
return
true
;
...
...
@@ -98,52 +98,51 @@ handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
#endif
static
bool
handle_listfiles_storage
(
Client
&
client
,
Storage
&
storage
,
const
char
*
uri
,
handle_listfiles_storage
(
Response
&
r
,
Storage
&
storage
,
const
char
*
uri
,
Error
&
error
)
{
auto
reader
=
storage
.
OpenDirectory
(
uri
,
error
);
if
(
reader
==
nullptr
)
return
false
;
bool
success
=
handle_listfiles_storage
(
client
,
*
reader
,
error
);
bool
success
=
handle_listfiles_storage
(
r
,
*
reader
,
error
);
delete
reader
;
return
success
;
}
CommandResult
handle_listfiles_storage
(
Client
&
client
,
Storage
&
storage
,
const
char
*
uri
)
handle_listfiles_storage
(
Response
&
r
,
Storage
&
storage
,
const
char
*
uri
)
{
Error
error
;
if
(
!
handle_listfiles_storage
(
client
,
storage
,
uri
,
error
))
return
print_error
(
client
,
error
);
if
(
!
handle_listfiles_storage
(
r
,
storage
,
uri
,
error
))
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
CommandResult
handle_listfiles_storage
(
Client
&
client
,
const
char
*
uri
)
handle_listfiles_storage
(
Response
&
r
,
const
char
*
uri
)
{
Error
error
;
Storage
*
storage
=
CreateStorageURI
(
io_thread_get
(),
uri
,
error
);
if
(
storage
==
nullptr
)
{
if
(
error
.
IsDefined
())
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
command_error
(
client
,
ACK_ERROR_ARG
,
"Unrecognized storage URI"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Unrecognized storage URI"
);
return
CommandResult
::
ERROR
;
}
bool
success
=
handle_listfiles_storage
(
client
,
*
storage
,
""
,
error
);
bool
success
=
handle_listfiles_storage
(
r
,
*
storage
,
""
,
error
);
delete
storage
;
if
(
!
success
)
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
static
void
print_storage_uri
(
Client
&
client
,
const
Storage
&
storage
)
print_storage_uri
(
Client
&
client
,
Response
&
r
,
const
Storage
&
storage
)
{
std
::
string
uri
=
storage
.
MapUTF8
(
""
);
if
(
uri
.
empty
())
...
...
@@ -165,24 +164,26 @@ print_storage_uri(Client &client, const Storage &storage)
uri
=
std
::
move
(
allocated
);
}
client_printf
(
client
,
"storage: %s
\n
"
,
uri
.
c_str
());
r
.
Format
(
"storage: %s
\n
"
,
uri
.
c_str
());
}
CommandResult
handle_listmounts
(
Client
&
client
,
gcc_unused
Request
args
)
{
Response
r
(
client
);
Storage
*
_composite
=
client
.
partition
.
instance
.
storage
;
if
(
_composite
==
nullptr
)
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No database"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No database"
);
return
CommandResult
::
ERROR
;
}
CompositeStorage
&
composite
=
*
(
CompositeStorage
*
)
_composite
;
const
auto
visitor
=
[
&
client
](
const
char
*
mount_uri
,
const
Storage
&
storage
){
client_printf
(
client
,
"mount: %s
\n
"
,
mount_uri
);
print_storage_uri
(
client
,
storage
);
const
auto
visitor
=
[
&
client
,
&
r
](
const
char
*
mount_uri
,
const
Storage
&
storage
){
r
.
Format
(
"mount: %s
\n
"
,
mount_uri
);
print_storage_uri
(
client
,
r
,
storage
);
};
composite
.
VisitMounts
(
visitor
);
...
...
@@ -193,9 +194,11 @@ handle_listmounts(Client &client, gcc_unused Request args)
CommandResult
handle_mount
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
Storage
*
_composite
=
client
.
partition
.
instance
.
storage
;
if
(
_composite
==
nullptr
)
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No database"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No database"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -205,7 +208,7 @@ handle_mount(Client &client, Request args)
const
char
*
const
remote_uri
=
args
[
1
];
if
(
*
local_uri
==
0
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Bad mount point"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Bad mount point"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -215,7 +218,7 @@ handle_mount(Client &client, Request args)
UpdateQueue::Erase() really gets called for every
unmount, and no Directory disappears recursively
during database update */
command_error
(
client
,
ACK_ERROR_ARG
,
"Bad mount point"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Bad mount point"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -224,10 +227,9 @@ handle_mount(Client &client, Request args)
error
);
if
(
storage
==
nullptr
)
{
if
(
error
.
IsDefined
())
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
command_error
(
client
,
ACK_ERROR_ARG
,
"Unrecognized storage URI"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Unrecognized storage URI"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -241,7 +243,7 @@ handle_mount(Client &client, Request args)
if
(
!
db
.
Mount
(
local_uri
,
remote_uri
,
error
))
{
composite
.
Unmount
(
local_uri
);
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
}
// TODO: call Instance::OnDatabaseModified()?
...
...
@@ -256,9 +258,11 @@ handle_mount(Client &client, Request args)
CommandResult
handle_unmount
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
Storage
*
_composite
=
client
.
partition
.
instance
.
storage
;
if
(
_composite
==
nullptr
)
{
command_error
(
client
,
ACK_ERROR_NO_EXIST
,
"No database"
);
r
.
Error
(
ACK_ERROR_NO_EXIST
,
"No database"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -267,7 +271,7 @@ handle_unmount(Client &client, Request args)
const
char
*
const
local_uri
=
args
.
front
();
if
(
*
local_uri
==
0
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Bad mount point"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Bad mount point"
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -289,7 +293,7 @@ handle_unmount(Client &client, Request args)
#endif
if
(
!
composite
.
Unmount
(
local_uri
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Not a mount point"
);
r
.
Error
(
ACK_ERROR_ARG
,
"Not a mount point"
);
return
CommandResult
::
ERROR
;
}
...
...
src/command/StorageCommands.hxx
View file @
7652a298
...
...
@@ -25,12 +25,13 @@
class
Client
;
class
Storage
;
class
Request
;
class
Response
;
CommandResult
handle_listfiles_storage
(
Client
&
client
,
Storage
&
storage
,
const
char
*
uri
);
handle_listfiles_storage
(
Response
&
r
,
Storage
&
storage
,
const
char
*
uri
);
CommandResult
handle_listfiles_storage
(
Client
&
client
,
const
char
*
uri
);
handle_listfiles_storage
(
Response
&
r
,
const
char
*
uri
);
CommandResult
handle_listmounts
(
Client
&
client
,
Request
args
);
...
...
src/command/TagCommands.cxx
View file @
7652a298
...
...
@@ -22,7 +22,7 @@
#include "Request.hxx"
#include "CommandError.hxx"
#include "client/Client.hxx"
#include "
protocol/Result
.hxx"
#include "
client/Response
.hxx"
#include "tag/Tag.hxx"
#include "Partition.hxx"
#include "util/ConstBuffer.hxx"
...
...
@@ -30,15 +30,16 @@
CommandResult
handle_addtagid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
song_id
;
if
(
!
args
.
Parse
(
0
,
song_id
,
client
))
if
(
!
args
.
Parse
(
0
,
song_id
,
r
))
return
CommandResult
::
ERROR
;
const
char
*
const
tag_name
=
args
[
1
];
const
TagType
tag_type
=
tag_name_parse_i
(
tag_name
);
if
(
tag_type
==
TAG_NUM_OF_ITEM_TYPES
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Unknown tag type: %s"
,
tag_name
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Unknown tag type: %s"
,
tag_name
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -47,7 +48,7 @@ handle_addtagid(Client &client, Request args)
Error
error
;
if
(
!
client
.
partition
.
playlist
.
AddSongIdTag
(
song_id
,
tag_type
,
value
,
error
))
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
...
...
@@ -55,8 +56,10 @@ handle_addtagid(Client &client, Request args)
CommandResult
handle_cleartagid
(
Client
&
client
,
Request
args
)
{
Response
r
(
client
);
unsigned
song_id
;
if
(
!
args
.
Parse
(
0
,
song_id
,
client
))
if
(
!
args
.
Parse
(
0
,
song_id
,
r
))
return
CommandResult
::
ERROR
;
TagType
tag_type
=
TAG_NUM_OF_ITEM_TYPES
;
...
...
@@ -64,7 +67,7 @@ handle_cleartagid(Client &client, Request args)
const
char
*
const
tag_name
=
args
[
1
];
tag_type
=
tag_name_parse_i
(
tag_name
);
if
(
tag_type
==
TAG_NUM_OF_ITEM_TYPES
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Unknown tag type: %s"
,
tag_name
);
return
CommandResult
::
ERROR
;
}
...
...
@@ -73,7 +76,7 @@ handle_cleartagid(Client &client, Request args)
Error
error
;
if
(
!
client
.
partition
.
playlist
.
ClearSongIdTag
(
song_id
,
tag_type
,
error
))
return
print_error
(
client
,
error
);
return
print_error
(
r
,
error
);
return
CommandResult
::
OK
;
}
src/db/Count.cxx
View file @
7652a298
...
...
@@ -21,7 +21,8 @@
#include "Count.hxx"
#include "Selection.hxx"
#include "Interface.hxx"
#include "client/Client.hxx"
#include "Partition.hxx"
#include "client/Response.hxx"
#include "LightSong.hxx"
#include "tag/Tag.hxx"
...
...
@@ -40,26 +41,24 @@ class TagCountMap : public std::map<std::string, SearchStats> {
};
static
void
PrintSearchStats
(
Client
&
client
,
const
SearchStats
&
stats
)
PrintSearchStats
(
Response
&
r
,
const
SearchStats
&
stats
)
{
unsigned
total_duration_s
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
seconds
>
(
stats
.
total_duration
).
count
();
client_printf
(
client
,
"songs: %u
\n
"
"playtime: %u
\n
"
,
stats
.
n_songs
,
total_duration_s
);
r
.
Format
(
"songs: %u
\n
"
"playtime: %u
\n
"
,
stats
.
n_songs
,
total_duration_s
);
}
static
void
Print
(
Client
&
client
,
TagType
group
,
const
TagCountMap
&
m
)
Print
(
Response
&
r
,
TagType
group
,
const
TagCountMap
&
m
)
{
assert
(
unsigned
(
group
)
<
TAG_NUM_OF_ITEM_TYPES
);
for
(
const
auto
&
i
:
m
)
{
client_printf
(
client
,
"%s: %s
\n
"
,
tag_item_names
[
group
],
i
.
first
.
c_str
());
PrintSearchStats
(
client
,
i
.
second
);
r
.
Format
(
"%s: %s
\n
"
,
tag_item_names
[
group
],
i
.
first
.
c_str
());
PrintSearchStats
(
r
,
i
.
second
);
}
}
...
...
@@ -109,12 +108,12 @@ GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
}
bool
PrintSongCount
(
Client
&
client
,
const
char
*
name
,
PrintSongCount
(
Response
&
r
,
const
Partition
&
partition
,
const
char
*
name
,
const
SongFilter
*
filter
,
TagType
group
,
Error
&
error
)
{
const
Database
*
db
=
client
.
GetDatabase
(
error
);
const
Database
*
db
=
partition
.
GetDatabase
(
error
);
if
(
db
==
nullptr
)
return
false
;
...
...
@@ -131,7 +130,7 @@ PrintSongCount(Client &client, const char *name,
if
(
!
db
->
Visit
(
selection
,
f
,
error
))
return
false
;
PrintSearchStats
(
client
,
stats
);
PrintSearchStats
(
r
,
stats
);
}
else
{
/* group by the specified tag: store counts in a
std::map */
...
...
@@ -144,7 +143,7 @@ PrintSongCount(Client &client, const char *name,
if
(
!
db
->
Visit
(
selection
,
f
,
error
))
return
false
;
Print
(
client
,
group
,
map
);
Print
(
r
,
group
,
map
);
}
return
true
;
...
...
src/db/Count.hxx
View file @
7652a298
...
...
@@ -25,13 +25,14 @@
#include <stdint.h>
enum
TagType
:
uint8_t
;
class
Client
;
struct
Partition
;
class
Response
;
class
SongFilter
;
class
Error
;
gcc_nonnull
(
2
)
gcc_nonnull
(
3
)
bool
PrintSongCount
(
Client
&
client
,
const
char
*
name
,
PrintSongCount
(
Response
&
r
,
const
Partition
&
partition
,
const
char
*
name
,
const
SongFilter
*
filter
,
TagType
group
,
Error
&
error
);
...
...
src/db/DatabasePrint.cxx
View file @
7652a298
...
...
@@ -24,6 +24,8 @@
#include "SongPrint.hxx"
#include "TimePrint.hxx"
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "Partition.hxx"
#include "tag/Tag.hxx"
#include "LightSong.hxx"
#include "LightDirectory.hxx"
...
...
@@ -42,116 +44,119 @@ ApplyBaseFlag(const char *uri, bool base)
}
static
void
PrintDirectoryURI
(
Client
&
client
,
bool
base
,
const
LightDirectory
&
directory
)
PrintDirectoryURI
(
Response
&
r
,
bool
base
,
const
LightDirectory
&
directory
)
{
client_printf
(
client
,
"directory: %s
\n
"
,
ApplyBaseFlag
(
directory
.
GetPath
(),
base
));
r
.
Format
(
"directory: %s
\n
"
,
ApplyBaseFlag
(
directory
.
GetPath
(),
base
));
}
static
bool
PrintDirectoryBrief
(
Client
&
client
,
bool
base
,
const
LightDirectory
&
directory
)
PrintDirectoryBrief
(
Response
&
r
,
bool
base
,
const
LightDirectory
&
directory
)
{
if
(
!
directory
.
IsRoot
())
PrintDirectoryURI
(
client
,
base
,
directory
);
PrintDirectoryURI
(
r
,
base
,
directory
);
return
true
;
}
static
bool
PrintDirectoryFull
(
Client
&
client
,
bool
base
,
const
LightDirectory
&
directory
)
PrintDirectoryFull
(
Response
&
r
,
bool
base
,
const
LightDirectory
&
directory
)
{
if
(
!
directory
.
IsRoot
())
{
PrintDirectoryURI
(
client
,
base
,
directory
);
PrintDirectoryURI
(
r
,
base
,
directory
);
if
(
directory
.
mtime
>
0
)
time_print
(
client
,
"Last-Modified"
,
directory
.
mtime
);
time_print
(
r
,
"Last-Modified"
,
directory
.
mtime
);
}
return
true
;
}
static
void
print_playlist_in_directory
(
Client
&
client
,
bool
base
,
print_playlist_in_directory
(
Response
&
r
,
bool
base
,
const
char
*
directory
,
const
char
*
name_utf8
)
{
if
(
base
||
directory
==
nullptr
)
client_printf
(
client
,
"playlist: %s
\n
"
,
ApplyBaseFlag
(
name_utf8
,
base
));
r
.
Format
(
"playlist: %s
\n
"
,
ApplyBaseFlag
(
name_utf8
,
base
));
else
client_printf
(
client
,
"playlist: %s/%s
\n
"
,
directory
,
name_utf8
);
r
.
Format
(
"playlist: %s/%s
\n
"
,
directory
,
name_utf8
);
}
static
void
print_playlist_in_directory
(
Client
&
client
,
bool
base
,
print_playlist_in_directory
(
Response
&
r
,
bool
base
,
const
LightDirectory
*
directory
,
const
char
*
name_utf8
)
{
if
(
base
||
directory
==
nullptr
||
directory
->
IsRoot
())
client_printf
(
client
,
"playlist: %s
\n
"
,
name_utf8
);
r
.
Format
(
"playlist: %s
\n
"
,
name_utf8
);
else
client_printf
(
client
,
"playlist: %s/%s
\n
"
,
directory
->
GetPath
(),
name_utf8
);
r
.
Format
(
"playlist: %s/%s
\n
"
,
directory
->
GetPath
(),
name_utf8
);
}
static
bool
PrintSongBrief
(
Client
&
client
,
bool
base
,
const
LightSong
&
song
)
PrintSongBrief
(
Response
&
r
,
Partition
&
partition
,
bool
base
,
const
LightSong
&
song
)
{
song_print_uri
(
client
,
song
,
base
);
song_print_uri
(
r
,
partition
,
song
,
base
);
if
(
song
.
tag
->
has_playlist
)
/* this song file has an embedded CUE sheet */
print_playlist_in_directory
(
client
,
base
,
print_playlist_in_directory
(
r
,
base
,
song
.
directory
,
song
.
uri
);
return
true
;
}
static
bool
PrintSongFull
(
Client
&
client
,
bool
base
,
const
LightSong
&
song
)
PrintSongFull
(
Response
&
r
,
Partition
&
partition
,
bool
base
,
const
LightSong
&
song
)
{
song_print_info
(
client
,
song
,
base
);
song_print_info
(
r
,
partition
,
song
,
base
);
if
(
song
.
tag
->
has_playlist
)
/* this song file has an embedded CUE sheet */
print_playlist_in_directory
(
client
,
base
,
print_playlist_in_directory
(
r
,
base
,
song
.
directory
,
song
.
uri
);
return
true
;
}
static
bool
PrintPlaylistBrief
(
Client
&
client
,
bool
base
,
PrintPlaylistBrief
(
Response
&
r
,
bool
base
,
const
PlaylistInfo
&
playlist
,
const
LightDirectory
&
directory
)
{
print_playlist_in_directory
(
client
,
base
,
print_playlist_in_directory
(
r
,
base
,
&
directory
,
playlist
.
name
.
c_str
());
return
true
;
}
static
bool
PrintPlaylistFull
(
Client
&
client
,
bool
base
,
PrintPlaylistFull
(
Response
&
r
,
bool
base
,
const
PlaylistInfo
&
playlist
,
const
LightDirectory
&
directory
)
{
print_playlist_in_directory
(
client
,
base
,
print_playlist_in_directory
(
r
,
base
,
&
directory
,
playlist
.
name
.
c_str
());
if
(
playlist
.
mtime
>
0
)
time_print
(
client
,
"Last-Modified"
,
playlist
.
mtime
);
time_print
(
r
,
"Last-Modified"
,
playlist
.
mtime
);
return
true
;
}
bool
db_selection_print
(
Client
&
client
,
const
DatabaseSelection
&
selection
,
db_selection_print
(
Response
&
r
,
Partition
&
partition
,
const
DatabaseSelection
&
selection
,
bool
full
,
bool
base
,
unsigned
window_start
,
unsigned
window_end
,
Error
&
error
)
{
const
Database
*
db
=
client
.
GetDatabase
(
error
);
const
Database
*
db
=
partition
.
GetDatabase
(
error
);
if
(
db
==
nullptr
)
return
false
;
...
...
@@ -160,13 +165,13 @@ db_selection_print(Client &client, const DatabaseSelection &selection,
using
namespace
std
::
placeholders
;
const
auto
d
=
selection
.
filter
==
nullptr
?
std
::
bind
(
full
?
PrintDirectoryFull
:
PrintDirectoryBrief
,
std
::
ref
(
client
),
base
,
_1
)
std
::
ref
(
r
),
base
,
_1
)
:
VisitDirectory
();
VisitSong
s
=
std
::
bind
(
full
?
PrintSongFull
:
PrintSongBrief
,
std
::
ref
(
client
),
base
,
_1
);
std
::
ref
(
r
),
std
::
ref
(
partition
),
base
,
_1
);
const
auto
p
=
selection
.
filter
==
nullptr
?
std
::
bind
(
full
?
PrintPlaylistFull
:
PrintPlaylistBrief
,
std
::
ref
(
client
),
base
,
_1
,
_2
)
std
::
ref
(
r
),
base
,
_1
,
_2
)
:
VisitPlaylist
();
if
(
window_start
>
0
||
...
...
@@ -182,45 +187,47 @@ db_selection_print(Client &client, const DatabaseSelection &selection,
}
bool
db_selection_print
(
Client
&
client
,
const
DatabaseSelection
&
selection
,
db_selection_print
(
Response
&
r
,
Partition
&
partition
,
const
DatabaseSelection
&
selection
,
bool
full
,
bool
base
,
Error
&
error
)
{
return
db_selection_print
(
client
,
selection
,
full
,
base
,
return
db_selection_print
(
r
,
partition
,
selection
,
full
,
base
,
0
,
std
::
numeric_limits
<
int
>::
max
(),
error
);
}
static
bool
PrintSongURIVisitor
(
Client
&
client
,
const
LightSong
&
song
)
PrintSongURIVisitor
(
Response
&
r
,
Partition
&
partition
,
const
LightSong
&
song
)
{
song_print_uri
(
client
,
song
);
song_print_uri
(
r
,
partition
,
song
);
return
true
;
}
static
bool
PrintUniqueTag
(
Client
&
client
,
TagType
tag_type
,
PrintUniqueTag
(
Response
&
r
,
TagType
tag_type
,
const
Tag
&
tag
)
{
const
char
*
value
=
tag
.
GetValue
(
tag_type
);
assert
(
value
!=
nullptr
);
client_printf
(
client
,
"%s: %s
\n
"
,
tag_item_names
[
tag_type
],
value
);
r
.
Format
(
"%s: %s
\n
"
,
tag_item_names
[
tag_type
],
value
);
for
(
const
auto
&
item
:
tag
)
if
(
item
.
type
!=
tag_type
)
client_printf
(
client
,
"%s: %s
\n
"
,
tag_item_names
[
item
.
type
],
item
.
value
);
r
.
Format
(
"%s: %s
\n
"
,
tag_item_names
[
item
.
type
],
item
.
value
);
return
true
;
}
bool
PrintUniqueTags
(
Client
&
client
,
unsigned
type
,
uint32_t
group_mask
,
PrintUniqueTags
(
Response
&
r
,
Partition
&
partition
,
unsigned
type
,
uint32_t
group_mask
,
const
SongFilter
*
filter
,
Error
&
error
)
{
const
Database
*
db
=
client
.
GetDatabase
(
error
);
const
Database
*
db
=
partition
.
GetDatabase
(
error
);
if
(
db
==
nullptr
)
return
false
;
...
...
@@ -229,13 +236,13 @@ PrintUniqueTags(Client &client, unsigned type, uint32_t group_mask,
if
(
type
==
LOCATE_TAG_FILE_TYPE
)
{
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
PrintSongURIVisitor
,
std
::
ref
(
client
),
_1
);
std
::
ref
(
r
),
std
::
ref
(
partition
),
_1
);
return
db
->
Visit
(
selection
,
f
,
error
);
}
else
{
assert
(
type
<
TAG_NUM_OF_ITEM_TYPES
);
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
PrintUniqueTag
,
std
::
ref
(
client
),
const
auto
f
=
std
::
bind
(
PrintUniqueTag
,
std
::
ref
(
r
),
(
TagType
)
type
,
_1
);
return
db
->
VisitUniqueTags
(
selection
,
(
TagType
)
type
,
group_mask
,
...
...
src/db/DatabasePrint.hxx
View file @
7652a298
...
...
@@ -26,7 +26,9 @@
class
SongFilter
;
struct
DatabaseSelection
;
struct
Partition
;
class
Client
;
class
Response
;
class
Error
;
/**
...
...
@@ -34,17 +36,20 @@ class Error;
* @param base print only base name of songs/directories?
*/
bool
db_selection_print
(
Client
&
client
,
const
DatabaseSelection
&
selection
,
db_selection_print
(
Response
&
r
,
Partition
&
partition
,
const
DatabaseSelection
&
selection
,
bool
full
,
bool
base
,
Error
&
error
);
bool
db_selection_print
(
Client
&
client
,
const
DatabaseSelection
&
selection
,
db_selection_print
(
Response
&
r
,
Partition
&
partition
,
const
DatabaseSelection
&
selection
,
bool
full
,
bool
base
,
unsigned
window_start
,
unsigned
window_end
,
Error
&
error
);
bool
PrintUniqueTags
(
Client
&
client
,
unsigned
type
,
uint32_t
group_mask
,
PrintUniqueTags
(
Response
&
r
,
Partition
&
partition
,
unsigned
type
,
uint32_t
group_mask
,
const
SongFilter
*
filter
,
Error
&
error
);
...
...
src/decoder/DecoderPrint.cxx
View file @
7652a298
...
...
@@ -21,35 +21,35 @@
#include "DecoderPrint.hxx"
#include "DecoderList.hxx"
#include "DecoderPlugin.hxx"
#include "client/
Client
.hxx"
#include "client/
Response
.hxx"
#include <functional>
#include <assert.h>
static
void
decoder_plugin_print
(
Client
&
client
,
decoder_plugin_print
(
Response
&
r
,
const
DecoderPlugin
&
plugin
)
{
const
char
*
const
*
p
;
assert
(
plugin
.
name
!=
nullptr
);
client_printf
(
client
,
"plugin: %s
\n
"
,
plugin
.
name
);
r
.
Format
(
"plugin: %s
\n
"
,
plugin
.
name
);
if
(
plugin
.
suffixes
!=
nullptr
)
for
(
p
=
plugin
.
suffixes
;
*
p
!=
nullptr
;
++
p
)
client_printf
(
client
,
"suffix: %s
\n
"
,
*
p
);
r
.
Format
(
"suffix: %s
\n
"
,
*
p
);
if
(
plugin
.
mime_types
!=
nullptr
)
for
(
p
=
plugin
.
mime_types
;
*
p
!=
nullptr
;
++
p
)
client_printf
(
client
,
"mime_type: %s
\n
"
,
*
p
);
r
.
Format
(
"mime_type: %s
\n
"
,
*
p
);
}
void
decoder_list_print
(
Client
&
client
)
decoder_list_print
(
Response
&
r
)
{
using
namespace
std
::
placeholders
;
const
auto
f
=
std
::
bind
(
decoder_plugin_print
,
std
::
ref
(
client
),
_1
);
const
auto
f
=
std
::
bind
(
decoder_plugin_print
,
std
::
ref
(
r
),
_1
);
decoder_plugins_for_each_enabled
(
f
);
}
src/decoder/DecoderPrint.hxx
View file @
7652a298
...
...
@@ -20,9 +20,9 @@
#ifndef MPD_DECODER_PRINT_HXX
#define MPD_DECODER_PRINT_HXX
class
Client
;
class
Response
;
void
decoder_list_print
(
Client
&
client
);
decoder_list_print
(
Response
&
r
);
#endif
src/ls.cxx
View file @
7652a298
...
...
@@ -19,9 +19,9 @@
#include "config.h"
#include "ls.hxx"
#include "client/Response.hxx"
#include "util/StringUtil.hxx"
#include "util/UriUtil.hxx"
#include "client/Client.hxx"
#include <assert.h>
...
...
@@ -78,12 +78,13 @@ void print_supported_uri_schemes_to_fp(FILE *fp)
fprintf
(
fp
,
"
\n
"
);
}
void
print_supported_uri_schemes
(
Client
&
client
)
void
print_supported_uri_schemes
(
Response
&
r
)
{
const
char
*
const
*
prefixes
=
remoteUrlPrefixes
;
while
(
*
prefixes
)
{
client_printf
(
client
,
"handler: %s
\n
"
,
*
prefixes
);
r
.
Format
(
"handler: %s
\n
"
,
*
prefixes
);
prefixes
++
;
}
}
...
...
src/ls.hxx
View file @
7652a298
...
...
@@ -24,7 +24,7 @@
#include <stdio.h>
class
Client
;
class
Response
;
/**
* Checks whether the scheme of the specified URI is supported by MPD.
...
...
@@ -38,7 +38,7 @@ bool uri_supported_scheme(const char *url);
* Send a list of supported URI schemes to the client. This is the
* response to the "urlhandlers" command.
*/
void
print_supported_uri_schemes
(
Client
&
client
);
void
print_supported_uri_schemes
(
Response
&
r
);
/**
* Send a list of supported URI schemes to a file pointer.
...
...
src/output/OutputPrint.cxx
View file @
7652a298
...
...
@@ -26,18 +26,17 @@
#include "OutputPrint.hxx"
#include "MultipleOutputs.hxx"
#include "Internal.hxx"
#include "client/
Client
.hxx"
#include "client/
Response
.hxx"
void
printAudioDevices
(
Client
&
client
,
const
MultipleOutputs
&
outputs
)
printAudioDevices
(
Response
&
r
,
const
MultipleOutputs
&
outputs
)
{
for
(
unsigned
i
=
0
,
n
=
outputs
.
Size
();
i
!=
n
;
++
i
)
{
const
AudioOutput
&
ao
=
outputs
.
Get
(
i
);
client_printf
(
client
,
"outputid: %i
\n
"
"outputname: %s
\n
"
"outputenabled: %i
\n
"
,
i
,
ao
.
name
,
ao
.
enabled
);
r
.
Format
(
"outputid: %i
\n
"
"outputname: %s
\n
"
"outputenabled: %i
\n
"
,
i
,
ao
.
name
,
ao
.
enabled
);
}
}
src/output/OutputPrint.hxx
View file @
7652a298
...
...
@@ -25,10 +25,10 @@
#ifndef MPD_OUTPUT_PRINT_HXX
#define MPD_OUTPUT_PRINT_HXX
class
Client
;
class
Response
;
class
MultipleOutputs
;
void
printAudioDevices
(
Client
&
client
,
const
MultipleOutputs
&
outputs
);
printAudioDevices
(
Response
&
r
,
const
MultipleOutputs
&
outputs
);
#endif
src/playlist/Print.cxx
View file @
7652a298
...
...
@@ -28,48 +28,51 @@
#include "fs/Traits.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
#include "client/Client.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
static
void
playlist_provider_print
(
Client
&
client
,
const
char
*
uri
,
playlist_provider_print
(
Response
&
r
,
Partition
&
partition
,
const
SongLoader
&
loader
,
const
char
*
uri
,
SongEnumerator
&
e
,
bool
detail
)
{
const
std
::
string
base_uri
=
uri
!=
nullptr
?
PathTraitsUTF8
::
GetParent
(
uri
)
:
std
::
string
(
"."
);
const
SongLoader
loader
(
client
);
DetachedSong
*
song
;
while
((
song
=
e
.
NextSong
())
!=
nullptr
)
{
if
(
playlist_check_translate_song
(
*
song
,
base_uri
.
c_str
(),
loader
)
&&
detail
)
song_print_info
(
client
,
*
song
);
song_print_info
(
r
,
partition
,
*
song
);
else
/* fallback if no detail was requested or no
detail was available */
song_print_uri
(
client
,
*
song
);
song_print_uri
(
r
,
partition
,
*
song
);
delete
song
;
}
}
bool
playlist_file_print
(
Client
&
client
,
const
char
*
uri
,
bool
detail
)
playlist_file_print
(
Response
&
r
,
Partition
&
partition
,
const
SongLoader
&
loader
,
const
char
*
uri
,
bool
detail
)
{
Mutex
mutex
;
Cond
cond
;
SongEnumerator
*
playlist
=
playlist_open_any
(
uri
,
#ifdef ENABLE_DATABASE
client
.
GetStorage
()
,
partition
.
instance
.
storage
,
#endif
mutex
,
cond
);
if
(
playlist
==
nullptr
)
return
false
;
playlist_provider_print
(
client
,
uri
,
*
playlist
,
detail
);
playlist_provider_print
(
r
,
partition
,
loader
,
uri
,
*
playlist
,
detail
);
delete
playlist
;
return
true
;
}
src/playlist/Print.hxx
View file @
7652a298
...
...
@@ -20,17 +20,20 @@
#ifndef MPD_PLAYLIST__PRINT_HXX
#define MPD_PLAYLIST__PRINT_HXX
class
Client
;
class
Response
;
class
SongLoader
;
struct
Partition
;
/**
* Send the playlist file to the client.
*
* @param client the client which requested the playlist
* @param uri the URI of the playlist file in UTF-8 encoding
* @param detail true if all details should be printed
* @return true on success, false if the playlist does not exist
*/
bool
playlist_file_print
(
Client
&
client
,
const
char
*
uri
,
bool
detail
);
playlist_file_print
(
Response
&
r
,
Partition
&
partition
,
const
SongLoader
&
loader
,
const
char
*
uri
,
bool
detail
);
#endif
src/protocol/ArgParser.cxx
View file @
7652a298
...
...
@@ -19,27 +19,26 @@
#include "config.h"
#include "ArgParser.hxx"
#include "Result.hxx"
#include "Chrono.hxx"
#include "client/Response.hxx"
#include <stdlib.h>
bool
check_uint32
(
Client
&
client
,
uint32_t
*
dst
,
const
char
*
s
)
ParseCommandArg32
(
Response
&
r
,
uint32_t
&
value_r
,
const
char
*
s
)
{
char
*
test
;
*
dst
=
strtoul
(
s
,
&
test
,
10
);
value_r
=
strtoul
(
s
,
&
test
,
10
);
if
(
test
==
s
||
*
test
!=
'\0'
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Integer expected: %s"
,
s
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Integer expected: %s"
,
s
);
return
false
;
}
return
true
;
}
bool
ParseCommandArg
(
Client
&
client
,
int
&
value_r
,
const
char
*
s
,
ParseCommandArg
(
Response
&
r
,
int
&
value_r
,
const
char
*
s
,
int
min_value
,
int
max_value
)
{
char
*
test
;
...
...
@@ -47,14 +46,12 @@ ParseCommandArg(Client &client, int &value_r, const char *s,
value
=
strtol
(
s
,
&
test
,
10
);
if
(
test
==
s
||
*
test
!=
'\0'
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Integer expected: %s"
,
s
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Integer expected: %s"
,
s
);
return
false
;
}
if
(
value
<
min_value
||
value
>
max_value
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Number too large: %s"
,
s
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Number too large: %s"
,
s
);
return
false
;
}
...
...
@@ -63,22 +60,22 @@ ParseCommandArg(Client &client, int &value_r, const char *s,
}
bool
ParseCommandArg
(
Client
&
client
,
int
&
value_r
,
const
char
*
s
)
ParseCommandArg
(
Response
&
r
,
int
&
value_r
,
const
char
*
s
)
{
return
ParseCommandArg
(
client
,
value_r
,
s
,
return
ParseCommandArg
(
r
,
value_r
,
s
,
std
::
numeric_limits
<
int
>::
min
(),
std
::
numeric_limits
<
int
>::
max
());
}
bool
ParseCommandArg
(
Client
&
client
,
RangeArg
&
value_r
,
const
char
*
s
)
ParseCommandArg
(
Response
&
r
,
RangeArg
&
value_r
,
const
char
*
s
)
{
char
*
test
,
*
test2
;
long
value
;
value
=
strtol
(
s
,
&
test
,
10
);
if
(
test
==
s
||
(
*
test
!=
'\0'
&&
*
test
!=
':'
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Integer or range expected: %s"
,
s
);
return
false
;
}
...
...
@@ -92,14 +89,12 @@ ParseCommandArg(Client &client, RangeArg &value_r, const char *s)
}
if
(
value
<
0
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Number is negative: %s"
,
s
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Number is negative: %s"
,
s
);
return
false
;
}
if
(
unsigned
(
value
)
>
std
::
numeric_limits
<
unsigned
>::
max
())
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Number too large: %s"
,
s
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Number too large: %s"
,
s
);
return
false
;
}
...
...
@@ -108,7 +103,7 @@ ParseCommandArg(Client &client, RangeArg &value_r, const char *s)
if
(
*
test
==
':'
)
{
value
=
strtol
(
++
test
,
&
test2
,
10
);
if
(
*
test2
!=
'\0'
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Integer or range expected: %s"
,
s
);
return
false
;
}
...
...
@@ -117,13 +112,13 @@ ParseCommandArg(Client &client, RangeArg &value_r, const char *s)
value
=
std
::
numeric_limits
<
int
>::
max
();
if
(
value
<
0
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Number is negative: %s"
,
s
);
return
false
;
}
if
(
unsigned
(
value
)
>
std
::
numeric_limits
<
unsigned
>::
max
())
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Number too large: %s"
,
s
);
return
false
;
}
...
...
@@ -137,7 +132,7 @@ ParseCommandArg(Client &client, RangeArg &value_r, const char *s)
}
bool
ParseCommandArg
(
Client
&
client
,
unsigned
&
value_r
,
const
char
*
s
,
ParseCommandArg
(
Response
&
r
,
unsigned
&
value_r
,
const
char
*
s
,
unsigned
max_value
)
{
unsigned
long
value
;
...
...
@@ -145,13 +140,12 @@ ParseCommandArg(Client &client, unsigned &value_r, const char *s,
value
=
strtoul
(
s
,
&
endptr
,
10
);
if
(
endptr
==
s
||
*
endptr
!=
0
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Integer expected: %s"
,
s
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Integer expected: %s"
,
s
);
return
false
;
}
if
(
value
>
max_value
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Number too large: %s"
,
s
);
return
false
;
}
...
...
@@ -161,21 +155,21 @@ ParseCommandArg(Client &client, unsigned &value_r, const char *s,
}
bool
ParseCommandArg
(
Client
&
client
,
unsigned
&
value_r
,
const
char
*
s
)
ParseCommandArg
(
Response
&
r
,
unsigned
&
value_r
,
const
char
*
s
)
{
return
ParseCommandArg
(
client
,
value_r
,
s
,
return
ParseCommandArg
(
r
,
value_r
,
s
,
std
::
numeric_limits
<
unsigned
>::
max
());
}
bool
ParseCommandArg
(
Client
&
client
,
bool
&
value_r
,
const
char
*
s
)
ParseCommandArg
(
Response
&
r
,
bool
&
value_r
,
const
char
*
s
)
{
long
value
;
char
*
endptr
;
value
=
strtol
(
s
,
&
endptr
,
10
);
if
(
endptr
==
s
||
*
endptr
!=
0
||
(
value
!=
0
&&
value
!=
1
))
{
command_error
(
client
,
ACK_ERROR_ARG
,
r
.
FormatError
(
ACK_ERROR_ARG
,
"Boolean (0/1) expected: %s"
,
s
);
return
false
;
}
...
...
@@ -185,15 +179,14 @@ ParseCommandArg(Client &client, bool &value_r, const char *s)
}
bool
ParseCommandArg
(
Client
&
client
,
float
&
value_r
,
const
char
*
s
)
ParseCommandArg
(
Response
&
r
,
float
&
value_r
,
const
char
*
s
)
{
float
value
;
char
*
endptr
;
value
=
strtof
(
s
,
&
endptr
);
if
(
endptr
==
s
||
*
endptr
!=
0
)
{
command_error
(
client
,
ACK_ERROR_ARG
,
"Float expected: %s"
,
s
);
r
.
FormatError
(
ACK_ERROR_ARG
,
"Float expected: %s"
,
s
);
return
false
;
}
...
...
@@ -202,10 +195,10 @@ ParseCommandArg(Client &client, float &value_r, const char *s)
}
bool
ParseCommandArg
(
Client
&
client
,
SongTime
&
value_r
,
const
char
*
s
)
ParseCommandArg
(
Response
&
r
,
SongTime
&
value_r
,
const
char
*
s
)
{
float
value
;
bool
success
=
ParseCommandArg
(
client
,
value
,
s
)
&&
value
>=
0
;
bool
success
=
ParseCommandArg
(
r
,
value
,
s
)
&&
value
>=
0
;
if
(
success
)
value_r
=
SongTime
::
FromS
(
value
);
...
...
@@ -213,10 +206,10 @@ ParseCommandArg(Client &client, SongTime &value_r, const char *s)
}
bool
ParseCommandArg
(
Client
&
client
,
SignedSongTime
&
value_r
,
const
char
*
s
)
ParseCommandArg
(
Response
&
r
,
SignedSongTime
&
value_r
,
const
char
*
s
)
{
float
value
;
bool
success
=
ParseCommandArg
(
client
,
value
,
s
);
bool
success
=
ParseCommandArg
(
r
,
value
,
s
);
if
(
success
)
value_r
=
SignedSongTime
::
FromS
(
value
);
...
...
src/protocol/ArgParser.hxx
View file @
7652a298
...
...
@@ -26,19 +26,19 @@
#include <stdint.h>
class
Client
;
class
Response
;
class
SongTime
;
class
SignedSongTime
;
bool
check_uint32
(
Client
&
client
,
uint32_t
*
dst
,
const
char
*
s
);
ParseCommandArg32
(
Response
&
r
,
uint32_t
&
value_r
,
const
char
*
s
);
bool
ParseCommandArg
(
Client
&
client
,
int
&
value_r
,
const
char
*
s
,
ParseCommandArg
(
Response
&
r
,
int
&
value_r
,
const
char
*
s
,
int
min_value
,
int
max_value
);
bool
ParseCommandArg
(
Client
&
client
,
int
&
value_r
,
const
char
*
s
);
ParseCommandArg
(
Response
&
r
,
int
&
value_r
,
const
char
*
s
);
struct
RangeArg
{
unsigned
start
,
end
;
...
...
@@ -54,25 +54,25 @@ struct RangeArg {
};
bool
ParseCommandArg
(
Client
&
client
,
RangeArg
&
value_r
,
const
char
*
s
);
ParseCommandArg
(
Response
&
r
,
RangeArg
&
value_r
,
const
char
*
s
);
bool
ParseCommandArg
(
Client
&
client
,
unsigned
&
value_r
,
const
char
*
s
,
ParseCommandArg
(
Response
&
r
,
unsigned
&
value_r
,
const
char
*
s
,
unsigned
max_value
);
bool
ParseCommandArg
(
Client
&
client
,
unsigned
&
value_r
,
const
char
*
s
);
ParseCommandArg
(
Response
&
r
,
unsigned
&
value_r
,
const
char
*
s
);
bool
ParseCommandArg
(
Client
&
client
,
bool
&
value_r
,
const
char
*
s
);
ParseCommandArg
(
Response
&
r
,
bool
&
value_r
,
const
char
*
s
);
bool
ParseCommandArg
(
Client
&
client
,
float
&
value_r
,
const
char
*
s
);
ParseCommandArg
(
Response
&
r
,
float
&
value_r
,
const
char
*
s
);
bool
ParseCommandArg
(
Client
&
client
,
SongTime
&
value_r
,
const
char
*
s
);
ParseCommandArg
(
Response
&
r
,
SongTime
&
value_r
,
const
char
*
s
);
bool
ParseCommandArg
(
Client
&
client
,
SignedSongTime
&
value_r
,
const
char
*
s
);
ParseCommandArg
(
Response
&
r
,
SignedSongTime
&
value_r
,
const
char
*
s
);
#endif
src/queue/QueuePrint.cxx
View file @
7652a298
...
...
@@ -22,7 +22,7 @@
#include "Queue.hxx"
#include "SongFilter.hxx"
#include "SongPrint.hxx"
#include "client/
Client
.hxx"
#include "client/
Response
.hxx"
/**
* Send detailed information about a range of songs in the queue to a
...
...
@@ -33,70 +33,70 @@
* @param end the index of the last song (excluding)
*/
static
void
queue_print_song_info
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_song_info
(
Response
&
r
,
Partition
&
partition
,
const
Queue
&
queue
,
unsigned
position
)
{
song_print_info
(
client
,
queue
.
Get
(
position
));
client_printf
(
client
,
"Pos: %u
\n
Id: %u
\n
"
,
position
,
queue
.
PositionToId
(
position
));
song_print_info
(
r
,
partition
,
queue
.
Get
(
position
));
r
.
Format
(
"Pos: %u
\n
Id: %u
\n
"
,
position
,
queue
.
PositionToId
(
position
));
uint8_t
priority
=
queue
.
GetPriorityAtPosition
(
position
);
if
(
priority
!=
0
)
client_printf
(
client
,
"Prio: %u
\n
"
,
priority
);
r
.
Format
(
"Prio: %u
\n
"
,
priority
);
}
void
queue_print_info
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_info
(
Response
&
r
,
Partition
&
partition
,
const
Queue
&
queue
,
unsigned
start
,
unsigned
end
)
{
assert
(
start
<=
end
);
assert
(
end
<=
queue
.
GetLength
());
for
(
unsigned
i
=
start
;
i
<
end
;
++
i
)
queue_print_song_info
(
client
,
queue
,
i
);
queue_print_song_info
(
r
,
partition
,
queue
,
i
);
}
void
queue_print_uris
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_uris
(
Response
&
r
,
Partition
&
partition
,
const
Queue
&
queue
,
unsigned
start
,
unsigned
end
)
{
assert
(
start
<=
end
);
assert
(
end
<=
queue
.
GetLength
());
for
(
unsigned
i
=
start
;
i
<
end
;
++
i
)
{
client_printf
(
client
,
"%i:"
,
i
);
song_print_uri
(
client
,
queue
.
Get
(
i
));
r
.
Format
(
"%i:"
,
i
);
song_print_uri
(
r
,
partition
,
queue
.
Get
(
i
));
}
}
void
queue_print_changes_info
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_changes_info
(
Response
&
r
,
Partition
&
partition
,
const
Queue
&
queue
,
uint32_t
version
)
{
for
(
unsigned
i
=
0
;
i
<
queue
.
GetLength
();
i
++
)
{
if
(
queue
.
IsNewerAtPosition
(
i
,
version
))
queue_print_song_info
(
client
,
queue
,
i
);
queue_print_song_info
(
r
,
partition
,
queue
,
i
);
}
}
void
queue_print_changes_position
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_changes_position
(
Response
&
r
,
const
Queue
&
queue
,
uint32_t
version
)
{
for
(
unsigned
i
=
0
;
i
<
queue
.
GetLength
();
i
++
)
if
(
queue
.
IsNewerAtPosition
(
i
,
version
))
client_printf
(
client
,
"cpos: %i
\n
Id: %i
\n
"
,
i
,
queue
.
PositionToId
(
i
));
r
.
Format
(
"cpos: %i
\n
Id: %i
\n
"
,
i
,
queue
.
PositionToId
(
i
));
}
void
queue_find
(
Client
&
client
,
const
Queue
&
queue
,
queue_find
(
Response
&
r
,
Partition
&
partition
,
const
Queue
&
queue
,
const
SongFilter
&
filter
)
{
for
(
unsigned
i
=
0
;
i
<
queue
.
GetLength
();
i
++
)
{
const
DetachedSong
&
song
=
queue
.
Get
(
i
);
if
(
filter
.
Match
(
song
))
queue_print_song_info
(
client
,
queue
,
i
);
queue_print_song_info
(
r
,
partition
,
queue
,
i
);
}
}
src/queue/QueuePrint.hxx
View file @
7652a298
...
...
@@ -28,27 +28,28 @@
#include <stdint.h>
struct
Queue
;
struct
Partition
;
class
SongFilter
;
class
Client
;
class
Response
;
void
queue_print_info
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_info
(
Response
&
r
,
Partition
&
partition
,
const
Queue
&
queue
,
unsigned
start
,
unsigned
end
);
void
queue_print_uris
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_uris
(
Response
&
r
,
Partition
&
partition
,
const
Queue
&
queue
,
unsigned
start
,
unsigned
end
);
void
queue_print_changes_info
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_changes_info
(
Response
&
r
,
Partition
&
partition
,
const
Queue
&
queue
,
uint32_t
version
);
void
queue_print_changes_position
(
Client
&
client
,
const
Queue
&
queue
,
queue_print_changes_position
(
Response
&
r
,
const
Queue
&
queue
,
uint32_t
version
);
void
queue_find
(
Client
&
client
,
const
Queue
&
queue
,
queue_find
(
Response
&
response
,
Partition
&
partition
,
const
Queue
&
queue
,
const
SongFilter
&
filter
);
#endif
src/sticker/StickerPrint.cxx
View file @
7652a298
...
...
@@ -20,25 +20,25 @@
#include "config.h"
#include "StickerPrint.hxx"
#include "StickerDatabase.hxx"
#include "client/
Client
.hxx"
#include "client/
Response
.hxx"
void
sticker_print_value
(
Client
&
client
,
sticker_print_value
(
Response
&
r
,
const
char
*
name
,
const
char
*
value
)
{
client_printf
(
client
,
"sticker: %s=%s
\n
"
,
name
,
value
);
r
.
Format
(
"sticker: %s=%s
\n
"
,
name
,
value
);
}
static
void
print_sticker_cb
(
const
char
*
name
,
const
char
*
value
,
void
*
data
)
{
Client
&
client
=
*
(
Client
*
)
data
;
auto
&
r
=
*
(
Response
*
)
data
;
sticker_print_value
(
client
,
name
,
value
);
sticker_print_value
(
r
,
name
,
value
);
}
void
sticker_print
(
Client
&
client
,
const
Sticker
&
sticker
)
sticker_print
(
Response
&
r
,
const
Sticker
&
sticker
)
{
sticker_foreach
(
sticker
,
print_sticker_cb
,
&
client
);
sticker_foreach
(
sticker
,
print_sticker_cb
,
&
r
);
}
src/sticker/StickerPrint.hxx
View file @
7652a298
...
...
@@ -21,18 +21,18 @@
#define MPD_STICKER_PRINT_HXX
struct
Sticker
;
class
Client
;
class
Response
;
/**
* Sends one sticker value to the client.
*/
void
sticker_print_value
(
Client
&
client
,
const
char
*
name
,
const
char
*
value
);
sticker_print_value
(
Response
&
r
,
const
char
*
name
,
const
char
*
value
);
/**
* Sends all sticker values to the client.
*/
void
sticker_print
(
Client
&
client
,
const
Sticker
&
sticker
);
sticker_print
(
Response
&
r
,
const
Sticker
&
sticker
);
#endif
test/test_protocol.cxx
View file @
7652a298
#include "config.h"
#include "protocol/ArgParser.hxx"
#include "
protocol/Result
.hxx"
#include "
client/Response
.hxx"
#include "Compiler.h"
#include <cppunit/TestFixture.h>
...
...
@@ -13,10 +13,15 @@
static
enum
ack
last_error
=
ack
(
-
1
);
void
command_error
(
gcc_unused
Client
&
client
,
enum
ack
error
,
gcc_unused
const
char
*
fmt
,
...)
Response
::
Error
(
enum
ack
code
,
gcc_unused
const
char
*
msg
)
{
last_error
=
error
;
last_error
=
code
;
}
void
Response
::
FormatError
(
enum
ack
code
,
gcc_unused
const
char
*
fmt
,
...)
{
last_error
=
code
;
}
class
ArgParserTest
:
public
CppUnit
::
TestFixture
{
...
...
@@ -32,22 +37,23 @@ void
ArgParserTest
::
TestRange
()
{
Client
&
client
=
*
(
Client
*
)
nullptr
;
Response
r
(
client
);
RangeArg
range
;
CPPUNIT_ASSERT
(
ParseCommandArg
(
client
,
range
,
"1"
));
CPPUNIT_ASSERT
(
ParseCommandArg
(
r
,
range
,
"1"
));
CPPUNIT_ASSERT_EQUAL
(
1u
,
range
.
start
);
CPPUNIT_ASSERT_EQUAL
(
2u
,
range
.
end
);
CPPUNIT_ASSERT
(
ParseCommandArg
(
client
,
range
,
"1:5"
));
CPPUNIT_ASSERT
(
ParseCommandArg
(
r
,
range
,
"1:5"
));
CPPUNIT_ASSERT_EQUAL
(
1u
,
range
.
start
);
CPPUNIT_ASSERT_EQUAL
(
5u
,
range
.
end
);
CPPUNIT_ASSERT
(
ParseCommandArg
(
client
,
range
,
"1:"
));
CPPUNIT_ASSERT
(
ParseCommandArg
(
r
,
range
,
"1:"
));
CPPUNIT_ASSERT_EQUAL
(
1u
,
range
.
start
);
CPPUNIT_ASSERT
(
range
.
end
>=
999999u
);
CPPUNIT_ASSERT
(
!
ParseCommandArg
(
client
,
range
,
"-2"
));
CPPUNIT_ASSERT
(
!
ParseCommandArg
(
r
,
range
,
"-2"
));
CPPUNIT_ASSERT_EQUAL
(
ACK_ERROR_ARG
,
last_error
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment