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