mirror of https://gitee.com/openkylin/gvfs.git
324 lines
8.6 KiB
C
324 lines
8.6 KiB
C
/* 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., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, 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;
|
|
}
|
|
|