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