1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* Copyright (C) 1999-2004 Novell, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
33 * @uri_string: the URI
37 * Return value: a parsed %E2kUri
40 e2k_uri_new (const char *uri_string)
43 const char *end, *hash, *colon, *semi, *at, *slash;
44 const char *question, *p;
46 uri = g_new0 (E2kUri, 1);
49 end = hash = strchr (uri_string, '#');
50 if (hash && hash[1]) {
51 uri->fragment = g_strdup (hash + 1);
52 e2k_uri_decode (uri->fragment);
54 end = uri_string + strlen (uri_string);
56 /* Find protocol: initial [a-z+.-]* substring until ":" */
58 while (p < end && (isalnum ((unsigned char)*p) ||
59 *p == '.' || *p == '+' || *p == '-'))
62 if (p > uri_string && *p == ':') {
63 uri->protocol = g_ascii_strdown (uri_string, p - uri_string);
70 /* Check for authority */
71 if (strncmp (uri_string, "//", 2) == 0) {
74 slash = uri_string + strcspn (uri_string, "/#");
75 at = strchr (uri_string, '@');
76 if (at && at < slash) {
79 colon = strchr (uri_string, ':');
80 if (colon && colon < at) {
81 uri->passwd = g_strndup (colon + 1,
83 e2k_uri_decode (uri->passwd);
89 semi = strchr(uri_string, ';');
90 if (semi && semi < colon &&
91 !g_ascii_strncasecmp (semi, ";auth=", 6)) {
92 uri->authmech = g_strndup (semi + 6,
94 e2k_uri_decode (uri->authmech);
100 uri->user = g_strndup (uri_string, semi - uri_string);
101 e2k_uri_decode (uri->user);
104 backslash = strchr (uri->user, '\\');
106 backslash = strchr (uri->user, '/');
108 uri->domain = uri->user;
110 uri->user = g_strdup (backslash + 1);
113 uri->user = uri->passwd = uri->domain = NULL;
115 /* Find host and port. */
116 colon = strchr (uri_string, ':');
117 if (colon && colon < slash) {
118 uri->host = g_strndup (uri_string, colon - uri_string);
119 uri->port = strtoul (colon + 1, NULL, 10);
121 uri->host = g_strndup (uri_string, slash - uri_string);
122 e2k_uri_decode (uri->host);
130 question = memchr (uri_string, '?', end - uri_string);
133 uri->query = g_strndup (question + 1,
134 end - (question + 1));
135 e2k_uri_decode (uri->query);
140 /* Find parameters */
141 semi = memchr (uri_string, ';', end - uri_string);
144 const char *cur, *p, *eq;
147 for (cur = semi + 1; cur < end; cur = p + 1) {
148 p = memchr (cur, ';', end - cur);
151 eq = memchr (cur, '=', p - cur);
153 name = g_strndup (cur, eq - cur);
154 value = g_strndup (eq + 1, p - (eq + 1));
155 e2k_uri_decode (value);
157 name = g_strndup (cur, p - cur);
158 value = g_strdup ("");
160 e2k_uri_decode (name);
161 g_datalist_set_data_full (&uri->params, name,
169 if (end != uri_string) {
170 uri->path = g_strndup (uri_string, end - uri_string);
171 e2k_uri_decode (uri->path);
184 e2k_uri_free (E2kUri *uri)
187 g_free (uri->protocol);
189 g_free (uri->domain);
190 g_free (uri->authmech);
191 g_free (uri->passwd);
194 g_datalist_clear (&uri->params);
196 g_free (uri->fragment);
205 * @name: name of the parameter
207 * Fetches a parameter from @uri
209 * Return value: the value of @name, or %NULL if it is not set
212 e2k_uri_get_param (E2kUri *uri, const char *name)
214 return g_datalist_get_data (&uri->params, name);
218 #define HEXVAL(c) (isdigit (c) ? (c) - '0' : g_ascii_tolower (c) - 'a' + 10)
222 * @part: a piece of a URI
224 * Undoes URI-escaping in @part in-place.
227 e2k_uri_decode (char *part)
231 s = d = (guchar *)part;
234 if (isxdigit (s[1]) && isxdigit (s[2])) {
235 *d++ = HEXVAL (s[1]) * 16 + HEXVAL (s[2]);
245 static const int uri_encoded_char[] = {
246 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 - 0x0f */
247 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 - 0x1f */
248 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, /* ' ' - '/' */
249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, /* '0' - '?' */
250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '@' - 'O' */
251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 1, 0, /* 'P' - '_' */
252 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '`' - 'o' */
253 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 1, /* 'p' - 0x7f */
254 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
255 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
256 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
257 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
258 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
259 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
260 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
261 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
265 * e2k_uri_append_encoded:
266 * @str: a %GString containing part of a URI
267 * @in: data to append to @str
268 * @wss_encode: whether or not to use the special Web Storage System
270 * @extra_enc_chars: additional characters beyond the normal URI-reserved
271 * characters to encode when appending to @str
273 * Appends @in to @str, encoding URI-unsafe characters as needed
274 * (optionally including some Exchange-specific encodings).
276 * When appending a path, you must append each segment separately;
277 * e2k_uri_append_encoded() will encode any "/"s passed in.
280 e2k_uri_append_encoded (GString *str, const char *in,
281 gboolean wss_encode, const char *extra_enc_chars)
283 const unsigned char *s = (const unsigned char *)in;
286 if (extra_enc_chars && strchr (extra_enc_chars, *s))
288 switch (uri_encoded_char[*s]) {
294 g_string_append (str, "_xF8FF_");
297 g_string_append (str, "_x003F_");
300 g_string_append (str, "_xF8FE_");
303 g_string_append (str, "_x007E_");
309 g_string_append_printf (str, "%%%02x", (int)*s++);
312 g_string_append_c (str, *s++);
320 * @in: data to encode
321 * @wss_encode: whether or not to use the special Web Storage System
323 * @extra_enc_chars: additional characters beyond the normal URI-reserved
324 * characters to encode when appending to @str
326 * Encodes URI-unsafe characters as in e2k_uri_append_encoded()
328 * Return value: the encoded string
331 e2k_uri_encode (const char *in, gboolean wss_encode,
332 const char *extra_enc_chars)
337 string = g_string_new (NULL);
338 e2k_uri_append_encoded (string, in, wss_encode, extra_enc_chars);
340 g_string_free (string, FALSE);
347 * @uri_string: a well-formed absolute URI
349 * Returns the path component of @uri_string, including the initial
350 * "/". (The return value is actually a pointer into the passed-in
351 * string, meaning this will only really work if the URI has no
352 * query/fragment/etc.)
354 * Return value: the path component of @uri_string.
357 e2k_uri_path (const char *uri_string)
361 p = strchr (uri_string, ':');
363 if (!strncmp (p, "//", 2)) {
364 p = strchr (p + 2, '/');
375 * @uri_prefix: an absolute URI
376 * @tail: a relative path
378 * Constructs a new URI consisting of the concatenation of
379 * @uri_prefix and @tail. If @uri_prefix does not end with a "/",
380 * one will be inserted between @uri_prefix and @tail.
382 * Return value: the new URI
385 e2k_uri_concat (const char *uri_prefix, const char *tail)
389 p = strrchr (uri_prefix, '/');
391 return g_strdup_printf ("%s%s", uri_prefix, tail);
393 return g_strdup_printf ("%s/%s", uri_prefix, tail);
398 * @uri_prefix: an absolute URI
399 * @uri: another URI, presumably a child of @uri_prefix
401 * Returns a URI describing @uri's relation to @uri_prefix; either a
402 * relative URI consisting of the subpath of @uri underneath
403 * @uri_prefix, or all of @uri if it is not a sub-uri of @uri_prefix.
405 * Return value: the relative URI
408 e2k_uri_relative (const char *uri_prefix, const char *uri)
410 int prefix_len = strlen (uri_prefix);
412 if (!strncmp (uri_prefix, uri, prefix_len)) {