+static AtkPlugClass *plug_class;
+static AtkSocketClass *socket_class;
+
+static gchar *
+get_plug_id (AtkPlug * plug)
+{
+ const char *uname = dbus_bus_get_unique_name (spi_global_app_data->bus);
+ gchar *path;
+ GString *str = g_string_new (NULL);
+
+ path = spi_register_object_to_path (spi_global_register, G_OBJECT (plug));
+ g_string_printf (str, "%s:%s", uname, path);
+ g_free (path);
+ return g_string_free (str, FALSE);
+}
+
+AtkStateSet *
+socket_ref_state_set (AtkObject *accessible)
+{
+ char *child_name, *child_path;
+ AtkSocket *socket = ATK_SOCKET (accessible);
+ int count = 0;
+ int j;
+ int v;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, iter_array;
+ AtkStateSet *set;
+
+ if (!socket->embedded_plug_id)
+ return NULL;
+
+ child_name = g_strdup (socket->embedded_plug_id);
+ if (!child_name)
+ return NULL;
+ child_path = g_utf8_strchr (child_name + 1, -1, ':');
+ if (!child_path)
+ {
+ g_free (child_name);
+ return NULL;
+ }
+ *(child_path++) = '\0';
+ message = dbus_message_new_method_call (child_name, child_path, SPI_DBUS_INTERFACE_ACCESSIBLE, "GetState");
+ g_free (child_name);
+ reply = dbus_connection_send_with_reply_and_block (spi_global_app_data->bus, message, 1, NULL);
+ dbus_message_unref (message);
+ if (reply == NULL)
+ return NULL;
+ if (strcmp (dbus_message_get_signature (reply), "au") != 0)
+ {
+ dbus_message_unref (reply);
+ return NULL;
+ }
+ set = atk_state_set_new ();
+ if (!set)
+ return NULL;
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_array);
+ do
+ {
+ dbus_message_iter_get_basic (&iter_array, &v);
+ for (j = 0; j < 32; j++)
+ {
+ if (v & (1 << j))
+ {
+ AtkState state = spi_atk_state_from_spi_state ((count << 5) + j);
+ atk_state_set_add_state (set, state);
+ }
+ }
+ count++;
+ }
+ while (dbus_message_iter_next (&iter_array));
+ dbus_message_unref (reply);
+ return set;
+}
+
+static void
+socket_embed_hook (AtkSocket * socket, gchar * plug_id)
+{
+ AtkObject *accessible = ATK_OBJECT(socket);
+ gchar *plug_name, *plug_path;
+ AtkObjectClass *klass;
+
+ /* Force registration */
+ gchar *path = spi_register_object_to_path (spi_global_register, G_OBJECT (accessible));
+ /* Let the plug know that it has been embedded */
+ plug_name = g_strdup (plug_id);
+ if (!plug_name)
+ {
+ g_free (path);
+ return;
+ }
+ plug_path = g_utf8_strchr (plug_name + 1, -1, ':');
+ if (plug_path)
+ {
+ DBusMessage *message;
+ *(plug_path++) = '\0';
+ message = dbus_message_new_method_call (plug_name, plug_path, SPI_DBUS_INTERFACE_SOCKET, "Embedded");
+ dbus_message_append_args (message, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
+ dbus_connection_send (spi_global_app_data->bus, message, NULL);
+ }
+ g_free (plug_name);
+ g_free (path);
+
+ klass = ATK_OBJECT_GET_CLASS (accessible);
+ klass->ref_state_set = socket_ref_state_set;
+}
+
+static void
+install_plug_hooks ()
+{
+ gpointer data;
+
+ data = g_type_class_ref (ATK_TYPE_PLUG);
+ plug_class = ATK_PLUG_CLASS (data);
+ data = g_type_class_ref (ATK_TYPE_SOCKET);
+ socket_class = ATK_SOCKET_CLASS (data);
+ plug_class->get_object_id = get_plug_id;
+ socket_class->embed = socket_embed_hook;
+}
+
+static uint
+get_ancestral_uid (uint pid)
+{
+ FILE *fp;
+ char buf [80];
+ int ppid = 0;
+ int uid = 0;
+ gboolean got_ppid = 0;
+ gboolean got_uid = 0;
+
+ sprintf (buf, "/proc/%d/status", pid);
+ fp = fopen (buf, "r");
+ if (!fp)
+ return 0;
+ while ((!got_ppid || !got_uid) && fgets (buf, sizeof (buf), fp))
+ {
+ if (sscanf (buf, "PPid:\t%d", &ppid) == 1)
+ got_ppid = TRUE;
+ else if (sscanf (buf, "Uid:\t%d", &uid) == 1)
+ got_uid = TRUE;
+ }
+ fclose (fp);
+
+ if (!got_ppid || !got_uid)
+ return 0;
+ if (uid != 0)
+ return uid;
+ if (ppid == 0 || ppid == 1)
+ return 0;
+ return get_ancestral_uid (ppid);
+}
+
+static dbus_bool_t
+user_check (DBusConnection *bus, unsigned long uid)
+{
+ if (uid == getuid () || uid == geteuid ())
+ return TRUE;
+ if (getuid () == 0)
+ return get_ancestral_uid (getpid ()) == uid;
+ return FALSE;
+}
+
+static void
+new_connection_cb (DBusServer *server, DBusConnection *con, void *data)
+{
+ GList *new_list;
+
+ dbus_connection_set_unix_user_function (con, user_check, NULL, NULL);
+ dbus_connection_ref(con);
+ atspi_dbus_connection_setup_with_g_main(con, NULL);
+ droute_intercept_dbus (con);
+ droute_context_register (spi_global_app_data->droute, con);