diff options
Diffstat (limited to 'daemon/gvfsbackenddnssd.c')
-rw-r--r-- | daemon/gvfsbackenddnssd.c | 731 |
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; -} - |