r18842 - gnucash/trunk - Use a normalized uri format internally to refer to data stores.

Geert Janssens gjanssens at code.gnucash.org
Fri Mar 5 15:15:32 EST 2010


Author: gjanssens
Date: 2010-03-05 15:15:31 -0500 (Fri, 05 Mar 2010)
New Revision: 18842
Trac: http://svn.gnucash.org/trac/changeset/18842

Added:
   gnucash/trunk/src/core-utils/gnc-uri-utils.c
   gnucash/trunk/src/core-utils/gnc-uri-utils.h
   gnucash/trunk/src/gnome-utils/gnc-keyring.c
   gnucash/trunk/src/gnome-utils/gnc-keyring.h
Modified:
   gnucash/trunk/configure.in
   gnucash/trunk/po/POTFILES.in
   gnucash/trunk/src/backend/dbi/gnc-backend-dbi.c
   gnucash/trunk/src/backend/xml/gnc-backend-xml.c
   gnucash/trunk/src/core-utils/Makefile.am
   gnucash/trunk/src/core-utils/gnc-filepath-utils.c
   gnucash/trunk/src/core-utils/gnc-filepath-utils.h
   gnucash/trunk/src/gnome-utils/Makefile.am
   gnucash/trunk/src/gnome-utils/dialog-file-access.c
   gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.c
   gnucash/trunk/src/gnome-utils/gnc-file.c
   gnucash/trunk/src/gnome-utils/gnc-main-window.c
   gnucash/trunk/src/gnome-utils/gnc-plugin-file-history.c
   gnucash/trunk/src/gnome/top-level.c
   gnucash/trunk/src/libqof/qof/qofsession.c
Log:
Use a normalized uri format internally to refer to data stores.

Data stores for GC can be a file (xml or sqlite3) or a database
one some server (mysql or postgres).
Wherever it makes sense internally, data stores will be referred to
via a normalized uri:
protocol://user:password@host:port/path
Depending on the context and story type some of these parts are optional or unused.

To achieve this, a new utility interface has been setup:
gnc_uri_<xxx>_<yyy>
that can be used to manipulate the uris or convert from non-normalized
formats to normalized and back.
For example, when the user selects a file in the Open or Save As dialog,
gnc_uri_get_normalized_uri will convert the file into a normalized uri.
Or when the actual filename is needed this can be extracted with
gnc_uri_get_path.
You can also test if a uri defines a file or something else with
gnc_uri_is_file_uri.

For the complete documentation, see src/core-utils/gnc-uri-uitls.h

This commit installs gnc-uri-utils and modifies the source where it makes
sense to use its convenience functions. This concerns all functions that
had to deal with file access in some way or another, the history module
and the functions that generate the history menu list and the window titles.

Note that gnc-uri-utils replaces xaccResolveFilePath and xaccResolveUrl in all cases.
xaccResolveUrl has been removed, because gnc-uri-utils fully replaces its functionality.
xaccResolveFilePath is used internally in gnc-uri-utils to ensure an absolute path
is always returned (in case of a file uri, not for db uris). But it has been renamed to
gnc_resolve_file_path to be more consistent with the other functions.

Lastly, this commit also adds a first implementation to work with a keyring to
store and retrieve passwords, althoug

Modified: gnucash/trunk/configure.in
===================================================================
--- gnucash/trunk/configure.in	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/configure.in	2010-03-05 20:15:31 UTC (rev 18842)
@@ -1103,7 +1103,18 @@
     AC_SUBST(GTKHTML_CFLAGS)
     AC_SUBST(GTKHTML_LIBS)
 
-   
+
+    ###-----------------------------------------------------------------------
+    ## Find a suitable password store
+    
+    if x$host_os = xdarwin
+    then
+        AC_DEFINE(HAVE_OSX_KEYCHAIN,1,[System has an OS X Key chain])
+    else
+        PKG_CHECK_MODULES(GNOME_KEYRING, gnome-keyring-1 >= "0.6",
+            [AC_DEFINE(HAVE_GNOME_KEYRING,1,[System has gnome-keyring 0.6 or better])],
+            [AC_DEFINE(HAVE_NO_KEYRING,1,[System has no suitable keyring service])])
+    fi
     ### ----------------------------------------------------------------------
     
     AC_ARG_ENABLE( efence,

Modified: gnucash/trunk/po/POTFILES.in
===================================================================
--- gnucash/trunk/po/POTFILES.in	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/po/POTFILES.in	2010-03-05 20:15:31 UTC (rev 18842)
@@ -153,6 +153,7 @@
 src/core-utils/gnc-glib-utils.c
 src/core-utils/gnc-main.c
 src/core-utils/gnc-path.c
+src/core-utils/gnc-uri-utils.c
 src/doc/doxygen_main_page.c
 src/engine/Account.c
 src/engine/cap-gains.c
@@ -163,7 +164,6 @@
 src/engine/gnc-budget.c
 src/engine/gnc-commodity.c
 src/engine/gnc-engine.c
-src/engine/gnc-filepath-utils.c
 src/engine/gnc-hooks.c
 src/engine/gnc-lot.c
 src/engine/gncmod-engine.c
@@ -315,6 +315,7 @@
 src/gnome-utils/gnc-gtk-utils.c
 src/gnome-utils/gnc-gui-query.c
 src/gnome-utils/gnc-icons.c
+src/gnome-utils/gnc-keyring.c
 src/gnome-utils/gnc-main-window.c
 src/gnome-utils/gnc-menu-extensions.c
 src/gnome-utils/gncmod-gnome-utils.c

Modified: gnucash/trunk/src/backend/dbi/gnc-backend-dbi.c
===================================================================
--- gnucash/trunk/src/backend/dbi/gnc-backend-dbi.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/backend/dbi/gnc-backend-dbi.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -50,6 +50,7 @@
 #include "Recurrence.h"
 
 #include "gnc-gconf-utils.h"
+#include "gnc-uri-utils.h"
 
 #include "gnc-backend-dbi.h"
 
@@ -220,6 +221,7 @@
     gint result;
     gchar* dirname;
     gchar* basename;
+    gchar *filepath = NULL;
 
     g_return_if_fail( qbe != NULL );
     g_return_if_fail( session != NULL );
@@ -228,17 +230,10 @@
     ENTER (" ");
 
     /* Remove uri type if present */
-    if ( g_str_has_prefix( book_id, FILE_URI_PREFIX ) )
-    {
-        book_id += strlen( FILE_URI_PREFIX );
-    }
-    if ( g_str_has_prefix( book_id, SQLITE3_URI_PREFIX ) )
-    {
-        book_id += strlen( SQLITE3_URI_PREFIX );
-    }
+    filepath = gnc_uri_get_path ( book_id );
 
     if ( !create_if_nonexistent
-            && !g_file_test( book_id, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS ) )
+            && !g_file_test( filepath, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS ) )
     {
         qof_backend_set_error( qbe, ERR_FILEIO_FILE_NOT_FOUND );
         LEAVE(" ");
@@ -258,8 +253,9 @@
         return;
     }
 
-    dirname = g_path_get_dirname( book_id );
-    basename = g_path_get_basename( book_id );
+    dirname = g_path_get_dirname( filepath );
+    basename = g_path_get_basename( filepath );
+    g_free ( filepath );
     dbi_conn_error_handler( be->conn, sqlite3_error_fn, be );
     result = dbi_conn_set_option( be->conn, "host", "localhost" );
     if ( result < 0 )
@@ -406,13 +402,12 @@
                              gboolean create_if_nonexistent )
 {
     GncDbiBackend *be = (GncDbiBackend*)qbe;
-    gchar* dsn = NULL;
-    gchar* host;
-    gchar* port = NULL;
-    gchar* dbname;
-    gchar* username;
-    gchar* password;
-    gint portnum;
+    gchar* protocol = NULL;
+    gchar* host = NULL;
+    gchar* dbname = NULL;
+    gchar* username = NULL;
+    gchar* password = NULL;
+    gint portnum = 0;
     gint result;
     gboolean success = FALSE;
 
@@ -422,33 +417,12 @@
 
     ENTER (" ");
 
-    /* Split the book-id (format host:dbname:username:password or
-       host:port:dbname:username:password) */
-    dsn = g_strdup( book_id );
-    for ( host = dsn; *host != '/'; host++ ) {}
-    host += 2;
-    for ( dbname = host; *dbname != ':'; dbname++ ) {}
-    *dbname++ = '\0';
-    if ( *dbname >= '0' && *dbname <= '9' )
-    {
-        port = dbname;
-        for ( ; *dbname != ':'; dbname++ ) {}
-        *dbname++ = '\0';
-    }
-    for ( username = dbname; *username != ':'; username++ ) {}
-    *username++ = '\0';
-    for ( password = username; *password != ':'; password++ ) {}
-    *password++ = '\0';
+    /* Split the book-id
+     * Format is protocol://username:password@hostname:port/dbname
+       where username, password and port are optional) */
+    gnc_uri_get_components ( book_id, &protocol, &host, portnum,
+                             &username, &password, &dbname );
 
-    if ( port != NULL && *port != '\0' )
-    {
-        portnum = atoi( port );
-    }
-    else
-    {
-        portnum = 0;
-    }
-
     // Try to connect to the db.  If it doesn't exist and the create_if_nonexistent
     // flag is TRUE, we'll need to connect to the 'mysql' db and execute the
     // CREATE DATABASE ddl statement there.
@@ -549,10 +523,11 @@
     }
     be->sql_be.timespec_format = MYSQL_TIMESPEC_STR_FORMAT;
 exit:
