Line data Source code
1 : #define G_SETTINGS_ENABLE_BACKEND
2 : #include <gio/gio.h>
3 : #include <gio/gsettingsbackend.h>
4 : #include <glib.h>
5 :
6 : #include <elektra/gelektra-kdb.h>
7 : #include <elektra/gelektra-key.h>
8 : #include <elektra/gelektra-keyset.h>
9 :
10 : #undef G_LOG_DOMAIN
11 : #define G_LOG_DOMAIN "ElektraSettings"
12 :
13 : #define G_ELEKTRA_TEST_STRING "test"
14 :
15 : #ifndef G_ELEKTRA_SETTINGS_MODULE_PRIORITY
16 : #error "no gsetting priority selected"
17 : #endif
18 :
19 : #define G_ELEKTRA_SETTINGS_SYSTEM "system"
20 : #define G_ELEKTRA_SETTINGS_USER "user"
21 : #ifndef G_ELEKTRA_SETTINGS_PATH
22 : #define G_ELEKTRA_SETTINGS_PATH "/sw"
23 : #endif
24 :
25 :
26 : typedef GSettingsBackendClass ElektraSettingsBackendClass;
27 :
28 : typedef struct
29 : {
30 : GSettingsBackend backend;
31 : /*< private >*/
32 : GElektraKey * gkey;
33 : GElektraKdb * gkdb;
34 : GElektraKeySet * gks;
35 : GElektraKeySet * subscription_gks;
36 :
37 : GDBusConnection * dbus_connections[2];
38 : } ElektraSettingsBackend;
39 :
40 : /**
41 : * SECTION:elektrasettingsbackend
42 : * @title: ElektraSettingsBackend
43 : * @short_description: Implementation of the GSettingsBackend Interface with Elektra
44 : * @include: gio/elektrasettingsbackend.h
45 : * @see_also: #GSettingsBackend #GSettings, #GIOExtensionPoint
46 : *
47 : * Description of the GSettingsBackend:
48 : *
49 : * The #GSettingsBackend interface defines a generic interface for
50 : * non-strictly-typed data that is stored in a hierarchy. To implement
51 : * an alternative storage backend for #GSettings, you need to implement
52 : * the #GSettingsBackend interface and then make it implement the
53 : * extension point #G_SETTINGS_BACKEND_EXTENSION_POINT_NAME.
54 : *
55 : * The interface defines methods for reading and writing values, a
56 : * method for determining if writing of certain values will fail
57 : * (lockdown) and a change notification mechanism.
58 : *
59 : * The semantics of the interface are very precisely defined and
60 : * implementations must carefully adhere to the expectations of
61 : * callers that are documented on each of the interface methods.
62 : *
63 : * Some of the GSettingsBackend functions accept or return a #GTree.
64 : * These trees always have strings as keys and #GVariant as values.
65 : * g_settings_backend_create_tree() is a convenience function to create
66 : * suitable trees.
67 : *
68 : * The GSettingsBackend API is exported to allow third-party
69 : * implementations, but does not carry the same stability guarantees
70 : * as the public GIO API. For this reason, you have to define the
71 : * C preprocessor symbol %G_SETTINGS_ENABLE_BACKEND before including
72 : * `gio/gsettingsbackend.h`.
73 : **/
74 :
75 : static GType elektra_settings_backend_get_type (void);
76 0 : G_DEFINE_TYPE (ElektraSettingsBackend, elektra_settings_backend, G_TYPE_SETTINGS_BACKEND)
77 :
78 0 : static GVariant * elektra_settings_read_string (GSettingsBackend * backend, gchar * keypathname, const GVariantType * expected_type)
79 : {
80 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
81 0 : gelektra_kdb_get (esb->gkdb, esb->gks, esb->gkey);
82 : /* Lookup the requested key */
83 0 : GElektraKey * gkey = gelektra_keyset_lookup_byname (esb->gks, keypathname, GELEKTRA_KDB_O_NONE);
84 : /* free the passed path string */
85 0 : g_free (keypathname);
86 0 : if (gkey == NULL)
87 : {
88 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Key with path could not be found in Elekras kdb");
89 0 : return NULL;
90 : }
91 : else
92 : {
93 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s ", "Key found");
94 : GVariant * read_gvariant;
95 0 : GError * err = NULL;
96 0 : gchar * string_value = g_malloc (gelektra_key_getvaluesize (gkey));
97 0 : if (gelektra_key_getstring (gkey, string_value, gelektra_key_getvaluesize (gkey)) == -1)
98 : {
99 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s!", "but we could not read the string from Elektra kdb");
100 0 : return NULL;
101 : }
102 : /* now parse it with the expected type from GSettings */
103 0 : read_gvariant = g_variant_parse (expected_type, string_value, NULL, NULL, &err);
104 0 : if (err != NULL)
105 : {
106 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s!", "but GVariant error on parsing string value:", err->message);
107 0 : g_error_free (err);
108 0 : return NULL;
109 : }
110 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s.", "and GVariant parsed value is:", string_value);
111 0 : return read_gvariant;
112 : }
113 : }
114 :
115 0 : static gboolean elektra_settings_write_string (GSettingsBackend * backend, const gchar * key, gchar * keypathname, GVariant * value,
116 : gpointer origin_tag)
117 : {
118 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
119 : /* Lookup if key already exists */
120 0 : GElektraKey * gkey = gelektra_keyset_lookup_byname (esb->gks, keypathname, GELEKTRA_KDB_O_NONE);
121 0 : gchar * string_value = (value != NULL ? g_variant_print ((GVariant *) value, FALSE) : NULL);
122 0 : if (gkey == NULL)
123 : {
124 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s %s.", "Key not found, creating new key:", keypathname, string_value);
125 0 : gkey = gelektra_key_new (keypathname, KEY_VALUE, string_value, KEY_END);
126 0 : g_free (keypathname);
127 0 : if (gkey == NULL)
128 : {
129 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Error douring key creation");
130 0 : return FALSE;
131 : }
132 0 : if (gelektra_keyset_append (esb->gks, gkey) == -1)
133 : {
134 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Could not append the new key!");
135 : }
136 : }
137 : else
138 : {
139 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s %s %s.", "Found key:", keypathname, "and set value to", string_value);
140 0 : g_free (keypathname);
141 0 : gelektra_key_setstring (gkey, string_value);
142 : }
143 : // Notify GSettings that the key has changed
144 0 : g_settings_backend_changed (backend, key, origin_tag);
145 0 : return TRUE;
146 : }
147 :
148 : /* elektra_settings_backend_read implements g_settings_backend_read:
149 : * @backend: a #GSettingsBackend implementation
150 : * @key: the key to read
151 : * @expected_type: a #GVariantType
152 : * @default_value: if the default value should be returned
153 : *
154 : * Reads a key. This call will never block.
155 : *
156 : * If the key exists, the value associated with it will be returned.
157 : * If the key does not exist, %NULL will be returned.
158 : *
159 : * The returned value will be of the type given in @expected_type. If
160 : * the backend stored a value of a different type then %NULL will be
161 : * returned.
162 : *
163 : * If @default_value is %TRUE then this gets the default value from the
164 : * backend (ie: the one that the backend would contain if
165 : * g_settings_reset() were called).
166 : *
167 : * Returns: the value that was read, or %NULL
168 : */
169 0 : static GVariant * elektra_settings_backend_read (GSettingsBackend * backend, const gchar * key, const GVariantType * expected_type,
170 : gboolean default_value)
171 : {
172 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s %s %.*s %s %s%s", "function read:", key,
173 0 : "expected_type is:", (int) (g_variant_type_get_string_length (expected_type) & INT_MAX),
174 : g_variant_type_peek_string (expected_type), "and we", (default_value ? "" : "do not "), "want the default_value");
175 0 : if (default_value)
176 : {
177 0 : return elektra_settings_read_string (backend, g_strconcat (G_ELEKTRA_SETTINGS_SYSTEM, G_ELEKTRA_SETTINGS_PATH, key, NULL),
178 : expected_type);
179 : }
180 : else
181 : {
182 0 : return elektra_settings_read_string (backend, g_strconcat (G_ELEKTRA_SETTINGS_PATH, key, NULL), expected_type);
183 : }
184 : }
185 :
186 : /* elektra_settings_backend_read_user_value implements g_settings_backend_read_user_value:
187 : * @backend: a #GSettingsBackend implementation
188 : * @key: the key to read
189 : * @expected_type: a #GVariantType
190 : *
191 : * Reads the 'user value' of a key.
192 : *
193 : * This is the value of the key that the user has control over and has
194 : * set for themselves. Put another way: if the user did not set the
195 : * value for themselves, then this will return %NULL (even if the
196 : * sysadmin has provided a default value).
197 : *
198 : * Returns: the value that was read, or %NULL
199 : */
200 0 : static GVariant * elektra_settings_backend_read_user_value (GSettingsBackend * backend, const gchar * key,
201 : const GVariantType * expected_type)
202 : {
203 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s. %s %s.", "Function read_user_value:", key,
204 : "Expected_type is:", g_variant_type_peek_string (expected_type));
205 0 : return elektra_settings_read_string (backend, g_strconcat (G_ELEKTRA_SETTINGS_USER, G_ELEKTRA_SETTINGS_PATH, key, NULL),
206 : expected_type);
207 : }
208 :
209 : /* elektra_settings_backend_write implements g_settings_backend_write:
210 : * @backend: a #GSettingsBackend implementation
211 : * @key: the name of the key
212 : * @value: a #GVariant value to write to this key
213 : * @origin_tag: the origin tag
214 : *
215 : * Writes exactly one key.
216 : *
217 : * This call does not fail. During this call a
218 : * #GSettingsBackend::changed signal will be emitted if the value of the
219 : * key has changed. The updated key value will be visible to any signal
220 : * callbacks.
221 : *
222 : * One possible method that an implementation might deal with failures is
223 : * to emit a second "changed" signal (either during this call, or later)
224 : * to indicate that the affected keys have suddenly "changed back" to their
225 : * old values.
226 : *
227 : * Returns: %TRUE if the write succeeded, %FALSE if the key was not writable
228 : */
229 0 : static gboolean elektra_settings_backend_write (GSettingsBackend * backend, const gchar * key, GVariant * value, gpointer origin_tag)
230 : {
231 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s %s %s", "Function write_key: ", key, "value is:", g_variant_print (value, TRUE));
232 0 : return elektra_settings_write_string (backend, key, g_strconcat (G_ELEKTRA_SETTINGS_USER, G_ELEKTRA_SETTINGS_PATH, key, NULL),
233 : value, origin_tag);
234 : }
235 :
236 : /* < private >
237 : * elektra_settings_keyset_from_tree:
238 : * @key: path of the GSettings key
239 : * @value: GVariant value of the key
240 : * @data: GElektraKeySet to append/write the key
241 : *
242 : * Writes one or more keys from a GSettings GTree to a GElektraKeySet
243 : *
244 : * A GSettings GTree consists of GSetting paths as keys and GVariants as values.
245 : *
246 : * Each key is looked up and created if needed.
247 : */
248 0 : static gint elektra_settings_keyset_from_tree (gpointer key, gpointer value, gpointer data)
249 : {
250 0 : gchar * fullpathname = g_strconcat (G_ELEKTRA_SETTINGS_PATH, (gchar *) (key), NULL);
251 0 : gchar * string_value = (value != NULL ? g_variant_print ((GVariant *) value, FALSE) : NULL);
252 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s: %s.", "Append to keyset ", fullpathname, string_value);
253 0 : GElektraKeySet * gks = (GElektraKeySet *) data;
254 0 : GElektraKey * gkey = gelektra_keyset_lookup_byname (gks, fullpathname, GELEKTRA_KDB_O_NONE);
255 0 : if (gkey == NULL)
256 : {
257 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Key is new, need to create it");
258 0 : gkey = gelektra_key_new (fullpathname, KEY_VALUE, string_value, KEY_END);
259 0 : if (gkey == NULL)
260 : {
261 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Error douring key creation");
262 0 : return FALSE;
263 : }
264 0 : if (gelektra_keyset_append (gks, gkey) == -1)
265 : {
266 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Could not append the new key!");
267 0 : return FALSE;
268 : }
269 : }
270 : else
271 : {
272 0 : gelektra_key_setstring (gkey, string_value);
273 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Key was found and new value set");
274 : }
275 : return FALSE;
276 : }
277 :
278 : /* elektra_settings_backend_write_tree implements g_settings_backend_write_tree:
279 : * @backend: a #GSettingsBackend implementation
280 : * @tree: a #GTree containing key-value pairs to write
281 : * @origin_tag: the origin tag
282 : *
283 : * Writes one or more keys. This call will never block.
284 : *
285 : * The key of each item in the tree is the key name to write to and the
286 : * value is a #GVariant to write. The proper type of #GTree for this
287 : * call can be created with g_settings_backend_create_tree(). This call
288 : * might take a reference to the tree; you must not modified the #GTree
289 : * after passing it to this call.
290 : *
291 : * This call does not fail. During this call a #GSettingsBackend::changed
292 : * signal will be emitted if any keys have been changed. The new values of
293 : * all updated keys will be visible to any signal callbacks.
294 : *
295 : * One possible method that an implementation might deal with failures is
296 : * to emit a second "changed" signal (either during this call, or later)
297 : * to indicate that the affected keys have suddenly "changed back" to their
298 : * old values.
299 : */
300 0 : static gboolean elektra_settings_backend_write_tree (GSettingsBackend * backend, GTree * tree, gpointer origin_tag)
301 : {
302 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
303 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s.", "Function writeTree. ", "We have to loop the tree and add the keys");
304 0 : g_tree_foreach (tree, elektra_settings_keyset_from_tree, esb->gks);
305 : /* Notify the GSettings about the changed tree */
306 0 : g_settings_backend_changed_tree (backend, tree, origin_tag);
307 0 : return TRUE;
308 : }
309 :
310 : /* elektra_settings_backend_reset implements g_settings_backend_reset:
311 : * @backend: a #GSettingsBackend implementation
312 : * @key: the name of a key
313 : * @origin_tag: the origin tag
314 : *
315 : * "Resets" the named key to its "default" value (ie: after system-wide
316 : * defaults, mandatory keys, etc. have been taken into account) or possibly
317 : * unsets it.
318 : */
319 0 : static void elektra_settings_backend_reset (GSettingsBackend * backend, const gchar * key, gpointer origin_tag)
320 : {
321 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s.", "Function reset:", key);
322 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
323 0 : gchar * keypathname = g_strconcat (G_ELEKTRA_SETTINGS_USER, G_ELEKTRA_SETTINGS_PATH, key, NULL);
324 0 : GElektraKey * gkey = gelektra_keyset_lookup_byname (esb->gks, keypathname, GELEKTRA_KDB_O_NONE);
325 0 : g_free (keypathname);
326 0 : if (gkey != NULL)
327 : {
328 0 : gelektra_keyset_lookup (esb->gks, gkey, KDB_O_POP);
329 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Key not found and reseted");
330 0 : g_settings_backend_changed (backend, key, origin_tag);
331 : }
332 : else
333 : {
334 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Key not found, nothing to be done");
335 : }
336 0 : }
337 :
338 : /* elektra_settings_backend_get_writable implements g_settings_backend_get_writable:
339 : * @backend: a #GSettingsBackend implementation
340 : * @key: the name of a key
341 : *
342 : * Finds out if a key is available for writing to. This is the
343 : * interface through which 'lockdown' is implemented. Locked down
344 : * keys will have %FALSE returned by this call.
345 : *
346 : * You should not write to locked-down keys, but if you do, the
347 : * implementation will deal with it.
348 : *
349 : * Returns: %TRUE if the key is writable
350 : */
351 : // NOTE elektra does not have a clear definition of what is writable or not
352 0 : static gboolean elektra_settings_backend_get_writable (GSettingsBackend * backend, const gchar * name)
353 : {
354 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s.", "Function get_writable:", name);
355 :
356 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
357 0 : gchar * pathToWrite = g_strconcat (G_ELEKTRA_SETTINGS_USER, G_ELEKTRA_SETTINGS_PATH, name, NULL);
358 0 : GElektraKey * gkey = gelektra_keyset_lookup_byname (esb->gks, pathToWrite, GELEKTRA_KDB_O_NONE);
359 : // TODO answer why inside the if block
360 0 : if (gkey == NULL) gkey = gelektra_key_new (pathToWrite, KEY_VALUE, G_ELEKTRA_TEST_STRING, KEY_END);
361 0 : g_free (pathToWrite);
362 0 : if (gkey == NULL) return FALSE;
363 0 : return TRUE;
364 : }
365 :
366 :
367 0 : static void elektra_settings_key_changed (GDBusConnection * connection G_GNUC_UNUSED, const gchar * sender_name G_GNUC_UNUSED,
368 : const gchar * object_path G_GNUC_UNUSED, const gchar * interface_name G_GNUC_UNUSED,
369 : const gchar * signal_name G_GNUC_UNUSED, GVariant * parameters, gpointer user_data)
370 : {
371 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s.", "dbus signal that key has changed", g_variant_print (parameters, FALSE));
372 0 : GVariant * variant = g_variant_get_child_value (parameters, 0);
373 0 : gchar const * keypathname = g_variant_get_string (variant, NULL);
374 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) user_data;
375 0 : GElektraKeySet * ks = gelektra_keyset_dup (esb->subscription_gks);
376 0 : gelektra_keyset_rewind (ks);
377 0 : GElektraKey * key = gelektra_key_new (keypathname, KEY_VALUE, "", KEY_END);
378 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s!",
379 0 : "GSEttings Path: ", (g_strstr_len (g_strstr_len (keypathname, -1, "/") + 1, -1, "/")));
380 0 : gelektra_keyset_next (ks);
381 : do
382 : {
383 0 : if (gelektra_key_isbeloworsame (key, gelektra_keyset_current (ks)))
384 : {
385 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s!", "Subscribed key changed");
386 0 : gchar * gsettingskeyname = g_strdup (g_strstr_len (g_strstr_len (keypathname, -1, "/") + 1, -1, "/"));
387 0 : g_settings_backend_changed (user_data, gsettingskeyname, NULL);
388 0 : g_free (gsettingskeyname);
389 : }
390 0 : } while (gelektra_keyset_next (ks) != NULL);
391 0 : g_variant_unref (variant);
392 0 : }
393 :
394 0 : static void elektra_settings_bus_connected (GObject * source_object G_GNUC_UNUSED, GAsyncResult * res, gpointer user_data)
395 : {
396 0 : GError * err = NULL;
397 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) user_data;
398 0 : GDBusConnection * connection = g_bus_get_finish (res, &err);
399 0 : if (esb->dbus_connections[0] == NULL)
400 : {
401 0 : esb->dbus_connections[0] = connection;
402 : }
403 0 : else if (esb->dbus_connections[1] == NULL)
404 : {
405 0 : esb->dbus_connections[1] = connection;
406 : }
407 : else
408 0 : return;
409 0 : if (err != NULL)
410 : {
411 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s!", "Error on connectin to dbus:", err->message);
412 0 : return;
413 : }
414 0 : g_dbus_connection_signal_subscribe (connection, NULL, "org.libelektra", NULL, "/org/libelektra/configuration", NULL,
415 : G_DBUS_SIGNAL_FLAGS_NONE, elektra_settings_key_changed, user_data, NULL);
416 : }
417 :
418 0 : static void elektra_settings_check_bus_connection (ElektraSettingsBackend * backend)
419 : {
420 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
421 0 : GCancellable * g_cancellable = g_cancellable_new ();
422 0 : if (esb->dbus_connections[0] == NULL)
423 : {
424 0 : g_bus_get (G_BUS_TYPE_SESSION, g_cancellable, elektra_settings_bus_connected, backend);
425 : }
426 0 : if (esb->dbus_connections[1] == NULL)
427 : {
428 0 : g_bus_get (G_BUS_TYPE_SYSTEM, g_cancellable, elektra_settings_bus_connected, backend);
429 : }
430 0 : }
431 :
432 : /* elektra_settings_backend_subscribe implements g_settings_backend_subscribe:
433 : * @backend: a #GSettingsBackend
434 : * @name: a key or path to subscribe to
435 : *
436 : * Requests that change signals be emitted for events on @name.
437 : */
438 0 : static void elektra_settings_backend_subscribe (GSettingsBackend * backend, const gchar * name)
439 : {
440 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s.", "Subscribe to:", name);
441 0 : gchar * pathToSubscribe = g_strconcat (G_ELEKTRA_SETTINGS_PATH, name, NULL);
442 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
443 0 : GElektraKey * gkey = gelektra_keyset_lookup_byname (esb->subscription_gks, pathToSubscribe, GELEKTRA_KDB_O_NONE);
444 0 : if (gkey != NULL)
445 : {
446 0 : (*(guint *) gelektra_key_getvalue (gkey))++;
447 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s", "Key is already subscribed, adding to subscription");
448 0 : return;
449 : }
450 0 : guint counter = 1;
451 0 : gkey = gelektra_key_new (pathToSubscribe, KEY_BINARY, KEY_SIZE, sizeof (guint), // now the size is important
452 : KEY_VALUE, &counter, // sets the binary value ("some")
453 : KEY_END);
454 0 : g_free (pathToSubscribe);
455 0 : if (gelektra_keyset_append (esb->subscription_gks, gkey) == -1)
456 : {
457 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Could not append the key to subscription keyset!");
458 0 : return;
459 : }
460 : }
461 :
462 : /* elektra_settings_backend_unsubscribe implements g_settings_backend_unsubscribe:
463 : * @backend: a #GSettingsBackend
464 : * @name: a key or path to subscribe to
465 : *
466 : * Reverses the effect of a previous call to
467 : * g_settings_backend_subscribe().
468 : */
469 0 : static void elektra_settings_backend_unsubscribe (GSettingsBackend * backend, const gchar * name)
470 : {
471 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s %s.", "Unsubscribe:", name);
472 0 : gchar * pathToUnsubscribe = g_strconcat (G_ELEKTRA_SETTINGS_PATH, name, NULL);
473 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
474 0 : GElektraKey * gkey = gelektra_keyset_lookup_byname (esb->subscription_gks, pathToUnsubscribe, GELEKTRA_KDB_O_NONE);
475 : // TODO CHECK VALUE BEFORE working with it
476 0 : if (gkey != NULL)
477 : {
478 0 : guint * counter = (guint *) gelektra_key_getvalue (gkey);
479 0 : (*counter)--;
480 0 : if (*counter == 0)
481 : {
482 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s", "Subscription found deleting");
483 0 : gelektra_keyset_lookup (esb->subscription_gks, gkey, KDB_O_POP);
484 : }
485 : return;
486 : }
487 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s", "Subscription not found");
488 0 : return;
489 : }
490 :
491 : /* elektra_settings_backend_sync implements g_settings_backend_sync:
492 : * @backend: a #GSettingsBackend
493 : *
494 : * Write and read changes.
495 : */
496 0 : static void elektra_settings_backend_sync (GSettingsBackend * backend)
497 : {
498 : // TODO conflict management
499 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) backend;
500 0 : if (gelektra_kdb_set (esb->gkdb, esb->gks, esb->gkey) == -1 || gelektra_kdb_get (esb->gkdb, esb->gks, esb->gkey) == -1)
501 : {
502 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s\n", "Error on sync!");
503 0 : return;
504 : }
505 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s\n", "Sync state");
506 : }
507 :
508 : /*
509 : * Open elektra on empty level, as we asume that any application using GSettings is
510 : * an application and GSettings itself does not offer any such distinction. In addition
511 : * we don't know the application path in advance.
512 : */
513 0 : static void elektra_settings_backend_init (ElektraSettingsBackend * esb)
514 : {
515 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Init new ElektraSettingsBackend");
516 0 : esb->gkey = gelektra_key_new ("", KEY_CASCADING_NAME, KEY_END);
517 0 : esb->gkdb = gelektra_kdb_open (esb->gkey);
518 0 : esb->gks = gelektra_keyset_new (0, GELEKTRA_KEYSET_END);
519 0 : esb->subscription_gks = gelektra_keyset_new (0, GELEKTRA_KEYSET_END);
520 0 : gelektra_kdb_get (esb->gkdb, esb->gks, esb->gkey);
521 0 : elektra_settings_check_bus_connection (esb);
522 0 : }
523 :
524 : /*
525 : * Cleanup
526 : */
527 0 : static void elektra_settings_backend_finalize (GObject * object)
528 : {
529 0 : g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s.", "Finalize ElektraSettingsBackend");
530 0 : ElektraSettingsBackend * esb = (ElektraSettingsBackend *) object;
531 0 : GElektraKey * errorkey = gelektra_key_new (0);
532 0 : gelektra_kdb_close (esb->gkdb, errorkey);
533 : // TODO error handling
534 0 : G_OBJECT_CLASS (elektra_settings_backend_parent_class)->finalize (object);
535 0 : }
536 :
537 0 : static void elektra_settings_backend_class_init (GSettingsBackendClass * class)
538 : {
539 0 : GObjectClass * object_class = G_OBJECT_CLASS (class);
540 :
541 0 : object_class->finalize = elektra_settings_backend_finalize;
542 :
543 0 : class->read = elektra_settings_backend_read;
544 0 : class->read_user_value = elektra_settings_backend_read_user_value;
545 0 : class->write = elektra_settings_backend_write;
546 0 : class->write_tree = elektra_settings_backend_write_tree;
547 0 : class->reset = elektra_settings_backend_reset;
548 0 : class->get_writable = elektra_settings_backend_get_writable;
549 0 : class->subscribe = elektra_settings_backend_subscribe;
550 0 : class->unsubscribe = elektra_settings_backend_unsubscribe;
551 0 : class->sync = elektra_settings_backend_sync;
552 0 : }
553 :
554 : // TODO check if this is changeable at runtime
555 : void g_io_module_load (GIOModule * module)
556 : {
557 0 : g_type_module_use (G_TYPE_MODULE (module));
558 0 : g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME, elektra_settings_backend_get_type (), "elektra",
559 : G_ELEKTRA_SETTINGS_MODULE_PRIORITY);
560 0 : }
561 :
562 : void g_io_module_unload (GIOModule * module G_GNUC_UNUSED)
563 : {
564 0 : g_assert_not_reached ();
565 : }
566 :
567 : gchar ** g_io_module_query (void)
568 : {
569 0 : return g_strsplit (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME, "!", 0);
570 : }
571 :
572 : #undef G_LOG_DOMAIN
|