/* * Copyright © 2008 Ross Burton * * 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, 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, see . */ #include "ephy-upnp-extension.h" #include #include #include #include #define GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_UPNP_EXTENSION, EphyUpnpExtensionPrivate)) struct _EphyUpnpExtensionPrivate { /* Epiphany objects */ EphyBookmarks *eb; EphyNode *bookmarks; EphyNode *local; /* GUPnP objects */ GHashTable *device_hash; GUPnPContext *context; GUPnPControlPoint *cp; }; static GObjectClass *parent_class = NULL; static GType type = 0; static void node_take_property_string (EphyNode *node, guint prop, char *string) { GValue value = {0,}; g_value_init (&value, G_TYPE_STRING); g_value_take_string (&value, string); ephy_node_set_property (node, prop, &value); g_value_unset (&value); } static void device_available_cb (GUPnPControlPoint *cp, GUPnPDeviceProxy *proxy, EphyUpnpExtension *extension) { EphyUpnpExtensionPrivate *priv; GUPnPDeviceInfo *info; char *url; EphyNode *node; priv = extension->priv; info = GUPNP_DEVICE_INFO (proxy); /* Skip devices we've seen already */ if (g_hash_table_lookup (priv->device_hash, gupnp_device_info_get_udn (info))) return; url = gupnp_device_info_get_presentation_url (info); if (!url) return; node = ephy_node_new (ephy_node_get_db (priv->local)); ephy_node_set_is_drag_source (node, FALSE); node_take_property_string (node, EPHY_NODE_BMK_PROP_LOCATION, url); node_take_property_string (node, EPHY_NODE_BMK_PROP_TITLE, gupnp_device_info_get_friendly_name (info)); ephy_node_set_property_boolean (node, EPHY_NODE_BMK_PROP_IMMUTABLE, TRUE); ephy_node_add_child (priv->bookmarks, node); ephy_node_add_child (priv->local, node); g_hash_table_insert (priv->device_hash, g_strdup (gupnp_device_info_get_udn (info)), node); } static void device_unavailable_cb (GUPnPControlPoint *cp, GUPnPDeviceProxy *proxy, EphyUpnpExtension *extension) { EphyUpnpExtensionPrivate *priv; GUPnPDeviceInfo *info; priv = extension->priv; info = GUPNP_DEVICE_INFO (proxy); g_hash_table_remove (priv->device_hash, gupnp_device_info_get_udn (info)); } static void ephy_upnp_extension_init (EphyUpnpExtension *extension) { EphyUpnpExtensionPrivate *priv; EphyShell *shell; priv = extension->priv = GET_PRIVATE (extension); priv->device_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)ephy_node_unref); shell = ephy_shell_get_default (); priv->eb = ephy_shell_get_bookmarks (shell); priv->bookmarks = ephy_bookmarks_get_bookmarks (priv->eb); priv->local = ephy_bookmarks_get_local (priv->eb); /* If Epiphany was built without Avahi then there is no Nearby Sites support, so this plugin can't work. */ if (!priv->local) { g_printerr ("ZeroConf support not enabled in Epiphany so no Nearby Sites support, sorry...\n"); return; } priv->context = gupnp_context_new (NULL, NULL, 0, NULL); priv->cp = gupnp_control_point_new (priv->context, "upnp:rootdevice"); g_signal_connect (priv->cp, "device-proxy-available", G_CALLBACK (device_available_cb), extension); g_signal_connect (priv->cp, "device-proxy-unavailable", G_CALLBACK (device_unavailable_cb), extension); gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (priv->cp), TRUE); } static void ephy_upnp_extension_dispose (GObject *object) { EphyUpnpExtension *extension = EPHY_UPNP_EXTENSION (object); if (extension->priv->cp) { g_object_unref (extension->priv->cp); extension->priv->cp = NULL; } if (extension->priv->context) { g_object_unref (extension->priv->context); extension->priv->context = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); } static void ephy_upnp_extension_finalize (GObject *object) { EphyUpnpExtension *extension = EPHY_UPNP_EXTENSION (object); /* This will free the keys (UDN strings) and unref the values (EphyNodes), which will cause them to be removed from the tree. */ g_hash_table_destroy (extension->priv->device_hash); G_OBJECT_CLASS (parent_class)->finalize (object); } static void ephy_upnp_extension_iface_init (EphyExtensionIface *iface) { } static void ephy_upnp_extension_class_init (EphyUpnpExtensionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->dispose = ephy_upnp_extension_dispose; object_class->finalize = ephy_upnp_extension_finalize; g_type_class_add_private (object_class, sizeof (EphyUpnpExtensionPrivate)); } GType ephy_upnp_extension_get_type (void) { return type; } GType ephy_upnp_extension_register_type (GTypeModule *module) { const GTypeInfo our_info = { sizeof (EphyUpnpExtensionClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) ephy_upnp_extension_class_init, NULL, NULL, /* class_data */ sizeof (EphyUpnpExtension), 0, /* n_preallocs */ (GInstanceInitFunc) ephy_upnp_extension_init }; const GInterfaceInfo extension_info = { (GInterfaceInitFunc) ephy_upnp_extension_iface_init, NULL, NULL }; type = g_type_module_register_type (module, G_TYPE_OBJECT, "EphyUpnpExtension", &our_info, 0); g_type_module_add_interface (module, type, EPHY_TYPE_EXTENSION, &extension_info); return type; }