static void
hash_destroy_entries_func(gpointer key, gpointer value, gpointer user_data)
{
  MateConfEntry* entry;

  entry = value;

  mateconf_entry_free(entry);
}
MateConfSchema *
mateconf_client_get_schema_for_key (MateConfClient *client, const char *key)
{
	MateConfEntry *entry;
	const char *schema_name;
	MateConfSchema *schema = NULL;

	entry = mateconf_client_get_entry (client, key, NULL, TRUE, NULL);
	schema_name = mateconf_entry_get_schema_name (entry);

	if (schema_name == NULL)
		goto out;

	schema = mateconf_client_get_schema (client, schema_name, NULL);

out:
	if (entry)
		mateconf_entry_free (entry);

	return schema;
}
static void
recursive_unset_helper (MateConfSources   *sources,
                        const char     *key,
                        const char     *locale,
                        MateConfUnsetFlags flags,
                        GSList        **notifies,
                        GError        **first_error)
{
  GError* err = NULL;
  GSList* subdirs;
  GSList* entries;
  GSList* tmp;
  const char *locales[2] = { NULL, NULL };
  MateConfSources* modified_sources;
  MateConfSources** modifiedp = NULL;

  if (notifies)
    {
      modified_sources = NULL;
      modifiedp = &modified_sources;
    }
  
  err = NULL;
  
  subdirs = mateconf_sources_all_dirs (sources, key, &err);
          
  if (subdirs != NULL)
    {
      tmp = subdirs;

      while (tmp != NULL)
        {
          char *s = tmp->data;
          char *full = mateconf_concat_dir_and_key (key, s);
          
          recursive_unset_helper (sources, full, locale, flags,
                                  notifies, first_error);
          
          g_free (s);
          g_free (full);

          tmp = g_slist_next (tmp);
        }

      g_slist_free (subdirs);
    }
  else
    {
      if (err != NULL)
        {
          mateconf_log (GCL_DEBUG, "Error listing subdirs of '%s': %s\n",
                     key, err->message);
          if (*first_error)
            g_error_free (err);
          else
            *first_error = err;
          err = NULL;
        }
    }

  locales[0] = locale;
  entries = mateconf_sources_all_entries (sources, key,
                                       locale ? locales : NULL,
                                       &err);
          
  if (err != NULL)
    {
      mateconf_log (GCL_DEBUG, "Failure listing entries in '%s': %s\n",
                 key, err->message);
      if (*first_error)
        g_error_free (err);
      else
        *first_error = err;
      err = NULL;
    }

  if (entries != NULL)
    {
      tmp = entries;

      while (tmp != NULL)
        {
          MateConfEntry* entry = tmp->data;
          char *full, *freeme;

	  full = freeme = mateconf_concat_dir_and_key (key,
						    mateconf_entry_get_key (entry));
          
          
          mateconf_sources_unset_value (sources, full, locale, modifiedp, &err);
          if (notifies)
	    {
	      *notifies = prepend_unset_notify (*notifies, modified_sources, full);
	      modified_sources = NULL;
	      freeme = NULL;
	    }

          if (err != NULL)
            {
              mateconf_log (GCL_DEBUG, "Error unsetting '%s': %s\n",
                         full, err->message);

              if (*first_error)
                g_error_free (err);
              else
                *first_error = err;
              err = NULL;
            }

          if (flags & MATECONF_UNSET_INCLUDING_SCHEMA_NAMES)
            {
              mateconf_sources_set_schema (sources,
                                        full, NULL,
                                        &err);
              if (err != NULL)
                {
                  mateconf_log (GCL_DEBUG, "Error unsetting schema on '%s': %s\n",
                             full, err->message);
                  
                  if (*first_error)
                    g_error_free (err);
                  else
                    *first_error = err;
                  err = NULL;
                }
            }
          
          mateconf_entry_free (entry);
          g_free (freeme);
          
          tmp = g_slist_next (tmp);
        }

      g_slist_free (entries);
    }

  mateconf_sources_unset_value (sources, key, locale, modifiedp, &err);
  if (notifies)
    {
      *notifies = prepend_unset_notify (*notifies,
					modified_sources,
					g_strdup (key));
      modified_sources = NULL;
    }
  
  if (err != NULL)
    {
      mateconf_log (GCL_DEBUG, "Error unsetting '%s': %s\n",
                 key, err->message);

      if (*first_error)
        g_error_free (err);
      else
        *first_error = err;
      err = NULL;
    }
}
GSList*       
mateconf_sources_all_entries   (MateConfSources* sources,
                             const gchar* dir,
                             const gchar** locales,
                             GError** err)
{
  GList* tmp;
  GHashTable* hash;
  GSList* flattened;
  gboolean first_pass = TRUE; /* as an optimization, don't bother
                                 doing hash lookups on first source
                              */
  struct DefaultsLookupData dld = { NULL, NULL };
  
  dld.sources = sources;
  dld.locales = locales;

  /* Empty MateConfSources, skip it */
  if (sources->sources == NULL)
    return NULL;

  hash = g_hash_table_new(g_str_hash, g_str_equal);

  tmp = sources->sources;

  while (tmp != NULL)
    {
      MateConfSource* src;
      GSList* pairs;
      GSList* iter;
      GError* error = NULL;
      
      src   = tmp->data;
      pairs = mateconf_source_all_entries(src, dir, locales, &error);
      iter  = pairs;
      
      /* On error, set error and bail */
      if (error != NULL)
        {
          g_hash_table_foreach(hash, hash_destroy_entries_func, NULL);
          
          g_hash_table_destroy(hash);
          
          if (err)
            {
              g_return_val_if_fail(*err == NULL, NULL);
              *err = error;
              return NULL;
            }
          else
            {
              g_error_free(error);
              return NULL;
            }
        }

      /* Iterate over the list of entries, stuffing them in the hash
         and setting their writability flag if they're new
      */
      
      while (iter != NULL)
        {
          MateConfEntry* pair = iter->data;
          MateConfEntry* previous;
          gchar *full;
          
          if (first_pass)
            previous = NULL; /* Can't possibly be there. */
          else
            previous = g_hash_table_lookup(hash, pair->key);
          
          if (previous != NULL)
            {
              if (mateconf_entry_get_value (previous) != NULL)
                /* Discard this latest one */
                ;
              else
                {
                  /* Save the new value, previously we had an entry but no value */
                  mateconf_entry_set_value_nocopy (previous,
                                                mateconf_entry_steal_value(pair));

                  /* As an efficiency hack, remember that
                   * entry->key is relative not absolute on the
                   * mateconfd side
                   */
                  full = mateconf_concat_dir_and_key (dir, previous->key);

                  mateconf_entry_set_is_writable (previous,
                                               key_is_writable (sources,
                                                                src,
                                                                full,
                                                                NULL));

                  g_free (full);
                }
              
              if (mateconf_entry_get_schema_name (previous) != NULL)
                /* Discard this latest one */
                ;
              else
                {
                  /* Save the new schema name, previously we had an entry but no schema name*/
                  if (mateconf_entry_get_schema_name (pair) != NULL)
                    {
                      mateconf_entry_set_schema_name (previous,
                                                   mateconf_entry_get_schema_name (pair));
                    }
                }

              mateconf_entry_free(pair);
            }
          else
            {
              /* Save */
              g_hash_table_insert(hash, pair->key, pair);
              
              /* As an efficiency hack, remember that
               * entry->key is relative not absolute on the
               * mateconfd side
               */
              full = mateconf_concat_dir_and_key (dir, pair->key);

              mateconf_entry_set_is_writable (pair,
                                           key_is_writable (sources,
                                                            src,
                                                            full,
                                                            NULL));
              
              g_free (full);
            }

          iter = g_slist_next(iter);
        }
      
      /* All pairs are either stored or destroyed. */
      g_slist_free(pairs);

      first_pass = FALSE;

      tmp = g_list_next(tmp);
    }

  flattened = NULL;

  g_hash_table_foreach(hash, hash_lookup_defaults_func, &dld);
  
  g_hash_table_foreach(hash, hash_listify_func, &flattened);

  g_hash_table_destroy(hash);
  
  return flattened;
}