diff --git a/src/global.c b/src/global.c index 151ac03..151ad76 100644 --- a/src/global.c +++ b/src/global.c @@ -27,35 +27,51 @@ #include #include #include +#include #include "tiny_queue.h" +#include "list.h" #include "global.h" +bool testdir(char *name, char *dirname) { + DIR* dir = opendir(dirname); + if (dir) { + closedir(dir); + LOG_INFO() printf("%s: \"%s\"\n", name, dirname); + return true; + } + else { + printf("%s: \"%s\" don't exists\n", name, dirname); + return false; + } +} + int randrange(int n) { return rand() / (RAND_MAX / (n + 1) + 1); } -void sanitize_string(const char *data) { - static char ok_chars[] = "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "1234567890_-. "; - char *cp = data; - const char *end = data + strlen(data); - for (cp += strspn(cp, ok_chars); cp != end; cp += strspn(cp, ok_chars)) - *cp = '_'; -} - bool validate_string(const char *data) { static char ok_chars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "1234567890_-. "; const char *cp = data; const char *end = data + strlen(data); - for (cp += strspn(cp, ok_chars); cp != end; cp += strspn(cp, ok_chars)) + for (cp += strspn(cp, ok_chars); cp != end; cp += strspn(cp, ok_chars)) { + printf("ERROR: Invalid character in string\n"); return false; + } return true; } +int replacechar(char *str, const char orig, const char rep) { + char *ix = str; + int n = 0; + while ((ix = strchr(ix, orig)) != NULL) { + *ix++ = rep; + n++; + } + return n; +} int copy_string(char * const dest, char const * const src, size_t const dst_len, size_t const src_len) { if (dst_len == 0 || src_len == 0) @@ -66,7 +82,7 @@ int copy_string(char * const dest, char const * const src, size_t const dst_len, return max; } -enum mypd_cmd_ids get_cmd_id(const char *cmd) { +enum mympd_cmd_ids get_cmd_id(const char *cmd) { const char * mympd_cmd_strs[] = { MYMPD_CMDS(GEN_STR) }; for (unsigned i = 0; i < sizeof(mympd_cmd_strs) / sizeof(mympd_cmd_strs[0]); i++) diff --git a/src/global.h.in b/src/global.h.in index 56424cf..d8c810f 100644 --- a/src/global.h.in +++ b/src/global.h.in @@ -45,13 +45,9 @@ //central logging definition #cmakedefine DEBUG -#define LOG_INFO() if (config.loglevel >= 1) -#define LOG_VERBOSE() if (config.loglevel >= 2) -#define LOG_DEBUG() if (config.loglevel == 3) - -#define LOG_INFO2() if (config->loglevel >= 1) -#define LOG_VERBOSE2() if (config->loglevel >= 2) -#define LOG_DEBUG2() if (config->loglevel == 3) +#define LOG_INFO() if (loglevel >= 1) +#define LOG_VERBOSE() if (loglevel >= 2) +#define LOG_DEBUG() if (loglevel == 3) //check and return buffer size #define CHECK_RETURN_LEN() do { \ @@ -122,7 +118,14 @@ #define GEN_ENUM(X) X, #define GEN_STR(X) #X, -enum mypd_cmd_ids { +//Global variables + +int loglevel; + +//signal handler +sig_atomic_t s_signal_received; + +enum mympd_cmd_ids { MYMPD_CMDS(GEN_ENUM) }; @@ -131,25 +134,21 @@ tiny_queue_t *web_server_queue; tiny_queue_t *mpd_client_queue; tiny_queue_t *mympd_api_queue; -struct work_request_t { +typedef struct t_work_request { long conn_id; // needed to identify the connection where to send the reply char data[1000]; int length; - enum mypd_cmd_ids cmd_id; -} work_request_t; + enum mympd_cmd_ids cmd_id; +} t_work_request; -struct work_result_t { +typedef struct t_work_result { long conn_id; // needed to identify the connection where to send the reply char data[MAX_SIZE]; int length; -} work_result_t; - - -//signal handler -sig_atomic_t s_signal_received; +} t_work_result; //myMPD configuration -typedef struct { +typedef struct t_config { long mpdport; const char *mpdhost; const char *mpdpass; @@ -177,15 +176,14 @@ typedef struct { const char *streamurl; unsigned long last_played_count; long loglevel; - void *syscmd_list; + struct list syscmd_list; } t_config; -t_config config; - //global functions +bool testdir(char *name, char *dirname); int randrange(int n); -void sanitize_string(const char *data); bool validate_string(const char *data); int copy_string(char * const dest, char const * const src, size_t const dst_len, size_t const src_len); -enum mypd_cmd_ids get_cmd_id(const char *cmd); +int replacechar(char *str, const char orig, const char rep); +enum mympd_cmd_ids get_cmd_id(const char *cmd); #endif diff --git a/src/main.c b/src/main.c index 03ba8f1..67f87d1 100644 --- a/src/main.c +++ b/src/main.c @@ -39,17 +39,18 @@ #include "tiny_queue.h" #include "global.h" #include "mpd_client.h" +#include "../dist/src/mongoose/mongoose.h" #include "web_server.h" #include "mympd_api.h" #include "../dist/src/inih/ini.h" -#include "../dist/src/mongoose/mongoose.h" + static void signal_handler(int sig_num) { signal(sig_num, signal_handler); // Reinstantiate signal handler s_signal_received = sig_num; } -static int inihandler(void* user, const char* section, const char* name, const char* value) { +static int inihandler(void *user, const char *section, const char *name, const char* value) { t_config* p_config = (t_config*)user; char *crap; @@ -141,178 +142,32 @@ static int inihandler(void* user, const char* section, const char* name, const c return 1; } -void read_syscmds(void *arg_config) { +void read_syscmds(t_config *config) { DIR *dir; struct dirent *ent; char dirname[400]; char *cmd; long order; - t_config *config = (t_config *) arg_config; if (config->syscmds == true) { snprintf(dirname, 400, "%s/syscmds", config->etcdir); - LOG_INFO2() printf("Reading syscmds: %s\n", dirname); + printf("Reading syscmds: %s\n", dirname); if ((dir = opendir (dirname)) != NULL) { while ((ent = readdir(dir)) != NULL) { if (strncmp(ent->d_name, ".", 1) == 0) continue; order = strtol(ent->d_name, &cmd, 10); if (strcmp(cmd, "") != 0) - list_push(config->syscmd_list, strdup(cmd), order); + list_push(&config->syscmd_list, strdup(cmd), order); } closedir(dir); } } else { - LOG_INFO2() printf("Syscmds are disabled\n"); + printf("Syscmds are disabled\n"); } } -void read_statefiles() { - char *crap; - char value[400]; - - LOG_INFO() printf("Reading states\n"); - if (mpd_client_state_get("notificationWeb", value)) { - if (strcmp(value, "true") == 0) - mympd_state.notificationWeb = true; - else - mympd_state.notificationWeb = false; - } - else { - mympd_state.notificationWeb = false; - mpd_client_state_set("notificationWeb", "false"); - } - - if (mpd_client_state_get("notificationPage", value)) { - if (strcmp(value, "true") == 0) - mympd_state.notificationPage = true; - else - mympd_state.notificationPage = false; - } - else { - mympd_state.notificationPage = true; - mpd_client_state_set("notificationPage", "true"); - } - - if (mpd_client_state_get("jukeboxMode", value)) - mympd_state.jukeboxMode = strtol(value, &crap, 10); - else { - mympd_state.jukeboxMode = 0; - mpd_client_state_set("jukeboxMode", "0"); - } - - if (mpd_client_state_get("jukeboxPlaylist", value)) - mympd_state.jukeboxPlaylist = strdup(value); - else { - mympd_state.jukeboxPlaylist = strdup("Database"); - mpd_client_state_set("jukeboxPlaylist", "Database"); - } - - if (mpd_client_state_get("jukeboxQueueLength", value)) - mympd_state.jukeboxQueueLength = strtol(value, &crap, 10); - else { - mympd_state.jukeboxQueueLength = 1; - mpd_client_state_set("jukeboxQueueLength", "1"); - } - - if (mpd_client_state_get("colsQueueCurrent", value)) - mympd_state.colsQueueCurrent = strdup(value); - else { - mympd_state.colsQueueCurrent = strdup("[\"Pos\",\"Title\",\"Artist\",\"Album\",\"Duration\"]"); - mpd_client_state_set("colsQueueCurrent", mympd_state.colsQueueCurrent); - } - - if (mpd_client_state_get("colsSearch", value)) - mympd_state.colsSearch = strdup(value); - else { - mympd_state.colsSearch = strdup("[\"Title\",\"Artist\",\"Album\",\"Duration\"]"); - mpd_client_state_set("colsSearch", mympd_state.colsSearch); - } - - if (mpd_client_state_get("colsBrowseDatabase", value)) - mympd_state.colsBrowseDatabase = strdup(value); - else { - mympd_state.colsBrowseDatabase = strdup("[\"Track\",\"Title\",\"Duration\"]"); - mpd_client_state_set("colsBrowseDatabase", mympd_state.colsBrowseDatabase); - } - - if (mpd_client_state_get("colsBrowsePlaylistsDetail", value)) - mympd_state.colsBrowsePlaylistsDetail = strdup(value); - else { - mympd_state.colsBrowsePlaylistsDetail = strdup("[\"Pos\",\"Title\",\"Artist\",\"Album\",\"Duration\"]"); - mpd_client_state_set("colsBrowsePlaylistsDetail", mympd_state.colsBrowsePlaylistsDetail); - } - - if (mpd_client_state_get("colsBrowseFilesystem", value)) - mympd_state.colsBrowseFilesystem = strdup(value); - else { - mympd_state.colsBrowseFilesystem = strdup("[\"Type\",\"Title\",\"Artist\",\"Album\",\"Duration\"]"); - mpd_client_state_set("colsBrowseFilesystem", mympd_state.colsBrowseFilesystem); - } - - if (mpd_client_state_get("colsPlayback", value)) - mympd_state.colsPlayback = strdup(value); - else { - mympd_state.colsPlayback = strdup("[\"Artist\",\"Album\",\"Genre\"]"); - mpd_client_state_set("colsPlayback", mympd_state.colsPlayback); - } - - if (mpd_client_state_get("colsQueueLastPlayed", value)) - mympd_state.colsQueueLastPlayed = strdup(value); - else { - mympd_state.colsQueueLastPlayed = strdup("[\"Pos\",\"Title\",\"Artist\",\"Album\",\"LastPlayed\"]"); - mpd_client_state_set("colsQueueLastPlayed", mympd_state.colsQueueLastPlayed); - } -} - -int read_last_played() { - char cfgfile[400]; - char *line; - char *data; - char *crap; - size_t n = 0; - ssize_t read; - long value; - - snprintf(cfgfile, 400, "%s/state/last_played", config.varlibdir); - FILE *fp = fopen(cfgfile, "r"); - if (fp == NULL) { - printf("Error opening %s\n", cfgfile); - return 0; - } - while ((read = getline(&line, &n, fp)) > 0) { - value = strtol(line, &data, 10); - if (strlen(data) > 2) - data = data + 2; - strtok_r(data, "\n", &crap); - list_push(&last_played, data, value); - } - fclose(fp); - return last_played.length;; -} - -bool testdir(char *name, char *dirname) { - DIR* dir = opendir(dirname); - if (dir) { - closedir(dir); - LOG_INFO() printf("%s: \"%s\"\n", name, dirname); - return true; - } - else { - printf("%s: \"%s\" don't exists\n", name, dirname); - return false; - } -} - -void *mpd_client_loop() { - while (s_signal_received == 0) { - mpd_client_idle(100); - } - mpd_client_disconnect(); - return NULL; -} - int main(int argc, char **argv) { s_signal_received = 0; char testdirname[400]; @@ -322,7 +177,8 @@ int main(int argc, char **argv) { srand((unsigned int)time(NULL)); - //defaults + //mympd config defaults + t_config config; config.mpdhost = "127.0.0.1"; config.mpdport = 6600; config.mpdpass = NULL; @@ -353,16 +209,10 @@ int main(int argc, char **argv) { config.localplayer = true; config.loglevel = 1; - mpd.timeout = 3000; - mpd.last_update_sticker_song_id = -1; - mpd.last_song_id = -1; - mpd.last_last_played_id = -1; - mpd.feat_library = false; - if (argc == 2) { - LOG_INFO() printf("Starting myMPD %s\n", MYMPD_VERSION); - LOG_INFO() printf("Libmpdclient %i.%i.%i\n", LIBMPDCLIENT_MAJOR_VERSION, LIBMPDCLIENT_MINOR_VERSION, LIBMPDCLIENT_PATCH_VERSION); - LOG_INFO() printf("Parsing config file: %s\n", argv[1]); + printf("Starting myMPD %s\n", MYMPD_VERSION); + printf("Libmpdclient %i.%i.%i\n", LIBMPDCLIENT_MAJOR_VERSION, LIBMPDCLIENT_MINOR_VERSION, LIBMPDCLIENT_PATCH_VERSION); + printf("Parsing config file: %s\n", argv[1]); if (ini_parse(argv[1], inihandler, &config) < 0) { printf("Can't load config file \"%s\"\n", argv[1]); return EXIT_FAILURE; @@ -383,6 +233,7 @@ int main(int argc, char **argv) { #ifdef DEBUG printf("Debug flag enabled, setting loglevel to debug\n"); config.loglevel = 3; + loglevel = config.loglevel; #endif signal(SIGTERM, signal_handler); @@ -398,7 +249,7 @@ int main(int argc, char **argv) { //drop privileges if (config.user != NULL) { - LOG_INFO() printf("Droping privileges to %s\n", config.user); + printf("Droping privileges to %s\n", config.user); struct passwd *pw; if ((pw = getpwnam(config.user)) == NULL) { printf("getpwnam() failed, unknown user\n"); @@ -430,12 +281,8 @@ int main(int argc, char **argv) { return EXIT_FAILURE; snprintf(testdirname, 400, "%s/library", DOC_ROOT); - if (testdir("Link to mpd music_directory", testdirname)) { - LOG_INFO() printf("Enabling featLibrary support\n"); - mpd.feat_library = true; - } - else { - LOG_INFO() printf("Disabling coverimage support\n"); + if (!testdir("Link to mpd music_directory", testdirname)) { + printf("Disabling coverimage support\n"); config.coverimage = false; } @@ -451,41 +298,26 @@ int main(int argc, char **argv) { if (!testdir("State dir", testdirname)) return EXIT_FAILURE; - //read myMPD states under config.varlibdir - read_statefiles(); - //read system command files - config.syscmd_list = malloc(sizeof(struct list)); - list_init(config.syscmd_list); + list_init(&config.syscmd_list); read_syscmds(&config); - list_sort_by_value(config.syscmd_list, true); + list_sort_by_value(&config.syscmd_list, true); - //init lists for tag handling - list_init(&mpd_tags); - list_init(&mympd_tags); - - //read last played songs history file - list_init(&last_played); - LOG_INFO() printf("Reading last played songs: %d\n", read_last_played()); - //Create working threads pthread_t mpd_client_thread, web_server_thread, mympd_api_thread; //mpd connection - pthread_create(&mpd_client_thread, NULL, mpd_client_loop, NULL); + pthread_create(&mpd_client_thread, NULL, mpd_client_loop, &config); //webserver pthread_create(&web_server_thread, NULL, web_server_loop, &mgr); //mympd api pthread_create(&mympd_api_thread, NULL, mympd_api_loop, &config); - //Do nothing... - + //Outsourced all work to separate threads, do nothing... //clean up pthread_join(mpd_client_thread, NULL); pthread_join(web_server_thread, NULL); - list_free(&mpd_tags); - list_free(&mympd_tags); - list_free(config.syscmd_list); + list_free(&config.syscmd_list); tiny_queue_free(web_server_queue); tiny_queue_free(mpd_client_queue); tiny_queue_free(mympd_api_queue); diff --git a/src/mpd_client.c b/src/mpd_client.c index d27b176..8ef6f07 100644 --- a/src/mpd_client.c +++ b/src/mpd_client.c @@ -39,8 +39,191 @@ #include "mpd_client.h" #include "../dist/src/frozen/frozen.h" -void mpd_client_api(void *arg_request) { - struct work_request_t *request = (struct work_request_t*) arg_request; +//private definitions +#define RETURN_ERROR_AND_RECOVER(X) do { \ + printf("MPD %s: %s\n", X, mpd_connection_get_error_message(mpd_state->conn)); \ + len = json_printf(&out, "{type: error, data: %Q}", mpd_connection_get_error_message(mpd_state->conn)); \ + if (!mpd_connection_clear_error(mpd_state->conn)) \ + mpd_state->conn_state = MPD_FAILURE; \ + return len; \ +} while (0) + +#define LOG_ERROR_AND_RECOVER(X) do { \ + printf("MPD %s: %s\n", X, mpd_connection_get_error_message(mpd_state->conn)); \ + if (!mpd_connection_clear_error(mpd_state->conn)) \ + mpd_state->conn_state = MPD_FAILURE; \ +} while (0) + +#define PUT_SONG_TAGS() do { \ + struct node *current = mpd_state->mympd_tags.list; \ + int tagnr = 0; \ + while (current != NULL) { \ + if (tagnr ++) \ + len += json_printf(&out, ","); \ + len += json_printf(&out, "%Q: %Q", current->data, mpd_client_get_tag(song, mpd_tag_name_parse(current->data))); \ + current = current->next; \ + } \ + len += json_printf(&out, ", Duration: %d, uri: %Q", mpd_song_get_duration(song), mpd_song_get_uri(song)); \ +} while (0) + +#define PUT_MIN_SONG_TAGS() do { \ + len += json_printf(&out, "Title: %Q, Duration: %d, uri: %Q", mpd_client_get_tag(song, MPD_TAG_TITLE), mpd_song_get_duration(song), mpd_song_get_uri(song)); \ +} while (0) + + +enum mpd_conn_states { + MPD_DISCONNECTED, + MPD_FAILURE, + MPD_CONNECTED, + MPD_RECONNECT, + MPD_DISCONNECT +}; + +typedef struct t_mpd_state { + // Connection + struct mpd_connection *conn; + enum mpd_conn_states conn_state; + int timeout; + + // States + int song_id; + int next_song_id; + int last_song_id; + unsigned queue_version; + unsigned queue_length; + int last_update_sticker_song_id; + int last_last_played_id; + + // Features + const unsigned* protocol; + bool feat_sticker; + bool feat_playlists; + bool feat_tags; + bool feat_library; + bool feat_advsearch; + + //mympd states + bool notificationWeb; + bool notificationPage; + int jukeboxMode; + const char *jukeboxPlaylist; + int jukeboxQueueLength; + char *colsQueueCurrent; + char *colsSearch; + char *colsBrowseDatabase; + char *colsBrowsePlaylistsDetail; + char *colsBrowseFilesystem; + char *colsPlayback; + char *colsQueueLastPlayed; + + //taglists + struct list mpd_tags; + struct list mympd_tags; + struct list mympd_searchtags; + struct list mympd_browsetags; + struct list last_played; +} t_mpd_state; + +typedef struct t_sticker { + long playCount; + long skipCount; + long lastPlayed; + long like; +} t_sticker; + +static void mpd_client_idle(t_config *config, t_mpd_state *mpd_state, const int timeout); +static void mpd_client_parse_idle(t_config *config, t_mpd_state *mpd_state, const int idle_bitmask); +static void mpd_client_api(t_config *config, t_mpd_state *mpd_state, void *arg_request); +static void mpd_client_notify(const char *message, const size_t n); +static bool mpd_client_count_song_id(t_config *config, t_mpd_state *mpd_state, const int song_id, const char *name, const int value); +static bool mpd_client_count_song_uri(t_config *config, t_mpd_state *mpd_state, const char *uri, const char *name, const int value); +static bool mpd_client_like_song_uri(t_config *config, t_mpd_state *mpd_state, const char *uri, int value); +static bool mpd_client_last_played_song_id(t_config *config, t_mpd_state *mpd_state, const int song_id); +static bool mpd_client_last_played_song_uri(t_config *config, t_mpd_state *mpd_state, const char *uri); +static bool mpd_client_get_sticker(t_config *config, t_mpd_state *mpd_state, const char *uri, t_sticker *sticker); +static bool mpd_client_last_played_list(t_config *config, t_mpd_state *mpd_state, const int song_id); +static bool mpd_client_jukebox(t_config *config, t_mpd_state *mpd_state); +static bool mpd_client_state_get(t_config *config, t_mpd_state *mpd_state, const char *name, char *value); +static bool mpd_client_state_set(t_config *config, t_mpd_state *mpd_state, const char *name, const char *value); +static bool mpd_client_smartpls_save(t_config *config, t_mpd_state *mpd_state, const char *smartpltype, const char *playlist, const char *tag, const char *searchstr, const int maxentries, const int timerange); +static int mpd_client_smartpls_put(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *playlist); +static bool mpd_client_smartpls_update_all(t_config *config, t_mpd_state *mpd_state); +static bool mpd_client_smartpls_clear(t_config *config, t_mpd_state *mpd_state, const char *playlist); +static bool mpd_client_smartpls_update_sticker(t_config *config, t_mpd_state *mpd_state, const char *playlist, const char *sticker, const int maxentries); +static bool mpd_client_smartpls_update_newest(t_config *config, t_mpd_state *mpd_state, const char *playlist, const int timerange); +static bool mpd_client_smartpls_update_search(t_config *config, t_mpd_state *mpd_state, const char *playlist, const char *tag, const char *searchstr); +static int mpd_client_get_updatedb_state(t_config *config, t_mpd_state *mpd_state, char *buffer); +static int mpd_client_put_state(t_config *config, t_mpd_state *mpd_state, char *buffer); +static int mpd_client_put_outputs(t_config *config, t_mpd_state *mpd_state, char *buffer); +static int mpd_client_put_current_song(t_config *config, t_mpd_state *mpd_state, char *buffer); +static int mpd_client_put_queue(t_config *config, t_mpd_state *mpd_state, char *buffer, const unsigned int offset); +static int mpd_client_put_browse(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *path, const unsigned int offset, const char *filter); +static int mpd_client_search(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *searchstr, const char *filter, const char *plist, const unsigned int offset); +static int mpd_client_search_adv(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *expression, const char *sort, const bool sortdesc, const char *grouptag, const char *plist, const unsigned int offset); +static int mpd_client_search_queue(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *mpdtagtype, const unsigned int offset, const char *searchstr); +static int mpd_client_put_volume(t_config *config, t_mpd_state *mpd_state, char *buffer); +static int mpd_client_put_stats(t_config *config, t_mpd_state *mpd_state, char *buffer); +static int mpd_client_put_settings(t_config *config, t_mpd_state *mpd_state, char *buffer); +static int mpd_client_put_db_tag(t_config *config, t_mpd_state *mpd_state, char *buffer, const unsigned int offset, const char *mpdtagtype, const char *mpdsearchtagtype, const char *searchstr, const char *filter); +static int mpd_client_put_songs_in_album(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *album, const char *search, const char *tag); +static int mpd_client_put_playlists(t_config *config, t_mpd_state *mpd_state, char *buffer, const unsigned int offset, const char *filter); +static int mpd_client_put_playlist_list(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *uri, const unsigned int offset, const char *filter); +static int mpd_client_put_songdetails(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *uri); +static int mpd_client_put_last_played_songs(t_config *config, t_mpd_state *mpd_state, char *buffer, const unsigned int offset); +static int mpd_client_queue_crop(t_config *config, t_mpd_state *mpd_state, char *buffer); +static void mpd_client_disconnect(t_config *config, t_mpd_state *mpd_state); +static void mpd_client_read_statefiles(t_config *config, t_mpd_state *mpd_state); +static int mpd_client_read_last_played(t_config *config, t_mpd_state *mpd_state); + +//public functions +void *mpd_client_loop(void *arg_config) { + t_config *config = (t_config *) arg_config; + //State of mpd connection + t_mpd_state mpd_state; + mpd_state.conn_state = MPD_DISCONNECTED; + mpd_state.timeout = 3000; + mpd_state.last_update_sticker_song_id = -1; + mpd_state.last_song_id = -1; + mpd_state.last_last_played_id = -1; + mpd_state.feat_library = false; + list_init(&mpd_state.mpd_tags); + list_init(&mpd_state.mympd_tags); + list_init(&mpd_state.mympd_searchtags); + list_init(&mpd_state.mympd_browsetags); + + char testdirname[400]; + snprintf(testdirname, 400, "%s/library", DOC_ROOT); + if (testdir("Link to mpd music_directory", testdirname)) { + LOG_INFO() printf("Enabling featLibrary support\n"); + mpd_state.feat_library = true; + } + + //read myMPD states under config.varlibdir + mpd_client_read_statefiles(config, &mpd_state); + + //read last played songs history file + list_init(&mpd_state.last_played); + int len = mpd_client_read_last_played(config, &mpd_state); + LOG_INFO() printf("Reading last played songs: %d\n", len); + + while (s_signal_received == 0) { + mpd_client_idle(config, &mpd_state, 100); + } + //Cleanup + mpd_client_disconnect(config, &mpd_state); + list_free(&mpd_state.mpd_tags); + list_free(&mpd_state.mympd_tags); + list_free(&mpd_state.mympd_searchtags); + list_free(&mpd_state.mympd_browsetags); + list_free(&mpd_state.last_played); + + return NULL; +} + +//private functions +static void mpd_client_api(t_config *config, t_mpd_state *mpd_state, void *arg_request) { + t_work_request *request = (t_work_request*) arg_request; + char buffer[MAX_SIZE]; size_t len = 0; unsigned int uint_buf1, uint_buf2, uint_rc; int je, int_buf1, int_rc; @@ -58,23 +241,25 @@ void mpd_client_api(void *arg_request) { clock_gettime(CLOCK_MONOTONIC_RAW, &start); #endif switch(request->cmd_id) { + case MYMPD_API_SYSCMD: + //is handled in mympd_api.c case MPD_API_UNKNOWN: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Unknown request\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Unknown request\"}"); printf("Unknown API request: %.*s\n", request->length, request->data); break; case MPD_API_LIKE: - if (config.stickers) { + if (config->stickers) { je = json_scanf(request->data, request->length, "{data: {uri: %Q, like: %d}}", &p_charbuf1, &uint_buf1); if (je == 2) { - if (!mpd_client_like_song_uri(p_charbuf1, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set like.\"}"); + if (!mpd_client_like_song_uri(config, mpd_state, p_charbuf1, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set like.\"}"); else - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); free(p_charbuf1); } } else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"MPD stickers are disabled\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"MPD stickers are disabled\"}"); printf("MPD_API_LIKE: MPD stickers are disabled\n"); } break; @@ -88,144 +273,144 @@ void mpd_client_api(void *arg_request) { if (col_len > 1) cols[col_len - 2] = '\0'; if (strcmp(p_charbuf1, "colsQueueCurrent") == 0) { - free(mympd_state.colsQueueCurrent); - mympd_state.colsQueueCurrent = strdup(cols); + free(mpd_state->colsQueueCurrent); + mpd_state->colsQueueCurrent = strdup(cols); } else if (strcmp(p_charbuf1, "colsSearch") == 0) { - free(mympd_state.colsSearch); - mympd_state.colsSearch = strdup(cols); + free(mpd_state->colsSearch); + mpd_state->colsSearch = strdup(cols); } else if (strcmp(p_charbuf1, "colsBrowseDatabase") == 0) { - free(mympd_state.colsBrowseDatabase); - mympd_state.colsBrowseDatabase = strdup(cols); + free(mpd_state->colsBrowseDatabase); + mpd_state->colsBrowseDatabase = strdup(cols); } else if (strcmp(p_charbuf1, "colsBrowsePlaylistsDetail") == 0) { - free(mympd_state.colsBrowsePlaylistsDetail); - mympd_state.colsBrowsePlaylistsDetail = strdup(cols); + free(mpd_state->colsBrowsePlaylistsDetail); + mpd_state->colsBrowsePlaylistsDetail = strdup(cols); } else if (strcmp(p_charbuf1, "colsBrowseFilesystem") == 0) { - free(mympd_state.colsBrowseFilesystem); - mympd_state.colsBrowseFilesystem = strdup(cols); + free(mpd_state->colsBrowseFilesystem); + mpd_state->colsBrowseFilesystem = strdup(cols); } else if (strcmp(p_charbuf1, "colsPlayback") == 0) { - free(mympd_state.colsPlayback); - mympd_state.colsPlayback = strdup(cols); + free(mpd_state->colsPlayback); + mpd_state->colsPlayback = strdup(cols); } else if (strcmp(p_charbuf1, "colsQueueLastPlayed") == 0) { - free(mympd_state.colsQueueLastPlayed); - mympd_state.colsQueueLastPlayed = strdup(cols); + free(mpd_state->colsQueueLastPlayed); + mpd_state->colsQueueLastPlayed = strdup(cols); } else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Unknown table %s\"}", p_charbuf1); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Unknown table %s\"}", p_charbuf1); printf("MPD_API_COLS_SAVE: Unknown table %s\n", p_charbuf1); free(p_charbuf1); break; } if (len == 0) { - if (mpd_client_state_set(p_charbuf1, cols)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_client_state_set(config, mpd_state, p_charbuf1, cols)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); } free(p_charbuf1); } break; case MPD_API_PLAYER_STATE: - len = mpd_client_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.last_song_id, &mpd.queue_version, &mpd.queue_length); + len = mpd_client_put_state(config, mpd_state, buffer); break; case MPD_API_SETTINGS_SET: - je = json_scanf(request->data, request->length, "{data: {notificationWeb: %B}}", &mympd_state.notificationWeb); + je = json_scanf(request->data, request->length, "{data: {notificationWeb: %B}}", &mpd_state->notificationWeb); if (je == 1) - if (!mpd_client_state_set("notificationWeb", (mympd_state.notificationWeb == true ? "true" : "false"))) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state notificationWeb.\"}"); + if (!mpd_client_state_set(config, mpd_state, "notificationWeb", (mpd_state->notificationWeb == true ? "true" : "false"))) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state notificationWeb.\"}"); - je = json_scanf(request->data, request->length, "{data: {notificationPage: %B}}", &mympd_state.notificationPage); + je = json_scanf(request->data, request->length, "{data: {notificationPage: %B}}", &mpd_state->notificationPage); if (je == 1) - if (!mpd_client_state_set("notificationPage", (mympd_state.notificationPage == true ? "true" : "false"))) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state notificationPage.\"}"); + if (!mpd_client_state_set(config, mpd_state, "notificationPage", (mpd_state->notificationPage == true ? "true" : "false"))) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state notificationPage.\"}"); - je = json_scanf(request->data, request->length, "{data: {jukeboxMode: %d}}", &mympd_state.jukeboxMode); + je = json_scanf(request->data, request->length, "{data: {jukeboxMode: %d}}", &mpd_state->jukeboxMode); if (je == 1) { - snprintf(p_char, 4, "%d", mympd_state.jukeboxMode); - if (!mpd_client_state_set("jukeboxMode", p_char)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state jukeboxMode.\"}"); + snprintf(p_char, 4, "%d", mpd_state->jukeboxMode); + if (!mpd_client_state_set(config, mpd_state, "jukeboxMode", p_char)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state jukeboxMode.\"}"); } - je = json_scanf(request->data, request->length, "{data: {jukeboxPlaylist: %Q}}", &mympd_state.jukeboxPlaylist); + je = json_scanf(request->data, request->length, "{data: {jukeboxPlaylist: %Q}}", &mpd_state->jukeboxPlaylist); if (je == 1) - if (!mpd_client_state_set("jukeboxPlaylist", mympd_state.jukeboxPlaylist)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state jukeboxPlaylist.\"}"); + if (!mpd_client_state_set(config, mpd_state, "jukeboxPlaylist", mpd_state->jukeboxPlaylist)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state jukeboxPlaylist.\"}"); - je = json_scanf(request->data, request->length, "{data: {jukeboxQueueLength: %d}}", &mympd_state.jukeboxQueueLength); + je = json_scanf(request->data, request->length, "{data: {jukeboxQueueLength: %d}}", &mpd_state->jukeboxQueueLength); if (je == 1) { - snprintf(p_char, 4, "%d", mympd_state.jukeboxQueueLength); - if (!mpd_client_state_set("jukeboxQueueLength", p_char)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state jukeboxQueueLength.\"}"); + snprintf(p_char, 4, "%d", mpd_state->jukeboxQueueLength); + if (!mpd_client_state_set(config, mpd_state, "jukeboxQueueLength", p_char)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set state jukeboxQueueLength.\"}"); } je = json_scanf(request->data, request->length, "{data: {random: %u}}", &uint_buf1); if (je == 1) - if (!mpd_run_random(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state random.\"}"); + if (!mpd_run_random(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state random.\"}"); je = json_scanf(request->data, request->length, "{data: {repeat: %u}}", &uint_buf1); if (je == 1) - if (!mpd_run_repeat(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state repeat.\"}"); + if (!mpd_run_repeat(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state repeat.\"}"); je = json_scanf(request->data, request->length, "{data: {consume: %u}}", &uint_buf1); if (je == 1) - if (!mpd_run_consume(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state consume.\"}"); + if (!mpd_run_consume(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state consume.\"}"); je = json_scanf(request->data, request->length, "{data: {single: %u}}", &uint_buf1); if (je == 1) - if (!mpd_run_single(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state single.\"}"); + if (!mpd_run_single(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state single.\"}"); je = json_scanf(request->data, request->length, "{data: {crossfade: %u}}", &uint_buf1); if (je == 1) - if (!mpd_run_crossfade(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state crossfade.\"}"); + if (!mpd_run_crossfade(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state crossfade.\"}"); - if (config.mixramp) { + if (config->mixramp) { je = json_scanf(request->data, request->length, "{data: {mixrampdb: %f}}", &float_buf); if (je == 1) - if (!mpd_run_mixrampdb(mpd.conn, float_buf)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state mixrampdb.\"}"); + if (!mpd_run_mixrampdb(mpd_state->conn, float_buf)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state mixrampdb.\"}"); je = json_scanf(request->data, request->length, "{data: {mixrampdelay: %f}}", &float_buf); if (je == 1) - if (!mpd_run_mixrampdelay(mpd.conn, float_buf)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state mixrampdelay.\"}"); + if (!mpd_run_mixrampdelay(mpd_state->conn, float_buf)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state mixrampdelay.\"}"); } je = json_scanf(request->data, request->length, "{data: {replaygain: %Q}}", &p_charbuf1); if (je == 1) { - if (!mpd_send_command(mpd.conn, "replay_gain_mode", p_charbuf1, NULL)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state replaygain.\"}"); - mpd_response_finish(mpd.conn); + if (!mpd_send_command(mpd_state->conn, "replay_gain_mode", p_charbuf1, NULL)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Can't set mpd state replaygain.\"}"); + mpd_response_finish(mpd_state->conn); free(p_charbuf1); } - if (mympd_state.jukeboxMode > 0) - mpd_client_jukebox(); + if (mpd_state->jukeboxMode > 0) + mpd_client_jukebox(config, mpd_state); if (len == 0) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); break; case MPD_API_DATABASE_UPDATE: - uint_rc = mpd_run_update(mpd.conn, NULL); + uint_rc = mpd_run_update(mpd_state->conn, NULL); if (uint_rc > 0) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); break; case MPD_API_DATABASE_RESCAN: - uint_rc = mpd_run_rescan(mpd.conn, NULL); + uint_rc = mpd_run_rescan(mpd_state->conn, NULL); if (uint_rc > 0) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); break; case MPD_API_SMARTPLS_UPDATE_ALL: - uint_rc = mpd_client_smartpls_update_all(); + uint_rc = mpd_client_smartpls_update_all(config, mpd_state); if (uint_rc == 0) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Smart Playlists updated\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Smart Playlists updated\"}"); else - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Smart Playlists update failed\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Smart Playlists update failed\"}"); break; case MPD_API_SMARTPLS_SAVE: je = json_scanf(request->data, request->length, "{data: {type: %Q}}", &p_charbuf1); @@ -234,7 +419,7 @@ void mpd_client_api(void *arg_request) { if (strcmp(p_charbuf1, "sticker") == 0) { je = json_scanf(request->data, request->length, "{data: {playlist: %Q, sticker: %Q, maxentries: %d}}", &p_charbuf2, &p_charbuf3, &int_buf1); if (je == 3) { - len = mpd_client_smartpls_save(p_charbuf1, p_charbuf2, p_charbuf3, NULL, int_buf1, 0); + len = mpd_client_smartpls_save(config, mpd_state, p_charbuf1, p_charbuf2, p_charbuf3, NULL, int_buf1, 0); free(p_charbuf2); free(p_charbuf3); } @@ -242,14 +427,14 @@ void mpd_client_api(void *arg_request) { else if (strcmp(p_charbuf1, "newest") == 0) { je = json_scanf(request->data, request->length, "{data: {playlist: %Q, timerange: %d}}", &p_charbuf2, &int_buf1); if (je == 2) { - len = mpd_client_smartpls_save(p_charbuf1, p_charbuf2, NULL, NULL, 0, int_buf1); + len = mpd_client_smartpls_save(config, mpd_state, p_charbuf1, p_charbuf2, NULL, NULL, 0, int_buf1); free(p_charbuf2); } } else if (strcmp(p_charbuf1, "search") == 0) { je = json_scanf(request->data, request->length, "{data: {playlist: %Q, tag: %Q, searchstr: %Q}}", &p_charbuf2, &p_charbuf3, &p_charbuf4); if (je == 3) { - len = mpd_client_smartpls_save(p_charbuf1, p_charbuf2, p_charbuf3, p_charbuf4, 0, 0); + len = mpd_client_smartpls_save(config, mpd_state, p_charbuf1, p_charbuf2, p_charbuf3, p_charbuf4, 0, 0); free(p_charbuf2); free(p_charbuf3); free(p_charbuf4); @@ -258,77 +443,77 @@ void mpd_client_api(void *arg_request) { free(p_charbuf1); } if (len == 0) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Saving playlist failed\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Saving playlist failed\"}"); break; case MPD_API_SMARTPLS_GET: je = json_scanf(request->data, request->length, "{data: {playlist: %Q}}", &p_charbuf1); if (je == 1) { - len = mpd_client_smartpls_put(mpd.buf, p_charbuf1); + len = mpd_client_smartpls_put(config, mpd_state, buffer, p_charbuf1); free(p_charbuf1); } break; case MPD_API_PLAYER_PAUSE: - if (mpd_run_toggle_pause(mpd.conn)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_toggle_pause(mpd_state->conn)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Toggling player pause failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Toggling player pause failed.\"}"); printf("MPD_API_PLAYER_PAUSE: Error mpd_run_toggle_pause()\n"); } break; case MPD_API_PLAYER_PREV: - if (mpd_run_previous(mpd.conn)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_previous(mpd_state->conn)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Goto previous song failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Goto previous song failed.\"}"); printf("MPD_API_PLAYER_PREV: Error mpd_run_previous()\n"); } break; case MPD_API_PLAYER_NEXT: - if (config.stickers) - mpd_client_count_song_id(mpd.song_id, "skipCount", 1); - if (mpd_run_next(mpd.conn)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (config->stickers) + mpd_client_count_song_id(config, mpd_state, mpd_state->song_id, "skipCount", 1); + if (mpd_run_next(mpd_state->conn)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Skip to next song failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Skip to next song failed.\"}"); printf("MPD_API_PLAYER_NEXT: Error mpd_run_next()\n"); } break; case MPD_API_PLAYER_PLAY: - if (mpd_run_play(mpd.conn)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_play(mpd_state->conn)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Begin to play failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Begin to play failed.\"}"); printf("MPD_API_PLAYER_PLAY: Error mpd_run_play()\n"); } break; case MPD_API_PLAYER_STOP: - if (mpd_run_stop(mpd.conn)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_stop(mpd_state->conn)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Stopping player failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Stopping player failed.\"}"); printf("MPD_API_PLAYER_STOP: Error mpd_run_stop()\n"); } break; case MPD_API_QUEUE_CLEAR: - if (mpd_run_clear(mpd.conn)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_clear(mpd_state->conn)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Clearing playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Clearing playlist failed.\"}"); printf("MPD_API_QUEUE_CLEAR: Error mpd_run_clear()\n"); } break; case MPD_API_QUEUE_CROP: - len = mpd_client_queue_crop(mpd.buf); + len = mpd_client_queue_crop(config, mpd_state, buffer); break; case MPD_API_QUEUE_RM_TRACK: je = json_scanf(request->data, request->length, "{data: {track:%u}}", &uint_buf1); if (je == 1) { - if (mpd_run_delete_id(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_delete_id(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Removing track from queue failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Removing track from queue failed.\"}"); printf("MPD_API_QUEUE_RM_TRACK: Error mpd_run_delete_id()\n"); } } @@ -336,10 +521,10 @@ void mpd_client_api(void *arg_request) { case MPD_API_QUEUE_RM_RANGE: je = json_scanf(request->data, request->length, "{data: {start: %u, end: %u}}", &uint_buf1, &uint_buf2); if (je == 2) { - if (mpd_run_delete_range(mpd.conn, uint_buf1, uint_buf2)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_delete_range(mpd_state->conn, uint_buf1, uint_buf2)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Removing track range from queue failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Removing track range from queue failed.\"}"); printf("MPD_API_QUEUE_RM_RANGE: Error mpd_run_delete_range()\n"); } } @@ -351,10 +536,10 @@ void mpd_client_api(void *arg_request) { uint_buf2--; if (uint_buf1 < uint_buf2) uint_buf2--; - if (mpd_run_move(mpd.conn, uint_buf1, uint_buf2)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_move(mpd_state->conn, uint_buf1, uint_buf2)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Moving track in queue failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Moving track in queue failed.\"}"); printf("MPD_API_QUEUE_MOVE_TRACK: Error mpd_run_move()\n"); } } @@ -366,12 +551,12 @@ void mpd_client_api(void *arg_request) { uint_buf2--; if (uint_buf1 < uint_buf2) uint_buf2--; - if (mpd_send_playlist_move(mpd.conn, p_charbuf1, uint_buf1, uint_buf2)) { - mpd_response_finish(mpd.conn); - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_send_playlist_move(mpd_state->conn, p_charbuf1, uint_buf1, uint_buf2)) { + mpd_response_finish(mpd_state->conn); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); } else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Moving track in playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Moving track in playlist failed.\"}"); printf("MPD_API_PLAYLIST_MOVE_TRACK: Error mpd_send_playlist_move()\n"); } free(p_charbuf1); @@ -380,33 +565,33 @@ void mpd_client_api(void *arg_request) { case MPD_API_PLAYER_PLAY_TRACK: je = json_scanf(request->data, request->length, "{data: { track:%u}}", &uint_buf1); if (je == 1) { - if (mpd_run_play_id(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_play_id(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Set playing track failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Set playing track failed.\"}"); printf("MPD_API_PLAYER_PLAY_TRACK: Error mpd_run_play_id()\n"); } } break; case MPD_API_PLAYER_OUTPUT_LIST: - len = mpd_client_put_outputs(mpd.buf); + len = mpd_client_put_outputs(config, mpd_state, buffer); break; case MPD_API_PLAYER_TOGGLE_OUTPUT: je = json_scanf(request->data, request->length, "{data: {output: %u, state: %u}}", &uint_buf1, &uint_buf2); if (je == 2) { if (uint_buf2) { - if (mpd_run_enable_output(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_enable_output(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Enabling output failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Enabling output failed.\"}"); printf("MPD_API_PLAYER_TOGGLE_OUTPUT: Error mpd_run_enable_output()\n"); } } else { - if (mpd_run_disable_output(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_disable_output(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Disabling output failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Disabling output failed.\"}"); printf("MPD_API_PLAYER_TOGGLE_OUTPUT: Error mpd_run_disable_output()\n"); } } @@ -415,24 +600,24 @@ void mpd_client_api(void *arg_request) { case MPD_API_PLAYER_VOLUME_SET: je = json_scanf(request->data, request->length, "{data: {volume:%u}}", &uint_buf1); if (je == 1) { - if (mpd_run_set_volume(mpd.conn, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_set_volume(mpd_state->conn, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Setting volume failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Setting volume failed.\"}"); printf("MPD_API_PLAYER_PLAY_TRACK: Error mpd_run_set_volume()\n"); } } break; case MPD_API_PLAYER_VOLUME_GET: - len = mpd_client_put_volume(mpd.buf); + len = mpd_client_put_volume(config, mpd_state, buffer); break; case MPD_API_PLAYER_SEEK: je = json_scanf(request->data, request->length, "{data: {songid: %u, seek: %u}}", &uint_buf1, &uint_buf2); if (je == 2) { - if (mpd_run_seek_id(mpd.conn, uint_buf1, uint_buf2)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_seek_id(mpd_state->conn, uint_buf1, uint_buf2)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Seeking song failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Seeking song failed.\"}"); printf("MPD_API_PLAYER_SEEK: Error mpd_run_seek_id()\n"); } } @@ -440,29 +625,29 @@ void mpd_client_api(void *arg_request) { case MPD_API_QUEUE_LIST: je = json_scanf(request->data, request->length, "{data: {offset: %u}}", &uint_buf1); if (je == 1) { - len = mpd_client_put_queue(mpd.buf, uint_buf1, &mpd.queue_version, &mpd.queue_length); + len = mpd_client_put_queue(config, mpd_state, buffer, uint_buf1); } break; case MPD_API_QUEUE_LAST_PLAYED: je = json_scanf(request->data, request->length, "{data: {offset: %u}}", &uint_buf1); if (je == 1) { - len = mpd_client_put_last_played_songs(mpd.buf, uint_buf1); + len = mpd_client_put_last_played_songs(config, mpd_state, buffer, uint_buf1); } break; case MPD_API_PLAYER_CURRENT_SONG: - len = mpd_client_put_current_song(mpd.buf); + len = mpd_client_put_current_song(config, mpd_state, buffer); break; case MPD_API_DATABASE_SONGDETAILS: je = json_scanf(request->data, request->length, "{data: { uri: %Q}}", &p_charbuf1); if (je == 1) { - len = mpd_client_put_songdetails(mpd.buf, p_charbuf1); + len = mpd_client_put_songdetails(config, mpd_state, buffer, p_charbuf1); free(p_charbuf1); } break; case MPD_API_DATABASE_TAG_LIST: je = json_scanf(request->data, request->length, "{data: {offset: %u, filter: %Q, tag: %Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2); if (je == 3) { - len = mpd_client_put_db_tag(mpd.buf, uint_buf1, p_charbuf2, "", "", p_charbuf1); + len = mpd_client_put_db_tag(config, mpd_state, buffer, uint_buf1, p_charbuf2, "", "", p_charbuf1); free(p_charbuf1); free(p_charbuf2); } @@ -470,7 +655,7 @@ void mpd_client_api(void *arg_request) { case MPD_API_DATABASE_TAG_ALBUM_LIST: je = json_scanf(request->data, request->length, "{data: {offset: %u, filter: %Q, search: %Q, tag: %Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2, &p_charbuf3); if (je == 4) { - len = mpd_client_put_db_tag(mpd.buf, uint_buf1, "Album", p_charbuf3, p_charbuf2, p_charbuf1); + len = mpd_client_put_db_tag(config, mpd_state, buffer, uint_buf1, "Album", p_charbuf3, p_charbuf2, p_charbuf1); free(p_charbuf1); free(p_charbuf2); free(p_charbuf3); @@ -479,7 +664,7 @@ void mpd_client_api(void *arg_request) { case MPD_API_DATABASE_TAG_ALBUM_TITLE_LIST: je = json_scanf(request->data, request->length, "{data: {album: %Q, search: %Q, tag: %Q}}", &p_charbuf1, &p_charbuf2, &p_charbuf3); if (je == 3) { - len = mpd_client_put_songs_in_album(mpd.buf, p_charbuf1, p_charbuf2, p_charbuf3); + len = mpd_client_put_songs_in_album(config, mpd_state, buffer, p_charbuf1, p_charbuf2, p_charbuf3); free(p_charbuf1); free(p_charbuf2); free(p_charbuf3); @@ -491,31 +676,33 @@ void mpd_client_api(void *arg_request) { //rename smart playlist char old_pl_file[400]; char new_pl_file[400]; - sanitize_string(p_charbuf1); - sanitize_string(p_charbuf2); - snprintf(old_pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf1); - snprintf(new_pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf2); + if (validate_string(p_charbuf1) == false || validate_string(p_charbuf2) == false) { + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Invalid filename.\"}"); + break; + } + snprintf(old_pl_file, 400, "%s/smartpls/%s", config->varlibdir, p_charbuf1); + snprintf(new_pl_file, 400, "%s/smartpls/%s", config->varlibdir, p_charbuf2); if (access(old_pl_file, F_OK ) != -1) { if (access(new_pl_file, F_OK ) == -1) { if (rename(old_pl_file, new_pl_file) == -1) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Renaming playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Renaming playlist failed.\"}"); printf("MPD_API_PLAYLIST_RENAME: Rename failed()\n"); } //rename mpd playlist - else if (mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2); + else if (mpd_run_rename(mpd_state->conn, p_charbuf1, p_charbuf2)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Renaming playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Renaming playlist failed.\"}"); printf("MPD_API_PLAYLIST_RENAME: Error mpd_run_rename()\n"); } } else - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Destination playlist %s already exists\"}", p_charbuf2); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Destination playlist %s already exists\"}", p_charbuf2); } else { - if (mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2); + if (mpd_run_rename(mpd_state->conn, p_charbuf1, p_charbuf2)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Renaming playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Renaming playlist failed.\"}"); printf("MPD_API_PLAYLIST_RENAME: Error mpd_run_rename()\n"); } } @@ -526,14 +713,14 @@ void mpd_client_api(void *arg_request) { case MPD_API_PLAYLIST_LIST: je = json_scanf(request->data, request->length, "{data: {offset: %u, filter: %Q}}", &uint_buf1, &p_charbuf1); if (je == 2) { - len = mpd_client_put_playlists(mpd.buf, uint_buf1, p_charbuf1); + len = mpd_client_put_playlists(config, mpd_state, buffer, uint_buf1, p_charbuf1); free(p_charbuf1); } break; case MPD_API_PLAYLIST_CONTENT_LIST: je = json_scanf(request->data, request->length, "{data: {uri: %Q, offset:%u, filter:%Q}}", &p_charbuf1, &uint_buf1, &p_charbuf2); if (je == 3) { - len = mpd_client_put_playlist_list(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2); + len = mpd_client_put_playlist_list(config, mpd_state, buffer, p_charbuf1, uint_buf1, p_charbuf2); free(p_charbuf1); free(p_charbuf2); } @@ -541,10 +728,10 @@ void mpd_client_api(void *arg_request) { case MPD_API_PLAYLIST_ADD_TRACK: je = json_scanf(request->data, request->length, "{data: {plist:%Q, uri:%Q}}", &p_charbuf1, &p_charbuf2); if (je == 2) { - if (mpd_run_playlist_add(mpd.conn, p_charbuf1, p_charbuf2)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Added %s to playlist %s\"}", p_charbuf2, p_charbuf1); + if (mpd_run_playlist_add(mpd_state->conn, p_charbuf1, p_charbuf2)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Added %s to playlist %s\"}", p_charbuf2, p_charbuf1); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding song to playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding song to playlist failed.\"}"); printf("MPD_API_PLAYLIST_ADD_TRACK: Error mpd_run_playlist_add()\n"); } free(p_charbuf1); @@ -554,10 +741,10 @@ void mpd_client_api(void *arg_request) { case MPD_API_PLAYLIST_CLEAR: je = json_scanf(request->data, request->length, "{data: {uri:%Q}}", &p_charbuf1); if (je == 1) { - if (mpd_run_playlist_clear(mpd.conn, p_charbuf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_playlist_clear(mpd_state->conn, p_charbuf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Clearing playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Clearing playlist failed.\"}"); printf("MPD_API_PLAYLIST_CLEAR: Error mpd_run_playlist_clear()\n"); } free(p_charbuf1); @@ -566,10 +753,10 @@ void mpd_client_api(void *arg_request) { case MPD_API_PLAYLIST_RM_TRACK: je = json_scanf(request->data, request->length, "{data: {uri:%Q, track:%u}}", &p_charbuf1, &uint_buf1); if (je == 2) { - if (mpd_run_playlist_delete(mpd.conn, p_charbuf1, uint_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_playlist_delete(mpd_state->conn, p_charbuf1, uint_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Removing track from playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Removing track from playlist failed.\"}"); printf("MPD_API_PLAYLIST_RM_TRACK: Error mpd_run_playlist_delete()\n"); } free(p_charbuf1); @@ -578,7 +765,7 @@ void mpd_client_api(void *arg_request) { case MPD_API_DATABASE_FILESYSTEM_LIST: je = json_scanf(request->data, request->length, "{data: {offset:%u, filter:%Q, path:%Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2); if (je == 3) { - len = mpd_client_put_browse(mpd.buf, p_charbuf2, uint_buf1, p_charbuf1); + len = mpd_client_put_browse(config, mpd_state, buffer, p_charbuf2, uint_buf1, p_charbuf1); free(p_charbuf1); free(p_charbuf2); } @@ -586,11 +773,11 @@ void mpd_client_api(void *arg_request) { case MPD_API_QUEUE_ADD_TRACK_AFTER: je = json_scanf(request->data, request->length, "{data: {uri:%Q, to:%d}}", &p_charbuf1, &int_buf1); if (je == 2) { - int_rc = mpd_run_add_id_to(mpd.conn, p_charbuf1, int_buf1); + int_rc = mpd_run_add_id_to(mpd_state->conn, p_charbuf1, int_buf1); if (int_rc > -1 ) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding track to queue failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding track to queue failed.\"}"); printf("MPD_API_QUEUE_ADD_TRACK_AFTER: Error mpd_run_add_id_to()\n"); } free(p_charbuf1); @@ -599,30 +786,30 @@ void mpd_client_api(void *arg_request) { case MPD_API_QUEUE_REPLACE_TRACK: je = json_scanf(request->data, request->length, "{data: {uri:%Q }}", &p_charbuf1); if (je == 1) { - if (!mpd_run_clear(mpd.conn)) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Clearing queue failed.\"}"); + if (!mpd_run_clear(mpd_state->conn)) { + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Clearing queue failed.\"}"); printf("MPD_API_QUEUE_REPLACE_TRACK: Error mpd_run_add_id_to()\n"); } - else if (!mpd_run_add(mpd.conn, p_charbuf1)) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding track to queue failed.\"}"); + else if (!mpd_run_add(mpd_state->conn, p_charbuf1)) { + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding track to queue failed.\"}"); printf("MPD_API_QUEUE_REPLACE_TRACK: Error mpd_run_add_id_to()\n"); } - else if (!mpd_run_play(mpd.conn)) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Playing failed.\"}"); + else if (!mpd_run_play(mpd_state->conn)) { + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Playing failed.\"}"); printf("MPD_API_QUEUE_REPLACE_TRACK: Error mpd_run_play()\n"); } else - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); free(p_charbuf1); } break; case MPD_API_QUEUE_ADD_TRACK: je = json_scanf(request->data, request->length, "{data: {uri:%Q}}", &p_charbuf1); if (je == 1) { - if (mpd_run_add(mpd.conn, p_charbuf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_add(mpd_state->conn, p_charbuf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Append track to queue failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Append track to queue failed.\"}"); printf("MPD_API_QUEUE_ADD_TRACK: Error mpd_run_add()\n"); } free(p_charbuf1); @@ -631,17 +818,17 @@ void mpd_client_api(void *arg_request) { case MPD_API_QUEUE_ADD_PLAY_TRACK: je = json_scanf(request->data, request->length, "{data: {uri:%Q}}", &p_charbuf1); if (je == 1) { - int_buf1 = mpd_run_add_id(mpd.conn, p_charbuf1); + int_buf1 = mpd_run_add_id(mpd_state->conn, p_charbuf1); if (int_buf1 != -1) { - if (mpd_run_play_id(mpd.conn, int_buf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_play_id(mpd_state->conn, int_buf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Setting playstate failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Setting playstate failed.\"}"); printf("MPD_API_QUEUE_ADD_PLAY_TRACK: Error mpd_run_play_id()\n"); } } else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding track to queue failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding track to queue failed.\"}"); printf("MPD_API_QUEUE_ADD_PLAY_TRACK: Error mpd_run_add_id()\n"); } free(p_charbuf1); @@ -650,30 +837,30 @@ void mpd_client_api(void *arg_request) { case MPD_API_QUEUE_REPLACE_PLAYLIST: je = json_scanf(request->data, request->length, "{data: {plist:%Q}}", &p_charbuf1); if (je == 1) { - if (!mpd_run_clear(mpd.conn)) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Clearing queue failed.\"}"); + if (!mpd_run_clear(mpd_state->conn)) { + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Clearing queue failed.\"}"); printf("MPD_API_QUEUE_REPLACE_PLAYLIST: Error mpd_run_clear()\n"); } - else if (!mpd_run_load(mpd.conn, p_charbuf1)) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding playlist to queue failed.\"}"); + else if (!mpd_run_load(mpd_state->conn, p_charbuf1)) { + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding playlist to queue failed.\"}"); printf("MPD_API_QUEUE_REPLACE_PLAYLIST: Error mpd_run_load()\n"); } - else if (!mpd_run_play(mpd.conn)) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Setting playstate failed.\"}"); + else if (!mpd_run_play(mpd_state->conn)) { + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Setting playstate failed.\"}"); printf("MPD_API_QUEUE_REPLACE_PLAYLIST: Error mpd_run_play()\n"); } else - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); free(p_charbuf1); } break; case MPD_API_QUEUE_ADD_PLAYLIST: je = json_scanf(request->data, request->length, "{data: {plist:%Q}}", &p_charbuf1); if (je == 1) { - if (mpd_run_load(mpd.conn, p_charbuf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_load(mpd_state->conn, p_charbuf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding playlist to queue failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Adding playlist to queue failed.\"}"); printf("MPD_API_QUEUE_ADD_PLAYLIST: Error mpd_run_add_id()\n"); } free(p_charbuf1); @@ -682,10 +869,10 @@ void mpd_client_api(void *arg_request) { case MPD_API_QUEUE_SAVE: je = json_scanf(request->data, request->length, "{ data: {plist:%Q}}", &p_charbuf1); if (je == 1) { - if (mpd_run_save(mpd.conn, p_charbuf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_save(mpd_state->conn, p_charbuf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Saving queue as playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Saving queue as playlist failed.\"}"); printf("MPD_API_QUEUE_SAVE: Error mpd_run_save()\n"); } free(p_charbuf1); @@ -694,7 +881,7 @@ void mpd_client_api(void *arg_request) { case MPD_API_QUEUE_SEARCH: je = json_scanf(request->data, request->length, "{data: {offset:%u, filter:%Q, searchstr:%Q}}", &uint_buf1, &p_charbuf1, &p_charbuf2); if (je == 3) { - len = mpd_client_search_queue(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2); + len = mpd_client_search_queue(config, mpd_state, buffer, p_charbuf1, uint_buf1, p_charbuf2); free(p_charbuf1); free(p_charbuf2); } @@ -702,7 +889,7 @@ void mpd_client_api(void *arg_request) { case MPD_API_DATABASE_SEARCH: je = json_scanf(request->data, request->length, "{data: {searchstr:%Q, filter:%Q, plist:%Q, offset:%u}}", &p_charbuf1, &p_charbuf2, &p_charbuf3, &uint_buf1); if (je == 4) { - len = mpd_client_search(mpd.buf, p_charbuf1, p_charbuf2, p_charbuf3, uint_buf1); + len = mpd_client_search(config, mpd_state, buffer, p_charbuf1, p_charbuf2, p_charbuf3, uint_buf1); free(p_charbuf1); free(p_charbuf2); } @@ -711,17 +898,17 @@ void mpd_client_api(void *arg_request) { je = json_scanf(request->data, request->length, "{data: {expression:%Q, sort:%Q, sortdesc:%B, plist:%Q, offset:%u}}", &p_charbuf1, &p_charbuf2, &bool_buf, &p_charbuf3, &uint_buf1); if (je == 5) { - len = mpd_client_search_adv(mpd.buf, p_charbuf1, p_charbuf2, bool_buf, NULL, p_charbuf3, uint_buf1); + len = mpd_client_search_adv(config, mpd_state, buffer, p_charbuf1, p_charbuf2, bool_buf, NULL, p_charbuf3, uint_buf1); free(p_charbuf1); free(p_charbuf2); free(p_charbuf3); } break; case MPD_API_QUEUE_SHUFFLE: - if (mpd_run_shuffle(mpd.conn)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_shuffle(mpd_state->conn)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Shuffling queue failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Shuffling queue failed.\"}"); printf("MPD_API_QUEUE_SHUFFLE: Error mpd_run_shuffle()\n"); } break; @@ -730,42 +917,45 @@ void mpd_client_api(void *arg_request) { if (je == 1) { //remove smart playlist char pl_file[400]; - sanitize_string(p_charbuf1); - snprintf(pl_file, 400, "%s/smartpls/%s", config.varlibdir, p_charbuf1); + if (validate_string(p_charbuf1) == false) { + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Invalid filename.\"}"); + break; + } + snprintf(pl_file, 400, "%s/smartpls/%s", config->varlibdir, p_charbuf1); if (access(pl_file, F_OK ) != -1 ) { if (unlink(pl_file) == -1) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Deleting smart playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Deleting smart playlist failed.\"}"); printf("MPD_API_PLAYLIST_RM: Error unlinking smart playlist file()\n"); free(p_charbuf1); break; } } //remove mpd playlist - if (mpd_run_rm(mpd.conn, p_charbuf1)) - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); + if (mpd_run_rm(mpd_state->conn, p_charbuf1)) + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}"); else { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Deleting playlist failed.\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Deleting playlist failed.\"}"); printf("MPD_API_QUEUE_SHUFFLE: Error mpd_run_rm()\n"); } free(p_charbuf1); } break; case MPD_API_SETTINGS_GET: - len = mpd_client_put_settings(mpd.buf, &config); + len = mpd_client_put_settings(config, mpd_state, buffer); break; case MPD_API_DATABASE_STATS: - len = mpd_client_put_stats(mpd.buf); + len = mpd_client_put_stats(config, mpd_state, buffer); break; } - if (mpd.conn_state == MPD_CONNECTED && mpd_connection_get_error(mpd.conn) != MPD_ERROR_SUCCESS) { - printf("Error: %s\n", mpd_connection_get_error_message(mpd.conn)); - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\":\"error\", \"data\": \"%s\"}", - mpd_connection_get_error_message(mpd.conn)); + if (mpd_state->conn_state == MPD_CONNECTED && mpd_connection_get_error(mpd_state->conn) != MPD_ERROR_SUCCESS) { + printf("Error: %s\n", mpd_connection_get_error_message(mpd_state->conn)); + len = snprintf(buffer, MAX_SIZE, "{\"type\":\"error\", \"data\": \"%s\"}", + mpd_connection_get_error_message(mpd_state->conn)); /* Try to recover error */ - if (!mpd_connection_clear_error(mpd.conn)) - mpd.conn_state = MPD_FAILURE; + if (!mpd_connection_clear_error(mpd_state->conn)) + mpd_state->conn_state = MPD_FAILURE; } #ifdef DEBUG @@ -779,29 +969,31 @@ void mpd_client_api(void *arg_request) { #endif if (len == 0) { - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"No response for cmd_id %u.\"}", request->cmd_id); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"No response for cmd_id %u.\"}", request->cmd_id); } - LOG_DEBUG() fprintf(stderr, "DEBUG: Send http response to connection %lu (first 800 chars):\n%*.*s\n", request->conn_id, 0, 800, mpd.buf); + LOG_DEBUG() fprintf(stderr, "DEBUG: Send http response to connection %lu (first 800 chars):\n%*.*s\n", request->conn_id, 0, 800, buffer); - struct work_result_t *response = (struct work_result_t*)malloc(sizeof(struct work_result_t)); + t_work_result *response = (t_work_result*)malloc(sizeof(t_work_result)); response->conn_id = request->conn_id; - response->length = copy_string(response->data, mpd.buf, MAX_SIZE, len); + response->length = copy_string(response->data, buffer, MAX_SIZE, len); tiny_queue_push(web_server_queue, response); free(request); } -void mpd_client_notify(size_t len) { - LOG_DEBUG() fprintf(stderr, "DEBUG: Websocket notify: %s.\n", mpd.buf); +static void mpd_client_notify(const char *message, const size_t len) { + LOG_DEBUG() fprintf(stderr, "DEBUG: Websocket notify: %s.\n", message); - struct work_result_t *response = (struct work_result_t*)malloc(sizeof(struct work_result_t)); + t_work_result *response = (t_work_result *)malloc(sizeof(t_work_result)); response->conn_id = 0; - response->length = copy_string(response->data, mpd.buf, MAX_SIZE, len); + response->length = copy_string(response->data, message, MAX_SIZE, len); tiny_queue_push(web_server_queue, response); } -void mpd_client_parse_idle(int idle_bitmask) { +static void mpd_client_parse_idle(t_config *config, t_mpd_state *mpd_state, int idle_bitmask) { size_t len = 0; + char buffer[MAX_SIZE]; + for (unsigned j = 0;; j++) { enum mpd_idle idle_event = 1 << j; const char *idle_name = mpd_idle_name(idle_event); @@ -811,131 +1003,131 @@ void mpd_client_parse_idle(int idle_bitmask) { LOG_VERBOSE() printf("MPD idle event: %s\n", idle_name); switch(idle_event) { case MPD_IDLE_DATABASE: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_database\"}"); - mpd_client_smartpls_update_all(); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"update_database\"}"); + mpd_client_smartpls_update_all(config, mpd_state); break; case MPD_IDLE_STORED_PLAYLIST: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_stored_playlist\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"update_stored_playlist\"}"); break; case MPD_IDLE_QUEUE: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_queue\"}"); - if (mympd_state.jukeboxMode > 0) - mpd_client_jukebox(); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"update_queue\"}"); + if (mpd_state->jukeboxMode > 0) + mpd_client_jukebox(config, mpd_state); break; case MPD_IDLE_PLAYER: - len = mpd_client_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.last_song_id, &mpd.queue_version, &mpd.queue_length); - if (mpd.song_id != mpd.last_song_id) { - if (mpd.last_last_played_id != mpd.song_id) - mpd_client_last_played_list(mpd.song_id); - if (config.stickers && mpd.last_update_sticker_song_id != mpd.song_id) { - mpd_client_count_song_id(mpd.song_id, "playCount", 1); - mpd_client_last_played_song_id(mpd.song_id); - mpd.last_update_sticker_song_id = mpd.song_id; + len = mpd_client_put_state(config, mpd_state, buffer); + if (mpd_state->song_id != mpd_state->last_song_id) { + if (mpd_state->last_last_played_id != mpd_state->song_id) + mpd_client_last_played_list(config, mpd_state, mpd_state->song_id); + if (config->stickers && mpd_state->last_update_sticker_song_id != mpd_state->song_id) { + mpd_client_count_song_id(config, mpd_state, mpd_state->song_id, "playCount", 1); + mpd_client_last_played_song_id(config, mpd_state, mpd_state->song_id); + mpd_state->last_update_sticker_song_id = mpd_state->song_id; } } break; case MPD_IDLE_MIXER: - len = mpd_client_put_volume(mpd.buf); + len = mpd_client_put_volume(config, mpd_state, buffer); break; case MPD_IDLE_OUTPUT: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_outputs\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"update_outputs\"}"); break; case MPD_IDLE_OPTIONS: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_options\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"update_options\"}"); break; case MPD_IDLE_UPDATE: - len = mpd_client_get_updatedb_state(mpd.buf); + len = mpd_client_get_updatedb_state(config, mpd_state, buffer); break; case MPD_IDLE_STICKER: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_sticker\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"update_sticker\"}"); break; case MPD_IDLE_SUBSCRIPTION: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_subscription\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"update_subscription\"}"); break; case MPD_IDLE_MESSAGE: - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_message\"}"); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"update_message\"}"); break; default: len = 0; } if (len > 0) { - mpd_client_notify(len); + mpd_client_notify(buffer, len); } } } } -void mpd_client_mpd_features() { +static void mpd_client_mpd_features(t_config *config, t_mpd_state *mpd_state) { struct mpd_pair *pair; char s[2] = ","; - char *taglist = strdup(config.taglist); - char *searchtaglist = strdup(config.searchtaglist); - char *browsetaglist = strdup(config.browsetaglist); + char *taglist = strdup(config->taglist); + char *searchtaglist = strdup(config->searchtaglist); + char *browsetaglist = strdup(config->browsetaglist); char *token, *rest; - mpd.protocol = mpd_connection_get_server_version(mpd.conn); + mpd_state->protocol = mpd_connection_get_server_version(mpd_state->conn); - LOG_INFO() printf("MPD protocoll version: %u.%u.%u\n", mpd.protocol[0], mpd.protocol[1], mpd.protocol[2]); + LOG_INFO() printf("MPD protocoll version: %u.%u.%u\n", mpd_state->protocol[0], mpd_state->protocol[1], mpd_state->protocol[2]); // Defaults - mpd.feat_sticker = false; - mpd.feat_playlists = false; - mpd.feat_tags = false; - mpd.feat_advsearch = false; + mpd_state->feat_sticker = false; + mpd_state->feat_playlists = false; + mpd_state->feat_tags = false; + mpd_state->feat_advsearch = false; - if (mpd_send_allowed_commands(mpd.conn)) { - while ((pair = mpd_recv_command_pair(mpd.conn)) != NULL) { + if (mpd_send_allowed_commands(mpd_state->conn)) { + while ((pair = mpd_recv_command_pair(mpd_state->conn)) != NULL) { if (strcmp(pair->value, "sticker") == 0) - mpd.feat_sticker = true; - if (strcmp(pair->value, "listplaylists") == 0) - mpd.feat_playlists = true; - mpd_return_pair(mpd.conn, pair); + mpd_state->feat_sticker = true; + else if (strcmp(pair->value, "listplaylists") == 0) + mpd_state->feat_playlists = true; + mpd_return_pair(mpd_state->conn, pair); } - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); } else { LOG_ERROR_AND_RECOVER("mpd_send_allowed_commands"); } - if (mpd.feat_sticker == false && config.stickers == true) { + if (mpd_state->feat_sticker == false && config->stickers == true) { LOG_INFO() printf("MPD don't support stickers, disabling myMPD feature\n"); - config.stickers = false; + config->stickers = false; } - if (config.stickers == false && config.smartpls == true) { + if (config->stickers == false && config->smartpls == true) { LOG_INFO() printf("Stickers are disabled, disabling smartplaylists\n"); - config.smartpls = false; + config->smartpls = false; } - if (mpd.feat_playlists == false && config.smartpls == true) { + if (mpd_state->feat_playlists == false && config->smartpls == true) { LOG_INFO() printf("Playlists are disabled, disabling smartplaylists\n"); - config.smartpls = false; + config->smartpls = false; } LOG_INFO() printf("MPD supported tags: "); - list_free(&mpd_tags); - if (mpd_send_list_tag_types(mpd.conn)) { - while ((pair = mpd_recv_tag_type_pair(mpd.conn)) != NULL) { + list_free(&mpd_state->mpd_tags); + if (mpd_send_list_tag_types(mpd_state->conn)) { + while ((pair = mpd_recv_tag_type_pair(mpd_state->conn)) != NULL) { LOG_INFO() printf("%s ", pair->value); - list_push(&mpd_tags, pair->value, 1); - mpd_return_pair(mpd.conn, pair); + list_push(&mpd_state->mpd_tags, pair->value, 1); + mpd_return_pair(mpd_state->conn, pair); } - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); } else { LOG_ERROR_AND_RECOVER("mpd_send_list_tag_types"); } - list_free(&mympd_tags); - if (mpd_tags.length == 0) { + list_free(&mpd_state->mympd_tags); + if (mpd_state->mpd_tags.length == 0) { LOG_INFO() printf("none\nTags are disabled\n"); - mpd.feat_tags = false; + mpd_state->feat_tags = false; } else { - mpd.feat_tags = true; + mpd_state->feat_tags = true; LOG_INFO() printf("\nmyMPD enabled tags: "); enum mpd_tag_type types[64]; unsigned n = 0; token = strtok_r(taglist, s, &rest); while (token != NULL) { - if (list_get_value(&mpd_tags, token) == 1) { - list_push(&mympd_tags, token, 1); + if (list_get_value(&mpd_state->mpd_tags, token) == 1) { + list_push(&mpd_state->mympd_tags, token, 1); types[n++] = mpd_tag_name_parse(token); LOG_INFO() printf("%s ", token); } @@ -943,24 +1135,24 @@ void mpd_client_mpd_features() { } LOG_INFO() printf("\n"); #if LIBMPDCLIENT_CHECK_VERSION(2,12,0) - if (mpd_connection_cmp_server_version(mpd.conn, 0, 21, 0) >= 0) { + if (mpd_connection_cmp_server_version(mpd_state->conn, 0, 21, 0) >= 0) { LOG_VERBOSE() printf("Enabling mpd tag types\n"); - if (mpd_command_list_begin(mpd.conn, false)) { - mpd_send_clear_tag_types(mpd.conn); - mpd_send_enable_tag_types(mpd.conn, types, n); - if (!mpd_command_list_end(mpd.conn)) + if (mpd_command_list_begin(mpd_state->conn, false)) { + mpd_send_clear_tag_types(mpd_state->conn); + mpd_send_enable_tag_types(mpd_state->conn, types, n); + if (!mpd_command_list_end(mpd_state->conn)) LOG_ERROR_AND_RECOVER("mpd_command_list_end"); } else LOG_ERROR_AND_RECOVER("mpd_command_list_begin"); - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); } #endif LOG_INFO() printf("myMPD enabled searchtags: "); token = strtok_r(searchtaglist, s, &rest); while (token != NULL) { - if (list_get_value(&mympd_tags, token) == 1) { - list_push(&mympd_searchtags, token, 1); + if (list_get_value(&mpd_state->mympd_tags, token) == 1) { + list_push(&mpd_state->mympd_searchtags, token, 1); LOG_INFO() printf("%s ", token); } token = strtok_r(NULL, s, &rest); @@ -968,8 +1160,8 @@ void mpd_client_mpd_features() { LOG_INFO() printf("\nmyMPD enabled browsetags: "); token = strtok_r(browsetaglist, s, &rest); while (token != NULL) { - if (list_get_value(&mympd_tags, token) == 1) { - list_push(&mympd_browsetags, token, 1); + if (list_get_value(&mpd_state->mympd_tags, token) == 1) { + list_push(&mpd_state->mympd_browsetags, token, 1); LOG_INFO() printf("%s ", token); } token = strtok_r(NULL, s, &rest); @@ -980,107 +1172,110 @@ void mpd_client_mpd_features() { free(searchtaglist); free(browsetaglist); - if (LIBMPDCLIENT_CHECK_VERSION(2, 17, 0) && mpd_connection_cmp_server_version(mpd.conn, 0, 21, 0) >= 0) { - mpd.feat_advsearch = true; + if (LIBMPDCLIENT_CHECK_VERSION(2, 17, 0) && mpd_connection_cmp_server_version(mpd_state->conn, 0, 21, 0) >= 0) { + mpd_state->feat_advsearch = true; LOG_INFO() printf("Enabling advanced search.\n"); } else LOG_INFO() printf("Disabling advanced search, depends on mpd >= 0.21.0 and libmpdclient >= 2.17.0.\n"); } -void mpd_client_idle(int timeout) { +static void mpd_client_idle(t_config *config, t_mpd_state *mpd_state, const int timeout) { struct pollfd fds[1]; int pollrc; + char buffer[MAX_SIZE]; size_t len = 0; - switch (mpd.conn_state) { + switch (mpd_state->conn_state) { case MPD_DISCONNECTED: /* Try to connect */ - LOG_INFO() printf("MPD Connecting to %s:%ld\n", config.mpdhost, config.mpdport); - mpd.conn = mpd_connection_new(config.mpdhost, config.mpdport, mpd.timeout); - if (mpd.conn == NULL) { + LOG_INFO() printf("MPD Connecting to %s:%ld\n", config->mpdhost, config->mpdport); + mpd_state->conn = mpd_connection_new(config->mpdhost, config->mpdport, mpd_state->timeout); + if (mpd_state->conn == NULL) { printf("MPD connection failed."); - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"disconnected\"}"); - mpd_client_notify(len); - mpd.conn_state = MPD_FAILURE; + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"disconnected\"}"); + mpd_client_notify(buffer, len); + mpd_state->conn_state = MPD_FAILURE; return; } - if (mpd_connection_get_error(mpd.conn) != MPD_ERROR_SUCCESS) { - printf("MPD connection: %s\n", mpd_connection_get_error_message(mpd.conn)); - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"%s\"}", mpd_connection_get_error_message(mpd.conn)); - mpd_client_notify(len); - mpd.conn_state = MPD_FAILURE; + if (mpd_connection_get_error(mpd_state->conn) != MPD_ERROR_SUCCESS) { + printf("MPD connection: %s\n", mpd_connection_get_error_message(mpd_state->conn)); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"%s\"}", mpd_connection_get_error_message(mpd_state->conn)); + mpd_client_notify(buffer, len); + mpd_state->conn_state = MPD_FAILURE; return; } - if (config.mpdpass && !mpd_run_password(mpd.conn, config.mpdpass)) { - printf("MPD connection: %s\n", mpd_connection_get_error_message(mpd.conn)); - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"%s\"}", mpd_connection_get_error_message(mpd.conn)); - mpd_client_notify(len); - mpd.conn_state = MPD_FAILURE; + if (config->mpdpass && !mpd_run_password(mpd_state->conn, config->mpdpass)) { + printf("MPD connection: %s\n", mpd_connection_get_error_message(mpd_state->conn)); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"%s\"}", mpd_connection_get_error_message(mpd_state->conn)); + mpd_client_notify(buffer, len); + mpd_state->conn_state = MPD_FAILURE; return; } LOG_INFO() printf("MPD connected.\n"); - mpd_connection_set_timeout(mpd.conn, mpd.timeout); - mpd.conn_state = MPD_CONNECTED; - mpd_client_mpd_features(); - mpd_client_smartpls_update_all(); - if (mympd_state.jukeboxMode > 0) - mpd_client_jukebox(); - mpd_send_idle(mpd.conn); + mpd_connection_set_timeout(mpd_state->conn, mpd_state->timeout); + mpd_state->conn_state = MPD_CONNECTED; + mpd_client_mpd_features(config, mpd_state); + mpd_client_smartpls_update_all(config, mpd_state); + if (mpd_state->jukeboxMode > 0) + mpd_client_jukebox(config, mpd_state); + mpd_send_idle(mpd_state->conn); break; case MPD_FAILURE: printf("MPD connection failed.\n"); - len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"disconnected\"}"); - mpd_client_notify(len); + len = snprintf(buffer, MAX_SIZE, "{\"type\": \"disconnected\"}"); + mpd_client_notify(buffer, len); case MPD_DISCONNECT: case MPD_RECONNECT: - if (mpd.conn != NULL) - mpd_connection_free(mpd.conn); - mpd.conn = NULL; - mpd.conn_state = MPD_DISCONNECTED; + if (mpd_state->conn != NULL) + mpd_connection_free(mpd_state->conn); + mpd_state->conn = NULL; + mpd_state->conn_state = MPD_DISCONNECTED; break; case MPD_CONNECTED: - fds[0].fd = mpd_connection_get_fd(mpd.conn); + fds[0].fd = mpd_connection_get_fd(mpd_state->conn); fds[0].events = POLLIN; pollrc = poll(fds, 1, timeout); unsigned mpd_client_queue_length = tiny_queue_length(mpd_client_queue); if (pollrc > 0 || mpd_client_queue_length > 0) { LOG_DEBUG() fprintf(stderr, "DEBUG: Leaving mpd idle mode.\n"); - mpd_send_noidle(mpd.conn); + mpd_send_noidle(mpd_state->conn); if (pollrc > 0) { //Handle idle events LOG_DEBUG() fprintf(stderr, "DEBUG: Checking for idle events.\n"); - enum mpd_idle idle_bitmask = mpd_recv_idle(mpd.conn, false); - mpd_client_parse_idle(idle_bitmask); + enum mpd_idle idle_bitmask = mpd_recv_idle(mpd_state->conn, false); + mpd_client_parse_idle(config, mpd_state, idle_bitmask); } else { - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); } if (mpd_client_queue_length > 0) { //Handle request LOG_DEBUG() fprintf(stderr, "DEBUG: Handle request.\n"); struct work_request_t *req = tiny_queue_shift(mpd_client_queue); - mpd_client_api(req); + mpd_client_api(config, mpd_state, req); } LOG_DEBUG() fprintf(stderr, "DEBUG: Entering mpd idle mode.\n"); - mpd_send_idle(mpd.conn); + mpd_send_idle(mpd_state->conn); } break; + default: + printf("ERROR: Invalid mpd connection state\n"); } } -int mpd_client_get_updatedb_state(char *buffer) { +static int mpd_client_get_updatedb_state(t_config *config, t_mpd_state *mpd_state, char *buffer) { struct mpd_status *status; int len, update_id; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - status = mpd_run_status(mpd.conn); + status = mpd_run_status(mpd_state->conn); if (!status) RETURN_ERROR_AND_RECOVER("mpd_run_status"); update_id = mpd_status_get_update_id(status); @@ -1096,7 +1291,7 @@ int mpd_client_get_updatedb_state(char *buffer) { } -bool mpd_client_get_sticker(const char *uri, t_sticker *sticker) { +static bool mpd_client_get_sticker(t_config *config, t_mpd_state *mpd_state, const char *uri, t_sticker *sticker) { struct mpd_pair *pair; char *crap; sticker->playCount = 0; @@ -1106,8 +1301,8 @@ bool mpd_client_get_sticker(const char *uri, t_sticker *sticker) { if (uri == NULL || strncasecmp("http:", uri, 5) == 0 || strncasecmp("https:", uri, 6) == 0) return false; - if (mpd_send_sticker_list(mpd.conn, "song", uri)) { - while ((pair = mpd_recv_sticker(mpd.conn)) != NULL) { + if (mpd_send_sticker_list(mpd_state->conn, "song", uri)) { + while ((pair = mpd_recv_sticker(mpd_state->conn)) != NULL) { if (strcmp(pair->name, "playCount") == 0) sticker->playCount = strtol(pair->value, &crap, 10); else if (strcmp(pair->name, "skipCount") == 0) @@ -1116,7 +1311,7 @@ bool mpd_client_get_sticker(const char *uri, t_sticker *sticker) { sticker->lastPlayed = strtol(pair->value, &crap, 10); else if (strcmp(pair->name, "like") == 0) sticker->like = strtol(pair->value, &crap, 10); - mpd_return_sticker(mpd.conn, pair); + mpd_return_sticker(mpd_state->conn, pair); } } else { @@ -1126,12 +1321,12 @@ bool mpd_client_get_sticker(const char *uri, t_sticker *sticker) { return true; } -bool mpd_client_count_song_id(int song_id, char *name, int value) { +static bool mpd_client_count_song_id(t_config *config, t_mpd_state *mpd_state, const int song_id, const char *name, const int value) { struct mpd_song *song; if (song_id > -1) { - song = mpd_run_get_queue_song_id(mpd.conn, song_id); + song = mpd_run_get_queue_song_id(mpd_state->conn, song_id); if (song) { - if (!mpd_client_count_song_uri(mpd_song_get_uri(song), name, value)) { + if (!mpd_client_count_song_uri(config, mpd_state, mpd_song_get_uri(song), name, value)) { mpd_song_free(song); return false; } @@ -1147,18 +1342,18 @@ bool mpd_client_count_song_id(int song_id, char *name, int value) { return true; } -bool mpd_client_count_song_uri(const char *uri, char *name, int value) { +static bool mpd_client_count_song_uri(t_config *config, t_mpd_state *mpd_state, const char *uri, const char *name, const int value) { if (uri == NULL || strncasecmp("http:", uri, 5) == 0 || strncasecmp("https:", uri, 6) == 0) return false; struct mpd_pair *pair; char *crap; int old_value = 0; char v[4]; - if (mpd_send_sticker_list(mpd.conn, "song", uri)) { - while ((pair = mpd_recv_sticker(mpd.conn)) != NULL) { + if (mpd_send_sticker_list(mpd_state->conn, "song", uri)) { + while ((pair = mpd_recv_sticker(mpd_state->conn)) != NULL) { if (strcmp(pair->name, name) == 0) old_value = strtol(pair->value, &crap, 10); - mpd_return_sticker(mpd.conn, pair); + mpd_return_sticker(mpd_state->conn, pair); } } else { LOG_ERROR_AND_RECOVER("mpd_send_sticker_list"); @@ -1171,14 +1366,14 @@ bool mpd_client_count_song_uri(const char *uri, char *name, int value) { old_value = 0; snprintf(v, 4, "%d", old_value); LOG_VERBOSE() printf("Setting sticker: \"%s\" -> %s: %s\n", uri, name, v); - if (!mpd_run_sticker_set(mpd.conn, "song", uri, name, v)) { + if (!mpd_run_sticker_set(mpd_state->conn, "song", uri, name, v)) { LOG_ERROR_AND_RECOVER("mpd_send_sticker_set"); return false; } return true; } -bool mpd_client_like_song_uri(const char *uri, int value) { +static bool mpd_client_like_song_uri(t_config *config, t_mpd_state *mpd_state, const char *uri, int value) { if (uri == NULL || strncasecmp("http:", uri, 5) == 0 || strncasecmp("https:", uri, 6) == 0) return false; char v[2]; @@ -1188,35 +1383,35 @@ bool mpd_client_like_song_uri(const char *uri, int value) { value = 0; snprintf(v, 2, "%d", value); LOG_VERBOSE() printf("Setting sticker: \"%s\" -> like: %s\n", uri, v); - if (!mpd_run_sticker_set(mpd.conn, "song", uri, "like", v)) { + if (!mpd_run_sticker_set(mpd_state->conn, "song", uri, "like", v)) { LOG_ERROR_AND_RECOVER("mpd_send_sticker_set"); return false; } return true; } -bool mpd_client_last_played_list(int song_id) { +static bool mpd_client_last_played_list(t_config *config, t_mpd_state *mpd_state, const int song_id) { struct mpd_song *song; char tmp_file[400]; char cfg_file[400]; - snprintf(cfg_file, 400, "%s/state/last_played", config.varlibdir); - snprintf(tmp_file, 400, "%s/tmp/last_played", config.varlibdir); + snprintf(cfg_file, 400, "%s/state/last_played", config->varlibdir); + snprintf(tmp_file, 400, "%s/tmp/last_played", config->varlibdir); if (song_id > -1) { - song = mpd_run_get_queue_song_id(mpd.conn, song_id); + song = mpd_run_get_queue_song_id(mpd_state->conn, song_id); if (song) { - list_insert(&last_played, mpd_song_get_uri(song), time(NULL)); - mpd.last_last_played_id = song_id; + list_insert(&mpd_state->last_played, mpd_song_get_uri(song), time(NULL)); + mpd_state->last_last_played_id = song_id; mpd_song_free(song); - if (last_played.length > config.last_played_count) { - list_shift(&last_played, last_played.length -1); + if (mpd_state->last_played.length > config->last_played_count) { + list_shift(&mpd_state->last_played, mpd_state->last_played.length -1); } FILE *fp = fopen(tmp_file, "w"); if (fp == NULL) { printf("Error opening %s\n", tmp_file); return false; } - struct node *current = last_played.list; + struct node *current = mpd_state->last_played.list; while (current != NULL) { fprintf(fp, "%ld::%s\n", current->value, current->data); current = current->next; @@ -1234,13 +1429,13 @@ bool mpd_client_last_played_list(int song_id) { return true; } -bool mpd_client_last_played_song_id(int song_id) { +static bool mpd_client_last_played_song_id(t_config *config, t_mpd_state *mpd_state, const int song_id) { struct mpd_song *song; if (song_id > -1) { - song = mpd_run_get_queue_song_id(mpd.conn, song_id); + song = mpd_run_get_queue_song_id(mpd_state->conn, song_id); if (song) { - if (!mpd_client_last_played_song_uri(mpd_song_get_uri(song))) { + if (mpd_client_last_played_song_uri(config, mpd_state, mpd_song_get_uri(song)) == false) { mpd_song_free(song); return false; } @@ -1260,13 +1455,13 @@ bool mpd_client_last_played_song_id(int song_id) { return true; } -bool mpd_client_last_played_song_uri(const char *uri) { +static bool mpd_client_last_played_song_uri(t_config *config, t_mpd_state *mpd_state, const char *uri) { if (uri == NULL || strncasecmp("http:", uri, 5) == 0 || strncasecmp("https:", uri, 6) == 0) return false; char v[20]; snprintf(v, 20, "%lu", time(NULL)); LOG_VERBOSE() printf("Setting sticker: \"%s\" -> lastPlayed: %s\n", uri, v); - if (!mpd_run_sticker_set(mpd.conn, "song", uri, "lastPlayed", v)) { + if (!mpd_run_sticker_set(mpd_state->conn, "song", uri, "lastPlayed", v)) { LOG_ERROR_AND_RECOVER("mpd_send_sticker_set"); return false; } @@ -1274,7 +1469,7 @@ bool mpd_client_last_played_song_uri(const char *uri) { } -char *mpd_client_get_tag(struct mpd_song const *song, enum mpd_tag_type tag) { +static char *mpd_client_get_tag(struct mpd_song const *song, const enum mpd_tag_type tag) { char *str; str = (char *)mpd_song_get_tag(song, tag, 0); if (str == NULL) { @@ -1288,9 +1483,8 @@ char *mpd_client_get_tag(struct mpd_song const *song, enum mpd_tag_type tag) { return str; } -bool mpd_client_jukebox() { - struct mpd_status *status; - status = mpd_run_status(mpd.conn); +static bool mpd_client_jukebox(t_config *config, t_mpd_state *mpd_state) { + struct mpd_status *status = mpd_run_status(mpd_state->conn); int queue_length, addSongs, i; struct mpd_entity *entity; const struct mpd_song *song; @@ -1304,18 +1498,18 @@ bool mpd_client_jukebox() { } queue_length = mpd_status_get_queue_length(status); mpd_status_free(status); - if (queue_length > mympd_state.jukeboxQueueLength) + if (queue_length > mpd_state->jukeboxQueueLength) return true; - if (mympd_state.jukeboxMode == 1) - addSongs = mympd_state.jukeboxQueueLength - queue_length; + if (mpd_state->jukeboxMode == 1) + addSongs = mpd_state->jukeboxQueueLength - queue_length; else addSongs = 1; if (addSongs < 1) return true; - if (mpd.feat_playlists == false && strcmp(mympd_state.jukeboxPlaylist, "Database") != 0) { + if (mpd_state->feat_playlists == false && strcmp(mpd_state->jukeboxPlaylist, "Database") != 0) { LOG_INFO() printf("Jukebox: Playlists are disabled\n"); return true; } @@ -1325,23 +1519,23 @@ bool mpd_client_jukebox() { struct list add_list; list_init(&add_list); - if (mympd_state.jukeboxMode == 1) { + if (mpd_state->jukeboxMode == 1) { //add songs - if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) { - if (!mpd_send_list_all(mpd.conn, "/")) { + if (strcmp(mpd_state->jukeboxPlaylist, "Database") == 0) { + if (!mpd_send_list_all(mpd_state->conn, "/")) { LOG_ERROR_AND_RECOVER("mpd_send_list_all"); list_free(&add_list); return false; } } else { - if (!mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist)) { + if (!mpd_send_list_playlist(mpd_state->conn, mpd_state->jukeboxPlaylist)) { LOG_ERROR_AND_RECOVER("mpd_send_list_playlist"); list_free(&add_list); return false; } } - while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { + while ((entity = mpd_recv_entity(mpd_state->conn)) != NULL) { if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { if (randrange(lineno) < addSongs) { if (nkeep < addSongs) { @@ -1368,19 +1562,19 @@ bool mpd_client_jukebox() { mpd_entity_free(entity); } } - else if (mympd_state.jukeboxMode == 2) { + else if (mpd_state->jukeboxMode == 2) { //add album - if (!mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM)) { + if (!mpd_search_db_tags(mpd_state->conn, MPD_TAG_ALBUM)) { LOG_ERROR_AND_RECOVER("mpd_search_db_tags"); list_free(&add_list); return false; } - if (!mpd_search_commit(mpd.conn)) { + if (!mpd_search_commit(mpd_state->conn)) { LOG_ERROR_AND_RECOVER("mpd_search_commit"); list_free(&add_list); return false; } - while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM )) != NULL) { + while ((pair = mpd_recv_pair_tag(mpd_state->conn, MPD_TAG_ALBUM )) != NULL) { if (randrange(lineno) < addSongs) { if (nkeep < addSongs) { list_push(&add_list, strdup(pair->value), lineno); @@ -1399,7 +1593,7 @@ bool mpd_client_jukebox() { } } lineno++; - mpd_return_pair(mpd.conn, pair); + mpd_return_pair(mpd_state->conn, pair); } } @@ -1411,51 +1605,49 @@ bool mpd_client_jukebox() { nkeep = 0; struct node *current = add_list.list; while (current != NULL) { - if (mympd_state.jukeboxMode == 1) { + if (mpd_state->jukeboxMode == 1) { LOG_INFO() printf("Jukebox adding song: %s\n", current->data); - if (!mpd_run_add(mpd.conn, current->data)) + if (!mpd_run_add(mpd_state->conn, current->data)) LOG_ERROR_AND_RECOVER("mpd_run_add"); else nkeep++; } else { LOG_INFO() printf("Jukebox adding album: %s\n", current->data); - if (!mpd_send_command(mpd.conn, "searchadd", "Album", current->data, NULL)) { + if (!mpd_send_command(mpd_state->conn, "searchadd", "Album", current->data, NULL)) { LOG_ERROR_AND_RECOVER("mpd_send_command"); return false; } else nkeep++; - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); } current = current->next; } list_free(&add_list); if (nkeep > 0) - mpd_run_play(mpd.conn); + mpd_run_play(mpd_state->conn); else { printf("Error adding song(s), trying again...\n"); - mpd_client_jukebox(); + mpd_client_jukebox(config, mpd_state); } return true; } -int mpd_client_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length) { - struct mpd_status *status; - const struct mpd_audio_format *audioformat; - int len; +static int mpd_client_put_state(t_config *config, t_mpd_state *mpd_state, char *buffer) { + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - status = mpd_run_status(mpd.conn); + struct mpd_status *status = mpd_run_status(mpd_state->conn); if (!status) { - printf("MPD mpd_run_status: %s\n", mpd_connection_get_error_message(mpd.conn)); - mpd.conn_state = MPD_FAILURE; + printf("MPD mpd_run_status: %s\n", mpd_connection_get_error_message(mpd_state->conn)); + mpd_state->conn_state = MPD_FAILURE; return 0; } - audioformat = mpd_status_get_audio_format(status); - int song_id = mpd_status_get_song_id(status); - if (*current_song_id != song_id) - *last_song_id = *current_song_id; + const struct mpd_audio_format *audioformat = mpd_status_get_audio_format(status); + const int song_id = mpd_status_get_song_id(status); + if (mpd_state->song_id != song_id) + mpd_state->last_song_id = mpd_state->song_id; len = json_printf(&out, "{type: update_state, data: {state: %d, volume: %d, songPos: %d, elapsedTime: %d, " "totalTime: %d, currentSongId: %d, kbitrate: %d, audioFormat: { sampleRate: %d, bits: %d, channels: %d}, " @@ -1473,30 +1665,29 @@ int mpd_client_put_state(char *buffer, int *current_song_id, int *next_song_id, mpd_status_get_queue_length(status), mpd_status_get_next_song_pos(status), mpd_status_get_next_song_id(status), - *last_song_id ? *last_song_id : -1, + mpd_state->last_song_id ? mpd_state->last_song_id : -1, mpd_status_get_queue_version(status) ); len += json_printf(&out, "}}"); - *current_song_id = song_id; - *next_song_id = mpd_status_get_next_song_id(status); - *queue_version = mpd_status_get_queue_version(status); - *queue_length = mpd_status_get_queue_length(status); + mpd_state->song_id = song_id; + mpd_state->next_song_id = mpd_status_get_next_song_id(status); + mpd_state->queue_version = mpd_status_get_queue_version(status); + mpd_state->queue_length = mpd_status_get_queue_length(status); mpd_status_free(status); CHECK_RETURN_LEN(); } -int mpd_client_put_volume(char *buffer) { - struct mpd_status *status; - int len; +static int mpd_client_put_volume(t_config *config, t_mpd_state *mpd_state, char *buffer) { + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - status = mpd_run_status(mpd.conn); + struct mpd_status *status = mpd_run_status(mpd_state->conn); if (!status) { - printf("MPD mpd_run_status: %s\n", mpd_connection_get_error_message(mpd.conn)); - mpd.conn_state = MPD_FAILURE; + printf("MPD mpd_run_status: %s\n", mpd_connection_get_error_message(mpd_state->conn)); + mpd_state->conn_state = MPD_FAILURE; return 0; } len = json_printf(&out, "{type: update_volume, data: {volume: %d}}", @@ -1507,33 +1698,15 @@ int mpd_client_put_volume(char *buffer) { CHECK_RETURN_LEN(); } -int mpd_client_put_welcome(char *buffer) { - int len; - struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - const unsigned *version = mpd_connection_get_server_version(mpd.conn); - char mpd_version[20]; - char libmpdclient_version[20]; - - snprintf(mpd_version, 20, "%u.%u.%u", version[0], version[1], version[2]); - snprintf(libmpdclient_version, 20, "%i.%i.%i", LIBMPDCLIENT_MAJOR_VERSION, LIBMPDCLIENT_MINOR_VERSION, LIBMPDCLIENT_PATCH_VERSION); - - len = json_printf(&out, "{type: welcome, data: {mympdVersion: %Q, mpdVersion: %Q, libmpdclientVersion: %Q}}", - MYMPD_VERSION, - mpd_version, - libmpdclient_version - ); - - CHECK_RETURN_LEN(); -} - -bool mpd_client_state_get(char *name, char *value) { +static bool mpd_client_state_get(t_config *config, t_mpd_state *mpd_state, const char *name, char *value) { char cfg_file[400]; char *line; size_t n = 0; ssize_t read; - sanitize_string(name); - snprintf(cfg_file, 400, "%s/state/%s", config.varlibdir, name); + if (!validate_string(name)) + return false; + snprintf(cfg_file, 400, "%s/state/%s", config->varlibdir, name); FILE *fp = fopen(cfg_file, "r"); if (fp == NULL) { printf("Error opening %s\n", cfg_file); @@ -1549,13 +1722,14 @@ bool mpd_client_state_get(char *name, char *value) { return false; } -bool mpd_client_state_set(const char *name, const char *value) { +static bool mpd_client_state_set(t_config *config, t_mpd_state *mpd_state, const char *name, const char *value) { char tmp_file[400]; char cfg_file[400]; - sanitize_string(name); - snprintf(cfg_file, 400, "%s/state/%s", config.varlibdir, name); - snprintf(tmp_file, 400, "%s/tmp/%s", config.varlibdir, name); + if (!validate_string(name)) + return false; + snprintf(cfg_file, 400, "%s/state/%s", config->varlibdir, name); + snprintf(tmp_file, 400, "%s/tmp/%s", config->varlibdir, name); FILE *fp = fopen(tmp_file, "w"); if (fp == NULL) { @@ -1571,27 +1745,25 @@ bool mpd_client_state_set(const char *name, const char *value) { return true; } -int mpd_client_put_settings(char *buffer, void *arg_config) { - struct mpd_status *status; - char *replaygain = strdup(""); - int len; +static int mpd_client_put_settings(t_config *config, t_mpd_state *mpd_state, char *buffer) { + char *replaygain = ""; + size_t len; int nr = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - t_config *config = (t_config *) arg_config; - status = mpd_run_status(mpd.conn); + struct mpd_status *status = mpd_run_status(mpd_state->conn); if (!status) { - printf("MPD mpd_run_status: %s\n", mpd_connection_get_error_message(mpd.conn)); - mpd.conn_state = MPD_FAILURE; + printf("MPD mpd_run_status: %s\n", mpd_connection_get_error_message(mpd_state->conn)); + mpd_state->conn_state = MPD_FAILURE; return 0; } - if (!mpd_send_command(mpd.conn, "replay_gain_status", NULL)) + if (!mpd_send_command(mpd_state->conn, "replay_gain_status", NULL)) RETURN_ERROR_AND_RECOVER("replay_gain_status"); struct mpd_pair *pair; - while ((pair = mpd_recv_pair(mpd.conn)) != NULL) { + while ((pair = mpd_recv_pair(mpd_state->conn)) != NULL) { replaygain = strdup(pair->value); - mpd_return_pair(mpd.conn, pair); + mpd_return_pair(mpd_state->conn, pair); } len = json_printf(&out, "{type: settings, data: {" @@ -1611,10 +1783,10 @@ int mpd_client_put_settings(char *buffer, void *arg_config) { config->mpdport, config->mpdpass ? "true" : "false", config->syscmds, - mpd.feat_playlists, - mpd.feat_tags, - mpd.feat_library, - mpd.feat_advsearch, + mpd_state->feat_playlists, + mpd_state->feat_tags, + mpd_state->feat_library, + mpd_state->feat_advsearch, config->localplayer, config->streamport, config->streamurl, @@ -1625,18 +1797,18 @@ int mpd_client_put_settings(char *buffer, void *arg_config) { config->smartpls, config->max_elements_per_page, replaygain, - mympd_state.notificationWeb, - mympd_state.notificationPage, - mympd_state.jukeboxMode, - mympd_state.jukeboxPlaylist, - mympd_state.jukeboxQueueLength, + mpd_state->notificationWeb, + mpd_state->notificationPage, + mpd_state->jukeboxMode, + mpd_state->jukeboxPlaylist, + mpd_state->jukeboxQueueLength, config->coverimagesize ); mpd_status_free(status); free(replaygain); nr = 0; - struct node *current = mympd_tags.list; + struct node *current = mpd_state->mympd_tags.list; while (current != NULL) { if (nr++) len += json_printf(&out, ","); @@ -1645,7 +1817,7 @@ int mpd_client_put_settings(char *buffer, void *arg_config) { } len += json_printf(&out, "], searchtags: ["); nr = 0; - current = mympd_searchtags.list; + current = mpd_state->mympd_searchtags.list; while (current != NULL) { if (nr++) len += json_printf(&out, ","); @@ -1654,7 +1826,7 @@ int mpd_client_put_settings(char *buffer, void *arg_config) { } len += json_printf(&out, "], browsetags: ["); nr = 0; - current = mympd_browsetags.list; + current = mpd_state->mympd_browsetags.list; while (current != NULL) { if (nr++) len += json_printf(&out, ","); @@ -1666,8 +1838,7 @@ int mpd_client_put_settings(char *buffer, void *arg_config) { if (config->syscmds == true) { len += json_printf(&out, ", syscmds: ["); nr = 0; - struct list *syscmd_list = (struct list *) config->syscmd_list; - current = syscmd_list->list; + current = config->syscmd_list.list; while (current != NULL) { if (nr++) len += json_printf(&out, ","); @@ -1678,41 +1849,40 @@ int mpd_client_put_settings(char *buffer, void *arg_config) { } len += json_printf(&out, ", colsQueueCurrent: %s, colsSearch: %s, colsBrowseDatabase: %s, colsBrowsePlaylistsDetail: %s, " "colsBrowseFilesystem: %s, colsPlayback: %s, colsQueueLastPlayed: %s}}", - mympd_state.colsQueueCurrent, - mympd_state.colsSearch, - mympd_state.colsBrowseDatabase, - mympd_state.colsBrowsePlaylistsDetail, - mympd_state.colsBrowseFilesystem, - mympd_state.colsPlayback, - mympd_state.colsQueueLastPlayed + mpd_state->colsQueueCurrent, + mpd_state->colsSearch, + mpd_state->colsBrowseDatabase, + mpd_state->colsBrowsePlaylistsDetail, + mpd_state->colsBrowseFilesystem, + mpd_state->colsPlayback, + mpd_state->colsQueueLastPlayed ); CHECK_RETURN_LEN(); } - -int mpd_client_put_outputs(char *buffer) { +static int mpd_client_put_outputs(t_config *config, t_mpd_state *mpd_state, char *buffer) { struct mpd_output *output; - int len; + size_t len; int nr; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - if (!mpd_send_outputs(mpd.conn)) + if (!mpd_send_outputs(mpd_state->conn)) RETURN_ERROR_AND_RECOVER("outputs"); len = json_printf(&out, "{type: outputs, data: {outputs: ["); nr = 0; - while ((output = mpd_recv_output(mpd.conn)) != NULL) { + while ((output = mpd_recv_output(mpd_state->conn)) != NULL) { if (nr++) len += json_printf(&out, ","); - len += json_printf(&out,"{id: %d, name: %Q, state: %d}", + len += json_printf(&out, "{id: %d, name: %Q, state: %d}", mpd_output_get_id(output), mpd_output_get_name(output), mpd_output_get_enabled(output) ); mpd_output_free(output); } - if (!mpd_response_finish(mpd.conn)) + if (!mpd_response_finish(mpd_state->conn)) LOG_ERROR_AND_RECOVER("outputs"); len += json_printf(&out,"]}}"); @@ -1720,22 +1890,12 @@ int mpd_client_put_outputs(char *buffer) { CHECK_RETURN_LEN(); } -int replacechar(char *str, char orig, char rep) { - char *ix = str; - int n = 0; - while ((ix = strchr(ix, orig)) != NULL) { - *ix++ = rep; - n++; - } - return n; -} - -int mpd_client_get_cover(const char *uri, char *cover, int cover_len) { +static int mpd_client_get_cover(t_config *config, t_mpd_state *mpd_state, const char *uri, char *cover, const int cover_len) { char *orgpath = strdup(uri); char *path = orgpath; - int len; + size_t len = 0; - if (!config.coverimage) { + if (!config->coverimage) { len = snprintf(cover, cover_len, "/assets/coverimage-notavailable.png"); } else if (strncasecmp("http:", path, 5) == 0 || strncasecmp("https:", path, 6) == 0) { @@ -1755,13 +1915,13 @@ int mpd_client_get_cover(const char *uri, char *cover, int cover_len) { len = snprintf(cover, cover_len, "/assets/coverimage-httpstream.png"); } else { - if (mpd.feat_library) { + if (mpd_state->feat_library) { dirname(path); - snprintf(cover, cover_len, "%s/library/%s/%s", DOC_ROOT, path, config.coverimagename); + snprintf(cover, cover_len, "%s/library/%s/%s", DOC_ROOT, path, config->coverimagename); if (access(cover, F_OK ) == -1 ) len = snprintf(cover, cover_len, "/assets/coverimage-notavailable.png"); else - len = snprintf(cover, cover_len, "/library/%s/%s", path, config.coverimagename); + len = snprintf(cover, cover_len, "/library/%s/%s", path, config->coverimagename); } else len = snprintf(cover, cover_len, "/assets/coverimage-notavailable.png"); } @@ -1769,35 +1929,34 @@ int mpd_client_get_cover(const char *uri, char *cover, int cover_len) { return len; } -int mpd_client_put_current_song(char *buffer) { - struct mpd_song *song; - int len; +static int mpd_client_put_current_song(t_config *config, t_mpd_state *mpd_state, char *buffer) { + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); char cover[500] = ""; - song = mpd_run_current_song(mpd.conn); + struct mpd_song *song = mpd_run_current_song(mpd_state->conn); if (song == NULL) { len = json_printf(&out, "{type: result, data: ok}"); return len; } - mpd_client_get_cover(mpd_song_get_uri(song), cover, 500); + mpd_client_get_cover(config, mpd_state, mpd_song_get_uri(song), cover, 500); len = json_printf(&out, "{type: song_change, data: {pos: %d, currentSongId: %d, cover: %Q, ", mpd_song_get_pos(song), - mpd.song_id, + mpd_state->song_id, cover ); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); - if (config.stickers) { + if (config->stickers) { t_sticker *sticker = (t_sticker *) malloc(sizeof(t_sticker)); - mpd_client_get_sticker(mpd_song_get_uri(song), sticker); + mpd_client_get_sticker(config, mpd_state, mpd_song_get_uri(song), sticker); len += json_printf(&out, ", playCount: %d, skipCount: %d, like: %d, lastPlayed: %d", sticker->playCount, sticker->skipCount, @@ -1812,31 +1971,31 @@ int mpd_client_put_current_song(char *buffer) { CHECK_RETURN_LEN(); } -int mpd_client_put_songdetails(char *buffer, char *uri) { +static int mpd_client_put_songdetails(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *uri) { struct mpd_entity *entity; const struct mpd_song *song; - int len; + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); char cover[500] = ""; len = json_printf(&out, "{type: song_details, data: {"); - if (!mpd_send_list_all_meta(mpd.conn, uri)) + if (!mpd_send_list_all_meta(mpd_state->conn, uri)) RETURN_ERROR_AND_RECOVER("mpd_send_list_all_meta"); - if ((entity = mpd_recv_entity(mpd.conn)) != NULL) { + if ((entity = mpd_recv_entity(mpd_state->conn)) != NULL) { song = mpd_entity_get_song(entity); - mpd_client_get_cover(uri, cover, 500); + mpd_client_get_cover(config, mpd_state, uri, cover, 500); len += json_printf(&out, "cover: %Q, ", cover); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); mpd_entity_free(entity); } - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); - if (config.stickers) { + if (config->stickers) { t_sticker *sticker = (t_sticker *) malloc(sizeof(t_sticker)); - mpd_client_get_sticker(uri, sticker); + mpd_client_get_sticker(config, mpd_state, uri, sticker); len += json_printf(&out, ", playCount: %d, skipCount: %d, like: %d, lastPlayed: %d", sticker->playCount, sticker->skipCount, @@ -1850,33 +2009,33 @@ int mpd_client_put_songdetails(char *buffer, char *uri) { CHECK_RETURN_LEN(); } -int mpd_client_put_last_played_songs(char *buffer, unsigned int offset) { +static int mpd_client_put_last_played_songs(t_config *config, t_mpd_state *mpd_state, char *buffer, unsigned int offset) { const struct mpd_song *song; struct mpd_entity *entity; - int len; - unsigned int entity_count = 0; - unsigned int entities_returned = 0; + size_t len = 0; + unsigned entity_count = 0; + unsigned entities_returned = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); len = json_printf(&out, "{type: last_played_songs, data: ["); - struct node *current = last_played.list; + struct node *current = mpd_state->last_played.list; while (current != NULL) { entity_count++; - if (entity_count > offset && entity_count <= offset + config.max_elements_per_page) { + if (entity_count > offset && entity_count <= offset + config->max_elements_per_page) { if (entities_returned++) len += json_printf(&out, ","); len += json_printf(&out, "{Pos: %d, LastPlayed: %ld, ", entity_count, current->value); - if (!mpd_send_list_all_meta(mpd.conn, current->data)) + if (!mpd_send_list_all_meta(mpd_state->conn, current->data)) RETURN_ERROR_AND_RECOVER("mpd_send_list_all_meta"); - if ((entity = mpd_recv_entity(mpd.conn)) != NULL) { + if ((entity = mpd_recv_entity(mpd_state->conn)) != NULL) { song = mpd_entity_get_song(entity); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); mpd_entity_free(entity); - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); } len += json_printf(&out, "}"); } @@ -1892,24 +2051,24 @@ int mpd_client_put_last_played_songs(char *buffer, unsigned int offset) { CHECK_RETURN_LEN(); } -int mpd_client_put_queue(char *buffer, unsigned int offset, unsigned *queue_version, unsigned *queue_length) { +static int mpd_client_put_queue(t_config *config, t_mpd_state *mpd_state, char *buffer, unsigned int offset) { struct mpd_entity *entity; - unsigned long totalTime = 0; - unsigned long entity_count = 0; - unsigned long entities_returned = 0; - int len; + int totalTime = 0; + unsigned entity_count = 0; + unsigned entities_returned = 0; + size_t len; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - struct mpd_status *status = mpd_run_status(mpd.conn); + struct mpd_status *status = mpd_run_status(mpd_state->conn); if (!status) RETURN_ERROR_AND_RECOVER("mpd_run_status"); - if (!mpd_send_list_queue_range_meta(mpd.conn, offset, offset + config.max_elements_per_page)) + if (!mpd_send_list_queue_range_meta(mpd_state->conn, offset, offset + config->max_elements_per_page)) RETURN_ERROR_AND_RECOVER("mpd_send_list_queue_meta"); len = json_printf(&out, "{type: queue, data: ["); - while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { + while ((entity = mpd_recv_entity(mpd_state->conn)) != NULL) { const struct mpd_song *song; unsigned int drtn; if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) { @@ -1923,7 +2082,7 @@ int mpd_client_put_queue(char *buffer, unsigned int offset, unsigned *queue_vers mpd_song_get_id(song), mpd_song_get_pos(song) ); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); @@ -1940,34 +2099,34 @@ int mpd_client_put_queue(char *buffer, unsigned int offset, unsigned *queue_vers mpd_status_get_queue_version(status) ); - *queue_version = mpd_status_get_queue_version(status); - *queue_length = mpd_status_get_queue_length(status); + mpd_state->queue_version = mpd_status_get_queue_version(status); + mpd_state->queue_length = mpd_status_get_queue_length(status); mpd_status_free(status); CHECK_RETURN_LEN(); } -int mpd_client_put_browse(char *buffer, char *path, unsigned int offset, char *filter) { +static int mpd_client_put_browse(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *path, const unsigned int offset, const char *filter) { struct mpd_entity *entity; const struct mpd_playlist *pl; - unsigned int entity_count = 0; - unsigned int entities_returned = 0; + unsigned entity_count = 0; + unsigned entities_returned = 0; const char *entityName; char smartpls_file[400]; bool smartpls; - int len; + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - if (!mpd_send_list_meta(mpd.conn, path)) + if (!mpd_send_list_meta(mpd_state->conn, path)) RETURN_ERROR_AND_RECOVER("mpd_send_list_meta"); len = json_printf(&out, "{type: browse, data: ["); - while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { + while ((entity = mpd_recv_entity(mpd_state->conn)) != NULL) { const struct mpd_song *song; const struct mpd_directory *dir; entity_count++; - if (entity_count > offset && entity_count <= offset + config.max_elements_per_page) { + if (entity_count > offset && entity_count <= offset + config->max_elements_per_page) { switch (mpd_entity_get_type(entity)) { case MPD_ENTITY_TYPE_UNKNOWN: entity_count--; @@ -1981,7 +2140,7 @@ int mpd_client_put_browse(char *buffer, char *path, unsigned int offset, char *f if (entities_returned++) len += json_printf(&out, ","); len += json_printf(&out, "{Type: song, "); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); @@ -2026,16 +2185,23 @@ int mpd_client_put_browse(char *buffer, char *path, unsigned int offset, char *f plName = strdup(entityName); } if (strncmp(filter, "-", 1) == 0 || strncasecmp(filter, plName, 1) == 0 || - (strncmp(filter, "0", 1) == 0 && isalpha(*plName) == 0 ) - ) { - if (entities_returned++) + (strncmp(filter, "0", 1) == 0 && isalpha(*plName) == 0 )) + { + if (entities_returned++) { len += json_printf(&out, ","); - sanitize_string(plName); - snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, plName); - if (access(smartpls_file, F_OK ) != -1) - smartpls = true; - else - smartpls = false; + } + if (validate_string(plName) == true) { + snprintf(smartpls_file, 400, "%s/smartpls/%s", config->varlibdir, plName); + if (access(smartpls_file, F_OK ) != -1) { + smartpls = true; + } + else { + smartpls = false; + } + } + else { + smartpls = false; + } len += json_printf(&out, "{Type: %Q, uri: %Q, name: %Q}", (smartpls == true ? "smartpls" : "plist"), entityName, @@ -2050,9 +2216,9 @@ int mpd_client_put_browse(char *buffer, char *path, unsigned int offset, char *f mpd_entity_free(entity); } - if (mpd_connection_get_error(mpd.conn) != MPD_ERROR_SUCCESS || !mpd_response_finish(mpd.conn)) { - printf("MPD mpd_send_list_meta: %s\n", mpd_connection_get_error_message(mpd.conn)); - mpd.conn_state = MPD_FAILURE; + if (mpd_connection_get_error(mpd_state->conn) != MPD_ERROR_SUCCESS || !mpd_response_finish(mpd_state->conn)) { + printf("MPD mpd_send_list_meta: %s\n", mpd_connection_get_error_message(mpd_state->conn)); + mpd_state->conn_state = MPD_FAILURE; return 0; } @@ -2066,28 +2232,28 @@ int mpd_client_put_browse(char *buffer, char *path, unsigned int offset, char *f CHECK_RETURN_LEN(); } -int mpd_client_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, char *mpdsearchtagtype, char *searchstr, char *filter) { +static int mpd_client_put_db_tag(t_config *config, t_mpd_state *mpd_state, char *buffer, const unsigned int offset, const char *mpdtagtype, const char *mpdsearchtagtype, const char *searchstr, const char *filter) { struct mpd_pair *pair; - unsigned long entity_count = 0; - unsigned long entities_returned = 0; - int len; + unsigned entity_count = 0; + unsigned entities_returned = 0; + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - if (mpd_search_db_tags(mpd.conn, mpd_tag_name_parse(mpdtagtype)) == false) + if (mpd_search_db_tags(mpd_state->conn, mpd_tag_name_parse(mpdtagtype)) == false) RETURN_ERROR_AND_RECOVER("mpd_search_db_tags"); if (mpd_tag_name_parse(mpdsearchtagtype) != MPD_TAG_UNKNOWN) { - if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(mpdsearchtagtype), searchstr) == false) + if (mpd_search_add_tag_constraint(mpd_state->conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(mpdsearchtagtype), searchstr) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_tag_constraint"); } - if (mpd_search_commit(mpd.conn) == false) + if (mpd_search_commit(mpd_state->conn) == false) RETURN_ERROR_AND_RECOVER("mpd_search_commit"); len = json_printf(&out, "{type: listDBtags, data: ["); - while ((pair = mpd_recv_pair_tag(mpd.conn, mpd_tag_name_parse(mpdtagtype))) != NULL) { + while ((pair = mpd_recv_pair_tag(mpd_state->conn, mpd_tag_name_parse(mpdtagtype))) != NULL) { entity_count++; - if (entity_count > offset && entity_count <= offset + config.max_elements_per_page) { + if (entity_count > offset && entity_count <= offset + config->max_elements_per_page) { if (strcmp(pair->value, "") == 0) { entity_count--; } @@ -2104,7 +2270,7 @@ int mpd_client_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, c entity_count--; } } - mpd_return_pair(mpd.conn, pair); + mpd_return_pair(mpd_state->conn, pair); } len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, " @@ -2121,36 +2287,36 @@ int mpd_client_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, c CHECK_RETURN_LEN(); } -int mpd_client_put_songs_in_album(char *buffer, char *album, char *search, char *tag) { +static int mpd_client_put_songs_in_album(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *album, const char *search, const char *tag) { struct mpd_song *song; unsigned long entity_count = 0; unsigned long entities_returned = 0; - int len; + size_t len = 0; char cover[500] = ""; char *albumartist = NULL; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - if (mpd_search_db_songs(mpd.conn, true) == false) + if (mpd_search_db_songs(mpd_state->conn, true) == false) RETURN_ERROR_AND_RECOVER("mpd_search_db_songs"); - if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(tag), search) == false) + if (mpd_search_add_tag_constraint(mpd_state->conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(tag), search) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_tag_constraint"); - if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM, album) == false) + if (mpd_search_add_tag_constraint(mpd_state->conn, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM, album) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_tag_constraint"); - if (mpd_search_commit(mpd.conn) == false) + if (mpd_search_commit(mpd_state->conn) == false) RETURN_ERROR_AND_RECOVER("mpd_search_commit"); else { len = json_printf(&out, "{type: listTitles, data: ["); - while ((song = mpd_recv_song(mpd.conn)) != NULL) { + while ((song = mpd_recv_song(mpd_state->conn)) != NULL) { entity_count++; - if (entity_count <= config.max_elements_per_page) { + if (entity_count <= config->max_elements_per_page) { if (entities_returned++) len += json_printf(&out, ", "); else { - mpd_client_get_cover(mpd_song_get_uri(song), cover, 500); + mpd_client_get_cover(config, mpd_state, mpd_song_get_uri(song), cover, 500); albumartist = strdup(mpd_client_get_tag(song, MPD_TAG_ALBUM_ARTIST)); } len += json_printf(&out, "{Type: song, "); @@ -2176,36 +2342,42 @@ int mpd_client_put_songs_in_album(char *buffer, char *album, char *search, char CHECK_RETURN_LEN(); } -int mpd_client_put_playlists(char *buffer, unsigned int offset, char *filter) { +static int mpd_client_put_playlists(t_config *config, t_mpd_state *mpd_state, char *buffer, const unsigned int offset, const char *filter) { struct mpd_playlist *pl; - unsigned int entity_count = 0; - unsigned int entities_returned = 0; + unsigned entity_count = 0; + unsigned entities_returned = 0; const char *plpath; - int len; + size_t len = 0; bool smartpls; char smartpls_file[400]; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - if (!mpd_send_list_playlists(mpd.conn)) + if (mpd_send_list_playlists(mpd_state->conn) == false) RETURN_ERROR_AND_RECOVER("mpd_send_lists_playlists"); len = json_printf(&out, "{type: playlists, data: ["); - while ((pl = mpd_recv_playlist(mpd.conn)) != NULL) { + while ((pl = mpd_recv_playlist(mpd_state->conn)) != NULL) { entity_count++; - if (entity_count > offset && entity_count <= offset + config.max_elements_per_page) { + if (entity_count > offset && entity_count <= offset + config->max_elements_per_page) { plpath = mpd_playlist_get_path(pl); if (strncmp(filter, "-", 1) == 0 || strncasecmp(filter, plpath, 1) == 0 || - (strncmp(filter, "0", 1) == 0 && isalpha(*plpath) == 0 ) - ) { + (strncmp(filter, "0", 1) == 0 && isalpha(*plpath) == 0 )) + { if (entities_returned++) len += json_printf(&out, ", "); - snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, plpath); - sanitize_string(plpath); - if (access(smartpls_file, F_OK ) != -1) - smartpls = true; - else + snprintf(smartpls_file, 400, "%s/smartpls/%s", config->varlibdir, plpath); + if (validate_string(plpath) == true) { + if (access(smartpls_file, F_OK ) != -1) { + smartpls = true; + } + else { + smartpls = false; + } + } + else { smartpls = false; + } len += json_printf(&out, "{Type: %Q, uri: %Q, name: %Q, last_modified: %d}", (smartpls == true ? "smartpls" : "plist"), plpath, @@ -2228,51 +2400,57 @@ int mpd_client_put_playlists(char *buffer, unsigned int offset, char *filter) { CHECK_RETURN_LEN(); } -int mpd_client_put_playlist_list(char *buffer, char *uri, unsigned int offset, char *filter) { +static int mpd_client_put_playlist_list(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *uri, const unsigned int offset, const char *filter) { struct mpd_entity *entity; - unsigned int entity_count = 0; - unsigned int entities_returned = 0; + unsigned entity_count = 0; + unsigned entities_returned = 0; const char *entityName; char smartpls_file[400]; bool smartpls; - int len; + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - if (!mpd_send_list_playlist_meta(mpd.conn, uri)) + if (mpd_send_list_playlist_meta(mpd_state->conn, uri) == false) RETURN_ERROR_AND_RECOVER("mpd_send_list_meta"); len = json_printf(&out, "{type: playlist_detail, data: ["); - while ((entity = mpd_recv_entity(mpd.conn)) != NULL) { + while ((entity = mpd_recv_entity(mpd_state->conn)) != NULL) { const struct mpd_song *song; entity_count++; - if (entity_count > offset && entity_count <= offset + config.max_elements_per_page) { + if (entity_count > offset && entity_count <= offset + config->max_elements_per_page) { song = mpd_entity_get_song(entity); entityName = mpd_client_get_tag(song, MPD_TAG_TITLE); if (strncmp(filter, "-", 1) == 0 || strncasecmp(filter, entityName, 1) == 0 || - (strncmp(filter, "0", 1) == 0 && isalpha(*entityName) == 0 ) - ) { + (strncmp(filter, "0", 1) == 0 && isalpha(*entityName) == 0)) + { if (entities_returned++) len += json_printf(&out, ","); len += json_printf(&out, "{Type: song, "); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); len += json_printf(&out, ", Pos: %d", entity_count); len += json_printf(&out, "}"); - } else { + } + else { entity_count--; } } mpd_entity_free(entity); } - sanitize_string(uri); - snprintf(smartpls_file, 400, "%s/smartpls/%s", config.varlibdir, uri); - if (access(smartpls_file, F_OK ) != -1) - smartpls = true; - else - smartpls = false; + + smartpls = false; + if (validate_string(uri) == true) { + snprintf(smartpls_file, 400, "%s/smartpls/%s", config->varlibdir, uri); + if (access(smartpls_file, F_OK ) != -1) { + smartpls = true; + } + else { + smartpls = false; + } + } len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, filter: %Q, uri: %Q, smartpls: %B}", entity_count, offset, @@ -2285,35 +2463,35 @@ int mpd_client_put_playlist_list(char *buffer, char *uri, unsigned int offset, c CHECK_RETURN_LEN(); } -int mpd_client_search(char *buffer, char *searchstr, char *filter, char *plist, unsigned int offset) { +static int mpd_client_search(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *searchstr, const char *filter, const char *plist, const unsigned int offset) { struct mpd_song *song; - unsigned long entity_count = 0; - unsigned long entities_returned = 0; - int len = 0; + unsigned entity_count = 0; + unsigned entities_returned = 0; + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); if (strcmp(plist, "") == 0) { - if (mpd_send_command(mpd.conn, "search", filter, searchstr, NULL) == false) + if (mpd_send_command(mpd_state->conn, "search", filter, searchstr, NULL) == false) RETURN_ERROR_AND_RECOVER("mpd_search"); len = json_printf(&out, "{type: search, data: ["); } else if (strcmp(plist, "queue") == 0) { - if (mpd_send_command(mpd.conn, "searchadd", filter, searchstr, NULL) == false) + if (mpd_send_command(mpd_state->conn, "searchadd", filter, searchstr, NULL) == false) RETURN_ERROR_AND_RECOVER("mpd_searchadd"); } else { - if (mpd_send_command(mpd.conn, "searchaddpl", plist, filter, searchstr, NULL) == false) + if (mpd_send_command(mpd_state->conn, "searchaddpl", plist, filter, searchstr, NULL) == false) RETURN_ERROR_AND_RECOVER("mpd_searchaddpl"); } if (strcmp(plist, "") == 0) { - while ((song = mpd_recv_song(mpd.conn)) != NULL) { + while ((song = mpd_recv_song(mpd_state->conn)) != NULL) { entity_count++; - if (entity_count > offset && entity_count <= offset + config.max_elements_per_page) { + if (entity_count > offset && entity_count <= offset + config->max_elements_per_page) { if (entities_returned++) len += json_printf(&out, ", "); len += json_printf(&out, "{Type: song, "); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); @@ -2323,7 +2501,7 @@ int mpd_client_search(char *buffer, char *searchstr, char *filter, char *plist, } } else - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); if (strcmp(plist, "") == 0) { len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, searchstr: %Q}", @@ -2340,8 +2518,8 @@ int mpd_client_search(char *buffer, char *searchstr, char *filter, char *plist, } -int mpd_client_search_adv(char *buffer, char *expression, char *sort, bool sortdesc, char *grouptag, char *plist, unsigned int offset) { - int len = 0; +static int mpd_client_search_adv(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *expression, const char *sort, const bool sortdesc, const char *grouptag, const char *plist, const unsigned int offset) { + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); #if LIBMPDCLIENT_CHECK_VERSION(2, 17, 0) struct mpd_song *song; @@ -2349,44 +2527,44 @@ int mpd_client_search_adv(char *buffer, char *expression, char *sort, bool sortd unsigned long entities_returned = 0; if (strcmp(plist, "") == 0) { - if (mpd_search_db_songs(mpd.conn, false) == false) + if (mpd_search_db_songs(mpd_state->conn, false) == false) RETURN_ERROR_AND_RECOVER("mpd_search_db_songs"); len = json_printf(&out, "{type: search, data: ["); } else if (strcmp(plist, "queue") == 0) { - if (mpd_search_add_db_songs(mpd.conn, false) == false) + if (mpd_search_add_db_songs(mpd_state->conn, false) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_db_songs"); } else { - if (mpd_search_add_db_songs_to_playlist(mpd.conn, plist) == false) + if (mpd_search_add_db_songs_to_playlist(mpd_state->conn, plist) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_db_songs_to_playlist"); } - if (mpd_search_add_expression(mpd.conn, expression) == false) + if (mpd_search_add_expression(mpd_state->conn, expression) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_expression"); if (strcmp(plist, "") == 0) { - if (sort != NULL && strcmp(sort, "") != 0 && mpd.feat_tags == true) { - if (mpd_search_add_sort_name(mpd.conn, sort, sortdesc) == false) + if (sort != NULL && strcmp(sort, "") != 0 && mpd_state->feat_tags == true) { + if (mpd_search_add_sort_name(mpd_state->conn, sort, sortdesc) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_sort_name"); } - if (grouptag != NULL && strcmp(grouptag, "") != 0 && mpd.feat_tags == true) { - if (mpd_search_add_group_tag(mpd.conn, mpd_tag_name_parse(grouptag)) == false) + if (grouptag != NULL && strcmp(grouptag, "") != 0 && mpd_state->feat_tags == true) { + if (mpd_search_add_group_tag(mpd_state->conn, mpd_tag_name_parse(grouptag)) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_group_tag"); } - if (mpd_search_add_window(mpd.conn, offset, offset + config.max_elements_per_page) == false) + if (mpd_search_add_window(mpd_state->conn, offset, offset + config->max_elements_per_page) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_window"); } - if (mpd_search_commit(mpd.conn) == false) + if (mpd_search_commit(mpd_state->conn) == false) RETURN_ERROR_AND_RECOVER("mpd_search_commit"); if (strcmp(plist, "") == 0) { - while ((song = mpd_recv_song(mpd.conn)) != NULL) { + while ((song = mpd_recv_song(mpd_state->conn)) != NULL) { if (entities_returned++) len += json_printf(&out, ", "); len += json_printf(&out, "{Type: song, "); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); @@ -2394,8 +2572,9 @@ int mpd_client_search_adv(char *buffer, char *expression, char *sort, bool sortd mpd_song_free(song); } } - else - mpd_response_finish(mpd.conn); + else { + mpd_response_finish(mpd_state->conn); + } if (strcmp(plist, "") == 0) { len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, expression: %Q, " @@ -2409,32 +2588,33 @@ int mpd_client_search_adv(char *buffer, char *expression, char *sort, bool sortd grouptag ); } - else + else { len = json_printf(&out, "{type: result, data: ok}"); + } #else len = json_printf(&out, "{type: error, data: %Q}", "Advanced search is disabled."); #endif CHECK_RETURN_LEN(); } -int mpd_client_queue_crop(char *buffer) { - int len = 0; +static int mpd_client_queue_crop(t_config *config, t_mpd_state *mpd_state, char *buffer) { + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - struct mpd_status *status = mpd_run_status(mpd.conn); - int length = mpd_status_get_queue_length(status) - 1; + struct mpd_status *status = mpd_run_status(mpd_state->conn); + const int length = mpd_status_get_queue_length(status) - 1; int playing_song_pos = mpd_status_get_song_pos(status); - if (length < 0) { + if (length < 1) { len = json_printf(&out, "{type: error, data: %Q}", "A playlist longer than 1 song in length is required to crop."); printf("A playlist longer than 1 song in length is required to crop.\n"); } else if (mpd_status_get_state(status) == MPD_STATE_PLAY || mpd_status_get_state(status) == MPD_STATE_PAUSE) { playing_song_pos++; if (playing_song_pos < length) - mpd_run_delete_range(mpd.conn, playing_song_pos, -1); + mpd_run_delete_range(mpd_state->conn, playing_song_pos, -1); playing_song_pos--; if (playing_song_pos > 0 ) - mpd_run_delete_range(mpd.conn, 0, playing_song_pos--); + mpd_run_delete_range(mpd_state->conn, 0, playing_song_pos--); len = json_printf(&out, "{type: result, data: ok}"); } else { len = json_printf(&out, "{type: error, data: %Q}", "You need to be playing to crop the playlist"); @@ -2446,41 +2626,42 @@ int mpd_client_queue_crop(char *buffer) { CHECK_RETURN_LEN(); } -int mpd_client_search_queue(char *buffer, char *mpdtagtype, unsigned int offset, char *searchstr) { +static int mpd_client_search_queue(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *mpdtagtype, const unsigned int offset, const char *searchstr) { struct mpd_song *song; - unsigned long entity_count = 0; - unsigned long entities_returned = 0; - int len; + unsigned entity_count = 0; + unsigned entities_returned = 0; + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - if (mpd_search_queue_songs(mpd.conn, false) == false) { + if (mpd_search_queue_songs(mpd_state->conn, false) == false) { RETURN_ERROR_AND_RECOVER("mpd_search_queue_songs"); } if (mpd_tag_name_parse(mpdtagtype) != MPD_TAG_UNKNOWN) { - if (mpd_search_add_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(mpdtagtype), searchstr) == false) + if (mpd_search_add_tag_constraint(mpd_state->conn, MPD_OPERATOR_DEFAULT, mpd_tag_name_parse(mpdtagtype), searchstr) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_tag_constraint"); } else { - if (mpd_search_add_any_tag_constraint(mpd.conn, MPD_OPERATOR_DEFAULT, searchstr) == false) + if (mpd_search_add_any_tag_constraint(mpd_state->conn, MPD_OPERATOR_DEFAULT, searchstr) == false) RETURN_ERROR_AND_RECOVER("mpd_search_add_any_tag_constraint"); } - if (mpd_search_commit(mpd.conn) == false) + if (mpd_search_commit(mpd_state->conn) == false) { RETURN_ERROR_AND_RECOVER("mpd_search_commit"); + } else { len = json_printf(&out, "{type: queuesearch, data: ["); - while ((song = mpd_recv_song(mpd.conn)) != NULL) { + while ((song = mpd_recv_song(mpd_state->conn)) != NULL) { entity_count++; - if (entity_count > offset && entity_count <= offset + config.max_elements_per_page) { + if (entity_count > offset && entity_count <= offset + config->max_elements_per_page) { if (entities_returned++) len += json_printf(&out, ", "); len += json_printf(&out, "{type: song, id: %d, Pos: %d, ", mpd_song_get_id(song), mpd_song_get_pos(song) ); - if (mpd.feat_tags == true) + if (mpd_state->feat_tags == true) PUT_SONG_TAGS(); else PUT_MIN_SONG_TAGS(); @@ -2500,18 +2681,19 @@ int mpd_client_search_queue(char *buffer, char *mpdtagtype, unsigned int offset, CHECK_RETURN_LEN(); } -int mpd_client_put_stats(char *buffer) { - struct mpd_stats *stats = mpd_run_stats(mpd.conn); - const unsigned *version = mpd_connection_get_server_version(mpd.conn); - int len; +static int mpd_client_put_stats(t_config *config, t_mpd_state *mpd_state, char *buffer) { + struct mpd_stats *stats = mpd_run_stats(mpd_state->conn); + const unsigned *version = mpd_connection_get_server_version(mpd_state->conn); + size_t len = 0; char mpd_version[20]; char libmpdclient_version[20]; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); snprintf(mpd_version, 20, "%u.%u.%u", version[0], version[1], version[2]); snprintf(libmpdclient_version, 20, "%i.%i.%i", LIBMPDCLIENT_MAJOR_VERSION, LIBMPDCLIENT_MINOR_VERSION, LIBMPDCLIENT_PATCH_VERSION); - if (stats == NULL) + if (stats == NULL) { RETURN_ERROR_AND_RECOVER("mpd_run_stats"); + } len = json_printf(&out, "{type: mpdstats, data: {artists: %d, albums: %d, songs: %d, " "playtime: %d, uptime: %d, dbUpdated: %d, dbPlaytime: %d, mympdVersion: %Q, mpdVersion: %Q, " "libmpdclientVersion: %Q}}", @@ -2531,21 +2713,24 @@ int mpd_client_put_stats(char *buffer) { CHECK_RETURN_LEN(); } -void mpd_client_disconnect() { - mpd.conn_state = MPD_DISCONNECT; - mpd_client_idle(100); +static void mpd_client_disconnect(t_config *config, t_mpd_state *mpd_state) { + mpd_state->conn_state = MPD_DISCONNECT; + mpd_client_idle(config, mpd_state, 100); } -int mpd_client_smartpls_put(char *buffer, char *playlist) { +static int mpd_client_smartpls_put(t_config *config, t_mpd_state *mpd_state, char *buffer, const char *playlist) { char pl_file[400]; char *smartpltype; char *p_charbuf1, *p_charbuf2; int je, int_buf1; - int len = 0; + size_t len = 0; struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE); - sanitize_string(playlist); - snprintf(pl_file, 400, "%s/smartpls/%s", config.varlibdir, playlist); + if (validate_string(playlist) == false) { + len = json_printf(&out, "{type: error, data: %Q}}", "Can't read smart playlist file"); + return len; + } + snprintf(pl_file, 400, "%s/smartpls/%s", config->varlibdir, playlist); char *content = json_fread(pl_file); if (content == NULL) { len = json_printf(&out, "{type: error, data: %Q}}", "Can't read smart playlist file"); @@ -2606,58 +2791,60 @@ int mpd_client_smartpls_put(char *buffer, char *playlist) { return len; } -int mpd_client_smartpls_save(char *smartpltype, char *playlist, char *tag, char *searchstr, int maxentries, int timerange) { +static bool mpd_client_smartpls_save(t_config *config, t_mpd_state *mpd_state, const char *smartpltype, const char *playlist, const char *tag, const char *searchstr, const int maxentries, const int timerange) { char tmp_file[400]; char pl_file[400]; - sanitize_string(playlist); - snprintf(tmp_file, 400, "%s/tmp/%s", config.varlibdir, playlist); - snprintf(pl_file, 400, "%s/smartpls/%s", config.varlibdir, playlist); + if (validate_string(playlist) == false) { + return false; + } + snprintf(tmp_file, 400, "%s/tmp/%s", config->varlibdir, playlist); + snprintf(pl_file, 400, "%s/smartpls/%s", config->varlibdir, playlist); if (strcmp(smartpltype, "sticker") == 0) { if (json_fprintf(tmp_file, "{type: %Q, sticker: %Q, maxentries: %d}", smartpltype, tag, maxentries) == -1) { printf("Error creating file %s\n", tmp_file); - return 1; + return false; } else if (rename(tmp_file, pl_file) == -1) { printf("Error renaming file from %s to %s\n", tmp_file, pl_file); - return 1; + return false; } - else if (mpd_client_smartpls_update_sticker(playlist, tag, maxentries) == 1) { + else if (mpd_client_smartpls_update_sticker(config, mpd_state, playlist, tag, maxentries) == 1) { printf("Update of smart playlist %s failed.\n", playlist); - return 1; + return false; } } else if (strcmp(smartpltype, "newest") == 0) { if (json_fprintf(tmp_file, "{type: %Q, timerange: %d}", smartpltype, timerange) == -1) { printf("Error creating file %s\n", tmp_file); - return 1; + return false; } else if (rename(tmp_file, pl_file) == -1) { printf("Error renaming file from %s to %s\n", tmp_file, pl_file); - return 1; + return false; } - else if (mpd_client_smartpls_update_newest(playlist, timerange) == 1) { + else if (mpd_client_smartpls_update_newest(config, mpd_state, playlist, timerange) == 1) { printf("Update of smart playlist %s failed.\n", playlist); - return 1; + return false; } } else if (strcmp(smartpltype, "search") == 0) { if (json_fprintf(tmp_file, "{type: %Q, tag: %Q, searchstr: %Q}", smartpltype, tag, searchstr) == -1) { printf("Error creating file %s\n", tmp_file); - return 1; + return false; } else if (rename(tmp_file, pl_file) == -1) { printf("Error renaming file from %s to %s\n", tmp_file, pl_file); - return 1; + return false; } - else if (mpd_client_smartpls_update_search(playlist, tag, searchstr) == 1) { + else if (mpd_client_smartpls_update_search(config, mpd_state, playlist, tag, searchstr) == 1) { printf("Update of smart playlist %s failed.\n", playlist); - return 1; + return false; } } - return 0; + return true; } -int mpd_client_smartpls_update_all() { +static bool mpd_client_smartpls_update_all(t_config *config, t_mpd_state *mpd_state) { DIR *dir; struct dirent *ent; char *smartpltype; @@ -2667,15 +2854,16 @@ int mpd_client_smartpls_update_all() { char *p_charbuf1, *p_charbuf2; int int_buf1; - if (!config.smartpls) - return 0; + if (config->smartpls == false) { + return true; + } - snprintf(dirname, 400, "%s/smartpls", config.varlibdir); + snprintf(dirname, 400, "%s/smartpls", config->varlibdir); if ((dir = opendir (dirname)) != NULL) { while ((ent = readdir(dir)) != NULL) { if (strncmp(ent->d_name, ".", 1) == 0) continue; - snprintf(filename, 400, "%s/smartpls/%s", config.varlibdir, ent->d_name); + snprintf(filename, 400, "%s/smartpls/%s", config->varlibdir, ent->d_name); char *content = json_fread(filename); if (content == NULL) { printf("Cant read smart playlist file %s\n", filename); @@ -2687,7 +2875,7 @@ int mpd_client_smartpls_update_all() { if (strcmp(smartpltype, "sticker") == 0) { je = json_scanf(content, strlen(content), "{sticker: %Q, maxentries: %d}", &p_charbuf1, &int_buf1); if (je == 2) { - mpd_client_smartpls_update_sticker(ent->d_name, p_charbuf1, int_buf1); + mpd_client_smartpls_update_sticker(config, mpd_state, ent->d_name, p_charbuf1, int_buf1); free(p_charbuf1); } else @@ -2696,7 +2884,7 @@ int mpd_client_smartpls_update_all() { else if (strcmp(smartpltype, "newest") == 0) { je = json_scanf(content, strlen(content), "{timerange: %d}", &int_buf1); if (je == 1) { - mpd_client_smartpls_update_newest(ent->d_name, int_buf1); + mpd_client_smartpls_update_newest(config, mpd_state, ent->d_name, int_buf1); } else printf("Can't parse smart playlist file %s\n", filename); @@ -2704,7 +2892,7 @@ int mpd_client_smartpls_update_all() { else if (strcmp(smartpltype, "search") == 0) { je = json_scanf(content, strlen(content), "{tag: %Q, searchstr: %Q}", &p_charbuf1, &p_charbuf2); if (je == 2) { - mpd_client_smartpls_update_search(ent->d_name, p_charbuf1, p_charbuf2); + mpd_client_smartpls_update_search(config, mpd_state, ent->d_name, p_charbuf1, p_charbuf2); free(p_charbuf1); free(p_charbuf2); } @@ -2717,49 +2905,53 @@ int mpd_client_smartpls_update_all() { closedir (dir); } else { printf("Can't open smart playlist directory %s\n", dirname); - return 1; + return false; } - return 0; + return true; } -int mpd_client_smartpls_clear(char *playlist) { +static bool mpd_client_smartpls_clear(t_config *config, t_mpd_state *mpd_state, const char *playlist) { struct mpd_playlist *pl; const char *plpath; bool exists = false; - if (!mpd_send_list_playlists(mpd.conn)) { + if (mpd_send_list_playlists(mpd_state->conn) == false) { LOG_ERROR_AND_RECOVER("mpd_send_list_playlists"); return 1; } - while ((pl = mpd_recv_playlist(mpd.conn)) != NULL) { + while ((pl = mpd_recv_playlist(mpd_state->conn)) != NULL) { plpath = mpd_playlist_get_path(pl); if (strcmp(playlist, plpath) == 0) exists = true; mpd_playlist_free(pl); - if (exists) + if (exists == true) { break; - } - mpd_response_finish(mpd.conn); - - if (exists) { - if (!mpd_run_rm(mpd.conn, playlist)) { - LOG_ERROR_AND_RECOVER("mpd_run_rm"); - return 1; } } - return 0; + mpd_response_finish(mpd_state->conn); + + if (exists) { + if (mpd_run_rm(mpd_state->conn, playlist) == false) { + LOG_ERROR_AND_RECOVER("mpd_run_rm"); + return false; + } + } + return true; } -int mpd_client_smartpls_update_search(char *playlist, char *tag, char *searchstr) { - mpd_client_smartpls_clear(playlist); - if (mpd.feat_advsearch == true && strcmp(tag, "expression") == 0) - mpd_client_search_adv(mpd.buf, searchstr, NULL, true, NULL, playlist, 0); - else - mpd_client_search(mpd.buf, searchstr, tag, playlist, 0); +static bool mpd_client_smartpls_update_search(t_config *config, t_mpd_state *mpd_state, const char *playlist, const char *tag, const char *searchstr) { + char buffer[MAX_SIZE]; + mpd_client_smartpls_clear(config, mpd_state, playlist); + if (mpd_state->feat_advsearch == true && strcmp(tag, "expression") == 0) { + mpd_client_search_adv(config, mpd_state, buffer, searchstr, NULL, true, NULL, playlist, 0); + } + else { + mpd_client_search(config, mpd_state, buffer, searchstr, tag, playlist, 0); + } LOG_INFO() printf("Updated %s\n", playlist); - return 0; + return true; } -int mpd_client_smartpls_update_sticker(char *playlist, char *sticker, int maxentries) { +static bool mpd_client_smartpls_update_sticker(t_config *config, t_mpd_state *mpd_state, const char *playlist, const char *sticker, const int maxentries) { struct mpd_pair *pair; char *uri = NULL; const char *p_value; @@ -2769,15 +2961,15 @@ int mpd_client_smartpls_update_sticker(char *playlist, char *sticker, int maxent long i = 0; size_t j; - if (!mpd_send_sticker_find(mpd.conn, "song", "", sticker)) { + if (mpd_send_sticker_find(mpd_state->conn, "song", "", sticker) == false) { LOG_ERROR_AND_RECOVER("mpd_send_sticker_find"); - return 1; + return false; } struct list add_list; list_init(&add_list); - while ((pair = mpd_recv_pair(mpd.conn)) != NULL) { + while ((pair = mpd_recv_pair(mpd_state->conn)) != NULL) { if (strcmp(pair->name, "file") == 0) { uri = strdup(pair->value); } @@ -2785,28 +2977,31 @@ int mpd_client_smartpls_update_sticker(char *playlist, char *sticker, int maxent p_value = mpd_parse_sticker(pair->value, &j); if (p_value != NULL) { value = strtol(p_value, &crap, 10); - if (value >= 1) + if (value >= 1) { list_push(&add_list, uri, value); - if (value > value_max) + } + if (value > value_max) { value_max = value; + } } } - mpd_return_pair(mpd.conn, pair); + mpd_return_pair(mpd_state->conn, pair); } - mpd_response_finish(mpd.conn); + mpd_response_finish(mpd_state->conn); free(uri); - mpd_client_smartpls_clear(playlist); + mpd_client_smartpls_clear(config, mpd_state, playlist); - if (value_max > 2) + if (value_max > 2) { value_max = value_max / 2; + } list_sort_by_value(&add_list, false); struct node *current = add_list.list; while (current != NULL) { if (current->value >= value_max) { - if (!mpd_run_playlist_add(mpd.conn, playlist, current->data)) { + if (mpd_run_playlist_add(mpd_state->conn, playlist, current->data) == false) { LOG_ERROR_AND_RECOVER("mpd_run_playlist_add"); list_free(&add_list); return 1; @@ -2819,35 +3014,160 @@ int mpd_client_smartpls_update_sticker(char *playlist, char *sticker, int maxent } list_free(&add_list); LOG_INFO() printf("Updated %s with %ld songs, minValue: %ld\n", playlist, i, value_max); - return 0; + return true; } -int mpd_client_smartpls_update_newest(char *playlist, int timerange) { - unsigned long value_max = 0; +static bool mpd_client_smartpls_update_newest(t_config *config, t_mpd_state *mpd_state, const char *playlist, const int timerange) { + int value_max = 0; + char buffer[MAX_SIZE]; char searchstr[50]; - struct mpd_stats *stats = mpd_run_stats(mpd.conn); + struct mpd_stats *stats = mpd_run_stats(mpd_state->conn); if (stats != NULL) { value_max = mpd_stats_get_db_update_time(stats); mpd_stats_free(stats); } else { LOG_ERROR_AND_RECOVER("mpd_run_stats"); - return 1; + return false; } - mpd_client_smartpls_clear(playlist); + mpd_client_smartpls_clear(config, mpd_state, playlist); value_max -= timerange; if (value_max > 0) { - if (mpd.feat_advsearch == true) { - snprintf(searchstr, 50, "(modified-since '%lu')", value_max); - mpd_client_search_adv(mpd.buf, searchstr, NULL, true, NULL, playlist, 0); + if (mpd_state->feat_advsearch == true) { + snprintf(searchstr, 50, "(modified-since '%d')", value_max); + mpd_client_search_adv(config, mpd_state, buffer, searchstr, NULL, true, NULL, playlist, 0); } else { - snprintf(searchstr, 20, "%lu", value_max); - mpd_client_search(mpd.buf, searchstr, "modified-since", playlist, 0); + snprintf(searchstr, 20, "%d", value_max); + mpd_client_search(config, mpd_state, buffer, searchstr, "modified-since", playlist, 0); } LOG_INFO() printf("Updated %s\n", playlist); } - return 0; + return true; +} + +static void mpd_client_read_statefiles(t_config *config, t_mpd_state *mpd_state) { + char *crap; + char value[400]; + + LOG_INFO() printf("Reading states\n"); + if (mpd_client_state_get(config, mpd_state, "notificationWeb", value)) { + if (strcmp(value, "true") == 0) + mpd_state->notificationWeb = true; + else + mpd_state->notificationWeb = false; + } + else { + mpd_state->notificationWeb = false; + mpd_client_state_set(config, mpd_state, "notificationWeb", "false"); + } + + if (mpd_client_state_get(config, mpd_state, "notificationPage", value)) { + if (strcmp(value, "true") == 0) + mpd_state->notificationPage = true; + else + mpd_state->notificationPage = false; + } + else { + mpd_state->notificationPage = true; + mpd_client_state_set(config, mpd_state, "notificationPage", "true"); + } + + if (mpd_client_state_get(config, mpd_state, "jukeboxMode", value)) + mpd_state->jukeboxMode = strtol(value, &crap, 10); + else { + mpd_state->jukeboxMode = 0; + mpd_client_state_set(config, mpd_state, "jukeboxMode", "0"); + } + + if (mpd_client_state_get(config, mpd_state, "jukeboxPlaylist", value)) + mpd_state->jukeboxPlaylist = strdup(value); + else { + mpd_state->jukeboxPlaylist = strdup("Database"); + mpd_client_state_set(config, mpd_state, "jukeboxPlaylist", "Database"); + } + + if (mpd_client_state_get(config, mpd_state, "jukeboxQueueLength", value)) + mpd_state->jukeboxQueueLength = strtol(value, &crap, 10); + else { + mpd_state->jukeboxQueueLength = 1; + mpd_client_state_set(config, mpd_state, "jukeboxQueueLength", "1"); + } + + if (mpd_client_state_get(config, mpd_state, "colsQueueCurrent", value)) + mpd_state->colsQueueCurrent = strdup(value); + else { + mpd_state->colsQueueCurrent = strdup("[\"Pos\",\"Title\",\"Artist\",\"Album\",\"Duration\"]"); + mpd_client_state_set(config, mpd_state, "colsQueueCurrent", mpd_state->colsQueueCurrent); + } + + if (mpd_client_state_get(config, mpd_state, "colsSearch", value)) + mpd_state->colsSearch = strdup(value); + else { + mpd_state->colsSearch = strdup("[\"Title\",\"Artist\",\"Album\",\"Duration\"]"); + mpd_client_state_set(config, mpd_state, "colsSearch", mpd_state->colsSearch); + } + + if (mpd_client_state_get(config, mpd_state, "colsBrowseDatabase", value)) + mpd_state->colsBrowseDatabase = strdup(value); + else { + mpd_state->colsBrowseDatabase = strdup("[\"Track\",\"Title\",\"Duration\"]"); + mpd_client_state_set(config, mpd_state, "colsBrowseDatabase", mpd_state->colsBrowseDatabase); + } + + if (mpd_client_state_get(config, mpd_state, "colsBrowsePlaylistsDetail", value)) + mpd_state->colsBrowsePlaylistsDetail = strdup(value); + else { + mpd_state->colsBrowsePlaylistsDetail = strdup("[\"Pos\",\"Title\",\"Artist\",\"Album\",\"Duration\"]"); + mpd_client_state_set(config, mpd_state, "colsBrowsePlaylistsDetail", mpd_state->colsBrowsePlaylistsDetail); + } + + if (mpd_client_state_get(config, mpd_state, "colsBrowseFilesystem", value)) + mpd_state->colsBrowseFilesystem = strdup(value); + else { + mpd_state->colsBrowseFilesystem = strdup("[\"Type\",\"Title\",\"Artist\",\"Album\",\"Duration\"]"); + mpd_client_state_set(config, mpd_state, "colsBrowseFilesystem", mpd_state->colsBrowseFilesystem); + } + + if (mpd_client_state_get(config, mpd_state, "colsPlayback", value)) + mpd_state->colsPlayback = strdup(value); + else { + mpd_state->colsPlayback = strdup("[\"Artist\",\"Album\",\"Genre\"]"); + mpd_client_state_set(config, mpd_state, "colsPlayback", mpd_state->colsPlayback); + } + + if (mpd_client_state_get(config, mpd_state, "colsQueueLastPlayed", value)) + mpd_state->colsQueueLastPlayed = strdup(value); + else { + mpd_state->colsQueueLastPlayed = strdup("[\"Pos\",\"Title\",\"Artist\",\"Album\",\"LastPlayed\"]"); + mpd_client_state_set(config, mpd_state, "colsQueueLastPlayed", mpd_state->colsQueueLastPlayed); + } +} + +static int mpd_client_read_last_played(t_config *config, t_mpd_state *mpd_state) { + char cfgfile[400]; + char *line; + char *data; + char *crap; + size_t n = 0; + ssize_t read; + long value; + + snprintf(cfgfile, 400, "%s/state/last_played", config->varlibdir); + FILE *fp = fopen(cfgfile, "r"); + if (fp == NULL) { + printf("Error opening %s\n", cfgfile); + return 0; + } + while ((read = getline(&line, &n, fp)) > 0) { + value = strtol(line, &data, 10); + if (strlen(data) > 2) + data = data + 2; + strtok_r(data, "\n", &crap); + list_push(&mpd_state->last_played, data, value); + } + fclose(fp); + return mpd_state->last_played.length;; } diff --git a/src/mpd_client.h b/src/mpd_client.h index 9f6365b..ac6de0c 100644 --- a/src/mpd_client.h +++ b/src/mpd_client.h @@ -24,144 +24,6 @@ #ifndef __MPD_CLIENT_H__ #define __MPD_CLIENT_H__ +void *mpd_client_loop(void *arg_config); -#define RETURN_ERROR_AND_RECOVER(X) do { \ - printf("MPD %s: %s\n", X, mpd_connection_get_error_message(mpd.conn)); \ - len = json_printf(&out, "{type: error, data: %Q}", mpd_connection_get_error_message(mpd.conn)); \ - if (!mpd_connection_clear_error(mpd.conn)) \ - mpd.conn_state = MPD_FAILURE; \ - return len; \ -} while (0) - -#define LOG_ERROR_AND_RECOVER(X) do { \ - printf("MPD %s: %s\n", X, mpd_connection_get_error_message(mpd.conn)); \ - if (!mpd_connection_clear_error(mpd.conn)) \ - mpd.conn_state = MPD_FAILURE; \ -} while (0) - -#define PUT_SONG_TAGS() do { \ - struct node *current = mympd_tags.list; \ - int tagnr = 0; \ - while (current != NULL) { \ - if (tagnr ++) \ - len += json_printf(&out, ","); \ - len += json_printf(&out, "%Q: %Q", current->data, mpd_client_get_tag(song, mpd_tag_name_parse(current->data))); \ - current = current->next; \ - } \ - len += json_printf(&out, ", Duration: %d, uri: %Q", mpd_song_get_duration(song), mpd_song_get_uri(song)); \ -} while (0) - -#define PUT_MIN_SONG_TAGS() do { \ - len += json_printf(&out, "Title: %Q, Duration: %d, uri: %Q", mpd_client_get_tag(song, MPD_TAG_TITLE), mpd_song_get_duration(song), mpd_song_get_uri(song)); \ -} while (0) - - -enum mpd_conn_states { - MPD_DISCONNECTED, - MPD_FAILURE, - MPD_CONNECTED, - MPD_RECONNECT, - MPD_DISCONNECT -}; - -struct t_mpd { - // Connection - struct mpd_connection *conn; - enum mpd_conn_states conn_state; - int timeout; - - // Reponse Buffer - char buf[MAX_SIZE]; - - // States - int song_id; - int next_song_id; - int last_song_id; - unsigned queue_version; - unsigned queue_length; - int last_update_sticker_song_id; - int last_last_played_id; - - // Features - const unsigned* protocol; - // Supported tags - bool feat_sticker; - bool feat_playlists; - bool feat_tags; - bool feat_library; - bool feat_advsearch; -} mpd; - -struct list mpd_tags; -struct list mympd_tags; -struct list mympd_searchtags; -struct list mympd_browsetags; -struct list last_played; - -typedef struct { - long playCount; - long skipCount; - long lastPlayed; - long like; -} t_sticker; - -typedef struct { - bool notificationWeb; - bool notificationPage; - int jukeboxMode; - const char *jukeboxPlaylist; - int jukeboxQueueLength; - char *colsQueueCurrent; - char *colsSearch; - char *colsBrowseDatabase; - char *colsBrowsePlaylistsDetail; - char *colsBrowseFilesystem; - char *colsPlayback; - char *colsQueueLastPlayed; -} t_mympd_state; - -t_mympd_state mympd_state; - -void mpd_client_idle(int timeout); -void mpd_client_parse_idle(int idle_bitmask); -void mpd_client_api(void *arg_request); -void mpd_client_notify(size_t n); -bool mpd_client_count_song_id(int song_id, char *name, int value); -bool mpd_client_count_song_uri(const char *uri, char *name, int value); -bool mpd_client_like_song_uri(const char *uri, int value); -bool mpd_client_last_played_song_uri(const char *uri); -bool mpd_client_last_played_song_id(int song_id); -bool mpd_client_get_sticker(const char *uri, t_sticker *sticker); -bool mpd_client_last_played_list(int song_id); -bool mpd_client_jukebox(); -bool mpd_client_state_get(char *name, char *value); -bool mpd_client_state_set(const char *name, const char *value); -int mpd_client_smartpls_save(char *smartpltype, char *playlist, char *tag, char *searchstr, int maxentries, int timerange); -int mpd_client_smartpls_put(char *buffer, char *playlist); -int mpd_client_smartpls_update_all(); -int mpd_client_smartpls_clear(char *playlist); -int mpd_client_smartpls_update_sticker(char *playlist, char *sticker, int maxentries); -int mpd_client_smartpls_update_newest(char *playlist, int timerange); -int mpd_client_smartpls_update_search(char *playlist, char *tag, char *searchstr); -int mpd_client_get_updatedb_state(char *buffer); -int mpd_client_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length); -int mpd_client_put_outputs(char *buffer); -int mpd_client_put_current_song(char *buffer); -int mpd_client_put_queue(char *buffer, unsigned int offset, unsigned *queue_version, unsigned *queue_length); -int mpd_client_put_browse(char *buffer, char *path, unsigned int offset, char *filter); -int mpd_client_search(char *buffer, char *searchstr, char *filter, char *plist, unsigned int offset); -int mpd_client_search_adv(char *buffer, char *expression, char *sort, bool sortdesc, char *grouptag, char *plist, unsigned int offset); -int mpd_client_search_queue(char *buffer, char *mpdtagtype, unsigned int offset, char *searchstr); -int mpd_client_put_welcome(char *buffer); -int mpd_client_put_volume(char *buffer); -int mpd_client_put_stats(char *buffer); -int mpd_client_put_settings(char *buffer, void *arg_config); -int mpd_client_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, char *mpdsearchtagtype, char *searchstr, char *filter); -int mpd_client_put_songs_in_album(char *buffer, char *album, char *search, char *tag); -int mpd_client_put_playlists(char *buffer, unsigned int offset, char *filter); -int mpd_client_put_playlist_list(char *buffer, char *uri, unsigned int offset, char *filter); -int mpd_client_put_songdetails(char *buffer, char *uri); -int mpd_client_put_last_played_songs(char *buffer, unsigned int offset); -int mpd_client_queue_crop(char *buffer); -void mpd_client_disconnect(); #endif diff --git a/src/mympd_api.c b/src/mympd_api.c index f265b53..1d0c397 100644 --- a/src/mympd_api.c +++ b/src/mympd_api.c @@ -39,21 +39,22 @@ #include "../dist/src/frozen/frozen.h" //private definitions -static void mympd_api(void *arg_request, void *arg_config); -static int mympd_api_syscmd(char *buffer, const char *cmd, void *arg_config); +//static void mympd_api(void *arg_request, void *arg_config); +static void mympd_api(t_work_request *request, t_config *config); +static int mympd_api_syscmd(char *buffer, const char *cmd, t_config *config); //public functions void *mympd_api_loop(void *arg_config) { while (s_signal_received == 0) { - struct work_request_t *req = tiny_queue_shift(mympd_api_queue); - mympd_api(req, arg_config); + struct t_work_request *request = tiny_queue_shift(mympd_api_queue); + mympd_api(request, arg_config); } return NULL; } //private functions -static void mympd_api(void *arg_request, void *arg_config) { - struct work_request_t *request = (struct work_request_t*) arg_request; +static void mympd_api(t_work_request *request, t_config *config) { + //t_work_request *request = (t_work_request *) arg_request; size_t len = 0; char buffer[MAX_SIZE]; int je; @@ -61,10 +62,10 @@ static void mympd_api(void *arg_request, void *arg_config) { LOG_VERBOSE() printf("MYMPD API request: %.*s\n", request->length, request->data); if (request->cmd_id == MYMPD_API_SYSCMD) { - if (config.syscmds == true) { + if (config->syscmds == true) { je = json_scanf(request->data, request->length, "{data: {cmd: %Q}}", &p_charbuf1); if (je == 1) { - len = mympd_api_syscmd(buffer, p_charbuf1, arg_config); + len = mympd_api_syscmd(buffer, p_charbuf1, config); free(p_charbuf1); } } @@ -83,7 +84,7 @@ static void mympd_api(void *arg_request, void *arg_config) { } LOG_DEBUG() fprintf(stderr, "DEBUG: Send http response to connection %lu (first 800 chars):\n%*.*s\n", request->conn_id, 0, 800, buffer); - struct work_result_t *response = (struct work_result_t*)malloc(sizeof(struct work_result_t)); + t_work_result *response = (t_work_result *)malloc(sizeof(t_work_result)); response->conn_id = request->conn_id; response->length = copy_string(response->data, buffer, MAX_SIZE, len); tiny_queue_push(web_server_queue, response); @@ -91,16 +92,15 @@ static void mympd_api(void *arg_request, void *arg_config) { free(request); } -static int mympd_api_syscmd(char *buffer, const char *cmd, void *arg_config) { +static int mympd_api_syscmd(char *buffer, const char *cmd, t_config *config) { int len; char filename[400]; char *line; char *crap; size_t n = 0; ssize_t read; - t_config *config = (t_config *) arg_config; - const int order = list_get_value(config->syscmd_list, cmd); + const int order = list_get_value(&config->syscmd_list, cmd); if (order == -1) { printf("ERROR: Syscmd not defined: %s\n", cmd); len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"System command not defined\"}"); @@ -118,9 +118,10 @@ static int mympd_api_syscmd(char *buffer, const char *cmd, void *arg_config) { fclose(fp); if (read > 0) { strtok_r(line, "\n", &crap); - if (system(line) == 0) { + const int rc = system(line); + if ( rc == 0) { len = snprintf(buffer, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Executed cmd %s.\"}", cmd); - LOG_VERBOSE2() printf("Executed syscmd: \"%s\"\n", line); + LOG_VERBOSE() printf("Executed syscmd: \"%s\"\n", line); } else { len = snprintf(buffer, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Executing cmd %s failed.\"}", cmd); diff --git a/src/web_server.c b/src/web_server.c index 2f51b7b..aceddf8 100644 --- a/src/web_server.c +++ b/src/web_server.c @@ -38,8 +38,8 @@ static int is_websocket(const struct mg_connection *nc); static void ev_handler(struct mg_connection *nc, int ev, void *ev_data); static void ev_handler_redirect(struct mg_connection *nc_http, int ev, void *ev_data); -static void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response); -static void send_api_response(struct mg_mgr *mgr, struct work_result_t *response); +static void send_ws_notify(struct mg_mgr *mgr, t_work_result *response); +static void send_api_response(struct mg_mgr *mgr, t_work_result *response); static bool handle_api(long conn_id, const char *request, int request_len); typedef struct t_user_data { @@ -48,9 +48,8 @@ typedef struct t_user_data { } t_user_data; //public functions -bool web_server_init(void *arg_mgr, void *arg_config) { +bool web_server_init(void *arg_mgr, t_config *config) { struct mg_mgr *mgr = (struct mg_mgr *) arg_mgr; - t_config *config = (t_config *) arg_config; struct mg_connection *nc_https; struct mg_connection *nc_http; struct mg_bind_opts bind_opts_https; @@ -78,7 +77,7 @@ bool web_server_init(void *arg_mgr, void *arg_config) { return false; } mg_set_protocol_http_websocket(nc_http); - LOG_INFO2() printf("Listening on http port %s.\n", config->webport); + LOG_INFO() printf("Listening on http port %s.\n", config->webport); //bind to sslport if (config->ssl == true) { @@ -93,7 +92,7 @@ bool web_server_init(void *arg_mgr, void *arg_config) { mg_mgr_free(mgr); return false; } - LOG_INFO2() printf("Listening on ssl port %s\n", config->sslport); + LOG_INFO() printf("Listening on ssl port %s\n", config->sslport); mg_set_protocol_http_websocket(nc_https); } return mgr; @@ -110,7 +109,7 @@ void *web_server_loop(void *arg_mgr) { mg_mgr_poll(mgr, 100); unsigned web_server_queue_length = tiny_queue_length(web_server_queue); if (web_server_queue_length > 0) { - struct work_result_t *response = tiny_queue_shift(web_server_queue); + t_work_result *response = tiny_queue_shift(web_server_queue); if (response->conn_id == 0) { //Websocket notify from mpd idle send_ws_notify(mgr, response); @@ -130,7 +129,7 @@ static int is_websocket(const struct mg_connection *nc) { return nc->flags & MG_F_IS_WEBSOCKET; } -static void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response) { +static void send_ws_notify(struct mg_mgr *mgr, t_work_result *response) { struct mg_connection *nc; for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) { if (!is_websocket(nc)) @@ -140,7 +139,7 @@ static void send_ws_notify(struct mg_mgr *mgr, struct work_result_t *response) { free(response); } -static void send_api_response(struct mg_mgr *mgr, struct work_result_t *response) { +static void send_api_response(struct mg_mgr *mgr, t_work_result *response) { struct mg_connection *nc; for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) { if (nc->user_data != NULL) { @@ -171,12 +170,12 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { nc_user_data->config = config; nc_user_data->conn_id = user_data->conn_id; nc->user_data = nc_user_data; - LOG_DEBUG2() fprintf(stderr, "DEBUG: New connection id %ld.\n", user_data->conn_id); + LOG_DEBUG() fprintf(stderr, "DEBUG: New connection id %ld.\n", user_data->conn_id); break; } case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: { struct http_message *hm = (struct http_message *) ev_data; - LOG_VERBOSE2() printf("New websocket request (%ld): %.*s\n", user_data->conn_id, hm->uri.len, hm->uri.p); + LOG_VERBOSE() printf("New websocket request (%ld): %.*s\n", user_data->conn_id, hm->uri.len, hm->uri.p); if (mg_vcmp(&hm->uri, "/ws") != 0) { printf("ERROR: Websocket request not to /ws, closing connection\n"); mg_printf(nc, "%s", "HTTP/1.1 403 FORBIDDEN\r\n\r\n"); @@ -185,14 +184,14 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { break; } case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { - LOG_VERBOSE2() printf("New Websocket connection established (%ld).\n", user_data->conn_id); + LOG_VERBOSE() printf("New Websocket connection established (%ld).\n", user_data->conn_id); char response[] = "{\"type\": \"welcome\", \"data\": {\"mympdVersion\": \"" MYMPD_VERSION "\"}}"; mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, response, strlen(response)); break; } case MG_EV_HTTP_REQUEST: { struct http_message *hm = (struct http_message *) ev_data; - LOG_VERBOSE2() printf("HTTP request (%ld): %.*s\n", user_data->conn_id, hm->uri.len, hm->uri.p); + LOG_VERBOSE() printf("HTTP request (%ld): %.*s\n", user_data->conn_id, hm->uri.len, hm->uri.p); if (mg_vcmp(&hm->uri, "/api") == 0) { bool rc = handle_api(user_data->conn_id, hm->body.p, hm->body.len); if (rc == false) { @@ -211,7 +210,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { break; } case MG_EV_CLOSE: { - LOG_VERBOSE2() fprintf(stderr, "HTTP connection %ld closed.\n", user_data->conn_id); + LOG_VERBOSE() fprintf(stderr, "HTTP connection %ld closed.\n", user_data->conn_id); free(nc->user_data); break; } @@ -239,7 +238,7 @@ static void ev_handler_redirect(struct mg_connection *nc, int ev, void *ev_data) snprintf(s_redirect, 250, "https://%s/", host); else snprintf(s_redirect, 250, "https://%s:%s/", host, config->sslport); - LOG_VERBOSE2() printf("Redirecting to %s\n", s_redirect); + LOG_VERBOSE() printf("Redirecting to %s\n", s_redirect); mg_http_send_redirect(nc, 301, mg_mk_str(s_redirect), mg_mk_str(NULL)); break; } @@ -257,11 +256,11 @@ static bool handle_api(long conn_id, const char *request_body, int request_len) if (je < 1) return false; - enum mypd_cmd_ids cmd_id = get_cmd_id(cmd); + enum mympd_cmd_ids cmd_id = get_cmd_id(cmd); if (cmd_id == 0) return false; - struct work_request_t *request = (struct work_request_t*)malloc(sizeof(struct work_request_t)); + t_work_request *request = (t_work_request*)malloc(sizeof(t_work_request)); request->conn_id = conn_id; request->cmd_id = cmd_id; request->length = copy_string(request->data, request_body, 1000, request_len); diff --git a/src/web_server.h b/src/web_server.h index 1e052d7..93bb650 100644 --- a/src/web_server.h +++ b/src/web_server.h @@ -26,7 +26,7 @@ #define __WEB_SERVER_H__ void *web_server_loop(void *arg_mgr); -bool web_server_init(void *arg_mgr, void *arg_config); +bool web_server_init(void *arg_mgr, t_config *config); void web_server_free(void *arg_mgr); #endif