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); }
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; }
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; }
struct mpd_entity * mpd_recv_entity(struct mpd_connection *connection) { struct mpd_pair *pair; struct mpd_entity *entity; pair = mpd_recv_pair(connection); if (pair == NULL) return NULL; entity = mpd_entity_begin(pair); mpd_return_pair(connection, pair); if (entity == NULL) { mpd_error_entity(&connection->error); return NULL; } while ((pair = mpd_recv_pair(connection)) != NULL && mpd_entity_feed(entity, pair)) mpd_return_pair(connection, pair); if (mpd_error_is_defined(&connection->error)) { mpd_entity_free(entity); return NULL; } /* unread this pair for the next mpd_recv_entity() call */ mpd_enqueue_pair(connection, pair); return entity; }
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; }
struct mpd_song * mpd_recv_song(struct mpd_connection *connection) { struct mpd_pair *pair; struct mpd_song *song; pair = mpd_recv_pair_named(connection, "file"); if (pair == NULL) return NULL; song = mpd_song_begin(pair); mpd_return_pair(connection, pair); if (song == NULL) { mpd_error_entity(&connection->error); return NULL; } while ((pair = mpd_recv_pair(connection)) != NULL && mpd_song_feed(song, pair)) mpd_return_pair(connection, pair); if (mpd_error_is_defined(&connection->error)) { mpd_song_free(song); return NULL; } /* unread this pair for the next mpd_recv_song() call */ mpd_enqueue_pair(connection, pair); return song; }
struct mpd_directory * mpd_recv_directory(struct mpd_connection *connection) { struct mpd_pair *pair; struct mpd_directory *directory; pair = mpd_recv_pair_named(connection, "directory"); if (pair == NULL) return NULL; directory = mpd_directory_begin(pair); mpd_return_pair(connection, pair); if (directory == NULL) { mpd_error_entity(&connection->error); return NULL; } while ((pair = mpd_recv_pair(connection)) != NULL && mpd_directory_feed(directory, pair)) mpd_return_pair(connection, pair); if (mpd_error_is_defined(&connection->error)) { assert(pair == NULL); mpd_directory_free(directory); return NULL; } /* unread this pair for the next mpd_recv_directory() call */ mpd_enqueue_pair(connection, pair); return directory; }
void mpd_error_message(struct mpd_error_info *error, const char *message) { assert(error != NULL); assert(message != NULL); assert(mpd_error_is_defined(error)); assert(error->message == NULL); error->message = strdup(message); if (error->message == NULL) error->code = MPD_ERROR_OOM; }
void mpd_error_message_n(struct mpd_error_info *error, const char *message, size_t length) { assert(error != NULL); assert(message != NULL); assert(mpd_error_is_defined(error)); assert(error->message == NULL); error->message = malloc(length + 1); if (error->message != NULL) { memcpy(error->message, message, length); error->message[length] = 0; } else error->code = MPD_ERROR_OOM; }
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; }
/** * 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; }
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; }
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; }
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; }
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; }
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; }