1 /*  HomeBank -- Free, easy, personal accounting for everyone.
2  *  Copyright (C) 1995-2021 Maxime DOYEN
3  *
4  *  This file is part of HomeBank.
5  *
6  *  HomeBank 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  *  HomeBank 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, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "homebank.h"
21 #include "hb-hbfile.h"
22 #include "hb-archive.h"
23 #include "hb-transaction.h"
24 
25 
26 /****************************************************************************/
27 /* Debug macros                                                             */
28 /****************************************************************************/
29 #define MYDEBUG 0
30 
31 #if MYDEBUG
32 #define DB(x) (x);
33 #else
34 #define DB(x);
35 #endif
36 
37 /* our global datas */
38 extern struct HomeBank *GLOBALS;
39 extern struct Preferences *PREFS;
40 
41 
42 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
43 
44 
hbfile_file_isbackup(gchar * filepath)45 gboolean hbfile_file_isbackup(gchar *filepath)
46 {
47 gboolean retval = FALSE;
48 
49 	if( filepath == NULL )
50 		return FALSE;
51 
52 	if( g_str_has_suffix(filepath, "xhb~") || g_str_has_suffix(filepath, "bak") )
53 		retval = TRUE;
54 
55 	return retval;
56 }
57 
58 
hbfile_file_hasrevert(gchar * filepath)59 gboolean hbfile_file_hasrevert(gchar *filepath)
60 {
61 gchar *bakfilepath;
62 
63 	bakfilepath = hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb~");
64 
65 	DB( g_print(" test bak exists '%s'\n", bakfilepath) );
66 
67 	GLOBALS->xhb_hasrevert = g_file_test(bakfilepath, G_FILE_TEST_EXISTS);
68 	g_free(bakfilepath);
69 	//todo check here if need to return something
70 	return GLOBALS->xhb_hasrevert;
71 }
72 
73 
74 //#1750161
hbfile_file_get_time_modified(gchar * filepath)75 guint64 hbfile_file_get_time_modified(gchar *filepath)
76 {
77 guint64 retval = 0ULL;
78 GFile *gfile;
79 GFileInfo *gfileinfo;
80 
81 	DB( g_print("\n[hbfile] get time modified\n") );
82 
83 	gfile = g_file_new_for_path(filepath);
84 	gfileinfo = g_file_query_info (gfile, G_FILE_ATTRIBUTE_TIME_MODIFIED, 0, NULL, NULL);
85 	if( gfileinfo )
86 	{
87 		retval = g_file_info_get_attribute_uint64 (gfileinfo, G_FILE_ATTRIBUTE_TIME_MODIFIED);
88 		DB( g_print("- '%s' last access = %lu\n", filepath, retval) );
89 		g_object_unref(gfileinfo);
90 	}
91 	g_object_unref(gfile);
92 
93 	return retval;
94 }
95 
96 
hbfile_file_default(void)97 void hbfile_file_default(void)
98 {
99 	DB( g_print("\n[hbfile] default\n") );
100 
101 	//todo: maybe translate this also
102 	hbfile_change_filepath(g_build_filename(PREFS->path_hbfile, "untitled.xhb", NULL));
103 	GLOBALS->hbfile_is_new = TRUE;
104 	GLOBALS->hbfile_is_bak = FALSE;
105 	GLOBALS->xhb_timemodified = 0ULL;
106 
107 	DB( g_print("- path_hbfile is '%s'\n", PREFS->path_hbfile) );
108 	DB( g_print("- xhb_filepath is '%s'\n", GLOBALS->xhb_filepath) );
109 }
110 
111 
112 
113 /*
114 static gint hbfile_file_load_xhb(gchar *filepath)
115 {
116 
117 
118 
119 
120 
121 
122 }
123 
124 
125 static void hbfile_file_load_backup_xhb(void)
126 {
127 //todo: get from dialog.c, and split between dilaog.c/hbfile.c
128 
129 
130 
131 }
132 */
133 
hbfile_replace_basecurrency(Currency4217 * curfmt)134 void hbfile_replace_basecurrency(Currency4217 *curfmt)
135 {
136 Currency *item;
137 guint32 oldkcur;
138 
139 	DB( g_print("\n[hbfile] replace base currency\n") );
140 
141 	oldkcur = GLOBALS->kcur;
142 	da_cur_delete(oldkcur);
143 	item = currency_add_from_user(curfmt);
144 	GLOBALS->kcur = item->key;
145 
146 	DB( g_print(" %d ==> %d %s\n", oldkcur, GLOBALS->kcur, item->iso_code) );
147 }
148 
149 
hbfile_change_basecurrency(guint32 key)150 void hbfile_change_basecurrency(guint32 key)
151 {
152 GList *list;
153 //guint32 oldkcur;
154 
155 	// set every rate to 0
156 	list = g_hash_table_get_values(GLOBALS->h_cur);
157 	while (list != NULL)
158 	{
159 	Currency *entry = list->data;
160 
161 		if(entry->key != GLOBALS->kcur)
162 		{
163 			entry->rate = 0.0;
164 			entry->mdate = 0;
165 		}
166 
167 		list = g_list_next(list);
168 	}
169 	g_list_free(list);
170 
171 	//oldkcur = GLOBALS->kcur;
172 	GLOBALS->kcur = key;
173 
174 	//#1851103: absolutely no reason to do that
175 	// update account with old base currency
176 	/*list = g_hash_table_get_values(GLOBALS->h_acc);
177 	while (list != NULL)
178 	{
179 	Account *acc = list->data;
180 
181 		if( acc->kcur == oldkcur )
182 			acc->kcur = key;
183 
184 		list = g_list_next(list);
185 	}
186 	g_list_free(list);
187 	*/
188 
189 	GLOBALS->changes_count++;
190 }
191 
192 
hbfile_transaction_get_partial_internal(guint32 minjulian,guint32 maxjulian,gushort exclusionflags)193 static GQueue *hbfile_transaction_get_partial_internal(guint32 minjulian, guint32 maxjulian, gushort exclusionflags)
194 {
195 GList *lst_acc, *lnk_acc;
196 GList *lnk_txn;
197 GQueue *txn_queue;
198 
199 	txn_queue = g_queue_new ();
200 
201 	lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
202 	lnk_acc = g_list_first(lst_acc);
203 	while (lnk_acc != NULL)
204 	{
205 	Account *acc = lnk_acc->data;
206 
207 		if( (acc->flags & exclusionflags) )
208 			goto next_acc;
209 
210 		lnk_txn = g_queue_peek_tail_link(acc->txn_queue);
211 		while (lnk_txn != NULL)
212 		{
213 		Transaction *txn = lnk_txn->data;
214 
215 			if( txn->date < minjulian ) //no need to go below mindate
216 				break;
217 
218 			if( !((txn->status == TXN_STATUS_REMIND) || (txn->status == TXN_STATUS_VOID))
219 				&& (txn->date >= minjulian)
220 				&& (txn->date <= maxjulian)
221 			  )
222 			{
223 				g_queue_push_head (txn_queue, txn);
224 			}
225 
226 			lnk_txn = g_list_previous(lnk_txn);
227 		}
228 
229 	next_acc:
230 		lnk_acc = g_list_next(lnk_acc);
231 	}
232 	g_list_free(lst_acc);
233 
234 	return txn_queue;
235 }
236 
237 
hbfile_transaction_get_partial(guint32 minjulian,guint32 maxjulian)238 GQueue *hbfile_transaction_get_partial(guint32 minjulian, guint32 maxjulian)
239 {
240 	//#1674045 ony rely on nosummary
241 	//return hbfile_transaction_get_partial_internal(minjulian, maxjulian, (AF_CLOSED|AF_NOREPORT));
242 	return hbfile_transaction_get_partial_internal(minjulian, maxjulian, (AF_NOREPORT));
243 }
244 
245 
hbfile_transaction_get_partial_budget(guint32 minjulian,guint32 maxjulian)246 GQueue *hbfile_transaction_get_partial_budget(guint32 minjulian, guint32 maxjulian)
247 {
248 	//#1674045 ony rely on nosummary
249 	//return hbfile_transaction_get_partial_internal(minjulian, maxjulian, (AF_CLOSED|AF_NOREPORT|AF_NOBUDGET));
250 	return hbfile_transaction_get_partial_internal(minjulian, maxjulian, (AF_NOREPORT|AF_NOBUDGET));
251 }
252 
253 
hbfile_sanity_check(void)254 void hbfile_sanity_check(void)
255 {
256 GList *lst_acc, *lnk_acc;
257 GList *lnk_txn;
258 GList *lxxx, *list;
259 
260 	DB( g_print("\n[hbfile] !! full sanity check !! \n") );
261 
262 	DB( g_print(" - transaction\n") );
263 	lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
264 	lnk_acc = g_list_first(lst_acc);
265 	while (lnk_acc != NULL)
266 	{
267 	Account *acc = lnk_acc->data;
268 
269 		lnk_txn = g_queue_peek_head_link(acc->txn_queue);
270 		while (lnk_txn != NULL)
271 		{
272 		Transaction *txn = lnk_txn->data;
273 
274 			da_transaction_consistency(txn);
275 			lnk_txn = g_list_next(lnk_txn);
276 		}
277 		lnk_acc = g_list_next(lnk_acc);
278 	}
279 	g_list_free(lst_acc);
280 
281 
282 	DB( g_print(" - scheduled/template\n") );
283 	list = g_list_first(GLOBALS->arc_list);
284 	while (list != NULL)
285 	{
286 	Archive *entry = list->data;
287 
288 		da_archive_consistency(entry);
289 		list = g_list_next(list);
290 	}
291 
292 
293 	DB( g_print(" - account\n") );
294 	lxxx = list = g_hash_table_get_values(GLOBALS->h_acc);
295 	while (list != NULL)
296 	{
297 	Account *item = list->data;
298 
299 		da_acc_consistency(item);
300 		list = g_list_next(list);
301 	}
302 	g_list_free(lxxx);
303 
304 
305 	DB( g_print(" - payee\n") );
306 	lxxx = list = g_hash_table_get_values(GLOBALS->h_pay);
307 	while (list != NULL)
308 	{
309 	Payee *item = list->data;
310 
311 		da_pay_consistency(item);
312 		list = g_list_next(list);
313 	}
314 	g_list_free(lxxx);
315 
316 
317 	DB( g_print(" - category\n") );
318 	lxxx = list = g_hash_table_get_values(GLOBALS->h_cat);
319 	while (list != NULL)
320 	{
321 	Category *item = list->data;
322 
323 		da_cat_consistency(item);
324 		list = g_list_next(list);
325 	}
326 	g_list_free(lxxx);
327 
328 
329 	DB( g_print(" - assignments\n") );
330 	lxxx = list = g_hash_table_get_values(GLOBALS->h_rul);
331 	while (list != NULL)
332 	{
333 	Assign *item = list->data;
334 
335 		da_asg_consistency(item);
336 		list = g_list_next(list);
337 	}
338 	g_list_free(lxxx);
339 
340 }
341 
342 
hbfile_anonymize(void)343 void hbfile_anonymize(void)
344 {
345 GList *lst_acc, *lnk_acc;
346 GList *lnk_txn;
347 GList *lxxx, *list;
348 guint cnt, i;
349 
350 	DB( g_print("\n[hbfile] anonymize\n") );
351 
352 	// owner
353 	hbfile_change_owner(g_strdup("An0nym0us"));
354 	GLOBALS->changes_count++;
355 	GLOBALS->hbfile_is_new = TRUE;
356 
357 	// filename
358 	hbfile_change_filepath(g_build_filename(PREFS->path_hbfile, "anonymized.xhb", NULL));
359 
360 	// accounts
361 	lxxx = list = g_hash_table_get_values(GLOBALS->h_acc);
362 	while (list != NULL)
363 	{
364 	Account *item = list->data;
365 		g_free(item->name);
366 		item->name = g_strdup_printf("account %d", item->key);
367 		g_free(item->number);
368 		item->number = NULL;
369 		g_free(item->bankname);
370 		item->bankname = NULL;
371 
372 		GLOBALS->changes_count++;
373 		list = g_list_next(list);
374 	}
375 	g_list_free(lxxx);
376 
377 	//payees
378 	lxxx = list = g_hash_table_get_values(GLOBALS->h_pay);
379 	while (list != NULL)
380 	{
381 	Payee *item = list->data;
382 
383 		if(item->key != 0)
384 		{
385 			g_free(item->name);
386 			item->name = g_strdup_printf("payee %d", item->key);
387 			GLOBALS->changes_count++;
388 		}
389 		list = g_list_next(list);
390 	}
391 	g_list_free(lxxx);
392 
393 	//categories
394 	lxxx = list = g_hash_table_get_values(GLOBALS->h_cat);
395 	while (list != NULL)
396 	{
397 	Category *item = list->data;
398 
399 		if(item->key != 0)
400 		{
401 			g_free(item->name);
402 			item->name = g_strdup_printf("category %d", item->key);
403 			GLOBALS->changes_count++;
404 		}
405 		list = g_list_next(list);
406 	}
407 	g_list_free(lxxx);
408 
409 	//tags
410 	lxxx = list = g_hash_table_get_values(GLOBALS->h_tag);
411 	while (list != NULL)
412 	{
413 	Tag *item = list->data;
414 
415 		if(item->key != 0)
416 		{
417 			g_free(item->name);
418 			item->name = g_strdup_printf("tag %d", item->key);
419 			GLOBALS->changes_count++;
420 		}
421 		list = g_list_next(list);
422 	}
423 	g_list_free(lxxx);
424 
425 	//assigns
426 	lxxx = list = g_hash_table_get_values(GLOBALS->h_rul);
427 	while (list != NULL)
428 	{
429 	Assign *item = list->data;
430 
431 		if(item->key != 0)
432 		{
433 			g_free(item->search);
434 			item->search = g_strdup_printf("assign %d", item->key);
435 			GLOBALS->changes_count++;
436 		}
437 		list = g_list_next(list);
438 	}
439 	g_list_free(lxxx);
440 
441 	//archives
442 	cnt = 0;
443 	list = g_list_first(GLOBALS->arc_list);
444 	while (list != NULL)
445 	{
446 	Archive *item = list->data;
447 
448 		g_free(item->memo);
449 		item->memo = g_strdup_printf("archive %d", cnt++);
450 		GLOBALS->changes_count++;
451 
452 		//later split anonymize also
453 
454 		list = g_list_next(list);
455 	}
456 
457 	//transaction
458 	lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
459 	lnk_acc = g_list_first(lst_acc);
460 	while (lnk_acc != NULL)
461 	{
462 	Account *acc = lnk_acc->data;
463 
464 		lnk_txn = g_queue_peek_head_link(acc->txn_queue);
465 		while (lnk_txn != NULL)
466 		{
467 		Transaction *item = lnk_txn->data;
468 		Split *split;
469 
470 			g_free(item->info);
471 			item->info = NULL;
472 			g_free(item->memo);
473 			item->memo = g_strdup_printf("memo %d", item->date);
474 			GLOBALS->changes_count++;
475 
476 			if(item->flags & OF_SPLIT)
477 			{
478 				cnt = da_splits_length (item->splits);
479 				for(i=0;i<cnt;i++)
480 				{
481 					split = da_splits_get(item->splits, i);
482 					if( split == NULL ) break;
483 
484 					if(split->memo != NULL)
485 						g_free(split->memo);
486 
487 					split->memo = g_strdup_printf("memo %d", i);
488 					GLOBALS->changes_count++;
489 				}
490 			}
491 			lnk_txn = g_list_next(lnk_txn);
492 		}
493 		lnk_acc = g_list_next(lnk_acc);
494 	}
495 	g_list_free(lst_acc);
496 
497 }
498 
499 
500 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
501 
502 
hbfile_change_owner(gchar * owner)503 void hbfile_change_owner(gchar *owner)
504 {
505 	g_free(GLOBALS->owner);
506 	GLOBALS->owner = (owner != NULL) ? owner : NULL;
507 }
508 
509 
hbfile_change_filepath(gchar * filepath)510 void hbfile_change_filepath(gchar *filepath)
511 {
512 	g_free(GLOBALS->xhb_filepath);
513 	GLOBALS->xhb_filepath = (filepath != NULL) ? filepath : NULL;
514 }
515 
516 
hbfile_cleanup(gboolean file_clear)517 void hbfile_cleanup(gboolean file_clear)
518 {
519 GSList *list;
520 //Transaction *txn;
521 
522 	DB( g_print("\n[hbfile] cleanup\n") );
523 	DB( g_print("- file clear is %d\n", file_clear) );
524 
525 	// Free data storage
526 	/*txn = g_trash_stack_pop(&GLOBALS->txn_stk);
527 	while( txn != NULL )
528 	{
529 		da_transaction_free (txn);
530 		txn = g_trash_stack_pop(&GLOBALS->txn_stk);
531 	}*/
532 	list = GLOBALS->deltxn_list;
533 	while(list != NULL)
534 	{
535 		da_transaction_free (list->data);
536 		list = g_slist_next(list);
537 	}
538 	g_slist_free(GLOBALS->deltxn_list);
539 
540 	g_slist_free(GLOBALS->openwindows);
541 
542 	da_transaction_destroy();
543 	da_archive_destroy(GLOBALS->arc_list);
544 	g_hash_table_destroy(GLOBALS->h_memo);
545 	da_asg_destroy();
546 	da_tag_destroy();
547 	da_cat_destroy();
548 	da_pay_destroy();
549 	da_acc_destroy();
550 	da_grp_destroy();
551 	da_cur_destroy();
552 
553 	hbfile_change_owner(NULL);
554 
555 	if(file_clear)
556 		hbfile_change_filepath(NULL);
557 
558 }
559 
560 
hbfile_setup(gboolean file_clear)561 void hbfile_setup(gboolean file_clear)
562 {
563 
564 	DB( g_print("\n[hbfile] setup\n") );
565 	DB( g_print("- file clear is %d\n", file_clear) );
566 
567 	// Allocate data storage
568 	da_cur_new();
569 	da_grp_new();
570 	da_acc_new();
571 	da_pay_new();
572 	da_cat_new();
573 	da_tag_new();
574 	da_asg_new();
575 	//txn queue is allocated into account
576 
577 	GLOBALS->h_memo = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
578 	GLOBALS->arc_list = NULL;
579 
580 	//5.5.1 list of opened windows
581 	GLOBALS->openwindows = NULL;
582 
583 	//#1419304 we keep the deleted txn to a trash stack
584 	//GLOBALS->txn_stk = NULL;
585 	GLOBALS->deltxn_list = NULL;
586 
587 	if(file_clear == TRUE)
588 	{
589 		hbfile_file_default();
590 	}
591 	else
592 	{
593 		GLOBALS->hbfile_is_new = FALSE;
594 	}
595 
596 	hbfile_change_owner(g_strdup(_("Unknown")));
597 
598 	GLOBALS->kcur = 1;
599 
600 	GLOBALS->vehicle_category = 0;
601 
602 	GLOBALS->auto_smode = 1;
603 	GLOBALS->auto_nbdays = 0;
604 	GLOBALS->auto_weekday = 1;
605 
606 	GLOBALS->changes_count = 0;
607 
608 	GLOBALS->xhb_hasrevert = FALSE;
609 
610 }
611 
612