LCOV - code coverage report
Current view: top level - src/bindings/gsettings - elektrasettingsbackend.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 204 0.0 %
Date: 2019-09-12 12:28:41 Functions: 0 23 0.0 %

          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

Generated by: LCOV version 1.13