~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to servers/exchange/lib/e2k-uri.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
 
 
3
 
/* Copyright (C) 1999-2004 Novell, Inc.
4
 
 *
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.
8
 
 *
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.
13
 
 *
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.
18
 
 */
19
 
 
20
 
#ifdef HAVE_CONFIG_H
21
 
#include <config.h>
22
 
#endif
23
 
 
24
 
#include <ctype.h>
25
 
#include <stdio.h>
26
 
#include <stdlib.h>
27
 
#include <string.h>
28
 
 
29
 
#include "e2k-uri.h"
30
 
 
31
 
/**
32
 
 * e2k_uri_new:
33
 
 * @uri_string: the URI
34
 
 *
35
 
 * Parses @uri_string.
36
 
 *
37
 
 * Return value: a parsed %E2kUri
38
 
 **/
39
 
E2kUri *
40
 
e2k_uri_new (const gchar *uri_string)
41
 
{
42
 
        E2kUri *uri;
43
 
        const gchar *end, *hash, *colon, *semi, *at, *slash;
44
 
        const gchar *question, *p;
45
 
 
46
 
        uri = g_new0 (E2kUri, 1);
47
 
 
48
 
        /* Find fragment. */
49
 
        end = hash = strchr (uri_string, '#');
50
 
        if (hash && hash[1]) {
51
 
                uri->fragment = g_strdup (hash + 1);
52
 
                e2k_uri_decode (uri->fragment);
53
 
        } else
54
 
                end = uri_string + strlen (uri_string);
55
 
 
56
 
        /* Find protocol: initial [a-z+.-]* substring until ":" */
57
 
        p = uri_string;
58
 
        while (p < end && (isalnum ((guchar)*p) ||
59
 
                           *p == '.' || *p == '+' || *p == '-'))
60
 
                p++;
61
 
 
62
 
        if (p > uri_string && *p == ':') {
63
 
                uri->protocol = g_ascii_strdown (uri_string, p - uri_string);
64
 
                uri_string = p + 1;
65
 
        }
66
 
 
67
 
        if (!*uri_string)
68
 
                return uri;
69
 
 
70
 
        /* Check for authority */
71
 
        if (strncmp (uri_string, "//", 2) == 0) {
72
 
                uri_string += 2;
73
 
 
74
 
                slash = uri_string + strcspn (uri_string, "/#");
75
 
                at = strchr (uri_string, '@');
76
 
                if (at && at < slash) {
77
 
                        gchar *backslash;
78
 
 
79
 
                        colon = strchr (uri_string, ':');
80
 
                        if (colon && colon < at) {
81
 
                                uri->passwd = g_strndup (colon + 1,
82
 
                                                         at - colon - 1);
83
 
                                e2k_uri_decode (uri->passwd);
84
 
                        } else {
85
 
                                uri->passwd = NULL;
86
 
                                colon = at;
87
 
                        }
88
 
 
89
 
                        semi = strchr(uri_string, ';');
90
 
                        if (semi && semi < colon &&
91
 
                            !g_ascii_strncasecmp (semi, ";auth=", 6)) {
92
 
                                uri->authmech = g_strndup (semi + 6,
93
 
                                                           colon - semi - 6);
94
 
                                e2k_uri_decode (uri->authmech);
95
 
                        } else {
96
 
                                uri->authmech = NULL;
97
 
                                semi = colon;
98
 
                        }
99
 
 
100
 
                        uri->user = g_strndup (uri_string, semi - uri_string);
101
 
                        e2k_uri_decode (uri->user);
102
 
                        uri_string = at + 1;
103
 
 
104
 
                        backslash = strchr (uri->user, '\\');
105
 
                        if (!backslash)
106
 
                                backslash = strchr (uri->user, '/');
107
 
                        if (backslash) {
108
 
                                uri->domain = uri->user;
109
 
                                *backslash = '\0';
110
 
                                uri->user = g_strdup (backslash + 1);
111
 
                        }
112
 
                } else
113
 
                        uri->user = uri->passwd = uri->domain = NULL;
114
 
 
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);
120
 
                } else {
121
 
                        uri->host = g_strndup (uri_string, slash - uri_string);
122
 
                        e2k_uri_decode (uri->host);
123
 
                        uri->port = 0;
124
 
                }
125
 
 
126
 
                uri_string = slash;
127
 
        }
128
 
 
129
 
        /* Find query */
130
 
        question = memchr (uri_string, '?', end - uri_string);
