/* * Syncdaemon API * * Authors: Rodrigo Moya * * Copyright 2010 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * */ #include "config.h" #include #ifdef HAVE_GDBUS #include #else #include #include #endif #include "syncdaemon-daemon.h" #include "syncdaemon-config-interface.h" #include "syncdaemon-events-interface.h" #include "syncdaemon-filesystem-interface.h" #include "syncdaemon-folders-interface.h" #include "syncdaemon-publicfiles-interface.h" #include "syncdaemon-shares-interface.h" #include "syncdaemon-status-interface.h" #include "syncdaemon-marshal.h" #define SYNCDAEMON_DBUS_NAME "com.ubuntuone.SyncDaemon" G_DEFINE_TYPE(SyncdaemonDaemon, syncdaemon_daemon, G_TYPE_OBJECT) struct _SyncdaemonDaemonPrivate { #ifdef HAVE_GDBUS GDBusConnection *bus; GDbusProxy *dbus_proxy; #else DBusGConnection *bus; DBusGProxy *dbus_proxy; #endif /* Interfaces */ GObject *daemon_interface; GHashTable *subinterfaces; /* Status */ gboolean ready; gboolean connected; gchar *root_dir; SyncdaemonAuthentication *auth; }; /* Signals */ enum { READY_SIGNAL, CONNECTED_SIGNAL, DISCONNECTED_SIGNAL, STATUS_CHANGED_SIGNAL, ERROR_SIGNAL, EVENT_SIGNAL, FOLDER_CREATED_SIGNAL, FOLDER_DELETED_SIGNAL, FOLDER_SUBSCRIBED_SIGNAL, FOLDER_UNSUBSCRIBED_SIGNAL, FILE_PUBLISHED_SIGNAL, FILE_UNPUBLISHED_SIGNAL, SHARE_CREATED_SIGNAL, SHARE_DELETED_SIGNAL, DOWNLOAD_STARTED_SIGNAL, DOWNLOAD_FILE_PROGRESS_SIGNAL, DOWNLOAD_FINISHED_SIGNAL, UPLOAD_STARTED_SIGNAL, UPLOAD_FILE_PROGRESS_SIGNAL, UPLOAD_FINISHED_SIGNAL, QUOTA_EXCEEDED_SIGNAL, LAST_SIGNAL }; static guint daemon_signals[LAST_SIGNAL] = { 0, }; static void syncdaemon_daemon_finalize (GObject *object) { SyncdaemonDaemon *daemon = SYNCDAEMON_DAEMON (object); if (daemon->priv != NULL) { g_hash_table_destroy (daemon->priv->subinterfaces); if (daemon->priv->dbus_proxy != NULL) g_object_unref (daemon->priv->dbus_proxy); if (daemon->priv->bus != NULL) { #ifdef HAVE_GDBUS g_object_unref (G_OBJECT (daemon->priv->bus)); #else dbus_g_connection_unref (daemon->priv->bus); #endif } if (daemon->priv->root_dir != NULL) g_free (daemon->priv->root_dir); if (daemon->priv->auth != NULL) g_object_unref (G_OBJECT (daemon->priv->auth)); g_free (daemon->priv); } G_OBJECT_CLASS (syncdaemon_daemon_parent_class)->finalize (object); } static void syncdaemon_daemon_class_init (SyncdaemonDaemonClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = syncdaemon_daemon_finalize; /* Register signals */ daemon_signals[READY_SIGNAL] = g_signal_new ("ready", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, ready), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); daemon_signals[CONNECTED_SIGNAL] = g_signal_new ("connected", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, connected), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); daemon_signals[DISCONNECTED_SIGNAL] = g_signal_new ("disconnected", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, disconnected), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); daemon_signals[STATUS_CHANGED_SIGNAL] = g_signal_new ("status_changed", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, status_changed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); daemon_signals[EVENT_SIGNAL] = g_signal_new ("event", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, event), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); daemon_signals[ERROR_SIGNAL] = g_signal_new ("error", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, error), NULL, NULL, _syncdaemon_marshal_VOID__STRING_POINTER, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER); daemon_signals[FOLDER_CREATED_SIGNAL] = g_signal_new ("folder_created", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, folder_created), NULL, NULL, _syncdaemon_marshal_VOID__BOOLEAN_OBJECT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_OBJECT); daemon_signals[FOLDER_DELETED_SIGNAL] = g_signal_new ("folder_deleted", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, folder_deleted), NULL, NULL, _syncdaemon_marshal_VOID__BOOLEAN_OBJECT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_OBJECT); daemon_signals[FOLDER_SUBSCRIBED_SIGNAL] = g_signal_new ("folder_subscribed", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, folder_subscribed), NULL, NULL, _syncdaemon_marshal_VOID__BOOLEAN_OBJECT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_OBJECT); daemon_signals[FOLDER_UNSUBSCRIBED_SIGNAL] = g_signal_new ("folder_unsubscribed", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, folder_unsubscribed), NULL, NULL, _syncdaemon_marshal_VOID__BOOLEAN_OBJECT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_OBJECT); daemon_signals[FILE_PUBLISHED_SIGNAL] = g_signal_new ("file_published", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, file_published), NULL, NULL, _syncdaemon_marshal_VOID__BOOLEAN_OBJECT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_OBJECT); daemon_signals[FILE_UNPUBLISHED_SIGNAL] = g_signal_new ("file_unpublished", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, file_unpublished), NULL, NULL, _syncdaemon_marshal_VOID__BOOLEAN_OBJECT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_OBJECT); daemon_signals[SHARE_CREATED_SIGNAL] = g_signal_new ("share_created", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, share_created), NULL, NULL, _syncdaemon_marshal_VOID__BOOLEAN_OBJECT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_OBJECT); daemon_signals[SHARE_DELETED_SIGNAL] = g_signal_new ("share_deleted", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, share_deleted), NULL, NULL, _syncdaemon_marshal_VOID__BOOLEAN_OBJECT, G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_OBJECT); daemon_signals[DOWNLOAD_STARTED_SIGNAL] = g_signal_new ("download_started", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, download_started), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); daemon_signals[DOWNLOAD_FILE_PROGRESS_SIGNAL] = g_signal_new ("download_file_progress", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, download_file_progress), NULL, NULL, _syncdaemon_marshal_VOID__STRING_OBJECT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_OBJECT); daemon_signals[DOWNLOAD_FINISHED_SIGNAL] = g_signal_new ("download_finished", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, download_finished), NULL, NULL, _syncdaemon_marshal_VOID__STRING_OBJECT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_OBJECT); daemon_signals[UPLOAD_STARTED_SIGNAL] = g_signal_new ("upload_started", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, upload_started), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); daemon_signals[UPLOAD_FILE_PROGRESS_SIGNAL] = g_signal_new ("upload_file_progress", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, upload_file_progress), NULL, NULL, _syncdaemon_marshal_VOID__STRING_OBJECT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_OBJECT); daemon_signals[UPLOAD_FINISHED_SIGNAL] = g_signal_new ("upload_finished", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, upload_finished), NULL, NULL, _syncdaemon_marshal_VOID__STRING_OBJECT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_OBJECT); daemon_signals[QUOTA_EXCEEDED_SIGNAL] = g_signal_new ("quota_exceeded", G_TYPE_FROM_CLASS (klass), (GSignalFlags) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SyncdaemonDaemonClass, quota_exceeded), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); } static void quota_exceeded_cb (DBusGProxy *proxy, GHashTable *volume_info, gpointer user_data) { SyncdaemonDaemon *daemon = SYNCDAEMON_DAEMON (user_data); if (daemon != NULL) g_signal_emit_by_name (daemon, "quota_exceeded", volume_info); } static gboolean ready_signal_idle_cb (gpointer user_data) { SyncdaemonDaemon *daemon = SYNCDAEMON_DAEMON (user_data); g_signal_emit (daemon, daemon_signals[READY_SIGNAL], 0); return FALSE; } static void setup_daemon_interface (SyncdaemonDaemon *daemon) { GObject *proxy = NULL; if (daemon->priv->daemon_interface != NULL) g_object_unref (daemon->priv->daemon_interface); daemon->priv->daemon_interface = g_object_new (SYNCDAEMON_TYPE_INTERFACE, "daemon", daemon, NULL); proxy = syncdaemon_interface_setup_proxy (SYNCDAEMON_INTERFACE (daemon->priv->daemon_interface), SYNCDAEMON_DBUS_NAME, "/", "com.ubuntuone.SyncDaemon.SyncDaemon"); if (proxy != NULL) { daemon->priv->ready = TRUE; dbus_g_proxy_add_signal (DBUS_G_PROXY (proxy), "QuotaExceeded", dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING), G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (proxy), "QuotaExceeded", G_CALLBACK (quota_exceeded_cb), daemon, NULL); /* Now get all the interfaces so that we get the signals from them */ syncdaemon_daemon_get_config_interface (daemon); syncdaemon_daemon_get_events_interface (daemon); syncdaemon_daemon_get_filesystem_interface (daemon); syncdaemon_daemon_get_folders_interface (daemon); syncdaemon_daemon_get_publicfiles_interface (daemon); syncdaemon_daemon_get_shares_interface (daemon); syncdaemon_daemon_get_status_interface (daemon); /* Emit the signal in an idle callback so that callers get it when syncdaemon is running and hence signal is emitted in the _init method */ g_idle_add ((GSourceFunc) ready_signal_idle_cb, daemon); } } static void name_owner_changed_cb (DBusGProxy *proxy, const char *name, const char *old_owner, const char *new_owner, gpointer user_data) { SyncdaemonDaemon *daemon = SYNCDAEMON_DAEMON (user_data); if (g_strcmp0 (name, SYNCDAEMON_DBUS_NAME) == 0) { if (new_owner != NULL && strlen (new_owner) > 0) { g_debug ("Got notification of SyncDaemon startup in NameOwnerChanged"); setup_daemon_interface (daemon); } else { daemon->priv->ready = FALSE; g_debug ("Syncdaemon service died"); if (daemon->priv->daemon_interface != NULL) { g_object_unref (daemon->priv->daemon_interface); daemon->priv->daemon_interface = NULL; } g_hash_table_remove_all (daemon->priv->subinterfaces); daemon->priv->connected = FALSE; } } } static void syncdaemon_daemon_init (SyncdaemonDaemon *daemon) { gboolean has_owner; GError *error = NULL; daemon->priv = g_new0 (SyncdaemonDaemonPrivate, 1); daemon->priv->ready = FALSE; daemon->priv->connected = FALSE; daemon->priv->subinterfaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); daemon->priv->auth = g_object_new (SYNCDAEMON_TYPE_AUTHENTICATION, NULL); /* Initialize DBus */ #ifdef HAVE_GDBUS daemon->priv->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); #else daemon->priv->bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); #endif if (error != NULL) { g_warning ("Couldn't get session bus: %s", error->message); g_error_free (error); return; } daemon->priv->dbus_proxy = dbus_g_proxy_new_for_name (daemon->priv->bus, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus"); /* Check if syncdaemon is running */ error = NULL; if (org_freedesktop_DBus_name_has_owner (daemon->priv->dbus_proxy, SYNCDAEMON_DBUS_NAME, &has_owner, &error)) { if (has_owner) { /* Already running, so initialize ourselves */ g_debug ("SyncDaemon already running, initializing SyncdaemonDaemon object"); setup_daemon_interface (daemon); } else g_debug ("Syncdaemon not running, waiting for it to start in NameOwnerChanged"); } else { /* The DBus call failed, so just wait for SyncDaemon to start in name_owner_changed_cb */ g_warning ("Error calling NameHasOwner: %s", error->message); g_error_free (error); } /* Listen to DBus for syncdaemon restarts */ dbus_g_proxy_add_signal (DBUS_G_PROXY (daemon->priv->dbus_proxy), "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (daemon->priv->dbus_proxy), "NameOwnerChanged", G_CALLBACK (name_owner_changed_cb), daemon, NULL); } /** * syncdaemon_daemon_new: * * Create a new #SyncdaemonDaemon object, which provides access to the * Syncdaemon daemon. * * Return value: A new #SyncdaemonDaemon object. */ SyncdaemonDaemon * syncdaemon_daemon_new (void) { return g_object_new (SYNCDAEMON_TYPE_DAEMON, NULL); } /** * syncdaemon_daemon_is_ready: */ gboolean syncdaemon_daemon_is_ready (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); return daemon->priv->ready; } static void connect_response_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) { GError *error = NULL; SyncdaemonDaemon *daemon = (SyncdaemonDaemon *) user_data; if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { daemon->priv->connected = TRUE; g_signal_emit (daemon, daemon_signals[CONNECTED_SIGNAL], 0); } else { g_warning ("Syncdaemon cannot connect: %s", error->message); g_error_free (error); } } /** * syncdaemon_daemon_connect: */ gboolean syncdaemon_daemon_connect (SyncdaemonDaemon *daemon) { GObject *proxy; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); proxy = syncdaemon_interface_get_proxy_object (SYNCDAEMON_INTERFACE (daemon->priv->daemon_interface)); if (proxy != NULL) { #ifdef HAVE_GDBUS #else if (!dbus_g_proxy_begin_call (DBUS_G_PROXY (proxy), "connect", connect_response_cb, daemon, NULL, G_TYPE_INVALID)) { g_warning ("Call to 'connect' method failed"); return FALSE; } #endif } return TRUE; } static void disconnect_response_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) { GError *error = NULL; SyncdaemonDaemon *daemon = (SyncdaemonDaemon *) user_data; if (dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { daemon->priv->connected = FALSE; g_signal_emit (daemon, daemon_signals[DISCONNECTED_SIGNAL], 0); } else { g_warning ("Syncdaemon cannot disconnect: %s", error->message); g_error_free (error); } } /** * syncdaemon_daemon_interface_disconnect: */ gboolean syncdaemon_daemon_disconnect (SyncdaemonDaemon *daemon) { GObject *proxy; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); proxy = syncdaemon_interface_get_proxy_object (SYNCDAEMON_INTERFACE (daemon->priv->daemon_interface)); if (proxy != NULL) { #ifdef HAVE_GDBUS #else if (!dbus_g_proxy_begin_call (DBUS_G_PROXY (proxy), "disconnect", disconnect_response_cb, daemon, NULL, G_TYPE_INVALID)) { g_warning ("Call to 'disconnect' method failed"); return FALSE; } #endif } return TRUE; } /** * syncdaemon_daemon_interface_quit: */ gboolean syncdaemon_daemon_quit (SyncdaemonDaemon *daemon) { GObject *proxy; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); proxy = syncdaemon_interface_get_proxy_object (SYNCDAEMON_INTERFACE (daemon->priv->daemon_interface)); if (proxy != NULL) { GError *error = NULL; #ifdef HAVE_GDBUS #else if (!dbus_g_proxy_call (DBUS_G_PROXY (proxy), "quit", &error, G_TYPE_INVALID, G_TYPE_INVALID)) { g_warning ("Could not quit syncdaemon: %s", error->message); g_error_free (error); return FALSE; } #endif } return TRUE; } /** * syncdaemon_daemon_get_root_dir: */ const gchar * syncdaemon_daemon_get_root_dir (SyncdaemonDaemon *daemon) { GObject *proxy; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); if (daemon->priv->root_dir != NULL) return (const gchar *) daemon->priv->root_dir; proxy = syncdaemon_interface_get_proxy_object (SYNCDAEMON_INTERFACE (daemon->priv->daemon_interface)); if (proxy != NULL) { gchar *new_root_dir; GError *error = NULL; #ifdef HAVE_GDBUS #else if (!dbus_g_proxy_call (DBUS_G_PROXY (proxy), "get_rootdir", &error, G_TYPE_INVALID, G_TYPE_STRING, &new_root_dir, G_TYPE_INVALID)) { g_warning ("Could not get syncdaemon's root dir: %s", error->message); g_error_free (error); return NULL; } #endif daemon->priv->root_dir = new_root_dir; return (const gchar *) daemon->priv->root_dir; } return NULL; } /** * syncdaemon_daemon_has_network: */ gboolean syncdaemon_daemon_has_network (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; gboolean result = FALSE; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); interface = syncdaemon_daemon_get_status_interface (daemon); if (SYNCDAEMON_IS_STATUS_INTERFACE (interface)) { SyncdaemonStatusInfo *status_info; status_info = syncdaemon_status_interface_get_current_status (SYNCDAEMON_STATUS_INTERFACE (interface)); if (g_strrstr (syncdaemon_status_info_get_connection (status_info), "With Network") != NULL) result = TRUE; g_object_unref (G_OBJECT (status_info)); } return result; } /** * syncdaemon_daemon_get_authentication: */ SyncdaemonAuthentication * syncdaemon_daemon_get_authentication (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return daemon->priv->auth; } /** * syncdaemon_daemon_get_bandwidth_throttling: * @daemon: A #SyncdaemonDaemon object * * Get whether bandwidth throttling is enabled or not. * * Return value: TRUE if enabled, FALSE if disabled. */ gboolean syncdaemon_daemon_get_bandwidth_throttling (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); interface = syncdaemon_daemon_get_config_interface (daemon); if (SYNCDAEMON_IS_CONFIG_INTERFACE (interface)) return syncdaemon_config_interface_get_bandwidth_throttling (SYNCDAEMON_CONFIG_INTERFACE (interface)); return FALSE; } /** * syncdaemon_daemon_set_bandwidth_throttling: * @daemon: A #SyncdaemonDaemon object * @enabled: Whether to enable bandwidth throttling or not. * * Enable or disable bandwidth throttling. */ void syncdaemon_daemon_set_bandwidth_throttling (SyncdaemonDaemon *daemon, gboolean enabled) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_config_interface (daemon); if (SYNCDAEMON_IS_CONFIG_INTERFACE (interface)) syncdaemon_config_interface_set_bandwidth_throttling (SYNCDAEMON_CONFIG_INTERFACE (interface), enabled); } /** * syncdaemon_daemon_get_files_sync: * @daemon: A #SyncdaemonDaemon object * * Get whether file syncing is enabled or not. * * Return value: TRUE if enabled, FALSE if disabled. */ gboolean syncdaemon_daemon_get_files_sync (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); interface = syncdaemon_daemon_get_config_interface (daemon); if (SYNCDAEMON_IS_CONFIG_INTERFACE (interface)) return syncdaemon_config_interface_get_files_sync (SYNCDAEMON_CONFIG_INTERFACE (interface)); return FALSE; } /** * syncdaemon_daemon_set_files_sync: * @daemon: A #SyncdaemonDaemon object * @enabled: Whether to enable file syncing or not. * * Enable or disable file syncing. */ void syncdaemon_daemon_set_files_sync (SyncdaemonDaemon *daemon, gboolean enabled) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_config_interface (daemon); if (SYNCDAEMON_IS_CONFIG_INTERFACE (interface)) syncdaemon_config_interface_set_files_sync (SYNCDAEMON_CONFIG_INTERFACE (interface), enabled); } /** * syncdaemon_daemon_get_throttling_limits: * @daemon: A #SyncdaemonDaemon object * @download: Placeholder for download limits * @upload: Placeholder for upload limits * * Retrieve download and upload throttling limits. */ void syncdaemon_daemon_get_throttling_limits (SyncdaemonDaemon *daemon, gint *download, gint *upload) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_config_interface (daemon); if (interface != NULL) { syncdaemon_config_interface_get_throttling_limits (SYNCDAEMON_CONFIG_INTERFACE (interface), download, upload); } } /** * syncdaemon_daemon_set_throttling_limits: * @daemon: A #SyncdaemonDaemon object * @download: Download limit * @upload: Upload limit * * Set download and upload throttling limits. */ void syncdaemon_daemon_set_throttling_limits (SyncdaemonDaemon *daemon, gint download, gint upload) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_config_interface (daemon); if (interface != NULL) { syncdaemon_config_interface_set_throttling_limits (SYNCDAEMON_CONFIG_INTERFACE (interface), download, upload); } } /** * syncdaemon_daemon_get_udf_autosubscribe: * @daemon: A #SyncdaemonDaemon object * * Get whether autosubscription for UDFs is enabled or not. * * Return value: TRUE if enabled, FALSE if disabled. */ gboolean syncdaemon_daemon_get_udf_autosubscribe (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); interface = syncdaemon_daemon_get_config_interface (daemon); if (SYNCDAEMON_IS_CONFIG_INTERFACE (interface)) return syncdaemon_config_interface_get_udf_autosubscribe (SYNCDAEMON_CONFIG_INTERFACE (interface)); return FALSE; } /** * syncdaemon_daemon_set_udf_autosubscribe: * @daemon: A #SyncdaemonDaemon object * @enabled: Whether to enable UDF autosubscription or not. * * Enable or disable UDF autosubscription. */ void syncdaemon_daemon_set_udf_autosubscribe (SyncdaemonDaemon *daemon, gboolean enabled) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_config_interface (daemon); if (SYNCDAEMON_IS_CONFIG_INTERFACE (interface)) syncdaemon_config_interface_set_udf_autosubscribe (SYNCDAEMON_CONFIG_INTERFACE (interface), enabled); } /** * syncdaemon_daemon_get_metadata: * @daemon: A #SyncdaemonDaemon object * @path: Path to check metadata for * @with_subtree_sync_check: For folders, whether to check the status of all its children * * Retrieve metadata for a file or folder inside a Ubuntu One directory. * * Return value: Metadata for the specified path. */ SyncdaemonMetadata * syncdaemon_daemon_get_metadata (SyncdaemonDaemon *daemon, const gchar *path, gboolean with_subtree_sync_check) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_filesystem_interface (daemon); if (interface != NULL) { return syncdaemon_filesystem_interface_get_metadata (SYNCDAEMON_FILESYSTEM_INTERFACE (interface), path, with_subtree_sync_check); } return NULL; } /** * syncdaemon_daemon_get_folders: * @daemon: A #SyncdaemonDaemon object * * Retrieve the list of folders setup for synchronization with Ubuntu One. * * Return value: A list of #SyncdaemonFolderInfo containing all the folders being * synchronized by the user. When no longer needed, the list should be freed * by calling g_slist_free. */ GSList * syncdaemon_daemon_get_folders (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_folders_interface (daemon); if (interface != NULL) return syncdaemon_folders_interface_get_folders (SYNCDAEMON_FOLDERS_INTERFACE (interface)); return NULL; } /** * syncdaemon_daemon_get_folder_info: * @daemon: A #SyncdaemonDaemon object * @path: Full path of the folder for which to retrieve information. * * Get information about a folder under Ubuntu One. * * Return value: A #SyncdaemonFolderInfo object containing all the information * for the node. When no longer needed, it should be freed by calling * g_object_unref. */ SyncdaemonFolderInfo * syncdaemon_daemon_get_folder_info (SyncdaemonDaemon *daemon, const gchar *path) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_folders_interface (daemon); if (interface != NULL) return syncdaemon_folders_interface_get_info (SYNCDAEMON_FOLDERS_INTERFACE (interface), path); return NULL; } /** * syncdaemon_daemon_is_folder_enabled: * @daemon: A #SyncdaemonDaemon object * @path: The folder path to check * @is_root: Placeholder for returning whether the given path is a U1 root folder * * Check whether a given path is a folder enabled for synchronization to U1. * * Return value: TRUE if the folder is enabled, FALSE otherwise. */ gboolean syncdaemon_daemon_is_folder_enabled (SyncdaemonDaemon *daemon, const gchar *path, gboolean *is_root) { const gchar *root; gchar *root_with_slash; gboolean managed = FALSE, is_subscribed = FALSE; gchar *dirpath; SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); g_return_val_if_fail (path != NULL, FALSE); *is_root = FALSE; /* First check the root folder */ root = syncdaemon_daemon_get_root_dir (daemon); if (g_strcmp0 (path, root) == 0) { *is_root = TRUE; return TRUE; } else { root_with_slash = g_build_filename (root, G_DIR_SEPARATOR_S, NULL); if (g_str_has_prefix (path, root_with_slash)) { g_free(root_with_slash); return TRUE; } g_free(root_with_slash); } /* Now check the 'Shared With Me' directory */ dirpath = g_build_filename (root, "Shared With Me", NULL); if (g_strcmp0 (path, dirpath) == 0) { g_free (dirpath); return FALSE; } /* And finally check UDFs */ interface = syncdaemon_daemon_get_folders_interface (daemon); if (SYNCDAEMON_IS_FOLDERS_INTERFACE (interface)) { GSList *udfs, *l; udfs = syncdaemon_folders_interface_get_folders (SYNCDAEMON_FOLDERS_INTERFACE (interface)); for (l = udfs; l != NULL; l = l->next) { const gchar *tmp_path; SyncdaemonFolderInfo *finfo = SYNCDAEMON_FOLDER_INFO (l->data); tmp_path = syncdaemon_folder_info_get_path (finfo); is_subscribed = syncdaemon_folder_info_get_subscribed (finfo); if (g_strcmp0 (path, tmp_path) == 0) { managed = is_subscribed; *is_root = TRUE; break; } else if (g_str_has_prefix (path, tmp_path)) { managed = is_subscribed; break; } } g_slist_free (udfs); } return managed; } /** * syncdaemon_daemon_create_folder: * @daemon: A #SyncdaemonDaemon object * @path: The full path of the folder to create * * Enable a folder for Ubuntu One synchronization. * * The result of the operation can be retrieved by connecting to the "folder_created" * signal of the #SyncdaemonDaemon object. */ void syncdaemon_daemon_create_folder (SyncdaemonDaemon *daemon, const gchar *path) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_folders_interface (daemon); if (interface != NULL) syncdaemon_folders_interface_create (SYNCDAEMON_FOLDERS_INTERFACE (interface), path); else g_signal_emit (daemon, daemon_signals[FOLDER_CREATED_SIGNAL], 0, FALSE, NULL); } /** * syncdaemon_daemon_delete_folder: * @daemon: A #SyncdaemonDaemon object * @path: The full path of the folder to delete * * Disable a folder for Ubuntu One synchronization. * * The result of the operation can be retrieved by connecting to the "folder_deleted" * signal of the #SyncdaemonDaemon object. */ void syncdaemon_daemon_delete_folder (SyncdaemonDaemon *daemon, const gchar *path) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_folders_interface (daemon); if (interface != NULL) syncdaemon_folders_interface_delete (SYNCDAEMON_FOLDERS_INTERFACE (interface), path); else g_signal_emit (daemon, daemon_signals[FOLDER_DELETED_SIGNAL], 0, FALSE, NULL); } /** * syncdaemon_daemon_subscribe_folder: * @daemon: A #SyncdaemonDaemon object * @path: The full path of the folder to subscribe * * Subscribe a folder for Ubuntu One synchronization. * * The result of the operation can be retrieved by connecting to the "folder_subscribed" * signal of the #SyncdaemonDaemon object. */ void syncdaemon_daemon_subscribe_folder (SyncdaemonDaemon *daemon, const gchar *path) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_folders_interface (daemon); if (interface != NULL) syncdaemon_folders_interface_subscribe (SYNCDAEMON_FOLDERS_INTERFACE (interface), path); else g_signal_emit (daemon, daemon_signals[FOLDER_SUBSCRIBED_SIGNAL], 0, FALSE, NULL); } /** * syncdaemon_daemon_unsubscribe_folder: * @daemon: A #SyncdaemonDaemon object * @path: The full path of the folder to unsubscribe * * Unsubscribe a folder from Ubuntu One synchronization. * * The result of the operation can be retrieved by connecting to the "folder_unsubscribed" * signal of the #SyncdaemonDaemon object. */ void syncdaemon_daemon_unsubscribe_folder (SyncdaemonDaemon *daemon, const gchar *path) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_folders_interface (daemon); if (interface != NULL) syncdaemon_folders_interface_unsubscribe (SYNCDAEMON_FOLDERS_INTERFACE (interface), path); else g_signal_emit (daemon, daemon_signals[FOLDER_UNSUBSCRIBED_SIGNAL], 0, FALSE, NULL); } /** * syncdaemon_daemon_publish_file: * @daemon: A #SyncdaemonDaemon object * @path: Full path of the file to be published * * Publish a file on Ubuntu One. When the file is successfully published, the "file_published" * signal will be emitted. * * Return value: TRUE if successful, FALSE otherwise. */ gboolean syncdaemon_daemon_publish_file (SyncdaemonDaemon *daemon, const gchar *path) { SyncdaemonMetadata *metadata; gboolean result = FALSE; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); /* First, retrieve the metadata */ metadata = syncdaemon_daemon_get_metadata (daemon, path, FALSE); if (metadata != NULL) { SyncdaemonInterface *interface; interface = syncdaemon_daemon_get_publicfiles_interface (daemon); syncdaemon_publicfiles_interface_change_public_access ( SYNCDAEMON_PUBLICFILES_INTERFACE (interface), syncdaemon_metadata_get_share_id (metadata), syncdaemon_metadata_get_node_id (metadata), TRUE); result = TRUE; g_object_unref (metadata); } return result; } /** * syncdaemon_daemon_unpublish_file: * @daemon: A #SyncdaemonDaemon object * @path: Full path of the file to be unpublished * * Unpublish a file from Ubuntu One. When the file is successfully unpublished, the "file_unpublished" * signal will be emitted. * * Return value: TRUE if successful, FALSE otherwise. */ gboolean syncdaemon_daemon_unpublish_file (SyncdaemonDaemon *daemon, const gchar *path) { SyncdaemonMetadata *metadata; gboolean result = FALSE; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), FALSE); /* First, retrieve the metadata */ metadata = syncdaemon_daemon_get_metadata (daemon, path, FALSE); if (metadata != NULL) { SyncdaemonInterface *interface; interface = syncdaemon_daemon_get_publicfiles_interface (daemon); syncdaemon_publicfiles_interface_change_public_access ( SYNCDAEMON_PUBLICFILES_INTERFACE (interface), syncdaemon_metadata_get_share_id (metadata), syncdaemon_metadata_get_node_id (metadata), FALSE); result = TRUE; g_object_unref (metadata); } return result; } /** * syncdaemon_daemon_get_public_files: * @daemon: A #SyncdaemonDaemon object * * Retrieve the list of public files. * * Return value: A #GSList of #SyncdaemonFileInfo objects, each of which describes * a published file for the user. When no longer needed, this list should be * freed by calling g_slist_free, but the data within the list should never * be freed, as it belongs to the library. */ GSList * syncdaemon_daemon_get_public_files (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_publicfiles_interface (daemon); if (interface != NULL) { return syncdaemon_publicfiles_interface_get_public_files ( SYNCDAEMON_PUBLICFILES_INTERFACE (interface)); } return NULL; } /** * syncdaemon_daemon_create_share: * @daemon: A #SyncdaemonDaemon object * @path: Full path of the folder to be shared * @usernames: List of users with whom to share the folder * @name: Name to be used for the share * @allow_modifications: Whether to allow modifications to the list of users * * Share a Ubuntu One folder with a list of users. * * The result of the operation can be retrieved by connecting to the "share_created" * signal of the #SyncdaemonDaemon object. */ void syncdaemon_daemon_create_share (SyncdaemonDaemon *daemon, const gchar *path, GSList *usernames, const gchar *name, gboolean allow_modifications) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_shares_interface (daemon); if (interface != NULL) { syncdaemon_shares_interface_create (SYNCDAEMON_SHARES_INTERFACE (interface), path, usernames, name, allow_modifications); } else g_signal_emit (daemon, daemon_signals[SHARE_CREATED_SIGNAL], 0, FALSE, NULL); } /** * syncdaemon_daemon_delete_share: * @daemon: A #SyncdaemonDaemon object * @path: Full path of the folder to be shared * * Stop sharing a Ubuntu One folder. * * The result of the operation can be retrieved by connecting to the "share_deleted" * signal of the #SyncdaemonDaemon object. */ void syncdaemon_daemon_delete_share (SyncdaemonDaemon *daemon, const gchar *path) { SyncdaemonInterface *interface; g_return_if_fail (SYNCDAEMON_IS_DAEMON (daemon)); interface = syncdaemon_daemon_get_shares_interface (daemon); if (interface != NULL) syncdaemon_shares_interface_delete (SYNCDAEMON_SHARES_INTERFACE (interface), path); else g_signal_emit (daemon, daemon_signals[SHARE_DELETED_SIGNAL], 0, FALSE, NULL); } /** * syncdaemon_daemon_get_shared_folders: * @daemon: A #SyncdaemonDaemon object * * Get the list of folders shared by the user with other users. * * Return value: A GSList of #SyncdaemonShareInfo objects. When no longer needed, * the list should be freed by calling #g_slist_free. */ GSList * syncdaemon_daemon_get_shared_folders (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_shares_interface (daemon); if (interface != NULL) return syncdaemon_shares_interface_get_shared (SYNCDAEMON_SHARES_INTERFACE (interface)); return NULL; } /** * syncdaemon_daemon_get_shares: * @daemon: A #SyncdaemonDaemon object * * Get the list of folders shared by other users with the current user. * * Return value: A GSList of #SyncdaemonShareInfo objects. When no longer needed, * the list should be freed by calling #g_slist_free. */ GSList * syncdaemon_daemon_get_shares (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_shares_interface (daemon); if (interface != NULL) return syncdaemon_shares_interface_get_shares (SYNCDAEMON_SHARES_INTERFACE (interface)); return NULL; } /** * syncdaemon_daemon_get_current_status: * @daemon: A #SyncdaemonDaemon object * * Retrieve the current status of SyncDaemon. * * Return value: A #SyncdaemonStatusInfo object containing information about * Syncdaemon's current status. When no longer needed, it should be freed by * calling g_object_unref. */ SyncdaemonStatusInfo * syncdaemon_daemon_get_current_status (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_status_interface (daemon); if (interface != NULL) return syncdaemon_status_interface_get_current_status (SYNCDAEMON_STATUS_INTERFACE (interface)); return NULL; } /** * syncdaemon_daemon_get_current_downloads: * @daemon: A #SyncdaemonDaemon object * * Retrieve the list of downloads in progress. * * Return value: A GSList of #SyncdaemonTransferInfo objects, each of which contains * information about a file download in progress. The data in the list belongs to * the library, so when no longer needed, the list should be freed by just calling * g_slist_free. */ GSList * syncdaemon_daemon_get_current_downloads (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_status_interface (daemon); if (interface != NULL) return syncdaemon_status_interface_get_current_downloads (SYNCDAEMON_STATUS_INTERFACE (interface)); return NULL; } /** * syncdaemon_daemon_get_current_uploads: * @daemon: A #SyncdaemonDaemon object * * Retrieve the list of uploads in progress. * * Return value: A GSList of #SyncdaemonTransferInfo objects, each of which contains * information about a file upload in progress. The data in the list belongs to * the library, so when no longer needed, the list should be freed by just calling * g_slist_free. */ GSList * syncdaemon_daemon_get_current_uploads (SyncdaemonDaemon *daemon) { SyncdaemonInterface *interface; g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); interface = syncdaemon_daemon_get_status_interface (daemon); if (interface != NULL) return syncdaemon_status_interface_get_current_uploads (SYNCDAEMON_STATUS_INTERFACE (interface)); return NULL; } typedef SyncdaemonInterface * (* SDINewFunc) (SyncdaemonDaemon * daemon); static SyncdaemonInterface * get_interface (SyncdaemonDaemon *daemon, const gchar *path, SDINewFunc new_func) { SyncdaemonInterface *interface; interface = g_hash_table_lookup (daemon->priv->subinterfaces, path); if (interface == NULL) { interface = new_func (daemon); if (SYNCDAEMON_IS_INTERFACE (interface)) g_hash_table_insert (daemon->priv->subinterfaces, g_strdup (path), interface); } return interface; } /** * syncdaemon_daemon_get_config_interface: */ SyncdaemonInterface * syncdaemon_daemon_get_config_interface (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return get_interface (daemon, "/config", (SDINewFunc) syncdaemon_config_interface_new); } /** * syncdaemon_daemon_get_events_interface: */ SyncdaemonInterface * syncdaemon_daemon_get_events_interface (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return get_interface (daemon, "/events", (SDINewFunc) syncdaemon_events_interface_new); } /** * syncdaemon_daemon_get_filesystem_interface: */ SyncdaemonInterface * syncdaemon_daemon_get_filesystem_interface (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return get_interface (daemon, "/filesystem", (SDINewFunc) syncdaemon_filesystem_interface_new); } /** * syncdaemon_daemon_get_folders_interface: */ SyncdaemonInterface * syncdaemon_daemon_get_folders_interface (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return get_interface (daemon, "/folders", (SDINewFunc) syncdaemon_folders_interface_new); } /** * syncdaemon_daemon_get_publicfiles_interface: */ SyncdaemonInterface * syncdaemon_daemon_get_publicfiles_interface (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return get_interface (daemon, "/publicfiles", (SDINewFunc) syncdaemon_publicfiles_interface_new); } /** * syncdaemon_daemon_get_shares_interface: */ SyncdaemonInterface * syncdaemon_daemon_get_shares_interface (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return get_interface (daemon, "/shares", (SDINewFunc) syncdaemon_shares_interface_new); } /** * syncdaemon_daemon_get_status_interface: */ SyncdaemonInterface * syncdaemon_daemon_get_status_interface (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return get_interface (daemon, "/status", (SDINewFunc) syncdaemon_status_interface_new); }