GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-uri-utils.c
1 /*
2  * gnc-uri-utils.c -- utility functions to convert uri in separate
3  * components and back.
4  *
5  * Copyright (C) 2010 Geert Janssens <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, contact:
19  *
20  * Free Software Foundation Voice: +1-617-542-5942
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
22  * Boston, MA 02110-1301, USA [email protected]
23  */
24 
25 #include <glib.h>
26 #include "gnc-uri-utils.h"
27 #include "gnc-filepath-utils.h"
28 #include "qofsession.h"
29 
30 /* Checks if the given protocol is used to refer to a file
31  * (as opposed to a network service)
32  */
33 gboolean gnc_uri_is_known_protocol (const gchar *protocol)
34 {
35  gboolean is_known_proto = FALSE;
36  GList *node;
37  GList *known_proto_list = qof_backend_get_registered_access_method_list();
38 
39  for ( node = known_proto_list; node != NULL; node = node->next )
40  {
41  gchar *known_proto = node->data;
42  if ( !g_ascii_strcasecmp (protocol, known_proto) )
43  {
44  is_known_proto = TRUE;
45  break;
46  }
47  }
48 
49  g_list_free (known_proto_list);
50  return is_known_proto;
51 }
52 
53 /* Checks if the given protocol is used to refer to a file
54  * (as opposed to a network service)
55  * For simplicity, handle all unknown protocols as if it were
56  * file based protocols. This will avoid password lookups and such.
57  */
58 gboolean gnc_uri_is_file_protocol (const gchar *protocol)
59 {
60  if ( !g_ascii_strcasecmp (protocol, "mysql") ||
61  !g_ascii_strcasecmp (protocol, "postgres")
62  )
63  return FALSE;
64  else
65  return TRUE;
66 }
67 
68 /* Checks if the given uri defines a file
69  * (as opposed to a network service)
70  */
71 gboolean gnc_uri_is_file_uri (const gchar *uri)
72 {
73  gchar *protocol = gnc_uri_get_protocol ( uri );
74  gboolean result = gnc_uri_is_file_protocol ( protocol );
75 
76  g_free ( protocol );
77 
78  return result;
79 }
80 
81 /* Splits a uri into its separate components */
82 void gnc_uri_get_components (const gchar *uri,
83  gchar **protocol,
84  gchar **hostname,
85  gint32 *port,
86  gchar **username,
87  gchar **password,
88  gchar **path)
89 {
90  gchar **splituri;
91  gchar *url = NULL, *tmpusername = NULL, *tmphostname = NULL;
92  gchar *delimiter = NULL;
93 
94  *protocol = NULL;
95  *hostname = NULL;
96  *port = 0;
97  *username = NULL;
98  *password = NULL;
99  *path = NULL;
100 
101  g_return_if_fail( uri != NULL && strlen (uri) > 0);
102 
103  splituri = g_strsplit ( uri, "://", 2 );
104  if ( splituri[1] == NULL )
105  {
106  /* No protocol means simple file uri */
107  *protocol = g_strdup ( "file" );
108  *path = g_strdup ( splituri[0] );
109  g_strfreev ( splituri );
110  return;
111  }
112 
113  /* At least a protocol was found, set it here */
114  *protocol = g_strdup ( splituri[0] );
115 
116  if ( gnc_uri_is_file_protocol ( *protocol ) )
117  {
118  /* Protocol indicates file based uri.
119  * Note that unknown protocols are treated as if they are
120  * file-based protocols. This is done to prevent password
121  * lookups on unknown protocols.
122  * On the other hand, since we don't know the specifics of
123  * unknown protocols, we don't attempt to return an absolute
124  * pathname for them, just whatever was there.
125  */
126  if ( gnc_uri_is_known_protocol ( *protocol ) )
127  *path = gnc_resolve_file_path ( splituri[1] );
128  else
129  *path = g_strdup ( splituri[1] );
130  g_strfreev ( splituri );
131  return;
132  }
133 
134  /* Protocol indicates full network style uri, let's see if it
135  * has a username and/or password
136  */
137  url = g_strdup (splituri[1]);
138  g_strfreev ( splituri );
139 
140  /* Check for "@" sign, but start from the end - the password may contain
141  * this sign as well
142  */
143  delimiter = g_strrstr ( url, "@" );
144  if ( delimiter != NULL )
145  {
146  /* There is at least a username in the url */
147  delimiter[0] = '\0';
148  tmpusername = url;
149  tmphostname = delimiter + 1;
150 
151  /* Check if there's a password too by looking for a :
152  * Start from the beginning this time to avoid possible :
153  * in the password */
154  delimiter = g_strstr_len ( tmpusername, -1, ":" );
155  if ( delimiter != NULL )
156  {
157  /* There is password in the url */
158  delimiter[0] = '\0';
159  *password = g_strdup ( (const gchar*)(delimiter + 1) );
160  }
161  *username = g_strdup ( (const gchar*)tmpusername );
162  }
163  else
164  {
165  /* No username and password were given */
166  tmphostname = url;
167  }
168 
169  /* Find the path part */
170  delimiter = g_strstr_len ( tmphostname, -1, "/" );
171  if ( delimiter != NULL )
172  {
173  delimiter[0] = '\0';
174  if ( gnc_uri_is_file_protocol ( *protocol ) ) /* always return absolute file paths */
175  *path = gnc_resolve_file_path ( (const gchar*)(delimiter + 1) );
176  else /* path is no file path, so copy it as is */
177  *path = g_strdup ( (const gchar*)(delimiter + 1) );
178  }
179 
180  /* Check for a port specifier */
181  delimiter = g_strstr_len ( tmphostname, -1, ":" );
182  if ( delimiter != NULL )
183  {
184  delimiter[0] = '\0';
185  *port = g_ascii_strtoll ( delimiter + 1, NULL, 0 );
186  }
187 
188  *hostname = g_strdup ( (const gchar*)tmphostname );
189 
190  g_free ( url );
191 
192  return;
193 
194 }
195 
196 gchar *gnc_uri_get_protocol (const gchar *uri)
197 {
198  gchar *protocol = NULL;
199  gchar *hostname = NULL;
200  gint32 port = 0;
201  gchar *username = NULL;
202  gchar *password = NULL;
203  gchar *path = NULL;
204 
205  gnc_uri_get_components ( uri, &protocol, &hostname, &port,
206  &username, &password, &path );
207 
208  g_free (hostname);
209  g_free (username);
210  g_free (password);
211  g_free (path);
212 
213  return protocol;
214 }
215 
216 gchar *gnc_uri_get_path (const gchar *uri)
217 {
218  gchar *protocol = NULL;
219  gchar *hostname = NULL;
220  gint32 port = 0;
221  gchar *username = NULL;
222  gchar *password = NULL;
223  gchar *path = NULL;
224 
225  gnc_uri_get_components ( uri, &protocol, &hostname, &port,
226  &username, &password, &path );
227 
228  g_free (protocol);
229  g_free (hostname);
230  g_free (username);
231  g_free (password);
232 
233  return path;
234 }
235 
236 /* Generates a normalized uri from the separate components */
237 gchar *gnc_uri_create_uri (const gchar *protocol,
238  const gchar *hostname,
239  gint32 port,
240  const gchar *username,
241  const gchar *password,
242  const gchar *path)
243 {
244  gchar *userpass = NULL, *portstr = NULL, *uri = NULL;
245 
246  g_return_val_if_fail( path != 0, NULL );
247 
248  if ( (protocol == NULL) || gnc_uri_is_file_protocol ( protocol ) )
249  {
250  /* Compose a file based uri, which means ignore everything but
251  * the protocol and the path
252  * We return an absolute pathname if the protocol is known or
253  * no protocol was given. For an unknown protocol, we return the
254  * path info as is.
255  */
256  gchar *abs_path;
257  if ( protocol && (!gnc_uri_is_known_protocol (protocol)) )
258  abs_path = g_strdup ( path );
259  else
260  abs_path = gnc_resolve_file_path ( path );
261  if ( protocol == NULL )
262  uri = g_strdup_printf ( "file://%s", abs_path );
263  else
264  uri = g_strdup_printf ( "%s://%s", protocol, abs_path );
265  g_free (abs_path);
266  return uri;
267  }
268 
269  /* Not a file based uri, we need to setup all components that are not NULL
270  * For this scenario, hostname is mandatory.
271  */
272  g_return_val_if_fail( hostname != 0, NULL );
273 
274  if ( username != NULL && *username )
275  {
276  if ( password != NULL && *password )
277  userpass = g_strdup_printf ( "%s:%s@", username, password );
278  else
279  userpass = g_strdup_printf ( "%s@", username );
280  }
281  else
282  userpass = g_strdup ( "" );
283 
284  if ( port != 0 )
285  portstr = g_strdup_printf ( ":%d", port );
286  else
287  portstr = g_strdup ( "" );
288 
289  // XXX Do I have to add the slash always or are there situations
290  // it is in the path already ?
291  uri = g_strconcat ( protocol, "://", userpass, hostname, portstr, "/", path, NULL );
292 
293  g_free ( userpass );
294  g_free ( portstr );
295 
296  return uri;
297 
298 }
299 
300 gchar *gnc_uri_normalize_uri (const gchar *uri, gboolean allow_password)
301 {
302  gchar *protocol = NULL;
303  gchar *hostname = NULL;
304  gint32 port = 0;
305  gchar *username = NULL;
306  gchar *password = NULL;
307  gchar *path = NULL;
308  gchar *newuri = NULL;
309 
310  gnc_uri_get_components ( uri, &protocol, &hostname, &port,
311  &username, &password, &path );
312  if (allow_password)
313  newuri = gnc_uri_create_uri ( protocol, hostname, port,
314  username, password, path);
315  else
316  newuri = gnc_uri_create_uri ( protocol, hostname, port,
317  username, /* no password */ NULL, path);
318 
319  g_free (protocol);
320  g_free (hostname);
321  g_free (username);
322  g_free (password);
323  g_free (path);
324 
325  return newuri;
326 }
327 
328 gchar *gnc_uri_add_extension ( const gchar *uri, const gchar *extension )
329 {
330  g_return_val_if_fail( uri != 0, NULL );
331 
332  /* Only add extension if the user provided the extension and the uri is
333  * file based.
334  */
335  if ( !extension || !gnc_uri_is_file_uri( uri ) )
336  return g_strdup( uri );
337 
338  /* Don't add extension if it's already there */
339  if ( g_str_has_suffix( uri, extension ) )
340  return g_strdup( uri );
341 
342  /* Ok, all tests passed, let's add the extension */
343  return g_strconcat( uri, extension, NULL );
344 }
Encapsulates a connection to a backend (persistent store)
gboolean gnc_uri_is_file_protocol(const gchar *protocol)
Definition: gnc-uri-utils.c:58
gboolean gnc_uri_is_file_uri(const gchar *uri)
Definition: gnc-uri-utils.c:71
gchar * gnc_uri_get_path(const gchar *uri)
gboolean gnc_uri_is_known_protocol(const gchar *protocol)
Definition: gnc-uri-utils.c:33
gchar * gnc_resolve_file_path(const gchar *filefrag)
Create an absolute path when given a relative path; otherwise return the argument.
gchar * gnc_uri_normalize_uri(const gchar *uri, gboolean allow_password)
void gnc_uri_get_components(const gchar *uri, gchar **protocol, gchar **hostname, gint32 *port, gchar **username, gchar **password, gchar **path)
Definition: gnc-uri-utils.c:82
gchar * gnc_uri_add_extension(const gchar *uri, const gchar *extension)
gchar * gnc_uri_create_uri(const gchar *protocol, const gchar *hostname, gint32 port, const gchar *username, const gchar *password, const gchar *path)
GList * qof_backend_get_registered_access_method_list(void)
Utility functions for convert uri in separate components and back.
File path resolution utility functions.
gchar * gnc_uri_get_protocol(const gchar *uri)