/* GConf * Copyright (C) 2003 Imendio HB * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, see . */ #include #include #include #include #include "gconf-database-dbus.h" #include "gconf-dbus-utils.h" #include "gconfd.h" #include "gconfd-dbus.h" static DBusConnection *bus_conn; static const char *server_path = "/org/gnome/GConf/Server"; static gint nr_of_connections = 0; static void server_unregistered_func (DBusConnection *connection, void *user_data); static DBusHandlerResult server_message_func (DBusConnection *connection, DBusMessage *message, void *user_data); static DBusHandlerResult server_filter_func (DBusConnection *connection, DBusMessage *message, void *user_data); static void server_handle_get_db (DBusConnection *connection, DBusMessage *message); static void server_handle_shutdown (DBusConnection *connection, DBusMessage *message); static void server_handle_get_default_db (DBusConnection *connection, DBusMessage *message); static DBusObjectPathVTable server_vtable = { server_unregistered_func, server_message_func, NULL, }; static void server_unregistered_func (DBusConnection *connection, void *user_data) { g_print ("Server object unregistered\n"); nr_of_connections = 0; } static DBusHandlerResult server_message_func (DBusConnection *connection, DBusMessage *message, void *user_data) { if (gconfd_dbus_check_in_shutdown (connection, message)) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) { g_print ("Not a method call\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (g_strcmp0 (dbus_message_get_interface (message), GCONF_DBUS_SERVER_INTERFACE) != 0) { g_print ("Not correct interface: \"%s\"\n", dbus_message_get_interface (message)); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (dbus_message_is_method_call (message, GCONF_DBUS_SERVER_INTERFACE, GCONF_DBUS_SERVER_GET_DEFAULT_DB)) server_handle_get_default_db (connection, message); else if (dbus_message_is_method_call (message, GCONF_DBUS_SERVER_INTERFACE, GCONF_DBUS_SERVER_GET_DB)) server_handle_get_db (connection, message); else if (dbus_message_is_method_call (message, GCONF_DBUS_SERVER_INTERFACE, GCONF_DBUS_SERVER_SHUTDOWN)) server_handle_shutdown (connection, message); else return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult server_filter_func (DBusConnection *connection, DBusMessage *message, void *user_data) { if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { /* Exit cleanly. */ gconfd_main_quit (); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void server_real_handle_get_db (DBusConnection *connection, DBusMessage *message, GSList *addresses) { GConfDatabase *db; DBusMessage *reply; GError *gerror = NULL; const gchar *str; if (gconfd_dbus_check_in_shutdown (connection, message)) return; db = gconfd_obtain_database (addresses, &gerror); if (gconfd_dbus_set_exception (connection, message, &gerror)) return; reply = dbus_message_new_method_return (message); if (reply == NULL) g_error ("No memory"); str = gconf_database_dbus_get_path (db); dbus_message_append_args (reply, DBUS_TYPE_OBJECT_PATH, &str, DBUS_TYPE_INVALID); if (!dbus_connection_send (connection, reply, NULL)) g_error ("No memory"); dbus_message_unref (reply); } static void server_handle_get_default_db (DBusConnection *connection, DBusMessage *message) { server_real_handle_get_db (connection, message, NULL); } static void server_handle_get_db (DBusConnection *connection, DBusMessage *message) { char *addresses; GSList *list; if (!gconfd_dbus_get_message_args (connection, message, DBUS_TYPE_STRING, &addresses, DBUS_TYPE_INVALID)) return; list = gconf_persistent_name_get_address_list (addresses); server_real_handle_get_db (connection, message, list); g_slist_foreach (list, (GFunc) g_free, NULL); g_slist_free (list); } static void server_handle_shutdown (DBusConnection *connection, DBusMessage *message) { DBusMessage *reply; if (gconfd_dbus_check_in_shutdown (connection, message)) return; gconf_log(GCL_DEBUG, _("Shutdown request received")); reply = dbus_message_new_method_return (message); dbus_connection_send (connection, reply, NULL); dbus_message_unref (reply); dbus_connection_unregister_object_path (connection, server_path); gconfd_main_quit(); } gboolean gconfd_dbus_init (void) { DBusError error; gint ret; dbus_error_init (&error); bus_conn = dbus_bus_get (DBUS_BUS_SESSION, &error); if (!bus_conn) { gconf_log (GCL_ERR, _("Daemon failed to connect to the D-BUS daemon:\n%s"), error.message); dbus_error_free (&error); return FALSE; } /* We handle exiting ourselves on disconnect. */ dbus_connection_set_exit_on_disconnect (bus_conn, FALSE); /* Add message filter to handle Disconnected. */ dbus_connection_add_filter (bus_conn, (DBusHandleMessageFunction) server_filter_func, NULL, NULL); ret = dbus_bus_request_name (bus_conn, GCONF_DBUS_SERVICE, 0, &error); if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { gconf_log (GCL_ERR, "Daemon could not become primary owner"); return FALSE; } if (dbus_error_is_set (&error)) { gconf_log (GCL_ERR, _("Daemon failed to acquire gconf service:\n%s"), error.message); dbus_error_free (&error); return FALSE; } if (!dbus_connection_register_object_path (bus_conn, server_path, &server_vtable, NULL)) { gconf_log (GCL_ERR, _("Failed to register server object with the D-BUS bus daemon")); return FALSE; } nr_of_connections = 1; dbus_connection_setup_with_g_main (bus_conn, NULL); return TRUE; } guint gconfd_dbus_client_count (void) { return nr_of_connections; } gboolean gconfd_dbus_get_message_args (DBusConnection *connection, DBusMessage *message, int first_arg_type, ...) { gboolean retval; va_list var_args; va_start (var_args, first_arg_type); retval = dbus_message_get_args_valist (message, NULL, first_arg_type, var_args); va_end (var_args); if (!retval) { DBusMessage *reply; reply = dbus_message_new_error (message, GCONF_DBUS_ERROR_FAILED, _("Got a malformed message.")); dbus_connection_send (connection, reply, NULL); dbus_message_unref (reply); return FALSE; } return TRUE; } gboolean gconfd_dbus_set_exception (DBusConnection *connection, DBusMessage *message, GError **error) { GConfError en; const char *name = NULL; DBusMessage *reply; if (error == NULL || *error == NULL) return FALSE; en = (*error)->code; /* success is not supposed to get set */ g_return_val_if_fail(en != GCONF_ERROR_SUCCESS, FALSE); switch (en) { case GCONF_ERROR_FAILED: name = GCONF_DBUS_ERROR_FAILED; break; case GCONF_ERROR_NO_PERMISSION: name = GCONF_DBUS_ERROR_NO_PERMISSION; break; case GCONF_ERROR_BAD_ADDRESS: name = GCONF_DBUS_ERROR_BAD_ADDRESS; break; case GCONF_ERROR_BAD_KEY: name = GCONF_DBUS_ERROR_BAD_KEY; break; case GCONF_ERROR_PARSE_ERROR: name = GCONF_DBUS_ERROR_PARSE_ERROR; break; case GCONF_ERROR_CORRUPT: name = GCONF_DBUS_ERROR_CORRUPT; break; case GCONF_ERROR_TYPE_MISMATCH: name = GCONF_DBUS_ERROR_TYPE_MISMATCH; break; case GCONF_ERROR_IS_DIR: name = GCONF_DBUS_ERROR_IS_DIR; break; case GCONF_ERROR_IS_KEY: name = GCONF_DBUS_ERROR_IS_KEY; break; case GCONF_ERROR_NO_WRITABLE_DATABASE: name = GCONF_DBUS_ERROR_NO_WRITABLE_DATABASE; break; case GCONF_ERROR_IN_SHUTDOWN: name = GCONF_DBUS_ERROR_IN_SHUTDOWN; break; case GCONF_ERROR_OVERRIDDEN: name = GCONF_DBUS_ERROR_OVERRIDDEN; break; case GCONF_ERROR_LOCK_FAILED: name = GCONF_DBUS_ERROR_LOCK_FAILED; break; case GCONF_ERROR_OAF_ERROR: case GCONF_ERROR_LOCAL_ENGINE: case GCONF_ERROR_NO_SERVER: case GCONF_ERROR_SUCCESS: default: gconf_log (GCL_ERR, "Unhandled error code %d", en); g_assert_not_reached(); break; } reply = dbus_message_new_error (message, name, (*error)->message); dbus_connection_send (connection, reply, NULL); dbus_message_unref (reply); return TRUE; } gboolean gconfd_dbus_check_in_shutdown (DBusConnection *connection, DBusMessage *message) { if (gconfd_in_shutdown ()) { DBusMessage *reply; reply = dbus_message_new_error (message, GCONF_DBUS_ERROR_IN_SHUTDOWN, _("The GConf daemon is currently shutting down.")); dbus_connection_send (connection, reply, NULL); dbus_message_unref (reply); return TRUE; } else return FALSE; } DBusConnection * gconfd_dbus_get_connection (void) { return bus_conn; } void gconfd_emit_db_gone (const char *object_path) { DBusMessage *signal; signal = dbus_message_new_signal (server_path, GCONF_DBUS_SERVER_INTERFACE, GCONF_DBUS_SERVER_BYE_SIGNAL); dbus_message_append_args (signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID); dbus_connection_send (bus_conn, signal, NULL); dbus_message_unref (signal); }