1 /* gdict-source.c - Source configuration for Gdict
2 *
3 * Copyright (C) 2005 Emmanuele Bassi <ebassi@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library 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 GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20 * SECTION:gdict-source
21 * @short_description: A dictionary source definition
22 *
23 * #GdictSource is the representation of a #GdictContext. Each dictionary
24 * source provides a list of available dictionaries (databases) and a list
25 * of available matching strategies. Using a #GdictContext you can query
26 * the dictionary source for matching words and for definitions.
27 *
28 * By using a #GdictSource object you can retrieve the appropriate
29 * #GdictContext, already set up with the right parameters.
30 */
31
32 #include "config.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/stat.h>
38
39 #include <glib/gi18n-lib.h>
40
41 #include "gdict-source.h"
42 #include "gdict-client-context.h"
43 #include "gdict-utils.h"
44 #include "gdict-enum-types.h"
45 #include "gdict-private.h"
46
47 /* Main group */
48 #define SOURCE_GROUP "Dictionary Source"
49
50 /* Common keys */
51 #define SOURCE_KEY_NAME "Name"
52 #define SOURCE_KEY_DESCRIPTION "Description" /* Deprecated */
53 #define SOURCE_KEY_COMMENT "Comment"
54 #define SOURCE_KEY_TRANSPORT "Transport"
55 #define SOURCE_KEY_DATABASE "Database"
56 #define SOURCE_KEY_STRATEGY "Strategy"
57
58 /* dictd transport keys */
59 #define SOURCE_KEY_HOSTNAME "Hostname"
60 #define SOURCE_KEY_PORT "Port"
61
62 struct _GdictSourcePrivate
63 {
64 gchar *filename;
65 GKeyFile *keyfile;
66
67 gchar *name;
68 gchar *description;
69 gboolean editable;
70
71 gchar *database;
72 gchar *strategy;
73
74 GdictSourceTransport transport;
75
76 GdictContext *context;
77 };
78
79 enum
80 {
81 PROP_0,
82
83 PROP_FILENAME,
84 PROP_NAME,
85 PROP_DESCRIPTION,
86 PROP_EDITABLE,
87 PROP_DATABASE,
88 PROP_STRATEGY,
89 PROP_TRANSPORT,
90 PROP_CONTEXT
91 };
92
93 /* keep in sync with GdictSourceTransport */
94 static const gchar *valid_transports[] =
95 {
96 "dictd", /* GDICT_SOURCE_TRANSPORT_DICTD */
97
98 NULL /* GDICT_SOURCE_TRANSPORT_INVALID */
99 };
100
101 #define IS_VALID_TRANSPORT(t) (((t) >= GDICT_SOURCE_TRANSPORT_DICTD) && \
102 ((t) < GDICT_SOURCE_TRANSPORT_INVALID))
103
104 GQuark
gdict_source_error_quark(void)105 gdict_source_error_quark (void)
106 {
107 static GQuark quark = 0;
108
109 if (G_UNLIKELY (quark == 0))
110 quark = g_quark_from_static_string ("gdict-source-error-quark");
111
112 return quark;
113 }
114
115
G_DEFINE_TYPE_WITH_PRIVATE(GdictSource,gdict_source,G_TYPE_OBJECT)116 G_DEFINE_TYPE_WITH_PRIVATE (GdictSource, gdict_source, G_TYPE_OBJECT)
117
118
119 static void
120 gdict_source_set_property (GObject *object,
121 guint prop_id,
122 const GValue *value,
123 GParamSpec *pspec)
124 {
125 GdictSource *source = GDICT_SOURCE (object);
126
127 switch (prop_id)
128 {
129 case PROP_NAME:
130 gdict_source_set_name (source, g_value_get_string (value));
131 break;
132 case PROP_DESCRIPTION:
133 gdict_source_set_description (source, g_value_get_string (value));
134 break;
135 case PROP_TRANSPORT:
136 gdict_source_set_transport (source, g_value_get_enum (value), NULL);
137 break;
138 case PROP_DATABASE:
139 gdict_source_set_database (source, g_value_get_string (value));
140 break;
141 case PROP_STRATEGY:
142 gdict_source_set_strategy (source, g_value_get_string (value));
143 break;
144 default:
145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
146 break;
147 }
148 }
149
150 static void
gdict_source_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)151 gdict_source_get_property (GObject *object,
152 guint prop_id,
153 GValue *value,
154 GParamSpec *pspec)
155 {
156 GdictSource *source = GDICT_SOURCE (object);
157 GdictSourcePrivate *priv = source->priv;
158
159 switch (prop_id)
160 {
161 case PROP_FILENAME:
162 g_value_set_string (value, priv->filename);
163 break;
164 case PROP_NAME:
165 g_value_set_string (value, priv->name);
166 break;
167 case PROP_DESCRIPTION:
168 g_value_set_string (value, priv->description);
169 break;
170 case PROP_EDITABLE:
171 g_value_set_boolean (value, priv->editable);
172 break;
173 case PROP_DATABASE:
174 g_value_set_string (value, priv->database);
175 break;
176 case PROP_STRATEGY:
177 g_value_set_string (value, priv->strategy);
178 break;
179 case PROP_TRANSPORT:
180 g_value_set_enum (value, priv->transport);
181 break;
182 case PROP_CONTEXT:
183 g_value_set_object (value, gdict_source_peek_context (source));
184 break;
185 default:
186 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
187 break;
188 }
189 }
190
191 static void
gdict_source_finalize(GObject * object)192 gdict_source_finalize (GObject *object)
193 {
194 GdictSource *self = GDICT_SOURCE (object);
195 GdictSourcePrivate *priv = gdict_source_get_instance_private (self);
196
197 g_free (priv->filename);
198 g_free (priv->name);
199 g_free (priv->description);
200 g_free (priv->database);
201 g_free (priv->strategy);
202
203 g_clear_pointer (&priv->keyfile, g_key_file_unref);
204 g_clear_object (&priv->context);
205
206 G_OBJECT_CLASS (gdict_source_parent_class)->finalize (object);
207 }
208
209 static void
gdict_source_class_init(GdictSourceClass * klass)210 gdict_source_class_init (GdictSourceClass *klass)
211 {
212 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
213
214 gobject_class->set_property = gdict_source_set_property;
215 gobject_class->get_property = gdict_source_get_property;
216 gobject_class->finalize = gdict_source_finalize;
217
218 /**
219 * GdictSource:filename
220 *
221 * The filename used by this dictionary source.
222 *
223 * Since: 1.0
224 */
225 g_object_class_install_property (gobject_class,
226 PROP_FILENAME,
227 g_param_spec_string ("filename",
228 "Filename",
229 "The filename used by this dictionary source",
230 NULL,
231 G_PARAM_READABLE));
232 /**
233 * GdictSource:name
234 *
235 * The display name of this dictionary source.
236 *
237 * Since: 1.0
238 */
239 g_object_class_install_property (gobject_class,
240 PROP_NAME,
241 g_param_spec_string ("name",
242 "Name",
243 "The display name of this dictionary source",
244 NULL,
245 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
246 /**
247 * GdictSource:description
248 *
249 * The description of this dictionary source.
250 *
251 * Since: 1.0
252 */
253 g_object_class_install_property (gobject_class,
254 PROP_DESCRIPTION,
255 g_param_spec_string ("description",
256 "Description",
257 "The description of this dictionary source",
258 NULL,
259 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
260 /**
261 * GdictSource:editable
262 *
263 * Whether the dictionary source is editable or not.
264 *
265 * Since: 1.0
266 */
267 g_object_class_install_property (gobject_class,
268 PROP_EDITABLE,
269 g_param_spec_boolean ("editable",
270 "Editable",
271 "Whether the dictionary source is editable or not",
272 TRUE,
273 (G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)));
274 /**
275 * GdictSource:database
276 *
277 * The default database of this dictionary source.
278 *
279 * Since: 1.0
280 */
281 g_object_class_install_property (gobject_class,
282 PROP_DATABASE,
283 g_param_spec_string ("database",
284 "Database",
285 "The default database of this dictionary source",
286 NULL,
287 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
288 /**
289 * GdictSource:strategy
290 *
291 * The default strategy of this dictionary source.
292 *
293 * Since: 1.0
294 */
295 g_object_class_install_property (gobject_class,
296 PROP_STRATEGY,
297 g_param_spec_string ("strategy",
298 "Strategy",
299 "The default strategy of this dictionary source",
300 NULL,
301 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
302 /**
303 * GdictSource:transport
304 *
305 * The transport mechanism used by this source.
306 *
307 * Since: 1.0
308 */
309 g_object_class_install_property (gobject_class,
310 PROP_TRANSPORT,
311 g_param_spec_enum ("transport",
312 "Transport",
313 "The transport mechanism used by this dictionary source",
314 GDICT_TYPE_SOURCE_TRANSPORT,
315 GDICT_SOURCE_TRANSPORT_INVALID,
316 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
317 /**
318 * GdictSource:context
319 *
320 * The #GdictContext bound to this source.
321 *
322 * Since: 1.0
323 */
324 g_object_class_install_property (gobject_class,
325 PROP_CONTEXT,
326 g_param_spec_object ("context",
327 "Context",
328 "The GdictContext bound to this source",
329 GDICT_TYPE_CONTEXT,
330 G_PARAM_READABLE));
331 }
332
333 static void
gdict_source_init(GdictSource * source)334 gdict_source_init (GdictSource *source)
335 {
336 GdictSourcePrivate *priv;
337
338 priv = gdict_source_get_instance_private (source);
339 source->priv = priv;
340
341 priv->keyfile = g_key_file_new ();
342 priv->transport = GDICT_SOURCE_TRANSPORT_INVALID;
343 priv->editable = TRUE;
344 }
345
346 /**
347 * gdict_source_new:
348 *
349 * Creates an empty #GdictSource object. Use gdict_load_from_file() to
350 * read an existing dictionary source definition file.
351 *
352 * Return value: an empty #GdictSource
353 */
354 GdictSource *
gdict_source_new(void)355 gdict_source_new (void)
356 {
357 return g_object_new (GDICT_TYPE_SOURCE, NULL);
358 }
359
360 static GdictSourceTransport
gdict_source_resolve_transport(const gchar * transport)361 gdict_source_resolve_transport (const gchar *transport)
362 {
363 if (!transport)
364 return GDICT_SOURCE_TRANSPORT_INVALID;
365
366 if (strcmp (transport, "dictd") == 0)
367 return GDICT_SOURCE_TRANSPORT_DICTD;
368 else
369 return GDICT_SOURCE_TRANSPORT_INVALID;
370
371 g_assert_not_reached ();
372 }
373
374 static GdictContext *
gdict_source_create_context(GdictSource * source,GdictSourceTransport transport,GError ** error)375 gdict_source_create_context (GdictSource *source,
376 GdictSourceTransport transport,
377 GError **error)
378 {
379 GdictSourcePrivate *priv;
380 GdictContext *context;
381
382 g_assert (GDICT_IS_SOURCE (source));
383
384 priv = source->priv;
385
386 switch (transport)
387 {
388 case GDICT_SOURCE_TRANSPORT_DICTD:
389 {
390 gchar *hostname;
391 gint port;
392
393 hostname = g_key_file_get_string (priv->keyfile,
394 SOURCE_GROUP,
395 SOURCE_KEY_HOSTNAME,
396 NULL);
397
398 port = g_key_file_get_integer (priv->keyfile,
399 SOURCE_GROUP,
400 SOURCE_KEY_PORT,
401 NULL);
402 if (!port)
403 port = -1;
404
405 context = gdict_client_context_new (hostname, port);
406
407 if (hostname)
408 g_free (hostname);
409 }
410 break;
411 default:
412 g_set_error (error, GDICT_SOURCE_ERROR,
413 GDICT_SOURCE_ERROR_PARSE,
414 _("Invalid transport type “%d”"),
415 transport);
416 return NULL;
417 }
418
419 g_assert (context != NULL);
420
421 if (priv->transport != transport)
422 priv->transport = transport;
423
424 return context;
425 }
426
427 static gboolean
gdict_source_parse(GdictSource * source,GError ** error)428 gdict_source_parse (GdictSource *source,
429 GError **error)
430 {
431 GdictSourcePrivate *priv;
432 GError *parse_error;
433 gchar *transport;
434 GdictSourceTransport t;
435
436 priv = source->priv;
437
438 if (!g_key_file_has_group (priv->keyfile, SOURCE_GROUP))
439 {
440 g_set_error (error, GDICT_SOURCE_ERROR,
441 GDICT_SOURCE_ERROR_PARSE,
442 _("No “%s” group found inside the dictionary source definition"),
443 SOURCE_GROUP);
444
445 return FALSE;
446 }
447
448 /* fetch the name for the dictionary source definition */
449 parse_error = NULL;
450 priv->name = g_key_file_get_string (priv->keyfile,
451 SOURCE_GROUP,
452 SOURCE_KEY_NAME,
453 &parse_error);
454 if (parse_error)
455 {
456 g_set_error (error, GDICT_SOURCE_ERROR,
457 GDICT_SOURCE_ERROR_PARSE,
458 _("Unable to get the “%s” key inside the dictionary "
459 "source definition: %s"),
460 SOURCE_KEY_NAME,
461 parse_error->message);
462 g_error_free (parse_error);
463
464 g_key_file_free (priv->keyfile);
465 priv->keyfile = NULL;
466
467 return FALSE;
468 }
469
470 /* if present, fetch the localized description */
471 const char *description_key;
472
473 if (g_key_file_has_key (priv->keyfile, SOURCE_GROUP, SOURCE_KEY_COMMENT, NULL))
474 description_key = SOURCE_KEY_COMMENT;
475 else if (g_key_file_has_key (priv->keyfile, SOURCE_GROUP, SOURCE_KEY_DESCRIPTION, NULL))
476 description_key = SOURCE_KEY_DESCRIPTION;
477 else
478 description_key = NULL;
479
480 if (description_key != NULL)
481 {
482 priv->description = g_key_file_get_locale_string (priv->keyfile,
483 SOURCE_GROUP,
484 description_key,
485 NULL,
486 &parse_error);
487 if (parse_error)
488 {
489 g_set_error (error, GDICT_SOURCE_ERROR,
490 GDICT_SOURCE_ERROR_PARSE,
491 _("Unable to get the “%s” key inside the dictionary "
492 "source definition: %s"),
493 description_key,
494 parse_error->message);
495
496 g_error_free (parse_error);
497 g_key_file_free (priv->keyfile);
498 priv->keyfile = NULL;
499 g_free (priv->name);
500
501 return FALSE;
502 }
503 }
504
505 if (g_key_file_has_key (priv->keyfile, SOURCE_GROUP, SOURCE_KEY_DATABASE, NULL))
506 {
507 priv->database = g_key_file_get_string (priv->keyfile,
508 SOURCE_GROUP,
509 SOURCE_KEY_DATABASE,
510 &parse_error);
511 if (parse_error)
512 {
513 g_set_error (error, GDICT_SOURCE_ERROR,
514 GDICT_SOURCE_ERROR_PARSE,
515 _("Unable to get the “%s” key inside the dictionary "
516 "source definition: %s"),
517 SOURCE_KEY_DATABASE,
518 parse_error->message);
519
520 g_error_free (parse_error);
521 g_key_file_free (priv->keyfile);
522 priv->keyfile = NULL;
523 g_free (priv->name);
524 g_free (priv->description);
525
526 return FALSE;
527 }
528 }
529
530 if (g_key_file_has_key (priv->keyfile, SOURCE_GROUP, SOURCE_KEY_STRATEGY, NULL))
531 {
532 priv->strategy = g_key_file_get_string (priv->keyfile,
533 SOURCE_GROUP,
534 SOURCE_KEY_STRATEGY,
535 &parse_error);
536 if (parse_error)
537 {
538 g_set_error (error, GDICT_SOURCE_ERROR,
539 GDICT_SOURCE_ERROR_PARSE,
540 _("Unable to get the “%s” key inside the dictionary "
541 "source definition: %s"),
542 SOURCE_KEY_STRATEGY,
543 parse_error->message);
544
545 g_error_free (parse_error);
546 g_key_file_free (priv->keyfile);
547 priv->keyfile = NULL;
548
549 g_free (priv->name);
550 g_free (priv->description);
551 g_free (priv->database);
552
553 return FALSE;
554 }
555 }
556
557 transport = g_key_file_get_string (priv->keyfile,
558 SOURCE_GROUP,
559 SOURCE_KEY_TRANSPORT,
560 &parse_error);
561 if (parse_error)
562 {
563 g_set_error (error, GDICT_SOURCE_ERROR,
564 GDICT_SOURCE_ERROR_PARSE,
565 _("Unable to get the “%s” key inside the dictionary "
566 "source definition file: %s"),
567 SOURCE_KEY_TRANSPORT,
568 parse_error->message);
569
570 g_error_free (parse_error);
571 g_key_file_free (priv->keyfile);
572 priv->keyfile = NULL;
573 g_free (priv->name);
574 g_free (priv->description);
575 g_free (priv->database);
576 g_free (priv->strategy);
577
578 return FALSE;
579 }
580
581 t = gdict_source_resolve_transport (transport);
582 g_free (transport);
583
584 priv->context = gdict_source_create_context (source, t, &parse_error);
585 if (parse_error)
586 {
587 g_propagate_error (error, parse_error);
588
589 g_key_file_free (priv->keyfile);
590 priv->keyfile = NULL;
591
592 g_free (priv->name);
593 g_free (priv->description);
594 g_free (priv->database);
595 g_free (priv->strategy);
596
597 return FALSE;
598 }
599
600 return TRUE;
601 }
602
603 /**
604 * gdict_source_load_from_file:
605 * @source: an empty #GdictSource
606 * @filename: path to a dictionary source file
607 * @error: return location for a #GError or %NULL
608 *
609 * Loads a dictionary source definition file into an empty #GdictSource
610 * object.
611 *
612 * Return value: %TRUE if @filename was loaded successfully.
613 *
614 * Since: 1.0
615 */
616 gboolean
gdict_source_load_from_file(GdictSource * source,const gchar * filename,GError ** error)617 gdict_source_load_from_file (GdictSource *source,
618 const gchar *filename,
619 GError **error)
620 {
621 struct stat stat_buf;
622 GdictSourcePrivate *priv;
623 GError *read_error;
624 GError *parse_error;
625
626 g_return_val_if_fail (GDICT_IS_SOURCE (source), FALSE);
627 g_return_val_if_fail (filename != NULL, FALSE);
628
629 priv = source->priv;
630
631 if (!priv->keyfile)
632 priv->keyfile = g_key_file_new ();
633
634 read_error = NULL;
635 g_key_file_load_from_file (priv->keyfile,
636 filename,
637 G_KEY_FILE_KEEP_TRANSLATIONS,
638 &read_error);
639 if (read_error)
640 {
641 g_propagate_error (error, read_error);
642
643 return FALSE;
644 }
645
646 parse_error = NULL;
647 gdict_source_parse (source, &parse_error);
648 if (parse_error)
649 {
650 g_propagate_error (error, parse_error);
651
652 return FALSE;
653 }
654
655 g_assert (priv->context != NULL);
656
657 priv->filename = g_strdup (filename);
658
659 if (lstat (filename, &stat_buf) < 0)
660 {
661 return FALSE;
662 }
663 priv->editable = (stat_buf.st_mode & S_IWUSR) ? TRUE : FALSE;
664
665 return TRUE;
666 }
667
668 /**
669 * gdict_source_load_from_data:
670 * @source: a #GdictSource
671 * @data: string containing a dictionary source
672 * @length: length of @data
673 * @error: return location for a #GError or %NULL
674 *
675 * Loads a dictionary source definition from @data inside an empty
676 * #GdictSource object.
677 *
678 * Return value: %TRUE if @filename was loaded successfully.
679 *
680 * Since: 1.0
681 */
682 gboolean
gdict_source_load_from_data(GdictSource * source,const gchar * data,gsize length,GError ** error)683 gdict_source_load_from_data (GdictSource *source,
684 const gchar *data,
685 gsize length,
686 GError **error)
687 {
688 GdictSourcePrivate *priv;
689 GError *read_error;
690 GError *parse_error;
691
692 g_return_val_if_fail (GDICT_IS_SOURCE (source), FALSE);
693 g_return_val_if_fail (data != NULL, FALSE);
694
695 priv = source->priv;
696
697 if (!priv->keyfile)
698 priv->keyfile = g_key_file_new ();
699
700 read_error = NULL;
701 g_key_file_load_from_data (priv->keyfile,
702 data,
703 length,
704 G_KEY_FILE_KEEP_TRANSLATIONS,
705 &read_error);
706 if (read_error)
707 {
708 g_propagate_error (error, read_error);
709
710 return FALSE;
711 }
712
713 parse_error = NULL;
714 gdict_source_parse (source, &parse_error);
715 if (parse_error)
716 {
717 g_propagate_error (error, parse_error);
718
719 return FALSE;
720 }
721
722 g_assert (priv->context != NULL);
723
724 g_free (priv->filename);
725 priv->filename = NULL;
726
727 return TRUE;
728 }
729
730 /**
731 * gdict_source_to_data:
732 * @source: a #GdictSource
733 * @length: (out) (optional): return loaction for the length
734 * of the string, or %NULL
735 * @error: return location for a #GError or %NULL
736 *
737 * Outputs a dictionary source as a string.
738 *
739 * Return value: a newly allocated string holding the contents of @source.
740 *
741 * Since: 1.0
742 */
743 gchar *
gdict_source_to_data(GdictSource * source,gsize * length,GError ** error)744 gdict_source_to_data (GdictSource *source,
745 gsize *length,
746 GError **error)
747 {
748 GdictSourcePrivate *priv;
749 gchar *retval = NULL;
750
751 g_return_val_if_fail (GDICT_IS_SOURCE (source), NULL);
752
753 priv = source->priv;
754
755 if (!priv->name)
756 {
757 g_set_error (error, GDICT_SOURCE_ERROR,
758 GDICT_SOURCE_ERROR_INVALID_NAME,
759 _("Dictionary source does not have name"));
760
761 return NULL;
762 }
763
764 if (!IS_VALID_TRANSPORT (priv->transport))
765 {
766 g_set_error (error, GDICT_SOURCE_ERROR,
767 GDICT_SOURCE_ERROR_INVALID_TRANSPORT,
768 _("Dictionary source “%s” has invalid transport “%s”"),
769 priv->name,
770 valid_transports[priv->transport]);
771
772 return NULL;
773 }
774
775 if (priv->keyfile)
776 {
777 GError *write_error = NULL;
778
779 retval = g_key_file_to_data (priv->keyfile,
780 length,
781 &write_error);
782 if (write_error)
783 g_propagate_error (error, write_error);
784 }
785
786 return retval;
787 }
788
789 /**
790 * gdict_source_set_name:
791 * @source: a #GdictSource
792 * @name: the UTF8-encoded name of the dictionary source
793 *
794 * Sets @name as the displayable name of the dictionary source.
795 *
796 * Since: 1.0
797 */
798 void
gdict_source_set_name(GdictSource * source,const gchar * name)799 gdict_source_set_name (GdictSource *source,
800 const gchar *name)
801 {
802 g_return_if_fail (GDICT_IS_SOURCE (source));
803 g_return_if_fail (name != NULL);
804
805 g_free (source->priv->name);
806 source->priv->name = g_strdup (name);
807
808 if (!source->priv->keyfile)
809 source->priv->keyfile = g_key_file_new ();
810
811 g_key_file_set_string (source->priv->keyfile,
812 SOURCE_GROUP,
813 SOURCE_KEY_NAME,
814 name);
815 }
816
817 /**
818 * gdict_source_get_name:
819 * @source: a #GdictSource
820 *
821 * Retrieves the name of @source.
822 *
823 * Return value: the name of a #GdictSource. The returned string is owned
824 * by the #GdictSource object, and should not be modified or freed.
825 *
826 * Since: 1.0
827 */
828 const gchar *
gdict_source_get_name(GdictSource * source)829 gdict_source_get_name (GdictSource *source)
830 {
831 g_return_val_if_fail (GDICT_IS_SOURCE (source), NULL);
832
833 return source->priv->name;
834 }
835
836 /**
837 * gdict_source_set_description:
838 * @source: a #GdictSource
839 * @description: (nullable): a UTF-8 encoded description or %NULL
840 *
841 * Sets the description of @source. If @description is %NULL, unsets the
842 * currently set description.
843 *
844 * Since: 1.0
845 */
846 void
gdict_source_set_description(GdictSource * source,const gchar * description)847 gdict_source_set_description (GdictSource *source,
848 const gchar *description)
849 {
850 g_return_if_fail (GDICT_IS_SOURCE (source));
851
852 g_free (source->priv->description);
853
854 if (!source->priv->keyfile)
855 source->priv->keyfile = g_key_file_new ();
856
857 if (description && description[0] != '\0')
858 {
859 source->priv->description = g_strdup (description);
860
861 g_key_file_set_string (source->priv->keyfile,
862 SOURCE_GROUP,
863 SOURCE_KEY_DESCRIPTION,
864 description);
865 }
866 else
867 {
868 if (g_key_file_has_key (source->priv->keyfile,
869 SOURCE_GROUP,
870 SOURCE_KEY_DESCRIPTION,
871 NULL))
872 g_key_file_remove_key (source->priv->keyfile,
873 SOURCE_GROUP,
874 SOURCE_KEY_DESCRIPTION,
875 NULL);
876 }
877 }
878
879 /**
880 * gdict_source_get_description:
881 * @source: a #GdictSource
882 *
883 * Retrieves the description of @source.
884 *
885 * Return value: the description of a #GdictSource. The returned string is
886 * owned by the #GdictSource object, and should not be modified or freed.
887 *
888 * Since: 1.0
889 */
890 const gchar *
gdict_source_get_description(GdictSource * source)891 gdict_source_get_description (GdictSource *source)
892 {
893 g_return_val_if_fail (GDICT_IS_SOURCE (source), NULL);
894
895 return source->priv->description;
896 }
897
898 /**
899 * gdict_source_is_editable:
900 * @source: a #GdictSource
901 *
902 * Retrieves the is-editable property of @source.
903 *
904 * Return value: %TRUE if @source is editable.
905 *
906 * Since: 1.0
907 */
908 gboolean
gdict_source_is_editable(GdictSource * source)909 gdict_source_is_editable (GdictSource *source)
910 {
911 g_return_val_if_fail (GDICT_IS_SOURCE (source), FALSE);
912
913 return source->priv->editable;
914 }
915
916 /**
917 * gdict_source_set_database:
918 * @source: a #GdictSource
919 * @database: (nullable): a UTF-8 encoded database name or %NULL
920 *
921 * Sets the default database of @source. If @database is %NULL, unsets the
922 * currently set database.
923 *
924 * Since: 1.0
925 */
926 void
gdict_source_set_database(GdictSource * source,const gchar * database)927 gdict_source_set_database (GdictSource *source,
928 const gchar *database)
929 {
930 g_return_if_fail (GDICT_IS_SOURCE (source));
931
932 g_free (source->priv->database);
933
934 if (!source->priv->keyfile)
935 source->priv->keyfile = g_key_file_new ();
936
937 if (database && database[0] != '\0')
938 {
939 source->priv->database = g_strdup (database);
940
941 g_key_file_set_string (source->priv->keyfile,
942 SOURCE_GROUP,
943 SOURCE_KEY_DATABASE,
944 database);
945 }
946 else
947 {
948 if (g_key_file_has_key (source->priv->keyfile,
949 SOURCE_GROUP,
950 SOURCE_KEY_DATABASE,
951 NULL))
952 g_key_file_remove_key (source->priv->keyfile,
953 SOURCE_GROUP,
954 SOURCE_KEY_DATABASE,
955 NULL);
956 }
957 }
958
959 /**
960 * gdict_source_get_database:
961 * @source: a #GdictSource
962 *
963 * Retrieves the default database of @source.
964 *
965 * Return value: the default strategy of a #GdictSource. The returned string
966 * is owned by the #GdictSource object, and should not be modified or freed.
967 *
968 * Since: 1.0
969 */
970 const gchar *
gdict_source_get_database(GdictSource * source)971 gdict_source_get_database (GdictSource *source)
972 {
973 g_return_val_if_fail (GDICT_IS_SOURCE (source), NULL);
974
975 return source->priv->database;
976 }
977
978 /**
979 * gdict_source_set_strategy:
980 * @source: a #GdictSource
981 * @strategy: (nullable): a UTF-8 encoded strategy or %NULL
982 *
983 * Sets the description of @source. If @strategy is %NULL, unsets the
984 * currently set strategy.
985 *
986 * Since: 1.0
987 */
988 void
gdict_source_set_strategy(GdictSource * source,const gchar * strategy)989 gdict_source_set_strategy (GdictSource *source,
990 const gchar *strategy)
991 {
992 g_return_if_fail (GDICT_IS_SOURCE (source));
993
994 g_free (source->priv->strategy);
995
996 if (!source->priv->keyfile)
997 source->priv->keyfile = g_key_file_new ();
998
999 if (strategy && strategy[0] != '\0')
1000 {
1001 source->priv->strategy = g_strdup (strategy);
1002
1003 g_key_file_set_string (source->priv->keyfile,
1004 SOURCE_GROUP,
1005 SOURCE_KEY_STRATEGY,
1006 strategy);
1007 }
1008 else
1009 {
1010 if (g_key_file_has_key (source->priv->keyfile,
1011 SOURCE_GROUP,
1012 SOURCE_KEY_STRATEGY,
1013 NULL))
1014 g_key_file_remove_key (source->priv->keyfile,
1015 SOURCE_GROUP,
1016 SOURCE_KEY_STRATEGY,
1017 NULL);
1018 }
1019 }
1020
1021 /**
1022 * gdict_source_get_strategy:
1023 * @source: a #GdictSource
1024 *
1025 * Retrieves the default strategy of @source.
1026 *
1027 * Return value: the default strategy of a #GdictSource. The returned string
1028 * is owned by the #GdictSource object, and should not be modified or freed.
1029 *
1030 * Since: 1.0
1031 */
1032 const gchar *
gdict_source_get_strategy(GdictSource * source)1033 gdict_source_get_strategy (GdictSource *source)
1034 {
1035 g_return_val_if_fail (GDICT_IS_SOURCE (source), NULL);
1036
1037 return source->priv->strategy;
1038 }
1039
1040 /**
1041 * gdict_source_set_transportv
1042 * @source: a #GdictSource
1043 * @transport: a #GdictSourceTransport
1044 * @first_transport_property: FIXME
1045 * @var_args: FIXME
1046 *
1047 * FIXME
1048 *
1049 * Since: 1.0
1050 */
1051 void
gdict_source_set_transportv(GdictSource * source,GdictSourceTransport transport,const gchar * first_transport_property,va_list var_args)1052 gdict_source_set_transportv (GdictSource *source,
1053 GdictSourceTransport transport,
1054 const gchar *first_transport_property,
1055 va_list var_args)
1056 {
1057 GdictSourcePrivate *priv;
1058
1059 g_return_if_fail (GDICT_IS_SOURCE (source));
1060 g_return_if_fail (IS_VALID_TRANSPORT (transport));
1061
1062 priv = source->priv;
1063
1064 priv->transport = transport;
1065
1066 if (priv->context)
1067 g_object_unref (priv->context);
1068
1069 switch (priv->transport)
1070 {
1071 case GDICT_SOURCE_TRANSPORT_DICTD:
1072 priv->context = gdict_client_context_new (NULL, -1);
1073 g_assert (GDICT_IS_CLIENT_CONTEXT (priv->context));
1074
1075 g_object_set_valist (G_OBJECT (priv->context),
1076 first_transport_property,
1077 var_args);
1078
1079 break;
1080 case GDICT_SOURCE_TRANSPORT_INVALID:
1081 default:
1082 g_assert_not_reached ();
1083 break;
1084 }
1085
1086 /* update the keyfile */
1087 if (!priv->keyfile)
1088 priv->keyfile = g_key_file_new ();
1089
1090 g_key_file_set_string (priv->keyfile,
1091 SOURCE_GROUP,
1092 SOURCE_KEY_TRANSPORT,
1093 valid_transports[transport]);
1094
1095 switch (priv->transport)
1096 {
1097 case GDICT_SOURCE_TRANSPORT_DICTD:
1098 g_key_file_set_string (priv->keyfile,
1099 SOURCE_GROUP,
1100 SOURCE_KEY_HOSTNAME,
1101 gdict_client_context_get_hostname (GDICT_CLIENT_CONTEXT (priv->context)));
1102 g_key_file_set_integer (priv->keyfile,
1103 SOURCE_GROUP,
1104 SOURCE_KEY_PORT,
1105 gdict_client_context_get_port (GDICT_CLIENT_CONTEXT (priv->context)));
1106 break;
1107 case GDICT_SOURCE_TRANSPORT_INVALID:
1108 default:
1109 g_assert_not_reached ();
1110 break;
1111 }
1112 }
1113
1114 /**
1115 * gdict_source_set_transport:
1116 * @source: a #GdictSource
1117 * @transport: a valid transport
1118 * @first_transport_property: property for the context bound to
1119 * the transport, or %NULL
1120 * @...: property value for first property name, then additionary
1121 * properties, ending with %NULL
1122 *
1123 * Sets @transport as the choosen transport for @source. The @transport
1124 * argument is a method of retrieving dictionary data from a source; it is
1125 * used to create the right #GdictContext for this #GdictSource. After
1126 * @transport, property name/value pairs should be listed, with a %NULL
1127 * pointer ending the list. Properties are the same passed to a #GdictContext
1128 * implementation instance using g_object_set().
1129 *
1130 * Here's a simple example:
1131 *
1132 * <informalexample><programlisting>
1133 * #include <gdict/gdict.h>
1134 * GdictSource *source = gdict_source_new ();
1135 *
1136 * gdict_source_set_name (source, "My Source");
1137 * gdict_source_set_transport (source, GDICT_SOURCE_TRANSPORT_DICTD,
1138 * "hostname", "dictionary-server.org",
1139 * "port", 2628,
1140 * NULL);
1141 * </programlisting></informalexample>
1142 *
1143 * Since: 1.0
1144 */
1145 void
gdict_source_set_transport(GdictSource * source,GdictSourceTransport transport,const gchar * first_transport_property,...)1146 gdict_source_set_transport (GdictSource *source,
1147 GdictSourceTransport transport,
1148 const gchar *first_transport_property,
1149 ...)
1150 {
1151 va_list args;
1152
1153 g_return_if_fail (GDICT_IS_SOURCE (source));
1154 g_return_if_fail (IS_VALID_TRANSPORT (transport));
1155
1156 va_start (args, first_transport_property);
1157
1158 gdict_source_set_transportv (source, transport,
1159 first_transport_property,
1160 args);
1161
1162 va_end (args);
1163 }
1164
1165 /**
1166 * gdict_source_get_transport:
1167 * @source: a #GdictSource
1168 *
1169 * FIXME
1170 *
1171 * Return value: FIXME
1172 *
1173 * Since: 1.0
1174 */
1175 GdictSourceTransport
gdict_source_get_transport(GdictSource * source)1176 gdict_source_get_transport (GdictSource *source)
1177 {
1178 g_return_val_if_fail (GDICT_IS_SOURCE (source), GDICT_SOURCE_TRANSPORT_INVALID);
1179
1180 return source->priv->transport;
1181 }
1182
1183 /**
1184 * gdict_source_get_context:
1185 * @source: a #GdictSource
1186 *
1187 * Gets the #GdictContext bound to @source.
1188 *
1189 * Return value: (transfer full): a #GdictContext for @source.
1190 * Use g_object_unref() when you don't need it anymore.
1191 *
1192 * Since: 1.0
1193 */
1194 GdictContext *
gdict_source_get_context(GdictSource * source)1195 gdict_source_get_context (GdictSource *source)
1196 {
1197 GdictContext *retval;
1198
1199 g_return_val_if_fail (GDICT_IS_SOURCE (source), NULL);
1200
1201 retval = gdict_source_create_context (source,
1202 source->priv->transport,
1203 NULL);
1204
1205 return retval;
1206 }
1207
1208 /**
1209 * gdict_source_peek_context:
1210 * @source: a #GdictSource
1211 *
1212 * Gets the #GdictContext bound to @source. The returned object is a
1213 * referenced copy of the context held by @source; if you want a different
1214 * instance, use gdict_source_get_context().
1215 *
1216 * Return value: (transfer full): a referenced #GdictContext.
1217 *
1218 * Since: 1.0
1219 */
1220 GdictContext *
gdict_source_peek_context(GdictSource * source)1221 gdict_source_peek_context (GdictSource *source)
1222 {
1223 g_return_val_if_fail (GDICT_IS_SOURCE (source), NULL);
1224
1225 if (!source->priv->context)
1226 source->priv->context = gdict_source_create_context (source,
1227 source->priv->transport,
1228 NULL);
1229 return g_object_ref (source->priv->context);
1230 }
1231