gvdb test: avoid infinite recursion
[dconf.git] / dbus-1 / dconf-libdbus-1.c
blob8ea187b06250d17c43c91020a858279f94a804a2
1 /**
2 * Copyright © 2010 Canonical Limited
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the licence, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * Author: Ryan Lortie <desrt@desrt.ca>
18 **/
20 #include "config.h"
22 #include "dconf-libdbus-1.h"
24 #include "../engine/dconf-engine.h"
26 #include <string.h>
28 static DBusConnection *dconf_libdbus_1_buses[5];
30 struct _DConfDBusClient
32 DConfEngine *engine;
33 GSList *watches;
34 gint ref_count;
37 #define DCONF_LIBDBUS_1_ERROR (g_quark_from_static_string("DCONF_LIBDBUS_1_ERROR"))
38 #define DCONF_LIBDBUS_1_ERROR_FAILED 0
40 static DBusMessage *
41 dconf_libdbus_1_new_method_call (const gchar *bus_name,
42 const gchar *object_path,
43 const gchar *interface_name,
44 const gchar *method_name,
45 GVariant *parameters)
47 DBusMessageIter dbus_iter;
48 DBusMessage *message;
49 GVariantIter iter;
50 GVariant *child;
52 g_variant_ref_sink (parameters);
54 message = dbus_message_new_method_call (bus_name, object_path, interface_name, method_name);
55 dbus_message_iter_init_append (message, &dbus_iter);
56 g_variant_iter_init (&iter, parameters);
58 while ((child = g_variant_iter_next_value (&iter)))
60 if (g_variant_is_of_type (child, G_VARIANT_TYPE_STRING))
62 const gchar *str;
64 str = g_variant_get_string (child, NULL);
65 dbus_message_iter_append_basic (&dbus_iter, DBUS_TYPE_STRING, &str);
68 else if (g_variant_is_of_type (child, G_VARIANT_TYPE_UINT32))
70 guint32 uint;
72 uint = g_variant_get_uint32 (child);
73 dbus_message_iter_append_basic (&dbus_iter, DBUS_TYPE_UINT32, &uint);
76 else
78 DBusMessageIter subiter;
79 const guint8 *bytes;
80 gsize n_elements;
82 g_assert (g_variant_is_of_type (child, G_VARIANT_TYPE_BYTESTRING));
84 bytes = g_variant_get_fixed_array (child, &n_elements, sizeof (guint8));
85 dbus_message_iter_open_container (&dbus_iter, DBUS_TYPE_ARRAY, "y", &subiter);
86 dbus_message_iter_append_fixed_array (&subiter, DBUS_TYPE_BYTE, &bytes, n_elements);
87 dbus_message_iter_close_container (&dbus_iter, &subiter);
90 g_variant_unref (child);
93 g_variant_unref (parameters);
95 return message;
98 static GVariant *
99 dconf_libdbus_1_get_message_body (DBusMessage *message,
100 GError **error)
102 GVariantBuilder builder;
103 const gchar *signature;
104 DBusMessageIter iter;
106 /* We support two types: strings and arrays of strings.
108 * It's very simple to detect if the message contains only these
109 * types: check that the signature contains only the letters "a" and
110 * "s" and that it does not contain "aa".
112 signature = dbus_message_get_signature (message);
113 if (signature[strspn(signature, "as")] != '\0' || strstr (signature, "aa"))
115 g_set_error (error, DCONF_LIBDBUS_1_ERROR, DCONF_LIBDBUS_1_ERROR_FAILED,
116 "unable to handle message type '(%s)'", signature);
117 return NULL;
120 g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
121 dbus_message_iter_init (message, &iter);
122 while (dbus_message_iter_get_arg_type (&iter))
124 const gchar *string;
126 if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
128 dbus_message_iter_get_basic (&iter, &string);
129 g_variant_builder_add (&builder, "s", string);
131 else
133 DBusMessageIter sub;
135 g_assert (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_ARRAY &&
136 dbus_message_iter_get_element_type (&iter) == DBUS_TYPE_STRING);
138 g_variant_builder_open (&builder, G_VARIANT_TYPE_STRING_ARRAY);
139 dbus_message_iter_recurse (&iter, &sub);
141 while (dbus_message_iter_get_arg_type (&sub))
143 const gchar *string;
144 dbus_message_iter_get_basic (&sub, &string);
145 g_variant_builder_add (&builder, "s", string);
146 dbus_message_iter_next (&sub);
149 g_variant_builder_close (&builder);
151 dbus_message_iter_next (&iter);
154 return g_variant_ref_sink (g_variant_builder_end (&builder));
157 static GVariant *
158 dconf_libdbus_1_interpret_result (DBusMessage *result,
159 const GVariantType *expected_type,
160 GError **error)
162 GVariant *reply;
164 if (dbus_message_get_type (result) == DBUS_MESSAGE_TYPE_ERROR)
166 const gchar *errstr = "(no message)";
168 dbus_message_get_args (result, NULL, DBUS_TYPE_STRING, &errstr, DBUS_TYPE_INVALID);
169 g_set_error (error, DCONF_LIBDBUS_1_ERROR, DCONF_LIBDBUS_1_ERROR_FAILED,
170 "%s: %s", dbus_message_get_error_name (result), errstr);
171 return NULL;
174 reply = dconf_libdbus_1_get_message_body (result, error);
176 if (reply && expected_type && !g_variant_is_of_type (reply, expected_type))
178 gchar *expected_string;
180 expected_string = g_variant_type_dup_string (expected_type);
181 g_set_error (error, DCONF_LIBDBUS_1_ERROR, DCONF_LIBDBUS_1_ERROR_FAILED,
182 "received reply '%s' is not of the expected type %s",
183 g_variant_get_type_string (reply), expected_string);
184 g_free (expected_string);
186 g_variant_unref (reply);
187 reply = NULL;
190 return reply;
193 static void
194 dconf_libdbus_1_method_call_done (DBusPendingCall *pending,
195 gpointer user_data)
197 DConfEngineCallHandle *handle = user_data;
198 const GVariantType *expected_type;
199 DBusMessage *message;
200 GError *error = NULL;
201 GVariant *reply;
203 if (pending == NULL)
204 return;
206 message = dbus_pending_call_steal_reply (pending);
207 dbus_pending_call_unref (pending);
209 expected_type = dconf_engine_call_handle_get_expected_type (handle);
210 reply = dconf_libdbus_1_interpret_result (message, expected_type, &error);
211 dbus_message_unref (message);
213 dconf_engine_call_handle_reply (handle, reply, error);
215 if (reply)
216 g_variant_unref (reply);
217 if (error)
218 g_error_free (error);
221 gboolean
222 dconf_engine_dbus_call_async_func (GBusType bus_type,
223 const gchar *bus_name,
224 const gchar *object_path,
225 const gchar *interface_name,
226 const gchar *method_name,
227 GVariant *parameters,
228 DConfEngineCallHandle *handle,
229 GError **error)
231 DBusConnection *connection;
232 DBusPendingCall *pending;
233 DBusMessage *message;
235 g_assert_cmpint (bus_type, <, G_N_ELEMENTS (dconf_libdbus_1_buses));
236 connection = dconf_libdbus_1_buses[bus_type];
237 g_assert (connection != NULL);
239 message = dconf_libdbus_1_new_method_call (bus_name, object_path, interface_name, method_name, parameters);
240 dbus_connection_send_with_reply (connection, message, &pending, -1);
241 dbus_pending_call_set_notify (pending, dconf_libdbus_1_method_call_done, handle, NULL);
242 dbus_message_unref (message);
244 return TRUE;
247 static void
248 dconf_libdbus_1_convert_error (DBusError *dbus_error,
249 GError **error)
251 g_set_error (error, DCONF_LIBDBUS_1_ERROR, DCONF_LIBDBUS_1_ERROR_FAILED,
252 "%s: %s", dbus_error->name, dbus_error->message);
255 GVariant *
256 dconf_engine_dbus_call_sync_func (GBusType bus_type,
257 const gchar *bus_name,
258 const gchar *object_path,
259 const gchar *interface_name,
260 const gchar *method_name,
261 GVariant *parameters,
262 const GVariantType *expected_type,
263 GError **error)
265 DBusConnection *connection;
266 DBusMessage *message;
267 DBusError dbus_error;
268 DBusMessage *result;
269 GVariant *reply;
271 g_assert_cmpint (bus_type, <, G_N_ELEMENTS (dconf_libdbus_1_buses));
272 connection = dconf_libdbus_1_buses[bus_type];
273 g_assert (connection != NULL);
275 dbus_error_init (&dbus_error);
276 message = dconf_libdbus_1_new_method_call (bus_name, object_path, interface_name, method_name, parameters);
277 result = dbus_connection_send_with_reply_and_block (connection, message, -1, &dbus_error);
278 dbus_message_unref (message);
280 if (result == NULL)
282 dconf_libdbus_1_convert_error (&dbus_error, error);
283 dbus_error_free (&dbus_error);
284 return NULL;
287 reply = dconf_libdbus_1_interpret_result (result, expected_type, error);
288 dbus_message_unref (result);
290 return reply;
293 static DBusHandlerResult
294 dconf_libdbus_1_filter (DBusConnection *connection,
295 DBusMessage *message,
296 gpointer user_data)
298 GBusType bus_type = GPOINTER_TO_INT (user_data);
300 if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL)
302 const gchar *interface;
304 interface = dbus_message_get_interface (message);
306 if (interface && g_str_equal (interface, "ca.desrt.dconf.Writer"))
308 GVariant *parameters;
310 parameters = dconf_libdbus_1_get_message_body (message, NULL);
312 if (parameters != NULL)
314 dconf_engine_handle_dbus_signal (bus_type,
315 dbus_message_get_sender (message),
316 dbus_message_get_path (message),
317 dbus_message_get_member (message),
318 parameters);
319 g_variant_unref (parameters);
324 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
327 void
328 dconf_libdbus_1_provide_bus (GBusType bus_type,
329 DBusConnection *connection)
331 g_assert_cmpint (bus_type, <, G_N_ELEMENTS (dconf_libdbus_1_buses));
333 if (!dconf_libdbus_1_buses[bus_type])
335 dconf_libdbus_1_buses[bus_type] = dbus_connection_ref (connection);
336 dbus_connection_add_filter (connection, dconf_libdbus_1_filter, GINT_TO_POINTER (bus_type), NULL);
340 #ifndef PIC
341 static gboolean
342 dconf_libdbus_1_check_connection (gpointer user_data)
344 DBusConnection *connection = user_data;
346 dbus_connection_read_write (connection, 0);
347 dbus_connection_dispatch (connection);
349 return G_SOURCE_CONTINUE;
352 void
353 dconf_engine_dbus_init_for_testing (void)
355 DBusConnection *session;
356 DBusConnection *system;
358 dconf_libdbus_1_provide_bus (G_BUS_TYPE_SESSION, session = dbus_bus_get (DBUS_BUS_SESSION, NULL));
359 dconf_libdbus_1_provide_bus (G_BUS_TYPE_SYSTEM, system = dbus_bus_get (DBUS_BUS_SYSTEM, NULL));
361 /* "mainloop integration" */
362 g_timeout_add (1, dconf_libdbus_1_check_connection, session);
363 g_timeout_add (1, dconf_libdbus_1_check_connection, system);
365 #endif