3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This Program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
33 * shamelessly pull out of GnomeVFS (gnome-vfs-uri and consorts)
36 /* gnome-vfs-uri.h - URI handling for the GNOME Virtual File System.
38 Copyright (C) 1999 Free Software Foundation
40 The Gnome Library is free software; you can redistribute it and/or
41 modify it under the terms of the GNU Library General Public License as
42 published by the Free Software Foundation; either version 2 of the
43 License, or (at your option) any later version.
45 The Gnome Library is distributed in the hope that it will be useful,
46 but WITHOUT ANY WARRANTY; without even the implied warranty of
47 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
48 Library General Public License for more details.
50 You should have received a copy of the GNU Library General Public
51 License along with the Gnome Library; see the file COPYING.LIB. If not,
52 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
53 Boston, MA 02111-1307, USA.
55 Author: Ettore Perazzoli <ettore@comm2000.it> */
63 #include "na-gnome-vfs-uri.h"
65 #define HEX_ESCAPE '%'
67 static void collapse_slash_runs (char *path
, int from_offset
);
68 static int find_next_slash (const char *path
, int current_offset
);
69 static int find_slash_before_offset (const char *path
, int to
);
70 static const gchar
*get_method_string (const gchar
*substring
, gchar
**method_string
);
71 static gchar
* gnome_vfs_canonicalize_pathname (gchar
*path
);
72 static char *gnome_vfs_escape_set(const char *string
, const char *match_set
);
73 static void gnome_vfs_remove_optional_escapes (char *uri
);
74 static char * gnome_vfs_unescape_string (const gchar
*escaped_string
, const gchar
*illegal_characters
);
75 static int hex_to_int (gchar c
);
76 static void set_uri_element (NAGnomeVFSURI
*vfs
, const gchar
*text
, guint len
);
77 static gchar
*split_toplevel_uri (const gchar
*path
, guint path_len
,
78 gchar
**host_return
, gchar
**user_return
,
79 guint
*port_return
, gchar
**password_return
);
80 static int unescape_character (const char *scanner
);
83 na_gnome_vfs_uri_parse( NAGnomeVFSURI
*vfs
, const gchar
*text_uri
)
85 const gchar
*method_scanner
;
86 gchar
*extension_scanner
;
90 vfs
->host_name
= NULL
;
92 vfs
->user_name
= NULL
;
95 if (text_uri
[0] == '\0') {
99 method_scanner
= get_method_string(text_uri
, &vfs
->scheme
);
100 if (strcmp (vfs
->scheme
, "pipe") == 0 ){
104 extension_scanner
= strchr (method_scanner
, GNOME_VFS_URI_MAGIC_CHR
);
105 if (extension_scanner
== NULL
) {
106 set_uri_element (vfs
, method_scanner
, strlen (method_scanner
));
111 set_uri_element (vfs
, method_scanner
, extension_scanner
- method_scanner
);
113 if (strchr (extension_scanner
, ':') == NULL
) {
114 /* extension is a fragment identifier */
115 /*uri->fragment_id = g_strdup (extension_scanner + 1);*/
121 na_gnome_vfs_uri_free( NAGnomeVFSURI
*vfs
)
124 g_free( vfs
->scheme
);
125 g_free( vfs
->host_name
);
126 g_free( vfs
->user_name
);
127 g_free( vfs
->password
);
132 collapse_slash_runs (char *path
, int from_offset
)
135 /* Collapse multiple `/'s in a row. */
136 for (i
= from_offset
;; i
++) {
137 if (path
[i
] != GNOME_VFS_URI_PATH_CHR
) {
142 if (from_offset
< i
) {
143 memmove (path
+ from_offset
, path
+ i
, strlen (path
+ i
) + 1);
149 find_next_slash (const char *path
, int current_offset
)
153 g_assert (current_offset
<= strlen (path
));
155 match
= strchr (path
+ current_offset
, GNOME_VFS_URI_PATH_CHR
);
156 return match
== NULL
? -1 : match
- path
;
160 find_slash_before_offset (const char *path
, int to
)
168 next_offset
= find_next_slash (path
, next_offset
);
169 if (next_offset
< 0 || next_offset
>= to
) {
172 result
= next_offset
;
179 get_method_string (const gchar
*substring
, gchar
**method_string
)
185 g_ascii_isalnum (*p
) || *p
== '+' || *p
== '-' || *p
== '.';
192 !(p
== substring
+ 1 && g_ascii_isalpha (*substring
))
195 /* Found toplevel method specification. */
196 method
= g_strndup (substring
, p
- substring
);
197 *method_string
= g_ascii_strdown (method
, -1);
201 *method_string
= g_strdup ("file");
207 /* Canonicalize path, and return a new path. Do everything in situ. The new
208 path differs from path in:
210 Multiple `/'s are collapsed to a single `/'.
211 Leading `./'s and trailing `/.'s are removed.
212 Non-leading `../'s and trailing `..'s are handled by removing
213 portions of the path. */
215 gnome_vfs_canonicalize_pathname (gchar
*path
)
219 if (path
== NULL
|| strlen (path
) == 0) {
223 /* Walk along path looking for things to compact. */
224 for (i
= 0, marker
= 0;;) {
228 /* Check for `../', `./' or trailing `.' by itself. */
229 if (path
[i
] == '.') {
230 /* Handle trailing `.' by itself. */
231 if (path
[i
+ 1] == '\0') {
232 if (i
> 1 && path
[i
- 1] == GNOME_VFS_URI_PATH_CHR
) {
233 /* strip the trailing /. */
236 /* convert path "/." to "/" */
243 if (path
[i
+ 1] == GNOME_VFS_URI_PATH_CHR
) {
244 memmove (path
+ i
, path
+ i
+ 2,
245 strlen (path
+ i
+ 2) + 1);
247 /* don't leave leading '/' for paths that started
248 * as relative (.//foo)
250 collapse_slash_runs (path
, i
);
256 /* Handle `../' or trailing `..' by itself.
257 * Remove the previous xxx/ part
259 if (path
[i
+ 1] == '.'
260 && (path
[i
+ 2] == GNOME_VFS_URI_PATH_CHR
261 || path
[i
+ 2] == '\0')) {
263 /* ignore ../ at the beginning of a path */
265 marker
= find_slash_before_offset (path
, i
- 1);
267 /* Either advance past '/' or point to the first character */
269 if (path
[i
+ 2] == '\0' && marker
> 1) {
270 /* If we are looking at a /.. at the end of the uri and we
271 * need to eat the last '/' too.
275 g_assert(marker
< i
);
277 if (path
[i
+ 2] == GNOME_VFS_URI_PATH_CHR
) {
278 /* strip the entire ../ string */
282 memmove (path
+ marker
, path
+ i
+ 2,
283 strlen (path
+ i
+ 2) + 1);
287 if (path
[i
] == GNOME_VFS_URI_PATH_CHR
) {
291 collapse_slash_runs (path
, i
);
296 /* advance to the next '/' */
297 i
= find_next_slash (path
, i
);
299 /* If we didn't find any slashes, then there is nothing left to do. */
305 collapse_slash_runs (path
, i
);
310 /* Escape undesirable characters using %
311 * -------------------------------------
313 * This function takes a pointer to a string in which
314 * some characters may be unacceptable unescaped.
315 * It returns a string which has these characters
316 * represented by a '%' character followed by two hex digits.
318 * This routine returns a g_malloced string.
321 static const gchar hex
[16] = "0123456789ABCDEF";
324 * gnome_vfs_escape_set:
325 * @string: string to be escaped.
326 * @match_set: a string containing all characters to be escaped in @string.
328 * Escapes all characters in @string which are listed in @match_set.
330 * Return value: a newly allocated string equivalent to @string but
331 * with characters in @match_string escaped.
334 gnome_vfs_escape_set (const char *string
,
335 const char *match_set
)
339 char *result_scanner
;
344 if (string
== NULL
) {
348 if (match_set
== NULL
) {
349 return g_strdup (string
);
352 for (scanner
= string
; *scanner
!= '\0'; scanner
++) {
353 if (strchr(match_set
, *scanner
) != NULL
) {
354 /* this character is in the set of characters
361 if (escape_count
== 0) {
362 return g_strdup (string
);
365 /* allocate two extra characters for every character that
366 * needs escaping and space for a trailing zero
368 result
= g_malloc (scanner
- string
+ escape_count
* 2 + 1);
369 for (scanner
= string
, result_scanner
= result
; *scanner
!= '\0'; scanner
++) {
370 if (strchr(match_set
, *scanner
) != NULL
) {
371 /* this character is in the set of characters
374 *result_scanner
++ = HEX_ESCAPE
;
375 *result_scanner
++ = hex
[*scanner
>> 4];
376 *result_scanner
++ = hex
[*scanner
& 15];
379 *result_scanner
++ = *scanner
;
383 *result_scanner
= '\0';
389 * gnome_vfs_remove_optional_escapes:
390 * @uri: an escaped uri.
392 * Scans the @uri and converts characters that do not have to be
393 * escaped into an un-escaped form. The characters that get treated this
394 * way are defined as unreserved by the RFC.
396 * Return value: an error value if the @uri is found to be malformed.
408 static const guchar uri_character_kind
[128] =
410 CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,
411 CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,
412 CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,
413 CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,CONTROL
,
414 /* ' ' ! " # $ % & ' */
415 SPACE
,UNRESERVED
,DELIMITERS
,DELIMITERS
,RESERVED
,DELIMITERS
,RESERVED
,UNRESERVED
,
416 /* ( ) * + , - . / */
417 UNRESERVED
,UNRESERVED
,UNRESERVED
,RESERVED
,RESERVED
,UNRESERVED
,UNRESERVED
,RESERVED
,
418 /* 0 1 2 3 4 5 6 7 */
419 UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,
420 /* 8 9 : ; < = > ? */
421 UNRESERVED
,UNRESERVED
,RESERVED
,RESERVED
,DELIMITERS
,RESERVED
,DELIMITERS
,RESERVED
,
422 /* @ A B C D E F G */
423 RESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,
424 /* H I J K L M N O */
425 UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,
426 /* P Q R S T U V W */
427 UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,
428 /* X Y Z [ \ ] ^ _ */
429 UNRESERVED
,UNRESERVED
,UNRESERVED
,UNWISE
,UNWISE
,UNWISE
,UNWISE
,UNRESERVED
,
430 /* ` a b c d e f g */
431 UNWISE
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,
432 /* h i j k l m n o */
433 UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,
434 /* p q r s t u v w */
435 UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,UNRESERVED
,
436 /* x y z { | } ~ DEL */
437 UNRESERVED
,UNRESERVED
,UNRESERVED
,UNWISE
,UNWISE
,UNWISE
,UNRESERVED
,CONTROL
441 gnome_vfs_remove_optional_escapes (char *uri
)
451 length
= strlen (uri
);
453 for (scanner
= (guchar
*)uri
; *scanner
!= '\0'; scanner
++, length
--) {
454 if (*scanner
== HEX_ESCAPE
) {
455 character
= unescape_character ((char *)scanner
+ 1);
457 /* invalid hexadecimal character */
461 if (uri_character_kind
[character
] == UNRESERVED
) {
462 /* This character does not need to be escaped, convert it
463 * to a non-escaped form.
465 *scanner
= (guchar
)character
;
466 g_assert (length
>= 3);
468 /* Shrink the string covering up the two extra digits of the
469 * escaped character. Include the trailing '\0' in the copy
470 * to keep the string terminated.
472 memmove (scanner
+ 1, scanner
+ 3, length
- 2);
474 /* This character must stay escaped, skip the entire
481 } else if (*scanner
> 127
482 || uri_character_kind
[*scanner
] == DELIMITERS
483 || uri_character_kind
[*scanner
] == UNWISE
484 || uri_character_kind
[*scanner
] == CONTROL
) {
485 /* It is illegal for this character to be in an un-escaped form
496 return c
>= '0' && c
<= '9' ? c
- '0'
497 : c
>= 'A' && c
<= 'F' ? c
- 'A' + 10
498 : c
>= 'a' && c
<= 'f' ? c
- 'a' + 10
503 unescape_character (const char *scanner
)
508 first_digit
= hex_to_int (*scanner
++);
509 if (first_digit
< 0) {
513 second_digit
= hex_to_int (*scanner
++);
514 if (second_digit
< 0) {
518 return (first_digit
<< 4) | second_digit
;
522 * gnome_vfs_unescape_string:
523 * @escaped_string: an escaped uri, path, or other string.
524 * @illegal_characters: a string containing a sequence of characters
525 * considered "illegal" to be escaped, '\0' is automatically in this list.
527 * Decodes escaped characters (i.e. PERCENTxx sequences) in @escaped_string.
528 * Characters are encoded in PERCENTxy form, where xy is the ASCII hex code
529 * for character 16x+y.
531 * Return value: a newly allocated string with the unescaped
532 * equivalents, or %NULL if @escaped_string contained an escaped
533 * encoding of one of the characters in @illegal_characters.
536 gnome_vfs_unescape_string (const gchar
*escaped_string
,
537 const gchar
*illegal_characters
)
543 if (escaped_string
== NULL
) {
547 result
= g_malloc (strlen (escaped_string
) + 1);
550 for (in
= escaped_string
; *in
!= '\0'; in
++) {
552 if (*in
== HEX_ESCAPE
) {
553 character
= unescape_character (in
+ 1);
555 /* Check for an illegal character. We consider '\0' illegal here. */
557 || (illegal_characters
!= NULL
558 && strchr (illegal_characters
, (char)character
) != NULL
)) {
564 *out
++ = (char)character
;
568 g_assert (out
- result
<= strlen (escaped_string
));
574 set_uri_element (NAGnomeVFSURI
*vfs
,
580 if (text
== NULL
|| len
== 0) {
581 vfs
->path
= g_strdup ("/");
585 if ( text
[0] == '/' && text
[1] == '/') {
586 vfs
->path
= split_toplevel_uri (text
+ 2, len
- 2,
592 vfs
->path
= g_strndup (text
, len
);
595 /* FIXME: this should be handled/supported by the specific method.
596 * This is a quick and dirty hack to minimize the amount of changes
597 * right before a milestone release.
599 * Do some method specific escaping. This for instance converts
600 * '?' to %3F in every method except "http" where it has a special
603 if ( ! (strcmp (vfs
->scheme
, "http") == 0
604 || strcmp (vfs
->scheme
, "https") == 0
605 || strcmp (vfs
->scheme
, "dav") == 0
606 || strcmp (vfs
->scheme
, "davs") == 0
607 || strcmp (vfs
->scheme
, "ghelp") == 0
608 || strcmp (vfs
->scheme
, "gnome-help") == 0
609 || strcmp (vfs
->scheme
, "help") == 0
612 escaped_text
= gnome_vfs_escape_set (vfs
->path
, ";?&=+$,");
614 vfs
->path
= escaped_text
;
617 gnome_vfs_remove_optional_escapes (vfs
->path
);
618 gnome_vfs_canonicalize_pathname (vfs
->path
);
624 Extract hostname and username from "path" with length "path_len"
627 sunsite.unc.edu/pub/linux
628 miguel@sphinx.nuclecu.unam.mx/c/nc
630 joe@foo.edu:11321/private
633 This function implements the following regexp: (whitespace for clarity)
635 ( ( ([^:@/]*) (:[^@/]*)? @ )? ([^/:]*) (:([0-9]*)?) )? (/.*)?
636 ( ( ( user ) ( pw )? )? (host) (port)? )? (path <return value>)?
638 It returns NULL if neither <host> nor <path> could be matched.
640 port is checked to ensure that it does not exceed 0xffff.
642 return value is <path> or is "/" if the path portion is not present
643 All other arguments are set to 0 or NULL if their portions are not present
645 pedantic: this function ends up doing an unbounded lookahead, making it
646 potentially O(n^2) instead of O(n). This could be avoided. Realistically, though,
647 its just the password field.
649 Differences between the old and the new implemention:
652 localhost:8080 host="localhost:8080" host="localhost" port=8080
653 /Users/mikef host="" host=NULL
658 #define URI_MOVE_PAST_DELIMITER \
660 cur_tok_start = (++cur); \
661 if (path_end == cur) { \
668 #define uri_strlen_to(from, to) ( (to) - (from) )
669 #define uri_strdup_to(from, to) g_strndup ((from), uri_strlen_to((from), (to)))
677 static UriStrspnSet uri_strspn_sets
[] = {
678 {":@]" GNOME_VFS_URI_PATH_STR
, FALSE
, ""},
679 {"@" GNOME_VFS_URI_PATH_STR
, FALSE
, ""},
680 {":" GNOME_VFS_URI_PATH_STR
, FALSE
, ""},
681 {"]" GNOME_VFS_URI_PATH_STR
, FALSE
, ""}
684 #define URI_DELIMITER_ALL_SET (uri_strspn_sets + 0)
685 #define URI_DELIMITER_USER_SET (uri_strspn_sets + 1)
686 #define URI_DELIMITER_HOST_SET (uri_strspn_sets + 2)
687 #define URI_DELIMITER_IPV6_SET (uri_strspn_sets + 3)
689 #define BV_SET(bv, idx) (bv)[((guchar)(idx))>>3] |= (1 << ( (idx) & 7) )
690 #define BV_IS_SET(bv, idx) ((bv)[((guchar)(idx))>>3] & (1 << ( (idx) & 7)))
693 uri_strspn_to(const char *str
, UriStrspnSet
*set
, const char *path_end
)
699 memset (set
->bv
, 0, sizeof(set
->bv
));
701 for (cur_chr
= set
->chrs
; '\0' != *cur_chr
; cur_chr
++) {
702 BV_SET (set
->bv
, *cur_chr
);
705 BV_SET (set
->bv
, '\0');
709 for (cur
= str
; cur
< path_end
&& ! BV_IS_SET (set
->bv
, *cur
); cur
++)
712 if (cur
>= path_end
|| '\0' == *cur
) {
720 split_toplevel_uri (const gchar
*path
, guint path_len
,
721 gchar
**host_return
, gchar
**user_return
,
722 guint
*port_return
, gchar
**password_return
)
724 const char *path_end
;
725 const char *cur_tok_start
;
727 const char *next_delimiter
;
732 g_assert (host_return
!= NULL
);
733 g_assert (user_return
!= NULL
);
734 g_assert (port_return
!= NULL
);
735 g_assert (password_return
!= NULL
);
740 *password_return
= NULL
;
745 if (path
== NULL
|| path_len
== 0) {
746 return g_strdup ("/");
750 path_end
= path
+ path_len
;
752 cur_tok_start
= path
;
753 cur
= uri_strspn_to (cur_tok_start
, URI_DELIMITER_ALL_SET
, path_end
);
759 /* This ':' belongs to username or IPv6 address.*/
760 tmp
= uri_strspn_to (cur_tok_start
, URI_DELIMITER_USER_SET
, path_end
);
762 if (tmp
== NULL
|| *tmp
!= '@') {
763 tmp
= uri_strspn_to (cur_tok_start
, URI_DELIMITER_IPV6_SET
, path_end
);
765 if (tmp
!= NULL
&& *tmp
== ']') {
774 /* Check for IPv6 address. */
777 /* No username:password in the URI */
778 /* cur points to ']' */
780 cur
= uri_strspn_to (cur
, URI_DELIMITER_HOST_SET
, path_end
);
785 next_delimiter
= uri_strspn_to (cur
, URI_DELIMITER_USER_SET
, path_end
);
787 next_delimiter
= NULL
;
792 || (next_delimiter
!= NULL
&& *next_delimiter
!= '/' ))) {
794 /* *cur == ':' or '@' and string contains a @ before a / */
796 if (uri_strlen_to (cur_tok_start
, cur
) > 0) {
798 tmp
= uri_strdup_to (cur_tok_start
,cur
);
799 *user_return
= gnome_vfs_unescape_string (tmp
, NULL
);
804 URI_MOVE_PAST_DELIMITER
;
806 cur
= uri_strspn_to(cur_tok_start
, URI_DELIMITER_USER_SET
, path_end
);
808 if (cur
== NULL
|| *cur
!= '@') {
811 } else if (uri_strlen_to (cur_tok_start
, cur
) > 0) {
813 tmp
= uri_strdup_to (cur_tok_start
,cur
);
814 *password_return
= gnome_vfs_unescape_string (tmp
, NULL
);
820 URI_MOVE_PAST_DELIMITER
;
822 /* Move cur to point to ':' after ']' */
823 cur
= uri_strspn_to (cur_tok_start
, URI_DELIMITER_IPV6_SET
, path_end
);
825 if (cur
!= NULL
&& *cur
== ']') { /* For IPv6 address */
826 cur
= uri_strspn_to (cur
, URI_DELIMITER_HOST_SET
, path_end
);
828 cur
= uri_strspn_to (cur_tok_start
, URI_DELIMITER_HOST_SET
, path_end
);
837 if (uri_strlen_to (cur_tok_start
, path_end
) > 0) {
838 *host_return
= uri_strdup_to (cur_tok_start
, path_end
);
839 if (*(path_end
- 1) == GNOME_VFS_URI_PATH_CHR
) {
840 ret
= g_strdup (GNOME_VFS_URI_PATH_STR
);
845 } else { /* No host, no path */
851 } else if (*cur
== ':') {
855 if (uri_strlen_to (cur_tok_start
, cur
) > 0) {
856 *host_return
= uri_strdup_to (cur_tok_start
, cur
);
859 goto done
; /*No host but a port?*/
862 URI_MOVE_PAST_DELIMITER
;
866 for ( ; cur
< path_end
&& g_ascii_isdigit (*cur
); cur
++) {
871 /* We let :(/.*)$ be treated gracefully */
872 if (*cur
!= '\0' && *cur
!= GNOME_VFS_URI_PATH_CHR
) {
874 goto done
; /* ...but this would be an error */
886 } else /* GNOME_VFS_URI_PATH_CHR == *cur */ {
889 if (uri_strlen_to (cur_tok_start
, cur
) > 0) {
890 *host_return
= uri_strdup_to (cur_tok_start
, cur
);
896 if (*cur_tok_start
!= '\0' && uri_strlen_to (cur_tok_start
, path_end
) > 0) {
897 ret
= uri_strdup_to(cur
, path_end
);
898 } else if (*host_return
!= NULL
) {
899 ret
= g_strdup (GNOME_VFS_URI_PATH_STR
);
905 if (*host_return
!= NULL
) {
907 /* Check for an IPv6 address in square brackets.*/
908 if (strchr (*host_return
, '[') && strchr (*host_return
, ']') && strchr (*host_return
, ':')) {
910 /* Extract the IPv6 address from square braced string. */
911 host
= g_ascii_strdown ((*host_return
) + 1, strlen (*host_return
) - 2);
913 host
= g_ascii_strdown (*host_return
, -1);
916 g_free (*host_return
);
921 /* If we didn't complete our mission, discard all the partials */
923 g_free (*host_return
);
924 g_free (*user_return
);
925 g_free (*password_return
);
931 *password_return
= NULL
;