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>
22 #include "dconf-libdbus-1.h"
24 #include "../engine/dconf-engine.h"
28 static DBusConnection
*dconf_libdbus_1_buses
[5];
30 struct _DConfDBusClient
37 #define DCONF_LIBDBUS_1_ERROR (g_quark_from_static_string("DCONF_LIBDBUS_1_ERROR"))
38 #define DCONF_LIBDBUS_1_ERROR_FAILED 0
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
,
47 DBusMessageIter dbus_iter
;
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
))
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
))
72 uint
= g_variant_get_uint32 (child
);
73 dbus_message_iter_append_basic (&dbus_iter
, DBUS_TYPE_UINT32
, &uint
);
78 DBusMessageIter subiter
;
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
);
99 dconf_libdbus_1_get_message_body (DBusMessage
*message
,
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
);
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
))
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
);
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
))
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
));
158 dconf_libdbus_1_interpret_result (DBusMessage
*result
,
159 const GVariantType
*expected_type
,
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
);
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
);
194 dconf_libdbus_1_method_call_done (DBusPendingCall
*pending
,
197 DConfEngineCallHandle
*handle
= user_data
;
198 const GVariantType
*expected_type
;
199 DBusMessage
*message
;
200 GError
*error
= NULL
;
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
);
216 g_variant_unref (reply
);
218 g_error_free (error
);
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
,
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
);
248 dconf_libdbus_1_convert_error (DBusError
*dbus_error
,
251 g_set_error (error
, DCONF_LIBDBUS_1_ERROR
, DCONF_LIBDBUS_1_ERROR_FAILED
,
252 "%s: %s", dbus_error
->name
, dbus_error
->message
);
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
,
265 DBusConnection
*connection
;
266 DBusMessage
*message
;
267 DBusError dbus_error
;
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
);
282 dconf_libdbus_1_convert_error (&dbus_error
, error
);
283 dbus_error_free (&dbus_error
);
287 reply
= dconf_libdbus_1_interpret_result (result
, expected_type
, error
);
288 dbus_message_unref (result
);
293 static DBusHandlerResult
294 dconf_libdbus_1_filter (DBusConnection
*connection
,
295 DBusMessage
*message
,
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
),
319 g_variant_unref (parameters
);
324 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
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
);
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
;
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
);