/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2007 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "logging.h" #include "dbus-helper.h" struct generic_data { void *user_data; DBusObjectPathUnregisterFunction unregister_function; GSList *interfaces; char *introspect; }; struct interface_data { const char *interface; DBusMethodVTable *methods; }; DBusHandlerResult dbus_connection_send_and_unref(DBusConnection *connection, DBusMessage *message) { if (message) { dbus_connection_send(connection, message, NULL); dbus_message_unref(message); } return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult introspect(DBusConnection *connection, DBusMessage *message, struct generic_data *data) { DBusMessage *reply; if (dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING) == FALSE) { error("Unexpected signature to introspect call"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (!data->introspect) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; reply = dbus_message_new_method_return(message); if (!reply) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect, DBUS_TYPE_INVALID); return dbus_connection_send_and_unref(connection, reply); } static void generic_unregister(DBusConnection *connection, void *user_data) { struct generic_data *data = user_data; if (data->unregister_function) data->unregister_function(connection, data->user_data); free(data); } static struct interface_data *find_interface(GSList *interfaces, const char *interface) { GSList *list; for (list = interfaces; list; list = list->next) { struct interface_data *iface = list->data; if (!strcmp(interface, iface->interface)) return iface; } return NULL; } static DBusHandlerResult generic_message(DBusConnection *connection, DBusMessage *message, void *user_data) { struct generic_data *data = user_data; struct interface_data *iface; DBusMethodVTable *current; const char *interface; if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect") == TRUE) return introspect(connection, message, data); interface = dbus_message_get_interface(message); iface = find_interface(data->interfaces, interface); if (!iface) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; for (current = iface->methods; current->name && current->message_function; current++) { if (dbus_message_is_method_call(message, iface->interface, current->name) == FALSE) continue; if (dbus_message_has_signature(message, current->signature) == TRUE) return current->message_function(connection, message, data->user_data); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusObjectPathVTable generic_table = { .unregister_function = generic_unregister, .message_function = generic_message, }; static char simple_xml[] = DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE ""; dbus_bool_t dbus_connection_create_object_path(DBusConnection *connection, const char *path, void *user_data, DBusObjectPathUnregisterFunction function) { struct generic_data *data; data = malloc(sizeof(*data)); if (!data) return FALSE; memset(data, 0, sizeof(*data)); data->user_data = user_data; data->unregister_function = function; data->interfaces = NULL; data->introspect = simple_xml; if (dbus_connection_register_object_path(connection, path, &generic_table, data) == FALSE) { free(data); return FALSE; } return TRUE; } dbus_bool_t dbus_connection_destroy_object_path(DBusConnection *connection, const char *path) { return dbus_connection_unregister_object_path(connection, path); } dbus_bool_t dbus_connection_register_interface(DBusConnection *connection, const char *path, const char *interface, DBusMethodVTable *methods, DBusPropertyVTable *properties) { struct generic_data *data; struct interface_data *iface; DBusMethodVTable *current; if (dbus_connection_get_object_path_data(connection, path, (void *) &data) == FALSE) return FALSE; iface = malloc(sizeof(*iface)); if (!iface) return FALSE; memset(iface, 0, sizeof(*iface)); iface->interface = interface; iface->methods = methods; for (current = iface->methods; current->name; current++) { debug("Adding introspection data for %s.%s", interface, current->name); } data->interfaces = g_slist_append(data->interfaces, iface); return TRUE; } dbus_bool_t dbus_connection_unregister_interface(DBusConnection *connection, const char *path, const char *interface) { return TRUE; }