8 #include "e_dbus_private.h"
10 static E_DBus_Interface *introspectable_interface = NULL;
11 static E_DBus_Interface *properties_interface = NULL;
13 typedef struct E_DBus_Method E_DBus_Method;
14 typedef struct E_DBus_Signal E_DBus_Signal;
16 Eina_Strbuf * e_dbus_object_introspect(E_DBus_Object *obj);
18 static void e_dbus_object_unregister(DBusConnection *conn, void *user_data);
19 static DBusHandlerResult e_dbus_object_handler(DBusConnection *conn, DBusMessage *message, void *user_data);
21 static void e_dbus_interface_free(E_DBus_Interface *iface);
23 static E_DBus_Method *e_dbus_method_new(const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func);
24 static void e_dbus_object_method_free(E_DBus_Method *m);
26 static E_DBus_Signal *e_dbus_signal_new(const char *name, const char *signature);
27 static void e_dbus_object_signal_free(E_DBus_Signal *s);
29 static void _introspect_indent_append(Eina_Strbuf *buf, int level);
30 static void _introspect_interface_append(Eina_Strbuf *buf, E_DBus_Interface *iface, int level);
31 static void _introspect_method_append(Eina_Strbuf *buf, E_DBus_Method *method, int level);
32 static void _introspect_signal_append(Eina_Strbuf *buf, E_DBus_Signal *signal, int level);
33 static void _introspect_arg_append(Eina_Strbuf *buf, const char *type, const char *direction, int level);
36 //static Eina_List *standard_methods = NULL;
39 static DBusObjectPathVTable vtable = {
40 e_dbus_object_unregister,
41 e_dbus_object_handler,
50 E_DBus_Connection *conn;
52 Eina_List *interfaces;
53 char *introspection_data;
54 int introspection_dirty;
56 E_DBus_Object_Property_Get_Cb cb_property_get;
57 E_DBus_Object_Property_Set_Cb cb_property_set;
62 struct E_DBus_Interface
74 char *reply_signature;
75 E_DBus_Method_Cb func;
85 cb_introspect(E_DBus_Object *obj, DBusMessage *msg)
90 if (obj->introspection_dirty || !obj->introspection_data)
92 buf = e_dbus_object_introspect(obj);
95 ret = dbus_message_new_error(msg, "org.enlightenment.NotIntrospectable", "This object does not provide introspection data");
99 if (obj->introspection_data) free(obj->introspection_data);
100 obj->introspection_data = strdup(eina_strbuf_string_get(buf));
101 eina_strbuf_free(buf);
103 //printf("XML: \n\n%s\n\n", obj->introspection_data);
104 ret = dbus_message_new_method_return(msg);
105 dbus_message_append_args(ret, DBUS_TYPE_STRING, &(obj->introspection_data), DBUS_TYPE_INVALID);
111 cb_properties_get(E_DBus_Object *obj, DBusMessage *msg)
114 DBusMessageIter iter, sub;
120 dbus_error_init(&err);
121 dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID);
123 if (dbus_error_is_set(&err))
125 return dbus_message_new_error(msg, err.name, err.message);
128 obj->cb_property_get(obj, property, &type, &value);
129 if (type == DBUS_TYPE_INVALID)
131 return dbus_message_new_error_printf(msg, "org.enlightenment.DBus.InvalidProperty", "The property '%s' does not exist on this object.", property);
134 if (dbus_type_is_basic(type))
136 reply = dbus_message_new_method_return(msg);
137 dbus_message_iter_init_append(msg, &iter);
138 if (dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, e_dbus_basic_type_as_string(type), &sub))
140 dbus_message_iter_append_basic(&sub, type, &value);
141 dbus_message_iter_close_container(&iter, &sub);
145 ERR("dbus_message_iter_open_container() failed");
151 return dbus_message_new_error(msg, "org.enlightenment.DBus.UnsupportedType", "E_DBus currently only supports properties of a basic type.");
156 cb_properties_set(E_DBus_Object *obj, DBusMessage *msg)
158 DBusMessageIter iter, sub;
163 dbus_message_iter_init(msg, &iter);
164 dbus_message_iter_get_basic(&iter, &property);
165 dbus_message_iter_recurse(&iter, &sub);
166 type = dbus_message_iter_get_arg_type(&sub);
167 if (dbus_type_is_basic(type))
169 dbus_message_iter_get_basic(&sub, &value);
170 if (obj->cb_property_set(obj, property, type, value))
172 return dbus_message_new_method_return(msg);
176 return dbus_message_new_error_printf(msg, "org.enlightenment.DBus.InvalidProperty", "The property '%s' does not exist on this object.", property);
181 return dbus_message_new_error(msg, "org.enlightenment.DBus.UnsupportedType", "E_DBus currently only supports properties of a basic type.");
187 e_dbus_object_init(void)
189 introspectable_interface = e_dbus_interface_new("org.freedesktop.DBus.Introspectable");
190 properties_interface = e_dbus_interface_new(E_DBUS_FDO_INTERFACE_PROPERTIES);
191 if (!introspectable_interface || !properties_interface)
193 if (introspectable_interface) e_dbus_interface_unref(introspectable_interface);
194 introspectable_interface = NULL;
195 if (properties_interface) e_dbus_interface_unref(properties_interface);
196 properties_interface = NULL;
200 e_dbus_interface_method_add(introspectable_interface, "Introspect", "", "s", cb_introspect);
201 e_dbus_interface_method_add(properties_interface, "Get", "s", "v", cb_properties_get);
202 e_dbus_interface_method_add(properties_interface, "Set", "sv", "", cb_properties_set);
207 e_dbus_object_shutdown(void)
209 e_dbus_interface_unref(introspectable_interface);
210 introspectable_interface = NULL;
212 e_dbus_interface_unref(properties_interface);
213 properties_interface = NULL;
217 e_dbus_object_add(E_DBus_Connection *conn, const char *object_path, void *data)
221 EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
222 EINA_SAFETY_ON_NULL_RETURN_VAL(object_path, NULL);
224 obj = calloc(1, sizeof(E_DBus_Object));
225 if (!obj) return NULL;
227 if (!dbus_connection_register_object_path(conn->conn, object_path, &vtable, obj))
234 e_dbus_connection_ref(conn);
235 obj->path = strdup(object_path);
237 obj->interfaces = NULL;
239 e_dbus_object_interface_attach(obj, introspectable_interface);
245 e_dbus_object_free(E_DBus_Object *obj)
247 E_DBus_Interface *iface;
251 DBG("e_dbus_object_free (%s)", obj->path);
252 dbus_connection_unregister_object_path(obj->conn->conn, obj->path);
253 e_dbus_connection_close(obj->conn);
255 if (obj->path) free(obj->path);
256 EINA_LIST_FREE(obj->interfaces, iface)
257 e_dbus_interface_unref(iface);
259 if (obj->introspection_data) free(obj->introspection_data);
265 e_dbus_object_data_get(E_DBus_Object *obj)
270 EAPI E_DBus_Connection *
271 e_dbus_object_conn_get(E_DBus_Object *obj)
277 e_dbus_object_path_get(E_DBus_Object *obj)
282 EAPI const Eina_List *
283 e_dbus_object_interfaces_get(E_DBus_Object *obj)
285 return obj->interfaces;
289 e_dbus_object_property_get_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Get_Cb func)
291 obj->cb_property_get = func;
295 e_dbus_object_property_set_cb_set(E_DBus_Object *obj, E_DBus_Object_Property_Set_Cb func)
297 obj->cb_property_set = func;
301 e_dbus_object_interface_attach(E_DBus_Object *obj, E_DBus_Interface *iface)
303 EINA_SAFETY_ON_NULL_RETURN(obj);
304 EINA_SAFETY_ON_NULL_RETURN(iface);
306 e_dbus_interface_ref(iface);
307 obj->interfaces = eina_list_append(obj->interfaces, iface);
308 obj->introspection_dirty = 1;
309 DBG("e_dbus_object_interface_attach (%s, %s) ", obj->path, iface->name);
313 e_dbus_object_interface_detach(E_DBus_Object *obj, E_DBus_Interface *iface)
315 E_DBus_Interface *found;
317 DBG("e_dbus_object_interface_detach (%s, %s) ", obj->path, iface->name);
318 found = eina_list_data_find(obj->interfaces, iface);
321 obj->interfaces = eina_list_remove(obj->interfaces, iface);
322 obj->introspection_dirty = 1;
323 e_dbus_interface_unref(iface);
327 e_dbus_interface_ref(E_DBus_Interface *iface)
330 DBG("e_dbus_interface_ref (%s) = %d", iface->name, iface->refcount);
334 e_dbus_interface_unref(E_DBus_Interface *iface)
336 DBG("e_dbus_interface_unref (%s) = %d", iface->name, iface->refcount - 1);
337 if (--(iface->refcount) == 0)
338 e_dbus_interface_free(iface);
342 e_dbus_interface_free(E_DBus_Interface *iface)
347 if (iface->name) free(iface->name);
348 EINA_LIST_FREE(iface->methods, m)
349 e_dbus_object_method_free(m);
350 EINA_LIST_FREE(iface->signals, s)
351 e_dbus_object_signal_free(s);
357 e_dbus_interface_method_add(E_DBus_Interface *iface, const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func)
361 m = e_dbus_method_new(member, signature, reply_signature, func);
362 DBG("E-dbus: Add method %s: %p", member, m);
365 iface->methods = eina_list_append(iface->methods, m);
370 e_dbus_interface_signal_add(E_DBus_Interface *iface, const char *name, const char *signature)
374 s = e_dbus_signal_new(name, signature);
375 DBG("E-dbus: Add signal %s: %p", name, s);
378 iface->signals = eina_list_append(iface->signals, s);
382 EAPI E_DBus_Interface *
383 e_dbus_interface_new(const char *interface)
385 E_DBus_Interface *iface;
387 if (!interface) return NULL;
389 iface = calloc(1, sizeof(E_DBus_Interface));
390 if (!iface) return NULL;
393 iface->name = strdup(interface);
394 iface->methods = NULL;
395 iface->signals = NULL;
400 static E_DBus_Method *
401 e_dbus_method_new(const char *member, const char *signature, const char *reply_signature, E_DBus_Method_Cb func)
405 if (!member || !func) return NULL;
407 if (signature && !dbus_signature_validate(signature, NULL)) return NULL;
408 if (reply_signature && !dbus_signature_validate(reply_signature, NULL)) return NULL;
409 m = calloc(1, sizeof(E_DBus_Method));
412 m->member = strdup(member);
414 m->signature = strdup(signature);
416 m->reply_signature = strdup(reply_signature);
423 e_dbus_object_method_free(E_DBus_Method *m)
426 if (m->member) free(m->member);
427 if (m->signature) free(m->signature);
428 if (m->reply_signature) free(m->reply_signature);
433 static E_DBus_Signal *
434 e_dbus_signal_new(const char *name, const char *signature)
438 if (!name) return NULL;
440 if (signature && !dbus_signature_validate(signature, NULL)) return NULL;
441 s = calloc(1, sizeof(E_DBus_Signal));
444 s->name = strdup(name);
446 s->signature = strdup(signature);
452 e_dbus_object_signal_free(E_DBus_Signal *s)
455 if (s->name) free(s->name);
456 if (s->signature) free(s->signature);
460 static E_DBus_Method *
461 e_dbus_object_method_find(E_DBus_Object *obj, const char *interface, const char *member)
464 E_DBus_Interface *iface;
467 if (!obj || !member) return NULL;
469 EINA_LIST_FOREACH(obj->interfaces, l, iface)
471 if (strcmp(interface, iface->name)) continue;
472 EINA_LIST_FOREACH(iface->methods, ll, m)
474 if (!strcmp(member, m->member))
481 static DBusHandlerResult
482 e_dbus_object_handler(DBusConnection *conn, DBusMessage *message, void *user_data)
487 dbus_uint32_t serial;
491 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
493 m = e_dbus_object_method_find(obj, dbus_message_get_interface(message), dbus_message_get_member(message));
495 /* XXX should this send an 'invalid method' error instead? */
497 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
499 if (m->signature && !dbus_message_has_signature(message, m->signature))
500 reply = dbus_message_new_error_printf(message, "org.enlightenment.InvalidSignature", "Expected signature: %s", m->signature);
502 reply = m->func(obj, message);
504 /* user can choose reply later */
506 return DBUS_HANDLER_RESULT_HANDLED;
508 dbus_connection_send(conn, reply, &serial);
509 dbus_message_unref(reply);
511 return DBUS_HANDLER_RESULT_HANDLED;
515 e_dbus_object_unregister(DBusConnection *conn __UNUSED__, void *user_data __UNUSED__)
517 /* free up the object struct? */
521 e_dbus_object_introspect(E_DBus_Object *obj)
525 E_DBus_Interface *iface;
528 buf = eina_strbuf_new();
531 eina_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");
533 eina_strbuf_append(buf, "<node name=\"");
534 eina_strbuf_append(buf, obj->path);
535 eina_strbuf_append(buf, "\">\n");
538 EINA_LIST_FOREACH(obj->interfaces, l, iface)
539 _introspect_interface_append(buf, iface, level);
541 eina_strbuf_append(buf, "</node>\n");
546 _introspect_indent_append(Eina_Strbuf *buf, int level)
548 /* XXX optimize this? */
551 eina_strbuf_append_char(buf, ' ');
554 _introspect_interface_append(Eina_Strbuf *buf, E_DBus_Interface *iface, int level)
560 _introspect_indent_append(buf, level);
561 eina_strbuf_append(buf, "<interface name=\"");
562 eina_strbuf_append(buf, iface->name);
563 eina_strbuf_append(buf, "\">\n");
566 DBG("introspect iface: %s", iface->name);
567 EINA_LIST_FOREACH(iface->methods, l, m)
568 _introspect_method_append(buf, m, level);
569 EINA_LIST_FOREACH(iface->signals, l, s)
570 _introspect_signal_append(buf, s, level);
573 _introspect_indent_append(buf, level);
574 eina_strbuf_append(buf, "</interface>\n");
577 _introspect_method_append(Eina_Strbuf *buf, E_DBus_Method *method, int level)
579 DBusSignatureIter iter;
582 _introspect_indent_append(buf, level);
583 DBG("introspect method: %s\n", method->member);
584 eina_strbuf_append(buf, "<method name=\"");
585 eina_strbuf_append(buf, method->member);
586 eina_strbuf_append(buf, "\">\n");
590 if (method->signature &&
591 method->signature[0] &&
592 dbus_signature_validate(method->signature, NULL))
594 dbus_signature_iter_init(&iter, method->signature);
595 while ((type = dbus_signature_iter_get_signature(&iter)))
597 _introspect_arg_append(buf, type, "in", level);
600 if (!dbus_signature_iter_next(&iter)) break;
604 /* append reply args */
605 if (method->reply_signature &&
606 method->reply_signature[0] &&
607 dbus_signature_validate(method->reply_signature, NULL))
609 dbus_signature_iter_init(&iter, method->reply_signature);
610 while ((type = dbus_signature_iter_get_signature(&iter)))
612 _introspect_arg_append(buf, type, "out", level);
615 if (!dbus_signature_iter_next(&iter)) break;
620 _introspect_indent_append(buf, level);
621 eina_strbuf_append(buf, "</method>\n");
625 _introspect_signal_append(Eina_Strbuf *buf, E_DBus_Signal *s, int level)
627 DBusSignatureIter iter;
630 _introspect_indent_append(buf, level);
631 DBG("introspect signal: %s", s->name);
632 eina_strbuf_append(buf, "<signal name=\"");
633 eina_strbuf_append(buf, s->name);
634 eina_strbuf_append(buf, "\">\n");
640 dbus_signature_validate(s->signature, NULL))
642 dbus_signature_iter_init(&iter, s->signature);
643 while ((type = dbus_signature_iter_get_signature(&iter)))
645 _introspect_arg_append(buf, type, NULL, level);
648 if (!dbus_signature_iter_next(&iter)) break;
653 _introspect_indent_append(buf, level);
654 eina_strbuf_append(buf, "</signal>\n");
658 _introspect_arg_append(Eina_Strbuf *buf, const char *type, const char *direction, int level)
660 _introspect_indent_append(buf, level);
661 eina_strbuf_append(buf, "<arg type=\"");
662 eina_strbuf_append(buf, type);
665 eina_strbuf_append(buf, "\" direction=\"");
666 eina_strbuf_append(buf, direction);
668 eina_strbuf_append(buf, "\"/>\n");