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 gchar *uri_string)
43
const gchar *end, *hash, *colon, *semi, *at, *slash;
44
const gchar *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 ((guchar)*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 gchar *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 gchar *name)
214
return g_datalist_get_data (&uri->params, name);
217
#define HEXVAL(c) (isdigit (c) ? (c) - '0' : g_ascii_tolower (c) - 'a' + 10)
221
* @part: a piece of a URI
223
* Undoes URI-escaping in @part in-place.
226
e2k_uri_decode (gchar *part)
230
s = d = (guchar *)part;
233
if (isxdigit (s[1]) && isxdigit (s[2])) {
234
*d++ = HEXVAL (s[1]) * 16 + HEXVAL (s[2]);
244
static const gint uri_encoded_char[] = {
245
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 - 0x0f */
246
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 - 0x1f */
247
1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, /* ' ' - '/' */
248
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, /* '0' - '?' */
249
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '@' - 'O' */
250
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 1, 0, /* 'P' - '_' */
251
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '`' - 'o' */
252
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 1, /* 'p' - 0x7f */
253
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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
264
* e2k_uri_append_encoded:
265
* @str: a %GString containing part of a URI
266
* @in: data to append to @str
267
* @wss_encode: whether or not to use the special Web Storage System
269
* @extra_enc_chars: additional characters beyond the normal URI-reserved
270
* characters to encode when appending to @str
272
* Appends @in to @str, encoding URI-unsafe characters as needed
273
* (optionally including some Exchange-specific encodings).
275
* When appending a path, you must append each segment separately;
276
* e2k_uri_append_encoded() will encode any "/"s passed in.
279
e2k_uri_append_encoded (GString *str, const gchar *in,
280
gboolean wss_encode, const gchar *extra_enc_chars)
282
const guchar *s = (const guchar *)in;
285
if (extra_enc_chars && strchr (extra_enc_chars, *s))
287
switch (uri_encoded_char[*s]) {
293
g_string_append (str, "_xF8FF_");
296
g_string_append (str, "_x003F_");
299
g_string_append (str, "_xF8FE_");
302
g_string_append (str, "_x007E_");
308
g_string_append_printf (str, "%%%02x", (gint)*s++);
311
g_string_append_c (str, *s++);
319
* @in: data to encode
320
* @wss_encode: whether or not to use the special Web Storage System
322
* @extra_enc_chars: additional characters beyond the normal URI-reserved
323
* characters to encode when appending to @str
325
* Encodes URI-unsafe characters as in e2k_uri_append_encoded()
327
* Return value: the encoded string
330
e2k_uri_encode (const gchar *in, gboolean wss_encode,
331
const gchar *extra_enc_chars)
336
string = g_string_new (NULL);
337
e2k_uri_append_encoded (string, in, wss_encode, extra_enc_chars);
339
g_string_free (string, FALSE);
346
* @uri_string: a well-formed absolute URI
348
* Returns the path component of @uri_string, including the initial
349
* "/". (The return value is actually a pointer into the passed-in
350
* string, meaning this will only really work if the URI has no
351
* query/fragment/etc.)
353
* Return value: the path component of @uri_string.
356
e2k_uri_path (const gchar *uri_string)
360
p = strchr (uri_string, ':');
362
if (!strncmp (p, "//", 2)) {
363
p = strchr (p + 2, '/');
374
* @uri_prefix: an absolute URI
375
* @tail: a relative path
377
* Constructs a new URI consisting of the concatenation of
378
* @uri_prefix and @tail. If @uri_prefix does not end with a "/",
379
* one will be inserted between @uri_prefix and @tail.
381
* Return value: the new URI
384
e2k_uri_concat (const gchar *uri_prefix, const gchar *tail)
388
p = strrchr (uri_prefix, '/');
390
return g_strdup_printf ("%s%s", uri_prefix, tail);
392
return g_strdup_printf ("%s/%s", uri_prefix, tail);
397
* @uri_prefix: an absolute URI
398
* @uri: another URI, presumably a child of @uri_prefix
400
* Returns a URI describing @uri's relation to @uri_prefix; either a
401
* relative URI consisting of the subpath of @uri underneath
402
* @uri_prefix, or all of @uri if it is not a sub-uri of @uri_prefix.
404
* Return value: the relative URI
407
e2k_uri_relative (const gchar *uri_prefix, const gchar *uri)
409
gint prefix_len = strlen (uri_prefix);
411
if (!strncmp (uri_prefix, uri, prefix_len)) {