-    if ( dsn != NULL )
-    {
-        g_free( dsn );
-    }
+    g_free( protocol );
+    g_free( host );
+    g_free( username );
+    g_free( password );
+    g_free( dbname );
 
     LEAVE (" ");
 }
@@ -586,15 +561,14 @@
                                 gboolean create_if_nonexistent )
 {
     GncDbiBackend *be = (GncDbiBackend*)qbe;
-    gint result;
-    gchar* dsn;
-    gchar* host;
-    gchar* port = NULL;
-    gchar* dbname;
-    gchar* username;
-    gchar* password;
+    gint result = 0;
+    gchar* protocol = NULL;
+    gchar* host = NULL;
+    gchar* dbname = NULL;
+    gchar* username = NULL;
+    gchar* password = NULL;
     gboolean success = FALSE;
-    gint portnum;
+    gint portnum = 0;
 
     g_return_if_fail( qbe != NULL );
     g_return_if_fail( session != NULL );
@@ -602,32 +576,13 @@
 
     ENTER (" ");
 
-    /* Split the book-id (format host:dbname:username:password or
-       host:port:dbname:username:password) */
-    dsn = g_strdup( book_id );
-    for ( host = dsn; *host != '/'; host++ ) {}
-    host += 2;
-    for ( dbname = host; *dbname != ':'; dbname++ ) {}
-    *dbname++ = '\0';
-    if ( *dbname >= '0' && *dbname <= '9' )
-    {
-        port = dbname;
-        for ( ; *dbname != ':'; dbname++ ) {}
-        *dbname++ = '\0';
-    }
-    for ( username = dbname; *username != ':'; username++ ) {}
-    *username++ = '\0';
-    for ( password = username; *password != ':'; password++ ) {}
-    *password++ = '\0';
-
-    if ( port != NULL && *port != '\0' )
-    {
-        portnum = atoi( port );
-    }
-    else
-    {
+    /* Split the book-id
+     * Format is protocol://username:password@hostname:port/dbname
+       where username, password and port are optional) */
+    gnc_uri_get_components ( book_id, &protocol, &host, portnum,
+                             &username, &password, &dbname );
+    if ( portnum == 0 )
         portnum = PGSQL_DEFAULT_PORT;
-    }
 
     // Try to connect to the db.  If it doesn't exist and the create_if_nonexistent
     // flag is TRUE, we'll need to connect to the 'postgres' db and execute the
@@ -729,10 +684,11 @@
     }
     be->sql_be.timespec_format = PGSQL_TIMESPEC_STR_FORMAT;
 exit:
-    if ( dsn != NULL )
-    {
-        g_free( dsn );
-    }
+    g_free( protocol );
+    g_free( host );
+    g_free( username );
+    g_free( password );
+    g_free( dbname );
 
     LEAVE (" ");
 }
@@ -1004,17 +960,20 @@
  *
  */
 static gboolean
