GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-state.c
1/********************************************************************\
2 * file-utils.c -- simple file utilities *
3 * Copyright (C) 1997 Robin D. Clark <rclark@cs.hmc.edu> *
4 * Copyright (C) 1998 Rob Browning *
5 * Copyright (C) 1998-2000 Linas Vepstas <linas@linas.org> *
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, write to the Free Software *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
20\********************************************************************/
21
22#include <config.h>
23
24#include <glib.h>
25//#include <glib/gstdio.h>
26//#include <errno.h>
27
28#include "gnc-state.h"
29//#include "gnc-engine.h"
30#include "gnc-filepath-utils.h"
31#include "gnc-gkeyfile-utils.h"
32#include "gnc-uri-utils.h"
33#include "qof.h"
34
35/* This static indicates the debugging module that this .o belongs to. */
36static QofLogModule log_module = G_LOG_DOMAIN;
37
38/* Absolute path to the state file for the current book
39 * Before 2.4.1, this file didn't have an extension.
40 * The code will look for such pre 2.4.0 file if no post 2.4.1
41 * version is found. If there is an old style file, save the
42 * name here as well. The old style state file will then be
43 * converted into a new style one the next time state is saved.
44 */
45static gchar* state_file_name = NULL;
46static gchar* state_file_name_pre_241 = NULL;
47/* State file data for current book */
48static GKeyFile *state_file = NULL;
49
50/* Determine which file name to use for the state file. This name is based
51 * the current book's uri and guid.
52 *
53 * The state files will be searched for in the books directory in GnuCash'
54 * private configuration directory. This configuration directory is
55 * platform dependent and can be overridden with environment variable
56 * DOT_GNUCASH_DIR. On linux for example this is ~/.gnucash by default.
57 *
58 * The URL is used to compute the base name of the state file and the
59 * guid is used to differentiate when the user has multiple data files
60 * with the same name.
61 *
62 * As of GnuCash 2.4.1 state files will have their own extension to
63 * differentiate them from data files saved by the user. New state
64 * files will always be created with such an extension. But GnuCash
65 * will continue to search for state files without an extension if
66 * no proper state file with extension is found. */
67
68
69static void
70gnc_state_set_base (const QofSession *session)
71{
72 gchar *basename, *original = NULL, *filename, *file_guid;
73 gchar *sf_extension = NULL;
74 const gchar *uri;
75 gchar guid_string[GUID_ENCODING_LENGTH+1];
76 QofBook *book;
77 const GncGUID *guid;
78 GKeyFile *key_file = NULL;
79 gint i;
80
81 /* Reset filenames possibly found in a previous run */
82 g_free (state_file_name);
83 g_free (state_file_name_pre_241);
84 state_file_name = NULL;
85 state_file_name_pre_241 = NULL;
86
87 uri = qof_session_get_url (session);
88 ENTER("session %p (%s)", session, uri ? uri : "(null)");
89 if (!strlen (uri))
90 {
91 LEAVE("no uri, nothing to do");
92 return;
93 }
94
95 /* Get the book GncGUID */
96 book = qof_session_get_book(session);
97 guid = qof_entity_get_guid(QOF_INSTANCE(book));
98 guid_to_string_buff(guid, guid_string);
99
100 if (gnc_uri_targets_local_fs (uri))
101 {
102 /* The book_uri is a true file, use its basename. */
103 gchar *path = gnc_uri_get_path (uri);
104 basename = g_path_get_basename (path);
105 g_free (path);
106 }
107 else
108 {
109 /* The book_uri is composed of database connection parameters. */
110 gchar* scheme = NULL;
111 gchar* host = NULL;
112 gchar* dbname = NULL;
113 gchar* username = NULL;
114 gchar* password = NULL;
115 gint portnum = 0;
116 gnc_uri_get_components (uri, &scheme, &host, &portnum,
117 &username, &password, &dbname);
118
119 basename = g_strjoin ("_", scheme, host, username, dbname, NULL);
120 g_free (scheme);
121 g_free (host);
122 g_free (username);
123 g_free (password);
124 g_free (dbname);
125 }
126
127 DEBUG ("Basename %s", basename);
128 original = gnc_build_book_path (basename);
129 g_free (basename);
130 DEBUG ("Original %s", original);
131
132 sf_extension = g_strdup (STATE_FILE_EXT);
133 i = 1;
134 while (1)
135 {
136 if (i == 1)
137 filename = g_strconcat (original, sf_extension, NULL);
138 else
139 filename = g_strdup_printf ("%s_%d%s", original, i, sf_extension);
140 DEBUG ("Trying %s", filename);
141 key_file = gnc_key_file_load_from_file (filename, TRUE, FALSE, NULL);
142 DEBUG ("Result %p", key_file);
143
144 if (!key_file)
145 {
146 DEBUG ("No key file by that name");
147 if (g_strcmp0 (sf_extension, STATE_FILE_EXT) == 0)
148 {
149 DEBUG ("Trying old state file names for compatibility");
150 i = 1;
151 g_free (sf_extension);
152 sf_extension = g_strdup ("");
153
154 /* Regardless of whether or not an old state file is found,
155 * the currently tested name should be used for the future
156 * state file.
157 */
158 state_file_name = filename;
159 continue;
160 }
161
162 /* No old style file found. We'll return with the new file name
163 * we set earlier, and no existing key file. */
164 g_free (filename);
165 break;
166 }
167
168 file_guid = g_key_file_get_string (key_file,
169 STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
170 NULL);
171 DEBUG ("File GncGUID is %s", file_guid ? file_guid : "<not found>");
172 if (g_strcmp0 (guid_string, file_guid) == 0)
173 {
174 DEBUG ("Matched !!!");
175 /* Save the found file for later use. Which name to save to
176 * depends on whether it was an old or new style file name
177 */
178 if (g_strcmp0 (sf_extension, STATE_FILE_EXT) == 0)
179 state_file_name = filename;
180 else
181 state_file_name_pre_241 = filename;
182
183 g_free (file_guid);
184 break;
185 }
186 DEBUG ("Clean up this pass");
187 g_free (file_guid);
188 g_key_file_free (key_file);
189 g_free (filename);
190 i++;
191 }
192
193 DEBUG("Clean up");
194 g_free(sf_extension);
195 g_free(original);
196 if (key_file != NULL)
197 g_key_file_free (key_file);
198
199 LEAVE ();
200}
201
202GKeyFile *gnc_state_load (const QofSession *session)
203{
204 /* Drop possible previous state_file first */
205 if (state_file)
206 {
207 g_key_file_free (state_file);
208 state_file = NULL;
209 }
210
211 gnc_state_set_base (session);
212
213 if (state_file_name_pre_241)
214 state_file = gnc_key_file_load_from_file (state_file_name_pre_241,
215 TRUE, TRUE, NULL);
216 else if (state_file_name)
217 state_file = gnc_key_file_load_from_file (state_file_name,
218 TRUE, TRUE, NULL);
219
220 return gnc_state_get_current ();
221}
222
223void gnc_state_save (const QofSession *session)
224{
225 GError *error = NULL;
226
227 if (!strlen (qof_session_get_url(session)))
228 {
229 DEBUG("No file associated with session - skip state saving");
230 return;
231 }
232
233 gnc_state_set_base (session);
234
235 /* Write it all out to disk */
236 if (state_file_name)
237 gnc_key_file_save_to_file(state_file_name, state_file, &error);
238 else
239 PWARN ("No state file name set, can't save state");
240
241 if (error)
242 {
243 PERR ("Error: Cannot open state file %s", error->message);
244 g_error_free (error);
245 }
246}
247
248GKeyFile *gnc_state_get_current (void)
249{
250 if (!state_file)
251 {
252 PINFO ("No pre-existing state found, creating new one");
253 state_file = g_key_file_new ();
254 }
255
256 return state_file;
257
258}
259
260gint gnc_state_drop_sections_for (const gchar *partial_name)
261{
262 gchar **groups;
263 gint found_count = 0, dropped_count = 0;
264 gsize i, num_groups;
265 GError *error = NULL;
266
267 if (!state_file)
268 {
269 PWARN ("No pre-existing state found, ignoring drop request");
270 return 0;
271 }
272
273 ENTER("");
274
275 groups = g_key_file_get_groups (state_file, &num_groups);
276 for (i = 0; i < num_groups; i++)
277 {
278 if (g_strstr_len (groups[i], -1, partial_name))
279 {
280 DEBUG ("Section \"%s\" matches \"%s\", removing", groups[i], partial_name);
281 found_count++;
282 if (!g_key_file_remove_group (state_file, groups[i], &error))
283 {
284 PWARN ("Warning: unable to remove section %s.\n %s",
285 groups[i],
286 error->message);
287 g_error_free (error);
288 }
289 else
290 dropped_count++;
291
292 }
293 }
294 g_strfreev (groups);
295
296 LEAVE("Found %i sections matching \"%s\", successfully removed %i",
297 found_count, partial_name, dropped_count);
298 return dropped_count;
299
300}
301
File path resolution utility functions.
GKeyFile helper routines.
Functions to load, save and get gui state.
Utility functions for convert uri in separate components and back.
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
gboolean gnc_key_file_save_to_file(const gchar *filename, GKeyFile *key_file, GError **error)
Write a key/value file from memory to disk.
GKeyFile * gnc_key_file_load_from_file(const gchar *filename, gboolean ignore_error, gboolean return_empty_struct, GError **caller_error)
Open and read a key/value file from disk into memory.
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition guid.cpp:208
gint gnc_state_drop_sections_for(const gchar *partial_name)
Drop all sections from the state file whose name contains partial_name.
Definition gnc-state.c:260
GKeyFile * gnc_state_load(const QofSession *session)
Load the state from a state file on disk for the given session.
Definition gnc-state.c:202
void gnc_state_save(const QofSession *session)
Save the state to a state file on disk for the given session.
Definition gnc-state.c:223
GKeyFile * gnc_state_get_current(void)
Returns a pointer to the most recently loaded state.
Definition gnc-state.c:248
const GncGUID * qof_entity_get_guid(gconstpointer ent)
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gchar * gnc_uri_get_path(const gchar *uri)
Extracts the path part from a uri.
gboolean gnc_uri_targets_local_fs(const gchar *uri)
Checks if the given uri is either a valid file uri or a local filesystem path.
void gnc_uri_get_components(const gchar *uri, gchar **scheme, gchar **hostname, gint32 *port, gchar **username, gchar **password, gchar **path)
Converts a uri in separate components.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47