Example #1
0
static bool
mpd_parse_welcome(struct mpd_connection *connection, const char *output)
{
	const char *tmp;
	char * test;

	if (strncmp(output,MPD_WELCOME_MESSAGE,strlen(MPD_WELCOME_MESSAGE))) {
		mpd_error_code(&connection->error, MPD_ERROR_MALFORMED);
		mpd_error_message(&connection->error,
				  "Malformed connect message received");
		return false;
	}

	tmp = &output[strlen(MPD_WELCOME_MESSAGE)];
	connection->version[0] = strtol(tmp, &test, 10);
	if (test == tmp) {
		mpd_error_code(&connection->error, MPD_ERROR_MALFORMED);
		mpd_error_message(&connection->error,
				  "Malformed version number in connect message");
		return false;
	}

	if (*test == '.') {
		connection->version[1] = strtol(test + 1, &test, 10);
		if (*test == '.')
			connection->version[2] = strtol(test + 1, &test, 10);
		else
			connection->version[2] = 0;
	} else {
		connection->version[1] = 0;
		connection->version[2] = 0;
	}

	return true;
}
Example #2
0
void
mpd_error_entity(struct mpd_error_info *error)
{
	if (errno == EINVAL) {
		mpd_error_code(error, MPD_ERROR_MALFORMED);
		mpd_error_message(error, "Malformed entity response line");
	} else
		mpd_error_code(error, MPD_ERROR_OOM);
}
bool
mpd_command_list_begin(struct mpd_connection *connection, bool discrete_ok)
{
	bool success;

	assert(connection != NULL);

	if (connection->sending_command_list) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "already in command list mode");
		return false;
	}

	success = mpd_send_command2(connection,
				    discrete_ok
				    ? "command_list_ok_begin"
				    : "command_list_begin");
	if (!success)
		return false;

	connection->sending_command_list = true;
	connection->sending_command_list_ok = discrete_ok;
	connection->command_list_remaining = 0;
	connection->discrete_finished = false;

	return true;
}
struct mpd_playlist *
mpd_recv_playlist(struct mpd_connection *connection)
{
	struct mpd_pair *pair;
	struct mpd_playlist *playlist;

	pair = mpd_recv_pair_named(connection, "playlist");
	if (pair == NULL)
		return NULL;

	playlist = mpd_playlist_begin(pair);
	mpd_return_pair(connection, pair);
	if (playlist == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return NULL;
	}

	while ((pair = mpd_recv_pair(connection)) != NULL &&
	       mpd_playlist_feed(playlist, pair))
		mpd_return_pair(connection, pair);

	if (mpd_error_is_defined(&connection->error)) {
		assert(pair == NULL);

		mpd_playlist_free(playlist);
		return NULL;
	}

	/* unread this pair for the next mpd_recv_playlist() call */
	mpd_enqueue_pair(connection, pair);

	return playlist;
}
Example #5
0
bool
mpd_recv_queue_change_brief(struct mpd_connection *connection,
			    unsigned *position_r, unsigned *id_r)
{
	struct mpd_pair *pair;

	pair = mpd_recv_pair_named(connection, "cpos");
	if (pair == NULL)
		return false;

	*position_r = atoi(pair->value);
	mpd_return_pair(connection, pair);

	pair = mpd_recv_pair_named(connection, "Id");
	if (pair == NULL) {
		mpd_return_pair(connection, pair);

		if (!mpd_error_is_defined(&connection->error)) {
			mpd_error_code(&connection->error,
				       MPD_ERROR_MALFORMED);
			mpd_error_message(&connection->error,
					  "No id received");
		}

		return false;
	}

	*id_r = atoi(pair->value);
	mpd_return_pair(connection, pair);

	return !mpd_error_is_defined(&connection->error);
}
Example #6
0
bool
mpd_search_commit(struct mpd_connection *connection)
{
	bool success;

	assert(connection != NULL);

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

	if (connection->request == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "no search in progress");
		return false;
	}

	success = mpd_send_command(connection, connection->request, NULL);
	free(connection->request);
	connection->request = NULL;

	return success;
}
Example #7
0
struct mpd_connection *
mpd_connection_new_async(struct mpd_async *async, const char *welcome)
{
	struct mpd_connection *connection = malloc(sizeof(*connection));

	assert(async != NULL);
	assert(welcome != NULL);

	if (connection == NULL)
		return NULL;

	mpd_error_init(&connection->error);
	connection->async = async;
	connection->timeout.tv_sec = 30;
	connection->timeout.tv_usec = 0;
	connection->parser = NULL;
	connection->receiving = false;
	connection->sending_command_list = false;
	connection->pair_state = PAIR_STATE_NONE;
	connection->request = NULL;

	if (!mpd_socket_global_init(&connection->error))
		return connection;

	connection->parser = mpd_parser_new();
	if (connection->parser == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return connection;
	}

	mpd_parse_welcome(connection, welcome);

	return connection;
}
Example #8
0
struct mpd_stats *
mpd_recv_stats(struct mpd_connection *connection)
{
	struct mpd_stats * stats;
	struct mpd_pair *pair;

	assert(connection != NULL);

	if (mpd_error_is_defined(&connection->error))
		/* refuse to receive a response if the connection's
		   state is not clean */
		return NULL;

	stats = mpd_stats_begin();
	if (stats == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return NULL;
	}

	/* read and parse all response lines */
	while ((pair = mpd_recv_pair(connection)) != NULL) {
		mpd_stats_feed(stats, pair);
		mpd_return_pair(connection, pair);
	}

	if (mpd_error_is_defined(&connection->error)) {
		/* an error has occurred; roll back */
		mpd_stats_free(stats);
		return NULL;
	}

	return stats;
}
Example #9
0
static bool
mpd_search_add_constraint(struct mpd_connection *connection,
			  mpd_unused enum mpd_operator oper,
			  const char *name,
			  const char *value)
{
	size_t old_length, add_length;
	char *arg, *request;

	assert(connection != NULL);
	assert(name != NULL);
	assert(value != NULL);

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

	if (!connection->request) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "no search in progress");
		return false;
	}

	old_length = strlen(connection->request);

	arg = mpd_sanitize_arg(value);
	if (arg == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return false;
	}

	add_length = 1 + strlen(name) + 2 + strlen(arg) + 2;
	request = realloc(connection->request, old_length + add_length);
	if (request == NULL) {
		free(arg);
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return false;
	}

	connection->request = request;
	snprintf(connection->request + old_length, add_length,
		 " %s \"%s\"", name, arg);

	free(arg);
	return true;
}
Example #10
0
void
mpd_connection_sync_error(struct mpd_connection *connection)
{
	if (mpd_async_copy_error(connection->async, &connection->error)) {
		/* no error noticed by async: must be a timeout in the
		   sync.c code */
		mpd_error_code(&connection->error, MPD_ERROR_TIMEOUT);
		mpd_error_message(&connection->error, "Timeout");
	}
}
Example #11
0
struct mpd_message *
mpd_recv_message(struct mpd_connection *connection)
{
	struct mpd_message *message;
	struct mpd_pair *pair;

	pair = mpd_recv_pair_named(connection, "channel");
	if (pair == NULL)
		return NULL;

	message = mpd_message_begin(pair);
	mpd_return_pair(connection, pair);
	if (message == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return NULL;
	}

	while ((pair = mpd_recv_pair(connection)) != NULL &&
	       mpd_message_feed(message, pair))
		mpd_return_pair(connection, pair);

	if (mpd_error_is_defined(&connection->error)) {
		assert(pair == NULL);

		mpd_message_free(message);
		return NULL;
	}

	mpd_enqueue_pair(connection, pair);

	if (mpd_message_get_text(message) == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_MALFORMED);
		mpd_error_message(&connection->error,
				  "No 'message' line received");
		mpd_message_free(message);
		return NULL;
	}

	return message;
}
Example #12
0
bool
mpd_count_db_songs(struct mpd_connection *connection)
{
	assert(connection != NULL);

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

	if (connection->request) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "search already in progress");
		return false;
	}

	connection->request = strdup("count");
	if (connection->request == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return false;
	}

	return true;
}
Example #13
0
bool
mpd_search_db_tags(struct mpd_connection *connection, enum mpd_tag_type type)
{
	const char *strtype;
	int len;

	assert(connection != NULL);

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

	if (connection->request) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "search already in progress");
		return false;
	}

	strtype = mpd_tag_name(type);
	if (strtype == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_ARGUMENT);
		mpd_error_message(&connection->error,
				  "invalid type specified");
		return false;
	}

	len = 5+strlen(strtype)+1;
	connection->request = malloc(len);
	if (connection->request == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return false;
	}

	snprintf(connection->request, len, "list %s", strtype);

	return true;
}
Example #14
0
static bool
mpd_search_init(struct mpd_connection *connection, const char *cmd)
{
	assert(connection != NULL);
	assert(cmd != NULL);

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

	if (connection->request) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "search already in progress");
		return false;
	}

	connection->request = strdup(cmd);
	if (connection->request == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return false;
	}

	return true;
}
Example #15
0
/**
 * Checks whether it is possible to run a command now.
 */
