Skip to content

Commit

Permalink
Merge pull request #130 from jcorporation/protocol
Browse files Browse the repository at this point in the history
Implement new protocol command to toggle features
  • Loading branch information
jcorporation authored Oct 26, 2024
2 parents 8f63c3d + 9a1b772 commit a9f06a8
Show file tree
Hide file tree
Showing 8 changed files with 340 additions and 1 deletion.
2 changes: 1 addition & 1 deletion NEWS
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
libmpdclient 2.23 (not yet released)
* support MPD protocol 0.24.0
- allow window for listplaylist and listplaylistinfo
- command "playlistlength", "stickertypes", "stickernamestypes", "searchplaylist"
- command "playlistlength", "protocol", "stickertypes", "stickernamestypes", "searchplaylist"
- tag "ShowMovement"
- new sticker find api
- new subcommand "tagtypes available"
Expand Down
131 changes: 131 additions & 0 deletions include/mpd/capabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "recv.h"
#include "compiler.h"
#include "tag.h"
#include "feature.h"

#include <stdbool.h>

Expand Down Expand Up @@ -217,6 +218,136 @@ mpd_send_all_tag_types(struct mpd_connection *connection);
bool
mpd_run_all_tag_types(struct mpd_connection *connection);

/**
* Requests a list of enabled protocol features.
* Use mpd_recv_protocol_feature_pair() to obtain the list of
* "protocol feature" pairs.
*
* @param connection the connection to MPD
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_send_list_protocol_features(struct mpd_connection *connection);

/**
* Requests a list of available protocol features.
* Use mpd_recv_protocol_feature_pair() to obtain the list of
* "protocol feature" pairs.
*
* @param connection the connection to MPD
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_send_list_protocol_features_available(struct mpd_connection *connection);

/**
* Receives the next protocol feature name. Call this in a loop after
* mpd_send_list_protocol().
*
* Free the return value with mpd_return_pair().
*
* @param connection a #mpd_connection
* @returns a "protocol feature" pair, or NULL on error or if the end of the
* response is reached
*
* @since libmpdclient 2.23, MPD 0.24
*/
mpd_malloc
static inline struct mpd_pair *
mpd_recv_protocol_feature_pair(struct mpd_connection *connection)
{
return mpd_recv_pair_named(connection, "feature");
}

/**
* Disables one or more features from the list of protocol features.
*
* @param connection the connection to MPD
* @param features an array of protocol features to disable
* @param n the number of protocol features in the array
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_send_disable_protocol_features(struct mpd_connection *connection,
const enum mpd_protocol_feature *features, unsigned n);

/**
* Shortcut for mpd_send_disable_protocol_features() and mpd_response_finish().
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_run_disable_protocol_features(struct mpd_connection *connection,
const enum mpd_protocol_feature *features, unsigned n);

/**
* Re-enable one or more features from the list of protocol features
* for this client.
*
* @param connection the connection to MPD
* @param features an array of protocol features to enable
* @param n the number of protocol features in the array
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_send_enable_protocol_features(struct mpd_connection *connection,
const enum mpd_protocol_feature *features, unsigned n);

/**
* Shortcut for mpd_send_enable_protocol_features() and mpd_response_finish().
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_run_enable_protocol_features(struct mpd_connection *connection,
const enum mpd_protocol_feature *features, unsigned n);

/**
* Clear the list of enabled protocol features for this client.
*
* @param connection the connection to MPD
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_send_clear_protocol_features(struct mpd_connection *connection);

/**
* Shortcut for mpd_send_clear_protocol_features() and mpd_response_finish().
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_run_clear_protocol_features(struct mpd_connection *connection);

/**
* Enable all available features for this client.
*
* @param connection the connection to MPD
* @return true on success, false on error
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_send_all_protocol_features(struct mpd_connection *connection);

/**
* Shortcut for mpd_send_all_protocol_features() and mpd_response_finish().
*
* @since libmpdclient 2.23, MPD 0.24
*/
bool
mpd_run_all_protocol_features(struct mpd_connection *connection);

#ifdef __cplusplus
}
#endif
Expand Down
1 change: 1 addition & 0 deletions include/mpd/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "database.h"
#include "directory.h"
#include "entity.h"
#include "feature.h"
#include "fingerprint.h"
#include "idle.h"
#include "list.h"
Expand Down
51 changes: 51 additions & 0 deletions include/mpd/feature.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright The Music Player Daemon Project

#ifndef LIBMPDCLIENT_FEATURE_H
#define LIBMPDCLIENT_FEATURE_H

/**
* @since libmpdclient 2.23 added support for #MPD_TAG_SHOWMOVEMENT.
*/
enum mpd_protocol_feature
{
/**
* Special value returned by mpd_feature_parse() when an
* unknown name was passed.
*/
MPD_FEATURE_UNKNOWN = -1,

MPD_FEATURE_HIDE_PLAYLISTS_IN_ROOT,

/* IMPORTANT: the ordering of tag types above must be
retained, or else the libmpdclient ABI breaks */

MPD_FEATURE_COUNT
};

#ifdef __cplusplus
extern "C" {
#endif

/**
* Looks up the name of the specified protocol feature.
*
* @return the name, or NULL if the tag type is not valid
*/
const char *
mpd_feature_name(enum mpd_protocol_feature feature);

/**
* Parses a protocol feature name, and returns its #mpd_protocol_feature value.
*
* @return a #mpd_protocol_feature value, or MPD_FEATURE_UNKNOWN if the name was
* not recognized
*/
enum mpd_protocol_feature
mpd_feature_name_parse(const char *name);

#ifdef __cplusplus
}
#endif