-gnc_dbi_check_sqlite3_file( const gchar *path )
+gnc_dbi_check_sqlite3_file( const gchar *uri )
 {
     FILE* f;
     gchar buf[50];
     size_t chars_read;
     gint status;
+    gchar *filename;
 
     // BAD if the path is null
-    g_return_val_if_fail( path != NULL, FALSE );
+    g_return_val_if_fail( uri != NULL, FALSE );
 
-    f = g_fopen( path, "r" );
+    filename = gnc_uri_get_path ( uri );
+    f = g_fopen( filename, "r" );
+    g_free ( filename );
 
     // OK if the file doesn't exist - new file
     if ( f == NULL )

Modified: gnucash/trunk/src/backend/xml/gnc-backend-xml.c
===================================================================
--- gnucash/trunk/src/backend/xml/gnc-backend-xml.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/backend/xml/gnc-backend-xml.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -64,7 +64,7 @@
 #include "TransLog.h"
 #include "gnc-engine.h"
 
-#include "gnc-filepath-utils.h"
+#include "gnc-uri-utils.h"
 
 #include "io-gncxml.h"
 #include "io-gncxml-v2.h"
@@ -227,11 +227,8 @@
     ENTER (" ");
 
     /* Make sure the directory is there */
-    if (g_str_has_prefix(book_id, XML_URI_PREFIX))
-        book_id += strlen(XML_URI_PREFIX);
-    if (g_str_has_prefix(book_id, FILE_URI_PREFIX))
-        book_id += strlen(FILE_URI_PREFIX);
-    be->fullpath = xaccResolveFilePath(book_id);
+    be->fullpath = gnc_uri_get_path (book_id);
+
     if (NULL == be->fullpath)
     {
         qof_backend_set_error (be_start, ERR_FILEIO_FILE_NOT_FOUND);
@@ -504,54 +501,61 @@
 }
 
 static gboolean
-gnc_determine_file_type (const char *path)
+gnc_determine_file_type (const char *uri)
 {
     struct stat sbuf;
     int rc;
     FILE *t;
+    gchar *filename;
+    gboolean result;
 
-    if (!path)
+    if (!uri)
     {
         return FALSE;
     }
 
-    // Since this can be called with "xml:" as a prefix, remove it if it exists
-    if ( g_str_has_prefix( path, "xml:" ) )
+    filename = gnc_uri_get_path ( uri );
+    if (0 == safe_strcmp(filename, QOF_STDOUT))
     {
-        path += 4;
+        result = FALSE;
+        goto det_exit;
     }
-
-    if (0 == safe_strcmp(path, QOF_STDOUT))
-    {
-        return FALSE;
-    }
-    t = g_fopen(path, "r");
+    t = g_fopen( filename, "r" );
     if (!t)
     {
         PINFO (" new file");
-        return TRUE;
+        result = TRUE;
+        goto det_exit;
     }
     fclose(t);
-    rc = g_stat(path, &sbuf);
+    rc = g_stat(filename, &sbuf);
     if (rc < 0)
     {
-        return FALSE;
+        result = FALSE;
+        goto det_exit;
     }
     if (sbuf.st_size == 0)
     {
         PINFO (" empty file");
-        return TRUE;
+        result = TRUE;
+        goto det_exit;
     }
-    if (gnc_is_xml_data_file_v2(path, NULL))
+    if (gnc_is_xml_data_file_v2(filename, NULL))
     {
-        return TRUE;
+        result = TRUE;
+        goto det_exit;
     }
-    else if (gnc_is_xml_data_file(path))
+    else if (gnc_is_xml_data_file(filename))
     {
-        return TRUE;
+        result = TRUE;
+        goto det_exit;
     }
-    PINFO (" %s is not a gnc XML file", path);
-    return FALSE;
+    PINFO (" %s is not a gnc XML file", filename);
+    result = FALSE;
+
+det_exit:
+    g_free ( filename );
+    return result;
 }
 
 static gboolean

Modified: gnucash/trunk/src/core-utils/Makefile.am
===================================================================
--- gnucash/trunk/src/core-utils/Makefile.am	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/core-utils/Makefile.am	2010-03-05 20:15:31 UTC (rev 18842)
@@ -11,6 +11,7 @@
   gnc-gkeyfile-utils.c \
   gnc-glib-utils.c \
   gnc-path.c \
+  gnc-uri-utils.c \
   swig-core-utils.c
 
 libgnc_core_utils_la_LIBADD = \
@@ -28,7 +29,8 @@
   gnc-gdate-utils.h \
   gnc-gkeyfile-utils.h \
   gnc-glib-utils.h \
-  gnc-path.h
+  gnc-path.h \
+  gnc-uri-utils.h
 
 if BUILDING_FROM_SVN
 swig-core-utils.c: core-utils.i ${top_srcdir}/src/base-typemaps.i

Modified: gnucash/trunk/src/core-utils/gnc-filepath-utils.c
===================================================================
--- gnucash/trunk/src/core-utils/gnc-filepath-utils.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/core-utils/gnc-filepath-utils.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -24,10 +24,6 @@
  * @brief file path resolution utilities
  * @author Copyright (c) 1998-2004 Linas Vepstas <linas at linas.org>
  * @author Copyright (c) 2000 Dave Peticolas
- *
- * XXX this file does not belong in the gnucash engine; it is here
- * for the moment only because both the file backend and the app-file
- * GUI code make use of it.
  */
 
 #include "config.h"
@@ -47,7 +43,6 @@
 #endif
 #include <errno.h>
 
-#include "qof.h"
 #include "gnc-path.h"
 #include "gnc-filepath-utils.h"
 
@@ -56,6 +51,7 @@
 #define PATH_MAX MAXPATHLEN
 #endif
 
+
 /**
  * Scrubs a filename by changing "strange" chars (e.g. those that are not
  * valid in a win32 file name) to "_".
@@ -86,37 +82,44 @@
 check_path_return_if_valid(gchar *path)
 {
     if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
+    {
         return path;
+    }
     g_free (path);
     return NULL;
 }
 
-/** @fn char * xaccResolveFilePath (const char * filefrag)
+/** @fn char * gnc_resolve_file_path (const char * filefrag)
  *
  *  @brief Create an absolute path when given a relative path;
  *  otherwise return the argument.
  *
- * If passed a string which g_path_is_absolute declares an absolute
- * path, return the argument. If the string begins with file:,
- * file://, xml:, or xml://, remove that and return the rest.
+ *  @warning filefrag should be a simple path fragment. It shouldn't
+ *  contain xml:// or http:// or <whatever>:// other protocol specifiers.
  *
- * Otherwise, assume that filefrag is a well-formed relative path and
- * try to find a file with its path relative to the current working
- * directory, the installed system-wide data directory (e.g.,
- * /usr/local/share/gnucash), the installed system configuration
- * directory (e.g., /usr/local/etc/gnucash), or in the user's
- * configuration directory (e.g., $HOME/.gnucash/data) in that
- * order. If a matching file is found, return the absolute path to
- * it. If one isn't found, return a absolute path relative to the
- * user's configuration directory and note in the trace file that it
- * needs to be created.
+ *  If passed a string which g_path_is_absolute declares an absolute
+ *  path, return the argument.
  *
- * @param filefrag
+ *  Otherwise, assume that filefrag is a well-formed relative path and
+ *  try to find a file with its path relative to
+ *  \li  the current working directory,
+ *  \li the installed system-wide data directory (e.g., /usr/local/share/gnucash),
+ *  \li the installed system configuration directory (e.g., /usr/local/etc/gnucash),
+ *  \li or in the user's configuration directory (e.g., $HOME/.gnucash/data)
  *
- * @return An absolute file path.
+ *  The paths are searched for in that order. If a matching file is
+ *  found, return the absolute path to it.
+
+ *  If one isn't found, return a absolute path relative to the
+ *  user's configuration directory and note in the trace file that it
+ *  needs to be created.
+ *
+ *  @param filefrag The file path to resolve
+ *
+ *  @return An absolute file path.
  */
-char *
-xaccResolveFilePath (const char * filefrag)
+gchar *
+gnc_resolve_file_path (const gchar * filefrag)
 {
     int namelen;
     gchar *fullpath = NULL, *tmp_path = NULL;
@@ -135,22 +138,6 @@
     if (g_path_is_absolute(filefrag))
         return g_strdup (filefrag);
 
-    if (!g_ascii_strncasecmp(filefrag, "file:", 5))
-    {
-        if (!g_ascii_strncasecmp(filefrag, "file://", 7))
-            return g_strdup(filefrag + 7);
-        else
-            return g_strdup(filefrag + 5);
-    }
-    if ( g_ascii_strncasecmp( filefrag, "xml:", 4 ) == 0 )
-    {
-        if ( g_ascii_strncasecmp( filefrag, "xml://", 6 ) == 0 )
-            return g_strdup( filefrag + 6);
-        else
-            return g_strdup( filefrag + 4);
-    }
-
-
     /* get conservative on the length so that sprintf(getpid()) works ... */
     /* strlen ("/.LCK") + sprintf (%x%d) */
     namelen = strlen (filefrag) + 25;
@@ -183,6 +170,7 @@
     fullpath = gnc_build_data_path(filefrag);
     if (g_file_test(fullpath, G_FILE_TEST_IS_REGULAR))
         return fullpath;
+
     /* OK, it's not there. Note that it needs to be created and pass it
      * back anyway */
     g_warning("create new file %s", fullpath);
@@ -192,89 +180,6 @@
 
 /* ====================================================================== */
 
-/** @fn char * xaccResolveURL (const char * pathfrag)
- *
- *  @brief Return the passed-in string unless it starts with file:,
- *  xml:, or is a raw relative path.
- *
- * Strings starting with http://, https://, or a "registered scheme"
- * (see qof_backend_get_registered_access_method_list()) are returned
- * as-is by this function.
- *
- * Strings which form an absolute path (as determined by
- * g_path_is_absolute()) are passed to xaccResolveFilePath() and
- * immediately returned as-is.
- *
- * Strings which begin with file: or xml: are passed to
- * xaccResolveFilePath, which strips off the "scheme" part (file: or
- * xml: plus // if present) and returns the rest unchanged. This
- * result is passed back to the caller as-is if the original astring
- * started with file:; if it started with xml:, then xml: is prepended
- * before passing it back to the caller. Note that this has the effect
- * of converting a URI of the form xml:///path/to/file into one of the
- * form xml:/path/to/file.
- *
- * Strings which meet none of the above are passed to
- * xaccResolveFilePath and the result returned to the caller.
- *
- * @param pathfrag the string to "resolve"
- *
- *  @return "resolved" string.
- */
-char *
-xaccResolveURL (const char * pathfrag)
-{
-    GList* list;
-    GList* node;
-
-    /* seriously invalid */
-    if (!pathfrag) return NULL;
-
-    /* At this stage of checking, URL's are always, by definition,
-     * resolved.  If there's an error connecting, we'll find out later.
-     */
-
-    if (!g_ascii_strncasecmp (pathfrag, "http://", 7) ||
-            !g_ascii_strncasecmp (pathfrag, "https://", 8))
-    {
-        return g_strdup(pathfrag);
-    }
-
-    /* Check the URL against the list of registered access methods */
-    list = qof_backend_get_registered_access_method_list();
-    for ( node = list; node != NULL; node = node->next )
-    {
-        const gchar* access_method = node->data;
-        if ( strcmp( access_method, "file" ) != 0 &&
-                strcmp( access_method, "xml" ) != 0 )
-        {
-            gchar s[30];
-            sprintf( s, "%s://", access_method );
-            if ( !g_ascii_strncasecmp( pathfrag, s, strlen(s) ) )
-            {
-                g_list_free(list);
-                return g_strdup(pathfrag);
-            }
-        }
-    }
-    g_list_free(list);
-    /*
-     * xml: schemes are a special case, becuase gnc_file_do_save_as()
-     * relies on the phony scheme id being present in the returned path
-     * to distinguish the backend used to save the file. Note that this
-     * has the amusing effect of stripping the // from the phony scheme,
-     * so if it started out as xml:///path/to/data, it gets returned
-     * from here as xml:/path/to/data.
-     */
-    if (!g_ascii_strncasecmp (pathfrag, "xml:", 4))
-    {
-        return (g_strdup_printf( "xml:%s", xaccResolveFilePath (pathfrag)) );
-    }
-    return (xaccResolveFilePath (pathfrag));
-}
-
-/* ====================================================================== */
-
 /** @fn void gnc_validate_directory (const gchar *dirname)
  *  @brief Check that the supplied directory path exists, is a directory, and that the user has adequate permissions to use it.
  *

Modified: gnucash/trunk/src/core-utils/gnc-filepath-utils.h
===================================================================
--- gnucash/trunk/src/core-utils/gnc-filepath-utils.h	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/core-utils/gnc-filepath-utils.h	2010-03-05 20:15:31 UTC (rev 18842)
@@ -1,5 +1,5 @@
 /********************************************************************\
- * gnc-filepath-utils.h -- file path resolutin utilitie             *
+ * gnc-filepath-utils.h -- file path resolution utilities           *
  *                                                                  *
  * This program is free software; you can redistribute it and/or    *
  * modify it under the terms of the GNU General Public License as   *
@@ -39,8 +39,7 @@
  *    $HOME is not defined, then the current working directory is
  *    used.
  */
-char * xaccResolveFilePath (const char * filefrag);
-char * xaccResolveURL (const char * pathfrag);
+gchar *gnc_resolve_file_path (const gchar *filefrag);
 
 const gchar *gnc_dotgnucash_dir (void);
 gchar *gnc_build_dotgnucash_path (const gchar *filename);

Added: gnucash/trunk/src/core-utils/gnc-uri-utils.c
===================================================================
--- gnucash/trunk/src/core-utils/gnc-uri-utils.c	                        (rev 0)
+++ gnucash/trunk/src/core-utils/gnc-uri-utils.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -0,0 +1,272 @@
+/*
+ * gnc-uri-utils.c -- utility functions to convert uri in separate
+ *                    components and back.
+ *
+ * Copyright (C) 2010 Geert Janssens <janssens.geert at telenet.be>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org
+ */
+
+#include <glib.h>
+#include "gnc-uri-utils.h"
+#include "gnc-filepath-utils.h"
+
+/* Checks if the given protocol is used to refer to a file
+ * (as opposed to a network service)
+ */
+gboolean gnc_uri_is_file_protocol (const gchar *protocol)
+{
+    if ( !g_ascii_strcasecmp (protocol, "file") ||
+         !g_ascii_strcasecmp (protocol, "xml") ||
+         !g_ascii_strcasecmp (protocol, "sqlite3")
+         )
+        return TRUE;
+    else
+        return FALSE;
+}
+
+/* Checks if the given uri defines a file
+ * (as opposed to a network service)
+ */
+gboolean gnc_uri_is_file_uri (const gchar *uri)
+{
+    gchar *protocol = gnc_uri_get_protocol ( uri );
+    gboolean result = gnc_uri_is_file_protocol ( protocol );
+
+    g_free ( protocol );
+
+    return result;
+}
+
+/* Splits a uri into its separate components */
+void gnc_uri_get_components (const gchar *uri,
+                             gchar **protocol,
+                             gchar **hostname,
+                             guint32 port,
+                             gchar **username,
+                             gchar **password,
+                             gchar **path)
+{
+    gchar **splituri, **spliturl;
+    gchar *url = NULL, *tmpusername = NULL, *tmphostname = NULL;
+    gchar *delimiter = NULL;
+
+    *protocol = NULL;
+    *hostname = NULL;
+    port      = 0;
+    *username = NULL;
+    *password = NULL;
+    *path     = NULL;
+
+    g_return_if_fail( uri != 0 );
+
+    splituri = g_strsplit ( uri, "://", 2 );
+    if ( splituri[1] == NULL )
+    {
+        /* No protocol means simple file uri */
+        *protocol = g_strdup ( "file" );
+        *path     = g_strdup ( splituri[0] );
+        g_strfreev ( splituri );
+        return;
+    }
+
+    /* At least a protocol was found, set it here */
+    *protocol = g_strdup ( splituri[0] );
+
+    if ( gnc_uri_is_file_protocol ( *protocol ) )
+    {
+        /* Protocol indicates file based uri */
+        *path     = gnc_resolve_file_path ( splituri[1] );
+        g_strfreev ( splituri );
+        return;
+    }
+
+    /* Protocol indicates full network style uri, let's see if it
+     * has a username and/or password
+     */
+    url = g_strdup (splituri[1]);
+    g_strfreev ( splituri );
+
+    delimiter = g_strrstr ( url, "@" );
+    if ( delimiter != NULL )
+    {
+        /* There is at least a username in the url */
+        delimiter[0] = '\0';
+        tmpusername = url;
+        tmphostname = delimiter + 1;
+
+        /* Check if there's a password too */
+        delimiter = g_strstr_len ( tmpusername, -1, ":" );
+        if ( delimiter != NULL )
+        {
+            /* There is password in the url */
+            delimiter[0] = '\0';
+            *username = g_strdup ( (const gchar*)tmpusername );
+            *password = g_strdup ( (const gchar*)(delimiter+1) );
+        }
+    }
+    else
+    {
+        /* No username and password were given */
+        tmphostname = url;
+    }
+
+    /* Find the path part */
+    delimiter = g_strstr_len ( tmphostname, -1, "/" );
+    if ( delimiter != NULL )
+    {
+         delimiter[0] = '\0';
+         if ( gnc_uri_is_file_protocol ( *protocol ) ) /* always return absolute file paths */
+             *path = gnc_resolve_file_path ( (const gchar*)(delimiter+1) );
+         else /* path is no file path, so copy it as is */
+             *path = g_strdup ( (const gchar*)(delimiter+1) );
+    }
+
+    /* Check for a port specifier */
+    delimiter = g_strstr_len ( tmphostname, -1, ":" );
+    if ( delimiter != NULL )
+    {
+         delimiter[0] = '\0';
+         port = g_ascii_strtoll ( (const gchar*)(delimiter+1), NULL, 0 );
+    }
+
+    *hostname = g_strdup ( (const gchar*)tmphostname );
+
+    g_free ( url );
+
+    return;
+
+}
+
+gchar *gnc_uri_get_protocol (const gchar *uri)
+{
+    gchar *protocol = NULL;
+    gchar *hostname = NULL;
+    guint32 port = 0;
+    gchar *username = NULL;
+    gchar *password = NULL;
+    gchar *path     = NULL;
+
+    gnc_uri_get_components ( uri, &protocol, &hostname, port,
+                             &username, &password, &path );
+
+    g_free (hostname);
+    g_free (username);
+    g_free (password);
+    g_free (path);
+
+    return protocol;
+}
+
+gchar *gnc_uri_get_path (const gchar *uri)
+{
+    gchar *protocol = NULL;
+    gchar *hostname = NULL;
+    guint32 port = 0;
+    gchar *username = NULL;
+    gchar *password = NULL;
+    gchar *path     = NULL;
+
+    gnc_uri_get_components ( uri, &protocol, &hostname, port,
+                             &username, &password, &path );
+
+    g_free (protocol);
+    g_free (hostname);
+    g_free (username);
+    g_free (password);
+
+    return path;
+}
+
+/* Generates a normalized uri from the separate components */
+gchar *gnc_uri_create_uri (const gchar *protocol,
+                           const gchar *hostname,
+                           guint32 port,
+                           const gchar *username,
+                           const gchar *password,
+                           const gchar *path)
+{
+    gchar *userpass=NULL, *uri=NULL;
+
+    g_return_val_if_fail( path != 0, NULL );
+
+    if ( (protocol == NULL) || gnc_uri_is_file_protocol ( protocol ) )
+    {
+        /* Compose a file based uri, which means ignore everything but
+         * the protocol and the path
+         * We always return absolute pathnames
+         */
+        gchar *abs_path = gnc_resolve_file_path ( path );
+        if ( protocol == NULL )
+            uri = g_strdup_printf ( "file://%s", abs_path );
+        else
+            uri = g_strdup_printf ( "%s://%s", protocol, abs_path );
+        g_free (abs_path);
+        return uri;
+    }
+
+    /* Not a file based uri, we need to setup all components that are not NULL
+     * For this scenario, hostname is mandatory.
+     */
+    g_return_val_if_fail( hostname != 0, NULL );
+
+    if ( username != NULL )
+    {
+        if ( password != NULL )
+            userpass = g_strdup_printf ( "%s:%s@", username, password);
+        else
+            userpass = g_strdup_printf ( "%s@", username);
+    }
+
+    // XXX Do I have to add the slash always or are there situations
+    //     it is in the path already ?
+    uri = g_strconcat ( protocol, "://", userpass, hostname, "/", path, NULL );
+
+    g_free ( userpass );
+
+    return uri;
+
+}
+
+gchar *gnc_uri_normalize_uri (const gchar *uri, gboolean allow_password)
+{
+    gchar *protocol = NULL;
+    gchar *hostname = NULL;
+    guint32 port = 0;
+    gchar *username = NULL;
+    gchar *password = NULL;
+    gchar *path     = NULL;
+    gchar *newuri   = NULL;
+
+    gnc_uri_get_components ( uri, &protocol, &hostname, port,
+                             &username, &password, &path );
+    if (allow_password)
+        newuri = gnc_uri_create_uri ( protocol, hostname, port,
+                                      username, password, path);
+    else
+        newuri = gnc_uri_create_uri ( protocol, hostname, port,
+                                      username, /* no password */ NULL, path);
+
+    g_free (protocol);
+    g_free (hostname);
+    g_free (username);
+    g_free (password);
+    g_free (path);
+
+    return newuri;
+}


Property changes on: gnucash/trunk/src/core-utils/gnc-uri-utils.c
___________________________________________________________________
Added: svn:eol-style
   + native

Added: gnucash/trunk/src/core-utils/gnc-uri-utils.h
===================================================================
--- gnucash/trunk/src/core-utils/gnc-uri-utils.h	                        (rev 0)
+++ gnucash/trunk/src/core-utils/gnc-uri-utils.h	2010-03-05 20:15:31 UTC (rev 18842)
@@ -0,0 +1,205 @@
+/*
+ * gnc-uri-utils.h -- utility functions to convert uri in separate
+ *                    components and back.
+ *
+ * Copyright (C) 2010 Geert Janssens <janssens.geert at telenet.be>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org
+ */
+
+/** @addtogroup Utils Utility functions
+    @{ */
+/** @addtogroup UtilUri Uri conversion
+ * @{ */
+/** @file gnc-uri-utils.h
+ *  @brief  Utility functions for convert uri in separate components and back
+ *  @author Copyright (C) 2010 Geert Janssens <janssens-geert at telenet.be>
+ *
+ *  These functions help you convert a uri into its separate components
+ *  (being protocol, host name, port, user name, password and path) or
+ *  to compose a uri from these separate components.
+ *
+ */
+
+#ifndef GNCURIUTILS_H_
+#define GNCURIUTILS_H_
+
+/** Converts a uri in separate components.
+ *
+ *  Uri's can take any of the following forms:
+ *
+ *  @li @c /some/filesystem/path A simple file system path (unix style)
+ *  @li @c c:\\some\windows\path A simple file system path (Windows style)
+ *  @li @c proto://[[username[:password]@]hostname[:port]]/path (universal uri)
+ *
+ *  In the last form, anything in square brackets is optional.
+ *
+ *  The function allocates memory for each of the components that it finds
+ *  in the uri. The calling function should free this memory with g_free
+ *  if the items are no longer needed.
+ *
+ *  @param uri The uri to convert
+ *
+ *  @param protocol The protocol for this uri. If the uri didn't have an
+ *  explicit protocol, 'file' will be the assumed protocol and hence what
+ *  will be returned.
+ *  @param hostname The host name of the server to connect to. In case of
+ *  the 'file' protocol, this will be NULL
+ *  @param port An optional port to connect to or 0 if the default port is to
+ *  be used. For the 'file' protocol this is always 0 as well.
+ *  @username Optional user name found in this uri or NULL if none is found.
+ *  @password Optional password found in this uri or NULL if none is found.
+ *  @path The path found in this uri. Note that if the protocol is a file based
+ *  protocol, the path will be converted to an absolute path.
+ *
+ */
+
+void gnc_uri_get_components (const gchar *uri,
+                             gchar **protocol,
+                             gchar **hostname,
+                             guint32 port,
+                             gchar **username,
+                             gchar **password,
+                             gchar **path);
+
+/** Extracts the protocol from a uri
+ *
+ *  Uri's can take any of the following forms:
+ *
+ *  @li @c /some/filesystem/path A simple file system path (unix style)
+ *  @li @c c:\\some\windows\path A simple file system path (Windows style)
+ *  @li @c proto://[[username[:password]@]hostname[:port]]/path (universal uri)
+ *
+ *  In the last form, anything in square brackets is optional.
+ *
+ *  The function allocates memory for the protocol. The calling function should
+ *  free this memory with g_free if it no longer needs the string.
+ *
+ *  @param uri The uri to extract the protocol from
+ *
+ *  @return The protocol for this uri. If the uri didn't have an
+ *  explicit protocol, 'file' will be returned as protocol.
+ */
+
+gchar *gnc_uri_get_protocol (const gchar *uri);
+
+/** Extracts the path part from a uri
+ *
+ *  Uri's can take any of the following forms:
+ *
+ *  @li @c /some/filesystem/path A simple file system path (unix style)
+ *  @li @c c:\\some\windows\path A simple file system path (Windows style)
+ *  @li @c proto://[[username[:password]@]hostname[:port]]/path (universal uri)
+ *
+ *  In the last form, anything in square brackets is optional.
+ *
+ *  The function allocates memory for the path. The calling function should
+ *  free this memory with g_free if it no longer needs the string.
+ *
+ *  @param uri The uri to extract the path part from
+ *
+ *  @return The protocol for this uri, or NULL if no path could be extracted.
+ */
+
+gchar *gnc_uri_get_path (const gchar *uri);
+
+/** Composes a normalized uri starting from its separate components.
+ *
+ *  The resulting uri will take either of these forms:
+ *  @li @c file:///some/absolute/path (file could also be xml or sqlite)
+ *  @li @c file://c:\\some\\windows\\path (file could also be xml or sqlite)
+ *  @li @c protocol://[user[:password]@]hostname[:port]/path
+ *
+ *  Only the components that are provided will be inserted in the uri. However
+ *  if no protocol has been provided, 'file' will be used as default protocol.
+ *
+ *  The function allocates memory for for the uri. The calling function should
+ *  free this memory with g_free the uri is no longer needed.
+ *
+*  @param protocol The protocol for this uri. If NULL,, 'file' will be used
+*   in the uri.
+ *  @param hostname The host name of the server to connect to. This will be
+ *  ignored for the 'file' type protocols ('file', 'xml', 'sqlite').
+ *  @param port An optional port to set o, the uri, or 0 if no port is to be
+ *  set. This will be ignored for the 'file' type protocols ('file', 'xml',
+ *  'sqlite').
+ *  @username Optional user name to set in the uri or NULL otherwise. This will
+ *  be ignored for the 'file' type protocols ('file', 'xml', 'sqlite').
+ *  @password Optional password to set in the uri or NULL otherwise. This will
+ *  be ignored for the 'file' type protocols ('file', 'xml', 'sqlite').
+ *  @path The path to set in the uri.
+ *
+ *  @return The normalized uri.
+ */
+
+gchar *gnc_uri_create_uri (const gchar *protocol,
+                           const gchar *hostname,
+                           guint32 port,
+                           const gchar *username,
+                           const gchar *password,
+                           const gchar *path);
+
+/** Composes a normalized uri starting from any uri (filename, db spec,...).
+ *
+ *  The resulting uri will take either of these forms:
+ *  @li @c file:///some/absolute/path (file could also be xml or sqlite)
+ *  @li @c file://c:\\some\\windows\\path (file could also be xml or sqlite)
+ *  @li @c protocol://[user[:password]@]hostname[:port]/path
+ *
+ *  Only the components that are provided will be inserted in the uri. The
+ *  allow_password parameter controls if the password should be added to the
+ *  returned uri when available.
+ *  If no protocol has been provided, 'file' will be used as default protocol.
+ *
+ *  The function allocates memory for for the uri. The calling function should
+ *  free this memory with g_free the uri is no longer needed.
+ *
+*  @param uri The uri that schould be converted into a normalized uri
+ *  @param allow_password If set to TRUE, the normalized uri and the input uri
+ *  has a password, this passworld will also be set in the normalized uri.
+ *  Otherwise no password will be set in the normalized uri.
+ *
+ *  @return The normalized uri.
+ */
+gchar *gnc_uri_normalize_uri (const gchar *uri, gboolean allow_password);
+
+
+/** Checks if the given protocol is used to refer to a file
+ *  (as opposed to a network service like a database or web url)
+ *
+ *  @param protocol The protocol to check
+ *
+ *  @return TRUE if the protocol is used with files, FALSE of the protocol
+ *  is normally used with network services (database, web url,...)
+ */
+gboolean gnc_uri_is_file_protocol (const gchar *protocol);
+
+/** Checks if the given uri defines a file
+ *  (as opposed to a network service like a database or web url)
+ *
+ *  @param uri The uri to check
+ *
+ *  @return TRUE if the uri is a files, FALSE of the protocol
+ *  is normally used with network services (database, web url,...)
+ */
+gboolean gnc_uri_is_file_uri (const gchar *uri);
+
+#endif /* GNCURIUTILS_H_ */
+/** @} */
+/** @} */
+


Property changes on: gnucash/trunk/src/core-utils/gnc-uri-utils.h
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: gnucash/trunk/src/gnome/top-level.c
===================================================================
--- gnucash/trunk/src/gnome/top-level.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/gnome/top-level.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -42,7 +42,6 @@
 #include "gnc-engine.h"
 #include "gnc-gconf-utils.h"
 #include "gnc-file.h"
-#include "gnc-filepath-utils.h"
 #include "gnc-hooks.h"
 #include "gfec.h"
 #include "gnc-main-window.h"
@@ -97,8 +96,8 @@
                                                location);                   \
       return FALSE;                                                         \
     }                                                                       \
