/* 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 */ #include #include #include #include #include #include #include #include #include #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 dns-sd * virtual file system that provides live data for resolving the given * DNS-SD service. * * The URI is of the form * dns-sd://domain/service_name.service_type 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 * service_name.service_type.domain 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; }