GnuCash 2.4.99
gnc-uri-utils.c
00001 /*
00002  * gnc-uri-utils.c -- utility functions to convert uri in separate
00003  *                    components and back.
00004  *
00005  * Copyright (C) 2010 Geert Janssens <janssens.geert@telenet.be>
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License as
00009  * published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, contact:
00019  *
00020  * Free Software Foundation           Voice:  +1-617-542-5942
00021  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00022  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00023  */
00024 
00025 #include <glib.h>
00026 #include "gnc-uri-utils.h"
00027 #include "gnc-filepath-utils.h"
00028 #include "qofsession.h"
00029 
00030 /* Checks if the given protocol is used to refer to a file
00031  * (as opposed to a network service)
00032  */
00033 gboolean gnc_uri_is_known_protocol (const gchar *protocol)
00034 {
00035     gboolean is_known_proto = FALSE;
00036     GList *node;
00037     GList *known_proto_list = qof_backend_get_registered_access_method_list();
00038 
00039     for ( node = known_proto_list; node != NULL; node = node->next )
00040     {
00041         gchar *known_proto = node->data;
00042         if ( !g_ascii_strcasecmp (protocol, known_proto) )
00043         {
00044             is_known_proto = TRUE;
00045             break;
00046         }
00047     }
00048 
00049     g_list_free (known_proto_list);
00050     return is_known_proto;
00051 }
00052 
00053 /* Checks if the given protocol is used to refer to a file
00054  * (as opposed to a network service)
00055  * For simplicity, handle all unknown protocols as if it were
00056  * file based protocols. This will avoid password lookups and such.
00057  */
00058 gboolean gnc_uri_is_file_protocol (const gchar *protocol)
00059 {
00060     if ( !g_ascii_strcasecmp (protocol, "mysql") ||
00061             !g_ascii_strcasecmp (protocol, "postgres")
00062        )
00063         return FALSE;
00064     else
00065         return TRUE;
00066 }
00067 
00068 /* Checks if the given uri defines a file
00069  * (as opposed to a network service)
00070  */
00071 gboolean gnc_uri_is_file_uri (const gchar *uri)
00072 {
00073     gchar *protocol = gnc_uri_get_protocol ( uri );
00074     gboolean result = gnc_uri_is_file_protocol ( protocol );
00075 
00076     g_free ( protocol );
00077 
00078     return result;
00079 }
00080 
00081 /* Splits a uri into its separate components */
00082 void gnc_uri_get_components (const gchar *uri,
00083                              gchar **protocol,
00084                              gchar **hostname,
00085                              gint32 *port,
00086                              gchar **username,
00087                              gchar **password,
00088                              gchar **path)
00089 {
00090     gchar **splituri, **spliturl;
00091     gchar *url = NULL, *tmpusername = NULL, *tmphostname = NULL;
00092     gchar *delimiter = NULL;
00093 
00094     *protocol = NULL;
00095     *hostname = NULL;
00096     *port      = 0;
00097     *username = NULL;
00098     *password = NULL;
00099     *path     = NULL;
00100 
00101     g_return_if_fail( uri != NULL );
00102 
00103     splituri = g_strsplit ( uri, "://", 2 );
00104     if ( splituri[1] == NULL )
00105     {
00106         /* No protocol means simple file uri */
00107         *protocol = g_strdup ( "file" );
00108         *path     = g_strdup ( splituri[0] );
00109         g_strfreev ( splituri );
00110         return;
00111     }
00112 
00113     /* At least a protocol was found, set it here */
00114     *protocol = g_strdup ( splituri[0] );
00115 
00116     if ( gnc_uri_is_file_protocol ( *protocol ) )
00117     {
00118         /* Protocol indicates file based uri.
00119          * Note that unknown protocols are treated as if they are
00120          * file-based protocols. This is done to prevent password
00121          * lookups on unknown protocols.
00122          * On the other hand, since we don't know the specifics of
00123          * unknown protocols, we don't attempt to return an absolute
00124          * pathname for them, just whatever was there.
00125          */
00126         if ( gnc_uri_is_known_protocol ( *protocol ) )
00127             *path     = gnc_resolve_file_path ( splituri[1] );
00128         else
00129             *path     = g_strdup ( splituri[1] );
00130         g_strfreev ( splituri );
00131         return;
00132     }
00133 
00134     /* Protocol indicates full network style uri, let's see if it
00135      * has a username and/or password
00136      */
00137     url = g_strdup (splituri[1]);
00138     g_strfreev ( splituri );
00139 
00140     /* Check for "@" sign, but start from the end - the password may contain
00141      * this sign as well
00142      */
00143     delimiter = g_strrstr ( url, "@" );
00144     if ( delimiter != NULL )
00145     {
00146         /* There is at least a username in the url */
00147         delimiter[0] = '\0';
00148         tmpusername = url;
00149         tmphostname = delimiter + 1;
00150 
00151         /* Check if there's a password too by looking for a :
00152          * Start from the beginning this time to avoid possible :
00153          * in the password */
00154         delimiter = g_strstr_len ( tmpusername, -1, ":" );
00155         if ( delimiter != NULL )
00156         {
00157             /* There is password in the url */
00158             delimiter[0] = '\0';
00159             *password = g_strdup ( (const gchar*)(delimiter + 1) );
00160         }
00161         *username = g_strdup ( (const gchar*)tmpusername );
00162     }
00163     else
00164     {
00165         /* No username and password were given */
00166         tmphostname = url;
00167     }
00168 
00169     /* Find the path part */
00170     delimiter = g_strstr_len ( tmphostname, -1, "/" );
00171     if ( delimiter != NULL )
00172     {
00173         delimiter[0] = '\0';
00174         if ( gnc_uri_is_file_protocol ( *protocol ) ) /* always return absolute file paths */
00175             *path = gnc_resolve_file_path ( (const gchar*)(delimiter + 1) );
00176         else /* path is no file path, so copy it as is */
00177             *path = g_strdup ( (const gchar*)(delimiter + 1) );
00178     }
00179 
00180     /* Check for a port specifier */
00181     delimiter = g_strstr_len ( tmphostname, -1, ":" );
00182     if ( delimiter != NULL )
00183     {
00184         delimiter[0] = '\0';
00185         *port = g_ascii_strtoll ( delimiter + 1, NULL, 0 );
00186     }
00187 
00188     *hostname = g_strdup ( (const gchar*)tmphostname );
00189 
00190     g_free ( url );
00191 
00192     return;
00193 
00194 }
00195 
00196 gchar *gnc_uri_get_protocol (const gchar *uri)
00197 {
00198     gchar *protocol = NULL;
00199     gchar *hostname = NULL;
00200     gint32 port     = 0;
00201     gchar *username = NULL;
00202     gchar *password = NULL;
00203     gchar *path     = NULL;
00204 
00205     gnc_uri_get_components ( uri, &protocol, &hostname, &port,
00206                              &username, &password, &path );
00207 
00208     g_free (hostname);
00209     g_free (username);
00210     g_free (password);
00211     g_free (path);
00212 
00213     return protocol;
00214 }
00215 
00216 gchar *gnc_uri_get_path (const gchar *uri)
00217 {
00218     gchar *protocol = NULL;
00219     gchar *hostname = NULL;
00220     gint32 port = 0;
00221     gchar *username = NULL;
00222     gchar *password = NULL;
00223     gchar *path     = NULL;
00224 
00225     gnc_uri_get_components ( uri, &protocol, &hostname, &port,
00226                              &username, &password, &path );
00227 
00228     g_free (protocol);
00229     g_free (hostname);
00230     g_free (username);
00231     g_free (password);
00232 
00233     return path;
00234 }
00235 
00236 /* Generates a normalized uri from the separate components */
00237 gchar *gnc_uri_create_uri (const gchar *protocol,
00238                            const gchar *hostname,
00239                            gint32 port,
00240                            const gchar *username,
00241                            const gchar *password,
00242                            const gchar *path)
00243 {
00244     gchar *userpass = NULL, *portstr = NULL, *uri = NULL;
00245 
00246     g_return_val_if_fail( path != 0, NULL );
00247 
00248     if ( (protocol == NULL) || gnc_uri_is_file_protocol ( protocol ) )
00249     {
00250         /* Compose a file based uri, which means ignore everything but
00251          * the protocol and the path
00252          * We return an absolute pathname if the protocol is known or
00253          * no protocol was given. For an unknown protocol, we return the
00254          * path info as is.
00255          */
00256         gchar *abs_path;
00257         if ( protocol && (!gnc_uri_is_known_protocol (protocol)) )
00258             abs_path = g_strdup ( path );
00259         else
00260             abs_path = gnc_resolve_file_path ( path );
00261         if ( protocol == NULL )
00262             uri = g_strdup_printf ( "file://%s", abs_path );
00263         else
00264             uri = g_strdup_printf ( "%s://%s", protocol, abs_path );
00265         g_free (abs_path);
00266         return uri;
00267     }
00268 
00269     /* Not a file based uri, we need to setup all components that are not NULL
00270      * For this scenario, hostname is mandatory.
00271      */
00272     g_return_val_if_fail( hostname != 0, NULL );
00273 
00274     if ( username != NULL && *username )
00275     {
00276         if ( password != NULL && *password )
00277             userpass = g_strdup_printf ( "%s:%s@", username, password );
00278         else
00279             userpass = g_strdup_printf ( "%s@", username );
00280     }
00281     else
00282         userpass = g_strdup ( "" );
00283 
00284     if ( port != 0 )
00285         portstr = g_strdup_printf ( ":%d", port );
00286     else
00287         portstr = g_strdup ( "" );
00288 
00289     // XXX Do I have to add the slash always or are there situations
00290     //     it is in the path already ?
00291     uri = g_strconcat ( protocol, "://", userpass, hostname, portstr, "/", path, NULL );
00292 
00293     g_free ( userpass );
00294     g_free ( portstr );
00295 
00296     return uri;
00297 
00298 }
00299 
00300 gchar *gnc_uri_normalize_uri (const gchar *uri, gboolean allow_password)
00301 {
00302     gchar *protocol = NULL;
00303     gchar *hostname = NULL;
00304     gint32 port = 0;
00305     gchar *username = NULL;
00306     gchar *password = NULL;
00307     gchar *path     = NULL;
00308     gchar *newuri   = NULL;
00309 
00310     gnc_uri_get_components ( uri, &protocol, &hostname, &port,
00311                              &username, &password, &path );
00312     if (allow_password)
00313         newuri = gnc_uri_create_uri ( protocol, hostname, port,
00314                                       username, password, path);
00315     else
00316         newuri = gnc_uri_create_uri ( protocol, hostname, port,
00317                                       username, /* no password */ NULL, path);
00318 
00319     g_free (protocol);
00320     g_free (hostname);
00321     g_free (username);
00322     g_free (password);
00323     g_free (path);
00324 
00325     return newuri;
00326 }
00327 
00328 gchar *gnc_uri_add_extension ( const gchar *uri, const gchar *extension )
00329 {
00330     g_return_val_if_fail( uri != 0, NULL );
00331 
00332     /* Only add extension if the user provided the extension and the uri is
00333      * file based.
00334      */
00335     if ( !extension || !gnc_uri_is_file_uri( uri ) )
00336         return g_strdup( uri );
00337 
00338     /* Don't add extension if it's already there */
00339     if ( g_str_has_suffix( uri, extension ) )
00340         return g_strdup( uri );
00341 
00342     /* Ok, all tests passed, let's add the extension */
00343     return g_strconcat( uri, extension, NULL );
00344 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines