aboutsummaryrefslogtreecommitdiffstats
path: root/src/bookmarks/ephy-bookmarks.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bookmarks/ephy-bookmarks.c')
-rw-r--r--src/bookmarks/ephy-bookmarks.c364
1 files changed, 270 insertions, 94 deletions
diff --git a/src/bookmarks/ephy-bookmarks.c b/src/bookmarks/ephy-bookmarks.c
index 121326874..535ac17f0 100644
--- a/src/bookmarks/ephy-bookmarks.c
+++ b/src/bookmarks/ephy-bookmarks.c
@@ -44,17 +44,19 @@
#include <string.h>
#include <glib/gi18n.h>
-#include <libgnomevfs/gnome-vfs-utils.h>
-#include <libgnomevfs/gnome-vfs-dns-sd.h>
#include <gtk/gtkmessagedialog.h>
#include <gtk/gtkdialog.h>
+#include <avahi-common/error.h>
+#include <avahi-gobject/ga-service-browser.h>
+#include <avahi-gobject/ga-service-resolver.h>
+#include <avahi-gobject/ga-client.h>
+#include <avahi-gobject/ga-enums.h>
#define EPHY_BOOKMARKS_XML_ROOT "ephy_bookmarks"
#define EPHY_BOOKMARKS_XML_VERSION "1.03"
#define BOOKMARKS_SAVE_DELAY 3 /* seconds */
#define MAX_FAVORITES_NUM 10
#define UPDATE_URI_DATA_KEY "updated-uri"
-#define SD_RESOLVE_TIMEOUT 0 /* ms; 0 means no timeout */
#define EPHY_BOOKMARKS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_BOOKMARKS, EphyBookmarksPrivate))
@@ -85,7 +87,8 @@ struct _EphyBookmarksPrivate
#ifdef ENABLE_ZEROCONF
/* Local sites */
EphyNode *local;
- GnomeVFSDNSSDBrowseHandle *browse_handles[G_N_ELEMENTS (zeroconf_protos)];
+ GaClient *ga_client;
+ GaServiceBrowser *browse_handles[G_N_ELEMENTS (zeroconf_protos)];
GHashTable *resolve_handles;
#endif
};
@@ -782,29 +785,96 @@ backup_file (const char *original_filename, const char *extension)
#ifdef ENABLE_ZEROCONF
+/* C&P adapted from gnome-vfs-dns-sd.c */
+static GHashTable *
+decode_txt_record (AvahiStringList *input_text)
+{
+ GHashTable *hash;
+ int i;
+ int len;
+ char *key, *value, *end;
+ char *key_dup, *value_dup;
+ char *raw_txt;
+ size_t raw_txt_len;
+
+ raw_txt_len = avahi_string_list_serialize (input_text, NULL, 0);
+ raw_txt = g_malloc (raw_txt_len);
+ raw_txt_len = avahi_string_list_serialize (input_text, raw_txt, raw_txt_len);
+
+ if (raw_txt == NULL)
+ return NULL;
+
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ i = 0;
+ while (i < raw_txt_len) {
+ len = raw_txt[i++];
+
+ if (i + len > raw_txt_len) {
+ break;
+ }
+
+ if (len == 0) {
+ continue;
+ }
+
+ key = &raw_txt[i];
+ end = &raw_txt[i + len];
+ i += len;
+
+ if (*key == '=') {
+ /* 6.4 - silently ignore keys starting with = */
+ continue;
+ }
+
+ value = memchr (key, '=', len);
+ if (value) {
+ key_dup = g_strndup (key, value - key);
+ value++; /* Skip '=' */
+ value_dup = g_strndup (value, end - value);
+ } else {
+ key_dup = g_strndup (key, len);
+ value_dup = NULL;
+ }
+ if (!g_hash_table_lookup_extended (hash,
+ key_dup,
+ NULL, NULL)) {
+ g_hash_table_insert (hash,
+ key_dup,
+ value_dup);
+ } else {
+ g_free (key_dup);
+ g_free (value_dup);
+ }
+ }
+
+ return hash;
+}
+
+/* End of copied code */
+
static char *
-get_id_for_service (const GnomeVFSDNSSDService *service)
+get_id_for_response (const char *type,
+ const char *domain,
+ const char *name)
{
/* FIXME: limit length! */
return g_strdup_printf ("%s\1%s\1%s",
- service->type,
- service->domain,
- service->name);
+ type,
+ domain,
+ name);
}
static EphyNode *
-get_node_for_service (EphyBookmarks *bookmarks,
- const GnomeVFSDNSSDService *service)
+get_node_for_id (EphyBookmarks *bookmarks,
+ char *node_id)
{
EphyBookmarksPrivate *priv = bookmarks->priv;
EphyNode *kid, *node = NULL;
GPtrArray *children;
- char *search_id;
const char *id;
guint i;
- search_id = get_id_for_service (service);
-
children = ephy_node_get_children (priv->local);
for (i = 0; i < children->len; i++)
{
@@ -813,14 +883,14 @@ get_node_for_service (EphyBookmarks *bookmarks,
id = ephy_node_get_property_string (kid,
EPHY_NODE_BMK_PROP_SERVICE_ID);
- if (g_str_equal (id, search_id))
+ if (g_str_equal (id, node_id))
{
node = kid;
break;
}
}
- g_free (search_id);
+ g_free (node_id);
return node;
}
@@ -833,21 +903,26 @@ typedef struct
} ResolveData;
static void
-resolve_cb (GnomeVFSDNSSDResolveHandle *handle,
- GnomeVFSResult result,
- const GnomeVFSDNSSDService *service,
- const char *host,
- int port,
- /* const */ GHashTable *text,
- int text_raw_len,
- const char *text_raw,
- ResolveData *data)
+resolver_found_cb (GaServiceResolver *resolver,
+ int interface,
+ GaProtocol protocol,
+ const char *name,
+ const char *type,
+ const char *domain,
+ const char *host_name,
+ const AvahiAddress *address,
+ guint16 port,
+ AvahiStringList *txt,
+ glong flags,
+ ResolveData *data)
{
EphyBookmarks *bookmarks = data->bookmarks;
EphyBookmarksPrivate *priv = bookmarks->priv;
EphyNode *node = data->node;
GValue value = { 0, };
const char *path = NULL;
+ char host[128];
+ GHashTable *text_table;
char *url;
gboolean was_immutable;
guint i;
@@ -856,39 +931,38 @@ resolve_cb (GnomeVFSDNSSDResolveHandle *handle,
ephy_node_db_set_immutable (priv->db, FALSE);
g_hash_table_steal (priv->resolve_handles, node);
-
- /* Error, don't add the service */
- if (result != GNOME_VFS_OK)
- {
- ephy_node_unref (node);
-
- ephy_node_db_set_immutable (priv->db, was_immutable);
-
- return;
- }
-
+
/* Find the protocol */
for (i = 0; i < G_N_ELEMENTS (zeroconf_protos); ++i)
{
char proto[20];
g_snprintf (proto, sizeof (proto), "_%s._tcp", zeroconf_protos[i]);
- if (strcmp (service->type, proto) == 0) break;
+ if (strcmp (type, proto) == 0) break;
}
if (i == G_N_ELEMENTS (zeroconf_protos)) return;
+
+ text_table = decode_txt_record (txt);
- if (text != NULL)
+ if (text_table != NULL)
{
- path = g_hash_table_lookup (text, "path");
+ path = g_hash_table_lookup (text_table, "path");
}
if (path == NULL || path[0] == '\0')
{
path = "/";
}
+
+ if (address == NULL)
+ {
+ g_warning ("Zeroconf failed to resolve host %s", name);
+ return;
+ }
+ avahi_address_snprint (host, sizeof (host), address);
LOG ("0conf RESOLVED type=%s domain=%s name=%s => proto=%s host=%s port=%d path=%s\n",
- service->type, service->domain, service->name,
- zeroconf_protos[i], host, port, path);
+ type, domain, name,
+ zeroconf_protos[i], host, port, path);
/* FIXME: limit length! */
url = g_strdup_printf ("%s://%s:%d%s", zeroconf_protos[i], host, port, path);
@@ -908,39 +982,84 @@ resolve_cb (GnomeVFSDNSSDResolveHandle *handle,
}
static void
-browse_cb (GnomeVFSDNSSDBrowseHandle *handle,
- GnomeVFSDNSSDServiceStatus status,
- const GnomeVFSDNSSDService *service,
- EphyBookmarks *bookmarks)
+resolver_failure_cb (GaServiceResolver *resolver,
+ GError *error,
+ ResolveData *data)
{
+ EphyBookmarks *bookmarks = data->bookmarks;
EphyBookmarksPrivate *priv = bookmarks->priv;
- GnomeVFSDNSSDResolveHandle *reshandle = NULL;
- ResolveData *data;
- EphyNode *node;
- GValue value = { 0, };
- gboolean new_node = FALSE;
+ EphyNode *node = data->node;
+ gboolean was_immutable;
- if (service == NULL) return;
+ was_immutable = ephy_node_db_is_immutable (priv->db);
+ ephy_node_db_set_immutable (priv->db, FALSE);
- node = get_node_for_service (bookmarks, service);
+ g_hash_table_steal (priv->resolve_handles, node);
- if (status == GNOME_VFS_DNS_SD_SERVICE_REMOVED)
- {
- if (node != NULL)
- {
- g_hash_table_remove (priv->resolve_handles, node);
- ephy_node_unref (node);
- }
+ /* Error, don't add the service */
+ ephy_node_unref (node);
+ ephy_node_db_set_immutable (priv->db, was_immutable);
- return;
- }
+ return;
+}
- /* status == GNOME_VFS_DNS_SD_SERVICE_ADDED */
+static void
+free_resolve_cb_data (gpointer data)
+{
+ g_slice_free (ResolveData, data);
+}
- LOG ("0conf ADD: type=%s domain=%s name=%s\n",
- service->type, service->domain, service->name);
+static void
+browser_removed_service_cb (GaServiceBrowser *browser,
+ int interface,
+ GaProtocol protocol,
+ const char *name,
+ const char *type,
+ const char *domain,
+ glong flags,
+ EphyBookmarks *bookmarks)
+{
+ EphyBookmarksPrivate *priv = bookmarks->priv;
+ EphyNode *node;
+ char *node_id;
+
+ node_id = get_id_for_response (type, domain, name);
+ node = get_node_for_id (bookmarks, node_id);
+
+ if (node != NULL)
+ {
+ g_hash_table_remove (priv->resolve_handles, node);
+ ephy_node_unref (node);
+ }
+
+ return;
+}
- if (node != NULL &&
+static void
+browser_new_service_cb (GaServiceBrowser *browser,
+ int interface,
+ GaProtocol protocol,
+ const char *name,
+ const char *type,
+ const char *domain,
+ glong flags,
+ EphyBookmarks *bookmarks)
+{
+ EphyBookmarksPrivate *priv = bookmarks->priv;
+ EphyNode *node;
+ GValue value = { 0, };
+ gboolean new_node = FALSE;
+ GaServiceResolver *resolver = NULL;
+ ResolveData *data;
+ char *node_id;
+
+ node_id = get_id_for_response (type, domain, name);
+ node = get_node_for_id (bookmarks, node_id);
+
+ LOG ("0conf ADD: type=%s domain=%s name=%s\n",
+ type, domain, name);
+
+ if (node != NULL &&
g_hash_table_lookup (priv->resolve_handles, node) != NULL) return;
if (node == NULL)
@@ -959,14 +1078,14 @@ browse_cb (GnomeVFSDNSSDBrowseHandle *handle,
ephy_node_set_is_drag_source (node, FALSE);
g_value_init (&value, G_TYPE_STRING);
- g_value_take_string (&value, get_id_for_service (service));
+ g_value_take_string (&value, get_id_for_response (type, domain, name));
ephy_node_set_property (node, EPHY_NODE_BMK_PROP_SERVICE_ID, &value);
g_value_unset (&value);
/* FIXME: limit length! */
ephy_node_set_property_string (node,
EPHY_NODE_BMK_PROP_TITLE,
- service->name);
+ name);
ephy_node_set_property_boolean (node,
EPHY_NODE_BMK_PROP_IMMUTABLE,
@@ -975,58 +1094,110 @@ browse_cb (GnomeVFSDNSSDBrowseHandle *handle,
ephy_node_db_set_immutable (priv->db, was_immutable);
}
- data = g_new (ResolveData, 1);
+ data = g_slice_new0 (ResolveData);
data->bookmarks = bookmarks;
data->node = node;
data->new_node = new_node;
-
- if (gnome_vfs_dns_sd_resolve (&reshandle,
- service->name, service->type, service->domain,
- SD_RESOLVE_TIMEOUT,
- (GnomeVFSDNSSDResolveCallback) resolve_cb,
- data,
- (GDestroyNotify) g_free) != GNOME_VFS_OK)
+
+ resolver = ga_service_resolver_new (AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC,
+ name, type, domain,
+ AVAHI_PROTO_UNSPEC,
+ GA_LOOKUP_USE_MULTICAST);
+ g_signal_connect_data (resolver, "found",
+ G_CALLBACK (resolver_found_cb), data,
+ (GClosureNotify) free_resolve_cb_data, 0);
+ g_signal_connect_data (resolver, "failure",
+ G_CALLBACK (resolver_failure_cb), data,
+ (GClosureNotify) free_resolve_cb_data, 0);
+ if (!ga_service_resolver_attach (resolver,
+ priv->ga_client,
+ NULL))
{
+ g_warning ("Unable to resolve Zeroconf service %s", name);
ephy_node_unref (node);
- g_free (data);
-
+ free_resolve_cb_data (data);
return;
}
-
g_hash_table_insert (priv->resolve_handles,
- node, reshandle);
+ node, resolver);
}
static void
-ephy_local_bookmarks_init (EphyBookmarks *bookmarks)
+start_browsing (GaClient *ga_client,
+ EphyBookmarks *bookmarks)
{
EphyBookmarksPrivate *priv = bookmarks->priv;
guint i;
- priv->resolve_handles =
- g_hash_table_new_full (g_direct_hash, g_direct_equal,
- NULL,
- (GDestroyNotify) gnome_vfs_dns_sd_cancel_resolve);
-
for (i = 0; i < G_N_ELEMENTS (zeroconf_protos); ++i)
{
- GnomeVFSDNSSDBrowseHandle *handle = NULL;
+ GaServiceBrowser *browser = NULL;
char proto[20];
g_snprintf (proto, sizeof (proto), "_%s._tcp", zeroconf_protos[i]);
- if (gnome_vfs_dns_sd_browse (&handle,
- "local", proto,
- (GnomeVFSDNSSDBrowseCallback) browse_cb,
- bookmarks,
- NULL) == GNOME_VFS_OK)
+ browser = ga_service_browser_new (proto);
+ g_signal_connect (browser, "new-service",
+ G_CALLBACK (browser_new_service_cb), bookmarks);
+ g_signal_connect (browser, "removed-service",
+ G_CALLBACK (browser_removed_service_cb), bookmarks);
+ if (!ga_service_browser_attach (browser,
+ ga_client,
+ NULL))
{
- priv->browse_handles[i] = handle;
+ g_warning ("Unable to start Zeroconf subsystem");
+ return;
}
+
+ priv->browse_handles[i] = browser;
}
}
static void
+ga_client_state_changed_cb (GaClient *ga_client,
+ GaClientState state,
+ EphyBookmarks *bookmarks)
+{
+ if (state == GA_CLIENT_STATE_FAILURE)
+ {
+ if (avahi_client_errno (ga_client->avahi_client) == AVAHI_ERR_DISCONNECTED)
+ {
+ /* Destroy and reconnect */
+ avahi_client_free (ga_client->avahi_client);
+ ga_client->avahi_client = NULL;
+ if (!ga_client_start (ga_client, NULL))
+ {
+ g_warning ("Unable to start Zeroconf subsystem");
+ }
+ }
+ }
+ if (state == GA_CLIENT_STATE_S_RUNNING)
+ {
+ start_browsing (ga_client, bookmarks);
+ }
+}
+
+static void
+ephy_local_bookmarks_init (EphyBookmarks *bookmarks)
+{
+ EphyBookmarksPrivate *priv = bookmarks->priv;
+ GaClient *ga_client;
+
+ ga_client = ga_client_new (GA_CLIENT_FLAG_NO_FAIL);
+ g_signal_connect (ga_client, "state-changed",
+ G_CALLBACK (ga_client_state_changed_cb),
+ bookmarks);
+ if (!ga_client_start (ga_client, NULL))
+ {
+ g_warning ("Unable to start Zeroconf subsystem");
+ return;
+ }
+ priv->ga_client = ga_client;
+ priv->resolve_handles = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+static void
ephy_local_bookmarks_stop (EphyBookmarks *bookmarks)
{
EphyBookmarksPrivate *priv = bookmarks->priv;
@@ -1036,7 +1207,6 @@ ephy_local_bookmarks_stop (EphyBookmarks *bookmarks)
{
if (priv->browse_handles[i] != NULL)
{
- gnome_vfs_dns_sd_stop_browse (priv->browse_handles[i]);
priv->browse_handles[i] = NULL;
}
}
@@ -1051,6 +1221,12 @@ ephy_local_bookmarks_stop (EphyBookmarks *bookmarks)
{
ephy_node_remove_child (priv->keywords, priv->local);
}
+
+ if (priv->ga_client != NULL)
+ {
+ g_object_unref (priv->ga_client);
+ priv->ga_client = NULL;
+ }
}
#endif /* ENABLE_ZEROCONF */
@@ -1569,7 +1745,7 @@ impl_resolve_address (EphyBookmarks *eb,
}
else
{
- escaped_arg = gnome_vfs_escape_string (arg);
+ escaped_arg = g_uri_escape_string (arg, NULL, TRUE);
g_string_append (result, escaped_arg);
g_free (escaped_arg);
g_free (arg);
@@ -1579,7 +1755,7 @@ impl_resolve_address (EphyBookmarks *eb,
}
else
{
- arg = gnome_vfs_escape_string (content);
+ arg = g_uri_escape_string (content, NULL, TRUE);
g_string_append (result, arg);
g_free (arg);
}