summaryrefslogtreecommitdiff
path: root/common/gvfsdnssdutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/gvfsdnssdutils.c')
-rw-r--r--common/gvfsdnssdutils.c323
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;
+}
+