2 #include "e_dbus_private.h"
3 #include <Ecore_Data.h>
8 static E_DBus_Interface *introspectable_interface = NULL;
9 static E_DBus_Interface *properties_interface = NULL;
11 typedef struct E_DBus_Method E_DBus_Method;
13 Ecore_Strbuf * e_dbus_object_introspect(E_DBus_Object *obj);
15 static void e_dbus_object_unregister(DBusConnection *conn, void *user_data);
16 static DBusHandlerResult e_dbus_object_handler(DBusConnection *conn, DBusMessage *message, void *user_data);
18 static void e_dbus_interface_free(E_DBus_Interface *iface);
20 static E_DBus_Method *e_dbus_method_new(const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func);
21 static void e_dbus_object_method_free(E_DBus_Method *m);
23 static void _introspect_indent_append(Ecore_Strbuf *buf, int level);
24 static void _introspect_interface_append(Ecore_Strbuf *buf, E_DBus_Interface *iface, int level);
25 static void _introspect_method_append(Ecore_Strbuf *buf, E_DBus_Method *method, int level);
26 static void _introspect_arg_append(Ecore_Strbuf *buf, const char *type, const char *direction, int level);
29 //static Ecore_List *standard_methods = NULL;
32 static DBusObjectPathVTable vtable = {
33 e_dbus_object_unregister,
34 e_dbus_object_handler,
43 E_DBus_Connection *conn;
45 Ecore_List *interfaces;
46 char *introspection_data;
47 int introspection_dirty;
49 E_DBus_Object_Property_Get_Cb cb_property_get;
50 E_DBus_Object_Property_Set_Cb cb_property_set;
55 struct E_DBus_Interface
66 char *reply_signature;
67 E_DBus_Method_Cb func;
71 cb_introspect(E_DBus_Object *obj, DBusMessage *msg)
76 if (obj->introspection_dirty || !obj->introspection_data)
78 buf = e_dbus_object_introspect(obj);
81 ret = dbus_message_new_error(msg, "org.enlightenment.NotIntrospectable", "This object does not provide introspection data");
85 if (obj->introspection_data) free(obj->introspection_data);
86 obj->introspection_data = strdup(ecore_strbuf_string_get(buf));
87 ecore_strbuf_free(buf);
89 //printf("XML: \n\n%s\n\n", obj->introspection_data);
90 ret = dbus_message_new_method_return(msg);
91 dbus_message_append_args(ret, DBUS_TYPE_STRING, &(obj->introspection_data), DBUS_TYPE_INVALID);
97 cb_properties_get(E_DBus_Object *obj, DBusMessage *msg)
100 DBusMessageIter iter, sub;
106 dbus_error_init(&err);
107 dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID);
109 if (dbus_error_is_set(&err))
111 return dbus_message_new_error(msg, err.name, err.message);
114 obj->cb_property_get(obj, property, &type, &value);
115 if (type == DBUS_TYPE_INVALID)
117 return dbus_message_new_error_printf(msg, "org.enlightenment.DBus.InvalidProperty", "The property '%s' does not exist on this object.", property);
120 if (dbus_type_is_basic(type))
122 reply = dbus_message_new_method_return(msg);
123 dbus_message_iter_init_append(msg, &iter);
124 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, e_dbus_basic_type_as_string(type), &sub);
125 dbus_message_iter_append_basic(&sub, type, &value);
126 dbus_message_iter_close_container(&iter, &sub);
131 return dbus_message_new_error(msg, "org.enlightenment.DBus.UnsupportedType", "E_DBus currently only supports properties of a basic type.");
136 cb_properties_set(E_DBus_Object *obj, DBusMessage *msg)
138 DBusMessageIter iter, sub;
143 dbus_message_iter_init(msg, &iter);
144 dbus_message_iter_get_basic(&iter, &property);
145 dbus_message_iter_recurse(&iter, &sub);
146 type = dbus_message_iter_get_arg_type(&sub);
147 if (dbus_type_is_basic(type))
149 dbus_message_iter_get_basic(&sub, &value);
150 if (obj->cb_property_set(obj, property, type, value))
152 return dbus_message_new_method_return(msg);
156 return dbus_message_new_error_printf(msg, "org.enlightenment.DBus.InvalidProperty", "The property '%s' does not exist on this object.", property);
161 return dbus_message_new_error(msg, "org.enlightenment.DBus.UnsupportedType", "E_DBus currently only supports properties of a basic type.");
167 e_dbus_object_init(void)
169 introspectable_interface = e_dbus_interface_new("org.freedesktop.DBus.Introspectable");
170 properties_interface = e_dbus_interface_new("org.freedesktop.DBus.Properties");
171 if (!introspectable_interface || !properties_interface)
173 if (introspectable_interface) e_dbus_interface_unref(introspectable_interface);
174 introspectable_interface = NULL;
175 if (properties_interface) e_dbus_interface_unref(properties_interface);
176 properties_interface = NULL;
180 e_dbus_interface_method_add(introspectable_interface, "Introspect", "", "s", cb_introspect);
181 e_dbus_interface_method_add(properties_interface, "Get", "s", "v", cb_properties_get);
182 e_dbus_interface_method_add(properties_interface, "Set", "sv", "", cb_properties_set);
187 e_dbus_object_shutdown(void)
189 e_dbus_interface_unref(introspectable_interface);
190 introspectable_interface = NULL;
192 e_dbus_interface_unref(properties_interface);
193 properties_interface = NULL;
199 * @param conn the connection on with the object should listen
200 * @param object_path a unique string identifying an object (e.g. org/enlightenment/WindowManager
201 * @param data custom data to set on the object (retrievable via
202 * e_dbus_object_data_get())
205 e_dbus_object_add(E_DBus_Connection *conn, const char *object_path, void *data)
209 obj = calloc(1, sizeof(E_DBus_Object));
210 if (!obj) return NULL;
212 if (!dbus_connection_register_object_path(conn->conn, object_path, &vtable, obj))
219 e_dbus_connection_ref(conn);
220 obj->path = strdup(object_path);
222 obj->interfaces = ecore_list_new();
223 ecore_list_free_cb_set(obj->interfaces, (Ecore_Free_Cb)e_dbus_interface_unref);
225 e_dbus_object_interface_attach(obj, introspectable_interface);
233 * @param obj the object to free
236 e_dbus_object_free(E_DBus_Object *obj)
240 DEBUG(5, "e_dbus_object_free (%s)\n", obj->path);
241 dbus_connection_unregister_object_path(obj->conn->conn, obj->path);
242 e_dbus_connection_close(obj->conn);
244 if (obj->path) free(obj->path);
245 ecore_list_destroy(obj->interfaces);
246 if (obj->introspection_data) free(obj->introspection_data);
252 * @brief Fetch the data pointer for a dbus object
253 * @param obj the dbus object
256 e_dbus_object_data_get(E_DBus_Object *obj)
262 * @brief Sets the callback to fetch properties from an object
263 * @param obj the object
264 * @param func the callback
267 e_dbus_object_property_get_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Get_Cb func)
269 obj->cb_property_get = func;
273 * @brief Sets the callback to set properties on an object
274 * @param obj the object
275 * @param func the callback
278 e_dbus_object_property_set_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Set_Cb func)
280 obj->cb_property_set = func;
284 e_dbus_object_interface_attach(E_DBus_Object *obj, E_DBus_Interface *iface)
286 e_dbus_interface_ref(iface);
287 ecore_list_append(obj->interfaces, iface);
288 obj->introspection_dirty = 1;
289 DEBUG(4, "e_dbus_object_interface_attach (%s, %s) ", obj->path, iface->name);
293 e_dbus_object_interface_detach(E_DBus_Object *obj, E_DBus_Interface *iface)
295 E_DBus_Interface *found;
297 DEBUG(4, "e_dbus_object_interface_detach (%s, %s) ", obj->path, iface->name);
298 found = ecore_list_goto(obj->interfaces, iface);
299 if (found == NULL) return;
301 ecore_list_remove(obj->interfaces);
302 obj->introspection_dirty = 1;
303 e_dbus_interface_unref(iface);
307 e_dbus_interface_ref(E_DBus_Interface *iface)
310 DEBUG(4, "e_dbus_interface_ref (%s) = %d\n", iface->name, iface->refcount);
314 e_dbus_interface_unref(E_DBus_Interface *iface)
316 DEBUG(4, "e_dbus_interface_unref (%s) = %d\n", iface->name, iface->refcount - 1);
317 if (--(iface->refcount) == 0)
318 e_dbus_interface_free(iface);
322 e_dbus_interface_free(E_DBus_Interface *iface)
324 if (iface->name) free(iface->name);
325 if (iface->methods) ecore_list_destroy(iface->methods);
331 * Add a method to an object
333 * @param iface the E_DBus_Interface to which this method belongs
334 * @param member the name of the method
335 * @param signature an optional message signature. if provided, then messages
336 * with invalid signatures will be automatically rejected
337 * (an Error response will be sent) and introspection data
340 * @return 1 if successful, 0 if failed (e.g. no memory)
343 e_dbus_interface_method_add(E_DBus_Interface *iface, const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func)
347 m = e_dbus_method_new(member, signature, reply_signature, func);
348 DEBUG(4, "Add method %s: %p\n", member, m);
351 ecore_list_append(iface->methods, m);
355 EAPI E_DBus_Interface *
356 e_dbus_interface_new(const char *interface)
358 E_DBus_Interface *iface;
360 if (!interface) return NULL;
362 iface = calloc(1, sizeof(E_DBus_Interface));
363 if (!iface) return NULL;
366 iface->name = strdup(interface);
367 iface->methods = ecore_list_new();
368 ecore_list_free_cb_set(iface->methods, (Ecore_Free_Cb)e_dbus_object_method_free);
373 static E_DBus_Method *
374 e_dbus_method_new(const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func)
378 if (!member || !func) return NULL;
380 if (signature && !dbus_signature_validate(signature, NULL)) return NULL;
381 if (reply_signature && !dbus_signature_validate(reply_signature, NULL)) return NULL;
382 m = calloc(1, sizeof(E_DBus_Method));
385 m->member = strdup(member);
387 m->signature = strdup(signature);
389 m->reply_signature = strdup(reply_signature);
396 e_dbus_object_method_free(E_DBus_Method *m)
399 if (m->member) free(m->member);
400 if (m->signature) free(m->signature);
401 if (m->reply_signature) free(m->reply_signature);
406 static E_DBus_Method *
407 e_dbus_object_method_find(E_DBus_Object *obj, const char *interface, const char *member)
410 E_DBus_Interface *iface;
411 if (!obj || !member) return NULL;
413 ecore_list_first_goto(obj->interfaces);
414 while ((iface = ecore_list_next(obj->interfaces)))
416 if (strcmp(interface, iface->name)) continue;
417 ecore_list_first_goto(iface->methods);
418 while ((m = ecore_list_next(iface->methods)))
420 if (!strcmp(member, m->member))
427 static DBusHandlerResult
428 e_dbus_object_handler(DBusConnection *conn, DBusMessage *message, void *user_data)
433 dbus_uint32_t serial;
437 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
439 m = e_dbus_object_method_find(obj, dbus_message_get_interface(message), dbus_message_get_member(message));
441 /* XXX should this send an 'invalid method' error instead? */
443 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
445 if (m->signature && !dbus_message_has_signature(message, m->signature))
446 reply = dbus_message_new_error_printf(message, "org.enlightenment.InvalidSignature", "Expected signature: %s", m->signature);
448 reply = m->func(obj, message);
450 dbus_connection_send(conn, reply, &serial);
451 dbus_message_unref(reply);
453 return DBUS_HANDLER_RESULT_HANDLED;
457 e_dbus_object_unregister(DBusConnection *conn, void *user_data)
459 /* free up the object struct? */
463 e_dbus_object_introspect(E_DBus_Object *obj)
467 E_DBus_Interface *iface;
469 buf = ecore_strbuf_new();
472 ecore_strbuf_append(buf, "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n");
474 ecore_strbuf_append(buf, "<node name=\"");
475 ecore_strbuf_append(buf, obj->path);
476 ecore_strbuf_append(buf, "\">\n");
479 ecore_list_first_goto(obj->interfaces);
480 while ((iface = ecore_list_next(obj->interfaces)))
481 _introspect_interface_append(buf, iface, level);
483 ecore_strbuf_append(buf, "</node>\n");
488 _introspect_indent_append(Ecore_Strbuf *buf, int level)
490 /* XXX optimize this? */
493 ecore_strbuf_append_char(buf, ' ');
496 _introspect_interface_append(Ecore_Strbuf *buf, E_DBus_Interface *iface, int level)
498 E_DBus_Method *method;
499 _introspect_indent_append(buf, level);
500 ecore_strbuf_append(buf, "<interface name=\"");
501 ecore_strbuf_append(buf, iface->name);
502 ecore_strbuf_append(buf, "\">\n");
505 DEBUG(4, "introspect iface: %s\n", iface->name);
506 ecore_list_first_goto(iface->methods);
507 while ((method = ecore_list_next(iface->methods)))
508 _introspect_method_append(buf, method, level);
511 _introspect_indent_append(buf, level);
512 ecore_strbuf_append(buf, "</interface>\n");
515 _introspect_method_append(Ecore_Strbuf *buf, E_DBus_Method *method, int level)
517 DBusSignatureIter iter;
520 _introspect_indent_append(buf, level);
521 DEBUG(4, "introspect method: %s\n", method->member);
522 ecore_strbuf_append(buf, "<method name=\"");
523 ecore_strbuf_append(buf, method->member);
524 ecore_strbuf_append(buf, "\">\n");
528 if (method->signature &&
529 method->signature[0] &&
530 dbus_signature_validate(method->signature, NULL))
532 dbus_signature_iter_init(&iter, method->signature);
533 while ((type = dbus_signature_iter_get_signature(&iter)))
535 _introspect_arg_append(buf, type, "in", level);
538 if (!dbus_signature_iter_next(&iter)) break;
542 /* append reply args */
543 if (method->reply_signature &&
544 method->reply_signature[0] &&
545 dbus_signature_validate(method->reply_signature, NULL))
547 dbus_signature_iter_init(&iter, method->reply_signature);
548 while ((type = dbus_signature_iter_get_signature(&iter)))
550 _introspect_arg_append(buf, type, "out", level);
553 if (!dbus_signature_iter_next(&iter)) break;
558 _introspect_indent_append(buf, level);
559 ecore_strbuf_append(buf, "</method>\n");
563 _introspect_arg_append(Ecore_Strbuf *buf, const char *type, const char *direction, int level)
565 _introspect_indent_append(buf, level);
566 ecore_strbuf_append(buf, "<arg type=\"");
567 ecore_strbuf_append(buf, type);
568 ecore_strbuf_append(buf, "\" direction=\"");
569 ecore_strbuf_append(buf, direction);
570 ecore_strbuf_append(buf, "\"/>\n");