bool
mpd_run_check(struct mpd_connection *connection)
{
	assert(connection != NULL);

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

	if (connection->sending_command_list) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "Not possible in command list mode");
		return false;
	}

	return true;
}
Example #16
0
bool
mpd_search_add_tag_constraint(struct mpd_connection *connection,
			      enum mpd_operator oper,
			      enum mpd_tag_type type, const char *value)
{
	const char *strtype;

	assert(connection != NULL);
	assert(value != NULL);

	strtype = mpd_tag_name(type);
	if (strtype == NULL) {
		mpd_error_code(&connection->error, MPD_ERROR_ARGUMENT);
		mpd_error_message(&connection->error,
				  "invalid type specified");
		return false;
	}

	return mpd_search_add_constraint(connection, oper, strtype, value);
}
bool
mpd_command_list_end(struct mpd_connection *connection)
{
	bool success;

	assert(connection != NULL);

	if (!connection->sending_command_list) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "not in command list mode");
		return false;
	}

	connection->sending_command_list = false;
	success = mpd_send_command(connection, "command_list_end", NULL);
	connection->sending_command_list = true;
	if (!success)
		return false;

	assert(connection->receiving);
	return true;
}
Example #18
0
struct mpd_pair *
mpd_recv_pair(struct mpd_connection *connection)
{
	struct mpd_pair *pair;
	char *line;
	enum mpd_parser_result result;
	const char *msg;

	assert(connection != NULL);

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

	/* check if the caller has returned the previous pair */
	assert(connection->pair_state != PAIR_STATE_FLOATING);

	if (connection->pair_state == PAIR_STATE_NULL) {
		/* return the enqueued NULL pair */
		connection->pair_state = PAIR_STATE_NONE;
		return NULL;
	}

	if (connection->pair_state == PAIR_STATE_QUEUED) {
		/* dequeue the pair from mpd_enqueue_pair() */
		pair = &connection->pair;
		connection->pair_state = PAIR_STATE_FLOATING;
		return pair;
	}

	assert(connection->pair_state == PAIR_STATE_NONE);

	if (!connection->receiving ||
	    (connection->sending_command_list &&
	     connection->command_list_remaining > 0 &&
	     connection->discrete_finished)) {
		mpd_error_code(&connection->error, MPD_ERROR_STATE);
		mpd_error_message(&connection->error,
				  "already done processing current command");
		return NULL;
	}

	line = mpd_sync_recv_line(connection->async,
				  mpd_connection_timeout(connection));
	if (line == NULL) {
		connection->receiving = false;
		connection->sending_command_list = false;

		mpd_connection_sync_error(connection);
		return NULL;
	}

	result = mpd_parser_feed(connection->parser, line);
	switch (result) {
	case MPD_PARSER_MALFORMED:
		mpd_error_code(&connection->error, MPD_ERROR_MALFORMED);
		mpd_error_message(&connection->error,
				  "Failed to parse MPD response");
		connection->receiving = false;
		return NULL;

	case MPD_PARSER_SUCCESS:
		if (!mpd_parser_is_discrete(connection->parser)) {
			if (connection->sending_command_list &&
			    connection->command_list_remaining > 0) {
				mpd_error_code(&connection->error,
					       MPD_ERROR_MALFORMED);
				mpd_error_message(&connection->error,
						  "expected more list_OK's");
				connection->command_list_remaining = 0;
			}

			connection->receiving = false;
			connection->sending_command_list = false;
			connection->discrete_finished = false;
		} else {
			if (!connection->sending_command_list ||
			    connection->command_list_remaining == 0) {
				mpd_error_code(&connection->error,
					       MPD_ERROR_MALFORMED);
				mpd_error_message(&connection->error,
						  "got an unexpected list_OK");
			} else {
				connection->discrete_finished = true;
				--connection->command_list_remaining;
			}
		}

		return NULL;

	case MPD_PARSER_ERROR:
		connection->receiving = false;
		connection->sending_command_list = false;
		mpd_error_server(&connection->error,
				 mpd_parser_get_server_error(connection->parser),
				 mpd_parser_get_at(connection->parser));
		msg = mpd_parser_get_message(connection->parser);
		if (msg == NULL)
			msg = "Unspecified MPD error";
		mpd_error_message(&connection->error, msg);
		return NULL;

	case MPD_PARSER_PAIR:
		pair = &connection->pair;
		pair->name = mpd_parser_get_name(connection->parser);
		pair->value = mpd_parser_get_value(connection->parser);

		connection->pair_state = PAIR_STATE_FLOATING;
		return pair;
	}

	/* unreachable */
	assert(false);
	return NULL;
}
Example #19
0
struct mpd_connection *
mpd_connection_new(const char *host, unsigned port, unsigned timeout_ms)
{
	struct mpd_connection *connection = malloc(sizeof(*connection));
	bool success;
	int fd;
	const char *line;
	char *password = NULL;


	if (connection == NULL)
		return NULL;

	mpd_error_init(&connection->error);
	connection->async = NULL;
	connection->parser = NULL;
	connection->receiving = false;
	connection->sending_command_list = false;
	connection->pair_state = PAIR_STATE_NONE;
	connection->request = NULL;

	if (!mpd_socket_global_init(&connection->error))
		return connection;

	if (timeout_ms == 0)
		/* 30s is the default */
		timeout_ms = 30000;

	mpd_connection_set_timeout(connection, timeout_ms);

	host = mpd_check_host(host, &password);
	port = mpd_check_port(port);

	fd = mpd_connect(host, port, &connection->timeout, &connection->error);
	if (fd < 0) {
		free(password);
		return connection;
	}

	connection->async = mpd_async_new(fd);
	if (connection->async == NULL) {
		free(password);
		mpd_socket_close(fd);
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return connection;
	}

	connection->parser = mpd_parser_new();
	if (connection->parser == NULL) {
		free(password);
		mpd_error_code(&connection->error, MPD_ERROR_OOM);
		return connection;
	}

	line = mpd_sync_recv_line(connection->async, &connection->timeout);
	if (line == NULL) {
		free(password);
		mpd_connection_sync_error(connection);
		return connection;
	}

	success = mpd_parse_welcome(connection, line);

	if (password != NULL) {
		if (success)
			mpd_run_password(connection, password);
		free(password);
	}

	return connection;
}