summaryrefslogtreecommitdiff
path: root/cut-n-paste-code/libegg/egg-recent-vfs-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'cut-n-paste-code/libegg/egg-recent-vfs-utils.c')
-rw-r--r--cut-n-paste-code/libegg/egg-recent-vfs-utils.c570
1 files changed, 570 insertions, 0 deletions
diff --git a/cut-n-paste-code/libegg/egg-recent-vfs-utils.c b/cut-n-paste-code/libegg/egg-recent-vfs-utils.c
new file mode 100644
index 000000000..51083dd96
--- /dev/null
+++ b/cut-n-paste-code/libegg/egg-recent-vfs-utils.c
@@ -0,0 +1,570 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* gnome-vfs-utils.c - Utility gnome-vfs methods. Will use gnome-vfs
+ HEAD in time.
+
+ Copyright (C) 1999 Free Software Foundation
+ Copyright (C) 2000, 2001 Eazel, Inc.
+
+ The Gnome 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.
+
+ The Gnome 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 the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Authors: Ettore Perazzoli <ettore@comm2000.it>
+ John Sullivan <sullivan@eazel.com>
+ Darin Adler <darin@eazel.com>
+*/
+
+#include <config.h>
+
+#include "egg-recent-vfs-utils.h"
+
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef ENABLE_NLS
+#include <glib.h>
+
+#include <libintl.h>
+#define _(String) gettext(String)
+
+#ifdef gettext_noop
+#define N_(String) gettext_noop(String)
+#else
+#define N_(String) (String)
+#endif
+#else /* NLS is disabled */
+#define _(String) (String)
+#define N_(String) (String)
+#define textdomain(String) (String)
+#define gettext(String) (String)
+#define dgettext(Domain,String) (String)
+#define dcgettext(Domain,String,Type) (String)
+#define bindtextdomain(Domain,Directory) (Domain)
+#endif
+
+static char *
+make_valid_utf8 (const char *name)
+{
+ GString *string;
+ const char *remainder, *invalid;
+ int remaining_bytes, valid_bytes;
+
+ string = NULL;
+ remainder = name;
+ remaining_bytes = strlen (name);
+
+ while (remaining_bytes != 0) {
+ if (g_utf8_validate (remainder, remaining_bytes, &invalid)) {
+ break;
+ }
+ valid_bytes = invalid - remainder;
+
+ if (string == NULL) {
+ string = g_string_sized_new (remaining_bytes);
+ }
+ g_string_append_len (string, remainder, valid_bytes);
+ g_string_append_c (string, '?');
+
+ remaining_bytes -= valid_bytes + 1;
+ remainder = invalid + 1;
+ }
+
+ if (string == NULL) {
+ return g_strdup (name);
+ }
+
+ g_string_append (string, remainder);
+ g_string_append (string, _(" (invalid Unicode)"));
+ g_assert (g_utf8_validate (string->str, -1, NULL));
+
+ return g_string_free (string, FALSE);
+}
+
+static gboolean
+istr_has_prefix (const char *haystack, const char *needle)
+{
+ const char *h, *n;
+ char hc, nc;
+
+ /* Eat one character at a time. */
+ h = haystack == NULL ? "" : haystack;
+ n = needle == NULL ? "" : needle;
+ do {
+ if (*n == '\0') {
+ return TRUE;
+ }
+ if (*h == '\0') {
+ return FALSE;
+ }
+ hc = *h++;
+ nc = *n++;
+ hc = g_ascii_tolower (hc);
+ nc = g_ascii_tolower (nc);
+ } while (hc == nc);
+ return FALSE;
+}
+
+static gboolean
+str_has_prefix (const char *haystack, const char *needle)
+{
+ const char *h, *n;
+
+ /* Eat one character at a time. */
+ h = haystack == NULL ? "" : haystack;
+ n = needle == NULL ? "" : needle;
+ do {
+ if (*n == '\0') {
+ return TRUE;
+ }
+ if (*h == '\0') {
+ return FALSE;
+ }
+ } while (*h++ == *n++);
+ return FALSE;
+}
+
+static gboolean
+uri_is_local_scheme (const char *uri)
+{
+ gboolean is_local_scheme;
+ char *temp_scheme;
+ int i;
+ char *local_schemes[] = {"file:", "help:", "ghelp:", "gnome-help:",
+ "trash:", "man:", "info:",
+ "hardware:", "search:", "pipe:",
+ "gnome-trash:", NULL};
+
+ is_local_scheme = FALSE;
+ for (temp_scheme = *local_schemes, i = 0; temp_scheme != NULL; i++, temp_scheme = local_schemes[i]) {
+ is_local_scheme = istr_has_prefix (uri, temp_scheme);
+ if (is_local_scheme) {
+ break;
+ }
+ }
+
+ return is_local_scheme;
+}
+
+static char *
+handle_trailing_slashes (const char *uri)
+{
+ char *temp, *uri_copy;
+ gboolean previous_char_is_column, previous_chars_are_slashes_without_column;
+ gboolean previous_chars_are_slashes_with_column;
+ gboolean is_local_scheme;
+
+ g_assert (uri != NULL);
+
+ uri_copy = g_strdup (uri);
+ if (strlen (uri_copy) <= 2) {
+ return uri_copy;
+ }
+
+ is_local_scheme = uri_is_local_scheme (uri);
+
+ previous_char_is_column = FALSE;
+ previous_chars_are_slashes_without_column = FALSE;
+ previous_chars_are_slashes_with_column = FALSE;
+
+ /* remove multiple trailing slashes */
+ for (temp = uri_copy; *temp != '\0'; temp++) {
+ if (*temp == '/' && !previous_char_is_column) {
+ previous_chars_are_slashes_without_column = TRUE;
+ } else if (*temp == '/' && previous_char_is_column) {
+ previous_chars_are_slashes_without_column = FALSE;
+ previous_char_is_column = TRUE;
+ previous_chars_are_slashes_with_column = TRUE;
+ } else {
+ previous_chars_are_slashes_without_column = FALSE;
+ previous_char_is_column = FALSE;
+ previous_chars_are_slashes_with_column = FALSE;
+ }
+
+ if (*temp == ':') {
+ previous_char_is_column = TRUE;
+ }
+ }
+
+ if (*temp == '\0' && previous_chars_are_slashes_without_column) {
+ if (is_local_scheme) {
+ /* go back till you remove them all. */
+ for (temp--; *(temp) == '/'; temp--) {
+ *temp = '\0';
+ }
+ } else {
+ /* go back till you remove them all but one. */
+ for (temp--; *(temp - 1) == '/'; temp--) {
+ *temp = '\0';
+ }
+ }
+ }
+
+ if (*temp == '\0' && previous_chars_are_slashes_with_column) {
+ /* go back till you remove them all but three. */
+ for (temp--; *(temp - 3) != ':' && *(temp - 2) != ':' && *(temp - 1) != ':'; temp--) {
+ *temp = '\0';
+ }
+ }
+
+
+ return uri_copy;
+}
+
+static char *
+make_uri_canonical (const char *uri)
+{
+ char *canonical_uri, *old_uri, *p;
+ gboolean relative_uri;
+
+ relative_uri = FALSE;
+
+ if (uri == NULL) {
+ return NULL;
+ }
+
+ /* FIXME bugzilla.eazel.com 648:
+ * This currently ignores the issue of two uris that are not identical but point
+ * to the same data except for the specific cases of trailing '/' characters,
+ * file:/ and file:///, and "lack of file:".
+ */
+
+ canonical_uri = handle_trailing_slashes (uri);
+
+ /* Note: In some cases, a trailing slash means nothing, and can
+ * be considered equivalent to no trailing slash. But this is
+ * not true in every case; specifically not for web addresses passed
+ * to a web-browser. So we don't have the trailing-slash-equivalence
+ * logic here, but we do use that logic in EelDirectory where
+ * the rules are more strict.
+ */
+
+ /* Add file: if there is no scheme. */
+ if (strchr (canonical_uri, ':') == NULL) {
+ old_uri = canonical_uri;
+
+ if (old_uri[0] != '/') {
+ /* FIXME bugzilla.eazel.com 5069:
+ * bandaid alert. Is this really the right thing to do?
+ *
+ * We got what really is a relative path. We do a little bit of
+ * a stretch here and assume it was meant to be a cryptic absolute path,
+ * and convert it to one. Since we can't call gnome_vfs_uri_new and
+ * gnome_vfs_uri_to_string to do the right make-canonical conversion,
+ * we have to do it ourselves.
+ */
+ relative_uri = TRUE;
+ canonical_uri = gnome_vfs_make_path_name_canonical (old_uri);
+ g_free (old_uri);
+ old_uri = canonical_uri;
+ canonical_uri = g_strconcat ("file:///", old_uri, NULL);
+ } else {
+ canonical_uri = g_strconcat ("file:", old_uri, NULL);
+ }
+ g_free (old_uri);
+ }
+
+ /* Lower-case the scheme. */
+ for (p = canonical_uri; *p != ':'; p++) {
+ g_assert (*p != '\0');
+ *p = g_ascii_tolower (*p);
+ }
+
+ if (!relative_uri) {
+ old_uri = canonical_uri;
+ canonical_uri = gnome_vfs_make_uri_canonical (canonical_uri);
+ if (canonical_uri != NULL) {
+ g_free (old_uri);
+ } else {
+ canonical_uri = old_uri;
+ }
+ }
+
+ /* FIXME bugzilla.eazel.com 2802:
+ * Work around gnome-vfs's desire to convert file:foo into file://foo
+ * by converting to file:///foo here. When you remove this, check that
+ * typing "foo" into location bar does not crash and returns an error
+ * rather than displaying the contents of /
+ */
+ if (str_has_prefix (canonical_uri, "file://")
+ && !str_has_prefix (canonical_uri, "file:///")) {
+ old_uri = canonical_uri;
+ canonical_uri = g_strconcat ("file:/", old_uri + 5, NULL);
+ g_free (old_uri);
+ }
+
+ return canonical_uri;
+}
+
+static char *
+format_uri_for_display (const char *uri, gboolean filenames_are_locale_encoded)
+{
+ char *canonical_uri, *path, *utf8_path;
+
+ g_return_val_if_fail (uri != NULL, g_strdup (""));
+
+ canonical_uri = make_uri_canonical (uri);
+
+ /* If there's no fragment and it's a local path. */
+ path = gnome_vfs_get_local_path_from_uri (canonical_uri);
+
+ if (path != NULL) {
+ if (filenames_are_locale_encoded) {
+ utf8_path = g_locale_to_utf8 (path, -1, NULL, NULL, NULL);
+ if (utf8_path) {
+ g_free (canonical_uri);
+ g_free (path);
+ return utf8_path;
+ }
+ } else if (g_utf8_validate (path, -1, NULL)) {
+ g_free (canonical_uri);
+ return path;
+ }
+ }
+
+ if (canonical_uri && !g_utf8_validate (canonical_uri, -1, NULL)) {
+ utf8_path = make_valid_utf8 (canonical_uri);
+ g_free (canonical_uri);
+ canonical_uri = utf8_path;
+ }
+
+ g_free (path);
+ return canonical_uri;
+}
+
+char *
+egg_recent_vfs_format_uri_for_display (const char *uri)
+{
+ static gboolean broken_filenames;
+
+ broken_filenames = g_getenv ("G_BROKEN_FILENAMES") != NULL;
+
+ return format_uri_for_display (uri, broken_filenames);
+}
+
+static gboolean
+is_valid_scheme_character (char c)
+{
+ return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.';
+}
+
+static gboolean
+has_valid_scheme (const char *uri)
+{
+ const char *p;
+
+ p = uri;
+
+ if (!is_valid_scheme_character (*p)) {
+ return FALSE;
+ }
+
+ do {
+ p++;
+ } while (is_valid_scheme_character (*p));
+
+ return *p == ':';
+}
+
+static char *
+escape_high_chars (const guchar *string)
+{
+ char *result;
+ const guchar *scanner;
+ guchar *result_scanner;
+ int escape_count;
+ static const gchar hex[16] = "0123456789ABCDEF";
+
+#define ACCEPTABLE(a) ((a)>=32 && (a)<128)
+
+ escape_count = 0;
+
+ if (string == NULL) {
+ return NULL;
+ }
+
+ for (scanner = string; *scanner != '\0'; scanner++) {
+ if (!ACCEPTABLE(*scanner)) {
+ escape_count++;
+ }
+ }
+
+ if (escape_count == 0) {
+ return g_strdup (string);
+ }
+
+ /* allocate two extra characters for every character that
+ * needs escaping and space for a trailing zero
+ */
+ result = g_malloc (scanner - string + escape_count * 2 + 1);
+ for (scanner = string, result_scanner = result; *scanner != '\0'; scanner++) {
+ if (!ACCEPTABLE(*scanner)) {
+ *result_scanner++ = '%';
+ *result_scanner++ = hex[*scanner >> 4];
+ *result_scanner++ = hex[*scanner & 15];
+
+ } else {
+ *result_scanner++ = *scanner;
+ }
+ }
+
+ *result_scanner = '\0';
+
+ return result;
+}
+
+static char *
+make_uri_from_input_internal (const char *text,
+ gboolean filenames_are_locale_encoded,
+ gboolean strip_trailing_whitespace)
+{
+ char *stripped, *path, *uri, *locale_path, *filesystem_path, *escaped;
+
+ g_return_val_if_fail (text != NULL, g_strdup (""));
+
+ /* Strip off leading whitespaces (since they can't be part of a valid
+ uri). Only strip off trailing whitespaces when requested since
+ they might be part of a valid uri.
+ */
+ if (strip_trailing_whitespace) {
+ stripped = g_strstrip (g_strdup (text));
+ } else {
+ stripped = g_strchug (g_strdup (text));
+ }
+
+ switch (stripped[0]) {
+ case '\0':
+ uri = g_strdup ("");
+ break;
+ case '/':
+ if (filenames_are_locale_encoded) {
+ GError *error = NULL;
+ locale_path = g_locale_from_utf8 (stripped, -1, NULL, NULL, &error);
+ if (locale_path != NULL) {
+ uri = gnome_vfs_get_uri_from_local_path (locale_path);
+ g_free (locale_path);
+ } else {
+ /* We couldn't convert to the locale. */
+ /* FIXME: We should probably give a user-visible error here. */
+ uri = g_strdup("");
+ }
+ } else {
+ uri = gnome_vfs_get_uri_from_local_path (stripped);
+ }
+ break;
+ case '~':
+ if (filenames_are_locale_encoded) {
+ filesystem_path = g_locale_from_utf8 (stripped, -1, NULL, NULL, NULL);
+ } else {
+ filesystem_path = g_strdup (stripped);
+ }
+ /* deliberately falling into default case on fail */
+ if (filesystem_path != NULL) {
+ path = gnome_vfs_expand_initial_tilde (filesystem_path);
+ g_free (filesystem_path);
+ if (*path == '/') {
+ uri = gnome_vfs_get_uri_from_local_path (path);
+ g_free (path);
+ break;
+ }
+ g_free (path);
+ }
+ /* don't insert break here, read above comment */
+ default:
+ if (has_valid_scheme (stripped)) {
+ uri = escape_high_chars (stripped);
+ } else {
+ escaped = escape_high_chars (stripped);
+ uri = g_strconcat ("http://", escaped, NULL);
+ g_free (escaped);
+ }
+ }
+
+ g_free (stripped);
+
+ return uri;
+
+}
+
+char *
+egg_recent_vfs_make_uri_from_input (const char *uri)
+{
+ static gboolean broken_filenames;
+
+ broken_filenames = g_getenv ("G_BROKEN_FILENAMES") != NULL;
+
+ return make_uri_from_input_internal (uri, broken_filenames, TRUE);
+}
+
+static char *
+make_uri_canonical_strip_fragment (const char *uri)
+{
+ const char *fragment;
+ char *without_fragment, *canonical;
+
+ fragment = strchr (uri, '#');
+ if (fragment == NULL) {
+ return make_uri_canonical (uri);
+ }
+
+ without_fragment = g_strndup (uri, fragment - uri);
+ canonical = make_uri_canonical (without_fragment);
+ g_free (without_fragment);
+ return canonical;
+}
+
+static gboolean
+uris_match (const char *uri_1, const char *uri_2, gboolean ignore_fragments)
+{
+ char *canonical_1, *canonical_2;
+ gboolean result;
+
+ if (ignore_fragments) {
+ canonical_1 = make_uri_canonical_strip_fragment (uri_1);
+ canonical_2 = make_uri_canonical_strip_fragment (uri_2);
+ } else {
+ canonical_1 = make_uri_canonical (uri_1);
+ canonical_2 = make_uri_canonical (uri_2);
+ }
+
+ result = strcmp (canonical_1, canonical_2) == 0;
+
+ g_free (canonical_1);
+ g_free (canonical_2);
+
+ return result;
+}
+
+gboolean
+egg_recent_vfs_uris_match (const char *uri_1, const char *uri_2)
+{
+ return uris_match (uri_1, uri_2, FALSE);
+}
+
+char *
+egg_recent_vfs_get_uri_scheme (const char *uri)
+{
+ char *colon;
+
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ colon = strchr (uri, ':');
+
+ if (colon == NULL) {
+ return NULL;
+ }
+
+ return g_strndup (uri, colon - uri);
+}