- 
 
+
 static gboolean
 gnc_html_register_url_cb (const char *location, const char *label,
                           gboolean new_window, GNCURLResult *result)

Modified: gnucash/trunk/src/gnome-utils/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome-utils/Makefile.am	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/gnome-utils/Makefile.am	2010-03-05 20:15:31 UTC (rev 18842)
@@ -18,6 +18,7 @@
   ${GLADE_CFLAGS} \
   ${GTK_CFLAGS} \
   ${GNOME_CFLAGS} \
+  ${GNOME_KEYRING_CFLAGS} \
   ${GUILE_INCS} \
   ${QOF_CFLAGS} \
   ${GOFFICE_CFLAGS} \
@@ -68,6 +69,7 @@
   gnc-gtk-utils.c \
   gnc-gui-query.c \
   gnc-icons.c \
+  gnc-keyring.c \
   gnc-main-window.c \
   gnc-menu-extensions.c \
   gnc-plugin-file-history.c \
@@ -136,6 +138,7 @@
   gnc-gnome-utils.h \
   gnc-gui-query.h \
   gnc-icons.h \
+  gnc-keyring.h \
   gnc-main-window.h \
   gnc-menu-extensions.h \
   gnc-plugin-file-history.h \
@@ -186,6 +189,7 @@
   $(top_builddir)/lib/libc/libc-missing.la \
   ${top_builddir}/src/libqof/qof/libgnc-qof.la \
   ${GNOME_LIBS} \
