diff options
Diffstat (limited to 'common/gvfsdnssdutils.c')
-rw-r--r-- | common/gvfsdnssdutils.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/common/gvfsdnssdutils.c b/common/gvfsdnssdutils.c new file mode 100644 index 00000000..f6592e1a --- /dev/null +++ b/common/gvfsdnssdutils.c @@ -0,0 +1,323 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2008 Red Hat, Inc. + * + * 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 Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: David Zeuthen <davidz@redhat.com> + */ + +#include <config.h> +#include <string.h> +#include <glib/gi18n-lib.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 "gvfsdnssdutils.h" + +static gchar * +escape_service_name (const gchar *service_name) +{ + GString *s; + char *res; + const gchar *p; + + g_return_val_if_fail (service_name != NULL, NULL); + + s = g_string_new (NULL); + + p = service_name; + while (*p != '\0') + { + if (*p == '\\') + g_string_append (s, "\\\\"); + else if (*p == '.') + g_string_append (s, "\\."); + else if (*p == '/') + g_string_append (s, "\\s"); + else + g_string_append_c (s, *p); + p++; + } + + res = g_uri_escape_string (s->str, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE); + g_string_free (s, TRUE); + return res; +} + +static gchar * +escape_service_name2 (const gchar *service_name) +{ + GString *s; + const gchar *p; + + g_return_val_if_fail (service_name != NULL, NULL); + + s = g_string_new (NULL); + + p = service_name; + while (*p != '\0') + { + if (*p == '.') + g_string_append (s, "%2e"); + else + g_string_append_c (s, *p); + p++; + } + + return g_string_free (s, FALSE); +} + +/** + * g_vfs_get_dns_sd_uri_for_triple: + * @service_name: DNS-SD service name. + * @service_type: DNS-SD service type. + * @domain: DNS-SD domain. + * + * Creates an URI for a file on the GVfs <literal>dns-sd</literal> + * virtual file system that provides live data for resolving the given + * DNS-SD service. + * + * The URI is of the form + * <literal>dns-sd://domain/service_name.service_type<literal> with + * suitable encoding added. + * + * Note that there may not exist a file at the returned URI, the + * resource providing the DNS-SD service will have to be available for + * the file to exist. + * + * Returns: An URI. Free with g_free(). + **/ +gchar * +g_vfs_get_dns_sd_uri_for_triple (const gchar *service_name, + const gchar *service_type, + const gchar *domain) +{ + gchar *escaped_service_name; + gchar *ret; + + g_return_val_if_fail (service_name != NULL, NULL); + g_return_val_if_fail (service_type != NULL, NULL); + g_return_val_if_fail (domain != NULL, NULL); + + escaped_service_name = escape_service_name (service_name); + + ret = g_strdup_printf ("dns-sd://%s/%s.%s", + domain, + escaped_service_name, + service_type); + g_free (escaped_service_name); + + return ret; +} + +/** + * g_vfs_encode_dns_sd_triple: + * @service_name: DNS-SD service name. + * @service_type: DNS-SD service type. + * @domain: DNS-SD domain. + * + * Creates an encoded triple representing a DNS-SD service. The triple + * will be of the form + * <literal>service_name.service_type.domain</literal> with suitable + * encoding. + * + * Use g_vfs_decode_dns_sd_triple() to decode the returned string. + * + * Returns: A string representing the triple, free with g_free(). + **/ +gchar * +g_vfs_encode_dns_sd_triple (const gchar *service_name, + const gchar *service_type, + const gchar *domain) +{ + char *dot_escaped_service_name; + char *escaped_service_name; + char *escaped_service_type; + char *escaped_domain; + char *s; + + escaped_service_name = g_uri_escape_string (service_name, NULL, FALSE); + dot_escaped_service_name = escape_service_name2 (escaped_service_name); + escaped_service_type = g_uri_escape_string (service_type, NULL, FALSE); + escaped_domain = g_uri_escape_string (domain, NULL, FALSE); + s = g_strdup_printf ("%s.%s.%s", + dot_escaped_service_name, + escaped_service_type, + escaped_domain); + g_free (dot_escaped_service_name); + g_free (escaped_service_name); + g_free (escaped_service_type); + g_free (escaped_domain); + return s; +} + +/** + * g_vfs_decode_dns_sd_triple: + * @encoded_triple: A string obtained from g_vfs_encode_dns_sd_triple(). + * @out_service_name: %NULL or return location for the service name. + * @out_service_type: %NULL or return location for the service type. + * @out_domain: %NULL or return location for the domain. + * @error: Return location for error or %NULL. + * + * Constructs a DNS-SD triple by decoding a string generated from + * g_vfs_encode_dns_sd_triple(). This can fail if @encoded_triple is + * malformed. + * + * Returns: %TRUE unless @error is set. + **/ +gboolean +g_vfs_decode_dns_sd_triple (const gchar *encoded_triple, + gchar **out_service_name, + gchar **out_service_type, + gchar **out_domain, + GError **error) +{ + gboolean ret; + int n; + int m; + int service_type_pos; + char *escaped_service_name; + char *escaped_service_type; + char *escaped_domain; + + g_return_val_if_fail (encoded_triple != NULL, FALSE); + + + escaped_service_name = NULL; + escaped_service_type = NULL; + escaped_domain = NULL; + ret = FALSE; + + if (out_service_name != NULL) + *out_service_name = NULL; + + if (out_service_type != NULL) + *out_service_type = NULL; + + if (out_domain != NULL) + *out_domain = NULL; + + /* Find first '.' followed by an underscore. */ + for (n = 0; encoded_triple[n] != '\0'; n++) + { + if (encoded_triple[n] == '.') + { + if (encoded_triple[n + 1] == '_') + break; + } + } + if (encoded_triple[n] == '\0') + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Malformed dns-sd encoded_triple '%s'"), + encoded_triple); + goto out; + } + + escaped_service_name = g_strndup (encoded_triple, n); + if (escaped_service_name == NULL) + goto out; + + if (out_service_name != NULL) + *out_service_name = g_uri_unescape_string (escaped_service_name, NULL); + + /* skip dot between service name and service type */ + n += 1; + + service_type_pos = n; + + /* skip next two dots */ + for (m = 0; m < 2; m++) + { + for (; encoded_triple[n] != '\0'; n++) + { + if (encoded_triple[n] == '.') + break; + } + if (encoded_triple[n] == '\0') + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Malformed dns-sd encoded_triple '%s'"), + encoded_triple); + goto out; + } + n++; + } + + escaped_service_type = g_strndup (encoded_triple + service_type_pos, n - service_type_pos - 1); + if (out_service_type != NULL) + *out_service_type = g_uri_unescape_string (escaped_service_type, NULL); + + /* the domain is the rest */ + if (encoded_triple[n] == '\0') + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Malformed dns-sd encoded_triple '%s'"), + encoded_triple); + goto out; + } + + escaped_domain = g_strdup (encoded_triple + n); + if (out_domain != NULL) + *out_domain = g_uri_unescape_string (escaped_domain, NULL); + + ret = TRUE; + + out: + g_free (escaped_service_name); + g_free (escaped_service_type); + g_free (escaped_domain); + return ret; +} + +gchar * +g_vfs_normalize_encoded_dns_sd_triple (const gchar *encoded_triple) +{ + char *service_name; + char *service_type; + char *domain; + char *ret; + + ret = NULL; + + if (!g_vfs_decode_dns_sd_triple (encoded_triple, + &service_name, + &service_type, + &domain, + NULL)) + goto out; + + ret = g_vfs_encode_dns_sd_triple (service_name, service_type, domain); + g_free (service_name); + g_free (service_type); + g_free (domain); + + out: + return ret; +} + |