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;
12 typedef struct E_DBus_Signal E_DBus_Signal;
14 Ecore_Strbuf * e_dbus_object_introspect(E_DBus_Object *obj);
16 static void e_dbus_object_unregister(DBusConnection *conn, void *user_data);
17 static DBusHandlerResult e_dbus_object_handler(DBusConnection *conn, DBusMessage *message, void *user_data);
19 static void e_dbus_interface_free(E_DBus_Interface *iface);
21 static E_DBus_Method *e_dbus_method_new(const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func);
22 static void e_dbus_object_method_free(E_DBus_Method *m);
24 static E_DBus_Signal *e_dbus_signal_new(const char *name, const char *signature);
25 static void e_dbus_object_signal_free(E_DBus_Signal *s);
27 static void _introspect_indent_append(Ecore_Strbuf *buf, int level);
28 static void _introspect_interface_append(Ecore_Strbuf *buf, E_DBus_Interface *iface, int level);
29 static void _introspect_method_append(Ecore_Strbuf *buf, E_DBus_Method *method, int level);
30 static void _introspect_signal_append(Ecore_Strbuf *buf, E_DBus_Signal *signal, int level);
31 static void _introspect_arg_append(Ecore_Strbuf *buf, const char *type, const char *direction, int level);
34 //static Eina_List *standard_methods = NULL;
37 static DBusObjectPathVTable vtable = {
38 e_dbus_object_unregister,
39 e_dbus_object_handler,
48 E_DBus_Connection *conn;
50 Eina_List *interfaces;
51 char *introspection_data;
52 int introspection_dirty;
54 E_DBus_Object_Property_Get_Cb cb_property_get;
55 E_DBus_Object_Property_Set_Cb cb_property_set;
60 struct E_DBus_Interface
72 char *reply_signature;
73 E_DBus_Method_Cb func;
83 cb_introspect(E_DBus_Object *obj, DBusMessage *msg)
88 if (obj->introspection_dirty || !obj->introspection_data)
90 buf = e_dbus_object_introspect(obj);
93 ret = dbus_message_new_error(msg, "org.enlightenment.NotIntrospectable", "This object does not provide introspection data");
97 if (obj->introspection_data) free(obj->introspection_data);
98 obj->introspection_data = strdup(ecore_strbuf_string_get(buf));
99 ecore_strbuf_free(buf);
101 //printf("XML: \n\n%s\n\n", obj->introspection_data);
102 ret = dbus_message_new_method_return(msg);
103 dbus_message_append_args(ret, DBUS_TYPE_STRING, &(obj->introspection_data), DBUS_TYPE_INVALID);
109 cb_properties_get(E_DBus_Object *obj, DBusMessage *msg)
112 DBusMessageIter iter, sub;
118 dbus_error_init(&err);
119 dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID);
121 if (dbus_error_is_set(&err))
123 return dbus_message_new_error(msg, err.name, err.message);
126 obj->cb_property_get(obj, property, &type, &value);
127 if (type == DBUS_TYPE_INVALID)
129 return dbus_message_new_error_printf(msg, "org.enlightenment.DBus.InvalidProperty", "The property '%s' does not exist on this object.", property);
132 if (dbus_type_is_basic(type))
134 reply = dbus_message_new_method_return(msg);
135 dbus_message_iter_init_append(msg, &iter);
136 dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, e_dbus_basic_type_as_string(type), &sub);
137 dbus_message_iter_append_basic(&sub, type, &value);
138 dbus_message_iter_close_container(&iter, &sub);
143 return dbus_message_new_error(msg, "org.enlightenment.DBus.UnsupportedType", "E_DBus currently only supports properties of a basic type.");
148 cb_properties_set(E_DBus_Object *obj, DBusMessage *msg)
150 DBusMessageIter iter, sub;
155 dbus_message_iter_init(msg, &iter);
156 dbus_message_iter_get_basic(&iter, &property);
157 dbus_message_iter_recurse(&iter, &sub);
158 type = dbus_message_iter_get_arg_type(&sub);
159 if (dbus_type_is_basic(type))
161 dbus_message_iter_get_basic(&sub, &value);
162 if (obj->cb_property_set(obj, property, type, value))
164 return dbus_message_new_method_return(msg);
168 return dbus_message_new_error_printf(msg, "org.enlightenment.DBus.InvalidProperty", "The property '%s' does not exist on this object.", property);
173 return dbus_message_new_error(msg, "org.enlightenment.DBus.UnsupportedType", "E_DBus currently only supports properties of a basic type.");
179 e_dbus_object_init(void)
181 introspectable_interface = e_dbus_interface_new("org.freedesktop.DBus.Introspectable");
182 properties_interface = e_dbus_interface_new("org.freedesktop.DBus.Properties");
183 if (!introspectable_interface || !properties_interface)
185 if (introspectable_interface) e_dbus_interface_unref(introspectable_interface);
186 introspectable_interface = NULL;
187 if (properties_interface) e_dbus_interface_unref(properties_interface);
188 properties_interface = NULL;
192 e_dbus_interface_method_add(introspectable_interface, "Introspect", "", "s", cb_introspect);
193 e_dbus_interface_method_add(properties_interface, "Get", "s", "v", cb_properties_get);
194 e_dbus_interface_method_add(properties_interface, "Set", "sv", "", cb_properties_set);
199 e_dbus_object_shutdown(void)
201 e_dbus_interface_unref(introspectable_interface);
202 introspectable_interface = NULL;
204 e_dbus_interface_unref(properties_interface);
205 properties_interface = NULL;
211 * @param conn the connection on with the object should listen
212 * @param object_path a unique string identifying an object (e.g. org/enlightenment/WindowManager
213 * @param data custom data to set on the object (retrievable via
214 * e_dbus_object_data_get())
217 e_dbus_object_add(E_DBus_Connection *conn, const char *object_path, void *data)
221 obj = calloc(1, sizeof(E_DBus_Object));
222 if (!obj) return NULL;
224 if (!dbus_connection_register_object_path(conn->conn, object_path, &vtable, obj))
231 e_dbus_connection_ref(conn);
232 obj->path = strdup(object_path);
234 obj->interfaces = NULL;
236 e_dbus_object_interface_attach(obj, introspectable_interface);
244 * @param obj the object to free
247 e_dbus_object_free(E_DBus_Object *obj)
249 E_DBus_Interface *iface;
253 DEBUG(5, "e_dbus_object_free (%s)\n", obj->path);
254 dbus_connection_unregister_object_path(obj->conn->conn, obj->path);
255 e_dbus_connection_close(obj->conn);
257 if (obj->path) free(obj->path);
258 while (obj->interfaces)
260 iface = eina_list_data_get(obj->interfaces);
261 e_dbus_interface_unref(iface);
262 obj->interfaces = eina_list_remove_list(obj->interfaces, obj->interfaces);
264 if (obj->introspection_data) free(obj->introspection_data);
270 * @brief Fetch the data pointer for a dbus object
271 * @param obj the dbus object
274 e_dbus_object_data_get(E_DBus_Object *obj)
280 * @brief Sets the callback to fetch properties from an object
281 * @param obj the object
282 * @param func the callback
285 e_dbus_object_property_get_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Get_Cb func)
287 obj->cb_property_get = func;
291 * @brief Sets the callback to set properties on an object
292 * @param obj the object
293 * @param func the callback
296 e_dbus_object_property_set_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Set_Cb func)
298 obj->cb_property_set = func;
302 e_dbus_object_interface_attach(E_DBus_Object *obj, E_DBus_Interface *iface)
304 e_dbus_interface_ref(iface);
305 obj->interfaces = eina_list_append(obj->interfaces, iface);
306 obj->introspection_dirty = 1;
307 DEBUG(4, "e_dbus_object_interface_attach (%s, %s) ", obj->path, iface->name);
311 e_dbus_object_interface_detach(E_DBus_Object *obj, E_DBus_Interface *iface)
313 E_DBus_Interface *found;
315 DEBUG(4, "e_dbus_object_interface_detach (%s, %s) ", obj->path, iface->name);
316 found = eina_list_data_find(obj->interfaces, iface);
317 if (found == NULL) return;
319 obj->interfaces = eina_list_remove(obj->interfaces, iface);
320 obj->introspection_dirty = 1;
321 e_dbus_interface_unref(iface);
325 e_dbus_interface_ref(E_DBus_Interface *iface)
328 DEBUG(4, "e_dbus_interface_ref (%s) = %d\n", iface->name, iface->refcount);
332 e_dbus_interface_unref(E_DBus_Interface *iface)
334 DEBUG(4, "e_dbus_interface_unref (%s) = %d\n", iface->name, iface->refcount - 1);
335 if (--(iface->refcount) == 0)
336 e_dbus_interface_free(iface);
340 e_dbus_interface_free(E_DBus_Interface *iface)
345 if (iface->name) free(iface->name);
346 while (iface->methods)
348 m = eina_list_data_get(iface->methods);
349 e_dbus_object_method_free(m);
350 iface->methods = eina_list_remove_list(iface->methods, iface->methods);
352 while (iface->signals)
354 s = eina_list_data_get(iface->signals);
355 e_dbus_object_signal_free(s);
356 iface->signals = eina_list_remove_list(iface->signals, iface->signals);
363 * Add a method to an object
365 * @param iface the E_DBus_Interface to which this method belongs
366 * @param member the name of the method
367 * @param signature an optional message signature. if provided, then messages
368 * with invalid signatures will be automatically rejected
369 * (an Error response will be sent) and introspection data
372 * @return 1 if successful, 0 if failed (e.g. no memory)
375 e_dbus_interface_method_add(E_DBus_Interface *iface, const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func)
379 m = e_dbus_method_new(member, signature, reply_signature, func);
380 DEBUG(4, "Add method %s: %p\n", member, m);
383 iface->methods = eina_list_append(iface->methods, m);
388 * Add a signal to an object
390 * @param iface the E_DBus_Interface to which this signal belongs
391 * @param name the name of the signal
392 * @param signature an optional message signature.
394 * @return 1 if successful, 0 if failed (e.g. no memory)
397 e_dbus_interface_signal_add(E_DBus_Interface *iface, const char *name, const char *signature)
401 s = e_dbus_signal_new(name, signature);
402 DEBUG(4, "Add signal %s: %p\n", name, s);
405 iface->signals = eina_list_append(iface->signals, s);
409 EAPI E_DBus_Interface *
410 e_dbus_interface_new(const char *interface)
412 E_DBus_Interface *iface;
414 if (!interface) return NULL;
416 iface = calloc(1, sizeof(E_DBus_Interface));
417 if (!iface) return NULL;
420 iface->name = strdup(interface);
421 iface->methods = NULL;
422 iface->signals = NULL;
427 static E_DBus_Method *
428 e_dbus_method_new(const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func)
432 if (!member || !func) return NULL;
434 if (signature && !dbus_signature_validate(signature, NULL)) return NULL;
435 if (reply_signature && !dbus_signature_validate(reply_signature, NULL)) return NULL;
436 m = calloc(1, sizeof(E_DBus_Method));
439 m->member = strdup(member);
441 m->signature = strdup(signature);
443 m->reply_signature = strdup(reply_signature);
450 e_dbus_object_method_free(E_DBus_Method *m)
453 if (m->member) free(m->member);
454 if (m->signature) free(m->signature);
455 if (m->reply_signature) free(m->reply_signature);
460 static E_DBus_Signal *
461 e_dbus_signal_new(const char *name, const char *signature)
465 if (!name) return NULL;
467 if (signature && !dbus_signature_validate(signature, NULL)) return NULL;
468 s = calloc(1, sizeof(E_DBus_Signal));
471 s->name = strdup(name);
473 s->signature = strdup(signature);
479 e_dbus_object_signal_free(E_DBus_Signal *s)
482 if (s->name) free(s->name);
483 if (s->signature) free(s->signature);
487 static E_DBus_Method *
488 e_dbus_object_method_find(E_DBus_Object *obj, const char *interface, const char *member)
491 E_DBus_Interface *iface;
494 if (!obj || !member) return NULL;
496 EINA_LIST_FOREACH(obj->interfaces, l, iface)
498 if (strcmp(interface, iface->name)) continue;
499 EINA_LIST_FOREACH(iface->methods, ll, m)
501 if (!strcmp(member, m->member))
508 static DBusHandlerResult
509 e_dbus_object_handler(DBusConnection *conn, DBusMessage *message, void *user_data)
514 dbus_uint32_t serial;
518 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
520 m = e_dbus_object_method_find(obj, dbus_message_get_interface(message), dbus_message_get_member(message));
522 /* XXX should this send an 'invalid method' error instead? */
524 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
526 if (m->signature && !dbus_message_has_signature(message, m->signature))
527 reply = dbus_message_new_error_printf(message, "org.enlightenment.InvalidSignature", "Expected signature: %s", m->signature);
529 reply = m->func(obj, message);
531 dbus_connection_send(conn, reply, &serial);
532 dbus_message_unref(reply);
534 return DBUS_HANDLER_RESULT_HANDLED;
538 e_dbus_object_unregister(DBusConnection *conn, void *user_data)
540 /* free up the object struct? */
544 e_dbus_object_introspect(E_DBus_Object *obj)
548 E_DBus_Interface *iface;
551 buf = ecore_strbuf_new();
554 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");
556 ecore_strbuf_append(buf, "<node name=\"");
557 ecore_strbuf_append(buf, obj->path);
558 ecore_strbuf_append(buf, "\">\n");
561 EINA_LIST_FOREACH(obj->interfaces, l, iface)
562 _introspect_interface_append(buf, iface, level);
564 ecore_strbuf_append(buf, "</node>\n");
569 _introspect_indent_append(Ecore_Strbuf *buf, int level)
571 /* XXX optimize this? */
574 ecore_strbuf_append_char(buf, ' ');
577 _introspect_interface_append(Ecore_Strbuf *buf, E_DBus_Interface *iface, int level)
579 E_DBus_Method *method;
580 E_DBus_Signal *signal;
583 _introspect_indent_append(buf, level);
584 ecore_strbuf_append(buf, "<interface name=\"");
585 ecore_strbuf_append(buf, iface->name);
586 ecore_strbuf_append(buf, "\">\n");
589 DEBUG(4, "introspect iface: %s\n", iface->name);
590 EINA_LIST_FOREACH(iface->methods, l, method)
591 _introspect_method_append(buf, method, level);
592 EINA_LIST_FOREACH(iface->signals, l, signal)
593 _introspect_signal_append(buf, signal, level);
596 _introspect_indent_append(buf, level);
597 ecore_strbuf_append(buf, "</interface>\n");
600 _introspect_method_append(Ecore_Strbuf *buf, E_DBus_Method *method, int level)
602 DBusSignatureIter iter;
605 _introspect_indent_append(buf, level);
606 DEBUG(4, "introspect method: %s\n", method->member);
607 ecore_strbuf_append(buf, "<method name=\"");
608 ecore_strbuf_append(buf, method->member);
609 ecore_strbuf_append(buf, "\">\n");
613 if (method->signature &&
614 method->signature[0] &&
615 dbus_signature_validate(method->signature, NULL))
617 dbus_signature_iter_init(&iter, method->signature);
618 while ((type = dbus_signature_iter_get_signature(&iter)))
620 _introspect_arg_append(buf, type, "in", level);
623 if (!dbus_signature_iter_next(&iter)) break;
627 /* append reply args */
628 if (method->reply_signature &&
629 method->reply_signature[0] &&
630 dbus_signature_validate(method->reply_signature, NULL))
632 dbus_signature_iter_init(&iter, method->reply_signature);
633 while ((type = dbus_signature_iter_get_signature(&iter)))
635 _introspect_arg_append(buf, type, "out", level);
638 if (!dbus_signature_iter_next(&iter)) break;
643 _introspect_indent_append(buf, level);
644 ecore_strbuf_append(buf, "</method>\n");
648 _introspect_signal_append(Ecore_Strbuf *buf, E_DBus_Signal *signal, int level)
650 DBusSignatureIter iter;
653 _introspect_indent_append(buf, level);
654 DEBUG(4, "introspect signal: %s\n", signal->name);
655 ecore_strbuf_append(buf, "<signal name=\"");
656 ecore_strbuf_append(buf, signal->name);
657 ecore_strbuf_append(buf, "\">\n");
661 if (signal->signature &&
662 signal->signature[0] &&
663 dbus_signature_validate(signal->signature, NULL))
665 dbus_signature_iter_init(&iter, signal->signature);
666 while ((type = dbus_signature_iter_get_signature(&iter)))
668 _introspect_arg_append(buf, type, NULL, level);
671 if (!dbus_signature_iter_next(&iter)) break;
676 _introspect_indent_append(buf, level);
677 ecore_strbuf_append(buf, "</signal>\n");
681 _introspect_arg_append(Ecore_Strbuf *buf, const char *type, const char *direction, int level)
683 _introspect_indent_append(buf, level);
684 ecore_strbuf_append(buf, "<arg type=\"");
685 ecore_strbuf_append(buf, type);
688 ecore_strbuf_append(buf, "\" direction=\"");
689 ecore_strbuf_append(buf, direction);
691 ecore_strbuf_append(buf, "\"/>\n");