|
GnuCash 2.4.99
|
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 }
1.7.4