#endif
15 changes: 15 additions & 0 deletions libmpdclient.ld
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ global:
mpd_run_clear_tag_types;
mpd_send_all_tag_types;
mpd_run_all_tag_types;
mpd_send_list_protocol_features;
mpd_send_list_protocol_features_available;
mpd_recv_protocol_feature_pair;
mpd_send_disable_protocol_features;
mpd_run_disable_protocol_features;
mpd_send_enable_protocol_features;
mpd_run_enable_protocol_features;
mpd_send_clear_protocol_features;
mpd_run_clear_protocol_features;
mpd_send_all_protocol_features;
mpd_run_all_protocol_features;

/* mpd/connection.h */
mpd_connection_new;
Expand Down Expand Up @@ -78,6 +89,10 @@ global:
mpd_entity_feed;
mpd_recv_entity;

/* mpd/feature.h */
mpd_feature_name;
mpd_feature_name_parse;

/* mpd/idle.h */
mpd_idle_name;
mpd_idle_name_parse;
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ libmpdclient = library('mpdclient',
'src/directory.c',
'src/rdirectory.c',
'src/error.c',
'src/feature.c',
'src/fd_util.c',
'src/fingerprint.c',
'src/output.c',
Expand Down
106 changes: 106 additions & 0 deletions src/capabilities.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,109 @@ mpd_run_all_tag_types(struct mpd_connection *connection)
return mpd_send_all_tag_types(connection) &&
mpd_response_finish(connection);
}

bool
mpd_send_list_protocol_features(struct mpd_connection *connection)
{
return mpd_send_command(connection, "protocol", NULL);
}

bool
mpd_send_list_protocol_features_available(struct mpd_connection *connection)
{
return mpd_send_command(connection, "protocol", "available", NULL);
}

static bool
mpd_send_protocol_features_v(struct mpd_connection *connection,
const char *sub_command,
const enum mpd_protocol_feature *features, unsigned n)
{
assert(connection != NULL);
assert(features != NULL);
assert(n > 0);

if (mpd_error_is_defined(&connection->error))
return false;

char buffer[1024] = "protocol ";
strcat(buffer, sub_command);
size_t length = strlen(buffer);

for (unsigned i = 0; i < n; ++i) {
const char *t = mpd_feature_name(features[i]);
assert(t != NULL);
size_t t_length = strlen(t);

if (length + 1 + t_length + 1 > sizeof(buffer)) {
mpd_error_code(&connection->error, MPD_ERROR_ARGUMENT);
mpd_error_message(&connection->error,
"Protocol feature list is too long");
return false;
}

buffer[length++] = ' ';
memcpy(buffer + length, t, t_length);
length += t_length;
}

buffer[length] = 0;

return mpd_send_command(connection, buffer, NULL);
}

bool
mpd_send_disable_protocol_features(struct mpd_connection *connection,
const enum mpd_protocol_feature *features, unsigned n)
{
return mpd_send_protocol_features_v(connection, "disable", features, n);
}

bool
mpd_run_disable_protocol_features(struct mpd_connection *connection,
const enum mpd_protocol_feature *features, unsigned n)
{
return mpd_send_disable_protocol_features(connection, features, n) &&
mpd_response_finish(connection);
}

bool
mpd_send_enable_protocol_features(struct mpd_connection *connection,
const enum mpd_protocol_feature *features, unsigned n)
{
return mpd_send_protocol_features_v(connection, "enable", features, n);
}

bool
mpd_run_enable_protocol_features(struct mpd_connection *connection,
const enum mpd_protocol_feature *features, unsigned n)
{
return mpd_send_enable_protocol_features(connection, features, n) &&
mpd_response_finish(connection);
}

bool
mpd_send_clear_protocol_features(struct mpd_connection *connection)
{
return mpd_send_command(connection, "protocol", "clear", NULL);
}

bool
mpd_run_clear_protocol_features(struct mpd_connection *connection)
{
return mpd_send_clear_protocol_features(connection) &&
mpd_response_finish(connection);
}

bool
mpd_send_all_protocol_features(struct mpd_connection *connection)
{
return mpd_send_command(connection, "protocol", "all", NULL);
}

bool
mpd_run_all_protocol_features(struct mpd_connection *connection)
{
return mpd_send_all_protocol_features(connection) &&
mpd_response_finish(connection);
}
34 changes: 34 additions & 0 deletions src/feature.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright The Music Player Daemon Project

#include <mpd/feature.h>

#include <assert.h>
#include <string.h>
#include <stdbool.h>

static const char *const mpd_feature_names[MPD_FEATURE_COUNT] =
{
[MPD_FEATURE_HIDE_PLAYLISTS_IN_ROOT] = "hide_playlists_in_root",
};

const char *
mpd_feature_name(enum mpd_protocol_feature feature)
{
if ((unsigned)feature >= MPD_FEATURE_COUNT)
return NULL;

return mpd_feature_names[feature];
}

enum mpd_protocol_feature
mpd_feature_name_parse(const char *name)
{
assert(name != NULL);

for (unsigned i = 0; i < MPD_FEATURE_COUNT; ++i)
if (strcmp(name, mpd_feature_names[i]) == 0)
return (enum mpd_protocol_feature)i;

return MPD_FEATURE_UNKNOWN;
}

0 comments on commit a9f06a8

Please sign in to comment.