131
 
        if (question) {
132
 
                if (question[1]) {
133
 
                        uri->query = g_strndup (question + 1,
134
 
                                                end - (question + 1));
135
 
                        e2k_uri_decode (uri->query);
136
 
                }
137
 
                end = question;
138
 
        }
139
 
 
140
 
        /* Find parameters */
141
 
        semi = memchr (uri_string, ';', end - uri_string);
142
 
        if (semi) {
143
 
                if (semi[1]) {
144
 
                        const gchar *cur, *p, *eq;
145
 
                        gchar *name, *value;
146
 
 
147
 
                        for (cur = semi + 1; cur < end; cur = p + 1) {
148
 
                                p = memchr (cur, ';', end - cur);
149
 
                                if (!p)
150
 
                                        p = end;
151
 
                                eq = memchr (cur, '=', p - cur);
152
 
                                if (eq) {
153
 
                                        name = g_strndup (cur, eq - cur);
154
 
                                        value = g_strndup (eq + 1, p - (eq + 1));
155
 
                                        e2k_uri_decode (value);
156
 
                                } else {
157
 
                                        name = g_strndup (cur, p - cur);
158
 
                                        value = g_strdup ("");
159
 
                                }
160
 
                                e2k_uri_decode (name);
161
 
                                g_datalist_set_data_full (&uri->params, name,
162
 
                                                          value, g_free);
163
 
                                g_free (name);
164
 
                        }
165
 
                }
166
 
                end = semi;
167
 
        }
168
 
 
169
 
        if (end != uri_string) {
170
 
                uri->path = g_strndup (uri_string, end - uri_string);
171
 
                e2k_uri_decode (uri->path);
172
 
        }
173
 
 
174
 
        return uri;
175
 
}
176
 
 
177
 
/**
178
 
 * e2k_uri_free:
179
 
 * @uri: an %E2kUri
180
 
 *
181
 
 * Frees @uri
182
 
 **/
183
 
void
184
 
e2k_uri_free (E2kUri *uri)
185
 
{
186
 
        if (uri) {
187
 
                g_free (uri->protocol);
188
 
                g_free (uri->user);
189
 
                g_free (uri->domain);
190
 
                g_free (uri->authmech);
191
 
                g_free (uri->passwd);
192
 
                g_free (uri->host);
193
 
                g_free (uri->path);
194
 
                g_datalist_clear (&uri->params);
195
 
                g_free (uri->query);
196
 
                g_free (uri->fragment);
197
 
 
198
 
                g_free (uri);
199
 
        }
200
 
}
201
 
 
202
 
/**
203
 
 * e2k_uri_get_param:
204
 
 * @uri: an %E2kUri
205
 
 * @name: name of the parameter
206
 
 *
207
 
 * Fetches a parameter from @uri
208
 
 *
209
 
 * Return value: the value of @name, or %NULL if it is not set
210
 
 **/
211
 
const gchar *
212
 
e2k_uri_get_param (E2kUri *uri, const gchar *name)
213
 
{
214
 
        return g_datalist_get_data (&uri->params, name);
215
 
}
216
 
 
217
 
#define HEXVAL(c) (isdigit (c) ? (c) - '0' : g_ascii_tolower (c) - 'a' + 10)
218
 
 
219
 
/**
220
 
 * e2k_uri_decode:
221
 
 * @part: a piece of a URI
222
 
 *
223
 
 * Undoes URI-escaping in @part in-place.
224
 
 **/
225
 
void
226
 
e2k_uri_decode (gchar *part)
227
 
{
228
 
        guchar *s, *d;
229
 
 
230
 
        s = d = (guchar *)part;
231
 
        while (*s) {
232
 
                if (*s == '%') {
233
 
                        if (isxdigit (s[1]) && isxdigit (s[2])) {
234
 
                                *d++ = HEXVAL (s[1]) * 16 + HEXVAL (s[2]);
235
 
                                s += 3;
236
 
                        } else
237
 
                                *d++ = *s++;
238
 
                } else
239
 
                        *d++ = *s++;
240
 
        }
241
 
        *d = '\0';
242
 
}
243
 
 
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
261
 
};
262
 
 
263
 
/**
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
268
 
 * encoding rules
269
 
 * @extra_enc_chars: additional characters beyond the normal URI-reserved
270
 
 * characters to encode when appending to @str
271
 
 *
272
 
 * Appends @in to @str, encoding URI-unsafe characters as needed
273
 
 * (optionally including some Exchange-specific encodings).
274
 
 *
275
 
 * When appending a path, you must append each segment separately;
276
 
 * e2k_uri_append_encoded() will encode any "/"s passed in.
277
 
 **/
278
 
void
279
 
