1 /* ************************************************************************** */
2 /* */
3 /* Copyright (C) 2000-2008 Cédric Auger (cedric@grisbi.org) */
4 /* https://www.grisbi.org/ */
5 /* */
6 /* This program is free software; you can redistribute it and/or modify */
7 /* it under the terms of the GNU General Public License as published by */
8 /* the Free Software Foundation; either version 2 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* This program is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with this program; if not, write to the Free Software */
18 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19 /* */
20 /* ************************************************************************** */
21
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "include.h"
28 #include <errno.h>
29 #include <glib/gi18n.h>
30 #include <zlib.h>
31
32 /*START_INCLUDE*/
33 #include "gsb_file_util.h"
34 #include "dialog.h"
35 #include "grisbi_win.h"
36 #include "gsb_data_account.h"
37 #include "gsb_data_transaction.h"
38 #include "gsb_file.h"
39 #include "utils_str.h"
40 #include "utils_files.h"
41 #include "structures.h"
42 #include "erreur.h"
43 /*END_INCLUDE*/
44
45 /*START_STATIC*/
46 /*END_STATIC*/
47
48 /*START_EXTERN*/
49 /*END_EXTERN*/
50
51 /******************************************************************************/
52 /* Public Methods */
53 /******************************************************************************/
54 /**
55 * check if the file exists, and if so, ask the user if he wants
56 * to overwrite it
57 * show an error message if necessary
58 * return TRUE if the saving action can continue, FALSE to stop it
59 *
60 * \param filename
61 *
62 *\return TRUE ok, can continue (no file exists or user wants to overwrite), FALSE stop the action
63 **/
gsb_file_util_test_overwrite(const gchar * filename)64 gboolean gsb_file_util_test_overwrite (const gchar *filename)
65 {
66 gchar* tmp_str;
67 gboolean response;
68
69 if (!filename || !strlen (filename))
70 {
71 dialogue_error (_("No name to the file !"));
72 return FALSE;
73 }
74
75 if (g_file_test (filename, G_FILE_TEST_EXISTS))
76 {
77 /* the file exists */
78 if (g_file_test (filename, G_FILE_TEST_IS_DIR))
79 {
80 tmp_str = g_strdup_printf (_("%s is a directory...\nPlease choose another name."),
81 filename);
82 dialogue_error (tmp_str);
83 g_free (tmp_str);
84 return FALSE;
85 }
86
87 tmp_str = g_strdup_printf (_("Do you want to overwrite file \"%s\"?"), filename);
88 response = dialogue_yes_no (tmp_str,
89 _("File already exists"),
90 GTK_RESPONSE_NO);
91 g_free (tmp_str);
92 return response;
93 }
94 return TRUE;
95 }
96
97 /**
98 * this function do the same as g_file_get_contents
99 * but can also open a compressed file with zlib
100 *
101 * \param filename the name of file to open
102 * \param file_content a gchar pointer to fill with the adress of the content of the file
103 * \param length a gulong pointer to file with the length of the loaded file
104 *
105 * \return TRUE all is ok, FALSE a problem occurred
106 **/
gsb_file_util_get_contents(const gchar * filename,gchar ** file_content,gulong * length)107 gboolean gsb_file_util_get_contents (const gchar *filename,
108 gchar **file_content,
109 gulong *length)
110 {
111 gzFile file;
112 struct stat stat_buf;
113 gulong alloc_size;
114 gulong orig_size;
115 gchar *content;
116 int iterator = 0;
117 gboolean eof = 0;
118 gchar *os_filename;
119
120 #ifdef G_OS_WIN32
121 os_filename = g_locale_from_utf8(filename, -1, NULL, NULL, NULL);
122 #else
123 os_filename = g_strdup(filename);
124 #endif /* G_OS_WIN32 */
125
126 file = gzopen (os_filename, "rb");
127 if (!file)
128 {
129 g_free (os_filename);
130
131 return FALSE;
132 }
133
134 /* use stat to get the size of the file, windows ? */
135 if (stat (os_filename, &stat_buf))
136 {
137 gchar *tmp_str;
138 tmp_str = g_strdup_printf (_("Grisbi cannot stat file %s, please check the file."),
139 os_filename);
140 dialogue_error (tmp_str);
141 g_free (tmp_str);
142 gzclose (file);
143 g_free (os_filename);
144
145 return FALSE;
146 }
147
148 orig_size = stat_buf.st_size;
149 #ifndef G_OS_WIN32
150 if (gzdirect (file))
151 /* the file is not compressed, keep the original size */
152 alloc_size = orig_size + 1;
153 else
154 #endif /*_G_OS_WIN32 */
155 /* the file is compressed, the final size should be about 20x more
156 * this is not completly true, if the file is compressed AND crypted,
157 * the size doesn't really change. but i can't know here if the file is crypted
158 * because encrypt before compressed. perhaps forbid to compress a crypted file ?
159 * but i don't think it's a big thing because that allocated memory will be freed
160 * after loading the file ...*/
161 alloc_size = 20 * orig_size;
162
163 content = g_try_malloc0 (alloc_size);
164 if (!content)
165 {
166 dialogue_error_memory ();
167 gzclose (file);
168 g_free (os_filename);
169
170 return FALSE;
171 }
172
173 /* we should be able to get directly the orig_size
174 * for most of files it's enough, if the file is compressed,
175 * we continue */
176 iterator = gzread (file, content, (unsigned) orig_size);
177
178 if (iterator < 0)
179 {
180 int save_errno = errno;
181 gchar *tmp_str;
182
183 g_free (content);
184 tmp_str = g_strdup_printf (_("Failed to read from file '%s': %s"),
185 os_filename,
186 g_strerror (save_errno));
187 dialogue_error (tmp_str);
188 g_free (tmp_str);
189 gzclose (file);
190 g_free (os_filename);
191
192 return FALSE;
193 }
194
195 /* ok, now add caracter by caracter untill the end of the file */
196 do
197 {
198 gchar c;
199
200 c = gzgetc (file);
201
202 eof = gzeof (file);
203 if (!eof)
204 {
205 content[iterator] = c;
206 iterator++;
207
208 if (iterator >= (gint) alloc_size)
209 {
210 gchar *old_content;
211
212 /* on mémorise le dernier contenu valide */
213 old_content = content;
214
215 /* we need more space, should be rare,
216 * show a warning to prevent and correct if necessary */
217 devel_debug ("Realloc is needed, if this message comes often, "
218 "please contact the Grisbi team to improve the software ;-)");
219 alloc_size = alloc_size + orig_size;
220 content = g_try_realloc (content, alloc_size);
221
222 if (!content)
223 {
224 g_free (old_content);
225 dialogue_error_memory ();
226 gzclose (file);
227 g_free (os_filename);
228
229 return FALSE;
230 }
231 }
232 }
233 }
234 while (!eof);
235
236 content[iterator] = '\0';
237
238 /* fill the returned values */
239 *length = iterator;
240 *file_content = content;
241
242 gzclose (file);
243 g_free(os_filename);
244 return TRUE;
245 }
246
247 /**
248 * create or delete a file ".name_of_file.lock" to check if the file is opened
249 * already or not
250 *
251 * \param create_lock if we create or delete it
252 *
253 * \return TRUE if ok
254 **/
gsb_file_util_modify_lock(const gchar * filename,gboolean create_lock)255 gboolean gsb_file_util_modify_lock (const gchar *filename,
256 gboolean create_lock)
257 {
258 gchar *lock_filename;
259 gchar *dir_part;
260 gchar *file_part;
261 gboolean ret_code = TRUE; /* success by default */
262
263 devel_debug_int (create_lock);
264 if (!filename)
265 return TRUE;
266
267 /* if the file was already opened we do nothing */
268 if ((etat.fichier_deja_ouvert) || strlen (filename) == 0)
269 return TRUE;
270
271 /* Check if filename exists. If not, this is a new
272 * file so don't try to lock it. */
273 if (!g_file_test (filename, G_FILE_TEST_EXISTS))
274 return FALSE;
275
276 dir_part = g_path_get_dirname(filename);
277 file_part = g_path_get_basename(filename);
278
279 /* Create the name of the lock file */
280 lock_filename = g_strconcat (dir_part, G_DIR_SEPARATOR_S, ".", file_part, ".lock", NULL);
281
282 g_free (dir_part);
283 g_free (file_part);
284
285 if (create_lock)
286 {
287 /* now we create the lock file */
288
289 FILE *fichier;
290
291 /* check if the file lock exists */
292 if (g_file_test (lock_filename, G_FILE_TEST_EXISTS))
293 {
294 dialogue_message ("account-already-opened", filename);
295
296 /* the lock is already created, return TRUE */
297 etat.fichier_deja_ouvert = 1;
298
299 goto out;
300 }
301
302 etat.fichier_deja_ouvert = 0;
303
304 fichier = utils_files_utf8_fopen (lock_filename, "w");
305
306 if (!fichier)
307 {
308 gchar *tmp_str;
309
310 tmp_str = g_strdup_printf (_("Cannot write lock file: '%s': %s"),
311 filename,
312 g_strerror (errno));
313 dialogue_error (tmp_str);
314
315 g_free (tmp_str);
316
317 ret_code = FALSE;
318 goto out;
319 }
320
321 fclose (fichier);
322 }
323 else
324 {
325 if (etat.fichier_deja_ouvert == 0)
326 {
327 /* delete the lock file */
328 gint result;
329
330 /* check if it exits, if not, just go away */
331 if (!g_file_test (lock_filename, G_FILE_TEST_EXISTS))
332 {
333 goto out;
334 }
335
336 result = utils_files_utf8_remove (lock_filename);
337
338 if (result == -1)
339 {
340 gchar* tmp_str;
341
342 tmp_str = g_strdup_printf (_("Cannot erase lock file: '%s': %s"),
343 filename,
344 g_strerror (errno));
345 dialogue_error (tmp_str);
346
347 g_free (tmp_str);
348
349 ret_code = FALSE;
350 goto out;
351 }
352 }
353 }
354
355 out:
356 g_free (lock_filename);
357 return ret_code;
358 }
359
360 /**
361 * called when loading a file, if the permissions are not set only for the user
362 * propose to change the permissions
363 *
364 * \param
365 *
366 * \return
367 **/
gsb_file_util_change_permissions(void)368 void gsb_file_util_change_permissions (void)
369 {
370 /* On Windows, the chmod feature does not work: FAT does not
371 * have right access permission notions , on NTFS it to
372 * complicated to implement => the feature is removed from the
373 * Windows version : for that the corresponding parameter
374 * check box is not displayed and the paramater is forced to
375 * not display msg. */
376 devel_debug (NULL);
377
378 #ifndef G_OS_WIN32
379 if (dialogue_conditional_yes_no ("account-file-readable") == TRUE)
380 {
381 const gchar *filename;
382
383 filename = grisbi_win_get_filename (NULL);
384 (void)chmod (filename, S_IRUSR | S_IWUSR);
385 }
386
387 #endif /* G_OS_WIN32 */
388 }
389
390 /**
391 * called when loading a file, if the permissions are not set only for the user
392 * display a conditional warning
393 *
394 * \param
395 *
396 * \return
397 **/
gsb_file_util_display_warning_permissions(void)398 void gsb_file_util_display_warning_permissions (void)
399 {
400 gint msg_no = 0;
401 ConditionalMsg *warning;
402
403 devel_debug (NULL);
404 warning = (ConditionalMsg*) dialogue_get_tab_warning_msg ();
405 msg_no = dialogue_conditional_yes_no_get_no_struct (warning, "account-file-readable");
406 if (msg_no < 0)
407 return;
408
409 dialogue_conditional_hint (_((warning+msg_no)->message), _((warning+msg_no)->hint), "account-file-readable");
410 }
411
412 /**
413 *
414 *
415 * \param
416 *
417 * \return
418 **/
419 /* Local Variables: */
420 /* c-basic-offset: 4 */
421 /* End: */
422