No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2011 Jonathan Matthew <jonathan@d14n.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * The Rhythmbox authors hereby grant permission for non-GPL compatible
11 * GStreamer plugins to be used and distributed together with GStreamer
12 * and Rhythmbox. This permission is above and beyond the permissions granted
13 * by the GPL license by which Rhythmbox is covered. If you modify this code
14 * you may extend this exception to your version of the code, but you are not
15 * obligated to do so. If you do not wish to do so, delete this exception
16 * statement from your version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 */
28
29 #include "config.h"
30
31 #include <gio/gio.h>
32
33 #include "rhythmdb.h"
34 #include "rhythmdb-private.h"
35
36 static const char *RHYTHMDB_OBJECT_PATH = "/org/gnome/Rhythmbox3/RhythmDB";
37 static const char *RHYTHMDB_INTERFACE_NAME = "org.gnome.Rhythmbox3.RhythmDB";
38
39 static const char *rhythmdb_dbus_spec =
40 "<node>"
41 " <interface name='org.gnome.Rhythmbox3.RhythmDB'>"
42 " <method name='GetEntryProperties'>"
43 " <arg name='uri' type='s'/>"
44 " <arg name='properties' type='a{sv}' direction='out'/>"
45 " </method>"
46 " <method name='SetEntryProperties'>"
47 " <arg name='uri' type='s'/>"
48 " <arg name='properties' type='a{sv}'/>"
49 " </method>"
50 " </interface>"
51 "</node>";
52
53 static void
54 return_entry_not_found (GDBusMethodInvocation *invocation, const char *uri)
55 {
56 g_dbus_method_invocation_return_error (invocation,
57 G_DBUS_ERROR,
58 G_DBUS_ERROR_FILE_NOT_FOUND,
59 "No database entry %s exists",
60 uri);
61 }
62
63 static void
64 rhythmdb_method_call (GDBusConnection *connection,
65 const char *sender,
66 const char *object_path,
67 const char *interface_name,
68 const char *method_name,
69 GVariant *parameters,
70 GDBusMethodInvocation *invocation,
71 RhythmDB *db)
72 {
73 const char *uri;
74 RhythmDBEntry *entry;
75
76 if (g_strcmp0 (object_path, RHYTHMDB_OBJECT_PATH) != 0 ||
77 g_strcmp0 (interface_name, RHYTHMDB_INTERFACE_NAME) != 0) {
78 g_dbus_method_invocation_return_error (invocation,
79 G_DBUS_ERROR,
80 G_DBUS_ERROR_NOT_SUPPORTED,
81 "Method %s.%s not supported",
82 interface_name,
83 method_name);
84 return;
85 }
86
87 if (g_strcmp0 (method_name, "GetEntryProperties") == 0) {
88 RBStringValueMap *properties;
89 GHashTable *prop_hash;
90 GHashTableIter iter;
91 GVariantBuilder *builder;
92 gpointer name_ptr, value_ptr;
93 int count = 0;
94
95 g_variant_get (parameters, "(&s)", &uri);
96
97 entry = rhythmdb_entry_lookup_by_location (db, uri);
98 if (entry == NULL) {
99 return_entry_not_found (invocation, uri);
100 return;
101 }
102
103 properties = rhythmdb_entry_gather_metadata (db, entry);
104 prop_hash = rb_string_value_map_steal_hashtable (properties);
105 g_object_unref (properties);
106
107 g_hash_table_iter_init (&iter, prop_hash);
108 builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
109 while (g_hash_table_iter_next (&iter, &name_ptr, &value_ptr)) {
110 GValue *value;
111 GVariant *v;
112
113 value = value_ptr;
114 v = NULL;
115 if (G_VALUE_HOLDS_STRING (value)) {
116 if (g_value_get_string (value) != NULL) {
117 v = g_variant_new_string (g_value_get_string (value));
118 }
119 } else if (G_VALUE_HOLDS_ULONG (value)) {
120 v = g_variant_new_uint32 (g_value_get_ulong (value));
121 } else if (G_VALUE_HOLDS_DOUBLE (value)) {
122 v = g_variant_new_double (g_value_get_double (value));
123 } else if (G_VALUE_HOLDS_BOOLEAN (value)) {
124 v = g_variant_new_boolean (g_value_get_boolean (value));
125 } else if (G_VALUE_HOLDS_UINT64 (value)) {
126 v = g_variant_new_uint64 (g_value_get_uint64 (value));
127 } else {
128 g_assert_not_reached ();
129 }
130 if (v != NULL) {
131 g_variant_builder_add (builder,
132 "{sv}",
133 (const char *)name_ptr,
134 v);
135 }
136 count++;
137 }
138 g_hash_table_destroy (prop_hash);
139
140 /* make sure there's at least one entry in the dict */
141 if (count == 0) {
142 g_variant_builder_add (builder, "{sv}", "", g_variant_new_string (""));
143 }
144
145 g_dbus_method_invocation_return_value (invocation,
146 g_variant_new ("(a{sv})", builder));
147 g_variant_builder_unref (builder);
148
149 } else if (g_strcmp0 (method_name, "SetEntryProperties") == 0) {
150 GVariant *properties;
151 GVariantIter iter;
152 const char *name;
153 GVariant *value;
154
155 g_variant_get (parameters, "(&s@a{sv})", &uri, &properties);
156
157 entry = rhythmdb_entry_lookup_by_location (db, uri);
158 if (entry == NULL) {
159 return_entry_not_found (invocation, uri);
160 return;
161 }
162
163 /* set properties on entry, commit, etc. */
164 g_variant_iter_init (&iter, properties);
165 while (g_variant_iter_loop (&iter, "{&sv}", &name, &value)) {
166 RhythmDBPropType propid;
167 GValue v = {0,};
168
169 propid = rhythmdb_propid_from_nice_elt_name (db, (xmlChar *)name);
170 if (propid == -1) {
171 /* can't really bail out and return an error at this point */
172 g_warning ("RhythmDB property %s doesn't exist", name);
173 continue;
174 }
175
176 if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) {
177 g_value_init (&v, G_TYPE_STRING);
178 g_value_set_string (&v, g_variant_get_string (value, NULL));
179 } else if (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) {
180 g_value_init (&v, G_TYPE_ULONG);
181 g_value_set_ulong (&v, g_variant_get_uint32 (value));
182 } else if (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE)) {
183 g_value_init (&v, G_TYPE_DOUBLE);
184 g_value_set_double (&v, g_variant_get_double (value));
185 } else {
186 /* again, can't bail out */
187 g_warning ("Can't convert variant type %s to rhythmdb property",
188 g_variant_get_type_string (value));
189 continue;
190 }
191
192 rhythmdb_entry_set (db, entry, propid, &v);
193 g_value_unset (&v);
194 }
195
196 g_dbus_method_invocation_return_value (invocation, NULL);
197 } else {
198 g_dbus_method_invocation_return_error (invocation,
199 G_DBUS_ERROR,
200 G_DBUS_ERROR_NOT_SUPPORTED,
201 "Method %s.%s not supported",
202 interface_name,
203 method_name);
204 }
205 }
206
207 static GDBusInterfaceVTable rhythmdb_interface_vtable = {
208 (GDBusInterfaceMethodCallFunc) rhythmdb_method_call,
209 NULL,
210 NULL
211 };
212
213 void
214 rhythmdb_dbus_register (RhythmDB *db)
215 {
216 GDBusConnection *bus;
217 GDBusInterfaceInfo *ifaceinfo;
218 GDBusNodeInfo *nodeinfo;
219 GError *error = NULL;
220
221 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
222 if (bus == NULL) {
223 return;
224 }
225
226 nodeinfo = g_dbus_node_info_new_for_xml (rhythmdb_dbus_spec, &error);
227 if (error != NULL) {
228 g_warning ("Unable to read RhythmDB D-Bus interface spec: %s", error->message);
229 return;
230 }
231
232 ifaceinfo = g_dbus_node_info_lookup_interface (nodeinfo, RHYTHMDB_INTERFACE_NAME);
233 db->priv->dbus_object_id = g_dbus_connection_register_object (bus,
234 RHYTHMDB_OBJECT_PATH,
235 ifaceinfo,
236 &rhythmdb_interface_vtable,
237 db,
238 NULL,
239 NULL);
240 }
241
242 void
243 rhythmdb_dbus_unregister (RhythmDB *db)
244 {
245 GDBusConnection *bus;
246
247 bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
248 if (bus == NULL) {
249 return;
250 }
251
252 if (db->priv->dbus_object_id) {
253 g_dbus_connection_unregister_object (bus,
254 db->priv->dbus_object_id);
255 db->priv->dbus_object_id = 0;
256 }
257 }