From f8875b2649a0f85624e0da7df96fa6d47840c4a9 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 1 Dec 2008 09:24:00 +0000 Subject: Added. Added. Added. Added. 2008-12-01 Alexander Larsson * common/Makefile.am: * common/gvfsdnssdresolver.c: Added. * common/gvfsdnssdresolver.h: Added. * common/gvfsdnssdutils.c: Added. * common/gvfsdnssdutils.h: Added. * daemon/Makefile.am: * daemon/dav+sd.mount.in: Added. * daemon/dav.mount.in: * daemon/gvfsbackenddav.c: * daemon/gvfsbackenddnssd.c: * daemon/gvfsbackendnetwork.c: For references to dns-sd dav services, use a dav+sd: uri, since this is stable over e.g. port changes and as such work better in e.g. bookmarks. Patch from David Zeuthen (#555436) svn path=/trunk/; revision=2112 --- daemon/Makefile.am | 18 +++- daemon/dav+sd.mount.in | 4 + daemon/dav.mount.in | 2 +- daemon/gvfsbackenddav.c | 152 ++++++++++++++++++++++++++++-- daemon/gvfsbackenddnssd.c | 218 ++++++++++++++++++++++++++++---------------- daemon/gvfsbackendnetwork.c | 2 +- 6 files changed, 307 insertions(+), 89 deletions(-) create mode 100644 daemon/dav+sd.mount.in (limited to 'daemon') diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 653018b8..035be2c1 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -42,6 +42,9 @@ mount_DATA = sftp.mount trash.mount computer.mount burn.mount localtest.mount mount_in_files += http.mount.in dav.mount.in ftp.mount.in if HAVE_HTTP mount_DATA += http.mount dav.mount ftp.mount +if HAVE_AVAHI +mount_DATA += dav+sd.mount +endif libexec_PROGRAMS += gvfsd-http gvfsd-dav gvfsd-ftp endif @@ -304,7 +307,7 @@ gvfsd_dnssd_CPPFLAGS = \ $(AVAHI_CFLAGS) \ -DBACKEND_TYPES='"dns-sd", G_VFS_TYPE_BACKEND_DNS_SD,' -gvfsd_dnssd_LDADD = $(libraries) $(AVAHI_LIBS) +gvfsd_dnssd_LDADD = $(libraries) $(AVAHI_LIBS) $(top_builddir)/common/libgvfscommon-dnssd.la gvfsd_archive_SOURCES = \ @@ -391,8 +394,15 @@ gvfsd_dav_CPPFLAGS = \ -DBACKEND_HEADER=gvfsbackenddav.h \ -DDEFAULT_BACKEND_TYPE=dav \ -DMAX_JOB_THREADS=1 \ - $(HTTP_CFLAGS) \ - -DBACKEND_TYPES='"dav", G_VFS_TYPE_BACKEND_DAV,' + $(HTTP_CFLAGS) -gvfsd_dav_LDADD = $(libraries) $(HTTP_LIBS) +if HAVE_AVAHI +gvfsd_dav_CPPFLAGS += -DBACKEND_TYPES='"dav", G_VFS_TYPE_BACKEND_DAV, "dav+sd", G_VFS_TYPE_BACKEND_DAV, "davs+sd", G_VFS_TYPE_BACKEND_DAV,' +else +gvfsd_dav_CPPFLAGS += -DBACKEND_TYPES='"dav", G_VFS_TYPE_BACKEND_DAV,' +endif +gvfsd_dav_LDADD = $(libraries) $(HTTP_LIBS) +if HAVE_AVAHI +gvfsd_dav_LDADD += $(top_builddir)/common/libgvfscommon-dnssd.la +endif diff --git a/daemon/dav+sd.mount.in b/daemon/dav+sd.mount.in new file mode 100644 index 00000000..45703270 --- /dev/null +++ b/daemon/dav+sd.mount.in @@ -0,0 +1,4 @@ +[Mount] +Type=dav+sd;davs+sd +Exec=@libexecdir@/gvfsd-dav +AutoMount=false diff --git a/daemon/dav.mount.in b/daemon/dav.mount.in index 6e75bce7..6324625c 100644 --- a/daemon/dav.mount.in +++ b/daemon/dav.mount.in @@ -1,4 +1,4 @@ [Mount] -Type=dav +Type=dav;davs Exec=@libexecdir@/gvfsd-dav AutoMount=false diff --git a/daemon/gvfsbackenddav.c b/daemon/gvfsbackenddav.c index 24c2b34c..a693ac90 100644 --- a/daemon/gvfsbackenddav.c +++ b/daemon/gvfsbackenddav.c @@ -61,10 +61,20 @@ #include "soup-input-stream.h" #include "soup-output-stream.h" +#ifdef HAVE_AVAHI +#include "gvfsdnssdutils.h" +#include "gvfsdnssdresolver.h" +#endif + typedef struct _MountAuthData MountAuthData; static void mount_auth_info_free (MountAuthData *info); + +#ifdef HAVE_AVAHI +static void dns_sd_resolver_changed (GVfsDnsSdResolver *resolver, GVfsBackendDav *dav_backend); +#endif + typedef struct _AuthInfo { /* for server authentication */ @@ -91,6 +101,11 @@ struct _GVfsBackendDav GVfsBackendHttp parent_instance; MountAuthData auth_info; + +#ifdef HAVE_AVAHI + /* only set if we're handling a [dav|davs]+sd:// mounts */ + GVfsDnsSdResolver *resolver; +#endif }; G_DEFINE_TYPE (GVfsBackendDav, g_vfs_backend_dav, G_VFS_TYPE_BACKEND_HTTP); @@ -102,6 +117,14 @@ g_vfs_backend_dav_finalize (GObject *object) dav_backend = G_VFS_BACKEND_DAV (object); +#ifdef HAVE_AVAHI + if (dav_backend->resolver != NULL) + { + g_signal_handlers_disconnect_by_func (dav_backend->resolver, dns_sd_resolver_changed, dav_backend); + g_object_unref (dav_backend->resolver); + } +#endif + mount_auth_info_free (&(dav_backend->auth_info)); if (G_OBJECT_CLASS (g_vfs_backend_dav_parent_class)->finalize) @@ -209,10 +232,10 @@ path_equal (const char *a, const char *b, gboolean relax) a_len = strlen (a); b_len = strlen (b); - while (a[a_len - 1] == '/') + while (a_len > 0 && a[a_len - 1] == '/') a_len--; - while (b[b_len - 1] == '/') + while (b_len > 0 && b[b_len - 1] == '/') b_len--; if (a_len == b_len) @@ -1392,11 +1415,32 @@ g_mount_spec_to_dav_uri (GMountSpec *spec) } static GMountSpec * -g_mount_spec_from_dav_uri (SoupURI *uri) +g_mount_spec_from_dav_uri (GVfsBackendDav *dav_backend, + SoupURI *uri) { GMountSpec *spec; const char *ssl; +#ifdef HAVE_AVAHI + if (dav_backend->resolver != NULL) + { + const char *type; + const char *service_type; + + service_type = g_vfs_dns_sd_resolver_get_service_type (dav_backend->resolver); + if (strcmp (service_type, "_webdavs._tcp") == 0) + type = "davs+sd"; + else + type = "dav+sd"; + + spec = g_mount_spec_new (type); + g_mount_spec_set (spec, + "host", + g_vfs_dns_sd_resolver_get_encoded_triple (dav_backend->resolver)); + return spec; + } +#endif + spec = g_mount_spec_new ("dav"); g_mount_spec_set (spec, "host", uri->host); @@ -1423,6 +1467,63 @@ g_mount_spec_from_dav_uri (SoupURI *uri) return spec; } +#ifdef HAVE_AVAHI +static SoupURI * +dav_uri_from_dns_sd_resolver (GVfsBackendDav *dav_backend) +{ + SoupURI *uri; + char *user; + char *path; + char *address; + const char *service_type; + guint port; + + service_type = g_vfs_dns_sd_resolver_get_service_type (dav_backend->resolver); + address = g_vfs_dns_sd_resolver_get_address (dav_backend->resolver); + port = g_vfs_dns_sd_resolver_get_port (dav_backend->resolver); + user = g_vfs_dns_sd_resolver_lookup_txt_record (dav_backend->resolver, "u"); /* mandatory */ + path = g_vfs_dns_sd_resolver_lookup_txt_record (dav_backend->resolver, "path"); /* optional */ + + /* TODO: According to http://www.dns-sd.org/ServiceTypes.html + * there's also a TXT record "p" for password. Handle this. + */ + + uri = soup_uri_new (NULL); + + if (strcmp (service_type, "_webdavs._tcp") == 0) + soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTPS); + else + soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP); + + soup_uri_set_user (uri, user); + + soup_uri_set_port (uri, port); + + soup_uri_set_host (uri, address); + + if (path != NULL) + soup_uri_set_path (uri, path); + else + soup_uri_set_path (uri, "/"); + + + g_free (address); + g_free (user); + g_free (path); + + return uri; +} +#endif + +#ifdef HAVE_AVAHI +static void +dns_sd_resolver_changed (GVfsDnsSdResolver *resolver, + GVfsBackendDav *dav_backend) +{ + /* TODO: handle when DNS-SD data changes */ +} +#endif + /* ************************************************************************* */ /* Backend Functions */ static void @@ -1432,6 +1533,7 @@ do_mount (GVfsBackend *backend, GMountSource *mount_source, gboolean is_automount) { + GVfsBackendDav *dav_backend = G_VFS_BACKEND_DAV (backend); MountAuthData *data; SoupSession *session; SoupMessage *msg_opts; @@ -1444,10 +1546,43 @@ do_mount (GVfsBackend *backend, gboolean res; char *last_good_path; char *display_name; + const char *host; + const char *type; g_print ("+ mount\n"); - mount_base = g_mount_spec_to_dav_uri (mount_spec); + host = g_mount_spec_get (mount_spec, "host"); + type = g_mount_spec_get (mount_spec, "type"); + +#ifdef HAVE_AVAHI + /* resolve DNS-SD style URIs */ + if ((strcmp (type, "dav+sd") == 0 || strcmp (type, "davs+sd") == 0) && host != NULL) + { + GError *error; + + dav_backend->resolver = g_vfs_dns_sd_resolver_new_for_encoded_triple (host, "u"); + + error = NULL; + if (!g_vfs_dns_sd_resolver_resolve_sync (dav_backend->resolver, + NULL, + &error)) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); + return; + } + g_signal_connect (dav_backend->resolver, + "changed", + (GCallback) dns_sd_resolver_changed, + dav_backend); + + mount_base = dav_uri_from_dns_sd_resolver (dav_backend); + } + else +#endif + { + mount_base = g_mount_spec_to_dav_uri (mount_spec); + } if (mount_base == NULL) { @@ -1546,12 +1681,17 @@ do_mount (GVfsBackend *backend, mount_base->path = last_good_path; /* dup the mountspec, but only copy known fields */ - mount_spec = g_mount_spec_from_dav_uri (mount_base); + mount_spec = g_mount_spec_from_dav_uri (dav_backend, mount_base); g_vfs_backend_set_mount_spec (backend, mount_spec); g_vfs_backend_set_icon_name (backend, "folder-remote"); - display_name = g_strdup_printf (_("WebDAV on %s"), mount_base->host); +#ifdef HAVE_AVAHI + if (dav_backend->resolver != NULL) + display_name = g_strdup (g_vfs_dns_sd_resolver_get_service_name (dav_backend->resolver)); + else +#endif + display_name = g_strdup_printf (_("WebDAV on %s"), mount_base->host); g_vfs_backend_set_display_name (backend, display_name); g_free (display_name); diff --git a/daemon/gvfsbackenddnssd.c b/daemon/gvfsbackenddnssd.c index 3a224a50..9ef21eaa 100644 --- a/daemon/gvfsbackenddnssd.c +++ b/daemon/gvfsbackenddnssd.c @@ -37,6 +37,7 @@ #include #include "gvfsbackenddnssd.h" +#include "gvfsdnssdutils.h" #include "gvfsdaemonprotocol.h" #include "gvfsjobcreatemonitor.h" @@ -45,15 +46,40 @@ #include "gvfsmonitor.h" static struct { - char *type; - char *method; - char *icon; - gpointer handle; + char *type; + char *method; + gboolean use_dns_sd_uri; + char *icon; } 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"}, + { + "_ftp._tcp", + "ftp", + FALSE, + "folder-remote-ftp" + }, + { + "_webdav._tcp", + "dav+sd", + TRUE, + "folder-remote-dav" + }, + { + "_webdavs._tcp", + "davs+sd", + TRUE, + "folder-remote-davs"}, + { + "_sftp-ssh._tcp", + "sftp", + FALSE, + "folder-remote-ssh" + }, + { + "_ssh._tcp", + "sftp", + FALSE, + "folder-remote-ssh" + }, }; static AvahiClient *global_client = NULL; @@ -62,15 +88,19 @@ static gboolean avahi_initialized = FALSE; static GList *dnssd_backends = NULL; typedef struct { - char *file_name; + char *file_name; char *name; char *type; + char *domain; char *target_uri; + GIcon *icon; } LinkFile; static LinkFile root = { "/" }; +static gboolean resolver_supports_mdns = FALSE; + struct _GVfsBackendDnsSd { GVfsBackend parent_instance; @@ -164,7 +194,7 @@ get_icon_for_type (const char *type) 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_with_default_fallbacks (dns_sd_types[i].icon); } return g_themed_icon_new ("text-x-generic"); @@ -184,34 +214,18 @@ get_method_for_type (const char *type) return NULL; } -static char * -encode_filename (const char *service, - const char *type) +static gboolean +use_dns_sd_uri_for_type (const char *type) { - GString *string; - const char *p; - - string = g_string_new (NULL); - - p = service; - - while (*p) + int i; + + for (i = 0; i < G_N_ELEMENTS (dns_sd_types); i++) { - 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++; + if (strcmp (type, dns_sd_types[i].type) == 0) + return dns_sd_types[i].use_dns_sd_uri; } - - g_string_append_c (string, '.'); - g_string_append (string, type); - - return g_string_free (string, FALSE); + + return FALSE; } static LinkFile * @@ -225,56 +239,89 @@ link_file_new (const char *name, AvahiStringList *txt) { LinkFile *file; - char *path, *user, *user_str; - AvahiStringList *path_l, *user_l; char a[128]; const char *method; - + char *uri; + file = g_slice_new0 (LinkFile); file->name = g_strdup (name); file->type = g_strdup (type); - file->file_name = encode_filename (name, type); + file->domain = g_strdup (domain); 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 ("/"); - + uri = g_vfs_get_dns_sd_uri_for_triple (name, type, domain); + file->file_name = g_path_get_basename (uri); + g_free (uri); + 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); + if (use_dns_sd_uri_for_type (type)) + { + char *encoded_triple; + encoded_triple = g_vfs_encode_dns_sd_triple (name, type, domain); + file->target_uri = g_strdup_printf ("%s://%s", + method, + encoded_triple); + g_free (encoded_triple); + } 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); + { + char *path, *user, *user_str; + AvahiStringList *path_l, *user_l; + + 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 ("/"); + + if (resolver_supports_mdns) + { + file->target_uri = g_strdup_printf ("%s://%s%s:%d%s", + method, + user_str != NULL ? user_str : "", + host_name, port, path); + } + else + { + 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; } @@ -285,6 +332,7 @@ link_file_free (LinkFile *file) g_free (file->file_name); g_free (file->name); g_free (file->type); + g_free (file->domain); g_free (file->target_uri); if (file->icon) @@ -357,7 +405,7 @@ file_info_from_file (LinkFile *file, g_file_info_set_name (info, file->file_name); g_file_info_set_display_name (info, file->name); - if (file->icon) + if (file->icon) g_file_info_set_icon (info, file->icon); g_file_info_set_file_type (info, G_FILE_TYPE_SHORTCUT); @@ -366,8 +414,7 @@ file_info_from_file (LinkFile *file, 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); + g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, file->target_uri); } /* Backend Functions */ @@ -427,13 +474,28 @@ try_query_info (GVfsBackend *backend, if (file == &root) { GIcon *icon; + char *display_name; + char *s; + + s = g_strdup (job->uri); + if (s[strlen(s) - 1] == '/') /* job->uri is guranteed to be longer than 1 byte */ + s[strlen(s) - 1] = '\0'; + display_name = g_path_get_basename (s); + if (strcmp (display_name, "local") == 0) + { + g_free (display_name); + display_name = g_strdup (_("Local Network")); + } + g_free (s); + 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")); + g_file_info_set_display_name (info, display_name); icon = g_themed_icon_new ("network-workgroup"); g_file_info_set_icon (info, icon); g_object_unref (icon); + g_free (display_name); + 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); @@ -689,6 +751,8 @@ g_vfs_backend_dns_sd_init (GVfsBackendDnsSd *network_backend) g_vfs_backend_set_icon_name (backend, "network-workgroup"); g_vfs_backend_set_user_visible (backend, FALSE); + resolver_supports_mdns = (avahi_nss_support () > 0); + } static void diff --git a/daemon/gvfsbackendnetwork.c b/daemon/gvfsbackendnetwork.c index d23438e7..939461e3 100644 --- a/daemon/gvfsbackendnetwork.c +++ b/daemon/gvfsbackendnetwork.c @@ -411,7 +411,7 @@ recompute_files (GVfsBackendNetwork *backend) file = network_file_new (file_name, domains[i], link_uri, - backend->server_icon); + backend->workgroup_icon); files = g_list_prepend (files, file); g_free (link_uri); g_free (file_name); -- cgit v1.2.1