summaryrefslogtreecommitdiff
path: root/src/applet-dbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/applet-dbus.c')
-rw-r--r--src/applet-dbus.c489
1 files changed, 489 insertions, 0 deletions
diff --git a/src/applet-dbus.c b/src/applet-dbus.c
new file mode 100644
index 00000000..9a2f07aa
--- /dev/null
+++ b/src/applet-dbus.c
@@ -0,0 +1,489 @@
+/* NetworkManager Wireless Applet -- Display wireless access points and allow user control
+ *
+ * Dan Williams <dcbw@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * (C) Copyright 2004 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include "applet.h"
+#include "applet-dbus.h"
+#include "applet-dbus-devices.h"
+#include "applet-dbus-vpn.h"
+#include "applet-dbus-info.h"
+#include "vpn-connection.h"
+#include "passphrase-dialog.h"
+#include "nm-utils.h"
+
+#define DBUS_NO_SERVICE_ERROR "org.freedesktop.DBus.Error.ServiceDoesNotExist"
+
+
+/*
+ * nma_dbus_filter
+ *
+ */
+static DBusHandlerResult nma_dbus_filter (DBusConnection *connection, DBusMessage *message, void *user_data)
+{
+ NMApplet *applet = (NMApplet *)user_data;
+ gboolean handled = TRUE;
+
+ const char * object_path;
+ const char * member;
+ const char * interface;
+
+ g_return_val_if_fail (applet != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+ g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+ g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+
+ if (!(object_path = dbus_message_get_path (message)))
+ return FALSE;
+ if (!(member = dbus_message_get_member (message)))
+ return FALSE;
+ if (!(interface = dbus_message_get_interface (message)))
+ return FALSE;
+
+ /* nm_info ("signal(): got signal op='%s' member='%s' interface='%s'", object_path, member, interface); */
+
+ if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected"))
+ {
+ dbus_connection_unref (applet->connection);
+ applet->connection = NULL;
+ nma_set_running (applet, FALSE);
+ if (!applet->connection_timeout_id)
+ nma_start_dbus_connection_watch (applet);
+ }
+ else if (dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
+ {
+ char *service;
+ char *old_owner;
+ char *new_owner;
+
+ if (dbus_message_get_args (message, NULL,
+ DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_STRING, &old_owner,
+ DBUS_TYPE_STRING, &new_owner,
+ DBUS_TYPE_INVALID))
+ {
+ if (strcmp (service, NM_DBUS_SERVICE) == 0)
+ {
+ gboolean old_owner_good = (old_owner && (strlen (old_owner) > 0));
+ gboolean new_owner_good = (new_owner && (strlen (new_owner) > 0));
+
+ if (!old_owner_good && new_owner_good && !applet->nm_running)
+ {
+ /* NetworkManager started up */
+ nma_set_running (applet, TRUE);
+ nma_set_state (applet, NM_STATE_DISCONNECTED);
+
+ nma_dbus_update_nm_state (applet);
+ nma_dbus_update_devices (applet);
+ nma_dbus_update_dialup (applet);
+ nma_dbus_vpn_update_vpn_connections (applet);
+
+ /* Immediate redraw */
+ nma_update_state (applet);
+ }
+ else if (old_owner_good && !new_owner_good)
+ {
+ nma_set_state (applet, NM_STATE_DISCONNECTED);
+ nma_set_running (applet, FALSE);
+ nmi_passphrase_dialog_destroy (applet);
+
+ /* One last redraw to capture new state before sleeping */
+ nma_update_state (applet);
+ }
+ }
+ }
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, NM_DBUS_SIGNAL_STATE_CHANGE))
+ {
+ NMState state = NM_STATE_UNKNOWN;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID))
+ {
+ NetworkDevice *act_dev = nma_get_first_active_device (applet->device_list);
+
+ /* If we've switched to connecting, update the active device to ensure that we have
+ * valid wireless network information for it.
+ */
+ if (state == NM_STATE_CONNECTING && act_dev && network_device_is_wireless (act_dev))
+ {
+ nma_dbus_device_update_one_device (applet, network_device_get_nm_path (act_dev));
+ }
+ nma_set_state (applet, state);
+ }
+ }
+ else if ( dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceAdded")
+ || dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceActivating")
+ || dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceCarrierOn")
+ || dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceCarrierOff"))
+ {
+ char *path = NULL;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
+ nma_dbus_device_update_one_device (applet, path);
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceNowActive"))
+ {
+ char *path = NULL;
+ char *essid = NULL;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_STRING, &essid, DBUS_TYPE_INVALID))
+ nma_dbus_device_activated (applet, path, essid);
+ else if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
+ nma_dbus_device_activated (applet, path, NULL);
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceNoLongerActive"))
+ {
+ char *path = NULL;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
+ nma_dbus_device_deactivated (applet, path);
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceRemoved"))
+ {
+ char *path = NULL;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
+ nma_dbus_device_remove_one_device (applet, path);
+ }
+ else if ( dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNConnectionAdded")
+ || dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNConnectionUpdate")) /* VPN connection properties changed */
+ {
+ char *name = NULL;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
+ nma_dbus_vpn_update_one_vpn_connection (applet, name);
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNConnectionStateChange")) /* Active VPN connection changed */
+ {
+ char * name = NULL;
+ NMVPNActStage vpn_stage;
+ dbus_uint32_t vpn_stage_int;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT32, &vpn_stage_int, DBUS_TYPE_INVALID))
+ {
+ vpn_stage = (NMVPNActStage) vpn_stage_int;
+ nma_dbus_vpn_update_vpn_connection_stage (applet, name, vpn_stage);
+ }
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, "VPNConnectionRemoved"))
+ {
+ char *name = NULL;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
+ nma_dbus_vpn_remove_one_vpn_connection (applet, name);
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "WirelessNetworkAppeared"))
+ {
+ char *dev_path = NULL;
+ char *net_path = NULL;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_OBJECT_PATH, &net_path, DBUS_TYPE_INVALID))
+ nma_dbus_device_update_one_network (applet, dev_path, net_path, NULL);
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "WirelessNetworkDisappeared"))
+ {
+ char *dev_path = NULL;
+ char *net_path = NULL;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_OBJECT_PATH, &net_path, DBUS_TYPE_INVALID))
+ nma_dbus_device_remove_one_network (applet, dev_path, net_path);
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "WirelessNetworkStrengthChanged"))
+ {
+ char * dev_path = NULL;
+ char * net_path = NULL;
+ int strength = -1;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_OBJECT_PATH, &net_path, DBUS_TYPE_INT32, &strength, DBUS_TYPE_INVALID))
+ nma_dbus_update_strength (applet, dev_path, net_path, strength);
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceStrengthChanged"))
+ {
+ char *dev_path = NULL;
+ int strength = -1;
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_INT32, &strength, DBUS_TYPE_INVALID))
+ nma_dbus_update_strength (applet, dev_path, NULL, strength);
+ }
+ else if ( dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, NM_DBUS_VPN_SIGNAL_LOGIN_FAILED)
+ || dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, NM_DBUS_VPN_SIGNAL_LAUNCH_FAILED)
+ || dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, NM_DBUS_VPN_SIGNAL_CONNECT_FAILED)
+ || dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, NM_DBUS_VPN_SIGNAL_VPN_CONFIG_BAD)
+ || dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, NM_DBUS_VPN_SIGNAL_IP_CONFIG_BAD))
+ {
+ char *vpn_name;
+ char *error_msg;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &error_msg, DBUS_TYPE_INVALID)) {
+ nma_show_vpn_failure_alert (applet, member, vpn_name, error_msg);
+ /* clear the 'last_attempt_success' key in gconf so we prompt for password next time */
+ nma_dbus_vpn_set_last_attempt_status (applet, vpn_name, FALSE);
+ }
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_VPN, NM_DBUS_VPN_SIGNAL_LOGIN_BANNER))
+ {
+ char *vpn_name;
+ char *banner;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &vpn_name, DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID))
+ {
+ char *stripped = g_strstrip (g_strdup (banner));
+
+ nma_show_vpn_login_banner (applet, vpn_name, stripped);
+ g_free (stripped);
+
+ /* set the 'last_attempt_success' key in gconf so we DON'T prompt for password next time */
+ nma_dbus_vpn_set_last_attempt_status (applet, vpn_name, TRUE);
+ }
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceActivationFailed"))
+ {
+ char *dev = NULL;
+ char *net = NULL;
+
+ if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &dev, DBUS_TYPE_STRING, &net, DBUS_TYPE_INVALID))
+ dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &dev, DBUS_TYPE_INVALID);
+
+ if (dev && net)
+ {
+ char *string = g_strdup_printf (_("Connection to the wireless network '%s' failed."), net);
+ nma_schedule_warning_dialog (applet, string);
+ g_free (string);
+ }
+ else if (dev)
+ nma_schedule_warning_dialog (applet, _("Connection to the wired network failed."));
+ }
+ else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE, "DeviceActivationStage"))
+ {
+ char * dev_path = NULL;
+ NMActStage stage;
+
+ if (dbus_message_get_args (message, NULL, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_UINT32, &stage, DBUS_TYPE_INVALID))
+ {
+ NetworkDevice *dev;
+
+ if ((dev = nma_get_device_for_nm_path (applet->device_list, dev_path)))
+ network_device_set_act_stage (dev, stage);
+ }
+ }
+ else
+ handled = FALSE;
+
+ return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+}
+
+
+/*
+ * nma_dbus_nm_is_running
+ *
+ * Ask dbus whether or not NetworkManager is running
+ *
+ */
+static gboolean nma_dbus_nm_is_running (DBusConnection *connection)
+{
+ DBusError error;
+ gboolean exists;
+
+ g_return_val_if_fail (connection != NULL, FALSE);
+
+ dbus_error_init (&error);
+ exists = dbus_bus_name_has_owner (connection, NM_DBUS_SERVICE, &error);
+ if (dbus_error_is_set (&error))
+ dbus_error_free (&error);
+ return (exists);
+}
+
+
+/*
+ * nma_dbus_init
+ *
+ * Initialize a connection to NetworkManager if we can get one
+ *
+ */
+static DBusConnection * nma_dbus_init (NMApplet *applet)
+{
+ DBusConnection * connection = NULL;
+ DBusError error;
+ DBusObjectPathVTable vtable = { NULL, &nmi_dbus_info_message_handler, NULL, NULL, NULL, NULL };
+ int acquisition;
+ dbus_bool_t success = FALSE;
+
+ g_return_val_if_fail (applet != NULL, NULL);
+
+ dbus_error_init (&error);
+ connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+ if (dbus_error_is_set (&error)) {
+ nm_warning ("%s raised:\n %s\n\n", error.name, error.message);
+ goto error;
+ }
+
+ dbus_error_init (&error);
+ acquisition = dbus_bus_request_name (connection,
+ NMI_DBUS_SERVICE,
+ DBUS_NAME_FLAG_REPLACE_EXISTING,
+ &error);
+ if (dbus_error_is_set (&error)) {
+ nm_warning ("could not acquire its service. dbus_bus_acquire_service()"
+ " says: '%s'",
+ error.message);
+ goto error;
+ }
+ if (acquisition == DBUS_REQUEST_NAME_REPLY_EXISTS)
+ goto error;
+
+ success = dbus_connection_register_object_path (connection,
+ NMI_DBUS_PATH,
+ &vtable,
+ applet);
+ if (!success) {
+ nm_warning ("could not register a messgae handler for the"
+ " NetworkManagerInfo service. Not enough memory?");
+ goto error;
+ }
+
+ success = dbus_connection_add_filter (connection, nma_dbus_filter, applet, NULL);
+ if (!success)
+ goto error;
+
+ dbus_connection_set_exit_on_disconnect (connection, FALSE);
+ dbus_connection_setup_with_g_main (connection, NULL);
+
+ dbus_error_init (&error);
+ dbus_bus_add_match(connection,
+ "type='signal',"
+ "interface='" DBUS_INTERFACE_DBUS "',"
+ "sender='" DBUS_SERVICE_DBUS "'",
+ &error);
+ if (dbus_error_is_set (&error)) {
+ nm_warning ("Could not register signal handlers. '%s'",
+ error.message);
+ goto error;
+ }
+
+ dbus_error_init (&error);
+ dbus_bus_add_match(connection,
+ "type='signal',"
+ "interface='" NM_DBUS_INTERFACE "',"
+ "path='" NM_DBUS_PATH "',"
+ "sender='" NM_DBUS_SERVICE "'",
+ &error);
+ if (dbus_error_is_set (&error)) {
+ nm_warning ("Could not register signal handlers. '%s'",
+ error.message);
+ goto error;
+ }
+
+ dbus_error_init (&error);
+ dbus_bus_add_match(connection,
+ "type='signal',"
+ "interface='" NM_DBUS_INTERFACE_VPN "',"
+ "path='" NM_DBUS_PATH_VPN "',"
+ "sender='" NM_DBUS_SERVICE "'",
+ &error);
+ if (dbus_error_is_set (&error)) {
+ nm_warning ("Could not register signal handlers. '%s'",
+ error.message);
+ goto error;
+ }
+
+ return connection;
+
+error:
+ if (dbus_error_is_set (&error))
+ dbus_error_free (&error);
+ if (connection)
+ dbus_connection_unref (connection);
+ return NULL;
+}
+
+
+/*
+ * nma_dbus_connection_watcher
+ *
+ * Try to reconnect if we ever get disconnected from the bus
+ *
+ */
+static gboolean
+nma_dbus_connection_watcher (gpointer user_data)
+{
+ NMApplet * applet = (NMApplet *)user_data;
+
+ g_return_val_if_fail (applet != NULL, TRUE);
+
+ nma_dbus_init_helper (applet);
+ if (applet->connection) {
+ applet->connection_timeout_id = 0;
+ return FALSE; /* Remove timeout */
+ }
+
+ return TRUE;
+}
+
+
+void
+nma_start_dbus_connection_watch (NMApplet *applet)
+{
+ if (applet->connection_timeout_id)
+ g_source_remove (applet->connection_timeout_id);
+
+ applet->connection_timeout_id = g_timeout_add (5000,
+ (GSourceFunc) nma_dbus_connection_watcher,
+ applet);
+}
+
+
+/*
+ * nma_dbus_init_helper
+ *
+ * Set up the applet's NMI dbus methods and dbus connection
+ *
+ */
+void
+nma_dbus_init_helper (NMApplet *applet)
+{
+ g_return_if_fail (applet != NULL);
+
+ applet->connection = nma_dbus_init (applet);
+ if (applet->connection) {
+ if (applet->connection_timeout_id) {
+ g_source_remove (applet->connection_timeout_id);
+ applet->connection_timeout_id = 0;
+ }
+
+ if (nma_dbus_nm_is_running (applet->connection)) {
+ nma_set_running (applet, TRUE);
+ nma_dbus_update_nm_state (applet);
+ nma_dbus_update_devices (applet);
+ nma_dbus_update_dialup (applet);
+ nma_dbus_vpn_update_vpn_connections (applet);
+
+ /* Immediate redraw */
+ nma_update_state (applet);
+ }
+ }
+}