e2k_uri_append_encoded (GString *str, const gchar *in,
280
 
                        gboolean wss_encode, const gchar *extra_enc_chars)
281
 
{
282
 
        const guchar *s = (const guchar *)in;
283
 
 
284
 
        while (*s) {
285
 
                if (extra_enc_chars && strchr (extra_enc_chars, *s))
286
 
                        goto escape;
287
 
                switch (uri_encoded_char[*s]) {
288
 
                case 2:
289
 
                        if (!wss_encode)
290
 
                                goto escape;
291
 
                        switch (*s++) {
292
 
                        case '/':
293
 
                                g_string_append (str, "_xF8FF_");
294
 
                                break;
295
 
                        case '?':
296
 
                                g_string_append (str, "_x003F_");
297
 
                                break;
298
 
                        case '\\':
299
 
                                g_string_append (str, "_xF8FE_");
300
 
                                break;
301
 
                        case '~':
302
 
                                g_string_append (str, "_x007E_");
303
 
                                break;
304
 
                        }
305
 
                        break;
306
 
                case 1:
307
 
                escape:
308
 
                        g_string_append_printf (str, "%%%02x", (gint)*s++);
309
 
                        break;
310
 
                default:
311
 
                        g_string_append_c (str, *s++);
312
 
                        break;
313
 
                }
314
 
        }
315
 
}
316
 
 
317
 
/**
318
 
 * e2k_uri_encode:
319
 
 * @in: data to encode
320
 
 * @wss_encode: whether or not to use the special Web Storage System
321
 
 * encoding rules
322
 
 * @extra_enc_chars: additional characters beyond the normal URI-reserved
323
 
 * characters to encode when appending to @str
324
 
 *
325
 
 * Encodes URI-unsafe characters as in e2k_uri_append_encoded()
326
 
 *
327
 
 * Return value: the encoded string
328
 
 **/
329
 
gchar *
330
 
e2k_uri_encode (const gchar *in, gboolean wss_encode,
331
 
                const gchar *extra_enc_chars)
332
 
{
333
 
        GString *string;
334
 
        gchar *out;
335
 
 
336
 
        string = g_string_new (NULL);
337
 
        e2k_uri_append_encoded (string, in, wss_encode, extra_enc_chars);
338
 
        out = string->str;
339
 
        g_string_free (string, FALSE);
340
 
 
341
 
        return out;
342
 
}
343
 
 
344
 
/**
345
 
 * e2k_uri_path:
346
 
 * @uri_string: a well-formed absolute URI
347
 
 *
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.)
352
 
 *
353
 
 * Return value: the path component of @uri_string.
354
 
 **/
355
 
const gchar *
356
 
e2k_uri_path (const gchar *uri_string)
357
 
{
358
 
        const gchar *p;
359
 
 
360
 
        p = strchr (uri_string, ':');
361
 
        if (p++) {
362
 
                if (!strncmp (p, "//", 2)) {
363
 
                        p = strchr (p + 2, '/');
364
 
                        if (p)
365
 
                                return p;
366
 
                } else if (*p)
367
 
                        return p;
368
 
        }
369
 
        return "";
370
 
}
371
 
 
372
 
/**
373
 
 * e2k_uri_concat:
374
 
 * @uri_prefix: an absolute URI
375
 
 * @tail: a relative path
376
 
 *
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.
380
 
 *
381
 
 * Return value: the new URI
382
 
 **/
383
 
gchar *
384
 
e2k_uri_concat (const gchar *uri_prefix, const gchar *tail)
385
 
{
386
 
        const gchar *p;
387
 
 
388
 
        p = strrchr (uri_prefix, '/');
389
 
        if (p && !p[1])
390
 
                return g_strdup_printf ("%s%s", uri_prefix, tail);
391
 
        else
392
 
                return g_strdup_printf ("%s/%s", uri_prefix, tail);
393
 
}
394
 
 
395
 
/**
396
 
 * e2k_uri_relative:
397
 
 * @uri_prefix: an absolute URI
398
 
 * @uri: another URI, presumably a child of @uri_prefix
399
 
 *
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.
403
 
 *
404
 
 * Return value: the relative URI
405
 
 **/
406
 
const gchar *
407
 
e2k_uri_relative (const gchar *uri_prefix, const gchar *uri)
408
 
{
409
 
        gint prefix_len = strlen (uri_prefix);
410
 
 
411
 
        if (!strncmp (uri_prefix, uri, prefix_len)) {
412
 
                uri += prefix_len;
413
 
                while (*uri == '/')
414
 
                        uri++;
415
 
        }
416
 
 
417
 
        return uri;
418
 
}