aboutsummaryrefslogtreecommitdiffstats
path: root/src/db
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/AllCommands.hxx (renamed from src/db_internal.h)21
-rw-r--r--src/ClientMessage.cxx (renamed from src/db/simple_db_plugin.h)36
-rw-r--r--src/DatabaseLock.cxx (renamed from src/db_lock.c)4
-rw-r--r--src/DatabaseLock.hxx (renamed from src/db_lock.h)22
-rw-r--r--src/DatabasePlaylist.hxx (renamed from src/db_save.h)19
-rw-r--r--src/DatabasePrint.hxx (renamed from src/db_print.h)42
-rw-r--r--src/DatabaseSave.cxx (renamed from src/db_save.c)30
-rw-r--r--src/DatabaseSelection.hxx (renamed from src/db_selection.h)32
-rw-r--r--src/db/ProxyDatabasePlugin.cxx476
-rw-r--r--src/db/ProxyDatabasePlugin.hxx27
-rw-r--r--src/db/SimpleDatabasePlugin.cxx347
-rw-r--r--src/db/SimpleDatabasePlugin.hxx98
-rw-r--r--src/db/simple_db_plugin.c357
-rw-r--r--src/dbUtils.c209
-rw-r--r--src/dbUtils.h56
-rw-r--r--src/db_plugin.h156
-rw-r--r--src/db_print.c393
-rw-r--r--src/db_visitor.h54
18 files changed, 1048 insertions, 1331 deletions
diff --git a/src/db_internal.h b/src/AllCommands.hxx
index a33351524..a55eb5a3b 100644
--- a/src/db_internal.h
+++ b/src/AllCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,19 +17,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_DB_INTERNAL_H
-#define MPD_DB_INTERNAL_H
+#ifndef MPD_ALL_COMMANDS_HXX
+#define MPD_ALL_COMMANDS_HXX
-#include "db_plugin.h"
+#include "command.h"
-#include <assert.h>
+class Client;
-static inline void
-db_base_init(struct db *db, const struct db_plugin *plugin)
-{
- assert(plugin != NULL);
+void command_init(void);
- db->plugin = plugin;
-}
+void command_finish(void);
+
+enum command_return
+command_process(Client *client, unsigned num, char *line);
#endif
diff --git a/src/db/simple_db_plugin.h b/src/ClientMessage.cxx
index 511505846..6fbcf3371 100644
--- a/src/db/simple_db_plugin.h
+++ b/src/ClientMessage.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,26 +17,26 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_SIMPLE_DB_PLUGIN_H
-#define MPD_SIMPLE_DB_PLUGIN_H
+#include "ClientMessage.hxx"
+#include <assert.h>
#include <glib.h>
-#include <stdbool.h>
-#include <time.h>
-
-extern const struct db_plugin simple_db_plugin;
-
-struct db;
G_GNUC_PURE
-struct directory *
-simple_db_get_root(struct db *db);
+static bool
+valid_channel_char(const char ch)
+{
+ return g_ascii_isalnum(ch) ||
+ ch == '_' || ch == '-' || ch == '.' || ch == ':';
+}
bool
-simple_db_save(struct db *db, GError **error_r);
-
-G_GNUC_PURE
-time_t
-simple_db_get_mtime(const struct db *db);
-
-#endif
+client_message_valid_channel_name(const char *name)
+{
+ do {
+ if (!valid_channel_char(*name))
+ return false;
+ } while (*++name != 0);
+
+ return true;
+}
diff --git a/src/db_lock.c b/src/DatabaseLock.cxx
index 53759673d..872b9bfd3 100644
--- a/src/db_lock.c
+++ b/src/DatabaseLock.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,7 +18,7 @@
*/
#include "config.h"
-#include "db_lock.h"
+#include "DatabaseLock.hxx"
#include "gcc.h"
#if GCC_CHECK_VERSION(4, 2)
diff --git a/src/db_lock.h b/src/DatabaseLock.hxx
index 4640502f3..6646fb43d 100644
--- a/src/db_lock.h
+++ b/src/DatabaseLock.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,14 +23,13 @@
* multi-threading.
*/
-#ifndef MPD_DB_LOCK_H
-#define MPD_DB_LOCK_H
+#ifndef MPD_DB_LOCK_HXX
+#define MPD_DB_LOCK_HXX
#include "check.h"
#include <glib.h>
#include <assert.h>
-#include <stdbool.h>
extern GStaticMutex db_mutex;
@@ -81,4 +80,19 @@ db_unlock(void)
g_static_mutex_unlock(&db_mutex);
}
+#ifdef __cplusplus
+
+class ScopeDatabaseLock {
+public:
+ ScopeDatabaseLock() {
+ db_lock();
+ }
+
+ ~ScopeDatabaseLock() {
+ db_unlock();
+ }
+};
+
+#endif
+
#endif
diff --git a/src/db_save.h b/src/DatabasePlaylist.hxx
index e760ec881..7c6952ffa 100644
--- a/src/db_save.h
+++ b/src/DatabasePlaylist.hxx
@@ -17,19 +17,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_DB_SAVE_H
-#define MPD_DB_SAVE_H
+#ifndef MPD_DATABASE_PLAYLIST_HXX
+#define MPD_DATABASE_PLAYLIST_HXX
-#include <glib.h>
-#include <stdbool.h>
-#include <stdio.h>
+#include "gcc.h"
+#include "gerror.h"
-struct directory;
-
-void
-db_save_internal(FILE *file, const struct directory *root);
+class SongFilter;
+gcc_nonnull(1,2)
bool
-db_load_internal(FILE *file, struct directory *root, GError **error);
+search_add_to_playlist(const char *uri, const char *path_utf8,
+ const SongFilter *filter,
+ GError **error_r);
#endif
diff --git a/src/db_print.h b/src/DatabasePrint.hxx
index 1b957da18..68551b63c 100644
--- a/src/db_print.h
+++ b/src/DatabasePrint.hxx
@@ -21,51 +21,37 @@
#define MPD_DB_PRINT_H
#include "gcc.h"
+#include "gerror.h"
-#include <glib.h>
-#include <stdbool.h>
-
-struct client;
-struct locate_item_list;
-struct db_selection;
+class SongFilter;
+struct DatabaseSelection;
struct db_visitor;
+class Client;
-gcc_nonnull(1,2)
+gcc_nonnull(1)
bool
-db_selection_print(struct client *client, const struct db_selection *selection,
+db_selection_print(Client *client, const DatabaseSelection &selection,
bool full, GError **error_r);
gcc_nonnull(1,2)
bool
-printAllIn(struct client *client, const char *uri_utf8, GError **error_r);
+printAllIn(Client *client, const char *uri_utf8, GError **error_r);
gcc_nonnull(1,2)
bool
-printInfoForAllIn(struct client *client, const char *uri_utf8,
+printInfoForAllIn(Client *client, const char *uri_utf8,
GError **error_r);
-gcc_nonnull(1,2,3)
-bool
-searchForSongsIn(struct client *client, const char *name,
- const struct locate_item_list *criteria,
- GError **error_r);
-
-gcc_nonnull(1,2,3)
-bool
-findSongsIn(struct client *client, const char *name,
- const struct locate_item_list *criteria,
- GError **error_r);
-
-gcc_nonnull(1,2,3)
+gcc_nonnull(1,2)
bool
-searchStatsForSongsIn(struct client *client, const char *name,
- const struct locate_item_list *criteria,
+searchStatsForSongsIn(Client *client, const char *name,
+ const SongFilter *filter,
GError **error_r);
-gcc_nonnull(1,3)
+gcc_nonnull(1)
bool
-listAllUniqueTags(struct client *client, int type,
- const struct locate_item_list *criteria,
+listAllUniqueTags(Client *client, int type,
+ const SongFilter *filter,
GError **error_r);
#endif
diff --git a/src/db_save.c b/src/DatabaseSave.cxx
index 4af9d58b8..78a2c4939 100644
--- a/src/db_save.c
+++ b/src/DatabaseSave.cxx
@@ -18,15 +18,18 @@
*/
#include "config.h"
-#include "db_save.h"
-#include "db_lock.h"
-#include "directory.h"
-#include "directory_save.h"
+#include "DatabaseSave.hxx"
+#include "DatabaseLock.hxx"
+#include "Directory.hxx"
+#include "DirectorySave.hxx"
#include "song.h"
+#include "TextFile.hxx"
+
+extern "C" {
#include "path.h"
-#include "text_file.h"
#include "tag.h"
#include "tag_internal.h"
+}
#include <glib.h>
@@ -55,7 +58,7 @@ db_quark(void)
}
void
-db_save_internal(FILE *fp, const struct directory *music_root)
+db_save_internal(FILE *fp, const Directory *music_root)
{
assert(music_root != NULL);
@@ -74,9 +77,8 @@ db_save_internal(FILE *fp, const struct directory *music_root)
}
bool
-db_load_internal(FILE *fp, struct directory *music_root, GError **error)
+db_load_internal(TextFile &file, Directory *music_root, GError **error)
{
- GString *buffer = g_string_sized_new(1024);
char *line;
int format = 0;
bool found_charset = false, found_version = false;
@@ -86,16 +88,15 @@ db_load_internal(FILE *fp, struct directory *music_root, GError **error)
assert(music_root != NULL);
/* get initial info */
- line = read_text_line(fp, buffer);
+ line = file.ReadLine();
if (line == NULL || strcmp(DIRECTORY_INFO_BEGIN, line) != 0) {
g_set_error(error, db_quark(), 0, "Database corrupted");
- g_string_free(buffer, true);
return false;
}
memset(tags, false, sizeof(tags));
- while ((line = read_text_line(fp, buffer)) != NULL &&
+ while ((line = file.ReadLine()) != NULL &&
strcmp(line, DIRECTORY_INFO_END) != 0) {
if (g_str_has_prefix(line, DB_FORMAT_PREFIX)) {
format = atoi(line + sizeof(DB_FORMAT_PREFIX) - 1);
@@ -103,7 +104,6 @@ db_load_internal(FILE *fp, struct directory *music_root, GError **error)
if (found_version) {
g_set_error(error, db_quark(), 0,
"Duplicate version line");
- g_string_free(buffer, true);
return false;
}
@@ -114,7 +114,6 @@ db_load_internal(FILE *fp, struct directory *music_root, GError **error)
if (found_charset) {
g_set_error(error, db_quark(), 0,
"Duplicate charset line");
- g_string_free(buffer, true);
return false;
}
@@ -129,7 +128,6 @@ db_load_internal(FILE *fp, struct directory *music_root, GError **error)
"\"%s\" instead of \"%s\"; "
"discarding database file",
new_charset, old_charset);
- g_string_free(buffer, true);
return false;
}
} else if (g_str_has_prefix(line, DB_TAG_PREFIX)) {
@@ -147,7 +145,6 @@ db_load_internal(FILE *fp, struct directory *music_root, GError **error)
} else {
g_set_error(error, db_quark(), 0,
"Malformed line: %s", line);
- g_string_free(buffer, true);
return false;
}
}
@@ -171,9 +168,8 @@ db_load_internal(FILE *fp, struct directory *music_root, GError **error)
g_debug("reading DB");
db_lock();
- success = directory_load(fp, music_root, buffer, error);
+ success = directory_load(file, music_root, error);
db_unlock();
- g_string_free(buffer, true);
return success;
}
diff --git a/src/db_selection.h b/src/DatabaseSelection.hxx
index 2cebb4907..3a81c01ec 100644
--- a/src/db_selection.h
+++ b/src/DatabaseSelection.hxx
@@ -17,17 +17,18 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_DB_SELECTION_H
-#define MPD_DB_SELECTION_H
+#ifndef MPD_DATABASE_SELECTION_HXX
+#define MPD_DATABASE_SELECTION_HXX
#include "gcc.h"
#include <assert.h>
+#include <stddef.h>
-struct directory;
+class SongFilter;
struct song;
-struct db_selection {
+struct DatabaseSelection {
/**
* The base URI of the search (UTF-8). Must not begin or end
* with a slash. NULL or an empty string searches the whole
@@ -39,18 +40,17 @@ struct db_selection {
* Recursively search all sub directories?
*/
bool recursive;
-};
-gcc_nonnull(1,2)
-static inline void
-db_selection_init(struct db_selection *selection,
- const char *uri, bool recursive)
-{
- assert(selection != NULL);
- assert(uri != NULL);
-
- selection->uri = uri;
- selection->recursive = recursive;
-}
+ const SongFilter *filter;
+
+ DatabaseSelection(const char *_uri, bool _recursive,
+ const SongFilter *_filter=nullptr)
+ :uri(_uri), recursive(_recursive), filter(_filter) {
+ assert(uri != NULL);
+ }
+
+ gcc_pure
+ bool Match(const song &song) const;
+};
#endif
diff --git a/src/db/ProxyDatabasePlugin.cxx b/src/db/ProxyDatabasePlugin.cxx
new file mode 100644
index 000000000..e41ee8819
--- /dev/null
+++ b/src/db/ProxyDatabasePlugin.cxx
@@ -0,0 +1,476 @@
+/*
+ * Copyright (C) 2003-2012 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "ProxyDatabasePlugin.hxx"
+#include "DatabasePlugin.hxx"
+#include "DatabaseSelection.hxx"
+#include "PlaylistVector.hxx"
+#include "Directory.hxx"
+#include "gcc.h"
+
+extern "C" {
+#include "db_error.h"
+#include "conf.h"
+#include "song.h"
+#include "tag.h"
+}
+
+#undef MPD_DIRECTORY_H
+#undef MPD_SONG_H
+#include <mpd/client.h>
+
+#include <cassert>
+#include <string>
+#include <list>
+
+class ProxyDatabase : public Database {
+ std::string host;
+ unsigned port;
+
+ struct mpd_connection *connection;
+ Directory *root;
+
+public:
+ static Database *Create(const struct config_param *param,
+ GError **error_r);
+
+ virtual bool Open(GError **error_r) override;
+ virtual void Close() override;
+ virtual struct song *GetSong(const char *uri_utf8,
+ GError **error_r) const override;
+ virtual void ReturnSong(struct song *song) const;
+
+ virtual bool Visit(const DatabaseSelection &selection,
+ VisitDirectory visit_directory,
+ VisitSong visit_song,
+ VisitPlaylist visit_playlist,
+ GError **error_r) const override;
+
+ virtual bool VisitUniqueTags(const DatabaseSelection &selection,
+ enum tag_type tag_type,
+ VisitString visit_string,
+ GError **error_r) const override;
+
+ virtual bool GetStats(const DatabaseSelection &selection,
+ DatabaseStats &stats,
+ GError **error_r) const override;
+
+protected:
+ bool Configure(const struct config_param *param, GError **error_r);
+};
+
+G_GNUC_CONST
+static inline GQuark
+libmpdclient_quark(void)
+{
+ return g_quark_from_static_string("libmpdclient");
+}
+
+static constexpr struct {
+ enum tag_type d;
+ enum mpd_tag_type s;
+} tag_table[] = {
+ { TAG_ARTIST, MPD_TAG_ARTIST },
+ { TAG_ALBUM, MPD_TAG_ALBUM },
+ { TAG_ALBUM_ARTIST, MPD_TAG_ALBUM_ARTIST },
+ { TAG_TITLE, MPD_TAG_TITLE },
+ { TAG_TRACK, MPD_TAG_TRACK },
+ { TAG_NAME, MPD_TAG_NAME },
+ { TAG_GENRE, MPD_TAG_GENRE },
+ { TAG_DATE, MPD_TAG_DATE },
+ { TAG_COMPOSER, MPD_TAG_COMPOSER },
+ { TAG_PERFORMER, MPD_TAG_PERFORMER },
+ { TAG_COMMENT, MPD_TAG_COMMENT },
+ { TAG_DISC, MPD_TAG_DISC },
+ { TAG_MUSICBRAINZ_ARTISTID, MPD_TAG_MUSICBRAINZ_ARTISTID },
+ { TAG_MUSICBRAINZ_ALBUMID, MPD_TAG_MUSICBRAINZ_ALBUMID },
+ { TAG_MUSICBRAINZ_ALBUMARTISTID,
+ MPD_TAG_MUSICBRAINZ_ALBUMARTISTID },
+ { TAG_MUSICBRAINZ_TRACKID, MPD_TAG_MUSICBRAINZ_TRACKID },
+ { TAG_NUM_OF_ITEM_TYPES, MPD_TAG_COUNT }
+};
+
+G_GNUC_CONST
+static enum mpd_tag_type
+Convert(enum tag_type tag_type)
+{
+ for (auto i = tag_table; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
+ if (i->d == tag_type)
+ return i->s;
+
+ return MPD_TAG_COUNT;
+}
+
+static bool
+CheckError(struct mpd_connection *connection, GError **error_r)
+{
+ const auto error = mpd_connection_get_error(connection);
+ if (error == MPD_ERROR_SUCCESS)
+ return true;
+
+ g_set_error_literal(error_r, libmpdclient_quark(), (int)error,
+ mpd_connection_get_error_message(connection));
+ mpd_connection_clear_error(connection);
+ return false;
+}
+
+Database *
+ProxyDatabase::Create(const struct config_param *param, GError **error_r)
+{
+ ProxyDatabase *db = new ProxyDatabase();
+ if (!db->Configure(param, error_r)) {
+ delete db;
+ db = NULL;
+ }
+
+ return db;
+}
+
+bool
+ProxyDatabase::Configure(const struct config_param *param, GError **)
+{
+ host = config_get_block_string(param, "host", "");
+ port = config_get_block_unsigned(param, "port", 0);
+
+ return true;
+}
+
+bool
+ProxyDatabase::Open(GError **error_r)
+{
+ connection = mpd_connection_new(host.empty() ? NULL : host.c_str(),
+ port, 0);
+ if (connection == NULL) {
+ g_set_error_literal(error_r, libmpdclient_quark(),
+ (int)MPD_ERROR_OOM, "Out of memory");
+ return false;
+ }
+
+ if (!CheckError(connection, error_r)) {
+ mpd_connection_free(connection);
+ return false;
+ }
+
+ root = Directory::NewRoot();
+
+ return true;
+}
+
+void
+ProxyDatabase::Close()
+{
+ assert(connection != nullptr);
+
+ root->Free();
+ mpd_connection_free(connection);
+}
+
+static song *
+Convert(const struct mpd_song *song);
+
+struct song *
+ProxyDatabase::GetSong(const char *uri, GError **error_r) const
+{
+ // TODO: implement
+ // TODO: auto-reconnect
+
+ if (!mpd_send_list_meta(connection, uri)) {
+ CheckError(connection, error_r);
+ return nullptr;
+ }
+
+ struct mpd_song *song = mpd_recv_song(connection);
+ struct song *song2 = song != nullptr
+ ? Convert(song)
+ : nullptr;
+ mpd_song_free(song);
+ if (!mpd_response_finish(connection)) {
+ if (song2 != nullptr)
+ song_free(song2);
+
+ CheckError(connection, error_r);
+ return nullptr;
+ }
+
+ if (song2 == nullptr)
+ g_set_error(error_r, db_quark(), DB_NOT_FOUND,
+ "No such song: %s", uri);
+
+ return song2;
+}
+
+void
+ProxyDatabase::ReturnSong(struct song *song) const
+{
+ assert(song != nullptr);
+ assert(song_in_database(song));
+ assert(song_is_detached(song));
+
+ song_free(song);
+}
+
+static bool
+Visit(struct mpd_connection *connection, const char *uri,
+ bool recursive, VisitDirectory visit_directory, VisitSong visit_song,
+ VisitPlaylist visit_playlist, GError **error_r);
+
+static bool
+Visit(struct mpd_connection *connection,
+ bool recursive, const struct mpd_directory *directory,
+ VisitDirectory visit_directory, VisitSong visit_song,
+ VisitPlaylist visit_playlist, GError **error_r)
+{
+ const char *path = mpd_directory_get_path(directory);
+
+ if (visit_directory) {
+ Directory *d = Directory::NewGeneric(path, &detached_root);
+ bool success = visit_directory(*d, error_r);
+ d->Free();
+ if (!success)
+ return false;
+ }
+
+ if (recursive &&
+ !Visit(connection, path, recursive,
+ visit_directory, visit_song, visit_playlist, error_r))
+ return false;
+
+ return true;
+}
+
+static void
+Copy(struct tag *tag, enum tag_type d_tag,
+ const struct mpd_song *song, enum mpd_tag_type s_tag)
+{
+
+ for (unsigned i = 0;; ++i) {
+ const char *value = mpd_song_get_tag(song, s_tag, i);
+ if (value == NULL)
+ break;
+
+ tag_add_item(tag, d_tag, value);
+ }
+}
+
+static song *
+Convert(const struct mpd_song *song)
+{
+ struct song *s = song_detached_new(mpd_song_get_uri(song));
+
+ s->mtime = mpd_song_get_last_modified(song);
+ s->start_ms = mpd_song_get_start(song) * 1000;
+ s->end_ms = mpd_song_get_end(song) * 1000;
+
+ struct tag *tag = tag_new();
+ tag->time = mpd_song_get_duration(song);
+
+ tag_begin_add(tag);
+ for (auto i = tag_table; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
+ Copy(tag, i->d, song, i->s);
+ tag_end_add(tag);
+
+ s->tag = tag;
+
+ return s;
+}
+
+static bool
+Visit(const struct mpd_song *song,
+ VisitSong visit_song, GError **error_r)
+{
+ if (!visit_song)
+ return true;
+
+ struct song *s = Convert(song);
+ bool success = visit_song(*s, error_r);
+ song_free(s);
+
+ return success;
+}
+
+static bool
+Visit(const struct mpd_playlist *playlist,
+ VisitPlaylist visit_playlist, GError **error_r)
+{
+ if (!visit_playlist)
+ return true;
+
+ PlaylistInfo p(mpd_playlist_get_path(playlist),
+ mpd_playlist_get_last_modified(playlist));
+
+ return visit_playlist(p, detached_root, error_r);
+}
+
+class ProxyEntity {
+ struct mpd_entity *entity;
+
+public:
+ explicit ProxyEntity(struct mpd_entity *_entity)
+ :entity(_entity) {}
+
+ ProxyEntity(const ProxyEntity &other) = delete;
+
+ ProxyEntity(ProxyEntity &&other)
+ :entity(other.entity) {
+ other.entity = nullptr;
+ }
+
+ ~ProxyEntity() {
+ if (entity != nullptr)
+ mpd_entity_free(entity);
+ }
+
+ ProxyEntity &operator=(const ProxyEntity &other) = delete;
+
+ operator const struct mpd_entity *() const {
+ return entity;
+ }
+};
+
+static std::list<ProxyEntity>
+ReceiveEntities(struct mpd_connection *connection)
+{
+ std::list<ProxyEntity> entities;
+ struct mpd_entity *entity;
+ while ((entity = mpd_recv_entity(connection)) != NULL)
+ entities.push_back(ProxyEntity(entity));
+
+ mpd_response_finish(connection);
+ return entities;
+}
+
+static bool
+Visit(struct mpd_connection *connection, const char *uri,
+ bool recursive, VisitDirectory visit_directory, VisitSong visit_song,
+ VisitPlaylist visit_playlist, GError **error_r)
+{
+ if (!mpd_send_list_meta(connection, uri))
+ return CheckError(connection, error_r);
+
+ std::list<ProxyEntity> entities(ReceiveEntities(connection));
+ if (!CheckError(connection, error_r))
+ return false;
+
+ for (const auto &entity : entities) {
+ switch (mpd_entity_get_type(entity)) {
+ case MPD_ENTITY_TYPE_UNKNOWN:
+ break;
+
+ case MPD_ENTITY_TYPE_DIRECTORY:
+ if (!Visit(connection, recursive,
+ mpd_entity_get_directory(entity),
+ visit_directory, visit_song, visit_playlist,
+ error_r))
+ return false;
+ break;
+
+ case MPD_ENTITY_TYPE_SONG:
+ if (!Visit(mpd_entity_get_song(entity), visit_song,
+ error_r))
+ return false;
+ break;
+
+ case MPD_ENTITY_TYPE_PLAYLIST:
+ if (!Visit(mpd_entity_get_playlist(entity),
+ visit_playlist, error_r))
+ return false;
+ break;
+ }
+ }
+
+ return CheckError(connection, error_r);
+}
+
+bool
+ProxyDatabase::Visit(const DatabaseSelection &selection,
+ VisitDirectory visit_directory,
+ VisitSong visit_song,
+ VisitPlaylist visit_playlist,
+ GError **error_r) const
+{
+ // TODO: match
+ // TODO: auto-reconnect
+
+ return ::Visit(connection, selection.uri, selection.recursive,
+ visit_directory, visit_song, visit_playlist,
+ error_r);
+}
+
+bool
+ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
+ enum tag_type tag_type,
+ VisitString visit_string,
+ GError **error_r) const
+{
+ enum mpd_tag_type tag_type2 = Convert(tag_type);
+ if (tag_type2 == MPD_TAG_COUNT) {
+ g_set_error_literal(error_r, libmpdclient_quark(), 0,
+ "Unsupported tag");
+ return false;
+ }
+
+ if (!mpd_search_db_tags(connection, tag_type2))
+ return CheckError(connection, error_r);
+
+ // TODO: match
+ (void)selection;
+
+ if (!mpd_search_commit(connection))
+ return CheckError(connection, error_r);
+
+ bool result = true;
+
+ struct mpd_pair *pair;
+ while (result &&
+ (pair = mpd_recv_pair_tag(connection, tag_type2)) != nullptr) {
+ result = visit_string(pair->value, error_r);
+ mpd_return_pair(connection, pair);
+ }
+
+ return mpd_response_finish(connection) &&
+ CheckError(connection, error_r) &&
+ result;
+}
+
+bool
+ProxyDatabase::GetStats(const DatabaseSelection &selection,
+ DatabaseStats &stats, GError **error_r) const
+{
+ // TODO: match
+ (void)selection;
+
+ struct mpd_stats *stats2 =
+ mpd_run_stats(connection);
+ if (stats2 == nullptr)
+ return CheckError(connection, error_r);
+
+ stats.song_count = mpd_stats_get_number_of_songs(stats2);
+ stats.total_duration = mpd_stats_get_db_play_time(stats2);
+ stats.artist_count = mpd_stats_get_number_of_artists(stats2);
+ stats.album_count = mpd_stats_get_number_of_albums(stats2);
+ mpd_stats_free(stats2);
+
+ return true;
+}
+
+const DatabasePlugin proxy_db_plugin = {
+ "proxy",
+ ProxyDatabase::Create,
+};
diff --git a/src/db/ProxyDatabasePlugin.hxx b/src/db/ProxyDatabasePlugin.hxx
new file mode 100644
index 000000000..8e878baca
--- /dev/null
+++ b/src/db/ProxyDatabasePlugin.hxx
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2003-2012 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PROXY_DATABASE_PLUGIN_HXX
+#define MPD_PROXY_DATABASE_PLUGIN_HXX
+
+struct DatabasePlugin;
+
+extern const DatabasePlugin proxy_db_plugin;
+
+#endif
diff --git a/src/db/SimpleDatabasePlugin.cxx b/src/db/SimpleDatabasePlugin.cxx
new file mode 100644
index 000000000..84e4e7cee
--- /dev/null
+++ b/src/db/SimpleDatabasePlugin.cxx
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "SimpleDatabasePlugin.hxx"
+#include "DatabaseSelection.hxx"
+#include "DatabaseHelpers.hxx"
+#include "Directory.hxx"
+#include "SongFilter.hxx"
+#include "DatabaseSave.hxx"
+#include "DatabaseLock.hxx"
+#include "db_error.h"
+#include "TextFile.hxx"
+
+extern "C" {
+#include "conf.h"
+}
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+G_GNUC_CONST
+static inline GQuark
+simple_db_quark(void)
+{
+ return g_quark_from_static_string("simple_db");
+}
+
+Database *
+SimpleDatabase::Create(const struct config_param *param, GError **error_r)
+{
+ SimpleDatabase *db = new SimpleDatabase();
+ if (!db->Configure(param, error_r)) {
+ delete db;
+ db = NULL;
+ }
+
+ return db;
+}
+
+bool
+SimpleDatabase::Configure(const struct config_param *param, GError **error_r)
+{
+ GError *error = NULL;
+
+ char *_path = config_dup_block_path(param, "path", &error);
+ if (_path == NULL) {
+ if (error != NULL)
+ g_propagate_error(error_r, error);
+ else
+ g_set_error(error_r, simple_db_quark(), 0,
+ "No \"path\" parameter specified");
+ return false;
+ }
+
+ path = _path;
+ free(_path);
+
+ return true;
+}
+
+bool
+SimpleDatabase::Check(GError **error_r) const
+{
+ assert(!path.empty());
+
+ /* Check if the file exists */
+ if (access(path.c_str(), F_OK)) {
+ /* If the file doesn't exist, we can't check if we can write
+ * it, so we are going to try to get the directory path, and
+ * see if we can write a file in that */
+ char *dirPath = g_path_get_dirname(path.c_str());
+
+ /* Check that the parent part of the path is a directory */
+ struct stat st;
+ if (stat(dirPath, &st) < 0) {
+ g_free(dirPath);
+ g_set_error(error_r, simple_db_quark(), errno,
+ "Couldn't stat parent directory of db file "
+ "\"%s\": %s",
+ path.c_str(), g_strerror(errno));
+ return false;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ g_free(dirPath);
+ g_set_error(error_r, simple_db_quark(), 0,
+ "Couldn't create db file \"%s\" because the "
+ "parent path is not a directory",
+ path.c_str());
+ return false;
+ }
+
+ /* Check if we can write to the directory */
+ if (access(dirPath, X_OK | W_OK)) {
+ g_set_error(error_r, simple_db_quark(), errno,
+ "Can't create db file in \"%s\": %s",
+ dirPath, g_strerror(errno));
+ g_free(dirPath);
+ return false;
+ }
+
+ g_free(dirPath);
+
+ return true;
+ }
+
+ /* Path exists, now check if it's a regular file */
+ struct stat st;
+ if (stat(path.c_str(), &st) < 0) {
+ g_set_error(error_r, simple_db_quark(), errno,
+ "Couldn't stat db file \"%s\": %s",
+ path.c_str(), g_strerror(errno));
+ return false;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ g_set_error(error_r, simple_db_quark(), 0,
+ "db file \"%s\" is not a regular file",
+ path.c_str());
+ return false;
+ }
+
+ /* And check that we can write to it */
+ if (access(path.c_str(), R_OK | W_OK)) {
+ g_set_error(error_r, simple_db_quark(), errno,
+ "Can't open db file \"%s\" for reading/writing: %s",
+ path.c_str(), g_strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+bool
+SimpleDatabase::Load(GError **error_r)
+{
+ assert(!path.empty());
+ assert(root != NULL);
+
+ TextFile file(path.c_str());
+ if (file.HasFailed()) {
+ g_set_error(error_r, simple_db_quark(), errno,
+ "Failed to open database file \"%s\": %s",
+ path.c_str(), g_strerror(errno));
+ return false;
+ }
+
+ if (!db_load_internal(file, root, error_r))
+ return false;
+
+ struct stat st;
+ if (stat(path.c_str(), &st) == 0)
+ mtime = st.st_mtime;
+
+ return true;
+}
+
+bool
+SimpleDatabase::Open(GError **error_r)
+{
+ root = Directory::NewRoot();
+ mtime = 0;
+
+#ifndef NDEBUG
+ borrowed_song_count = 0;
+#endif
+
+ GError *error = NULL;
+ if (!Load(&error)) {
+ root->Free();
+
+ g_warning("Failed to load database: %s", error->message);
+ g_error_free(error);
+
+ if (!Check(error_r))
+ return false;
+
+ root = Directory::NewRoot();
+ }
+
+ return true;
+}
+
+void
+SimpleDatabase::Close()
+{
+ assert(root != NULL);
+ assert(borrowed_song_count == 0);
+
+ root->Free();
+}
+
+struct song *
+SimpleDatabase::GetSong(const char *uri, GError **error_r) const
+{
+ assert(root != NULL);
+
+ db_lock();
+ song *song = root->LookupSong(uri);
+ db_unlock();
+ if (song == NULL)
+ g_set_error(error_r, db_quark(), DB_NOT_FOUND,
+ "No such song: %s", uri);
+#ifndef NDEBUG
+ else
+ ++const_cast<unsigned &>(borrowed_song_count);
+#endif
+
+ return song;
+}
+
+void
+SimpleDatabase::ReturnSong(gcc_unused struct song *song) const
+{
+ assert(song != nullptr);
+
+#ifndef NDEBUG
+ assert(borrowed_song_count > 0);
+ --const_cast<unsigned &>(borrowed_song_count);
+#endif
+}
+
+G_GNUC_PURE
+const Directory *
+SimpleDatabase::LookupDirectory(const char *uri) const
+{
+ assert(root != NULL);
+ assert(uri != NULL);
+
+ ScopeDatabaseLock protect;
+ return root->LookupDirectory(uri);
+}
+
+bool
+SimpleDatabase::Visit(const DatabaseSelection &selection,
+ VisitDirectory visit_directory,
+ VisitSong visit_song,
+ VisitPlaylist visit_playlist,
+ GError **error_r) const
+{
+ ScopeDatabaseLock protect;
+
+ const Directory *directory = root->LookupDirectory(selection.uri);
+ if (directory == NULL) {
+ if (visit_song) {
+ song *song = root->LookupSong(selection.uri);
+ if (song != nullptr)
+ return !selection.Match(*song) ||
+ visit_song(*song, error_r);
+ }
+
+ g_set_error(error_r, db_quark(), DB_NOT_FOUND,
+ "No such directory");
+ return false;
+ }
+
+ if (selection.recursive && visit_directory &&
+ !visit_directory(*directory, error_r))
+ return false;
+
+ return directory->Walk(selection.recursive, selection.filter,
+ visit_directory, visit_song, visit_playlist,
+ error_r);
+}
+
+bool
+SimpleDatabase::VisitUniqueTags(const DatabaseSelection &selection,
+ enum tag_type tag_type,
+ VisitString visit_string,
+ GError **error_r) const
+{
+ return ::VisitUniqueTags(*this, selection, tag_type, visit_string,
+ error_r);
+}
+
+bool
+SimpleDatabase::GetStats(const DatabaseSelection &selection,
+ DatabaseStats &stats, GError **error_r) const
+{
+ return ::GetStats(*this, selection, stats, error_r);
+}
+
+bool
+SimpleDatabase::Save(GError **error_r)
+{
+ db_lock();
+
+ g_debug("removing empty directories from DB");
+ root->PruneEmpty();
+
+ g_debug("sorting DB");
+ root->Sort();
+
+ db_unlock();
+
+ g_debug("writing DB");
+
+ FILE *fp = fopen(path.c_str(), "w");
+ if (!fp) {
+ g_set_error(error_r, simple_db_quark(), errno,
+ "unable to write to db file \"%s\": %s",
+ path.c_str(), g_strerror(errno));
+ return false;
+ }
+
+ db_save_internal(fp, root);
+
+ if (ferror(fp)) {
+ g_set_error(error_r, simple_db_quark(), errno,
+ "Failed to write to database file: %s",
+ g_strerror(errno));
+ fclose(fp);
+ return false;
+ }
+
+ fclose(fp);
+
+ struct stat st;
+ if (stat(path.c_str(), &st) == 0)
+ mtime = st.st_mtime;
+
+ return true;
+}
+
+const DatabasePlugin simple_db_plugin = {
+ "simple",
+ SimpleDatabase::Create,
+};
diff --git a/src/db/SimpleDatabasePlugin.hxx b/src/db/SimpleDatabasePlugin.hxx
new file mode 100644
index 000000000..789dcdae9
--- /dev/null
+++ b/src/db/SimpleDatabasePlugin.hxx
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_SIMPLE_DATABASE_PLUGIN_HXX
+#define MPD_SIMPLE_DATABASE_PLUGIN_HXX
+
+#include "DatabasePlugin.hxx"
+#include "gcc.h"
+
+#include <cassert>
+#include <string>
+
+#include <time.h>
+
+struct Directory;
+
+class SimpleDatabase : public Database {
+ std::string path;
+
+ Directory *root;
+
+ time_t mtime;
+
+#ifndef NDEBUG
+ unsigned borrowed_song_count;
+#endif
+
+public:
+ gcc_pure
+ Directory *GetRoot() {
+ assert(root != NULL);
+
+ return root;
+ }
+
+ bool Save(GError **error_r);
+
+ gcc_pure
+ time_t GetLastModified() const {
+ return mtime;
+ }
+
+ static Database *Create(const struct config_param *param,
+ GError **error_r);
+
+ virtual bool Open(GError **error_r) override;
+ virtual void Close() override;
+
+ virtual struct song *GetSong(const char *uri_utf8,
+ GError **error_r) const override;
+ virtual void ReturnSong(struct song *song) const;
+
+ virtual bool Visit(const DatabaseSelection &selection,
+ VisitDirectory visit_directory,
+ VisitSong visit_song,
+ VisitPlaylist visit_playlist,
+ GError **error_r) const override;
+
+ virtual bool VisitUniqueTags(const DatabaseSelection &selection,
+ enum tag_type tag_type,
+ VisitString visit_string,
+ GError **error_r) const override;
+
+ virtual bool GetStats(const DatabaseSelection &selection,
+ DatabaseStats &stats,
+ GError **error_r) const override;
+
+protected:
+ bool Configure(const struct config_param *param, GError **error_r);
+
+ gcc_pure
+ bool Check(GError **error_r) const;
+
+ bool Load(GError **error_r);
+
+ gcc_pure
+ const Directory *LookupDirectory(const char *uri) const;
+};
+
+extern const DatabasePlugin simple_db_plugin;
+
+#endif
diff --git a/src/db/simple_db_plugin.c b/src/db/simple_db_plugin.c
deleted file mode 100644
index 697e8da5f..000000000
--- a/src/db/simple_db_plugin.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "simple_db_plugin.h"
-#include "db_internal.h"
-#include "db_error.h"
-#include "db_selection.h"
-#include "db_visitor.h"
-#include "db_save.h"
-#include "db_lock.h"
-#include "conf.h"
-#include "directory.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-
-struct simple_db {
- struct db base;
-
- char *path;
-
- struct directory *root;
-
- time_t mtime;
-};
-
-G_GNUC_CONST
-static inline GQuark
-simple_db_quark(void)
-{
- return g_quark_from_static_string("simple_db");
-}
-
-G_GNUC_PURE
-static const struct directory *
-simple_db_lookup_directory(const struct simple_db *db, const char *uri)
-{
- assert(db != NULL);
- assert(db->root != NULL);
- assert(uri != NULL);
-
- db_lock();
- struct directory *directory =
- directory_lookup_directory(db->root, uri);
- db_unlock();
- return directory;
-}
-
-static struct db *
-simple_db_init(const struct config_param *param, GError **error_r)
-{
- struct simple_db *db = g_malloc(sizeof(*db));
- db_base_init(&db->base, &simple_db_plugin);
-
- GError *error = NULL;
- db->path = config_dup_block_path(param, "path", &error);
- if (db->path == NULL) {
- g_free(db);
- if (error != NULL)
- g_propagate_error(error_r, error);
- else
- g_set_error(error_r, simple_db_quark(), 0,
- "No \"path\" parameter specified");
- return NULL;
- }
-
- return &db->base;
-}
-
-static void
-simple_db_finish(struct db *_db)
-{
- struct simple_db *db = (struct simple_db *)_db;
-
- g_free(db->path);
- g_free(db);
-}
-
-static bool
-simple_db_check(struct simple_db *db, GError **error_r)
-{
- assert(db != NULL);
- assert(db->path != NULL);
-
- /* Check if the file exists */
- if (access(db->path, F_OK)) {
- /* If the file doesn't exist, we can't check if we can write
- * it, so we are going to try to get the directory path, and
- * see if we can write a file in that */
- char *dirPath = g_path_get_dirname(db->path);
-
- /* Check that the parent part of the path is a directory */
- struct stat st;
- if (stat(dirPath, &st) < 0) {
- g_free(dirPath);
- g_set_error(error_r, simple_db_quark(), errno,
- "Couldn't stat parent directory of db file "
- "\"%s\": %s",
- db->path, g_strerror(errno));
- return false;
- }
-
- if (!S_ISDIR(st.st_mode)) {
- g_free(dirPath);
- g_set_error(error_r, simple_db_quark(), 0,
- "Couldn't create db file \"%s\" because the "
- "parent path is not a directory",
- db->path);
- return false;
- }
-
- /* Check if we can write to the directory */
- if (access(dirPath, X_OK | W_OK)) {
- g_set_error(error_r, simple_db_quark(), errno,
- "Can't create db file in \"%s\": %s",
- dirPath, g_strerror(errno));
- g_free(dirPath);
- return false;
- }
-
- g_free(dirPath);
-
- return true;
- }
-
- /* Path exists, now check if it's a regular file */
- struct stat st;
- if (stat(db->path, &st) < 0) {
- g_set_error(error_r, simple_db_quark(), errno,
- "Couldn't stat db file \"%s\": %s",
- db->path, g_strerror(errno));
- return false;
- }
-
- if (!S_ISREG(st.st_mode)) {
- g_set_error(error_r, simple_db_quark(), 0,
- "db file \"%s\" is not a regular file",
- db->path);
- return false;
- }
-
- /* And check that we can write to it */
- if (access(db->path, R_OK | W_OK)) {
- g_set_error(error_r, simple_db_quark(), errno,
- "Can't open db file \"%s\" for reading/writing: %s",
- db->path, g_strerror(errno));
- return false;
- }
-
- return true;
-}
-
-static bool
-simple_db_load(struct simple_db *db, GError **error_r)
-{
- assert(db != NULL);
- assert(db->path != NULL);
- assert(db->root != NULL);
-
- FILE *fp = fopen(db->path, "r");
- if (fp == NULL) {
- g_set_error(error_r, simple_db_quark(), errno,
- "Failed to open database file \"%s\": %s",
- db->path, g_strerror(errno));
- return false;
- }
-
- if (!db_load_internal(fp, db->root, error_r)) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
-
- struct stat st;
- if (stat(db->path, &st) == 0)
- db->mtime = st.st_mtime;
-
- return true;
-}
-
-static bool
-simple_db_open(struct db *_db, G_GNUC_UNUSED GError **error_r)
-{
- struct simple_db *db = (struct simple_db *)_db;
-
- db->root = directory_new_root();
- db->mtime = 0;
-
- GError *error = NULL;
- if (!simple_db_load(db, &error)) {
- directory_free(db->root);
-
- g_warning("Failed to load database: %s", error->message);
- g_error_free(error);
-
- if (!simple_db_check(db, error_r))
- return false;
-
- db->root = directory_new_root();
- }
-
- return true;
-}
-
-static void
-simple_db_close(struct db *_db)
-{
- struct simple_db *db = (struct simple_db *)_db;
-
- assert(db->root != NULL);
-
- directory_free(db->root);
-}
-
-static struct song *
-simple_db_get_song(struct db *_db, const char *uri, GError **error_r)
-{
- struct simple_db *db = (struct simple_db *)_db;
-
- assert(db->root != NULL);
-
- db_lock();
- struct song *song = directory_lookup_song(db->root, uri);
- db_unlock();
- if (song == NULL)
- g_set_error(error_r, db_quark(), DB_NOT_FOUND,
- "No such song: %s", uri);
-
- return song;
-}
-
-static bool
-simple_db_visit(struct db *_db, const struct db_selection *selection,
- const struct db_visitor *visitor, void *ctx,
- GError **error_r)
-{
- const struct simple_db *db = (const struct simple_db *)_db;
- const struct directory *directory =
- simple_db_lookup_directory(db, selection->uri);
- if (directory == NULL) {
- struct song *song;
- if (visitor->song != NULL &&
- (song = simple_db_get_song(_db, selection->uri, NULL)) != NULL)
- return visitor->song(song, ctx, error_r);
-
- g_set_error(error_r, db_quark(), DB_NOT_FOUND,
- "No such directory");
- return false;
- }
-
- if (selection->recursive && visitor->directory != NULL &&
- !visitor->directory(directory, ctx, error_r))
- return false;
-
- db_lock();
- bool ret = directory_walk(directory, selection->recursive,
- visitor, ctx, error_r);
- db_unlock();
- return ret;
-}
-
-const struct db_plugin simple_db_plugin = {
- .name = "simple",
- .init = simple_db_init,
- .finish = simple_db_finish,
- .open = simple_db_open,
- .close = simple_db_close,
- .get_song = simple_db_get_song,
- .visit = simple_db_visit,
-};
-
-struct directory *
-simple_db_get_root(struct db *_db)
-{
- struct simple_db *db = (struct simple_db *)_db;
-
- assert(db != NULL);
- assert(db->root != NULL);
-
- return db->root;
-}
-
-bool
-simple_db_save(struct db *_db, GError **error_r)
-{
- struct simple_db *db = (struct simple_db *)_db;
- struct directory *music_root = db->root;
-
- db_lock();
-
- g_debug("removing empty directories from DB");
- directory_prune_empty(music_root);
-
- g_debug("sorting DB");
- directory_sort(music_root);
-
- db_unlock();
-
- g_debug("writing DB");
-
- FILE *fp = fopen(db->path, "w");
- if (!fp) {
- g_set_error(error_r, simple_db_quark(), errno,
- "unable to write to db file \"%s\": %s",
- db->path, g_strerror(errno));
- return false;
- }
-
- db_save_internal(fp, music_root);
-
- if (ferror(fp)) {
- g_set_error(error_r, simple_db_quark(), errno,
- "Failed to write to database file: %s",
- g_strerror(errno));
- fclose(fp);
- return false;
- }
-
- fclose(fp);
-
- struct stat st;
- if (stat(db->path, &st) == 0)
- db->mtime = st.st_mtime;
-
- return true;
-}
-
-time_t
-simple_db_get_mtime(const struct db *_db)
-{
- const struct simple_db *db = (const struct simple_db *)_db;
-
- assert(db != NULL);
- assert(db->root != NULL);
-
- return db->mtime;
-}
diff --git a/src/dbUtils.c b/src/dbUtils.c
deleted file mode 100644
index c212d9f9c..000000000
--- a/src/dbUtils.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "dbUtils.h"
-#include "locate.h"
-#include "database.h"
-#include "db_visitor.h"
-#include "playlist.h"
-#include "stored_playlist.h"
-
-#include <glib.h>
-
-static bool
-add_to_queue_song(struct song *song, void *ctx, GError **error_r)
-{
- struct player_control *pc = ctx;
-
- enum playlist_result result =
- playlist_append_song(&g_playlist, pc, song, NULL);
- if (result != PLAYLIST_RESULT_SUCCESS) {
- g_set_error(error_r, playlist_quark(), result,
- "Playlist error");
- return false;
- }
-
- return true;
-}
-
-static const struct db_visitor add_to_queue_visitor = {
- .song = add_to_queue_song,
-};
-
-bool
-addAllIn(struct player_control *pc, const char *uri, GError **error_r)
-{
- return db_walk(uri, &add_to_queue_visitor, pc, error_r);
-}
-
-struct add_data {
- const char *path;
-};
-
-static bool
-add_to_spl_song(struct song *song, void *ctx, GError **error_r)
-{
- struct add_data *data = ctx;
-
- if (!spl_append_song(data->path, song, error_r))
- return false;
-
- return true;
-}
-
-static const struct db_visitor add_to_spl_visitor = {
- .song = add_to_spl_song,
-};
-
-bool
-addAllInToStoredPlaylist(const char *uri_utf8, const char *path_utf8,
- GError **error_r)
-{
- struct add_data data = {
- .path = path_utf8,
- };
-
- return db_walk(uri_utf8, &add_to_spl_visitor, &data, error_r);
-}
-
-struct find_add_data {
- struct player_control *pc;
- const struct locate_item_list *criteria;
-};
-
-static bool
-find_add_song(struct song *song, void *ctx, GError **error_r)
-{
- struct find_add_data *data = ctx;
-
- if (!locate_song_match(song, data->criteria))
- return true;
-
- enum playlist_result result =
- playlist_append_song(&g_playlist, data->pc,
- song, NULL);
- if (result != PLAYLIST_RESULT_SUCCESS) {
- g_set_error(error_r, playlist_quark(), result,
- "Playlist error");
- return false;
- }
-
- return true;
-}
-
-static const struct db_visitor find_add_visitor = {
- .song = find_add_song,
-};
-
-bool
-findAddIn(struct player_control *pc, const char *name,
- const struct locate_item_list *criteria, GError **error_r)
-{
- struct find_add_data data;
- data.pc = pc;
- data.criteria = criteria;
-
- return db_walk(name, &find_add_visitor, &data, error_r);
-}
-
-static bool
-searchadd_visitor_song(struct song *song, void *_data, GError **error_r)
-{
- struct find_add_data *data = _data;
-
- if (!locate_song_search(song, data->criteria))
- return true;
-
- enum playlist_result result =
- playlist_append_song(&g_playlist, data->pc, song, NULL);
- if (result != PLAYLIST_RESULT_SUCCESS) {
- g_set_error(error_r, playlist_quark(), result,
- "Playlist error");
- return false;
- }
-
- return true;
-}
-
-static const struct db_visitor searchadd_visitor = {
- .song = searchadd_visitor_song,
-};
-
-bool
-search_add_songs(struct player_control *pc, const char *uri,
- const struct locate_item_list *criteria,
- GError **error_r)
-{
- struct locate_item_list *new_list =
- locate_item_list_casefold(criteria);
- struct find_add_data data = {
- .pc = pc,
- .criteria = new_list,
- };
-
- bool success = db_walk(uri, &searchadd_visitor, &data, error_r);
-
- locate_item_list_free(new_list);
-
- return success;
-}
-
-struct search_add_playlist_data {
- const char *playlist;
- const struct locate_item_list *criteria;
-};
-
-static bool
-searchaddpl_visitor_song(struct song *song, void *_data,
- G_GNUC_UNUSED GError **error_r)
-{
- struct search_add_playlist_data *data = _data;
-
- if (!locate_song_search(song, data->criteria))
- return true;
-
- if (!spl_append_song(data->playlist, song, error_r))
- return false;
-
- return true;
-}
-
-static const struct db_visitor searchaddpl_visitor = {
- .song = searchaddpl_visitor_song,
-};
-
-bool
-search_add_to_playlist(const char *uri, const char *path_utf8,
- const struct locate_item_list *criteria,
- GError **error_r)
-{
- struct locate_item_list *new_list
- = locate_item_list_casefold(criteria);
- struct search_add_playlist_data data = {
- .playlist = path_utf8,
- .criteria = new_list,
- };
-
- bool success = db_walk(uri, &searchaddpl_visitor, &data, error_r);
-
- locate_item_list_free(new_list);
-
- return success;
-}
diff --git a/src/dbUtils.h b/src/dbUtils.h
deleted file mode 100644
index 706c807fd..000000000
--- a/src/dbUtils.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_DB_UTILS_H
-#define MPD_DB_UTILS_H
-
-#include "gcc.h"
-
-#include <glib.h>
-#include <stdbool.h>
-
-struct locate_item_list;
-struct player_control;
-
-gcc_nonnull(1,2)
-bool
-addAllIn(struct player_control *pc, const char *uri, GError **error_r);
-
-gcc_nonnull(1,2)
-bool
-addAllInToStoredPlaylist(const char *uri_utf8, const char *path_utf8,
- GError **error_r);
-
-gcc_nonnull(1,2,3)
-bool
-findAddIn(struct player_control *pc, const char *name,
- const struct locate_item_list *criteria, GError **error_r);
-
-gcc_nonnull(1,2,3)
-bool
-search_add_songs(struct player_control *pc, const char *uri,
- const struct locate_item_list *criteria, GError **error_r);
-
-gcc_nonnull(1,2,3)
-bool
-search_add_to_playlist(const char *uri, const char *path_utf8,
- const struct locate_item_list *criteria,
- GError **error_r);
-
-#endif
diff --git a/src/db_plugin.h b/src/db_plugin.h
deleted file mode 100644
index 1c7e14ede..000000000
--- a/src/db_plugin.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/** \file
- *
- * This header declares the db_plugin class. It describes a
- * plugin API for databases of song metadata.
- */
-
-#ifndef MPD_DB_PLUGIN_H
-#define MPD_DB_PLUGIN_H
-
-#include <glib.h>
-#include <assert.h>
-#include <stdbool.h>
-
-struct config_param;
-struct db_selection;
-struct db_visitor;
-
-struct db {
- const struct db_plugin *plugin;
-};
-
-struct db_plugin {
- const char *name;
-
- /**
- * Allocates and configures a database.
- */
- struct db *(*init)(const struct config_param *param, GError **error_r);
-
- /**
- * Free instance data.
- */
- void (*finish)(struct db *db);
-
- /**
- * Open the database. Read it into memory if applicable.
- */
- bool (*open)(struct db *db, GError **error_r);
-
- /**
- * Close the database, free allocated memory.
- */
- void (*close)(struct db *db);
-
- /**
- * Look up a song (including tag data) in the database.
- *
- * @param the URI of the song within the music directory
- * (UTF-8)
- */
- struct song *(*get_song)(struct db *db, const char *uri,
- GError **error_r);
-
- /**
- * Visit the selected entities.
- */
- bool (*visit)(struct db *db, const struct db_selection *selection,
- const struct db_visitor *visitor, void *ctx,
- GError **error_r);
-};
-
-G_GNUC_MALLOC
-static inline struct db *
-db_plugin_new(const struct db_plugin *plugin, const struct config_param *param,
- GError **error_r)
-{
- assert(plugin != NULL);
- assert(plugin->init != NULL);
- assert(plugin->finish != NULL);
- assert(plugin->get_song != NULL);
- assert(plugin->visit != NULL);
- assert(error_r == NULL || *error_r == NULL);
-
- struct db *db = plugin->init(param, error_r);
- assert(db == NULL || db->plugin == plugin);
- assert(db != NULL || error_r == NULL || *error_r != NULL);
-
- return db;
-}
-
-static inline void
-db_plugin_free(struct db *db)
-{
- assert(db != NULL);
- assert(db->plugin != NULL);
- assert(db->plugin->finish != NULL);
-
- db->plugin->finish(db);
-}
-
-static inline bool
-db_plugin_open(struct db *db, GError **error_r)
-{
- assert(db != NULL);
- assert(db->plugin != NULL);
-
- return db->plugin->open != NULL
- ? db->plugin->open(db, error_r)
- : true;
-}
-
-static inline void
-db_plugin_close(struct db *db)
-{
- assert(db != NULL);
- assert(db->plugin != NULL);
-
- if (db->plugin->close != NULL)
- db->plugin->close(db);
-}
-
-static inline struct song *
-db_plugin_get_song(struct db *db, const char *uri, GError **error_r)
-{
- assert(db != NULL);
- assert(db->plugin != NULL);
- assert(db->plugin->get_song != NULL);
- assert(uri != NULL);
-
- return db->plugin->get_song(db, uri, error_r);
-}
-
-static inline bool
-db_plugin_visit(struct db *db, const struct db_selection *selection,
- const struct db_visitor *visitor, void *ctx,
- GError **error_r)
-{
- assert(db != NULL);
- assert(db->plugin != NULL);
- assert(selection != NULL);
- assert(visitor != NULL);
- assert(error_r == NULL || *error_r == NULL);
-
- return db->plugin->visit(db, selection, visitor, ctx, error_r);
-}
-
-#endif
diff --git a/src/db_print.c b/src/db_print.c
deleted file mode 100644
index 4d7e3f5ef..000000000
--- a/src/db_print.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "db_print.h"
-#include "db_selection.h"
-#include "db_visitor.h"
-#include "locate.h"
-#include "directory.h"
-#include "database.h"
-#include "client.h"
-#include "song.h"
-#include "song_print.h"
-#include "playlist_vector.h"
-#include "tag.h"
-#include "strset.h"
-
-#include <glib.h>
-
-typedef struct _ListCommandItem {
- int8_t tagType;
- const struct locate_item_list *criteria;
-} ListCommandItem;
-
-typedef struct _SearchStats {
- const struct locate_item_list *criteria;
- int numberOfSongs;
- unsigned long playTime;
-} SearchStats;
-
-static bool
-print_visitor_directory(const struct directory *directory, void *data,
- G_GNUC_UNUSED GError **error_r)
-{
- struct client *client = data;
-
- if (!directory_is_root(directory))
- client_printf(client, "directory: %s\n", directory_get_path(directory));
-
- return true;
-}
-
-static void
-print_playlist_in_directory(struct client *client,
- const struct directory *directory,
- const char *name_utf8)
-{
- if (directory_is_root(directory))
- client_printf(client, "playlist: %s\n", name_utf8);
- else
- client_printf(client, "playlist: %s/%s\n",
- directory_get_path(directory), name_utf8);
-}
-
-static bool
-print_visitor_song(struct song *song, void *data,
- G_GNUC_UNUSED GError **error_r)
-{
- assert(song != NULL);
- assert(song->parent != NULL);
-
- struct client *client = data;
- song_print_uri(client, song);
-
- if (song->tag != NULL && song->tag->has_playlist)
- /* this song file has an embedded CUE sheet */
- print_playlist_in_directory(client, song->parent,
- song->uri);
-
- return true;
-}
-
-static bool
-print_visitor_song_info(struct song *song, void *data,
- G_GNUC_UNUSED GError **error_r)
-{
- assert(song != NULL);
- assert(song->parent != NULL);
-
- struct client *client = data;
- song_print_info(client, song);
-
- if (song->tag != NULL && song->tag->has_playlist)
- /* this song file has an embedded CUE sheet */
- print_playlist_in_directory(client, song->parent,
- song->uri);
-
- return true;
-}
-
-static bool
-print_visitor_playlist(const struct playlist_metadata *playlist,
- const struct directory *directory, void *ctx,
- G_GNUC_UNUSED GError **error_r)
-{
- struct client *client = ctx;
- print_playlist_in_directory(client, directory, playlist->name);
- return true;
-}
-
-static bool
-print_visitor_playlist_info(const struct playlist_metadata *playlist,
- const struct directory *directory,
- void *ctx, G_GNUC_UNUSED GError **error_r)
-{
- struct client *client = ctx;
- print_playlist_in_directory(client, directory, playlist->name);
-
-#ifndef G_OS_WIN32
- struct tm tm;
-#endif
- char timestamp[32];
- time_t t = playlist->mtime;
- strftime(timestamp, sizeof(timestamp),
-#ifdef G_OS_WIN32
- "%Y-%m-%dT%H:%M:%SZ",
- gmtime(&t)
-#else
- "%FT%TZ",
- gmtime_r(&t, &tm)
-#endif
- );
- client_printf(client, "Last-Modified: %s\n", timestamp);
-
- return true;
-}
-
-static const struct db_visitor print_visitor = {
- .directory = print_visitor_directory,
- .song = print_visitor_song,
- .playlist = print_visitor_playlist,
-};
-
-static const struct db_visitor print_info_visitor = {
- .directory = print_visitor_directory,
- .song = print_visitor_song_info,
- .playlist = print_visitor_playlist_info,
-};
-
-bool
-db_selection_print(struct client *client, const struct db_selection *selection,
- bool full, GError **error_r)
-{
- return db_visit(selection, full ? &print_info_visitor : &print_visitor,
- client, error_r);
-}
-
-struct search_data {
- struct client *client;
- const struct locate_item_list *criteria;
-};
-
-static bool
-search_visitor_song(struct song *song, void *_data,
- G_GNUC_UNUSED GError **error_r)
-{
- struct search_data *data = _data;
-
- if (locate_song_search(song, data->criteria))
- song_print_info(data->client, song);
-
- return true;
-}
-
-static const struct db_visitor search_visitor = {
- .song = search_visitor_song,
-};
-
-bool
-searchForSongsIn(struct client *client, const char *name,
- const struct locate_item_list *criteria,
- GError **error_r)
-{
- struct locate_item_list *new_list
- = locate_item_list_casefold(criteria);
- struct search_data data;
-
- data.client = client;
- data.criteria = new_list;
-
- bool success = db_walk(name, &search_visitor, &data, error_r);
-
- locate_item_list_free(new_list);
-
- return success;
-}
-
-static bool
-find_visitor_song(struct song *song, void *_data,
- G_GNUC_UNUSED GError **error_r)
-{
- struct search_data *data = _data;
-
- if (locate_song_match(song, data->criteria))
- song_print_info(data->client, song);
-
- return true;
-}
-
-static const struct db_visitor find_visitor = {
- .song = find_visitor_song,
-};
-
-bool
-findSongsIn(struct client *client, const char *name,
- const struct locate_item_list *criteria,
- GError **error_r)
-{
- struct search_data data;
-
- data.client = client;
- data.criteria = criteria;
-
- return db_walk(name, &find_visitor, &data, error_r);
-}
-
-static void printSearchStats(struct client *client, SearchStats *stats)
-{
- client_printf(client, "songs: %i\n", stats->numberOfSongs);
- client_printf(client, "playtime: %li\n", stats->playTime);
-}
-
-static bool
-stats_visitor_song(struct song *song, void *data,
- G_GNUC_UNUSED GError **error_r)
-{
- SearchStats *stats = data;
-
- if (locate_song_match(song, stats->criteria)) {
- stats->numberOfSongs++;
- stats->playTime += song_get_duration(song);
- }
-
- return true;
-}
-
-static const struct db_visitor stats_visitor = {
- .song = stats_visitor_song,
-};
-
-bool
-searchStatsForSongsIn(struct client *client, const char *name,
- const struct locate_item_list *criteria,
- GError **error_r)
-{
- SearchStats stats;
-
- stats.criteria = criteria;
- stats.numberOfSongs = 0;
- stats.playTime = 0;
-
- if (!db_walk(name, &stats_visitor, &stats, error_r))
- return false;
-
- printSearchStats(client, &stats);
- return true;
-}
-
-bool
-printAllIn(struct client *client, const char *uri_utf8, GError **error_r)
-{
- struct db_selection selection;
- db_selection_init(&selection, uri_utf8, true);
- return db_selection_print(client, &selection, false, error_r);
-}
-
-bool
-printInfoForAllIn(struct client *client, const char *uri_utf8,
- GError **error_r)
-{
- struct db_selection selection;
- db_selection_init(&selection, uri_utf8, true);
- return db_selection_print(client, &selection, true, error_r);
-}
-
-static ListCommandItem *
-newListCommandItem(int tagType, const struct locate_item_list *criteria)
-{
- ListCommandItem *item = g_new(ListCommandItem, 1);
-
- item->tagType = tagType;
- item->criteria = criteria;
-
- return item;
-}
-
-static void freeListCommandItem(ListCommandItem * item)
-{
- g_free(item);
-}
-
-static void
-visitTag(struct client *client, struct strset *set,
- struct song *song, enum tag_type tagType)
-{
- struct tag *tag = song->tag;
- bool found = false;
-
- if (tagType == LOCATE_TAG_FILE_TYPE) {
- song_print_uri(client, song);
- return;
- }
-
- if (!tag)
- return;
-
- for (unsigned i = 0; i < tag->num_items; i++) {
- if (tag->items[i]->type == tagType) {
- strset_add(set, tag->items[i]->value);
- found = true;
- }
- }
-
- if (!found)
- strset_add(set, "");
-}
-
-struct list_tags_data {
- struct client *client;
- ListCommandItem *item;
- struct strset *set;
-};
-
-static bool
-unique_tags_visitor_song(struct song *song, void *_data,
- G_GNUC_UNUSED GError **error_r)
-{
- struct list_tags_data *data = _data;
- ListCommandItem *item = data->item;
-
- if (locate_song_match(song, item->criteria))
- visitTag(data->client, data->set, song, item->tagType);
-
- return true;
-}
-
-static const struct db_visitor unique_tags_visitor = {
- .song = unique_tags_visitor_song,
-};
-
-bool
-listAllUniqueTags(struct client *client, int type,
- const struct locate_item_list *criteria,
- GError **error_r)
-{
- ListCommandItem *item = newListCommandItem(type, criteria);
- struct list_tags_data data = {
- .client = client,
- .item = item,
- };
-
- if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
- data.set = strset_new();
- }
-
- if (!db_walk("", &unique_tags_visitor, &data, error_r)) {
- freeListCommandItem(item);
- return false;
- }
-
- if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
- const char *value;
-
- strset_rewind(data.set);
-
- while ((value = strset_next(data.set)) != NULL)
- client_printf(client, "%s: %s\n",
- tag_item_names[type],
- value);
-
- strset_free(data.set);
- }
-
- freeListCommandItem(item);
-
- return true;
-}
diff --git a/src/db_visitor.h b/src/db_visitor.h
deleted file mode 100644
index 6b90c1868..000000000
--- a/src/db_visitor.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPD_DB_VISITOR_H
-#define MPD_DB_VISITOR_H
-
-struct directory;
-struct song;
-struct playlist_metadata;
-
-struct db_visitor {
- /**
- * Visit a directory. Optional method.
- *
- * @return true to continue the operation, false on error (set error_r)
- */
- bool (*directory)(const struct directory *directory, void *ctx,
- GError **error_r);
-
- /**
- * Visit a song. Optional method.
- *
- * @return true to continue the operation, false on error (set error_r)
- */
- bool (*song)(struct song *song, void *ctx, GError **error_r);
-
- /**
- * Visit a playlist. Optional method.
- *
- * @param directory the directory the playlist resides in
- * @return true to continue the operation, false on error (set error_r)
- */
- bool (*playlist)(const struct playlist_metadata *playlist,
- const struct directory *directory, void *ctx,
- GError **error_r);
-};
-
-#endif