Line data Source code
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. */
36 : static 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 : */
45 : static gchar* state_file_name = NULL;
46 : static gchar* state_file_name_pre_241 = NULL;
47 : /* State file data for current book */
48 : static 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 :
69 : static void
70 0 : gnc_state_set_base (const QofSession *session)
71 : {
72 0 : gchar *basename, *original = NULL, *filename, *file_guid;
73 0 : gchar *sf_extension = NULL;
74 : const gchar *uri;
75 : gchar guid_string[GUID_ENCODING_LENGTH+1];
76 : QofBook *book;
77 : const GncGUID *guid;
78 0 : GKeyFile *key_file = NULL;
79 : gint i;
80 :
81 : /* Reset filenames possibly found in a previous run */
82 0 : g_free (state_file_name);
83 0 : g_free (state_file_name_pre_241);
84 0 : state_file_name = NULL;
85 0 : state_file_name_pre_241 = NULL;
86 :
87 0 : uri = qof_session_get_url (session);
88 0 : ENTER("session %p (%s)", session, uri ? uri : "(null)");
89 0 : if (!strlen (uri))
90 : {
91 0 : LEAVE("no uri, nothing to do");
92 0 : return;
93 : }
94 :
95 : /* Get the book GncGUID */
96 0 : book = qof_session_get_book(session);
97 0 : guid = qof_entity_get_guid(QOF_INSTANCE(book));
98 0 : guid_to_string_buff(guid, guid_string);
99 :
100 0 : if (gnc_uri_targets_local_fs (uri))
101 : {
102 : /* The book_uri is a true file, use its basename. */
103 0 : gchar *path = gnc_uri_get_path (uri);
104 0 : basename = g_path_get_basename (path);
105 0 : g_free (path);
106 : }
107 : else
108 : {
109 : /* The book_uri is composed of database connection parameters. */
110 0 : gchar* scheme = NULL;
111 0 : gchar* host = NULL;
112 0 : gchar* dbname = NULL;
113 0 : gchar* username = NULL;
114 0 : gchar* password = NULL;
115 0 : gint portnum = 0;
116 0 : gnc_uri_get_components (uri, &scheme, &host, &portnum,
117 : &username, &password, &dbname);
118 :
119 0 : basename = g_strjoin ("_", scheme, host, username, dbname, NULL);
120 0 : g_free (scheme);
121 0 : g_free (host);
122 0 : g_free (username);
123 0 : g_free (password);
124 0 : g_free (dbname);
125 : }
126 :
127 0 : DEBUG ("Basename %s", basename);
128 0 : original = gnc_build_book_path (basename);
129 0 : g_free (basename);
130 0 : DEBUG ("Original %s", original);
131 :
132 0 : sf_extension = g_strdup (STATE_FILE_EXT);
133 0 : i = 1;
134 : while (1)
135 : {
136 0 : if (i == 1)
137 0 : filename = g_strconcat (original, sf_extension, NULL);
138 : else
139 0 : filename = g_strdup_printf ("%s_%d%s", original, i, sf_extension);
140 0 : DEBUG ("Trying %s", filename);
141 0 : key_file = gnc_key_file_load_from_file (filename, TRUE, FALSE, NULL);
142 0 : DEBUG ("Result %p", key_file);
143 :
144 0 : if (!key_file)
145 : {
146 0 : DEBUG ("No key file by that name");
147 0 : if (g_strcmp0 (sf_extension, STATE_FILE_EXT) == 0)
148 : {
149 0 : DEBUG ("Trying old state file names for compatibility");
150 0 : i = 1;
151 0 : g_free (sf_extension);
152 0 : 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 0 : state_file_name = filename;
159 0 : 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 0 : g_free (filename);
165 0 : break;
166 : }
167 :
168 0 : file_guid = g_key_file_get_string (key_file,
169 : STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
170 : NULL);
171 0 : DEBUG ("File GncGUID is %s", file_guid ? file_guid : "<not found>");
172 0 : if (g_strcmp0 (guid_string, file_guid) == 0)
173 : {
174 0 : 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 0 : if (g_strcmp0 (sf_extension, STATE_FILE_EXT) == 0)
179 0 : state_file_name = filename;
180 : else
181 0 : state_file_name_pre_241 = filename;
182 :
183 0 : g_free (file_guid);
184 0 : break;
185 : }
186 0 : DEBUG ("Clean up this pass");
187 0 : g_free (file_guid);
188 0 : g_key_file_free (key_file);
189 0 : g_free (filename);
190 0 : i++;
191 : }
192 :
193 0 : DEBUG("Clean up");
194 0 : g_free(sf_extension);
195 0 : g_free(original);
196 0 : if (key_file != NULL)
197 0 : g_key_file_free (key_file);
198 :
199 0 : LEAVE ();
200 : }
201 :
202 0 : GKeyFile *gnc_state_load (const QofSession *session)
203 : {
204 : /* Drop possible previous state_file first */
205 0 : if (state_file)
206 : {
207 0 : g_key_file_free (state_file);
208 0 : state_file = NULL;
209 : }
210 :
211 0 : gnc_state_set_base (session);
212 :
213 0 : if (state_file_name_pre_241)
214 0 : state_file = gnc_key_file_load_from_file (state_file_name_pre_241,
215 : TRUE, TRUE, NULL);
216 0 : else if (state_file_name)
217 0 : state_file = gnc_key_file_load_from_file (state_file_name,
218 : TRUE, TRUE, NULL);
219 :
220 0 : return gnc_state_get_current ();
221 : }
222 :
223 0 : void gnc_state_save (const QofSession *session)
224 : {
225 0 : GError *error = NULL;
226 :
227 0 : if (!strlen (qof_session_get_url(session)))
228 : {
229 0 : DEBUG("No file associated with session - skip state saving");
230 0 : return;
231 : }
232 :
233 0 : gnc_state_set_base (session);
234 :
235 : /* Write it all out to disk */
236 0 : if (state_file_name)
237 0 : gnc_key_file_save_to_file(state_file_name, state_file, &error);
238 : else
239 0 : PWARN ("No state file name set, can't save state");
240 :
241 0 : if (error)
242 : {
243 0 : PERR ("Error: Cannot open state file %s", error->message);
244 0 : g_error_free (error);
245 : }
246 : }
247 :
248 0 : GKeyFile *gnc_state_get_current (void)
249 : {
250 0 : if (!state_file)
251 : {
252 0 : PINFO ("No pre-existing state found, creating new one");
253 0 : state_file = g_key_file_new ();
254 : }
255 :
256 0 : return state_file;
257 :
258 : }
259 :
260 0 : gint gnc_state_drop_sections_for (const gchar *partial_name)
261 : {
262 : gchar **groups;
263 0 : gint found_count = 0, dropped_count = 0;
264 : gsize i, num_groups;
265 0 : GError *error = NULL;
266 :
267 0 : if (!state_file)
268 : {
269 0 : PWARN ("No pre-existing state found, ignoring drop request");
270 0 : return 0;
271 : }
272 :
273 0 : ENTER("");
274 :
275 0 : groups = g_key_file_get_groups (state_file, &num_groups);
276 0 : for (i = 0; i < num_groups; i++)
277 : {
278 0 : if (g_strstr_len (groups[i], -1, partial_name))
279 : {
280 0 : DEBUG ("Section \"%s\" matches \"%s\", removing", groups[i], partial_name);
281 0 : found_count++;
282 0 : if (!g_key_file_remove_group (state_file, groups[i], &error))
283 : {
284 0 : PWARN ("Warning: unable to remove section %s.\n %s",
285 : groups[i],
286 : error->message);
287 0 : g_error_free (error);
288 : }
289 : else
290 0 : dropped_count++;
291 :
292 : }
293 : }
294 0 : g_strfreev (groups);
295 :
296 0 : LEAVE("Found %i sections matching \"%s\", successfully removed %i",
297 : found_count, partial_name, dropped_count);
298 0 : return dropped_count;
299 :
300 : }
301 :
|