1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2006 Juernjakob Harder <juernjakob.harder@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307 USA
19 *
20 * $Id: tomoe-config.c 1307 2007-06-07 03:31:25Z ikezoe $
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif /* HAVE_CONFIG_H */
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <glib.h>
31 #include <glib/gi18n-lib.h>
32
33 #include "tomoe-config.h"
34 #include "tomoe-dict.h"
35 #include "tomoe-config.h"
36 #include "glib-utils.h"
37
38 #define DEFAULT_USER_DICT_NAME "user"
39
40 #define TOMOE_CONFIG_GET_PRIVATE(obj) \
41 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TOMOE_TYPE_CONFIG, TomoeConfigPrivate))
42
43 typedef struct _TomoeConfigPrivate TomoeConfigPrivate;
44 struct _TomoeConfigPrivate
45 {
46 gchar *filename;
47 gchar *user_dict_name;
48 GKeyFile *key_file;
49 gchar **languages;
50 };
51
52 enum
53 {
54 PROP_0,
55 PROP_FILENAME
56 };
57
58
59 G_DEFINE_TYPE (TomoeConfig, tomoe_config, G_TYPE_OBJECT)
60
61 static const gchar *system_config_file = CONFDIR "/config";
62
63 static void dispose (GObject *object);
64 static GObject *constructor (GType type,
65 guint n_props,
66 GObjectConstructParam *props);
67 static void set_property (GObject *object,
68 guint prop_id,
69 const GValue *value,
70 GParamSpec *pspec);
71 static void get_property (GObject *object,
72 guint prop_id,
73 GValue *value,
74 GParamSpec *pspec);
75
76 static void tomoe_config_load (TomoeConfig *config);
77 static void tomoe_config_save (TomoeConfig *config);
78
79 static gboolean _tomoe_config_key_file_get_boolean (GKeyFile *key_file,
80 const gchar *group,
81 const gchar *key,
82 gboolean default_value);
83 static gchar *_tomoe_config_key_file_get_string (GKeyFile *key_file,
84 const gchar *group,
85 const gchar *key,
86 const gchar *default_value);
87 static gchar **_tomoe_config_key_file_get_string_list(GKeyFile *key_file,
88 const gchar *group,
89 const gchar *key,
90 gchar **default_value);
91 static gint _tomoe_config_key_file_get_integer (GKeyFile *key_file,
92 const gchar *group,
93 const gchar *key,
94 gint default_value);
95 static void _tomoe_config_load_system_dictionaries (TomoeConfig *config,
96 TomoeShelf *shelf);
97 static TomoeDict *_tomoe_config_load_dictionary (GKeyFile *key_file,
98 const gchar *dict_name,
99 const gchar *type);
100
101 static void
tomoe_config_class_init(TomoeConfigClass * klass)102 tomoe_config_class_init (TomoeConfigClass *klass)
103 {
104 GObjectClass *gobject_class;
105
106 gobject_class = G_OBJECT_CLASS (klass);
107
108 gobject_class->dispose = dispose;
109 gobject_class->constructor = constructor;
110 gobject_class->set_property = set_property;
111 gobject_class->get_property = get_property;
112
113 g_object_class_install_property (gobject_class,
114 PROP_FILENAME,
115 g_param_spec_string ("filename",
116 N_("Filename"),
117 N_("The filename for storing user settings"),
118 NULL,
119 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
120
121 g_type_class_add_private (gobject_class, sizeof (TomoeConfigPrivate));
122 }
123
124 static GObject *
constructor(GType type,guint n_props,GObjectConstructParam * props)125 constructor (GType type, guint n_props, GObjectConstructParam *props)
126 {
127
128 GObject *object;
129 GObjectClass *klass = G_OBJECT_CLASS (tomoe_config_parent_class);
130
131 object = klass->constructor (type, n_props, props);
132
133 tomoe_config_load (TOMOE_CONFIG (object));
134
135 return object;
136 }
137
138 static void
tomoe_config_init(TomoeConfig * config)139 tomoe_config_init (TomoeConfig *config)
140 {
141 TomoeConfigPrivate *priv = TOMOE_CONFIG_GET_PRIVATE (config);
142
143 priv->filename = NULL;
144 priv->user_dict_name = NULL;
145 priv->key_file = NULL;
146 priv->languages = NULL;
147 }
148
149 TomoeConfig *
tomoe_config_new(const gchar * config_file)150 tomoe_config_new (const gchar *config_file)
151 {
152 TomoeConfig *config;
153
154 config = g_object_new(TOMOE_TYPE_CONFIG,
155 "filename", config_file,
156 NULL);
157
158 return config;
159 }
160
161 static void
dispose(GObject * object)162 dispose (GObject *object)
163 {
164 TomoeConfig *config;
165 TomoeConfigPrivate *priv;
166
167 config = TOMOE_CONFIG (object);
168 priv = TOMOE_CONFIG_GET_PRIVATE (config);
169
170 tomoe_config_save (config);
171
172 if (priv->filename)
173 g_free (priv->filename);
174 if (priv->user_dict_name)
175 g_free (priv->user_dict_name);
176 if (priv->key_file)
177 g_key_file_free (priv->key_file);
178 if (priv->languages)
179 g_strfreev (priv->languages);
180
181 priv->filename = NULL;
182 priv->user_dict_name = NULL;
183 priv->key_file = NULL;
184 priv->languages = NULL;
185
186 if (G_OBJECT_CLASS (tomoe_config_parent_class)->dispose)
187 G_OBJECT_CLASS (tomoe_config_parent_class)->dispose (object);
188 }
189
190 static void
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)191 set_property (GObject *object,
192 guint prop_id,
193 const GValue *value,
194 GParamSpec *pspec)
195 {
196 TomoeConfigPrivate *priv = TOMOE_CONFIG_GET_PRIVATE (object);
197
198 switch (prop_id) {
199 case PROP_FILENAME:
200 if (priv->filename)
201 g_free (priv->filename);
202 priv->filename = g_value_dup_string (value);
203 break;
204
205 default:
206 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
207 break;
208 }
209 }
210
211 static void
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)212 get_property (GObject *object,
213 guint prop_id,
214 GValue *value,
215 GParamSpec *pspec)
216 {
217 TomoeConfigPrivate *priv = TOMOE_CONFIG_GET_PRIVATE (object);
218
219 switch (prop_id) {
220 case PROP_FILENAME:
221 g_value_set_string (value, priv->filename);
222 break;
223
224 default:
225 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
226 break;
227 }
228 }
229
230 static void
tomoe_config_load(TomoeConfig * config)231 tomoe_config_load (TomoeConfig *config)
232 {
233 GKeyFile *key_file;
234 GError *error = NULL;
235 TomoeConfigPrivate *priv;
236 const gchar *config_file;
237 gchar *language;
238
239 g_return_if_fail (config);
240
241 priv = TOMOE_CONFIG_GET_PRIVATE (config);
242
243 if (priv->key_file) {
244 g_key_file_free (priv->key_file);
245 priv->key_file = NULL;
246 }
247
248 key_file = g_key_file_new ();
249 config_file = priv->filename ? priv->filename : system_config_file;
250 if (!g_key_file_load_from_file (key_file, config_file,
251 G_KEY_FILE_KEEP_COMMENTS |
252 G_KEY_FILE_KEEP_TRANSLATIONS,
253 &error)) {
254 g_key_file_free (key_file);
255 TOMOE_HANDLE_ERROR (error);
256 return;
257 }
258
259 priv->key_file = key_file;
260
261 if (priv->user_dict_name)
262 g_free (priv->user_dict_name);
263 priv->user_dict_name =
264 _tomoe_config_key_file_get_string (key_file,
265 "config", "user-dictionary",
266 DEFAULT_USER_DICT_NAME);
267
268 if (priv->languages)
269 g_strfreev (priv->languages);
270 language = _tomoe_config_key_file_get_string (key_file,
271 "config", "language",
272 NULL);
273 if (language) {
274 priv->languages = g_new0(gchar *, 2);
275 priv->languages[0] = language;
276 } else {
277 priv->languages =
278 _tomoe_config_key_file_get_string_list (key_file,
279 "config", "languages",
280 NULL);
281 }
282 }
283
284 static void
tomoe_config_save(TomoeConfig * config)285 tomoe_config_save (TomoeConfig *config)
286 {
287 TomoeConfigPrivate *priv;
288
289 g_return_if_fail (config);
290
291 priv = TOMOE_CONFIG_GET_PRIVATE (config);
292 if (priv->filename && priv->key_file) {
293 gchar *data;
294 gsize length;
295 GError *error = NULL;
296
297 data = g_key_file_to_data (priv->key_file, &length, &error);
298 if (error) {
299 TOMOE_HANDLE_ERROR (error);
300 return;
301 }
302
303 if (!g_file_set_contents (priv->filename, data, length, &error)) {
304 TOMOE_HANDLE_ERROR (error);
305 return;
306 }
307 }
308 }
309
310 const gchar *
tomoe_config_get_filename(TomoeConfig * config)311 tomoe_config_get_filename (TomoeConfig *config)
312 {
313 TomoeConfigPrivate *priv;
314
315 g_return_val_if_fail (TOMOE_IS_CONFIG (config), NULL);
316
317 priv = TOMOE_CONFIG_GET_PRIVATE(config);
318 return priv->filename;
319 }
320
321 const gchar *
tomoe_config_get_user_dict_name(TomoeConfig * config)322 tomoe_config_get_user_dict_name (TomoeConfig *config)
323 {
324 TomoeConfigPrivate *priv;
325
326 g_return_val_if_fail (TOMOE_IS_CONFIG (config), NULL);
327
328 priv = TOMOE_CONFIG_GET_PRIVATE(config);
329 return priv->user_dict_name;
330 }
331
332 TomoeShelf *
tomoe_config_make_shelf(TomoeConfig * config,const gchar * language)333 tomoe_config_make_shelf (TomoeConfig *config, const gchar *language)
334 {
335 TomoeConfigPrivate *priv;
336 TomoeShelf *shelf;
337 GKeyFile *key_file;
338 guint i;
339 gchar **dicts;
340 gsize dicts_size;
341
342 g_return_val_if_fail (config, NULL);
343
344 priv = TOMOE_CONFIG_GET_PRIVATE(config);
345 key_file = priv->key_file;
346 g_return_val_if_fail (key_file, NULL);
347
348 shelf = tomoe_shelf_new ();
349 dicts = g_key_file_get_groups (key_file, &dicts_size);
350 for (i = 0; i < dicts_size; i++) {
351 gchar *dict_name, *type;
352 TomoeDict *dict;
353
354 dict_name = dicts[i];
355 if (!g_str_has_suffix (dict_name, "-dictionary"))
356 continue;
357
358 if (!_tomoe_config_key_file_get_boolean (key_file, dict_name,
359 "use", TRUE))
360 continue;
361
362 type = _tomoe_config_key_file_get_string (key_file, dict_name,
363 "type", "xml");
364 dict = _tomoe_config_load_dictionary (key_file, dict_name, type);
365 if (dict) {
366 gchar tmp, *dictionary_suffix;
367 dictionary_suffix = g_strrstr (dict_name, "-dictionary");
368 tmp = dict_name[dictionary_suffix - dict_name];
369 dict_name[dictionary_suffix - dict_name] = '\0';
370 tomoe_shelf_register_dict (shelf, dict_name, dict);
371 dict_name[dictionary_suffix - dict_name] = tmp;
372 g_object_unref (dict);
373 }
374 g_free (type);
375 }
376 g_strfreev(dicts);
377
378 if (_tomoe_config_key_file_get_boolean (key_file,
379 "config", "use-system-dictionaries",
380 TRUE)) {
381 _tomoe_config_load_system_dictionaries (config, shelf);
382 }
383
384 return shelf;
385 }
386
387 const gchar *const *
tomoe_config_get_languages(TomoeConfig * config)388 tomoe_config_get_languages (TomoeConfig *config)
389 {
390 TomoeConfigPrivate *priv;
391
392 g_return_val_if_fail (TOMOE_IS_CONFIG (config), NULL);
393
394 priv = TOMOE_CONFIG_GET_PRIVATE (config);
395 return (const gchar *const *)(priv->languages);
396 }
397
398
399 static gboolean
_tomoe_config_key_file_get_boolean(GKeyFile * key_file,const gchar * group,const gchar * key,gboolean default_value)400 _tomoe_config_key_file_get_boolean (GKeyFile *key_file,
401 const gchar *group,
402 const gchar *key,
403 gboolean default_value)
404 {
405 gboolean result;
406 GError *error = NULL;
407
408 result = g_key_file_get_boolean (key_file, group, key, &error);
409 if (error) {
410 switch (error->code) {
411 case G_KEY_FILE_ERROR_NOT_FOUND:
412 g_error_free (error);
413 break;
414 case G_KEY_FILE_ERROR_INVALID_VALUE:
415 TOMOE_HANDLE_ERROR (error);
416 break;
417 }
418 result = default_value;
419 }
420
421 return result;
422 }
423
424 static gchar *
_tomoe_config_key_file_get_string(GKeyFile * key_file,const gchar * group,const gchar * key,const gchar * default_value)425 _tomoe_config_key_file_get_string (GKeyFile *key_file,
426 const gchar *group,
427 const gchar *key,
428 const gchar *default_value)
429 {
430 gchar *result = NULL;
431 GError *error = NULL;
432
433 result = g_key_file_get_string (key_file, group, key, &error);
434 if (error) {
435 switch (error->code) {
436 case G_KEY_FILE_ERROR_NOT_FOUND:
437 g_error_free (error);
438 break;
439 case G_KEY_FILE_ERROR_INVALID_VALUE:
440 TOMOE_HANDLE_ERROR (error);
441 break;
442 }
443 if (default_value)
444 result = g_strdup (default_value);
445 }
446
447 return result;
448 }
449
450 static gchar **
_tomoe_config_key_file_get_string_list(GKeyFile * key_file,const gchar * group,const gchar * key,gchar ** default_value)451 _tomoe_config_key_file_get_string_list (GKeyFile *key_file,
452 const gchar *group,
453 const gchar *key,
454 gchar **default_value)
455 {
456 gchar **result = NULL;
457 gsize length = 0;
458 GError *error = NULL;
459
460 result = g_key_file_get_string_list (key_file, group, key, &length, &error);
461 if (error) {
462 switch (error->code) {
463 case G_KEY_FILE_ERROR_NOT_FOUND:
464 g_error_free (error);
465 break;
466 case G_KEY_FILE_ERROR_INVALID_VALUE:
467 TOMOE_HANDLE_ERROR (error);
468 break;
469 }
470 if (default_value)
471 result = g_strdupv (default_value);
472 }
473
474 return result;
475 }
476
477 static gint
_tomoe_config_key_file_get_integer(GKeyFile * key_file,const gchar * group,const gchar * key,gint default_value)478 _tomoe_config_key_file_get_integer (GKeyFile *key_file,
479 const gchar *group,
480 const gchar *key,
481 gint default_value)
482 {
483 gint result;
484 GError *error = NULL;
485
486 result = g_key_file_get_integer (key_file, group, key, &error);
487 if (error) {
488 switch (error->code) {
489 case G_KEY_FILE_ERROR_NOT_FOUND:
490 g_error_free (error);
491 break;
492 case G_KEY_FILE_ERROR_INVALID_VALUE:
493 TOMOE_HANDLE_ERROR (error);
494 break;
495 }
496 result = default_value;
497 }
498
499 return result;
500 }
501
502 static void
_tomoe_config_load_system_dictionaries(TomoeConfig * config,TomoeShelf * shelf)503 _tomoe_config_load_system_dictionaries (TomoeConfig *config, TomoeShelf *shelf)
504 {
505 const gchar *filename;
506 GDir *gdir;
507 TomoeDict *dict;
508
509 dict = tomoe_dict_new ("unihan", NULL);
510 if (dict) {
511 tomoe_shelf_register_dict (shelf, "Unihan", dict);
512 g_object_unref (dict);
513 }
514
515 gdir = g_dir_open (DICT_DATADIR, 0, NULL);
516 if (!gdir)
517 return;
518
519 while ((filename = g_dir_read_name (gdir))) {
520 gchar *path;
521
522 if (!g_str_has_suffix (filename, ".xml"))
523 continue;
524 path = g_build_filename(DICT_DATADIR, filename, NULL);
525 if (tomoe_shelf_has_dict (shelf, path)) {
526 g_free (path);
527 continue;
528 }
529
530 dict = tomoe_dict_new ("xml", "filename", path, "editable", FALSE,
531 NULL);
532 if (dict) {
533 tomoe_shelf_register_dict (shelf, tomoe_dict_get_name (dict), dict);
534 g_object_unref (dict);
535 }
536
537 g_free (path);
538 }
539 g_dir_close (gdir);
540 }
541
542 static TomoeDict *
load_xml_dictionary(GKeyFile * key_file,const gchar * dict_name)543 load_xml_dictionary (GKeyFile *key_file, const gchar *dict_name)
544 {
545 TomoeDict *dict;
546 GError *error = NULL;
547 gchar *filename;
548 gboolean user_dict, editable;
549
550 filename = g_key_file_get_string (key_file, dict_name, "file", &error);
551 if (error) {
552 TOMOE_HANDLE_ERROR (error);
553 return NULL;
554 }
555
556 editable = _tomoe_config_key_file_get_boolean (key_file, dict_name,
557 "editable", TRUE);
558 user_dict = _tomoe_config_key_file_get_boolean (key_file, dict_name,
559 "user", TRUE);
560 if (!user_dict) {
561 gchar *tmp;
562 tmp = g_build_filename (DICT_DATADIR, filename, NULL);
563 g_free (filename);
564 filename = tmp;
565 }
566
567 dict = tomoe_dict_new ("xml",
568 "filename", filename,
569 "editable", editable,
570 NULL);
571
572 g_free (filename);
573
574 return dict;
575 }
576
577 static TomoeDict *
load_est_dictionary(GKeyFile * key_file,const gchar * dict_name)578 load_est_dictionary (GKeyFile *key_file, const gchar *dict_name)
579 {
580 TomoeDict *dict;
581 GError *error = NULL;
582 gchar *name, *database;
583 gboolean user_dict, editable;
584
585 name = g_key_file_get_string (key_file, dict_name, "name", &error);
586 if (error) {
587 TOMOE_HANDLE_ERROR (error);
588 return NULL;
589 }
590
591 database = g_key_file_get_string (key_file, dict_name, "database", &error);
592 if (error) {
593 TOMOE_HANDLE_ERROR (error);
594 return NULL;
595 }
596
597 editable = _tomoe_config_key_file_get_boolean (key_file, dict_name,
598 "editable", TRUE);
599 user_dict = _tomoe_config_key_file_get_boolean (key_file, dict_name,
600 "user", TRUE);
601 if (!user_dict) {
602 gchar *tmp;
603 tmp = g_build_filename (DICT_DATADIR, database, NULL);
604 g_free (database);
605 database = tmp;
606 }
607
608 dict = tomoe_dict_new ("est",
609 "name", name,
610 "database", database,
611 "editable", editable,
612 NULL);
613
614 g_free (name);
615 g_free (database);
616
617 return dict;
618 }
619
620 static TomoeDict *
load_unihan_dictionary(GKeyFile * key_file,const gchar * dict_name)621 load_unihan_dictionary (GKeyFile *key_file, const gchar *dict_name)
622 {
623 TomoeDict *dict;
624 gchar *name;
625
626 name = _tomoe_config_key_file_get_string (key_file, dict_name,
627 "name", NULL);
628 dict = tomoe_dict_new ("unihan",
629 "name", name,
630 NULL);
631 g_free (name);
632
633 return dict;
634 }
635
636 static TomoeDict *
load_mysql_dictionary(GKeyFile * key_file,const gchar * dict_name)637 load_mysql_dictionary (GKeyFile *key_file, const gchar *dict_name)
638 {
639 TomoeDict *dict;
640 gchar *name, *user, *password, *host, *socket, *database;
641 gint port;
642 gboolean editable;
643
644 name = _tomoe_config_key_file_get_string (key_file, dict_name,
645 "name", NULL);
646 editable = _tomoe_config_key_file_get_boolean (key_file, dict_name,
647 "editable", TRUE);
648 user = _tomoe_config_key_file_get_string (key_file, dict_name,
649 "user", NULL);
650 password = _tomoe_config_key_file_get_string (key_file, dict_name,
651 "password", NULL);
652 host = _tomoe_config_key_file_get_string (key_file, dict_name,
653 "host", NULL);
654 port = _tomoe_config_key_file_get_integer (key_file, dict_name,
655 "port", 0);
656 socket = _tomoe_config_key_file_get_string (key_file, dict_name,
657 "socket", NULL);
658 database = _tomoe_config_key_file_get_string (key_file, dict_name,
659 "database", NULL);
660
661 dict = tomoe_dict_new ("mysql",
662 "name", name,
663 "editable", editable,
664 "user", user,
665 "password", password,
666 "host", host,
667 "port", port,
668 "socket", socket,
669 "database", database,
670 NULL);
671 g_free (name);
672
673 return dict;
674 }
675
676 static TomoeDict *
_tomoe_config_load_dictionary(GKeyFile * key_file,const gchar * dict_name,const gchar * type)677 _tomoe_config_load_dictionary (GKeyFile *key_file,
678 const gchar *dict_name,
679 const gchar *type)
680 {
681 if (strcmp (type, "xml") == 0) {
682 return load_xml_dictionary (key_file, dict_name);
683 } else if (strcmp (type, "est") == 0) {
684 return load_est_dictionary (key_file, dict_name);
685 } else if (strcmp (type, "unihan") == 0) {
686 return load_unihan_dictionary (key_file, dict_name);
687 } else if (strcmp (type, "mysql") == 0) {
688 return load_mysql_dictionary (key_file, dict_name);
689 } else {
690 return NULL;
691 }
692 }
693
694 /*
695 * vi:ts=4:nowrap:ai:expandtab
696 */
697