Branch data 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 : :
|