#include "e-book-backend-factory.h"
#include "e-data-book.h"
#include "e-data-book-factory.h"
+#include "e-dbus-localed.h"
#define d(x)
* The value is the watcher ID for g_bus_unwatch_name(). */
GHashTable *watched_names;
GMutex watched_names_lock;
+
+ /* Watching "org.freedesktop.locale1" for locale changes */
+ guint localed_watch_id;
+ EDBusLocale1 *localed_proxy;
+ GCancellable *localed_cancel;
+ gchar *locale;
};
enum {
data_book_factory_connections_remove (factory, sender, backend);
}
+/* This is totally backwards, for some insane reason we holding
+ * references to the EBookBackends and then fetching the EDataBook
+ * via e_book_backend_ref_data_book(), the whole scheme should
+ * be reversed and this function probably removed.
+ */
+static GList *
+data_book_factory_list_books (EDataBookFactory *factory)
+{
+ GList *books = NULL;
+ GHashTable *connections;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_mutex_lock (&factory->priv->connections_lock);
+
+ connections = factory->priv->connections;
+
+ g_hash_table_iter_init (&iter, connections);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ GPtrArray *array = (GPtrArray *)value;
+ gint i;
+
+ for (i = 0; i < array->len; i++) {
+ EBookBackend *backend = g_ptr_array_index (array, i);
+ EDataBook *book = e_book_backend_ref_data_book (backend);
+
+ if (g_list_find (books, book) == NULL)
+ books = g_list_prepend (books, book);
+ else
+ g_object_unref (book);
+ }
+ }
+ g_mutex_unlock (&factory->priv->connections_lock);
+
+ return books;
+}
+
static gchar *
data_book_factory_open (EDataBookFactory *factory,
GDBusConnection *connection,
G_CALLBACK (data_book_factory_closed_cb),
factory, 0);
+ /* Don't set the locale on a new book if we have not
+ * yet received a notification of a locale change
+ */
+ if (factory->priv->locale)
+ e_data_book_set_locale (data_book,
+ factory->priv->locale,
+ NULL, NULL);
} else {
g_free (object_path);
object_path = NULL;
priv->dbus_factory = NULL;
}
+ if (priv->localed_cancel) {
+ g_cancellable_cancel (priv->localed_cancel);
+ g_object_unref (priv->localed_cancel);
+ priv->localed_cancel = NULL;
+ }
+
+ if (priv->localed_proxy) {
+ g_object_unref (priv->localed_proxy);
+ priv->localed_proxy = NULL;
+ }
+
+ if (priv->localed_watch_id > 0)
+ g_bus_unwatch_name (priv->localed_watch_id);
+
g_hash_table_remove_all (priv->connections);
g_hash_table_remove_all (priv->watched_names);
g_hash_table_destroy (priv->watched_names);
g_mutex_clear (&priv->watched_names_lock);
+ g_free (priv->locale);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_data_book_factory_parent_class)->finalize (object);
}
quit_server (server, exit_code);
}
+static gchar *
+data_book_factory_interpret_locale_value (const gchar *value)
+{
+ gchar *interpreted_value = NULL;
+ gchar **split;
+
+ split = g_strsplit (value, "=", 2);
+
+ if (split && split[0] && split[1])
+ interpreted_value = g_strdup (split[1]);
+
+ g_strfreev (split);
+
+ if (!interpreted_value)
+ g_warning ("Failed to interpret locale value: %s", value);
+
+ return interpreted_value;
+}
+
+static gchar *
+data_book_factory_interpret_locale (const gchar * const * locale)
+{
+ gint i;
+ gchar *interpreted_locale = NULL;
+
+ /* Prioritize LC_COLLATE and then LANG values
+ * in the 'locale' specified by localed.
+ *
+ * If localed explicitly specifies no locale, then
+ * default to checking system locale.
+ */
+ if (locale) {
+ for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
+ if (strncmp (locale[i], "LC_COLLATE", 10) == 0)
+ interpreted_locale =
+ data_book_factory_interpret_locale_value (locale[i]);
+ }
+
+ for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
+ if (strncmp (locale[i], "LANG", 4) == 0)
+ interpreted_locale =
+ data_book_factory_interpret_locale_value (locale[i]);
+ }
+ }
+
+ if (!interpreted_locale) {
+ const gchar *system_locale = setlocale (LC_COLLATE, NULL);
+
+ interpreted_locale = g_strdup (system_locale);
+ }
+
+ return interpreted_locale;
+}
+
+static void
+data_book_factory_set_locale (EDataBookFactory *factory,
+ const gchar *locale)
+{
+ EDataBookFactoryPrivate *priv = factory->priv;
+ GError *error = NULL;
+ GList *books, *l;
+
+ if (g_strcmp0 (priv->locale, locale) != 0) {
+
+ g_free (priv->locale);
+ priv->locale = g_strdup (locale);
+
+ books = data_book_factory_list_books (factory);
+ for (l = books; l; l = l->next) {
+ EDataBook *book = l->data;
+
+ if (!e_data_book_set_locale (book, locale, NULL, &error)) {
+ g_warning ("Failed to set locale on addressbook: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+ }
+ g_list_free_full (books, g_object_unref);
+ }
+}
+
+static void
+data_book_factory_locale_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ EDBusLocale1 *locale_proxy = E_DBUS_LOCALE1 (object);
+ EDataBookFactory *factory = (EDataBookFactory *)user_data;
+ const gchar * const *locale;
+ gchar *interpreted_locale;
+
+ locale = e_dbus_locale1_get_locale (locale_proxy);
+ interpreted_locale = data_book_factory_interpret_locale (locale);
+
+ data_book_factory_set_locale (factory, interpreted_locale);
+
+ g_free (interpreted_locale);
+}
+
+static void
+data_book_factory_localed_ready (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EDataBookFactory *factory = (EDataBookFactory *)user_data;
+ GError *error = NULL;
+
+ factory->priv->localed_proxy = e_dbus_locale1_proxy_new_finish (res, &error);
+
+ if (factory->priv->localed_proxy == NULL) {
+ g_warning ("Error fetching localed proxy: %s", error->message);
+ g_error_free (error);
+ }
+
+ if (factory->priv->localed_cancel) {
+ g_object_unref (factory->priv->localed_cancel);
+ factory->priv->localed_cancel = NULL;
+ }
+
+ if (factory->priv->localed_proxy) {
+ g_signal_connect (factory->priv->localed_proxy, "notify::locale",
+ G_CALLBACK (data_book_factory_locale_changed), factory);
+
+ /* Initial refresh of the locale */
+ data_book_factory_locale_changed (G_OBJECT (factory->priv->localed_proxy), NULL, factory);
+ }
+}
+
+static void
+data_book_factory_localed_appeared (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ EDataBookFactory *factory = (EDataBookFactory *)user_data;
+
+ factory->priv->localed_cancel = g_cancellable_new ();
+
+ e_dbus_locale1_proxy_new (connection,
+ G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
+ "org.freedesktop.locale1",
+ "/org/freedesktop/locale1",
+ factory->priv->localed_cancel,
+ data_book_factory_localed_ready,
+ factory);
+}
+
+static void
+data_book_factory_localed_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ EDataBookFactory *factory = (EDataBookFactory *)user_data;
+
+ if (factory->priv->localed_cancel) {
+ g_cancellable_cancel (factory->priv->localed_cancel);
+ g_object_unref (factory->priv->localed_cancel);
+ factory->priv->localed_cancel = NULL;
+ }
+
+ if (factory->priv->localed_proxy) {
+ g_object_unref (factory->priv->localed_proxy);
+ factory->priv->localed_proxy = NULL;
+ }
+}
+
static gboolean
data_book_factory_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
EDataBookFactoryPrivate *priv;
+ GBusType bus_type = G_BUS_TYPE_SYSTEM;
priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (initable);
priv->registry = e_source_registry_new_sync (cancellable, error);
+ /* When running tests, we pretend to be the "org.freedesktop.locale1" service
+ * on the session bus instead of the real location on the system bus.
+ */
+ if (g_getenv ("EDS_TESTING") != NULL)
+ bus_type = G_BUS_TYPE_SESSION;
+
+ /* Watch system bus for locale change notifications */
+ priv->localed_watch_id =
+ g_bus_watch_name (bus_type,
+ "org.freedesktop.locale1",
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ data_book_factory_localed_appeared,
+ data_book_factory_localed_vanished,
+ initable,
+ NULL);
+
return (priv->registry != NULL);
}
#include "e-book-backend.h"
#include "e-book-backend-sexp.h"
#include "e-book-backend-factory.h"
-#include "e-dbus-localed.h"
#define E_DATA_BOOK_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
GMutex sender_lock;
GHashTable *sender_table;
-
- guint localed_watch_id;
- EDBusLocale1 *localed_proxy;
- GCancellable *localed_cancel;
};
struct _AsyncContext {
/* Disregard anything else. */
}
-static gchar *
-data_book_interpret_locale_value (const gchar *value)
-{
- gchar *interpreted_value = NULL;
- gchar **split;
-
- split = g_strsplit (value, "=", 2);
-
- if (split && split[0] && split[1])
- interpreted_value = g_strdup (split[1]);
-
- g_strfreev (split);
-
- if (!interpreted_value)
- g_warning ("Failed to interpret locale value: %s", value);
-
- return interpreted_value;
-}
-
-static gchar *
-data_book_interpret_locale (const gchar * const * locale)
-{
- gint i;
- gchar *interpreted_locale = NULL;
-
- /* Prioritize LC_COLLATE and then LANG values
- * in the 'locale' specified by localed.
- *
- * If localed explicitly specifies no locale, then
- * default to checking system locale.
- */
- if (locale) {
-
- for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
-
- if (strncmp (locale[i], "LC_COLLATE", 10) == 0)
- interpreted_locale = data_book_interpret_locale_value (locale[i]);
- }
-
- for (i = 0; locale[i] != NULL && interpreted_locale == NULL; i++) {
-
- if (strncmp (locale[i], "LANG", 4) == 0)
- interpreted_locale = data_book_interpret_locale_value (locale[i]);
- }
- }
-
- if (!interpreted_locale) {
- const gchar *system_locale = setlocale (LC_COLLATE, NULL);
-
- interpreted_locale = g_strdup (system_locale);
- }
-
- return interpreted_locale;
-}
-
-static void
-data_book_locale_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- EDBusLocale1 *locale_proxy = E_DBUS_LOCALE1 (object);
- EDataBook *book = (EDataBook *)user_data;
- EBookBackend *backend;
-
- backend = e_data_book_ref_backend (book);
-
- if (backend) {
- const gchar * const *locale;
- gchar *interpreted_locale;
-
- locale = e_dbus_locale1_get_locale (locale_proxy);
- interpreted_locale = data_book_interpret_locale (locale);
-
- /* XXX This needs work, the whole handling should be done
- * by the singleton EDataBookFactory, and handle errors well
- */
- e_book_backend_set_locale (backend, interpreted_locale, NULL, NULL);
-
- e_dbus_address_book_set_locale (book->priv->dbus_interface, interpreted_locale);
-
- g_free (interpreted_locale);
- }
-
- g_object_unref (backend);
-}
-
-static void
-data_book_localed_ready (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- EDataBook *book = (EDataBook *)user_data;
- GError *error = NULL;
-
- book->priv->localed_proxy = e_dbus_locale1_proxy_new_finish (res, &error);
-
- if (book->priv->localed_proxy == NULL) {
- g_warning ("Error fetching localed proxy: %s", error->message);
- g_error_free (error);
- }
-
- if (book->priv->localed_cancel) {
- g_object_unref (book->priv->localed_cancel);
- book->priv->localed_cancel = NULL;
- }
-
- if (book->priv->localed_proxy) {
- g_signal_connect (book->priv->localed_proxy, "notify::locale",
- G_CALLBACK (data_book_locale_changed), book);
-
- /* Initial refresh of the locale */
- data_book_locale_changed (G_OBJECT (book->priv->localed_proxy), NULL, book);
- }
-}
-
-static void
-data_book_localed_appeared (GDBusConnection *connection,
- const gchar *name,
- const gchar *name_owner,
- gpointer user_data)
-{
- EDataBook *book = (EDataBook *)user_data;
-
- book->priv->localed_cancel = g_cancellable_new ();
-
- e_dbus_locale1_proxy_new (connection,
- G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
- "org.freedesktop.locale1",
- "/org/freedesktop/locale1",
- book->priv->localed_cancel,
- data_book_localed_ready,
- book);
-}
-
-static void
-data_book_localed_vanished (GDBusConnection *connection,
- const gchar *name,
- gpointer user_data)
-{
- EDataBook *book = (EDataBook *)user_data;
-
- if (book->priv->localed_cancel) {
- g_cancellable_cancel (book->priv->localed_cancel);
- g_object_unref (book->priv->localed_cancel);
- book->priv->localed_cancel = NULL;
- }
-
- if (book->priv->localed_proxy) {
- g_object_unref (book->priv->localed_proxy);
- book->priv->localed_proxy = NULL;
- }
-}
-
static void
data_book_set_backend (EDataBook *book,
EBookBackend *backend)
priv->direct_module = NULL;
}
- if (priv->localed_cancel) {
- g_cancellable_cancel (priv->localed_cancel);
- g_object_unref (priv->localed_cancel);
- priv->localed_cancel = NULL;
- }
-
- if (priv->localed_proxy) {
- g_object_unref (priv->localed_proxy);
- priv->localed_proxy = NULL;
- }
-
g_hash_table_remove_all (priv->sender_table);
/* Chain up to parent's dispose() metnod. */
priv->dbus_interface = NULL;
}
- if (priv->localed_watch_id > 0)
- g_bus_unwatch_name (priv->localed_watch_id);
-
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (e_data_book_parent_class)->finalize (object);
}
EBookBackend *backend;
EDataBook *book;
gchar *locale;
- GBusType bus_type = G_BUS_TYPE_SYSTEM;
book = E_DATA_BOOK (initable);
e_dbus_address_book_set_locale (book->priv->dbus_interface, locale);
g_free (locale);
- /* When running tests, we pretend to be the "org.freedesktop.locale1" service
- * on the session bus instead of the real location on the system bus.
- */
- if (g_getenv ("EDS_TESTING") != NULL)
- bus_type = G_BUS_TYPE_SESSION;
-
- /* Watch system bus for locale change notifications */
- book->priv->localed_watch_id =
- g_bus_watch_name (bus_type,
- "org.freedesktop.locale1",
- G_BUS_NAME_WATCHER_FLAGS_NONE,
- data_book_localed_appeared,
- data_book_localed_vanished,
- book,
- NULL);
-
return g_dbus_interface_skeleton_export (
G_DBUS_INTERFACE_SKELETON (book->priv->dbus_interface),
book->priv->connection,
return book->priv->object_path;
}
+/**
+ * e_data_book_set_locale:
+ * @book: an #EDataBook
+ * @locale: the new locale to set for this book
+ * @cancellable: (allow-none): a #GCancellable
+ * @error: (allow-none): a location to store any error which might occur
+ *
+ * Set's the locale for this addressbook, this can result in renormalization of
+ * locale sensitive data.
+ *
+ * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
+ *
+ * Since: 3.12
+ */
+gboolean
+e_data_book_set_locale (EDataBook *book,
+ const gchar *locale,
+ GCancellable *cancellable,
+ GError **error)
+{
+ EBookBackend *backend;
+ gboolean success;
+
+ g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
+
+ backend = e_data_book_ref_backend (book);
+ success = e_book_backend_set_locale (backend,
+ locale,
+ cancellable,
+ error);
+
+ if (success)
+ e_dbus_address_book_set_locale (book->priv->dbus_interface, locale);
+
+ g_object_unref (backend);
+
+ return success;
+}