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 
21 #include "homebank.h"
22 
23 #include "dsp-mainwindow.h"
24 #include "hb-preferences.h"
25 #include "language.h"
26 
27 
28 #ifdef G_OS_WIN32
29 #include <windows.h>
30 #endif
31 
32 #define APPLICATION_NAME "HomeBank"
33 
34 
35 /****************************************************************************/
36 /* Debug macros                                                             */
37 /****************************************************************************/
38 #define MYDEBUG 0
39 
40 #if MYDEBUG
41 #define DB(x) (x);
42 #else
43 #define DB(x);
44 #endif
45 
46 /* our global datas */
47 struct HomeBank *GLOBALS;
48 struct Preferences *PREFS;
49 
50 
51 /* installation paths */
52 static gchar *config_dir   = NULL;
53 static gchar *images_dir   = NULL;
54 static gchar *pixmaps_dir  = NULL;
55 static gchar *locale_dir   = NULL;
56 static gchar *help_dir     = NULL;
57 static gchar *datas_dir    = NULL;
58 
59 
60 //#define MARKUP_STRING "<span size='small'>%s</span>"
61 
62 
63 /* Application arguments */
64 static gboolean arg_version = FALSE;
65 static gchar **files = NULL;
66 
67 static GOptionEntry option_entries[] =
68 {
69 	{ "version", '\0', 0, G_OPTION_ARG_NONE, &arg_version,
70 	  N_("Output version information and exit"), NULL },
71 
72 	{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &files,
73 	  NULL, N_("[FILE]") },
74 
75 	{ NULL }
76 };
77 
78 
79 
80 /* = = = = = = = = = = = = = = = = = = = = */
81 
82 
83 /*
84 ** ensure the filename ends with '.xhb'
85 */
homebank_file_ensure_xhb(gchar * filename)86 void homebank_file_ensure_xhb(gchar *filename)
87 {
88 	DB( g_print("\n[homebank] file_ensure_xhb\n") );
89 	filename = (filename == NULL) ? g_strdup(GLOBALS->xhb_filepath) : filename;
90 	if( g_str_has_suffix (filename, ".xhb") == FALSE )
91 	{
92 	gchar *newfilename;
93 
94 		newfilename = hb_filename_new_with_extension(filename, "xhb");
95 		hbfile_change_filepath(newfilename);
96 		DB( g_print(" - changed to: '%s'\n", GLOBALS->xhb_filepath) );
97 	}
98 	//#1460390
99 	else
100 	{
101 		hbfile_change_filepath(filename);
102 	}
103 }
104 
105 
homebank_file_copy(gchar * srcfile,gchar * dstfile)106 static gboolean homebank_file_copy(gchar *srcfile, gchar *dstfile)
107 {
108 gchar *buffer;
109 gsize length;
110 //GError *error = NULL;
111 gboolean retval = FALSE;
112 
113 	DB( g_print("\n[homebank] file copy\n") );
114 
115 	if (g_file_get_contents (srcfile, &buffer, &length, NULL))
116 	{
117 		if(g_file_set_contents(dstfile, buffer, length, NULL))
118 		{
119 			retval = TRUE;
120 		}
121 		g_free(buffer);
122 	}
123 
124 	DB( g_print(" - copied '%s' => '%s' :: %d\n", srcfile, dstfile, retval) );
125 	return retval;
126 }
127 
128 
homebank_file_delete_existing(gchar * filepath)129 static gboolean homebank_file_delete_existing(gchar *filepath)
130 {
131 gboolean retval = FALSE;
132 
133 	DB( g_print("\n[homebank] file delete existing\n") );
134 
135 	if( g_file_test(filepath, G_FILE_TEST_EXISTS) )
136 	{
137 		DB( g_print(" - deleting: '%s'\n", filepath) );
138 		g_remove(filepath);
139 		retval = TRUE;
140 	}
141 	else
142 	{
143 		DB( g_print(" - cannot delete: '%s'\n", filepath) );
144 	}
145 
146 	return retval;
147 }
148 
149 
homebank_backup_current_file(void)150 void homebank_backup_current_file(void)
151 {
152 gchar *bakfilename;
153 GPtrArray *array;
154 gint i;
155 
156 	DB( g_print("\n[homebank] backup_current_file\n") );
157 
158 	//do normal linux backup file
159 	DB( g_print(" normal backup with ~\n") );
160 	bakfilename = hb_filename_new_with_extension (GLOBALS->xhb_filepath, "xhb~");
161 	homebank_file_delete_existing(bakfilename);
162 	//#512046 copy file not to broke potential links
163 	//retval = g_rename(pathname, newname);
164 	homebank_file_copy (GLOBALS->xhb_filepath, bakfilename);
165 	g_free(bakfilename);
166 
167 	//do safe backup according to user preferences
168 	DB( g_print(" user pref backup\n") );
169 	if( PREFS->bak_is_automatic == TRUE )
170 	{
171 		bakfilename = hb_filename_new_for_backup(GLOBALS->xhb_filepath);
172 		if( g_file_test(bakfilename, G_FILE_TEST_EXISTS) == FALSE )
173 		{
174 			homebank_file_copy (GLOBALS->xhb_filepath, bakfilename);
175 		}
176 		g_free(bakfilename);
177 
178 		//delete any offscale backup
179 		DB( g_print(" clean old backup\n") );
180 		array = hb_filename_backup_list(GLOBALS->xhb_filepath);
181 
182 		DB( g_print(" found %d match\n", array->len) );
183 
184 		//#1847645
185 		//gchar *dirname = g_path_get_dirname(GLOBALS->xhb_filepath);
186 		gchar *dirname = PREFS->path_hbbak;
187 
188 		for(i=0;i<(gint)array->len;i++)
189 		{
190 		gchar *offscalefilename = g_ptr_array_index(array, i);
191 
192 			DB( g_print(" %d : '%s'\n", i, offscalefilename) );
193 			if( i >= PREFS->bak_max_num_copies )
194 			{
195 			gchar *bakdelfilepath = g_build_filename(dirname, offscalefilename, NULL);
196 
197 				DB( g_print(" - should delete '%s'\n", bakdelfilepath) );
198 
199 				homebank_file_delete_existing(bakdelfilepath);
200 
201 				g_free(bakdelfilepath);
202 			}
203 		}
204 		g_ptr_array_free(array, TRUE);
205 
206 		//g_free(dirname);
207 	}
208 
209 }
210 
211 
212 /* = = = = = = = = = = = = = = = = = = = = */
213 /* url open */
214 
215 
216 #ifdef G_OS_WIN32
217 #define SW_NORMAL 1
218 
219 static gboolean
homebank_util_url_show_win32(const gchar * url)220 homebank_util_url_show_win32 (const gchar *url)
221 {
222 int retval;
223 gchar *errmsg;
224 
225 	/* win32 API call */
226 	retval = ShellExecuteA (NULL, "open", url, NULL, NULL, SW_NORMAL);
227 
228 	if (retval < 0 || retval > 32)
229 		return TRUE;
230 
231 	errmsg = g_win32_error_message(retval);
232 	DB( g_print ("%s\n", errmsg) );
233 	g_free(errmsg);
234 
235 	return FALSE;
236 }
237 
238 #else
239 
240 static gboolean
homebank_util_url_show_unix(const gchar * url)241 homebank_util_url_show_unix (const gchar *url)
242 {
243 gboolean retval;
244 GError *err = NULL;
245 
246 	#if( (GTK_MAJOR_VERSION == 3) && (GTK_MINOR_VERSION >= 22) )
247 	retval = gtk_show_uri_on_window (GTK_WINDOW(GLOBALS->mainwindow), url, GDK_CURRENT_TIME, &err);
248 	#else
249 	retval = gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (GLOBALS->mainwindow)), url, GDK_CURRENT_TIME, &err);
250 	#endif
251 
252 	if (!retval)
253 	{
254 		ui_dialog_msg_infoerror(GTK_WINDOW(GLOBALS->mainwindow), GTK_MESSAGE_ERROR,
255 			_("Browser error."),
256 			_("Could not display the URL '%s'"),
257 			url
258 			);
259 	}
260 
261 	if(err != NULL)
262 	{
263 		g_print ("%s\n", err->message);
264 		g_error_free (err);
265 	}
266 
267 	return retval;
268 }
269 
270 #endif
271 
272 gboolean
homebank_util_url_show(const gchar * url)273 homebank_util_url_show (const gchar *url)
274 {
275 
276 	if(url == NULL)
277 		return FALSE;
278 
279 
280 #ifdef G_OS_WIN32
281 	return homebank_util_url_show_win32 (url);
282 #else
283 	return homebank_util_url_show_unix (url);
284 #endif
285 }
286 
287 
288 /* = = = = = = = = = = = = = = = = = = = = */
289 /* lastopenedfiles */
290 
291 /*
292 ** load lastopenedfiles from homedir/.homebank
293 */
homebank_lastopenedfiles_load(void)294 gchar *homebank_lastopenedfiles_load(void)
295 {
296 GKeyFile *keyfile;
297 gchar *group, *filename, *tmpfilename;
298 gchar *lastfilename = NULL;
299 GError *error = NULL;
300 
301 	DB( g_print("\n[homebank] lastopenedfiles load\n") );
302 
303 	keyfile = g_key_file_new();
304 	if(keyfile)
305 	{
306 		filename = g_build_filename(homebank_app_get_config_dir(), "lastopenedfiles", NULL );
307 		if(g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error))
308 		{
309 			group = "HomeBank";
310 
311 			if(g_key_file_has_key(keyfile, group, "LastOpenedFile", NULL))
312 			{
313 				tmpfilename = g_key_file_get_string  (keyfile, group, "LastOpenedFile", NULL);
314 				// #593082
315 				if (g_file_test (tmpfilename, G_FILE_TEST_EXISTS) != FALSE)
316 				{
317 					lastfilename = tmpfilename;
318 				}
319 			}
320 		}
321 
322 		if( error )
323 		{
324 			g_print("failed: %s\n", error->message);
325 			g_error_free (error);
326 		}
327 
328 		g_free(filename);
329 		g_key_file_free (keyfile);
330 	}
331 
332 	return lastfilename;
333 }
334 
335 
336 /*
337 ** save lastopenedfiles to homedir/.homebank (HB_DATA_PATH)
338 */
homebank_lastopenedfiles_save(void)339 gboolean homebank_lastopenedfiles_save(void)
340 {
341 GKeyFile *keyfile;
342 gboolean retval = FALSE;
343 gchar *group, *filename;
344 gsize length;
345 GError *error = NULL;
346 
347 	DB( g_print("\n[homebank] lastopenedfiles save\n") );
348 
349 	if( GLOBALS->xhb_filepath != NULL )
350 	{
351 		//don't save bakup files
352 		if( hbfile_file_isbackup(GLOBALS->xhb_filepath) == FALSE )
353 		{
354 			keyfile = g_key_file_new();
355 			if(keyfile )
356 			{
357 				DB( g_print(" - saving '%s'\n", GLOBALS->xhb_filepath) );
358 
359 				group = "HomeBank";
360 				g_key_file_set_string  (keyfile, group, "LastOpenedFile", GLOBALS->xhb_filepath);
361 
362 				gchar *contents = g_key_file_to_data( keyfile, &length, NULL);
363 
364 				//DB( g_print(" keyfile:\n%s\nlen=%d\n", contents, length) );
365 
366 				filename = g_build_filename(homebank_app_get_config_dir(), "lastopenedfiles", NULL );
367 
368 				g_file_set_contents(filename, contents, length, &error);
369 				g_free(filename);
370 
371 				if( error )
372 				{
373 					g_print("failed: %s\n", error->message);
374 					g_error_free (error);
375 				}
376 
377 				g_free(contents);
378 				g_key_file_free (keyfile);
379 			}
380 		}
381 	}
382 
383 	return retval;
384 }
385 
386 
387 
388 /* = = = = = = = = = = = = = = = = = = = = */
389 /* Main homebank */
390 #ifdef G_OS_WIN32
391 static GtkCssProvider *provider;
392 
393 static void
homebank_theme_changed(GtkSettings * settings,GParamSpec * pspec,gpointer data)394 homebank_theme_changed (GtkSettings *settings, GParamSpec  *pspec, gpointer     data)
395 {
396 
397 	if (pspec == NULL || g_str_equal (pspec->name, "gtk-theme-name"))
398 	{
399 		gchar *theme;
400 		GdkScreen *screen;
401 
402 		g_object_get (settings, "gtk-theme-name", &theme, NULL);
403 		screen = gdk_screen_get_default ();
404 
405 		DB( g_print("theme %s\n", theme) );
406 
407 		if (g_str_equal (theme, "gtk-win32"))
408 		{
409 			if (provider == NULL)
410 			{
411 				gchar *filename;
412 
413                 filename = g_build_filename(homebank_app_get_datas_dir(), "homebank-gtk-win32.css", NULL );
414                 DB( g_print("tweak file %s\n", filename) );
415 
416                 if( g_file_test(filename, G_FILE_TEST_EXISTS) )
417                 {
418                     provider = gtk_css_provider_new ();
419                     gtk_css_provider_load_from_path (provider, filename, NULL);
420                 }
421                 g_free (filename);
422 			}
423 
424             if(provider != NULL)
425             {
426                 DB( g_print(" assign provider %p to screen %p\n", provider, screen) );
427 
428                 gtk_style_context_add_provider_for_screen (screen,
429                                        GTK_STYLE_PROVIDER (provider),
430                                        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
431             }
432 		}
433 		else if (provider != NULL)
434 		{
435 			gtk_style_context_remove_provider_for_screen (screen,
436 								      GTK_STYLE_PROVIDER (provider));
437 			g_clear_object (&provider);
438 		}
439 
440 		g_free (theme);
441 	}
442 }
443 
444 
445 static void
homebank_setup_theme_extensions(void)446 homebank_setup_theme_extensions (void)
447 {
448 	GtkSettings *settings;
449 
450 	settings = gtk_settings_get_default ();
451 	provider = NULL;
452 	g_signal_connect (settings, "notify", G_CALLBACK (homebank_theme_changed), NULL);
453 	homebank_theme_changed (settings, NULL, NULL);
454 }
455 #endif
456 
457 
458 static void
homebank_icon_theme_setup()459 homebank_icon_theme_setup()
460 {
461 	DB( g_print("\n[homebank] icon_theme_setup\n") );
462 
463 	GLOBALS->icontheme = gtk_icon_theme_get_default();
464 
465 	DB( g_print(" - prepend theme search path: %s\n", homebank_app_get_pixmaps_dir()) );
466 	gtk_icon_theme_prepend_search_path (GLOBALS->icontheme, homebank_app_get_pixmaps_dir());
467 	//DB( g_print(" - append theme search path: %s\n", homebank_app_get_pixmaps_dir()) );
468 	//gtk_icon_theme_append_search_path (GLOBALS->icontheme, homebank_app_get_pixmaps_dir());
469 
470 
471 	#if MYDEBUG == 1
472 	GtkIconTheme *ic = gtk_icon_theme_get_default();
473 	guint i;
474 	gchar **paths;
475 
476 		DB( g_print(" - get default icon theme\n") );
477 
478 		gtk_icon_theme_get_search_path(ic, &paths, NULL);
479 		for(i=0;i<g_strv_length(paths);i++)
480 		{
481 			g_print(" - path %d: %s\n", i, paths[i]);
482 		}
483 
484 		g_strfreev(paths);
485 
486 	#endif
487 
488 
489 }
490 
491 
492 const gchar *
homebank_app_get_config_dir(void)493 homebank_app_get_config_dir (void)
494 {
495 	return config_dir;
496 }
497 
498 const gchar *
homebank_app_get_images_dir(void)499 homebank_app_get_images_dir (void)
500 {
501 	return images_dir;
502 }
503 
504 const gchar *
homebank_app_get_pixmaps_dir(void)505 homebank_app_get_pixmaps_dir (void)
506 {
507 	return pixmaps_dir;
508 }
509 
510 const gchar *
homebank_app_get_locale_dir(void)511 homebank_app_get_locale_dir (void)
512 {
513 	return locale_dir;
514 }
515 
516 const gchar *
homebank_app_get_help_dir(void)517 homebank_app_get_help_dir (void)
518 {
519 	return help_dir;
520 }
521 
522 const gchar *
homebank_app_get_datas_dir(void)523 homebank_app_get_datas_dir (void)
524 {
525 	return datas_dir;
526 }
527 
528 
529 /* build package paths at runtime */
530 static void
build_package_paths(void)531 build_package_paths (void)
532 {
533 	DB( g_print("\n[homebank] build_package_paths\n") );
534 
535 #ifdef G_OS_WIN32
536 	gchar *prefix;
537 
538 	prefix = g_win32_get_package_installation_directory_of_module (NULL);
539 	locale_dir   = g_build_filename (prefix, "share", "locale", NULL);
540 	images_dir   = g_build_filename (prefix, "share", PACKAGE, "images", NULL);
541 	pixmaps_dir  = g_build_filename (prefix, "share", PACKAGE, "icons", NULL);
542 	help_dir     = g_build_filename (prefix, "share", PACKAGE, "help", NULL);
543 	datas_dir    = g_build_filename (prefix, "share", PACKAGE, "datas", NULL);
544 	#ifdef PORTABLE_APP
545 		DB( g_print(" - app is portable under windows\n") );
546 		config_dir   = g_build_filename(prefix, "config", NULL);
547 	#else
548 		config_dir   = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL);
549 	#endif
550 	g_free (prefix);
551 #else
552 	locale_dir   = g_build_filename (DATA_DIR, "locale", NULL);
553 	images_dir   = g_build_filename (SHARE_DIR, "images", NULL);
554 	pixmaps_dir  = g_build_filename (DATA_DIR, PACKAGE, "icons", NULL);
555 	help_dir     = g_build_filename (DATA_DIR, PACKAGE, "help", NULL);
556 	datas_dir    = g_build_filename (DATA_DIR, PACKAGE, "datas", NULL);
557 	config_dir   = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL);
558 
559 	//#870023 Ubuntu packages the help files in "/usr/share/doc/homebank-data/help/" for some strange reason
560 	if(! g_file_test(help_dir, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
561 	{
562 		g_free (help_dir);
563 		help_dir = g_build_filename ("/usr", "share", "doc", "homebank-data", "help", NULL);
564 	}
565 #endif
566 
567 	DB( g_print(" - config_dir : %s\n", config_dir) );
568 	DB( g_print(" - images_dir : %s\n", images_dir) );
569 	DB( g_print(" - pixmaps_dir: %s\n", pixmaps_dir) );
570 	DB( g_print(" - locale_dir : %s\n", locale_dir) );
571 	DB( g_print(" - help_dir   : %s\n", help_dir) );
572 	DB( g_print(" - datas_dir  : %s\n", datas_dir) );
573 
574 }
575 
576 
homebank_app_date_get_julian(void)577 guint32 homebank_app_date_get_julian(void)
578 {
579 GDate *date;
580 	//init global default value
581 	date = g_date_new();
582 	g_date_set_time_t(date, time(NULL));
583 	GLOBALS->today = g_date_get_julian(date);
584 	g_date_free(date);
585 	return GLOBALS->today;
586 }
587 
588 
homebank_check_app_dir_migrate_file(gchar * srcdir,gchar * dstdir,gchar * filename)589 static gboolean homebank_check_app_dir_migrate_file(gchar *srcdir, gchar *dstdir, gchar *filename)
590 {
591 gchar *srcpath;
592 gchar *dstpath;
593 gchar *buffer;
594 gsize length;
595 //GError *error = NULL;
596 gboolean retval = FALSE;
597 
598 	DB( g_print("\n[homebank] check_app_dir_migrate_file\n") );
599 
600 	srcpath = g_build_filename(srcdir, filename, NULL );
601 	dstpath = g_build_filename(dstdir, filename, NULL );
602 
603 	if (g_file_get_contents (srcpath, &buffer, &length, NULL))
604 	{
605 		if(g_file_set_contents(dstpath, buffer, length, NULL))
606 		{
607 			//g_print("sould delete %s\n", srcpath);
608 			g_remove(srcpath);
609 			retval = TRUE;
610 		}
611 	}
612 
613 	g_free(dstpath);
614 	g_free(srcpath);
615 
616 	return retval;
617 }
618 
619 /*
620  * check/create user home directory for .homebank (HB_DATA_PATH) directory
621  */
homebank_check_app_dir()622 static void homebank_check_app_dir()
623 {
624 gchar *homedir;
625 const gchar *configdir;
626 gboolean exists;
627 
628 	DB( g_print("\n[homebank] check_app_dir\n") );
629 
630 	/* check if <userdir>/.config exist */
631 #ifndef G_OS_WIN32
632 	configdir = g_get_user_config_dir();
633 	DB( g_print(" - check '%s' exists\n", configdir) );
634 	if(!g_file_test(configdir, G_FILE_TEST_IS_DIR))
635 	{
636 		DB( g_print(" - creating dir\n") );
637 		g_mkdir(configdir, 0755);
638 	}
639 #endif
640 
641 	/* check for XDG .config/homebank */
642 	configdir = homebank_app_get_config_dir();
643 	DB( g_print(" - config_dir is: '%s'\n", configdir) );
644 	exists = g_file_test(configdir, G_FILE_TEST_IS_DIR);
645 	if(exists)
646 	{
647 		/* just update folder security */
648 		DB( g_print(" - chmod 0700\n") );
649 		g_chmod(configdir, 0700);
650 		GLOBALS->first_run = FALSE;
651 	}
652 	else
653 	{
654 		/* create the config dir */
655 		DB( g_print(" - create config_dir\n") );
656 		g_mkdir(configdir, 0755);
657 		g_chmod(configdir, 0700);
658 
659 		/* any old homedir configuration out there ? */
660 		homedir = g_build_filename(g_get_home_dir (), ".homebank", NULL );
661 		DB(	g_print(" - homedir is: '%s'\n", homedir) );
662 
663 		exists = g_file_test(homedir, G_FILE_TEST_IS_DIR);
664 		if(exists)
665 		{
666 		gboolean f1, f2;
667 			/* we must do the migration properly */
668 			DB( g_print(" - migrate old 2 files\n") );
669 			f1 = homebank_check_app_dir_migrate_file(homedir, config_dir, "preferences");
670 			f2 = homebank_check_app_dir_migrate_file(homedir, config_dir, "lastopenedfiles");
671 			if(f1 && f2)
672 			{
673 				DB( g_print(" - removing old dir\n") );
674 				g_rmdir(homedir);
675 			}
676 		}
677 		g_free(homedir);
678 		GLOBALS->first_run = TRUE;
679 	}
680 
681 }
682 
683 
684 /*
685 ** application cleanup: icons, GList, memory
686 */
homebank_cleanup()687 static void homebank_cleanup()
688 {
689 
690 	DB( g_print("\n[homebank] cleanup\n") );
691 
692 	//v3.4 save windows size/position
693 	homebank_pref_save();
694 
695 	hbfile_cleanup(TRUE);
696 
697 	/* free our global datas */
698 	if( PREFS  )
699 	{
700 		homebank_pref_free();
701 		g_free(PREFS);
702 	}
703 
704 	if(GLOBALS)
705 	{
706 		g_free(GLOBALS);
707 	}
708 
709 	g_free (config_dir);
710 	g_free (images_dir);
711 	g_free (pixmaps_dir);
712 	g_free (locale_dir);
713 	g_free (help_dir);
714 
715 }
716 
717 
718 
719 /*
720 ** application setup: icons, GList, memory
721 */
homebank_setup()722 static gboolean homebank_setup()
723 {
724 
725 	DB( g_print("\n[homebank] setup\n") );
726 
727 	GLOBALS = g_malloc0(sizeof(struct HomeBank));
728 	if(!GLOBALS) return FALSE;
729 	PREFS   = g_malloc0(sizeof(struct Preferences));
730 	if(!PREFS) return FALSE;
731 
732 	// check homedir for .homebank dir
733 	homebank_check_app_dir();
734 
735 	homebank_pref_setdefault();
736 
737 	homebank_pref_load();
738 
739 	homebank_pref_apply();
740 
741 	hbfile_setup(TRUE);
742 
743 	homebank_icon_theme_setup();
744 
745 #ifdef G_OS_WIN32
746 	homebank_setup_theme_extensions();
747 #endif
748 
749 	homebank_app_date_get_julian();
750 
751 
752 	#if MYDEBUG == 1
753 
754 	g_print(" - user_name: %s\n", g_get_user_name ());
755 	g_print(" - real_name: %s\n", g_get_real_name ());
756 	g_print(" - user_cache_dir: %s\n", g_get_user_cache_dir());
757 	g_print(" - user_data_dir: %s\n", g_get_user_data_dir ());
758 	g_print(" - user_config_dir: %s\n", g_get_user_config_dir ());
759 	//g_print(" - system_data_dirs: %s\n", g_get_system_data_dirs ());
760 	//g_print(" - system_config_dirs: %s\n", g_get_system_config_dirs ());
761 
762 	g_print(" - home_dir: %s\n", g_get_home_dir ());
763 	g_print(" - tmp_dir: %s\n", g_get_tmp_dir ());
764 	g_print(" - current_dir: %s\n", g_get_current_dir ());
765 
766 	#endif
767 
768 	return TRUE;
769 }
770 
771 
772 /* = = = = = = = = = = = = = = = = = = = = */
773 /* Main homebank */
774 
775 static GtkWidget *
homebank_construct_splash()776 homebank_construct_splash()
777 {
778 GtkWidget *window;
779 GtkWidget *frame, *vbox, *image;
780 //gchar *ver_string, *markup, *version;
781 gchar *pathfilename;
782 
783 	DB( g_print("\n[homebank_construct_splash]\n") );
784 
785 	window = gtk_window_new(GTK_WINDOW_POPUP);	//TOPLEVEL DONT WORK
786 	gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
787 	gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
788 
789 	gtk_window_set_title (GTK_WINDOW (window), "HomeBank");
790 	gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
791 
792 	pathfilename = g_build_filename(homebank_app_get_images_dir(), "splash.png", NULL);
793 	image = gtk_image_new_from_file((const gchar *)pathfilename);
794 	g_free(pathfilename);
795 
796 	frame = gtk_frame_new (NULL);
797 	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
798 	gtk_container_add (GTK_CONTAINER (window), frame);
799 
800 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
801 	gtk_container_add (GTK_CONTAINER (frame), vbox);
802 
803 	/*
804 	ver_string = g_strdup_printf(_("Version: HomeBank-%s"), VERSION);
805 
806 	version = gtk_label_new(NULL);
807 	markup = g_markup_printf_escaped(MARKUP_STRING, ver_string);
808 	gtk_label_set_markup(GTK_LABEL(version), markup);
809 	g_free(markup);
810 	g_free(ver_string);
811 	*/
812 
813 	gtk_box_pack_start (GTK_BOX (vbox), image, FALSE, FALSE, 0);
814 	//gtk_box_pack_start (GTK_BOX (vbox), version, FALSE, FALSE, 0);
815 
816 	return window;
817 }
818 
819 static void
homebank_init_i18n(void)820 homebank_init_i18n (void)
821 {
822 	/*  We may change the locale later if the user specifies a language
823 	*  in the gimprc file. Here we are just initializing the locale
824 	*  according to the environment variables and set up the paths to
825 	*  the message catalogs.
826 	*/
827 
828 	setlocale (LC_ALL, "");
829 
830 	//#1842292 as indicated in gtk+ win32 gtk_get_localedir [1], bindtextdomain() is not
831 	// UTF-8 aware on win32, so it needs a filename in locale encoding
832 	#ifdef G_OS_WIN32
833 	gchar *localedir = g_win32_locale_filename_from_utf8 (homebank_app_get_locale_dir ());
834 	bindtextdomain (GETTEXT_PACKAGE, localedir);
835 	g_free(localedir);
836 	#else
837 	bindtextdomain (GETTEXT_PACKAGE, homebank_app_get_locale_dir ());
838 	#endif
839 
840 //#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
841 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
842 //#endif
843 
844 	textdomain (GETTEXT_PACKAGE);
845 
846 	/*#ifdef G_OS_WIN32
847 	gchar *wl = g_win32_getlocale ();
848 	DB( g_print(" - win32 locale is '%s'\n", wl) );
849 	g_free(wl);
850 	#endif*/
851 
852 }
853 
854 
855 int
main(int argc,char * argv[])856 main (int argc, char *argv[])
857 {
858 GOptionContext *option_context;
859 GOptionGroup *option_group;
860 GError *error = NULL;
861 GtkWidget *mainwin;
862 GtkWidget *splash = NULL;
863 
864 	DB( g_print("\n--------------------------------" ) );
865 	DB( g_print("\nhomebank starting...\n" ) );
866 
867 	build_package_paths();
868 
869 	homebank_init_i18n ();
870 
871 	/* Set up option groups */
872 	option_context = g_option_context_new (NULL);
873 
874 	//g_option_context_set_summary (option_context, _(""));
875 
876 	option_group = g_option_group_new ("homebank",
877 					   N_("HomeBank options"),
878 					   N_("HomeBank options"),
879 					   NULL, NULL);
880 	g_option_group_add_entries (option_group, option_entries);
881 	g_option_context_set_main_group (option_context, option_group);
882 	g_option_group_set_translation_domain (option_group, GETTEXT_PACKAGE);
883 
884 	/* Add Gtk option group */
885 	g_option_context_add_group (option_context, gtk_get_option_group (FALSE));
886 
887 	/* Parse command line */
888 	if (!g_option_context_parse (option_context, &argc, &argv, &error))
889 	{
890 		g_option_context_free (option_context);
891 
892 		if (error)
893 		{
894 			g_print ("%s\n", error->message);
895 			g_error_free (error);
896 		}
897 		else
898 			g_print ("An unknown error occurred\n");
899 
900 		return -1;
901 	}
902 
903 	g_option_context_free (option_context);
904 	option_context = NULL;
905 
906 	if (arg_version != FALSE)
907 	{
908 		/* Print version information and exit */
909 		g_print ("%s\n", PACKAGE " " VERSION);
910 		return 0;
911 	}
912 
913 	/* Pass NULL here since we parsed the gtk+ args already...
914 	 * from this point all we need a DISPLAY variable to be set.
915 	 */
916 	gtk_init (NULL, NULL);
917 
918 	//todo: sanity check gtk version here ?
919 
920 	g_set_application_name (APPLICATION_NAME);
921 
922 	if( homebank_setup() )
923 	{
924 		/*  change the locale if a language is specified  */
925 		language_init (PREFS->language);
926 
927 		if( PREFS->showsplash == TRUE )
928 		{
929 			splash = homebank_construct_splash();
930 			gtk_window_set_auto_startup_notification (FALSE);
931 			gtk_widget_show_all (splash);
932 			gtk_window_set_auto_startup_notification (TRUE);
933 
934 			// make sure splash is up
935 			while (gtk_events_pending ())
936 				gtk_main_iteration ();
937 		}
938 
939 		gtk_window_set_default_icon_name ("homebank");
940 
941 		DB( g_print(" - creating window\n" ) );
942 
943 		mainwin = (GtkWidget *)create_hbfile_window (NULL);
944 
945 		if(mainwin)
946 		{
947 		gchar *rawfilepath;
948 
949 			//todo: pause on splash
950 			if( PREFS->showsplash == TRUE )
951 			{
952 				//g_usleep( G_USEC_PER_SEC * 1 );
953 				gtk_widget_hide(splash);
954 				gtk_widget_destroy(splash);
955 
956 				/* make sure splash is gone */
957 				while (gtk_events_pending ())
958 					gtk_main_iteration ();
959 			}
960 
961 			rawfilepath = NULL;
962 			//priority here:
963 			// - command line file
964 			// - welcome dialog
965 			// - last opened file, if welcome dialog was not opened
966 			if( files != NULL )
967 			{
968 				DB( g_print(" command line open '%s'\n", files[0] ) );
969 				rawfilepath = g_strdup(files[0]);
970 				g_strfreev (files);
971 			}
972 			else
973 			if( PREFS->showwelcome )
974 			{
975 				ui_mainwindow_action_help_welcome();
976 			}
977 			else
978 			if( PREFS->loadlast )
979 			{
980 				rawfilepath = homebank_lastopenedfiles_load();
981 			}
982 
983 			ui_mainwindow_open_check(mainwin, rawfilepath);
984 
985 			/* update the mainwin display */
986 			//TODO: not sure this is usefull here
987 			ui_mainwindow_update(mainwin, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL));
988 
989 			DB( g_print(" - gtk_main()\n" ) );
990 			gtk_main ();
991 
992 			DB( g_print(" - call destroy mainwin\n" ) );
993 			gtk_widget_destroy(mainwin);
994 		}
995 
996 	}
997 
998 
999     homebank_cleanup();
1000 
1001 	return EXIT_SUCCESS;
1002 }
1003 
1004 #ifdef G_OS_WIN32
1005 /* In case we build this as a windows application */
1006 
1007 #ifdef __GNUC__
1008 #define _stdcall  __attribute__((stdcall))
1009 #endif
1010 
1011 int _stdcall
WinMain(struct HINSTANCE__ * hInstance,struct HINSTANCE__ * hPrevInstance,char * lpszCmdLine,int nCmdShow)1012 WinMain (struct HINSTANCE__ *hInstance,
1013 	 struct HINSTANCE__ *hPrevInstance,
1014 	 char               *lpszCmdLine,
1015 	 int                 nCmdShow)
1016 {
1017 	return main (__argc, __argv);
1018 }
1019 #endif
1020 
1021