+  ${GNOME_KEYRING_LIBS} \
   ${GLADE_LIBS} \
   ${GUILE_LIBS} \
   ${GLIB_LIBS} \

Modified: gnucash/trunk/src/gnome-utils/dialog-file-access.c
===================================================================
--- gnucash/trunk/src/gnome-utils/dialog-file-access.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/gnome-utils/dialog-file-access.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -29,6 +29,7 @@
 #include <glade/glade.h>
 
 #include "gnc-ui.h"
+#include "gnc-uri-utils.h"
 #include "dialog-utils.h"
 #include "dialog-file-access.h"
 #include "gnc-file.h"
@@ -63,13 +64,14 @@
 static gchar*
 geturl( FileAccessWindow* faw )
 {
-    gchar* url;
+    gchar* url = NULL;
     const gchar* host;
     const gchar* database;
     const gchar* username;
     const gchar* password;
     const gchar* type;
     const gchar* file;
+    const gchar* path;
 
     host = gtk_entry_get_text( faw->tf_host );
     database = gtk_entry_get_text( faw->tf_database );
@@ -78,37 +80,18 @@
     file = gtk_file_chooser_get_filename( faw->fileChooser );
 
     type = gtk_combo_box_get_active_text( faw->cb_uri_type );
-    if ( (( strcmp( type, "xml" ) == 0 ) ||
-            ( strcmp( type, "sqlite3" ) == 0 ) ||
-            ( strcmp( type, "file" ) == 0 )) &&
-            ( file == NULL ) )
-        return NULL;
-
-    if ( strcmp( type, "xml" ) == 0 )
+    if ( gnc_uri_is_file_protocol( type ) )
     {
-        url = g_strdup_printf( "xml://%s", file );
+        if ( file == NULL ) /* file protocol was chosen but no filename was set */
+            return NULL;
+        else                /* file protocol was chosen with filename set */
+            path = file;
     }
-    else if ( strcmp( type, "sqlite3" ) == 0 )
-    {
-        url = g_strdup_printf( "sqlite3://%s", file );
-    }
-    else if ( strcmp( type, "file" ) == 0 )
-    {
-        url = g_strdup_printf( "file://%s", file );
-    }
-    else if ( strcmp( type, "mysql" ) == 0 )
-    {
-        url = g_strdup_printf( "mysql://%s:%s:%s:%s",
-                               host, database, username, password );
-    }
-    else
-    {
-        g_assert( strcmp( type, "postgres" ) == 0 );
-        type = "postgres";
-        url = g_strdup_printf( "postgres://%s:%s:%s:%s",
-                               host, database, username, password );
-    }
+    else                    /* db protocol was chosen */
+        path = database;
 
+    url = gnc_uri_create_uri (type, host, 0, username, password, path);
+
     return url;
 }
 

Modified: gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.c
===================================================================
--- gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -31,7 +31,7 @@
 #include "dialog-utils.h"
 #include "druid-utils.h"
 #include "gnc-backend-xml.h"
-#include "gnc-filepath-utils.h"
+#include "gnc-uri-utils.h"
 #include "gnc-module.h"
 #include "gnc-ui.h"
 #include "io-gncxml-v2.h"
@@ -273,7 +273,7 @@
 
     data = g_new0 (GncXmlImportData, 1);
     data->import_type = XML_CONVERT_SINGLE_FILE;
-    data->filename = g_strdup (filename);
+    data->filename = gnc_uri_get_path (filename);
 
     /* gather ambiguous info */
     gxi_check_file (data);
@@ -751,7 +751,7 @@
         goto cleanup_parse_file;
     }
 
-    logpath = xaccResolveFilePath (data->filename);
+    logpath = gnc_uri_get_path (data->filename);
     xaccLogSetBaseName (logpath);
     xaccLogDisable ();
     gxi_update_progress_bar (_("Reading file..."), 0.0);

