1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of gsignond
6 * Copyright (C) 2013 Intel Corporation.
8 * Contact: Imran Zaman <imran.zaman@intel.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 #include "gsignond/gsignond-log.h"
27 #include "gsignond/gsignond-error.h"
28 #include "gsignond/gsignond-plugin-interface.h"
29 #include "common/gsignond-pipe-stream.h"
30 #include "daemon/dbus/gsignond-dbus.h"
31 #include "gsignond-plugin-remote-private.h"
32 #include "gsignond-plugin-remote.h"
43 gsignond_plugin_remote_interface_init (
44 GSignondPluginInterface *iface);
46 G_DEFINE_TYPE_WITH_CODE (GSignondPluginRemote, gsignond_plugin_remote,
47 G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (GSIGNOND_TYPE_PLUGIN,
48 gsignond_plugin_remote_interface_init));
50 #define GSIGNOND_PLUGIN_REMOTE_GET_PRIV(obj) \
51 G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_PLUGIN_REMOTE, \
52 GSignondPluginRemotePrivate)
54 #define GSIGNOND_PLUGIND_NAME "gsignond-plugind"
62 g_spawn_close_pid (pid);
64 GSignondPluginRemote *plugin = GSIGNOND_PLUGIN_REMOTE (data);
66 DBG ("Plugind(%p) with pid (%d) closed with status %d", plugin, pid,
69 if (!g_source_is_destroyed (g_main_current_source ())) {
70 if (plugin->priv->main_loop && g_main_loop_is_running (
71 plugin->priv->main_loop)) {
72 g_main_loop_quit (plugin->priv->main_loop);
74 plugin->priv->is_plugind_up = FALSE;
77 if (plugin->priv->unref_in_down_cb) {
78 plugin->priv->unref_in_down_cb = FALSE;
79 g_object_unref (plugin);
86 GIOCondition condition,
89 GSignondPluginRemote *plugin = GSIGNOND_PLUGIN_REMOTE (data);
90 DBG ("Plugind(%p) with pid (%d) status cb", plugin, plugin->priv->cpid);
92 if (plugin->priv->main_loop && g_main_loop_is_running (
93 plugin->priv->main_loop)) {
94 g_main_loop_quit (plugin->priv->main_loop);
97 if (g_io_channel_get_flags (channel) & G_IO_FLAG_IS_READABLE) {
100 gsize bytes_read = 0;
101 GIOStatus status = g_io_channel_read_chars (channel, string, 1,
102 &bytes_read, &error);
103 if (status == G_IO_STATUS_NORMAL && error == NULL) {
104 if (*string == '1') {
105 DBG ("Plugind is UP and READY");
106 plugin->priv->is_plugind_up = TRUE;
107 } else if (*string == '0') {
108 DBG ("Plugind is DOWN");
109 plugin->priv->is_plugind_up = FALSE;
113 g_error_free (error);
121 _on_loop_timeout_cb (gpointer data)
123 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (data);
125 if (g_main_loop_is_running (self->priv->main_loop)) {
126 g_main_loop_quit (self->priv->main_loop);
133 _create_main_loop_with_timeout (
134 GSignondPluginRemote *self,
135 GMainContext *context,
139 GSource *timer = g_timeout_source_new (timeout);
140 g_source_set_callback (timer, (GSourceFunc) _on_loop_timeout_cb, self,
142 //g_source_attach increments the ref count of the source
143 timer_id = g_source_attach (timer, context);
144 g_source_unref (timer);
146 self->priv->main_loop = g_main_loop_new (context, TRUE);
147 //loop has ref'd the context
149 g_main_context_unref (context);
156 GSignondPluginRemote *self)
158 if (self->priv->main_loop) {
159 g_main_loop_run (self->priv->main_loop);
160 /* attached context gets freed as well, which internally destroys all
161 * the attached sources */
162 g_main_loop_unref (self->priv->main_loop);
163 self->priv->main_loop = NULL;
168 _run_main_loop_with_timeout (
169 GSignondPluginRemote *self,
172 guint timer_id = _create_main_loop_with_timeout (self, NULL, timeout);
173 _run_main_loop (self);
174 g_source_remove (timer_id);
178 _run_main_loop_with_ready_watch (
179 GSignondPluginRemote *self,
183 GIOChannel *ready_watch = NULL;
184 GSource *up_source = NULL;
186 GMainContext *context = g_main_context_new ();
187 _create_main_loop_with_timeout (self, context, timeout);
189 ready_watch = g_io_channel_unix_new (fd);
190 up_source = g_io_create_watch (ready_watch, G_IO_IN | G_IO_HUP);
191 g_source_set_callback (up_source, (GSourceFunc)_on_child_status_cb, self,
193 g_source_attach (up_source, context);
194 g_source_unref (up_source);
196 _run_main_loop (self);
198 g_io_channel_unref (ready_watch);
202 gsignond_plugin_remote_set_property (
208 switch (property_id) {
210 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
215 gsignond_plugin_remote_get_property (
221 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (object);
223 switch (property_id) {
225 if (!self->priv->plugin_type) {
226 GError *error = NULL;
227 gsignond_dbus_remote_plugin_call_get_info_sync (
228 self->priv->dbus_plugin_proxy, &self->priv->plugin_type,
229 &self->priv->plugin_mechanisms, NULL, &error);
231 DBG ("Plugin type retrieval error :: %s", error->message);
232 g_error_free (error);
233 if (self->priv->plugin_type) {
234 g_free (self->priv->plugin_type);
235 self->priv->plugin_type = NULL;
239 g_value_set_string (value, self->priv->plugin_type);
242 case PROP_MECHANISMS: {
243 if (!self->priv->plugin_mechanisms) {
244 GError *error = NULL;
245 gsignond_dbus_remote_plugin_call_get_info_sync (
246 self->priv->dbus_plugin_proxy, &self->priv->plugin_type,
247 &self->priv->plugin_mechanisms, NULL, &error);
249 DBG ("Plugin mechanisms retrieval error :: %s",
251 g_error_free (error);
252 if (self->priv->plugin_mechanisms) {
253 g_strfreev (self->priv->plugin_mechanisms);
254 self->priv->plugin_mechanisms = NULL;
258 g_value_set_boxed (value, self->priv->plugin_mechanisms);
262 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
268 gsignond_plugin_remote_dispose (GObject *object)
270 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (object);
272 self->priv->unref_in_down_cb = FALSE;
274 if (self->priv->main_loop) {
275 if (g_main_loop_is_running (self->priv->main_loop)) {
276 g_main_loop_quit (self->priv->main_loop);
278 g_main_loop_unref (self->priv->main_loop);
279 self->priv->main_loop = NULL;
282 if (self->priv->cpid > 0 && self->priv->is_plugind_up) {
283 DBG ("Send SIGTERM to Plugind");
284 kill (self->priv->cpid, SIGTERM);
285 _run_main_loop_with_timeout (self, 1000); //1 sec
287 if (kill (self->priv->cpid, 0) == 0) {
288 WARN ("Plugind have to be killed with SIGKILL");
289 kill (self->priv->cpid, SIGKILL);
290 _run_main_loop_with_timeout (self, 1000); //1 sec
293 if (self->priv->is_plugind_up) {
294 WARN ("Plugind did not exit even after SIGKILL");
296 DBG ("Plugind DESTROYED");
299 self->priv->cpid = 0;
301 if (self->priv->child_watch_id > 0) {
302 g_source_remove (self->priv->child_watch_id);
303 self->priv->child_watch_id = 0;
306 if (self->priv->connection) {
307 g_object_unref (self->priv->connection);
308 self->priv->connection = NULL;
311 if (self->priv->dbus_plugin_proxy) {
312 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
313 self->priv->signal_response);
314 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
315 self->priv->signal_response_final);
316 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
317 self->priv->signal_store);
318 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
319 self->priv->signal_error);
320 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
321 self->priv->signal_user_action_required);
322 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
323 self->priv->signal_refreshed);
324 g_signal_handler_disconnect (self->priv->dbus_plugin_proxy,
325 self->priv->signal_status_changed);
326 g_object_unref (self->priv->dbus_plugin_proxy);
327 self->priv->dbus_plugin_proxy = NULL;
330 if (self->priv->err_watch_ch) {
331 g_io_channel_shutdown (self->priv->err_watch_ch, FALSE, NULL);
332 g_io_channel_unref (self->priv->err_watch_ch);
333 self->priv->err_watch_ch = NULL;
334 if (self->priv->err_watch_id) {
335 g_source_remove (self->priv->err_watch_id);
339 G_OBJECT_CLASS (gsignond_plugin_remote_parent_class)->dispose (object);
343 gsignond_plugin_remote_finalize (GObject *object)
345 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (object);
347 if (self->priv->plugin_type) {
348 g_free (self->priv->plugin_type);
349 self->priv->plugin_type = NULL;
352 if (self->priv->plugin_mechanisms) {
353 g_strfreev (self->priv->plugin_mechanisms);
354 self->priv->plugin_mechanisms = NULL;
357 G_OBJECT_CLASS (gsignond_plugin_remote_parent_class)->finalize (object);
361 gsignond_plugin_remote_class_init (GSignondPluginRemoteClass *klass)
363 GObjectClass* object_class = G_OBJECT_CLASS (klass);
365 g_type_class_add_private (object_class,
366 sizeof (GSignondPluginRemotePrivate));
368 object_class->get_property = gsignond_plugin_remote_get_property;
369 object_class->set_property = gsignond_plugin_remote_set_property;
370 object_class->dispose = gsignond_plugin_remote_dispose;
371 object_class->finalize = gsignond_plugin_remote_finalize;
373 g_object_class_override_property (object_class, PROP_TYPE, "type");
374 g_object_class_override_property (object_class, PROP_MECHANISMS,
380 gsignond_plugin_remote_init (GSignondPluginRemote *self)
382 self->priv = GSIGNOND_PLUGIN_REMOTE_GET_PRIV(self);
384 self->priv->connection = NULL;
385 self->priv->dbus_plugin_proxy = NULL;
386 self->priv->plugin_type = NULL;
387 self->priv->plugin_mechanisms = NULL;
388 self->priv->cpid = 0;
390 self->priv->err_watch_ch = NULL;
391 self->priv->child_watch_id = 0;
393 self->priv->main_loop = NULL;
394 self->priv->is_plugind_up = FALSE;
395 self->priv->unref_in_down_cb = FALSE;
404 GError *error = NULL;
405 GSignondDbusRemotePlugin *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN (object);
406 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
408 gsignond_dbus_remote_plugin_call_cancel_finish (proxy, res, &error);
410 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
411 g_error_free (error);
416 gsignond_plugin_remote_cancel (
417 GSignondPlugin *plugin)
419 g_return_if_fail (plugin && GSIGNOND_IS_PLUGIN_REMOTE (plugin));
420 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
422 gsignond_dbus_remote_plugin_call_cancel (
423 self->priv->dbus_plugin_proxy, NULL, _cancel_async_cb, self);
427 _request_initial_async_cb (
432 GError *error = NULL;
433 GSignondDbusRemotePlugin *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN (object);
434 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
435 gsignond_dbus_remote_plugin_call_request_initial_finish (proxy,
438 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
439 g_error_free (error);
444 gsignond_plugin_remote_request_initial (
445 GSignondPlugin *plugin,
446 GSignondSessionData *session_data,
447 GSignondDictionary *identity_method_cache,
448 const gchar *mechanism)
450 g_return_if_fail (session_data && plugin &&
451 GSIGNOND_IS_PLUGIN_REMOTE (plugin));
452 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
454 GVariant *data = gsignond_dictionary_to_variant (session_data);
456 if (identity_method_cache)
457 cache = gsignond_dictionary_to_variant (identity_method_cache);
459 GSignondDictionary* empty_cache = gsignond_dictionary_new();
460 cache = gsignond_dictionary_to_variant (empty_cache);
461 gsignond_dictionary_unref(empty_cache);
463 gsignond_dbus_remote_plugin_call_request_initial (
464 self->priv->dbus_plugin_proxy, data, cache, mechanism, NULL,
465 _request_initial_async_cb, self);
474 GError *error = NULL;
475 GSignondDbusRemotePlugin *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN (object);
476 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
478 gsignond_dbus_remote_plugin_call_request_finish (proxy, res, &error);
480 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
481 g_error_free (error);
486 gsignond_plugin_remote_request (
487 GSignondPlugin *plugin,
488 GSignondSessionData *session_data)
490 g_return_if_fail (session_data && plugin &&
491 GSIGNOND_IS_PLUGIN_REMOTE (plugin));
492 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
494 GVariant *data = gsignond_dictionary_to_variant (session_data);
495 gsignond_dbus_remote_plugin_call_request (
496 self->priv->dbus_plugin_proxy, data, NULL, _request_async_cb, self);
500 _user_action_finished_async_cb (
505 GError *error = NULL;
506 GSignondDbusRemotePlugin *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN (object);
507 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
509 gsignond_dbus_remote_plugin_call_user_action_finished_finish (proxy,
512 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
513 g_error_free (error);
518 gsignond_plugin_remote_user_action_finished (
519 GSignondPlugin *plugin,
520 GSignondSignonuiData *signonui_data)
522 g_return_if_fail (signonui_data && plugin &&
523 GSIGNOND_IS_PLUGIN_REMOTE (plugin));
524 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
526 GVariant *data = gsignond_dictionary_to_variant (signonui_data);
527 gsignond_dbus_remote_plugin_call_user_action_finished (
528 self->priv->dbus_plugin_proxy, data, NULL,
529 _user_action_finished_async_cb, self);
538 GError *error = NULL;
539 GSignondDbusRemotePlugin *proxy = GSIGNOND_DBUS_REMOTE_PLUGIN (object);
540 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (user_data);
542 gsignond_dbus_remote_plugin_call_refresh_finish (proxy, res, &error);
544 gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
545 g_error_free (error);
550 gsignond_plugin_remote_refresh (
551 GSignondPlugin *plugin,
552 GSignondSignonuiData *signonui_data)
554 g_return_if_fail (signonui_data && plugin &&
555 GSIGNOND_IS_PLUGIN_REMOTE (plugin));
556 GSignondPluginRemote *self = GSIGNOND_PLUGIN_REMOTE (plugin);
558 GVariant *data = gsignond_dictionary_to_variant (signonui_data);
559 gsignond_dbus_remote_plugin_call_refresh (
560 self->priv->dbus_plugin_proxy, data, NULL, _refresh_async_cb, self);
564 gsignond_plugin_remote_interface_init (GSignondPluginInterface *iface)
566 iface->cancel = gsignond_plugin_remote_cancel;
567 iface->request_initial = gsignond_plugin_remote_request_initial;
568 iface->request = gsignond_plugin_remote_request;
569 iface->user_action_finished = gsignond_plugin_remote_user_action_finished;
570 iface->refresh = gsignond_plugin_remote_refresh;
575 GSignondPluginRemote *self,
576 GVariant *session_data,
579 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
581 GSignondSessionData *data = (GSignondSessionData *)
582 gsignond_dictionary_new_from_variant (session_data);
583 gsignond_plugin_response (GSIGNOND_PLUGIN(self), data);
584 gsignond_dictionary_unref (data);
589 GSignondPluginRemote *self,
590 GVariant *session_data,
593 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
595 GSignondSessionData *data = (GSignondSessionData *)
596 gsignond_dictionary_new_from_variant (session_data);
597 gsignond_plugin_response_final (GSIGNOND_PLUGIN(self), data);
598 gsignond_dictionary_unref (data);
603 GSignondPluginRemote *self,
604 GVariant *session_data,
607 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
609 GSignondSessionData *data = (GSignondSessionData *)
610 gsignond_dictionary_new_from_variant (session_data);
611 gsignond_plugin_store (GSIGNOND_PLUGIN(self), data);
612 gsignond_dictionary_unref (data);
617 GSignondPluginRemote *self,
621 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
622 GError *gerror = gsignond_error_new_from_variant (error);
623 gsignond_plugin_error (GSIGNOND_PLUGIN(self), gerror);
624 g_error_free (gerror);
628 _user_action_required_cb (
629 GSignondPluginRemote *self,
633 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
635 GSignondSignonuiData *data = (GSignondSignonuiData *)
636 gsignond_dictionary_new_from_variant (ui_data);
637 gsignond_plugin_user_action_required (GSIGNOND_PLUGIN(self), data);
638 gsignond_dictionary_unref (data);
643 GSignondPluginRemote *self,
647 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
649 GSignondSignonuiData *data = (GSignondSignonuiData *)
650 gsignond_dictionary_new_from_variant (ui_data);
651 gsignond_plugin_refreshed (GSIGNOND_PLUGIN(self), data);
652 gsignond_dictionary_unref (data);
657 GSignondPluginRemote *self,
662 g_return_if_fail (self && GSIGNOND_IS_PLUGIN_REMOTE (self));
664 gsignond_plugin_status_changed (GSIGNOND_PLUGIN(self),
665 (GSignondPluginState)status, message);
668 GSignondPluginRemote *
669 gsignond_plugin_remote_new (
670 GSignondConfig *config,
671 const gchar *plugin_type)
673 GError *error = NULL;
676 gint cin_fd, cout_fd;
677 GSignondPluginRemote *plugin = NULL;
678 GSignondPipeStream *stream = NULL;
679 gboolean ret = FALSE;
681 /* This guarantees that writes to a pipe will never cause
682 * a process terminanation via SIGPIPE, and instead a proper
683 * error will be returned */
684 signal(SIGPIPE, SIG_IGN);
686 /* Spawn child process */
687 argv = g_malloc0 ((3 + 1) * sizeof (gchar *));
688 argv[0] = g_build_filename (gsignond_config_get_string (config,
689 GSIGNOND_CONFIG_GENERAL_BIN_DIR), GSIGNOND_PLUGIND_NAME, NULL);
690 argv[1] = g_module_build_path (gsignond_config_get_string (config,
691 GSIGNOND_CONFIG_GENERAL_PLUGINS_DIR), plugin_type);
692 argv[2] = g_strdup(plugin_type);
693 ret = g_spawn_async_with_pipes (NULL, argv, NULL,
694 G_SPAWN_DO_NOT_REAP_CHILD, NULL,
695 NULL, &cpid, &cin_fd, &cout_fd, NULL, &error);
697 if (ret == FALSE || (kill(cpid, 0) != 0)) {
698 DBG ("failed to start plugind: error %s(%d)",
699 error ? error->message : "(null)", ret);
700 if (error) g_error_free (error);
704 /* Create dbus plugin object */
705 plugin = GSIGNOND_PLUGIN_REMOTE (g_object_new (GSIGNOND_TYPE_PLUGIN_REMOTE,
708 plugin->priv->child_watch_id = g_child_watch_add (cpid,
709 (GChildWatchFunc)_on_child_down_cb, plugin);
710 plugin->priv->cpid = cpid;
712 _run_main_loop_with_ready_watch (plugin, cout_fd, 1000);
713 if (!plugin->priv->is_plugind_up) {
714 DBG ("Plugind (%s) with pid %d process failed to start up", plugin_type,
716 /* moved unref'ng into the cb to avoid zombies */
717 plugin->priv->unref_in_down_cb = TRUE;
721 /* Create dbus connection */
722 stream = gsignond_pipe_stream_new (cout_fd, cin_fd, TRUE);
723 plugin->priv->connection = g_dbus_connection_new_sync (G_IO_STREAM (stream),
724 NULL, G_DBUS_CONNECTION_FLAGS_NONE, NULL, NULL, NULL);
725 g_object_unref (stream);
727 /* Create dbus proxy */
728 plugin->priv->dbus_plugin_proxy =
729 gsignond_dbus_remote_plugin_proxy_new_sync (
730 plugin->priv->connection,
731 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
733 GSIGNOND_PLUGIN_OBJECTPATH,
737 DBG ("Failed to register object: %s", error->message);
738 g_error_free (error);
739 g_object_unref (plugin);
742 DBG("'%s' object exported(%p)", GSIGNOND_PLUGIN_OBJECTPATH, plugin);
744 plugin->priv->signal_response = g_signal_connect_swapped (
745 plugin->priv->dbus_plugin_proxy, "response",
746 G_CALLBACK (_response_cb), plugin);
747 plugin->priv->signal_response_final = g_signal_connect_swapped (
748 plugin->priv->dbus_plugin_proxy, "response-final",
749 G_CALLBACK(_response_final_cb), plugin);
750 plugin->priv->signal_store = g_signal_connect_swapped (
751 plugin->priv->dbus_plugin_proxy, "store",
752 G_CALLBACK(_store_cb), plugin);
753 plugin->priv->signal_error = g_signal_connect_swapped (
754 plugin->priv->dbus_plugin_proxy, "error",
755 G_CALLBACK(_error_cb), plugin);
756 plugin->priv->signal_user_action_required = g_signal_connect_swapped (
757 plugin->priv->dbus_plugin_proxy, "user-action-required",
758 G_CALLBACK(_user_action_required_cb), plugin);
759 plugin->priv->signal_refreshed = g_signal_connect_swapped (
760 plugin->priv->dbus_plugin_proxy, "refreshed",
761 G_CALLBACK(_refreshed_cb), plugin);
762 plugin->priv->signal_status_changed = g_signal_connect_swapped (
763 plugin->priv->dbus_plugin_proxy, "status-changed",
764 G_CALLBACK(_status_changed_cb), plugin);