summaryrefslogtreecommitdiff
path: root/plugins/mms/libmms/uri.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/mms/libmms/uri.c')
-rw-r--r--plugins/mms/libmms/uri.c1033
1 files changed, 1033 insertions, 0 deletions
diff --git a/plugins/mms/libmms/uri.c b/plugins/mms/libmms/uri.c
new file mode 100644
index 00000000..6b6475eb
--- /dev/null
+++ b/plugins/mms/libmms/uri.c
@@ -0,0 +1,1033 @@
+/* GNet - Networking library
+ * Copyright (C) 2000-2003 David Helder, David Bolcsfoldi, Eric Williams
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library 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.
+ */
+
+/* FIXME: #include "gnet-private.h" */
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "uri.h"
+#include <string.h>
+
+static void field_unescape (char *str);
+static char* field_escape (char* str, unsigned char mask);
+
+#define USERINFO_ESCAPE_MASK 0x01
+#define PATH_ESCAPE_MASK 0x02
+#define QUERY_ESCAPE_MASK 0x04
+#define FRAGMENT_ESCAPE_MASK 0x08
+
+/* #define FALSE 0 */
+/* #define TRUE (!FALSE) */
+
+static unsigned char neednt_escape_table[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x00, 0x0c,
+ 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x0f,
+ 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+/*
+Perl code to generate above table:
+
+#!/usr/bin/perl
+
+$ok = "abcdefghijklmnopqrstuvwxyz" .
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" .
+ "0123456789" .
+ "-_.!~*'()";
+$userinfo_ok = ';:&=+\$,';
+$path_ok = ':\@&=+\$,;/';
+$query_ok = ';/?:\@&=+\$,';
+$fragment_ok = ';/?:\@&=+\$,';
+
+for ($i = 0; $i < 32; $i++)
+{
+ print " ";
+ for ($j = 0; $j < 8; $j++)
+ {
+ $num = 0;
+ $letter = chr(($i * 8) + $j);
+
+ $num |= 0b0001 if (index($userinfo_ok, $letter) != -1);
+ $num |= 0b0010 if (index($path_ok, $letter) != -1);
+ $num |= 0b0100 if (index($query_ok, $letter) != -1);
+ $num |= 0b1000 if (index($fragment_ok, $letter) != -1);
+ $num |= 0b1111 if (index($ok, $letter) != -1);
+
+ printf "0x%02x, ", $num;
+ }
+ print "\n";
+}
+*/
+
+
+/* our own ISSPACE. ANSI isspace is local dependent */
+#define ISSPACE(C) (((C) >= 9 && (C) <= 13) || (C) == ' ')
+
+
+static int split_user_passwd(const char* in, char** user, char** passwd)
+{
+ char *tmp = strdup(in);
+
+ if(!tmp)
+ return 0;
+ *passwd = strchr(tmp, ':');
+ if(!(*passwd))
+ {
+ free(tmp);
+ return 0;
+ }
+ *((*passwd)++) = '\0'; // don't you love C? :)
+
+ *user = strdup(tmp);
+ if(!*user)
+ return 0;
+ *passwd = strdup(*passwd);
+ if(!*passwd)
+ return 0;
+
+ free(tmp);
+ return 1;
+}
+
+/**
+ * gnet_uri_new
+ * @uri: URI string
+ *
+ * Creates a #GURI from a string. Empty fields are set to NULL. The
+ * parser does not validate the URI -- it will accept some malformed
+ * URI. URIs are usually in the form
+ * scheme://userinfo@hostname:port/path?query#fragment
+ *
+ * URIs created from user input are typically unescaped. URIs
+ * created from machine input (e.g. received over the internet) are
+ * typically escaped.
+ *
+ * Returns: a new #GURI, or NULL if there was a failure.
+ *
+ **/
+GURI*
+gnet_uri_new (const char* uri)
+{
+ GURI* guri = NULL;
+ const char* p;
+ const char* temp;
+
+ if (!uri) {
+ return NULL;
+ }
+
+ /* Skip initial whitespace */
+ p = uri;
+ while (*p && ISSPACE((int)*p))
+ ++p;
+ if (!*p) /* Error if it's just a string of space */
+ return NULL;
+
+ guri = malloc (sizeof (GURI));
+ memset (guri, 0, sizeof (GURI));
+
+ /* Scheme */
+ temp = p;
+ while (*p && *p != ':' && *p != '/' && *p != '?' && *p != '#')
+ ++p;
+ if (*p == ':')
+ {
+ guri->scheme = strndup (temp, p - temp);
+ ++p;
+ }
+ else /* This char is NUL, /, ?, or # */
+ p = temp;
+
+ /* Authority */
+ if (*p == '/' && p[1] == '/')
+ {
+ char *userinfo;
+ p += 2;
+
+ /* Userinfo */
+ temp = p;
+ while (*p && *p != '@' && *p != '/' ) /* Look for @ or / */
+ ++p;
+ if (*p == '@') /* Found userinfo */
+ {
+ userinfo = strndup (temp, p - temp);
+ if(!split_user_passwd(userinfo, &guri->user, &guri->passwd))
+ {
+ free(userinfo);
+ goto error;
+ }
+ free(userinfo);
+ ++p;
+ }
+ else
+ p = temp;
+
+ /* Hostname */
+
+ /* Check for IPv6 canonical hostname in brackets */
+ if (*p == '[')
+ {
+ p++; /* Skip [ */
+ temp = p;
+ while (*p && *p != ']') ++p;
+ if ((p - temp) == 0)
+ goto error;
+ guri->hostname = strndup (temp, p - temp);
+ if (*p)
+ p++; /* Skip ] (if there) */
+ }
+ else
+ {
+ temp = p;
+ while (*p && *p != '/' && *p != '?' && *p != '#' && *p != ':') ++p;
+ if ((p - temp) == 0)
+ goto error;
+ guri->hostname = strndup (temp, p - temp);
+ }
+
+ /* Port */
+ if (*p == ':')
+ {
+ for (++p; isdigit((int)*p); ++p)
+ guri->port = guri->port * 10 + (*p - '0');
+ }
+
+ }
+
+ /* Path (we are liberal and won't check if it starts with /) */
+ temp = p;
+ while (*p && *p != '?' && *p != '#')
+ ++p;
+ if (p != temp)
+ guri->path = strndup(temp, p - temp);
+
+ /* Query */
+ if (*p == '?')
+ {
+ temp = p + 1;
+ while (*p && *p != '#')
+ ++p;
+ guri->query = strndup (temp, p - temp);
+ }
+
+ /* Fragment */
+ if (*p == '#')
+ {
+ ++p;
+ guri->fragment = strdup (p);
+ }
+
+ return guri;
+
+ error:
+ gnet_uri_delete (guri);
+ return NULL;
+}
+
+
+/**
+ * gnet_uri_new_fields
+ * @scheme: scheme
+ * @hostname: host name
+ * @port: port
+ * @path: path
+ *
+ * Creates a #GURI from the fields. This function uses the most
+ * common fields. Use gnet_uri_new_fields_all() to specify all
+ * fields.
+ *
+ * Returns: a new #GURI.
+ *
+ **/
+GURI*
+gnet_uri_new_fields (const char* scheme, const char* hostname,
+ const int port, const char* path)
+{
+ GURI* uri = NULL;
+
+ uri = malloc (sizeof (GURI));
+ memset (uri, 0, sizeof (GURI));
+ if (scheme) uri->scheme = strdup (scheme);
+ if (hostname) uri->hostname = strdup (hostname);
+ uri->port = port;
+ if (path) uri->path = strdup (path);
+
+ return uri;
+}
+
+
+/**
+ * gnet_uri_new_fields_all
+ * @scheme: scheme
+ * @userinfo: user info
+ * @hostname: host name
+ * @port: port
+ * @path: path
+ * @query: query
+ * @fragment: fragment
+ *
+ * Creates a #GURI from all fields.
+ *
+ * Returns: a new #GURI.
+ *
+ **/
+GURI*
+gnet_uri_new_fields_all (const char* scheme, const char* user,
+ const char* passwd, const char* hostname,
+ const int port, const char* path,
+ const char* query, const char* fragment)
+{
+ GURI* uri = NULL;
+
+ uri = malloc (sizeof (GURI));
+ memset (uri, 0, sizeof (GURI));
+ if (scheme) uri->scheme = strdup (scheme);
+ if (user) uri->user = strdup (user);
+ if (passwd) uri->passwd = strdup (passwd);
+ if (hostname) uri->hostname = strdup (hostname);
+ uri->port = port;
+ if (path) uri->path = strdup (path);
+ if (query) uri->query = strdup (query);
+ if (fragment) uri->fragment = strdup (fragment);
+
+ return uri;
+}
+
+
+/**
+ * gnet_uri_clone:
+ * @uri: a #GURI
+ *
+ * Copies a #GURI.
+ *
+ * Returns: a copy of @uri.
+ *
+ **/
+GURI*
+gnet_uri_clone (const GURI* uri)
+{
+ GURI* uri2;
+
+ if (!uri) {
+ return NULL;
+ }
+
+ uri2 = malloc (sizeof (GURI));
+ memset (uri2, 0, sizeof (GURI));
+ uri2->scheme = strdup (uri->scheme);
+ uri2->user = strdup (uri->user);
+ uri2->passwd = strdup (uri->passwd);
+ uri2->hostname = strdup (uri->hostname);
+ uri2->port = uri->port;
+ uri2->path = strdup (uri->path);
+ uri2->query = strdup (uri->query);
+ uri2->fragment = strdup (uri->fragment);
+
+ return uri2;
+}
+
+
+/**
+ * gnet_uri_delete:
+ * @uri: a #GURI
+ *
+ * Deletes a #GURI.
+ *
+ **/
+void
+gnet_uri_delete (GURI* uri)
+{
+ if (uri)
+ {
+ free (uri->scheme);
+ free (uri->user);
+ free (uri->passwd);
+ free (uri->hostname);
+ free (uri->path);
+ free (uri->query);
+ free (uri->fragment);
+ free (uri);
+ }
+}
+
+
+
+
+#define SAFESTRCMP(A,B) (((A)&&(B))?(strcmp((A),(B))):((A)||(B)))
+
+/**
+ * gnet_uri_equal
+ * @p1: a #GURI
+ * @p2: another #GURI
+ *
+ * Compares two #GURI's for equality.
+ *
+ * Returns: TRUE if they are equal; FALSE otherwise.
+ *
+ **/
+int
+gnet_uri_equal (const char * p1, const char * p2)
+{
+ const GURI* uri1 = (const GURI*) p1;
+ const GURI* uri2 = (const GURI*) p2;
+
+ if (!uri1) {
+ return 0;
+ }
+ if (!uri2) {
+ return 0;
+ }
+
+ if (uri1->port == uri2->port &&
+ !SAFESTRCMP(uri1->scheme, uri2->scheme) &&
+ !SAFESTRCMP(uri1->user, uri2->user) &&
+ !SAFESTRCMP(uri1->passwd, uri2->passwd) &&
+ !SAFESTRCMP(uri1->hostname, uri2->hostname) &&
+ !SAFESTRCMP(uri1->path, uri2->path) &&
+ !SAFESTRCMP(uri1->query, uri2->query) &&
+ !SAFESTRCMP(uri1->fragment, uri2->fragment))
+ return 1;
+
+ return 0;
+}
+
+
+/**
+ * gnet_uri_hash
+ * @p: a #GURI
+ *
+ * Creates a hash code for @p for use with GHashTable.
+ *
+ * Returns: hash code for @p.
+ *
+ **/
+#if 0
+unsigned int
+gnet_uri_hash (const char * p)
+{
+ const GURI* uri = (const GURI*) p;
+ unsigned int h = 0;
+
+ if (!uri) {
+ return 0;
+ }
+
+ if (uri->scheme) h = g_str_hash (uri->scheme);
+ if (uri->user) h ^= g_str_hash (uri->user);
+ if (uri->passwd) h ^= g_str_hash (uri->passwd);
+ if (uri->hostname) h ^= g_str_hash (uri->hostname);
+ h ^= uri->port;
+ if (uri->path) h ^= g_str_hash (uri->path);
+ if (uri->query) h ^= g_str_hash (uri->query);
+ if (uri->fragment) h ^= g_str_hash (uri->fragment);
+
+ return h;
+}
+#endif
+
+
+/**
+ * gnet_uri_escape
+ * @uri: a #GURI
+ *
+ * Escapes the fields in a #GURI. Network protocols use escaped
+ * URIs. People use unescaped URIs.
+ *
+ **/
+void
+gnet_uri_escape (GURI* uri)
+{
+ if (!uri) {
+ return;
+ }
+
+ uri->user = field_escape (uri->user, USERINFO_ESCAPE_MASK);
+ uri->passwd = field_escape (uri->passwd, USERINFO_ESCAPE_MASK);
+ uri->path = field_escape (uri->path, PATH_ESCAPE_MASK);
+ uri->query = field_escape (uri->query, QUERY_ESCAPE_MASK);
+ uri->fragment = field_escape (uri->fragment, FRAGMENT_ESCAPE_MASK);
+}
+
+
+/**
+ * gnet_uri_unescape
+ * @uri: a #GURI
+ *
+ * Unescapes the fields in the URI. Network protocols use escaped
+ * URIs. People use unescaped URIs.
+ *
+ **/
+void
+gnet_uri_unescape (GURI* uri)
+{
+ if (!uri) {
+ return;
+ }
+
+ if (uri->user)
+ field_unescape (uri->user);
+ if (uri->passwd)
+ field_unescape (uri->passwd);
+ if (uri->path)
+ field_unescape (uri->path);
+ if (uri->query)
+ field_unescape (uri->query);
+ if (uri->fragment)
+ field_unescape (uri->fragment);
+}
+
+
+static char*
+field_escape (char* str, unsigned char mask)
+{
+ int len;
+ int i;
+ int must_escape = 0;
+ char* dst;
+ int j;
+
+ if (str == NULL)
+ return NULL;
+
+ /* Roughly calculate buffer size */
+ len = 0;
+ for (i = 0; str[i]; i++)
+ {
+ if (neednt_escape_table[(unsigned int) str[i]] & mask)
+ len++;
+ else
+ {
+ len += 3;
+ must_escape = 1;
+ }
+ }
+
+ /* Don't escape if unnecessary */
+ if (must_escape == 0)
+ return str;
+
+ /* Allocate buffer */
+ dst = (char*) malloc(len + 1);
+ memset (dst, 0, len+1);
+
+ /* Copy */
+ for (i = j = 0; str[i]; i++, j++)
+ {
+ /* Unescaped character */
+ if (neednt_escape_table[(unsigned int) str[i]] & mask)
+ {
+ dst[j] = str[i];
+ }
+
+ /* Escaped character */
+ else
+ {
+ dst[j] = '%';
+
+ if (((str[i] & 0xf0) >> 4) < 10)
+ dst[j+1] = ((str[i] & 0xf0) >> 4) + '0';
+ else
+ dst[j+1] = ((str[i] & 0xf0) >> 4) + 'a' - 10;
+
+ if ((str[i] & 0x0f) < 10)
+ dst[j+2] = (str[i] & 0x0f) + '0';
+ else
+ dst[j+2] = (str[i] & 0x0f) + 'a' - 10;
+
+ j += 2; /* and j is incremented in loop too */
+ }
+ }
+ dst[j] = '\0';
+
+ free (str);
+ return dst;
+}
+
+
+
+static void
+field_unescape (char* s)
+{
+ char* src;
+ char* dst;
+
+ for (src = dst = s; *src; ++src, ++dst)
+ {
+ if (src[0] == '%' && src[1] != '\0' && src[2] != '\0')
+ {
+ int high, low;
+
+ if ('a' <= src[1] && src[1] <= 'f')
+ high = src[1] - 'a' + 10;
+ else if ('A' <= src[1] && src[1] <= 'F')
+ high = src[1] - 'A' + 10;
+ else if ('0' <= src[1] && src[1] <= '9')
+ high = src[1] - '0';
+ else /* malformed */
+ goto regular_copy;
+
+ if ('a' <= src[2] && src[2] <= 'f')
+ low = src[2] - 'a' + 10;
+ else if ('A' <= src[2] && src[2] <= 'F')
+ low = src[2] - 'A' + 10;
+ else if ('0' <= src[2] && src[2] <= '9')
+ low = src[2] - '0';
+ else /* malformed */
+ goto regular_copy;
+
+ *dst = (char)((high << 4) + low);
+ src += 2;
+ }
+ else
+ {
+ regular_copy:
+ *dst = *src;
+ }
+ }
+
+ *dst = '\0';
+}
+
+
+
+/**
+ * gnet_uri_get_string
+ * @uri: a #GURI
+ *
+ * Gets a string representation of a #GURI. This function does not
+ * escape or unescape the fields first. Call gnet_uri_escape() or
+ * gnet_uri_unescape first if necessary.
+ *
+ * Returns: a string.
+ *
+ **/
+char*
+gnet_uri_get_string (const GURI* uri)
+{
+ char* rv = NULL;
+ char *buffer = malloc (1024);
+ memset (buffer, 0, 1024);
+ char *b = buffer;
+ int remaining = 1024;
+
+ if (!uri) {
+ return NULL;
+ }
+
+ if (uri->scheme) {
+ int n = snprintf (buffer, n, "%s:", uri->scheme);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+
+ if (uri->user || uri->passwd || uri->hostname || uri->port) {
+ strcpy (buffer, "//");
+ buffer += 2;
+ remaining -= 2;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+
+ if (uri->user)
+ {
+ int n = strlen (uri->user);
+ memcpy (buffer, uri->user, n+1);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ strcpy (buffer, "@");
+ buffer += 1;
+ remaining -= 1;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+ if (uri->passwd)
+ {
+ int n = strlen (uri->passwd);
+ memcpy (buffer, uri->passwd, n+1);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ strcpy (buffer, "@");
+ buffer += 1;
+ remaining -= 1;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+
+ /* Add brackets around the hostname if it's IPv6 */
+ if (uri->hostname)
+ {
+ if (strchr(uri->hostname, ':') == NULL) {
+ int n = strlen (uri->hostname);
+ memcpy (buffer, uri->hostname, n+1);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+ else {
+ int n = snprintf (buffer, remaining, "[%s]", uri->hostname);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+ }
+
+ if (uri->port) {
+ int n = snprintf (buffer, remaining, ":%d", uri->port);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+
+ if (uri->path)
+ {
+ if (*uri->path == '/' ||
+ !(uri->user || uri->passwd || uri->hostname || uri->port)) {
+ int n = strlen (uri->path);
+ memcpy (buffer, uri->path, n+1);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+ else {
+ int n = snprintf (buffer, remaining, "/%s", uri->path);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+ }
+
+ if (uri->query) {
+ int n = snprintf (buffer, remaining, "?%s", uri->query);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+
+ if (uri->fragment) {
+ int n = snprintf (buffer, remaining, "#%s", uri->fragment);
+ buffer += n;
+ remaining -= n;
+ if (remaining < 10) {
+ free (buffer);
+ return NULL;
+ }
+ }
+
+ /* Free only GString not data contained, return the data instead */
+ return b;
+}
+
+
+/**
+ * gnet_uri_set_scheme
+ * @uri: a #GURI
+ * @scheme: scheme
+ *
+ * Sets a #GURI's scheme.
+ *
+ **/
+void
+gnet_uri_set_scheme (GURI* uri, const char* scheme)
+{
+ if (!uri) {
+ return;
+ }
+
+ if (uri->scheme)
+ {
+ free (uri->scheme);
+ uri->scheme = NULL;
+ }
+
+ if (scheme)
+ uri->scheme = strdup (scheme);
+}
+
+
+/**
+ * gnet_uri_set_userinfo
+ * @uri: a #GURI
+ * @userinfo: user info
+ *
+ * Sets a #GURI's user info.
+ *
+ **/
+void
+gnet_uri_set_userinfo (GURI* uri, const char* user, const char* passwd)
+{
+ if (!uri) {
+ return;
+ }
+
+ if (uri->user)
+ {
+ free (uri->user);
+ uri->user = NULL;
+ }
+ if (uri->passwd)
+ {
+ free (uri->passwd);
+ uri->passwd = NULL;
+ }
+
+ if (user)
+ uri->user = strdup (user);
+ if (passwd)
+ uri->passwd = strdup (passwd);
+}
+
+
+/**
+ * gnet_uri_set_hostname
+ * @uri: a #GURI
+ * @hostname: host name
+ *
+ * Sets a #GURI's host name.
+ *
+ **/
+void
+gnet_uri_set_hostname (GURI* uri, const char* hostname)
+{
+ if (!uri) {
+ return;
+ }
+
+ if (uri->hostname)
+ {
+ free (uri->hostname);
+ uri->hostname = NULL;
+ }
+
+ if (hostname)
+ uri->hostname = strdup (hostname);
+}
+
+
+/**
+ * gnet_uri_set_port
+ * @uri: a #GURI
+ * @port: port
+ *
+ * Set a #GURI's port.
+ *
+ **/
+void
+gnet_uri_set_port (GURI* uri, int port)
+{
+ uri->port = port;
+}
+
+
+/**
+ * gnet_uri_set_path
+ * @uri: a #GURI
+ * @path: path
+ *
+ * Set a #GURI's path.
+ *
+ **/
+void
+gnet_uri_set_path (GURI* uri, const char* path)
+{
+ if (!uri) {
+ return;
+ }
+
+ if (uri->path)
+ {
+ free (uri->path);
+ uri->path = NULL;
+ }
+
+ if (path)
+ uri->path = strdup (path);
+}
+
+
+
+/**
+ * gnet_uri_set_query
+ * @uri: a #GURI
+ * @query: query
+ *
+ * Set a #GURI's query.
+ *
+ **/
+void
+gnet_uri_set_query (GURI* uri, const char* query)
+{
+ if (!uri) {
+ return;
+ }
+
+ if (uri->query)
+ {
+ free (uri->query);
+ uri->query = NULL;
+ }
+
+ if (query)
+ uri->query = strdup (query);
+}
+
+
+/**
+ * gnet_uri_set_fragment
+ * @uri: a #GURI
+ * @fragment: fragment
+ *
+ * Set a #GURI's fragment.
+ *
+ **/
+void
+gnet_uri_set_fragment (GURI* uri, const char* fragment)
+{
+ if (!uri) {
+ return;
+ }
+
+ if (uri->fragment)
+ {
+ free (uri->fragment);
+ uri->fragment = NULL;
+ }
+
+ if (fragment)
+ uri->fragment = strdup (fragment);
+}
+
+
+/**
+ * gnet_mms_helper
+ * @uri: a #GURI
+ *
+ * returns char* representation of an uri that is sutable for
+ * using in mms protocol.
+ * '/path?query'
+ *
+ **/
+
+char* gnet_mms_helper(const GURI* uri, int make_absolute)
+{
+ size_t len = 0;
+ char *ret, *tmp = NULL;
+
+
+ /* Strip leading slashes and calculate the length of the path
+ * which might not be present in the URI */
+ if (uri->path) {
+ tmp = uri->path;
+ while (*tmp == '/')
+ ++tmp;
+ len += strlen(tmp);
+ }
+ /* Append length of the query part */
+ if (uri->query)
+ len += strlen(uri->query) + 1; /* + '?' */
+
+ if (!(ret = (char *) malloc(len + 2)))
+ return NULL;
+ memset (ret, 0, len + 2);
+
+ if (make_absolute)
+ strcpy(ret, "/");
+ else
+ ret[0] = 0;
+
+ /* Copy the optional path */
+ if (tmp)
+ strcat(ret, tmp);
+
+ /* Copy the optional query */
+ if (uri->query) {
+ strcat(ret, "?");
+ strcat(ret, uri->query);
+ }
+
+ return ret;
+}