summaryrefslogtreecommitdiff
path: root/daemon/gvfsbackenddnssd.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/gvfsbackenddnssd.c')
-rw-r--r--daemon/gvfsbackenddnssd.c731
1 files changed, 0 insertions, 731 deletions
diff --git a/daemon/gvfsbackenddnssd.c b/daemon/gvfsbackenddnssd.c
deleted file mode 100644
index 3a224a50..00000000
--- a/daemon/gvfsbackenddnssd.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/* GIO - GLib Input, Output and Streaming Library
- * Original work, Copyright (C) 2003 Red Hat, Inc
- * GVFS port, Copyright (c) 2008 Andrew Walton.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with the Gnome Library; see the file COPYING.LIB. If not,
- * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Authors:
- * Alexander Larsson <alexl@redhat.com>
- */
-
-#include <config.h>
-
-#include <string.h>
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <glib/gurifuncs.h>
-#include <gio/gio.h>
-
-#include <avahi-client/client.h>
-#include <avahi-client/lookup.h>
-#include <avahi-common/error.h>
-#include <avahi-common/timeval.h>
-#include <avahi-glib/glib-watch.h>
-#include <avahi-glib/glib-malloc.h>
-
-#include "gvfsbackenddnssd.h"
-
-#include "gvfsdaemonprotocol.h"
-#include "gvfsjobcreatemonitor.h"
-#include "gvfsjobenumerate.h"
-#include "gvfsjobqueryinfo.h"
-#include "gvfsmonitor.h"
-
-static struct {
- char *type;
- char *method;
- char *icon;
- gpointer handle;
-} dns_sd_types[] = {
- {"_ftp._tcp", "ftp", "folder-remote-ftp"},
- {"_webdav._tcp", "dav", "folder-remote"},
- {"_webdavs._tcp", "davs", "folder-remote"},
- {"_sftp-ssh._tcp", "sftp", "folder-remote-ssh"},
-};
-
-static AvahiClient *global_client = NULL;
-static gboolean avahi_initialized = FALSE;
-
-static GList *dnssd_backends = NULL;
-
-typedef struct {
- char *file_name;
- char *name;
- char *type;
- char *target_uri;
- GIcon *icon;
-} LinkFile;
-
-static LinkFile root = { "/" };
-
-struct _GVfsBackendDnsSd
-{
- GVfsBackend parent_instance;
- GVfsMonitor *root_monitor;
- char *domain;
- GMountSpec *mount_spec;
- GList *files; /* list of LinkFiles */
-
- GList *browsers;
-};
-
-typedef struct _GVfsBackendDnsSd GVfsBackendDnsSd;
-
-G_DEFINE_TYPE (GVfsBackendDnsSd, g_vfs_backend_dns_sd, G_VFS_TYPE_BACKEND)
-
-static void add_browsers (GVfsBackendDnsSd *backend);
-static void remove_browsers (GVfsBackendDnsSd *backend);
-static AvahiClient *get_global_avahi_client (void);
-
-/* Callback for state changes on the Client */
-static void
-avahi_client_callback (AvahiClient *client, AvahiClientState state, void *userdata)
-{
- /* We need to set this early, as the add_browsers call below may reenter
- when this is called from the client creation call */
- if (global_client == NULL)
- global_client = client;
-
- if (state == AVAHI_CLIENT_FAILURE)
- {
- if (avahi_client_errno (client) == AVAHI_ERR_DISCONNECTED)
- {
- /* Remove the service browsers from the handles */
- g_list_foreach (dnssd_backends, (GFunc)remove_browsers, NULL);
-
- /* Destroy old client */
- avahi_client_free (client);
- global_client = NULL;
- avahi_initialized = FALSE;
-
- /* Reconnect */
- get_global_avahi_client ();
- }
- }
- else if (state == AVAHI_CLIENT_S_RUNNING)
- {
- /* Start browsing again */
- g_list_foreach (dnssd_backends, (GFunc)add_browsers, NULL);
- }
-}
-
-static AvahiClient *
-get_global_avahi_client (void)
-{
- static AvahiGLibPoll *glib_poll = NULL;
- int error;
-
- if (!avahi_initialized)
- {
- avahi_initialized = TRUE;
-
- if (glib_poll == NULL)
- {
- avahi_set_allocator (avahi_glib_allocator ());
- glib_poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
- }
-
- /* Create a new AvahiClient instance */
- global_client = avahi_client_new (avahi_glib_poll_get (glib_poll),
- AVAHI_CLIENT_NO_FAIL,
- avahi_client_callback,
- glib_poll,
- &error);
-
- if (global_client == NULL)
- {
- /* Print out the error string */
- g_warning ("Error initializing Avahi: %s", avahi_strerror (error));
- return NULL;
- }
- }
-
- return global_client;
-}
-
-static GIcon *
-get_icon_for_type (const char *type)
-{
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++)
- {
- if (strcmp (type, dns_sd_types[i].type) == 0)
- return g_themed_icon_new (dns_sd_types[i].icon);
- }
-
- return g_themed_icon_new ("text-x-generic");
-}
-
-static const char *
-get_method_for_type (const char *type)
-{
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++)
- {
- if (strcmp (type, dns_sd_types[i].type) == 0)
- return dns_sd_types[i].method;
- }
-
- return NULL;
-}
-
-static char *
-encode_filename (const char *service,
- const char *type)
-{
- GString *string;
- const char *p;
-
- string = g_string_new (NULL);
-
- p = service;
-
- while (*p)
- {
- if (*p == '\\')
- g_string_append (string, "\\\\");
- else if (*p == '.')
- g_string_append (string, "\\.");
- else if (*p == '/')
- g_string_append (string, "\\s");
- else
- g_string_append_c (string, *p);
- p++;
- }
-
- g_string_append_c (string, '.');
- g_string_append (string, type);
-
- return g_string_free (string, FALSE);
-}
-
-static LinkFile *
-link_file_new (const char *name,
- const char *type,
- const char *domain,
- const char *host_name,
- AvahiProtocol protocol,
- const AvahiAddress *address,
- uint16_t port,
- AvahiStringList *txt)
-{
- LinkFile *file;
- char *path, *user, *user_str;
- AvahiStringList *path_l, *user_l;
- char a[128];
- const char *method;
-
- file = g_slice_new0 (LinkFile);
-
- file->name = g_strdup (name);
- file->type = g_strdup (type);
- file->file_name = encode_filename (name, type);
- file->icon = get_icon_for_type (type);
-
-
- path = NULL;
- user_str = NULL;
- if (txt != NULL)
- {
- path_l = avahi_string_list_find (txt, "path");
- if (path_l != NULL)
- avahi_string_list_get_pair (path_l, NULL, &path, NULL);
-
- user_l = avahi_string_list_find (txt, "u");
- if (user_l != NULL)
- {
- avahi_string_list_get_pair (user_l, NULL, &user, NULL);
-
- user_str = g_strconcat (user, "@", NULL);
- }
- }
-
- if (path == NULL)
- path = g_strdup ("/");
-
- avahi_address_snprint (a, sizeof(a), address);
-
- method = get_method_for_type (type);
-
- if (protocol == AVAHI_PROTO_INET6)
- /* an ipv6 address, follow rfc2732 */
- file->target_uri = g_strdup_printf ("%s://%s[%s]:%d%s",
- method,
- user_str?user_str:"",
- a, port, path);
- else
- file->target_uri = g_strdup_printf ("%s://%s%s:%d%s",
- method,
- user_str?user_str:"",
- a, port, path);
- g_free (user_str);
- g_free (path);
-
- return file;
-}
-
-static void
-link_file_free (LinkFile *file)
-{
- g_free (file->file_name);
- g_free (file->name);
- g_free (file->type);
- g_free (file->target_uri);
-
- if (file->icon)
- g_object_unref (file->icon);
-
- g_slice_free (LinkFile, file);
-}
-
-static LinkFile *
-lookup_link_file_by_name_and_type (GVfsBackendDnsSd *backend,
- const char *name,
- const char *type)
-{
- GList *l;
- LinkFile *file;
-
- for (l = backend->files; l != NULL; l = l->next)
- {
- file = l->data;
- if (strcmp (file->name, name) == 0 &&
- strcmp (file->type, type) == 0)
- return file;
- }
-
- return NULL;
-}
-
-static LinkFile *
-lookup_link_file (GVfsBackendDnsSd *backend,
- GVfsJob *job,
- const char *file_name)
-{
- GList *l;
- LinkFile *file;
-
- if (*file_name != '/')
- goto out;
-
- while (*file_name == '/')
- file_name++;
-
- if (*file_name == 0)
- return &root;
-
- if (strchr (file_name, '/') != NULL)
- goto out;
-
- for (l = backend->files; l != NULL; l = l->next)
- {
- file = l->data;
- if (strcmp (file->file_name, file_name) == 0)
- return file;
- }
-
- out:
- g_vfs_job_failed (job, G_IO_ERROR,
- G_IO_ERROR_NOT_FOUND,
- _("File doesn't exist"));
-
- return NULL;
-}
-
-
-static void
-file_info_from_file (LinkFile *file,
- GFileInfo *info)
-{
- g_return_if_fail (file != NULL || info != NULL);
-
- g_file_info_set_name (info, file->file_name);
- g_file_info_set_display_name (info, file->name);
-
- if (file->icon)
- g_file_info_set_icon (info, file->icon);
-
- g_file_info_set_file_type (info, G_FILE_TYPE_SHORTCUT);
- g_file_info_set_size(info, 0);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VIRTUAL, TRUE);
- g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI,
- file->target_uri);
-}
-
-/* Backend Functions */
-static gboolean
-try_enumerate (GVfsBackend *backend,
- GVfsJobEnumerate *job,
- const char *file_name,
- GFileAttributeMatcher *attribute_matcher,
- GFileQueryInfoFlags flags)
-{
- LinkFile *file;
- GList *l;
- GFileInfo *info;
-
- file = lookup_link_file (G_VFS_BACKEND_DNS_SD (backend),
- G_VFS_JOB (job), file_name);
-
- if (file != &root)
- {
- if (file != NULL)
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
- G_IO_ERROR_NOT_DIRECTORY,
- _("The file is not a directory"));
- return TRUE;
- }
-
- g_vfs_job_succeeded (G_VFS_JOB(job));
-
- /* Enumerate root */
- for (l = G_VFS_BACKEND_DNS_SD (backend)->files; l != NULL; l = l->next)
- {
- file = l->data;
- info = g_file_info_new ();
- file_info_from_file (file, info);
- g_vfs_job_enumerate_add_info (job, info);
- g_object_unref (info);
- }
-
- g_vfs_job_enumerate_done (job);
-
- return TRUE;
-}
-
-static gboolean
-try_query_info (GVfsBackend *backend,
- GVfsJobQueryInfo *job,
- const char *file_name,
- GFileQueryInfoFlags flags,
- GFileInfo *info,
- GFileAttributeMatcher *matcher)
-{
- LinkFile *file;
-
- file = lookup_link_file (G_VFS_BACKEND_DNS_SD (backend),
- G_VFS_JOB (job), file_name);
-
- if (file == &root)
- {
- GIcon *icon;
- g_file_info_set_name (info, "/");
- g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
- /* TODO: Name */
- g_file_info_set_display_name (info, _("dns-sd"));
- icon = g_themed_icon_new ("network-workgroup");
- g_file_info_set_icon (info, icon);
- g_object_unref (icon);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
- g_file_info_set_content_type (info, "inode/directory");
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
- else if (file != NULL)
- {
- file_info_from_file (file, info);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
-
- return TRUE;
-}
-
-
-static void
-resolve_callback (AvahiServiceResolver *r,
- AvahiIfIndex interface,
- AvahiProtocol protocol,
- AvahiResolverEvent event,
- const char *name,
- const char *type,
- const char *domain,
- const char *host_name,
- const AvahiAddress *address,
- uint16_t port,
- AvahiStringList *txt,
- AvahiLookupResultFlags flags,
- void *userdata)
-{
- GVfsBackendDnsSd *backend = userdata;
- LinkFile *file;
- char *path;
-
- if (event == AVAHI_RESOLVER_FAILURE)
- return;
-
- /* Link-local ipv6 address, can't make a uri from this, ignore */
- if (address->proto == AVAHI_PROTO_INET6 &&
- address->data.ipv6.address[0] == 0xfe &&
- address->data.ipv6.address[1] == 0x80)
- return;
-
- file = lookup_link_file_by_name_and_type (backend,
- name, type);
-
- if (file != NULL)
- return;
-
- file = link_file_new (name, type, domain, host_name, protocol,
- address, port, txt);
-
- backend->files = g_list_prepend (backend->files, file);
-
- path = g_strconcat ("/", file->file_name, NULL);
- g_vfs_monitor_emit_event (backend->root_monitor,
- G_FILE_MONITOR_EVENT_CREATED,
- path,
- NULL);
- g_free (path);
-}
-
-static void
-browse_callback (AvahiServiceBrowser *b,
- AvahiIfIndex interface,
- AvahiProtocol protocol,
- AvahiBrowserEvent event,
- const char *name,
- const char *type,
- const char *domain,
- AvahiLookupResultFlags flags,
- void *userdata)
-{
- GVfsBackendDnsSd *backend = userdata;
- AvahiServiceResolver *sr;
- AvahiClient *client;
- LinkFile *file;
- char *path;
-
- switch (event)
- {
- case AVAHI_BROWSER_FAILURE:
- break;
-
- case AVAHI_BROWSER_NEW:
- client = get_global_avahi_client ();
-
- /* We ignore the returned resolver object. In the callback
- function we free it. If the server is terminated before
- the callback function is called the server will free
- the resolver for us. */
-
- sr = avahi_service_resolver_new (client, interface, protocol,
- name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, backend);
-
- if (sr == NULL)
- g_warning ("Failed to resolve service name '%s': %s\n", name, avahi_strerror (avahi_client_errno (client)));
-
- break;
-
- case AVAHI_BROWSER_REMOVE:
- file = lookup_link_file_by_name_and_type (backend,
- name, type);
-
- if (file != NULL)
- {
- backend->files = g_list_remove (backend->files, file);
-
- path = g_strconcat ("/", file->file_name, NULL);
- g_vfs_monitor_emit_event (backend->root_monitor,
- G_FILE_MONITOR_EVENT_DELETED,
- path,
- NULL);
- g_free (path);
-
- link_file_free (file);
- }
-
- break;
-
- case AVAHI_BROWSER_ALL_FOR_NOW:
- case AVAHI_BROWSER_CACHE_EXHAUSTED:
- break;
- }
-}
-
-static void
-browse_type (GVfsBackendDnsSd *backend,
- const char *type)
-{
- AvahiClient *client;
- AvahiServiceBrowser *sb;
- const char *domain;
-
- client = get_global_avahi_client ();
-
- domain = NULL;
- if (strcmp (backend->domain, "local") != 0)
- domain = backend->domain;
-
- sb = avahi_service_browser_new (client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
- type, domain, 0, browse_callback, backend);
-
- if (sb == NULL)
- {
- g_warning ("Failed to create service browser: %s\n", avahi_strerror( avahi_client_errno (client)));
- return;
- }
-
- backend->browsers = g_list_prepend (backend->browsers, sb);
-
-}
-
-static void
-add_browsers (GVfsBackendDnsSd *backend)
-{
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++)
- browse_type (backend, dns_sd_types[i].type);
-}
-
-static void
-remove_browsers (GVfsBackendDnsSd *backend)
-{
- g_list_free (backend->browsers);
- backend->browsers = NULL;
-}
-
-static gboolean
-try_mount (GVfsBackend *backend,
- GVfsJobMount *job,
- GMountSpec *mount_spec,
- GMountSource *mount_source,
- gboolean is_automount)
-{
- GVfsBackendDnsSd *op_backend = G_VFS_BACKEND_DNS_SD (backend);
- GMountSpec *real_mount_spec;
- const char *domain;
-
- domain = g_mount_spec_get (mount_spec, "host");
-
- if (domain == NULL)
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
- "No domain specified for dns-sd share");
- return TRUE;
- }
-
- op_backend->domain = g_strdup (domain);
-
- if (get_global_avahi_client() == NULL)
- {
- g_vfs_job_failed (G_VFS_JOB (job),
- G_IO_ERROR, G_IO_ERROR_FAILED,
- "Unable to initialize avahi");
- return TRUE;
- }
-
- real_mount_spec = g_mount_spec_new ("dns-sd");
- g_mount_spec_set (real_mount_spec, "host", op_backend->domain);
- g_vfs_backend_set_mount_spec (backend, real_mount_spec);
- op_backend->mount_spec = real_mount_spec;
-
- op_backend->root_monitor = g_vfs_monitor_new (backend);
-
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- return TRUE;
-}
-
-/* handles both file and dir monitors,
- * as we really don't "support" (e.g. fire events for) either, yet. */
-static gboolean
-try_create_monitor (GVfsBackend *backend,
- GVfsJobCreateMonitor *job,
- const char *file_name,
- GFileMonitorFlags flags)
-{
- LinkFile *file;
- GVfsBackendDnsSd *network_backend;
-
- network_backend = G_VFS_BACKEND_DNS_SD (backend);
-
- file = lookup_link_file (network_backend, G_VFS_JOB (job), file_name);
-
- if (file != &root)
- {
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Can't monitor file or directory."));
- return TRUE;
- }
-
- g_vfs_job_create_monitor_set_monitor (job, network_backend->root_monitor);
- g_vfs_job_succeeded (G_VFS_JOB (job));
-
- return TRUE;
-}
-
-static void
-g_vfs_backend_dns_sd_init (GVfsBackendDnsSd *network_backend)
-{
- GVfsBackend *backend = G_VFS_BACKEND (network_backend);
-
- dnssd_backends = g_list_prepend (dnssd_backends, backend);
-
- /* TODO: Names, etc */
- g_vfs_backend_set_display_name (backend, _("Dns-SD"));
- g_vfs_backend_set_stable_name (backend, _("Network"));
- g_vfs_backend_set_icon_name (backend, "network-workgroup");
- g_vfs_backend_set_user_visible (backend, FALSE);
-
-}
-
-static void
-g_vfs_backend_dns_sd_finalize (GObject *object)
-{
- GVfsBackendDnsSd *backend;
-
- backend = G_VFS_BACKEND_DNS_SD (object);
-
- dnssd_backends = g_list_remove (dnssd_backends, backend);
-
- if (backend->mount_spec)
- g_mount_spec_unref (backend->mount_spec);
-
- if (backend->root_monitor)
- g_object_unref (backend->root_monitor);
-
- g_free (backend->domain);
-
- g_list_foreach (backend->files, (GFunc)link_file_free, NULL);
-
- if (G_OBJECT_CLASS (g_vfs_backend_dns_sd_parent_class)->finalize)
- (*G_OBJECT_CLASS (g_vfs_backend_dns_sd_parent_class)->finalize) (object);
-}
-
-static void
-g_vfs_backend_dns_sd_class_init (GVfsBackendDnsSdClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
-
- gobject_class->finalize = g_vfs_backend_dns_sd_finalize;
-
- backend_class->try_mount = try_mount;
- backend_class->try_query_info = try_query_info;
- backend_class->try_enumerate = try_enumerate;
- backend_class->try_create_dir_monitor = try_create_monitor;
- backend_class->try_create_file_monitor = try_create_monitor;
-}
-