/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* e-url.c * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * * 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. * * 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, see . * * Authors: Jon Trowbridge * Rodrigo Moya */ #include "evolution-data-server-config.h" #include #include #include #include "e-url.h" /** * e_url_shroud: * @url: The url to shroud. * * Removes the moniker (i.e. mailto:) from a url. * * Returns: The newly-allocated shrouded url. **/ gchar * e_url_shroud (const gchar *url) { const gchar *first_colon = NULL; const gchar *last_at = NULL; const gchar *p; gchar *shrouded; if (url == NULL) return NULL; /* Skip past the moniker */ for (p = url; *p && *p != ':'; ++p); if (*p) ++p; while (*p) { if (first_colon == NULL && *p == ':') first_colon = p; if (*p == '@') last_at = p; ++p; } if (first_colon && last_at && first_colon < last_at) { shrouded = g_malloc (first_colon - url + strlen (last_at) + 1); memcpy (shrouded, url, first_colon - url); strcpy (shrouded + (first_colon - url), last_at); } else { shrouded = g_strdup (url); } return shrouded; } /** * e_url_equal: * @url1: The first url to compare. * @url2: The second url to compare. * * Checks two urls for equality, after first removing any monikers on * the urls. * * Returns: %TRUE if the urls are equal, %FALSE if they are not. **/ gboolean e_url_equal (const gchar *url1, const gchar *url2) { gchar *shroud1 = e_url_shroud (url1); gchar *shroud2 = e_url_shroud (url2); gint len1, len2; gboolean rv; if (shroud1 == NULL || shroud2 == NULL) { rv = (shroud1 == shroud2); } else { len1 = strlen (shroud1); len2 = strlen (shroud2); rv = !strncmp (shroud1, shroud2, MIN (len1, len2)); } g_free (shroud1); g_free (shroud2); return rv; } #define HEXVAL(c) (isdigit (c) ? (c) - '0' : tolower (c) - 'a' + 10) static void uri_decode (gchar *part) { guchar *s, *d; s = d = (guchar *) part; while (*s) { if (*s == '%') { if (isxdigit (s[1]) && isxdigit (s[2])) { *d++ = HEXVAL (s[1]) * 16 + HEXVAL (s[2]); s += 3; } else *d++ = *s++; } else *d++ = *s++; } *d = '\0'; } /** * e_uri_new: * @uri_string: The uri to represent as an #EUri. * * Creates an #EUri representation of the uri given in @uri_string. * * Returns: The newly-allocated #EUri structure. **/ EUri * e_uri_new (const gchar *uri_string) { EUri *uri; const gchar *end, *hash, *colon, *semi, *at, *slash, *question; const gchar *p; if (!uri_string) return NULL; uri = g_new0 (EUri, 1); /* find fragment */ end = hash = strchr (uri_string, '#'); if (hash && hash[1]) { uri->fragment = g_strdup (hash + 1); uri_decode (uri->fragment); } else end = uri_string + strlen (uri_string); /* find protocol: initial [a-z+.-]* substring until ":" */ p = uri_string; while (p < end && (isalnum ((guchar) *p) || *p == '.' || *p == '+' || *p == '-')) p++; if (p > uri_string && *p == ':') { uri->protocol = g_ascii_strdown (uri_string, p - uri_string); uri_string = p + 1; } else uri->protocol = g_strdup ("file"); if (!*uri_string) return uri; /* check for authority */ if (strncmp (uri_string, "//", 2) == 0) { uri_string += 2; slash = uri_string + strcspn (uri_string, "/#"); at = strchr (uri_string, '@'); if (at && at < slash) { const gchar *at2; /* this is for cases where username contains '@' at it, like: * http://user@domain.com@server.addr.com/path * We skip all at-s before the slash here. */ while (at2 = strchr (at + 1, '@'), at2 && at2 < slash) { at = at2; } } if (at && at < slash) { colon = strchr (uri_string, ':'); if (colon && colon < at) { uri->passwd = g_strndup (colon + 1, at - colon - 1); uri_decode (uri->passwd); } else { uri->passwd = NULL; colon = at; } semi = strchr (uri_string, ';'); if (semi && semi < colon && !g_ascii_strncasecmp (semi, ";auth=", 6)) { uri->authmech = g_strndup (semi + 6, colon - semi - 6); uri_decode (uri->authmech); } else { uri->authmech = NULL; semi = colon; } uri->user = g_strndup (uri_string, semi - uri_string); uri_decode (uri->user); uri_string = at + 1; } else uri->user = uri->passwd = uri->authmech = NULL; /* find host and port */ colon = strchr (uri_string, ':'); if (colon && colon < slash) { uri->host = g_strndup (uri_string, colon - uri_string); uri->port = strtoul (colon + 1, NULL, 10); } else { uri->host = g_strndup (uri_string, slash - uri_string); uri_decode (uri->host); uri->port = 0; } uri_string = slash; } /* find query */ question = memchr (uri_string, '?', end - uri_string); if (question) { if (question[1]) { uri->query = g_strndup (question + 1, end - (question + 1)); uri_decode (uri->query); } end = question; } /* find parameters */ semi = memchr (uri_string, ';', end - uri_string); if (semi) { if (semi[1]) { const gchar *cur, *ptr, *eq; gchar *name, *value; for (cur = semi + 1; cur < end; cur = ptr + 1) { ptr = memchr (cur, ';', end - cur); if (!ptr) ptr = end; eq = memchr (cur, '=', ptr - cur); if (eq) { name = g_strndup (cur, eq - cur); value = g_strndup (eq + 1, ptr - (eq + 1)); uri_decode (value); } else { name = g_strndup (cur, ptr - cur); value = g_strdup (""); } uri_decode (name); g_datalist_set_data_full ( &uri->params, name, value, g_free); g_free (name); } } end = semi; } if (end != uri_string) { uri->path = g_strndup (uri_string, end - uri_string); uri_decode (uri->path); } return uri; } /** * e_uri_free: * @uri: A pointer to the #EUri to free. * * Frees the memory of an #EUri structure. **/ void e_uri_free (EUri *uri) { if (uri) { g_free (uri->protocol); g_free (uri->user); g_free (uri->authmech); g_free (uri->passwd); g_free (uri->host); g_free (uri->path); g_datalist_clear (&uri->params); g_free (uri->query); g_free (uri->fragment); g_free (uri); } } /** * e_uri_get_param: * @uri: The #EUri to get the parameter from. * @name: The name of the parameter to get. * * Retrieves the value of the parameter associated with @name in @uri. * * Returns: The value of the parameter. **/ const gchar * e_uri_get_param (EUri *uri, const gchar *name) { return g_datalist_get_data (&uri->params, name); } static void copy_param_cb (GQuark key_id, gpointer data, gpointer user_data) { GData *params = (GData *) user_data; g_datalist_id_set_data_full (¶ms, key_id, g_strdup (data), g_free); } /** * e_uri_copy: * @uri: The #EUri to copy. * * Makes a copy of @uri. * * Returns: The newly-allocated copy of @uri. **/ EUri * e_uri_copy (EUri *uri) { EUri *uri_copy; g_return_val_if_fail (uri != NULL, NULL); uri_copy = g_new0 (EUri, 1); uri_copy->protocol = g_strdup (uri->protocol); uri_copy->user = g_strdup (uri->user); uri_copy->authmech = g_strdup (uri->authmech); uri_copy->passwd = g_strdup (uri->passwd); uri_copy->host = g_strdup (uri->host); uri_copy->port = uri->port; uri_copy->path = g_strdup (uri->path); uri_copy->query = g_strdup (uri->query); uri_copy->fragment = g_strdup (uri->fragment); /* copy uri->params */ g_datalist_foreach (&uri->params, (GDataForeachFunc) copy_param_cb, &uri_copy->params); return uri_copy; } /** * e_uri_to_string: * @uri: The #EUri to convert to a string. * @show_password: Whether or not to show the password in the string. * * Creates a string representation of @uri. The password will only be * included in the string if @show_password is set to %TRUE. * * Returns: The string representation of @uri. **/ gchar * e_uri_to_string (EUri *uri, gboolean show_password) { gchar *str_uri = NULL; g_return_val_if_fail (uri != NULL, NULL); if (uri->port != 0) str_uri = g_strdup_printf ( "%s://%s%s%s%s%s%s%s:%d%s%s%s", uri->protocol, uri->user ? uri->user : "", uri->authmech ? ";auth=" : "", uri->authmech ? uri->authmech : "", uri->passwd && show_password ? ":" : "", uri->passwd && show_password ? uri->passwd : "", uri->user ? "@" : "", uri->host ? uri->host : "", uri->port, uri->path ? uri->path : "", uri->query ? "?" : "", uri->query ? uri->query : ""); else str_uri = g_strdup_printf ( "%s://%s%s%s%s%s%s%s%s%s%s", uri->protocol, uri->user ? uri->user : "", uri->authmech ? ";auth=" : "", uri->authmech ? uri->authmech : "", uri->passwd && show_password ? ":" : "", uri->passwd && show_password ? uri->passwd : "", uri->user ? "@" : "", uri->host ? uri->host : "", uri->path ? uri->path : "", uri->query ? "?" : "", uri->query ? uri->query : ""); return str_uri; }