hythmbox-2.98/rhythmdb/rhythmdb-dbus.c

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 }