Modified: gnucash/trunk/src/gnome-utils/gnc-file.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-file.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/gnome-utils/gnc-file.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -33,12 +33,12 @@
 #include "gnc-component-manager.h"
 #include "gnc-engine.h"
 #include "gnc-file.h"
-#include "gnc-filepath-utils.h"
 #include "gnc-gui-query.h"
 #include "gnc-hooks.h"
 #include "gnc-splash.h"
 #include "gnc-ui.h"
 #include "gnc-ui-util.h"
+#include "gnc-uri-utils.h"
 #include "gnc-window.h"
 #include "gnc-plugin-file-history.h"
 #include "qof.h"
@@ -497,23 +497,21 @@
 static void
 gnc_add_history (QofSession * session)
 {
-    char *url;
+    const gchar *url;
     char *file;
 
     if (!session) return;
 
-    url = xaccResolveURL (qof_session_get_url (session));
-    if (!url)
+    url = qof_session_get_url ( session );
+    if ( !url )
         return;
 
-    if (strncmp (url, "file:", 5) == 0)
-        file = url + 5;
+    if ( gnc_uri_is_file_uri ( url ) )
+        file = gnc_uri_get_path ( url );
     else
-        file = url;
+        file = gnc_uri_normalize_uri ( url, TRUE ); /* FIXME this saves the password visibly in history ! */
 
     gnc_history_add_file (file);
-
-    g_free (url);
 }
 
 static void
@@ -646,7 +644,10 @@
 
     if (!filename) return FALSE;
 
