/* * Syncdaemon API * * Authors: Rodrigo Moya * * Copyright 2010-2012 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 . * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. * */ #include "config.h" #include "syncdaemon-status-interface.h" #include "utils.h" G_DEFINE_TYPE(SyncdaemonStatusInterface, syncdaemon_status_interface, SYNCDAEMON_TYPE_INTERFACE) struct _SyncdaemonStatusInterfacePrivate { GObject *proxy; GHashTable *downloads; GHashTable *uploads; SyncdaemonStatusInfo *current_status; }; static void syncdaemon_status_interface_finalize (GObject *object) { SyncdaemonStatusInterface *interface = SYNCDAEMON_STATUS_INTERFACE (object); if (interface->priv != NULL) { if (interface->priv->downloads != NULL) g_hash_table_destroy (interface->priv->downloads); if (interface->priv->uploads != NULL) g_hash_table_destroy (interface->priv->uploads); if (interface->priv->current_status != NULL) g_object_unref (G_OBJECT (interface->priv->current_status)); g_free (interface->priv); } G_OBJECT_CLASS (syncdaemon_status_interface_parent_class)->finalize (object); } static void syncdaemon_status_interface_class_init (SyncdaemonStatusInterfaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = syncdaemon_status_interface_finalize; } static void status_changed_cb (DBusGProxy *proxy, GHashTable *hash, gpointer user_data) { SyncdaemonDaemon *daemon; SyncdaemonStatusInterface *interface = SYNCDAEMON_STATUS_INTERFACE (user_data); g_object_get (G_OBJECT (interface), "daemon", &daemon, NULL); if (daemon != NULL) { if (interface->priv->current_status != NULL) g_object_unref (G_OBJECT (interface->priv->current_status)); interface->priv->current_status = syncdaemon_status_info_new_from_hash_table (hash); g_signal_emit_by_name (daemon, "status_changed", interface->priv->current_status); } } static void download_started_cb (DBusGProxy *proxy, gchar *path, gpointer user_data) { SyncdaemonDaemon *daemon; SyncdaemonStatusInterface *interface = SYNCDAEMON_STATUS_INTERFACE (user_data); if (interface->priv->downloads == NULL) { interface->priv->downloads = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } g_hash_table_insert (interface->priv->downloads, g_strdup (path), syncdaemon_transfer_info_new (path)); g_object_get (G_OBJECT (interface), "daemon", &daemon, NULL); if (daemon != NULL) g_signal_emit_by_name (daemon, "download_started", path); } static void download_finished_cb (DBusGProxy *proxy, gchar *path, GHashTable *info, gpointer user_data) { SyncdaemonDaemon *daemon; SyncdaemonStatusInterface *interface = SYNCDAEMON_STATUS_INTERFACE (user_data); g_object_get (G_OBJECT (interface), "daemon", &daemon, NULL); if (daemon != NULL) { SyncdaemonTransferInfo *tinfo; tinfo = g_hash_table_lookup (interface->priv->downloads, path); if (tinfo != NULL) g_signal_emit_by_name (daemon, "download_finished", path, tinfo); else { tinfo = syncdaemon_transfer_info_new_from_hash_table (info); g_signal_emit_by_name (daemon, "download_finished", path, tinfo); g_object_unref (G_OBJECT (tinfo)); } } if (interface->priv->downloads != NULL) g_hash_table_remove (interface->priv->downloads, path); } static void upload_started_cb (DBusGProxy *proxy, gchar *path, gpointer user_data) { SyncdaemonDaemon *daemon; SyncdaemonStatusInterface *interface = SYNCDAEMON_STATUS_INTERFACE (user_data); if (interface->priv->uploads == NULL) { interface->priv->uploads = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } g_hash_table_insert (interface->priv->uploads, g_strdup (path), syncdaemon_transfer_info_new (path)); g_object_get (G_OBJECT (interface), "daemon", &daemon, NULL); if (daemon != NULL) g_signal_emit_by_name (daemon, "upload_started", path); } static void upload_finished_cb (DBusGProxy *proxy, gchar *path, GHashTable *info, gpointer user_data) { SyncdaemonDaemon *daemon = NULL; SyncdaemonStatusInterface *interface = SYNCDAEMON_STATUS_INTERFACE (user_data); g_object_get (G_OBJECT (interface), "daemon", &daemon, NULL); if (daemon != NULL) { SyncdaemonTransferInfo *tinfo; tinfo = g_hash_table_lookup (interface->priv->uploads, path); if (tinfo != NULL) g_signal_emit_by_name (daemon, "upload_finished", path, tinfo); else { tinfo = syncdaemon_transfer_info_new_from_hash_table (info); g_signal_emit_by_name (daemon, "upload_finished", path, tinfo); g_object_unref (G_OBJECT (tinfo)); } } if (interface->priv->downloads != NULL) g_hash_table_remove (interface->priv->uploads, path); } static void download_file_progress_cb (DBusGProxy *proxy, gchar *path, GHashTable *info, gpointer user_data) { SyncdaemonDaemon *daemon = NULL; SyncdaemonTransferInfo *tinfo; SyncdaemonStatusInterface *interface = SYNCDAEMON_STATUS_INTERFACE (user_data); tinfo = syncdaemon_transfer_info_new_from_hash_table (info); g_hash_table_insert (interface->priv->downloads, g_strdup (path), tinfo); g_object_get (G_OBJECT (interface), "daemon", &daemon, NULL); if (daemon != NULL) g_signal_emit_by_name (daemon, "download_file_progress", path, tinfo); } static void upload_file_progress_cb (DBusGProxy *proxy, gchar *path, GHashTable *info, gpointer user_data) { SyncdaemonDaemon *daemon = NULL; SyncdaemonTransferInfo *tinfo; SyncdaemonStatusInterface *interface = SYNCDAEMON_STATUS_INTERFACE (user_data); tinfo = syncdaemon_transfer_info_new_from_hash_table (info); g_hash_table_insert (interface->priv->downloads, g_strdup (path), tinfo); g_object_get (G_OBJECT (interface), "daemon", &daemon, NULL); if (daemon != NULL) g_signal_emit_by_name (daemon, "upload_file_progress", path, tinfo); } static void syncdaemon_status_interface_init (SyncdaemonStatusInterface *interface) { interface->priv = g_new0 (SyncdaemonStatusInterfacePrivate, 1); /* Setup DBus proxy */ interface->priv->proxy = syncdaemon_interface_setup_proxy (SYNCDAEMON_INTERFACE (interface), "com.ubuntuone.SyncDaemon", "/status", "com.ubuntuone.SyncDaemon.Status"); if (interface->priv->proxy != NULL) { /* Connect to DBus signals */ dbus_g_proxy_add_signal (DBUS_G_PROXY (interface->priv->proxy), "StatusChanged", dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING), G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (interface->priv->proxy), "StatusChanged", G_CALLBACK (status_changed_cb), interface, NULL); dbus_g_proxy_add_signal (DBUS_G_PROXY (interface->priv->proxy), "DownloadStarted", G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (interface->priv->proxy), "DownloadStarted", G_CALLBACK (download_started_cb), interface, NULL); dbus_g_proxy_add_signal (DBUS_G_PROXY (interface->priv->proxy), "DownloadFinished", G_TYPE_STRING, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING), G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (interface->priv->proxy), "DownloadFinished", G_CALLBACK (download_finished_cb), interface, NULL); dbus_g_proxy_add_signal (DBUS_G_PROXY (interface->priv->proxy), "UploadStarted", G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (interface->priv->proxy), "UploadStarted", G_CALLBACK (upload_started_cb), interface, NULL); dbus_g_proxy_add_signal (DBUS_G_PROXY (interface->priv->proxy), "UploadFinished", G_TYPE_STRING, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING), G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (interface->priv->proxy), "UploadFinished", G_CALLBACK (upload_finished_cb), interface, NULL); dbus_g_proxy_add_signal (DBUS_G_PROXY (interface->priv->proxy), "DownloadFileProgress", G_TYPE_STRING, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING), G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (interface->priv->proxy), "DownloadFileProgress", G_CALLBACK (download_file_progress_cb), interface, NULL); dbus_g_proxy_add_signal (DBUS_G_PROXY (interface->priv->proxy), "UploadFileProgress", G_TYPE_STRING, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING), G_TYPE_INVALID); dbus_g_proxy_connect_signal (DBUS_G_PROXY (interface->priv->proxy), "UploadFileProgress", G_CALLBACK (upload_file_progress_cb), interface, NULL); } } /** * syncdaemon_status_interface_new: */ SyncdaemonStatusInterface * syncdaemon_status_interface_new (SyncdaemonDaemon *daemon) { g_return_val_if_fail (SYNCDAEMON_IS_DAEMON (daemon), NULL); return g_object_new (SYNCDAEMON_TYPE_STATUS_INTERFACE, "daemon", daemon, NULL); } /** * syncdaemon_status_interface_get_current_status: * * 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_status_interface_get_current_status (SyncdaemonStatusInterface *interface) { g_return_val_if_fail (SYNCDAEMON_IS_STATUS_INTERFACE (interface), NULL); /* Only call DBus method if we haven't got the status yet */ if (interface->priv->current_status == NULL) { GHashTable *hash; GError *error = NULL; if (dbus_g_proxy_call (DBUS_G_PROXY (interface->priv->proxy), "current_status", &error, G_TYPE_INVALID, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING), &hash, G_TYPE_INVALID)) { interface->priv->current_status = syncdaemon_status_info_new_from_hash_table (hash); g_hash_table_destroy (hash); } else { g_warning ("Error calling current_status: %s", error->message); g_error_free (error); return NULL; } } return g_object_ref (G_OBJECT (interface->priv->current_status)); } /** * syncdaemon_status_interface_get_current_downloads: * * 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_status_interface_get_current_downloads (SyncdaemonStatusInterface *interface) { GHashTableIter iter; gchar *path; SyncdaemonTransferInfo *tinfo; GSList *downloads = NULL; g_return_val_if_fail (SYNCDAEMON_IS_STATUS_INTERFACE (interface), NULL); if (interface->priv->downloads == NULL) { GSList *list; GError *error = NULL; interface->priv->downloads = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); if (!dbus_g_proxy_call (DBUS_G_PROXY (interface->priv->proxy), "current_downloads", &error, G_TYPE_INVALID, dbus_g_type_get_collection ("GSList", dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING)), &list, G_TYPE_INVALID)) { g_warning ("Error calling current_downloads: %s", error->message); g_error_free (error); return NULL; } /* Now add all downloads to our cache */ while (list != NULL) { GHashTable *hash = (GHashTable *) list->data; g_hash_table_insert (interface->priv->downloads, g_strdup (g_hash_table_lookup (hash, "path")), syncdaemon_transfer_info_new_from_hash_table (hash)); list = g_slist_remove (list, hash); g_hash_table_destroy (hash); } } /* Create list to be returned to user */ g_hash_table_iter_init (&iter, interface->priv->downloads); while (g_hash_table_iter_next (&iter, (gpointer *) &path, (gpointer *) &tinfo)) downloads = g_slist_append (downloads, tinfo); return downloads; } /** * syncdaemon_status_interface_get_current_uploads: * * 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_status_interface_get_current_uploads (SyncdaemonStatusInterface *interface) { GHashTableIter iter; gchar *path; SyncdaemonTransferInfo *tinfo; GSList *uploads = NULL; g_return_val_if_fail (SYNCDAEMON_IS_STATUS_INTERFACE (interface), NULL); if (interface->priv->uploads == NULL) { GSList *list; GError *error = NULL; interface->priv->uploads = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); if (!dbus_g_proxy_call (DBUS_G_PROXY (interface->priv->proxy), "current_uploads", &error, G_TYPE_INVALID, dbus_g_type_get_collection ("GSList", dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING)), &list, G_TYPE_INVALID)) { g_warning ("Error calling current_uploads: %s", error->message); g_error_free (error); return NULL; } /* Now add all uploads to our cache */ while (list != NULL) { GHashTable *hash = (GHashTable *) list->data; g_hash_table_insert (interface->priv->uploads, g_strdup (g_hash_table_lookup (hash, "path")), syncdaemon_transfer_info_new_from_hash_table (hash)); list = g_slist_remove (list, hash); g_hash_table_destroy (hash); } } /* Create list to be returned to user */ g_hash_table_iter_init (&iter, interface->priv->uploads); while (g_hash_table_iter_next (&iter, (gpointer *) &path, (gpointer *) &tinfo)) uploads = g_slist_append (uploads, tinfo); return uploads; }