[mpd] Fix idle command (idle events got lost if they happened while the

client was not in idle mode)
This commit is contained in:
chme 2017-11-12 16:20:06 +01:00
parent 4fe4bee809
commit 1e24b3656a

457
src/mpd.c
View File

@ -20,6 +20,7 @@
# include <config.h> # include <config.h>
#endif #endif
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -141,11 +142,66 @@ static const char * const ffmpeg_mime_types[] = { "application/flv", "applicatio
NULL NULL
}; };
/* Provide for connection specfic authentication. */ /*
struct mpd_cmd_ctx { * MPD client connection data
*/
struct mpd_client_ctx
{
// True if the connection is already authenticated or does not need authentication
int authenticated; int authenticated;
// The events the client needs to be notified of
short events;
// True if the client is waiting for idle events
bool is_idle;
// The events the client is waiting for (set by the idle command)
short idle_events;
// The output buffer for the client (used to send data to the client)
struct evbuffer *evbuffer;
struct mpd_client_ctx *next;
}; };
// List of all connected mpd clients
struct mpd_client_ctx *mpd_clients;
static void
free_mpd_client_ctx(void *ctx)
{
struct mpd_client_ctx *client_ctx = ctx;
struct mpd_client_ctx *client;
struct mpd_client_ctx *prev;
if (!client_ctx)
return;
client = mpd_clients;
prev = NULL;
while (client)
{
if (client == client_ctx)
{
DPRINTF(E_DBG, L_MPD, "Removing mpd client\n");
if (prev)
prev->next = client->next;
else
mpd_clients = client->next;
break;
}
prev = client;
client = client->next;
}
free(client_ctx);
}
struct output struct output
{ {
unsigned short shortid; unsigned short shortid;
@ -181,17 +237,6 @@ free_outputs(struct output *outputs)
} }
} }
struct idle_client
{
struct evbuffer *evbuffer;
short events;
struct idle_client *next;
};
struct idle_client *idle_clients;
/* /*
* Creates a new string for the given path that starts with a '/'. * Creates a new string for the given path that starts with a '/'.
* If 'path' already starts with a '/' the returned string is a duplicate * If 'path' already starts with a '/' the returned string is a duplicate
@ -550,7 +595,7 @@ mpd_add_db_media_file_info(struct evbuffer *evbuf, struct db_media_file_info *db
* Command handler function for 'currentsong' * Command handler function for 'currentsong'
*/ */
static int static int
mpd_command_currentsong(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_currentsong(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct player_status status; struct player_status status;
@ -585,111 +630,89 @@ mpd_command_currentsong(struct evbuffer *evbuf, int argc, char **argv, char **er
return 0; return 0;
} }
static int
mpd_notify_idle_client(struct mpd_client_ctx *client_ctx, short events);
/* /*
*
* Example input: * Example input:
* idle "database" "mixer" "options" "output" "player" "playlist" "sticker" "update" * idle "database" "mixer" "options" "output" "player" "playlist" "sticker" "update"
*/ */
static int static int
mpd_command_idle(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_idle(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct idle_client *client;
int i; int i;
client = (struct idle_client*)malloc(sizeof(struct idle_client)); ctx->idle_events = 0;
if (!client) ctx->is_idle = true;
{
DPRINTF(E_LOG, L_MPD, "Out of memory for idle_client\n");
return ACK_ERROR_UNKNOWN;
}
client->evbuffer = evbuf;
client->events = 0;
client->next = idle_clients;
if (argc > 1) if (argc > 1)
{ {
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
{ {
if (0 == strcmp(argv[i], "database")) if (0 == strcmp(argv[i], "database"))
{ ctx->idle_events |= LISTENER_DATABASE;
client->events |= LISTENER_DATABASE;
}
else if (0 == strcmp(argv[i], "update")) else if (0 == strcmp(argv[i], "update"))
{ ctx->idle_events |= LISTENER_UPDATE;
client->events |= LISTENER_UPDATE;
}
else if (0 == strcmp(argv[i], "player")) else if (0 == strcmp(argv[i], "player"))
{ ctx->idle_events |= LISTENER_PLAYER;
client->events |= LISTENER_PLAYER;
}
else if (0 == strcmp(argv[i], "playlist")) else if (0 == strcmp(argv[i], "playlist"))
{ ctx->idle_events |= LISTENER_QUEUE;
client->events |= LISTENER_QUEUE;
}
else if (0 == strcmp(argv[i], "mixer")) else if (0 == strcmp(argv[i], "mixer"))
{ ctx->idle_events |= LISTENER_VOLUME;
client->events |= LISTENER_VOLUME;
}
else if (0 == strcmp(argv[i], "output")) else if (0 == strcmp(argv[i], "output"))
{ ctx->idle_events |= LISTENER_SPEAKER;
client->events |= LISTENER_SPEAKER;
}
else if (0 == strcmp(argv[i], "options")) else if (0 == strcmp(argv[i], "options"))
{ ctx->idle_events |= LISTENER_OPTIONS;
client->events |= LISTENER_OPTIONS;
}
else if (0 == strcmp(argv[i], "stored_playlist")) else if (0 == strcmp(argv[i], "stored_playlist"))
{ ctx->idle_events |= LISTENER_STORED_PLAYLIST;
client->events |= LISTENER_STORED_PLAYLIST;
}
else else
{
DPRINTF(E_DBG, L_MPD, "Idle command for '%s' not supported\n", argv[i]); DPRINTF(E_DBG, L_MPD, "Idle command for '%s' not supported\n", argv[i]);
} }
} }
}
else else
client->events = LISTENER_PLAYER | LISTENER_QUEUE | LISTENER_VOLUME | LISTENER_SPEAKER | LISTENER_OPTIONS | LISTENER_DATABASE | LISTENER_UPDATE | LISTENER_STORED_PLAYLIST; ctx->idle_events = LISTENER_PLAYER | LISTENER_QUEUE | LISTENER_VOLUME | LISTENER_SPEAKER | LISTENER_OPTIONS | LISTENER_DATABASE | LISTENER_UPDATE | LISTENER_STORED_PLAYLIST;
idle_clients = client; // If events the client listens to occurred since the last idle call (or since the client connected,
// if it is the first idle call), notify immediately.
if (ctx->events & ctx->idle_events)
mpd_notify_idle_client(ctx, ctx->events);
return 0; return 0;
} }
static void //static void
mpd_remove_idle_client(struct evbuffer *evbuf) //mpd_remove_client(struct evbuffer *evbuf)
{ //{
struct idle_client *client; // struct idle_client *client;
struct idle_client *prev; // struct idle_client *prev;
//
client = idle_clients; // client = idle_clients;
prev = NULL; // prev = NULL;
//
while (client) // while (client)
{ // {
if (client->evbuffer == evbuf) // if (client->evbuffer == evbuf)
{ // {
DPRINTF(E_DBG, L_MPD, "Removing idle client for evbuffer\n"); // DPRINTF(E_DBG, L_MPD, "Removing idle client for evbuffer\n");
//
if (prev) // if (prev)
prev->next = client->next; // prev->next = client->next;
else // else
idle_clients = client->next; // idle_clients = client->next;
//
free(client); // free(client);
break; // break;
} // }
//
prev = client; // prev = client;
client = client->next; // client = client->next;
} // }
} //}
static int static int
mpd_command_noidle(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_noidle(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
mpd_remove_idle_client(evbuf); ctx->is_idle = false;
ctx->idle_events = 0;
return 0; return 0;
} }
@ -716,7 +739,7 @@ mpd_command_noidle(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* nextsongid: 2 * nextsongid: 2
*/ */
static int static int
mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct player_status status; struct player_status status;
int queue_length; int queue_length;
@ -808,7 +831,7 @@ mpd_command_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* Command handler function for 'stats' * Command handler function for 'stats'
*/ */
static int static int
mpd_command_stats(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_stats(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params qp; struct query_params qp;
struct filecount_info fci; struct filecount_info fci;
@ -856,7 +879,7 @@ mpd_command_stats(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* 1 = enable consume * 1 = enable consume
*/ */
static int static int
mpd_command_consume(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_consume(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int enable; int enable;
int ret; int ret;
@ -885,7 +908,7 @@ mpd_command_consume(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
* 1 = enable shuffle * 1 = enable shuffle
*/ */
static int static int
mpd_command_random(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_random(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int enable; int enable;
int ret; int ret;
@ -914,7 +937,7 @@ mpd_command_random(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* 1 = repeat all * 1 = repeat all
*/ */
static int static int
mpd_command_repeat(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_repeat(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int enable; int enable;
int ret; int ret;
@ -945,7 +968,7 @@ mpd_command_repeat(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* Sets the volume, expects argument argv[1] to be an integer 0-100 * Sets the volume, expects argument argv[1] to be an integer 0-100
*/ */
static int static int
mpd_command_setvol(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_setvol(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int volume; int volume;
int ret; int ret;
@ -984,7 +1007,7 @@ mpd_command_setvol(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* 1 = repeat song * 1 = repeat song
*/ */
static int static int
mpd_command_single(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_single(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int enable; int enable;
struct player_status status; struct player_status status;
@ -1021,7 +1044,7 @@ mpd_command_single(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* "replay_gain_mode: off". * "replay_gain_mode: off".
*/ */
static int static int
mpd_command_replay_gain_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_replay_gain_status(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
evbuffer_add(evbuf, "replay_gain_mode: off\n", 22); evbuffer_add(evbuf, "replay_gain_mode: off\n", 22);
return 0; return 0;
@ -1034,7 +1057,7 @@ mpd_command_replay_gain_status(struct evbuffer *evbuf, int argc, char **argv, ch
* According to the mpd protocoll specification this function is deprecated. * According to the mpd protocoll specification this function is deprecated.
*/ */
static int static int
mpd_command_volume(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_volume(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct player_status status; struct player_status status;
int volume; int volume;
@ -1067,7 +1090,7 @@ mpd_command_volume(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* Skips to the next song in the playqueue * Skips to the next song in the playqueue
*/ */
static int static int
mpd_command_next(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_next(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int ret; int ret;
@ -1096,7 +1119,7 @@ mpd_command_next(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* 1 = pause * 1 = pause
*/ */
static int static int
mpd_command_pause(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_pause(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int pause; int pause;
struct player_status status; struct player_status status;
@ -1140,7 +1163,7 @@ mpd_command_pause(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* where to start playback. * where to start playback.
*/ */
static int static int
mpd_command_play(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_play(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int songpos; int songpos;
struct player_status status; struct player_status status;
@ -1202,7 +1225,7 @@ mpd_command_play(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* where to start playback. * where to start playback.
*/ */
static int static int
mpd_command_playid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_playid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
uint32_t id; uint32_t id;
struct player_status status; struct player_status status;
@ -1258,7 +1281,7 @@ mpd_command_playid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* Skips to the previous song in the playqueue * Skips to the previous song in the playqueue
*/ */
static int static int
mpd_command_previous(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_previous(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int ret; int ret;
@ -1286,7 +1309,7 @@ mpd_command_previous(struct evbuffer *evbuf, int argc, char **argv, char **errms
* (fractions allowed). * (fractions allowed).
*/ */
static int static int
mpd_command_seek(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_seek(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
uint32_t songpos; uint32_t songpos;
float seek_target_sec; float seek_target_sec;
@ -1335,7 +1358,7 @@ mpd_command_seek(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* (fractions allowed). * (fractions allowed).
*/ */
static int static int
mpd_command_seekid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_seekid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct player_status status; struct player_status status;
uint32_t id; uint32_t id;
@ -1390,7 +1413,7 @@ mpd_command_seekid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* Seeks the current song to the position in seconds given in argument argv[1] (fractions allowed). * Seeks the current song to the position in seconds given in argument argv[1] (fractions allowed).
*/ */
static int static int
mpd_command_seekcur(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_seekcur(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
float seek_target_sec; float seek_target_sec;
int seek_target_msec; int seek_target_msec;
@ -1429,7 +1452,7 @@ mpd_command_seekcur(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
* Stop playback. * Stop playback.
*/ */
static int static int
mpd_command_stop(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_stop(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int ret; int ret;
@ -1491,7 +1514,7 @@ mpd_queue_add(char *path, int recursive)
* Expects argument argv[1] to be a path to a single file or directory. * Expects argument argv[1] to be a path to a single file or directory.
*/ */
static int static int
mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct media_file_info mfi; struct media_file_info mfi;
int ret; int ret;
@ -1534,7 +1557,7 @@ mpd_command_add(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* it must be an integer representing the position in the playqueue. * it must be an integer representing the position in the playqueue.
*/ */
static int static int
mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct media_file_info mfi; struct media_file_info mfi;
int ret; int ret;
@ -1585,7 +1608,7 @@ mpd_command_addid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* Stops playback and removes all songs from the playqueue * Stops playback and removes all songs from the playqueue
*/ */
static int static int
mpd_command_clear(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_clear(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int ret; int ret;
@ -1607,7 +1630,7 @@ mpd_command_clear(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* should be removed. * should be removed.
*/ */
static int static int
mpd_command_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int start_pos; int start_pos;
int end_pos; int end_pos;
@ -1646,7 +1669,7 @@ mpd_command_delete(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* Removes the song with given id from the playqueue. Expects argument argv[1] to be an integer (song id). * Removes the song with given id from the playqueue. Expects argument argv[1] to be an integer (song id).
*/ */
static int static int
mpd_command_deleteid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_deleteid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
uint32_t songid; uint32_t songid;
int ret; int ret;
@ -1676,7 +1699,7 @@ mpd_command_deleteid(struct evbuffer *evbuf, int argc, char **argv, char **errms
//Moves the song at FROM or range of songs at START:END to TO in the playlist. //Moves the song at FROM or range of songs at START:END to TO in the playlist.
static int static int
mpd_command_move(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_move(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int start_pos; int start_pos;
int end_pos; int end_pos;
@ -1719,7 +1742,7 @@ mpd_command_move(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
static int static int
mpd_command_moveid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_moveid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
uint32_t songid; uint32_t songid;
uint32_t to_pos; uint32_t to_pos;
@ -1763,7 +1786,7 @@ mpd_command_moveid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
* The order of the songs is always the not shuffled order. * The order of the songs is always the not shuffled order.
*/ */
static int static int
mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params query_params; struct query_params query_params;
struct db_queue_item queue_item; struct db_queue_item queue_item;
@ -1823,7 +1846,7 @@ mpd_command_playlistid(struct evbuffer *evbuf, int argc, char **argv, char **err
* The order of the songs is always the not shuffled order. * The order of the songs is always the not shuffled order.
*/ */
static int static int
mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params query_params; struct query_params query_params;
struct db_queue_item queue_item; struct db_queue_item queue_item;
@ -1882,7 +1905,7 @@ mpd_command_playlistinfo(struct evbuffer *evbuf, int argc, char **argv, char **e
* Lists all changed songs in the queue since the given playlist version in argv[1]. * Lists all changed songs in the queue since the given playlist version in argv[1].
*/ */
static int static int
mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params query_params; struct query_params query_params;
struct db_queue_item queue_item; struct db_queue_item queue_item;
@ -1923,7 +1946,7 @@ mpd_command_plchanges(struct evbuffer *evbuf, int argc, char **argv, char **errm
* Lists all changed songs in the queue since the given playlist version in argv[1] without metadata. * Lists all changed songs in the queue since the given playlist version in argv[1] without metadata.
*/ */
static int static int
mpd_command_plchangesposid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_plchangesposid(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params query_params; struct query_params query_params;
struct db_queue_item queue_item; struct db_queue_item queue_item;
@ -1961,7 +1984,7 @@ mpd_command_plchangesposid(struct evbuffer *evbuf, int argc, char **argv, char *
* Lists all songs in the playlist given by virtual-path in argv[1]. * Lists all songs in the playlist given by virtual-path in argv[1].
*/ */
static int static int
mpd_command_listplaylist(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_listplaylist(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
struct playlist_info *pli; struct playlist_info *pli;
@ -2029,7 +2052,7 @@ mpd_command_listplaylist(struct evbuffer *evbuf, int argc, char **argv, char **e
* Lists all songs in the playlist given by virtual-path in argv[1] with metadata. * Lists all songs in the playlist given by virtual-path in argv[1] with metadata.
*/ */
static int static int
mpd_command_listplaylistinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_listplaylistinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
struct playlist_info *pli; struct playlist_info *pli;
@ -2099,7 +2122,7 @@ mpd_command_listplaylistinfo(struct evbuffer *evbuf, int argc, char **argv, char
* Lists all playlists with their last modified date. * Lists all playlists with their last modified date.
*/ */
static int static int
mpd_command_listplaylists(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_listplaylists(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params qp; struct query_params qp;
struct db_playlist_info dbpli; struct db_playlist_info dbpli;
@ -2152,7 +2175,7 @@ mpd_command_listplaylists(struct evbuffer *evbuf, int argc, char **argv, char **
* Adds the playlist given by virtual-path in argv[1] to the queue. * Adds the playlist given by virtual-path in argv[1] to the queue.
*/ */
static int static int
mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
struct playlist_info *pli; struct playlist_info *pli;
@ -2199,7 +2222,7 @@ mpd_command_load(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
static int static int
mpd_command_playlistadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_playlistadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
char *vp_playlist; char *vp_playlist;
char *vp_item; char *vp_item;
@ -2243,7 +2266,7 @@ mpd_command_playlistadd(struct evbuffer *evbuf, int argc, char **argv, char **er
} }
static int static int
mpd_command_rm(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_rm(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
char *virtual_path; char *virtual_path;
int ret; int ret;
@ -2283,7 +2306,7 @@ mpd_command_rm(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
static int static int
mpd_command_save(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_save(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
char *virtual_path; char *virtual_path;
int ret; int ret;
@ -2442,7 +2465,7 @@ mpd_get_query_params_find(int argc, char **argv, struct query_params *qp)
} }
static int static int
mpd_command_count(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_count(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params qp; struct query_params qp;
struct filecount_info fci; struct filecount_info fci;
@ -2480,7 +2503,7 @@ mpd_command_count(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
static int static int
mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params qp; struct query_params qp;
struct db_media_file_info dbmfi; struct db_media_file_info dbmfi;
@ -2526,7 +2549,7 @@ mpd_command_find(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
static int static int
mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params qp; struct query_params qp;
struct player_status status; struct player_status status;
@ -2560,7 +2583,7 @@ mpd_command_findadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
} }
static int static int
mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_list(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params qp; struct query_params qp;
struct db_group_info dbgri; struct db_group_info dbgri;
@ -2813,7 +2836,7 @@ mpd_add_directory(struct evbuffer *evbuf, int directory_id, int listall, int lis
} }
static int static int
mpd_command_listall(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_listall(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int dir_id; int dir_id;
char parent[PATH_MAX]; char parent[PATH_MAX];
@ -2853,7 +2876,7 @@ mpd_command_listall(struct evbuffer *evbuf, int argc, char **argv, char **errmsg
} }
static int static int
mpd_command_listallinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_listallinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int dir_id; int dir_id;
char parent[PATH_MAX]; char parent[PATH_MAX];
@ -2897,7 +2920,7 @@ mpd_command_listallinfo(struct evbuffer *evbuf, int argc, char **argv, char **er
* Lists the contents of the directory given in argv[1]. * Lists the contents of the directory given in argv[1].
*/ */
static int static int
mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int dir_id; int dir_id;
char parent[PATH_MAX]; char parent[PATH_MAX];
@ -2949,7 +2972,7 @@ mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
// If the root directory was passed as argument add the stored playlists to the response // If the root directory was passed as argument add the stored playlists to the response
if (ret == 0 && print_playlists) if (ret == 0 && print_playlists)
{ {
return mpd_command_listplaylists(evbuf, argc, argv, errmsg); return mpd_command_listplaylists(evbuf, argc, argv, errmsg, ctx);
} }
return ret; return ret;
@ -3084,7 +3107,7 @@ mpd_get_query_params_search(int argc, char **argv, struct query_params *qp)
* Example request: "search artist foo album bar" * Example request: "search artist foo album bar"
*/ */
static int static int
mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params qp; struct query_params qp;
struct db_media_file_info dbmfi; struct db_media_file_info dbmfi;
@ -3130,7 +3153,7 @@ mpd_command_search(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
static int static int
mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct query_params qp; struct query_params qp;
struct player_status status; struct player_status status;
@ -3168,7 +3191,7 @@ mpd_command_searchadd(struct evbuffer *evbuf, int argc, char **argv, char **errm
* Initiates an init-rescan (scans for new files) * Initiates an init-rescan (scans for new files)
*/ */
static int static int
mpd_command_update(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_update(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
if (argc > 1 && strlen(argv[1]) > 0) if (argc > 1 && strlen(argv[1]) > 0)
{ {
@ -3185,7 +3208,7 @@ mpd_command_update(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
/* /*
static int static int
mpd_command_rescan(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_rescan(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int ret; int ret;
@ -3205,7 +3228,7 @@ mpd_command_rescan(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
*/ */
static int static int
mpd_command_password(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_password(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
char *required_password; char *required_password;
char *supplied_password = ""; char *supplied_password = "";
@ -3270,7 +3293,7 @@ outputs_enum_cb(uint64_t id, const char *name, int relvol, int absvol, struct sp
* Expects argument argv[1] to be the id of the speaker to disable. * Expects argument argv[1] to be the id of the speaker to disable.
*/ */
static int static int
mpd_command_disableoutput(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_disableoutput(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct outputs outputs; struct outputs outputs;
struct output *output; struct output *output;
@ -3354,7 +3377,7 @@ mpd_command_disableoutput(struct evbuffer *evbuf, int argc, char **argv, char **
* Expects argument argv[1] to be the id of the speaker to enable. * Expects argument argv[1] to be the id of the speaker to enable.
*/ */
static int static int
mpd_command_enableoutput(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_enableoutput(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct outputs outputs; struct outputs outputs;
struct output *output; struct output *output;
@ -3439,7 +3462,7 @@ mpd_command_enableoutput(struct evbuffer *evbuf, int argc, char **argv, char **e
* Expects argument argv[1] to be the id of the speaker to enable/disable. * Expects argument argv[1] to be the id of the speaker to enable/disable.
*/ */
static int static int
mpd_command_toggleoutput(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_toggleoutput(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
struct outputs outputs; struct outputs outputs;
struct output *output; struct output *output;
@ -3558,7 +3581,7 @@ speaker_enum_cb(uint64_t id, const char *name, int relvol, int absvol, struct sp
* Returns a lists with the avaiable speakers. * Returns a lists with the avaiable speakers.
*/ */
static int static int
mpd_command_outputs(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_outputs(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
player_speaker_enumerate(speaker_enum_cb, evbuf); player_speaker_enumerate(speaker_enum_cb, evbuf);
@ -3609,7 +3632,7 @@ outputvolume_set(uint32_t shortid, int volume, char **errmsg)
} }
static int static int
mpd_command_outputvolume(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_outputvolume(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
uint32_t shortid; uint32_t shortid;
int volume; int volume;
@ -3752,7 +3775,7 @@ mpd_find_channel(const char *name)
} }
static int static int
mpd_command_channels(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_channels(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int i; int i;
@ -3767,7 +3790,7 @@ mpd_command_channels(struct evbuffer *evbuf, int argc, char **argv, char **errms
} }
static int static int
mpd_command_sendmessage(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_sendmessage(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
const char *channelname; const char *channelname;
const char *message; const char *message;
@ -3799,7 +3822,7 @@ mpd_command_sendmessage(struct evbuffer *evbuf, int argc, char **argv, char **er
* not raise an error. * not raise an error.
*/ */
static int static int
mpd_command_ignore(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_ignore(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
//do nothing //do nothing
DPRINTF(E_DBG, L_MPD, "Ignore command %s\n", argv[0]); DPRINTF(E_DBG, L_MPD, "Ignore command %s\n", argv[0]);
@ -3807,7 +3830,7 @@ mpd_command_ignore(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
} }
static int static int
mpd_command_commands(struct evbuffer *evbuf, int argc, char **argv, char **errmsg); mpd_command_commands(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx);
/* /*
* Command handler function for 'tagtypes' * Command handler function for 'tagtypes'
@ -3815,7 +3838,7 @@ mpd_command_commands(struct evbuffer *evbuf, int argc, char **argv, char **errms
* tagtype: Artist * tagtype: Artist
*/ */
static int static int
mpd_command_tagtypes(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_tagtypes(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
evbuffer_add_printf(evbuf, evbuffer_add_printf(evbuf,
"tagtype: Artist\n" "tagtype: Artist\n"
@ -3839,7 +3862,7 @@ mpd_command_tagtypes(struct evbuffer *evbuf, int argc, char **argv, char **errms
* therefor the function reports only ffmpeg as available. * therefor the function reports only ffmpeg as available.
*/ */
static int static int
mpd_command_decoders(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_decoders(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int i; int i;
@ -3872,7 +3895,7 @@ struct mpd_command
* @param errmsg error message set by this function if an error occured * @param errmsg error message set by this function if an error occured
* @return 0 if successful, one of ack values if an error occured * @return 0 if successful, one of ack values if an error occured
*/ */
int (*handler)(struct evbuffer *evbuf, int argc, char **argv, char **errmsg); int (*handler)(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx);
}; };
static struct mpd_command mpd_handlers[] = static struct mpd_command mpd_handlers[] =
@ -4376,7 +4399,7 @@ mpd_find_command(const char *name)
} }
static int static int
mpd_command_commands(struct evbuffer *evbuf, int argc, char **argv, char **errmsg) mpd_command_commands(struct evbuffer *evbuf, int argc, char **argv, char **errmsg, struct mpd_client_ctx *ctx)
{ {
int i; int i;
@ -4413,7 +4436,7 @@ mpd_read_cb(struct bufferevent *bev, void *ctx)
int close_cmd; int close_cmd;
char *argv[COMMAND_ARGV_MAX]; char *argv[COMMAND_ARGV_MAX];
int argc; int argc;
struct mpd_cmd_ctx *cmd_ctx = (struct mpd_cmd_ctx *)ctx; struct mpd_client_ctx *client_ctx = (struct mpd_client_ctx *)ctx;
/* Get the input evbuffer, contains the command sequence received from the client */ /* Get the input evbuffer, contains the command sequence received from the client */
input = bufferevent_get_input(bev); input = bufferevent_get_input(bev);
@ -4486,16 +4509,16 @@ mpd_read_cb(struct bufferevent *bev, void *ctx)
} }
else if (strcmp(command->mpdcommand, "password") == 0) else if (strcmp(command->mpdcommand, "password") == 0)
{ {
ret = command->handler(output, argc, argv, &errmsg); ret = command->handler(output, argc, argv, &errmsg, client_ctx);
cmd_ctx->authenticated = ret == 0; client_ctx->authenticated = ret == 0;
} }
else if (!cmd_ctx->authenticated) else if (!client_ctx->authenticated)
{ {
errmsg = safe_asprintf("Not authenticated"); errmsg = safe_asprintf("Not authenticated");
ret = ACK_ERROR_PERMISSION; ret = ACK_ERROR_PERMISSION;
} }
else else
ret = command->handler(output, argc, argv, &errmsg); ret = command->handler(output, argc, argv, &errmsg, client_ctx);
/* /*
* If an error occurred, add the ACK line to the response buffer and exit the loop * If an error occurred, add the ACK line to the response buffer and exit the loop
@ -4540,8 +4563,6 @@ mpd_read_cb(struct bufferevent *bev, void *ctx)
static void static void
mpd_event_cb(struct bufferevent *bev, short events, void *ctx) mpd_event_cb(struct bufferevent *bev, short events, void *ctx)
{ {
struct evbuffer *evbuf;
if (events & BEV_EVENT_ERROR) if (events & BEV_EVENT_ERROR)
{ {
DPRINTF(E_LOG, L_MPD, "Error from bufferevent: %s\n", DPRINTF(E_LOG, L_MPD, "Error from bufferevent: %s\n",
@ -4550,8 +4571,6 @@ mpd_event_cb(struct bufferevent *bev, short events, void *ctx)
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR))
{ {
evbuf = bufferevent_get_output(bev);
mpd_remove_idle_client(evbuf);
bufferevent_free(bev); bufferevent_free(bev);
} }
} }
@ -4658,25 +4677,27 @@ mpd_accept_conn_cb(struct evconnlistener *listener,
*/ */
struct event_base *base = evconnlistener_get_base(listener); struct event_base *base = evconnlistener_get_base(listener);
struct bufferevent *bev = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE); struct bufferevent *bev = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);
struct mpd_cmd_ctx *cmd_ctx = (struct mpd_cmd_ctx *)malloc(sizeof(struct mpd_cmd_ctx));
char addr_str[INET6_ADDRSTRLEN]; char addr_str[INET6_ADDRSTRLEN];
struct mpd_client_ctx *client_ctx = calloc(1, sizeof(struct mpd_client_ctx));
if (!cmd_ctx) if (!client_ctx)
{ {
DPRINTF(E_LOG, L_MPD, "Out of memory for command context\n"); DPRINTF(E_LOG, L_MPD, "Out of memory for command context\n");
bufferevent_free(bev); bufferevent_free(bev);
return; return;
} }
cmd_ctx->authenticated = !cfg_getstr(cfg_getsec(cfg, "library"), "password"); client_ctx->authenticated = !cfg_getstr(cfg_getsec(cfg, "library"), "password");
if (!cmd_ctx->authenticated) if (!client_ctx->authenticated)
{ {
sockaddr_to_string(address, addr_str, sizeof(addr_str)); sockaddr_to_string(address, addr_str, sizeof(addr_str));
cmd_ctx->authenticated = peer_address_is_trusted(addr_str); client_ctx->authenticated = peer_address_is_trusted(addr_str);
} }
client_ctx->next = mpd_clients;
mpd_clients = client_ctx;
bev = bufferevent_filter_new(bev, mpd_input_filter, NULL, BEV_OPT_CLOSE_ON_FREE, free, cmd_ctx); bev = bufferevent_filter_new(bev, mpd_input_filter, NULL, BEV_OPT_CLOSE_ON_FREE, free_mpd_client_ctx, client_ctx);
bufferevent_setcb(bev, mpd_read_cb, NULL, mpd_event_cb, cmd_ctx); bufferevent_setcb(bev, mpd_read_cb, NULL, mpd_event_cb, client_ctx);
bufferevent_enable(bev, EV_READ | EV_WRITE); bufferevent_enable(bev, EV_READ | EV_WRITE);
/* /*
@ -4684,6 +4705,9 @@ mpd_accept_conn_cb(struct evconnlistener *listener,
* of the supported mpd protocol and not the server version. * of the supported mpd protocol and not the server version.
*/ */
evbuffer_add(bufferevent_get_output(bev), "OK MPD 0.18.0\n", 14); evbuffer_add(bufferevent_get_output(bev), "OK MPD 0.18.0\n", 14);
client_ctx->evbuffer = bufferevent_get_output(bev);
DPRINTF(E_INFO, L_MPD, "New mpd client connection accepted\n");
} }
/* /*
@ -4701,54 +4725,42 @@ mpd_accept_error_cb(struct evconnlistener *listener, void *ctx)
} }
static int static int
mpd_notify_idle_client(struct idle_client *client, enum listener_event_type type) mpd_notify_idle_client(struct mpd_client_ctx *client_ctx, short events)
{ {
if (!(client->events & type)) if (!client_ctx->is_idle)
{ {
DPRINTF(E_DBG, L_MPD, "Client not listening for event: %d\n", type); client_ctx->events |= events;
return 1; return 1;
} }
switch (type) if (!(client_ctx->idle_events & events))
{ {
case LISTENER_DATABASE: DPRINTF(E_DBG, L_MPD, "Client not listening for events: %d\n", events);
evbuffer_add(client->evbuffer, "changed: database\n", 18); return 1;
break;
case LISTENER_UPDATE:
evbuffer_add(client->evbuffer, "changed: update\n", 16);
break;
case LISTENER_PLAYER:
evbuffer_add(client->evbuffer, "changed: player\n", 16);
break;
case LISTENER_QUEUE:
evbuffer_add(client->evbuffer, "changed: playlist\n", 18);
break;
case LISTENER_VOLUME:
evbuffer_add(client->evbuffer, "changed: mixer\n", 15);
break;
case LISTENER_SPEAKER:
evbuffer_add(client->evbuffer, "changed: output\n", 16);
break;
case LISTENER_OPTIONS:
evbuffer_add(client->evbuffer, "changed: options\n", 17);
break;
case LISTENER_STORED_PLAYLIST:
evbuffer_add(client->evbuffer, "changed: stored_playlist\n", 25);
break;
default:
DPRINTF(E_WARN, L_MPD, "Unsupported event type (%d) in notify idle clients.\n", type);
return -1;
} }
evbuffer_add(client->evbuffer, "OK\n", 3); if (events & LISTENER_DATABASE)
evbuffer_add(client_ctx->evbuffer, "changed: database\n", 18);
if (events & LISTENER_UPDATE)
evbuffer_add(client_ctx->evbuffer, "changed: update\n", 16);
if (events & LISTENER_PLAYER)
evbuffer_add(client_ctx->evbuffer, "changed: player\n", 16);
if (events & LISTENER_QUEUE)
evbuffer_add(client_ctx->evbuffer, "changed: playlist\n", 18);
if (events & LISTENER_VOLUME)
evbuffer_add(client_ctx->evbuffer, "changed: mixer\n", 15);
if (events & LISTENER_SPEAKER)
evbuffer_add(client_ctx->evbuffer, "changed: output\n", 16);
if (events & LISTENER_OPTIONS)
evbuffer_add(client_ctx->evbuffer, "changed: options\n", 17);
if (events & LISTENER_STORED_PLAYLIST)
evbuffer_add(client_ctx->evbuffer, "changed: stored_playlist\n", 25);
evbuffer_add(client_ctx->evbuffer, "OK\n", 3);
client_ctx->is_idle = false;
client_ctx->idle_events = 0;
client_ctx->events = 0;
return 0; return 0;
} }
@ -4757,42 +4769,20 @@ static enum command_state
mpd_notify_idle(void *arg, int *retval) mpd_notify_idle(void *arg, int *retval)
{ {
enum listener_event_type type; enum listener_event_type type;
struct idle_client *client; struct mpd_client_ctx *client;
struct idle_client *prev;
struct idle_client *next;
int i; int i;
int ret;
type = *(enum listener_event_type *)arg; type = *(enum listener_event_type *)arg;
DPRINTF(E_DBG, L_MPD, "Notify clients waiting for idle results: %d\n", type); DPRINTF(E_DBG, L_MPD, "Notify clients waiting for idle results: %d\n", type);
prev = NULL;
next = NULL;
i = 0; i = 0;
client = idle_clients; client = mpd_clients;
while (client) while (client)
{ {
DPRINTF(E_DBG, L_MPD, "Notify client #%d\n", i); DPRINTF(E_DBG, L_MPD, "Notify client #%d\n", i);
next = client->next; mpd_notify_idle_client(client, type);
client = client->next;
ret = mpd_notify_idle_client(client, type);
if (ret == 0)
{
if (prev)
prev->next = next;
else
idle_clients = next;
free(client);
}
else
{
prev = client;
}
client = next;
i++; i++;
} }
@ -5076,7 +5066,7 @@ int mpd_init(void)
pthread_set_name_np(tid_mpd, "mpd"); pthread_set_name_np(tid_mpd, "mpd");
#endif #endif
idle_clients = NULL; mpd_clients = NULL;
listener_add(mpd_listener_cb, LISTENER_PLAYER | LISTENER_QUEUE | LISTENER_VOLUME | LISTENER_SPEAKER | LISTENER_OPTIONS | LISTENER_DATABASE | LISTENER_UPDATE | LISTENER_STORED_PLAYLIST); listener_add(mpd_listener_cb, LISTENER_PLAYER | LISTENER_QUEUE | LISTENER_VOLUME | LISTENER_SPEAKER | LISTENER_OPTIONS | LISTENER_DATABASE | LISTENER_UPDATE | LISTENER_STORED_PLAYLIST);
return 0; return 0;
@ -5104,7 +5094,6 @@ int mpd_init(void)
/* Thread: main */ /* Thread: main */
void mpd_deinit(void) void mpd_deinit(void)
{ {
struct idle_client *temp;
unsigned short port; unsigned short port;
unsigned short http_port; unsigned short http_port;
int ret; int ret;
@ -5127,11 +5116,9 @@ void mpd_deinit(void)
listener_remove(mpd_listener_cb); listener_remove(mpd_listener_cb);
while (idle_clients) while (mpd_clients)
{ {
temp = idle_clients; free_mpd_client_ctx(mpd_clients);
idle_clients = idle_clients->next;
free(temp);
} }
http_port = cfg_getint(cfg_getsec(cfg, "mpd"), "http_port"); http_port = cfg_getint(cfg_getsec(cfg, "mpd"), "http_port");