-    newfile = xaccResolveURL (filename);
+    /* FIXME Verify if it is ok that a password is stored
+     * in the uri here.
+     */
+    newfile = gnc_uri_normalize_uri ( filename, TRUE );
     if (!newfile)
     {
         show_session_error (ERR_FILEIO_FILE_NOT_FOUND, filename,
@@ -773,12 +774,20 @@
     if (!uh_oh)
     {
         Account *new_root;
+        gchar *logpath = NULL;
 
-        char * logpath = xaccResolveFilePath(newfile);
+        /* XXX Would logging make sense for databases as well (mysql/postgres) ?
+         * Currently the logpath is relative to the data file path.
+         * Databases don't have a file path, so no logging will be
+         * done for them in the current setup.
+         */
+        if ( gnc_uri_is_file_uri ( newfile ) )
+            logpath = gnc_uri_get_path(newfile);
         PINFO ("logpath=%s", logpath ? logpath : "(null)");
         xaccLogSetBaseName (logpath);
+        g_free ( logpath );
+
         xaccLogDisable();
-
         gnc_window_show_progress(_("Loading user data..."), 0.0);
         qof_session_load (new_session, gnc_window_show_progress);
         gnc_window_show_progress(NULL, -1.0);
@@ -864,27 +873,35 @@
     return TRUE;
 }
 
+/* Routine that pops up a file chooser dialog
+ * 
+ * Note: this dialog is used when dbi is not enabled
+ *       so the paths used in here are always file
+ *       paths, never db uris.
+ */
 gboolean
 gnc_file_open (void)
 {
     const char * newfile;
-    char *lastfile = NULL;
+    gchar *lastpath = NULL;
+    gchar *lastfile = NULL;
     gchar *last_file_dir = NULL;
     gboolean result;
 
     if (!gnc_file_query_save (TRUE))
         return FALSE;
 
-    lastfile = gnc_history_get_last();
-    if (lastfile)
+    lastpath = gnc_history_get_last();
+    lastfile = gnc_uri_get_path ( lastpath );
+    if ( lastfile )
         last_file_dir = g_path_get_dirname(lastfile);
     newfile = gnc_file_dialog (_("Open"), NULL, last_file_dir, GNC_FILE_DIALOG_OPEN);
-    if (lastfile != NULL)
-        g_free(lastfile);
-    if (last_file_dir != NULL)
-        g_free(last_file_dir);
-    result = gnc_post_file_open (newfile);
+    g_free ( lastpath );
+    g_free ( lastfile );
+    g_free ( last_file_dir );
 
+    result = gnc_post_file_open ( newfile );
+
     /* This dialogue can show up early in the startup process. If the
      * user fails to pick a file (by e.g. hitting the cancel button), we
      * might be left with a null topgroup, which leads to nastiness when
@@ -1037,6 +1054,10 @@
     LEAVE (" ");
 }
 
+/* Note: this dialog will only be used when dbi is not enabled
+ *       paths used in it always refer to files and are
+ *       never db uris
+ */
 void
 gnc_file_save_as (void)
 {
@@ -1052,10 +1073,11 @@
     ENTER(" ");
 
     last = gnc_history_get_last();
-    if (last)
+    if ( last && gnc_uri_is_file_uri ( last ) )
     {
-        default_dir = g_path_get_dirname(last);
-        g_free(last);
+        gchar *filepath = gnc_uri_get_path ( last );
+        default_dir = g_path_get_dirname( filepath );
+        g_free ( filepath );
     }
     else
     {
@@ -1063,7 +1085,8 @@
     }
     filename = gnc_file_dialog (_("Save"), NULL, default_dir,
                                 GNC_FILE_DIALOG_SAVE);
-    g_free(default_dir);
+    g_free ( last );
+    g_free ( default_dir );
     if (!filename) return;
 
     gnc_file_do_save_as( filename );
@@ -1080,14 +1103,16 @@
     char *last;
     char *newfile;
     const char *oldfile;
+    gchar *logpath = NULL;
+
     QofBackendError io_err = ERR_BACKEND_NO_ERR;
 
     ENTER(" ");
 
     /* Check to see if the user specified the same file as the current
-     * file. If so, then just do that, instead of the below, which
-     * assumes a truly new name was given. */
-    newfile = xaccResolveURL (filename);
+     * file. If so, then just do a simple save, instead of a full save as */
+    /* FIXME Check if it is ok to have a password in the uri here */
+    newfile = gnc_uri_normalize_uri ( filename, TRUE );
     if (!newfile)
     {
         show_session_error (ERR_FILEIO_FILE_NOT_FOUND, filename,
@@ -1109,7 +1134,6 @@
 
     /* -- this session code is NOT identical in FileOpen and FileSaveAs -- */
 
-    xaccLogSetBaseName(newfile); //FIXME: This is premature.
     save_in_progress++;
     new_session = qof_session_new ();
     qof_session_begin (new_session, newfile, FALSE, FALSE);
@@ -1154,6 +1178,18 @@
         return;
     }
 
+    /* XXX Would logging make sense for databases as well (mysql/postgres) ?
+     * Currently the logpath is relative to the data file path.
+     * Databases don't have a file path, so no logging will be
+     * done for them in the current setup.
+     */
+    if ( gnc_uri_is_file_uri ( newfile ) )
+        logpath = gnc_uri_get_path(newfile);
+    PINFO ("logpath=%s", logpath ? logpath : "(null)");
+    xaccLogSetBaseName (logpath);
+    g_free ( logpath );
+
+
     /* Prevent race condition between swapping the contents of the two
      * sessions, and actually installing the new session as the current
      * one. Any event callbacks that occur in this interval will have

Added: gnucash/trunk/src/gnome-utils/gnc-keyring.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-keyring.c	                        (rev 0)
+++ gnucash/trunk/src/gnome-utils/gnc-keyring.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -0,0 +1,231 @@
+/*
+ * gnc-keyring.c -- utility functions to store and retrieve passwords.
+ *
+ * Copyright (C) 2010 Geert Janssens <janssens.geert at telenet.be>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org
+ */
+
+#include "config.h"
+#include <glib/gi18n.h>
+#include "qof.h"
+#include "gnc-ui.h"
+#include "gnc-keyring.h"
+#ifdef HAVE_GNOME_KEYRING
+#include <gnome-keyring.h>
+#endif
+#ifdef HAVE_OSX_KEYCHAIN
+#include <SecKeychain.h>
+#endif
+
+/* This static indicates the debugging module that this .o belongs to. */
+static QofLogModule log_module = GNC_MOD_GUI;
+
+void gnc_keyring_set_password (const gchar *access_method,
+                               const gchar *server,
+                               guint32 port,
+                               const gchar *service,
+                               const gchar *user,
+                               const gchar* password)
+{
+
+#ifdef HAVE_GNOME_KEYRING
+    GnomeKeyringResult  gkr_result;
+    guint32 *item_id = NULL;
+
+    gkr_result = gnome_keyring_set_network_password_sync
+                       (NULL, user, NULL, server, service,
+                        access_method, NULL, port, password, item_id);
+
+    if (gkr_result != GNOME_KEYRING_RESULT_OK)
+    {
+        PWARN ("Gnome-keyring error: %s",
+                gnome_keyring_result_to_message(gkr_result));
+        PWARN ("The user will be prompted for a password again next time.");
+    }
+#endif /* HAVE_GNOME_KEYRING */
+#ifdef HAVE_OSX_KEYCHAIN
+#  ifdef 0
+    /* FIXME The OSX part hasn't been tested yet */
+    OSStatus status;
+    SecKeychainItemRef *itemRef = NULL;
+
+    /* mysql and postgres aren't valid protocols on Mac OS X.
+     * So we use the security domain parameter to allow us to
+     * distinguish between these two.
+     */
+    // FIXME I'm not sure this works if a password was already in the keychain
+    //       I may have to do a lookup first and if it exists, run some update
+    //       update function instead
+    g_set_application_name(PACKAGE);
+    status = SecKeychainAddInternetPassword ( NULL, /* keychain */
+               strlen(server), server,              /* servername */
+               strlen(access_method), access_method,/* securitydomain */
+               strlen(*user), *user,                /* acountname */
+               strlen(service), service,            /* path */
+               port,                                /* port */
+               kSecProtocolTypeAny,                 /* protocol */
+               kSecAuthenticationTypeDefault,       /* auth type */
+               strlen(password), password,          /* passworddata */
+               SecKeychainItemRef *itemRef );
+
+    if ( status != noErr )
+    {
+        CFStringRef resultstring = SecCopyErrorMessageString( status, NULL );
+        PWARN ( "OS X keychain error: %s", resultstring );
+        PWARN ( "The user will be prompted for a password again next time." );
+        CFRelease ( resultstring );
+    }
+
+
+#  endif /* 0 */
+#endif /* HAVE_OSX_KEYCHAIN */
+}
+
+
+gboolean gnc_keyring_get_password ( GtkWidget *parent,
+                                    const gchar *access_method,
+                                    const gchar *server,
+                                    guint32 port,
+                                    const gchar *service,
+                                    gchar **user,
+                                    gchar **password)
+{
+    gboolean password_found = FALSE;
+#ifdef HAVE_GNOME_KEYRING
+    GnomeKeyringResult  gkr_result;
+    GList *found_list = NULL;
+    GnomeKeyringNetworkPasswordData *found;
+#endif
+#ifdef HAVE_OSX_KEYCHAIN
+#  ifdef 0
+    /* FIXME The OSX part hasn't been tested yet */
+    void *password_data;
+    UInt32 password_length;
+    OSStatus status;
+#  endif /* 0 */
+#endif
+
+    g_return_val_if_fail (user != NULL, FALSE);
+    g_return_val_if_fail (password != NULL, FALSE);
+
+    *password = NULL;
+
+#ifdef HAVE_GNOME_KEYRING
+    g_set_application_name(PACKAGE);
+    gkr_result = gnome_keyring_find_network_password_sync
+                       ( *user, NULL, server, service,
+                        access_method, NULL, port, &found_list );
+
+    if (gkr_result == GNOME_KEYRING_RESULT_OK)
+    {
+        found = (GnomeKeyringNetworkPasswordData *) found_list->data;
+        if (found->password)
+            *password = g_strdup(found->password);
+        password_found = TRUE;
+    }
+    else
+        PWARN ("Gnome-keyring access failed: %s.",
+                gnome_keyring_result_to_message(gkr_result));
+
+    gnome_keyring_network_password_list_free(found_list);
+#endif /* HAVE_GNOME_KEYRING */
+#ifdef HAVE_OSX_KEYCHAIN
+#  ifdef 0
+    /* FIXME The OSX part hasn't been tested yet */
+    void *password_data;
+    UInt32 password_length;
+    OSStatus status;
+
+    /* mysql and postgres aren't valid protocols on Mac OS X.
+     * So we use the security domain parameter to allow us to
+     * distinguish between these two.
+     */
+    status = SecKeychainFindInternetPassword( NULL,
+                strlen(server), server,
+                strlen(access_method), access_method,
+                strlen(*user), *user,
+                strlen(service), service,
+                port,
+                kSecProtocolTypeAny,
+                kSecAuthenticationTypeDefault,
+                &password_length, &password_data,
+                NULL);
+
+    if ( status == noErr )
+    {
+        *password = xmalloc((password_length + 1) * sizeof(char));
+        strncpy(*password, password_data, (size_t)password_length);
+        (*password)[password_length] = '\0';
+        password_found = TRUE;
+        SecKeychainItemFreeContent(NULL, password_data);
+    }
+    else
+    {
+        CFStringRef resultstring = SecCopyErrorMessageString( status, NULL );
+        PWARN ( "OS X keychain error: %s", resultstring );
+        CFRelease ( resultstring );
+    }
+
+#  endif /* 0 */
+#endif /* HAVE_OSX_KEYCHAIN */
+
+    if ( !password_found )
+    {
+        /* If we got here, either no proper password store is
+         * available on this system, or we couldn't retrieve
+         * a password from it. In both cases, just ask the user
+         * to enter one
+         */
+        gchar *db_path, *heading;
+
+        if ( port == 0 )
+            db_path=g_strdup_printf ( "%s://%s/%s", access_method, server, service );
+        else
+            db_path=g_strdup_printf ( "%s://%s:%d/%s", access_method, server, port, service );
+        heading = g_strdup_printf ( /* Translators: %s is a path to a database or any other url,
+                 like mysql://user@server.somewhere/somedb, http://www.somequotes.com/thequotes */
+                _("Enter a user name and password to connect to: %s"),
+                             db_path );
+
+        password_found = gnc_get_username_password ( parent, heading,
+                                                     *user, NULL,
+                                                     user, password );
+        g_free ( db_path );
+        g_free ( heading );
+
+        if ( password_found )
+        {
+            /* User entered new user/password information
+             * Let's try to add it to a password store.
+             */
+            gchar *newuser = g_strdup( *user );
+            gchar *newpassword = g_strdup( *password );
+            gnc_keyring_set_password ( access_method,
+                                       server,
+                                       port,
+                                       service,
+                                       newuser,
+                                       newpassword );
+            g_free ( newuser );
+            g_free ( newpassword );
+        }
+    }
+
+    return password_found;
+}


Property changes on: gnucash/trunk/src/gnome-utils/gnc-keyring.c
___________________________________________________________________
Added: svn:eol-style
   + native

Added: gnucash/trunk/src/gnome-utils/gnc-keyring.h
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-keyring.h	                        (rev 0)
+++ gnucash/trunk/src/gnome-utils/gnc-keyring.h	2010-03-05 20:15:31 UTC (rev 18842)
@@ -0,0 +1,127 @@
+/*
+ * gnc-keyring.h -- utility functions to store and retrieve passwords.
+ *
+ * Copyright (C) 2010 Geert Janssens <janssens.geert at telenet.be>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org
+ */
+
+/** @addtogroup GUI
+    @{ */
+/** @addtogroup GUIUtility
+    @{ */
+/** @file gnc-keyring.h
+    @brief Functions to save and retrieve passwords.
+    @author Copyright (C) 2010 Geert Janssens <janssens-geert at telenet.be>
+
+    GnuCash needs passwords for some of the services it uses, like
+    connecting to a remote database, or bank. For security these passwords
+    shouldn't be stored unless in an encrypted password store. This is
+    implemented for example in Gnome's keyring or Mac OS X' keychain.
+    This file defines some convenience functions to store a password
+    or to retrieve one.
+*/
+#ifndef KEYRING_H_
+#define KEYRING_H_
+
+#include <glib.h>
+
+#include "gnc-ui.h"
+
+/** Attempt to store a password in some trusted keystore. At this point
+ *  that can be Gnome's keyring or Mac OS X' keychain. If no
+ *  such keystore is available, this function does nothing.
+ *
+ *  All the parameters passed (except for the password) will be
+ *  used to create a unique key, so the password can later be
+ *  retrieved again with the same parameters.
+ *
+ *  @param parent Used to transition from in case the user is prompted
+ *                for a password.
+ *  @param access_method Service type the user attempts to access. Can
+ *                things like 'mysql', 'postgres' and so on.
+ *  @param server Server the user wishes to connect to.
+ *  @param port   Port the service listens on. If set to 0, it will
+ *                be ignored in the search for a password.
+ *  @param service The service the user wishes to access on the server.
+ *                This can be a database name or a path.
+ *  @param user   The username to access the service. Remember, although
+ *                you pass it to search for the password, it can have
+ *                changed when the function returns.
+ *  @param password The password to access the service.
+ */
+void gnc_keyring_set_password ( const gchar *access_method,
+                                const gchar *server,
+                                guint32 port,
+                                const gchar *service,
+                                const gchar *user,
+                                const gchar* password );
+
+/** Attempt to retrieve a password to connect to
+ *  a remote service. This is deliberately generic: the remote
+ *  service can be a database, website, anything.
+ *
+ *  If a trusted keystore infrastructure is found (such as the
+ *  Gnome's keyring or Mac OS X' keychain) this infrastructure
+ *  will be queried first.
+ *
+ *  If no such infrastructure is available or the query didn't
+ *  return a valid result, the user will be prompted for his
+ *  password.
+ *
+ *  @warning When the user is prompted for a password, he can also
+ *  change the username. So whenever you call this function, read
+ *  both the username and password values before you continue !
+ *
+ *  @param parent Used to transition from in case the user is prompted
+ *                for a password.
+ *  @param access_method Service type the user attempts to access. Can
+ *                things like 'mysql', 'postgres' and so on.
+ *  @param server Server the user wishes to connect to.
+ *  @param port   Port the service listens on. If set to 0, it will
+ *                be ignored in the search for a password.
+ *  @param service The service the user wishes to access on the server.
+ *                This can be a database name or a path.
+ *  @param user   The user name to access the service. Remember, although
+ *                you pass it to search for the password, it can have
+ *                changed when the function returns.
+ *  @param password The password to access the service.
+ *  @return       a boolean indicating whether or not a valid password
+ *                has been retrieved. The function will return FALSE
+ *                when the user explicitly cancels the password dialog or
+ *                if it wasn't called properly. Otherwise it wil return
+ *                TRUE.
+ *
+ *  access_method, server, port, service and user will be the parameters
+ *  passed to the trusted keystore (if available) to find the unique
+ *  password for this service.
+ */
+
+gboolean gnc_keyring_get_password ( GtkWidget *parent,
+                                    const gchar *access_method,
+                                    const gchar *server,
+                                    guint32 port,
+                                    const gchar *service,
+                                    gchar **user,
+                                    gchar **password );
+
+/* @} */
+/* @} */
+
+
+#endif /* KEYRING_H_ */


Property changes on: gnucash/trunk/src/gnome-utils/gnc-keyring.h
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: gnucash/trunk/src/gnome-utils/gnc-main-window.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-main-window.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/gnome-utils/gnc-main-window.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -59,6 +59,7 @@
 #include "gnc-session.h"
 #include "gnc-ui.h"
 #include "gnc-ui-util.h"
+#include "gnc-uri-utils.h"
 #include "gnc-version.h"
 #include "gnc-window.h"
 #include "gnc-main.h"
@@ -1357,8 +1358,9 @@
     GncPluginPage *page;
     QofBook *book;
     gchar *filename = NULL;
+    const gchar *book_id = NULL;
     const gchar *dirty = "";
-    gchar *title, *ptr;
+    gchar *title;
     GtkAction* action;
 
     /* The save action is sensitive if the book is dirty */
@@ -1369,7 +1371,7 @@
     }
     if (gnc_current_session_exist())
     {
-        filename = (gchar*)gnc_session_get_url (gnc_get_current_session ());
+        book_id = gnc_session_get_url (gnc_get_current_session ());
         book = gnc_get_current_book();
         if (qof_instance_is_dirty(QOF_INSTANCE(book)))
         {
@@ -1381,60 +1383,37 @@
         }
     }
 
-    if (!filename)
+    if (!book_id)
         filename = g_strdup(_("Unsaved Book"));
     else
     {
-        gint num_colons = 0;
-        for (ptr = filename; *ptr; ptr = g_utf8_next_char(ptr))
-        {
-            gunichar c = g_utf8_get_char(ptr);
-            if (c == ':') num_colons++;
-        }
+        gchar *protocol = NULL;
+        gchar *hostname = NULL;
+        gchar *username = NULL;
+        gchar *password = NULL;
+        gchar *path = NULL;
+        guint32 port = 0;
 
-        if (num_colons < 4)
+        gnc_uri_get_components (book_id, &protocol, &hostname,
+                                port, &username, &password, &path);
+
+        if ( gnc_uri_is_file_protocol ( (const gchar*) protocol ) )
         {
-            /* The Gnome HIG 2.0 recommends only the file name (no path) be used. (p15) */
-            ptr = g_utf8_strrchr(filename, -1, G_DIR_SEPARATOR);
-            if (ptr != NULL)
-                filename = g_strdup(g_utf8_next_char(ptr));
+            /* The filename is a true file.
+             * The Gnome HIG 2.0 recommends only the file name (no path) be used. (p15) */
+            filename = g_path_get_basename ( path );
         }
         else
         {
-            const gchar* src = filename;
-            gboolean has_explicit_port = (num_colons == 5);
-
-            filename = g_strdup(filename);
-            ptr = filename;
-            num_colons = 0;
-
-            /* Loop and copy chars, converting username and password (after 3rd ':' (4th if there's
-               an explicit port number) to asterisks. */
-            for ( ; *src; src = g_utf8_next_char(src))
-            {
-                gunichar unichar;
-
-                if (*src == ':' ||
-                        (!has_explicit_port && num_colons < 3) ||
-                        (has_explicit_port && num_colons < 4))
-                {
-                    unichar = g_utf8_get_char(src);
-                }
-                else
-                {
-                    unichar = '*';
-                }
-                ptr += g_unichar_to_utf8 (unichar, ptr);
-                if (unichar == '_')
-                {
-                    ptr += g_unichar_to_utf8 ('_', ptr);
-                }
-                else if (unichar == ':')
-                {
-                    num_colons++;
-                }
-            }
+            /* The filename is composed of database connection parameters.
+             * For this we will show access_method://username@database[:port] */
+            filename = gnc_uri_normalize_uri (book_id, FALSE);
         }
+        g_free(protocol);
+        g_free(hostname);
+        g_free(username);
+        g_free(password);
+        g_free(path);
     }
 
     priv = GNC_MAIN_WINDOW_GET_PRIVATE(window);
@@ -1450,7 +1429,7 @@
     {
         title = g_strdup_printf("%s%s - GnuCash", dirty, filename);
     }
-    g_free(filename);
+    g_free( filename );
 
     return title;
 }

Modified: gnucash/trunk/src/gnome-utils/gnc-plugin-file-history.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-plugin-file-history.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/gnome-utils/gnc-plugin-file-history.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -43,6 +43,7 @@
 #include "gnc-window.h"
 #include "gnc-engine.h"
 #include "gnc-gconf-utils.h"
+#include "gnc-uri-utils.h"
 
 static GObjectClass *parent_class = NULL;
 
@@ -290,85 +291,25 @@
 static gchar *
 gnc_history_generate_label (int index, const gchar *filename)
 {
-    const gchar *src;
-    gchar *result, *dst;
-    gunichar  unichar;
+    gchar *label, *result;
 
-    /* raw byte length, not num characters */
-    result = g_malloc(strlen(filename) * 2);
-
-    dst = result;
-    if (index < 10)
-        dst += g_sprintf(result, "_%d ", (index + 1) % 10);
-
-    /* If the filename begins with "mysql://" or "postgres://", hide the
-    user name and password.  Otherwise, it is a filename - hide everything
-    except the file name. */
-
-    if (g_ascii_strncasecmp(filename, "mysql://", 8) == 0 ||
-            g_ascii_strncasecmp(filename, "postgres://", 11) == 0 )
+    if ( gnc_uri_is_file_uri ( filename ) )
     {
-        gint num_colons = 0;
-        gboolean has_explicit_port;
-
-        /* Count the number of colons to see if there is an explicit port number or not */
-        for (src = filename; *src; src = g_utf8_next_char(src))
-        {
-            gunichar c = g_utf8_get_char(src);
-            if (c == ':') num_colons++;
-        }
-        has_explicit_port = (num_colons == 5);
-        num_colons = 0;
-
-        /* Loop for all chars and copy from 'src' to 'dst'.  While doing this,
-           convert username and password (after 2nd ':', 3rd if explicit port) to asterisks. */
-        src = filename;
-        for ( ; *src; src = g_utf8_next_char(src))
-        {
-            if (*src == ':' ||
-                    (!has_explicit_port && num_colons < 3) ||
-                    (has_explicit_port && num_colons < 4))
-            {
-                unichar = g_utf8_get_char(src);
-            }
-            else
-            {
-                unichar = '*';
-            }
-            dst += g_unichar_to_utf8 (unichar, dst);
-            if (unichar == '_')
-            {
-                dst += g_unichar_to_utf8 ('_', dst);
-            }
-            else if (unichar == ':')
-            {
-                num_colons++;
-            }
-        }
+        /* for file paths, only display the file name */
+        gchar *filepath = gnc_uri_get_path ( filename );
+        label = g_path_get_basename ( filepath );
+        g_free ( filepath );
     }
     else
     {
-        /* Find the filename portion of the path */
-        src = g_utf8_strrchr(filename, -1, G_DIR_SEPARATOR);
-        if (src)
-        {
-            src = g_utf8_next_char(src);
-
-            /* Fix up any underline characters so they aren't mistaken as
-             * command accelerator keys. */
-            for ( ; *src; src = g_utf8_next_char(src))
-            {
-                unichar = g_utf8_get_char(src);
-                dst += g_unichar_to_utf8 (unichar, dst);
-
-                if (unichar == '_')
-                    dst += g_unichar_to_utf8 ('_', dst);
-            }
-        }
+        /* for databases, display the full uri, except for the password */
+        label = gnc_uri_normalize_uri ( filename, FALSE );
     }
 
-    *dst = '\0';
+    result = g_strdup_printf ( "_%d %s", (index + 1) % 10, label);
+    g_free ( label );
     return result;
+
 }
 
 

Modified: gnucash/trunk/src/libqof/qof/qofsession.c
===================================================================
--- gnucash/trunk/src/libqof/qof/qofsession.c	2010-03-05 19:57:25 UTC (rev 18841)
+++ gnucash/trunk/src/libqof/qof/qofsession.c	2010-03-05 20:15:31 UTC (rev 18842)
@@ -1142,6 +1142,7 @@
 {
     char *p, *access_method, *msg;
     int err;
+    gchar **splituri;
 
     if (!session) return;
 
@@ -1174,36 +1175,16 @@
     /* Store the session URL  */
     session->book_id = g_strdup (book_id);
 
-    /* Look for something of the form of "file:/", "http://" or
+    /* Look for something of the form of "file://", "http://" or
      * "postgres://". Everything before the colon is the access
      * method.  Load the first backend found for that access method.
      */
-    p = strchr (book_id, ':');
-    if (p)
-    {
-        access_method = g_strdup (book_id);
-        p = strchr (access_method, ':');
-        *p = '\0';
-        qof_session_load_backend(session, access_method);
-        g_free (access_method);
-#ifdef G_OS_WIN32
-        if (NULL == session->backend)
-        {
-            /* Clear the error condition of previous errors */
-            qof_session_clear_error (session);
-
-            /* On windows, a colon can be part of a normal filename. So if
-            no backend was found (which means the part before the colon
-            wasn't an access method), fall back to the file backend. */
-            qof_session_load_backend(session, "file");
-        }
-#endif
-    }
-    else
-    {
-        /* If no colon found, assume it must be a file-path */
+    splituri = g_strsplit ( book_id, "://", 2 );
+    if ( splituri[1] == NULL ) /* no access method in the uri, use generic "file" backend */
         qof_session_load_backend(session, "file");
-    }
+    else                       /* access method found, load appropriate backend */
+        qof_session_load_backend(session, splituri[0]);
+    g_strfreev ( splituri );
 
     /* No backend was found. That's bad. */
     if (NULL == session->backend)



More information about the gnucash-changes mailing list