/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ /* NetworkManager Wireless Applet -- Display wireless access points and allow user control * * Dan Williams * * 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-2005 Red Hat, Inc. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "applet-dbus-devices.h" #include "applet-dbus.h" #include "applet.h" #include "vpn-connection.h" #include "nm-utils.h" void nmwa_dbus_devices_schedule_copy (NMWirelessApplet *applet); /* * nmwa_dbus_get_active_device_cb * * Callback from nmwa_dbus_get_active_device * */ void nmwa_dbus_get_active_device_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; NMWirelessApplet * applet = (NMWirelessApplet *) user_data; const char * act_dev; g_return_if_fail (pcall != NULL); g_return_if_fail (applet != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (dbus_message_is_error (reply, NM_DBUS_NO_ACTIVE_DEVICE_ERROR)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &act_dev, DBUS_TYPE_INVALID)) { g_free (applet->dbus_active_device_path); applet->dbus_active_device_path = g_strdup (act_dev); } dbus_message_unref (reply); out: applet->dev_pending_call_list = g_slist_remove (applet->dev_pending_call_list, pcall); nmwa_dbus_devices_schedule_copy (applet); dbus_pending_call_unref (pcall); } /* * nmwa_dbus_get_active_device * * Get the active device from NetworkManager * */ void nmwa_dbus_get_active_device (NMWirelessApplet *applet) { DBusMessage * message; DBusPendingCall * pcall = NULL; g_return_if_fail (applet != NULL); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "getActiveDevice"))) { dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) { dbus_pending_call_set_notify (pcall, nmwa_dbus_get_active_device_cb, applet, NULL); applet->dev_pending_call_list = g_slist_append (applet->dev_pending_call_list, pcall); } } } /* * nmwa_dbus_nm_state_cb * * Callback from nmwa_dbus_update_nm_state * */ void nmwa_dbus_nm_state_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; NMWirelessApplet * applet = (NMWirelessApplet *) user_data; NMState nm_state; g_return_if_fail (pcall != NULL); g_return_if_fail (applet != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (message_is_error (reply)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &nm_state, DBUS_TYPE_INVALID)) { applet->dbus_nm_state = nm_state; applet->gui_nm_state = nm_state; } dbus_message_unref (reply); out: applet->dev_pending_call_list = g_slist_remove (applet->dev_pending_call_list, pcall); nmwa_dbus_devices_schedule_copy (applet); dbus_pending_call_unref (pcall); } /* * nmwa_dbus_update_nm_state * * Update internal applet state from NetworkManager state * */ void nmwa_dbus_update_nm_state (NMWirelessApplet *applet) { DBusMessage * message; DBusPendingCall * pcall = NULL; g_return_if_fail (applet != NULL); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "state"))) { dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) { dbus_pending_call_set_notify (pcall, nmwa_dbus_nm_state_cb, applet, NULL); applet->dev_pending_call_list = g_slist_append (applet->dev_pending_call_list, pcall); } } } /* * nmwa_dbus_update_scanning_enabled_cb * * Callback from nmwa_dbus_update_scanning_enabled * */ void nmwa_dbus_update_scanning_enabled_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; NMWirelessApplet * applet = (NMWirelessApplet *) user_data; gboolean scanning_enabled; g_return_if_fail (pcall != NULL); g_return_if_fail (applet != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (message_is_error (reply)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_BOOLEAN, &scanning_enabled, DBUS_TYPE_INVALID)) applet->scanning_enabled = scanning_enabled; dbus_message_unref (reply); out: dbus_pending_call_unref (pcall); } /* * nmwa_dbus_update_scanning_enabled * * Get the scanning_enabled value from NetworkManager * */ void nmwa_dbus_update_scanning_enabled (NMWirelessApplet *applet) { DBusMessage * message; DBusPendingCall * pcall = NULL; g_return_if_fail (applet != NULL); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "getScanningEnabled"))) { dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) dbus_pending_call_set_notify (pcall, nmwa_dbus_update_scanning_enabled_cb, applet, NULL); } } /* * nmwa_dbus_update_wireless_enabled_cb * * Callback from nmwa_dbus_update_wireless_enabled * */ void nmwa_dbus_update_wireless_enabled_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; NMWirelessApplet * applet = (NMWirelessApplet *) user_data; gboolean wireless_enabled; g_return_if_fail (pcall != NULL); g_return_if_fail (applet != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (message_is_error (reply)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_BOOLEAN, &wireless_enabled, DBUS_TYPE_INVALID)) applet->wireless_enabled = wireless_enabled; dbus_message_unref (reply); out: dbus_pending_call_unref (pcall); } /* * nmwa_dbus_update_wireless_enabled * * Get the wireless_enabled value from NetworkManager * */ void nmwa_dbus_update_wireless_enabled (NMWirelessApplet *applet) { DBusMessage * message; DBusPendingCall * pcall = NULL; g_return_if_fail (applet != NULL); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "getWirelessEnabled"))) { dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) dbus_pending_call_set_notify (pcall, nmwa_dbus_update_wireless_enabled_cb, applet, NULL); } } /* * nmwa_dbus_get_hal_device_string_property * * Get a string property from a device * */ static char *nmwa_dbus_get_hal_device_string_property (DBusConnection *connection, const char *udi, const char *property_name) { DBusError error; DBusMessage *message; DBusMessage *reply; char *dbus_property = NULL; char *property = NULL; g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (udi != NULL, NULL); if (!(message = dbus_message_new_method_call ("org.freedesktop.Hal", udi, "org.freedesktop.Hal.Device", "GetPropertyString"))) return (NULL); dbus_error_init (&error); dbus_message_append_args (message, DBUS_TYPE_STRING, &property_name, DBUS_TYPE_INVALID); reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); dbus_message_unref (message); if (dbus_error_is_set (&error)) { nm_warning ("nmwa_dbus_get_hal_device_string_property(): %s raised:\n %s\n\n", error.name, error.message); dbus_error_free (&error); return (NULL); } if (reply == NULL) { nm_warning ("nmwa_dbus_get_hal_device_string_property(): dbus reply message was NULL\n" ); return (NULL); } dbus_error_init (&error); if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &dbus_property, DBUS_TYPE_INVALID)) { if (dbus_error_is_set (&error)) dbus_error_free (&error); } else property = g_strdup (dbus_property); dbus_message_unref (reply); return (property); } typedef struct HalInfoCBData { NMWirelessApplet * applet; NetworkDevice * dev; char * parent_op; char * vendor; } HalInfoCBData; void free_hal_info_cb_data (HalInfoCBData *cb_data) { if (cb_data) { network_device_unref (cb_data->dev); g_free (cb_data->parent_op); g_free (cb_data->vendor); memset (cb_data, 0, sizeof (HalInfoCBData)); g_free (cb_data); } } /* * hal_info_product_cb * * hal_info_vendor callback * */ static void hal_info_product_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; HalInfoCBData * cb_data = (HalInfoCBData *) user_data; char * info_product; g_return_if_fail (pcall != NULL); g_return_if_fail (cb_data != NULL); g_return_if_fail (cb_data->applet != NULL); g_return_if_fail (cb_data->dev != NULL); g_return_if_fail (cb_data->parent_op != NULL); g_return_if_fail (cb_data->vendor != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (message_is_error (reply)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &info_product, DBUS_TYPE_INVALID)) { char *desc = g_strdup_printf ("%s %s", cb_data->vendor, info_product); network_device_set_desc (cb_data->dev, desc); } dbus_message_unref (reply); out: cb_data->applet->dev_pending_call_list = g_slist_remove (cb_data->applet->dev_pending_call_list, pcall); nmwa_dbus_devices_schedule_copy (cb_data->applet); dbus_pending_call_unref (pcall); } /* * hal_info_vendor_cb * * hal_info_parent callback * */ static void hal_info_vendor_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; HalInfoCBData * cb_data = (HalInfoCBData *) user_data; char * info_vendor; g_return_if_fail (pcall != NULL); g_return_if_fail (cb_data != NULL); g_return_if_fail (cb_data->applet != NULL); g_return_if_fail (cb_data->dev != NULL); g_return_if_fail (cb_data->parent_op != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (message_is_error (reply)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &info_vendor, DBUS_TYPE_INVALID)) { DBusMessage * message; DBusPendingCall * product_pcall = NULL; if ((message = dbus_message_new_method_call ("org.freedesktop.Hal", cb_data->parent_op, "org.freedesktop.Hal.Device", "GetPropertyString"))) { const char * prop = "info.product"; dbus_message_append_args (message, DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID); dbus_connection_send_with_reply (cb_data->applet->connection, message, &product_pcall, -1); dbus_message_unref (message); if (product_pcall) { HalInfoCBData * product_cb_data = g_malloc0 (sizeof (HalInfoCBData)); product_cb_data->applet = cb_data->applet; network_device_ref (cb_data->dev); product_cb_data->dev = cb_data->dev; product_cb_data->parent_op = g_strdup (cb_data->parent_op); product_cb_data->vendor = g_strdup (info_vendor); dbus_pending_call_set_notify (product_pcall, hal_info_product_cb, product_cb_data, (DBusFreeFunction) free_hal_info_cb_data); cb_data->applet->dev_pending_call_list = g_slist_append (cb_data->applet->dev_pending_call_list, product_pcall); } } } dbus_message_unref (reply); out: cb_data->applet->dev_pending_call_list = g_slist_remove (cb_data->applet->dev_pending_call_list, pcall); nmwa_dbus_devices_schedule_copy (cb_data->applet); dbus_pending_call_unref (pcall); } /* * hal_info_parent_cb * * nmwa_dbus_update_device_info_from_hal callback * */ static void hal_info_parent_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; HalInfoCBData * cb_data = (HalInfoCBData *) user_data; char * op; g_return_if_fail (pcall != NULL); g_return_if_fail (cb_data != NULL); g_return_if_fail (cb_data->applet != NULL); g_return_if_fail (cb_data->dev != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (message_is_error (reply)) { dbus_message_unref (reply); goto out; } /* Grab the object path of the parent item of this "Network Interface" */ if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &op, DBUS_TYPE_INVALID)) { DBusMessage * message; DBusPendingCall * vendor_pcall = NULL; if ((message = dbus_message_new_method_call ("org.freedesktop.Hal", op, "org.freedesktop.Hal.Device", "GetPropertyString"))) { const char * prop = "info.vendor"; dbus_message_append_args (message, DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID); dbus_connection_send_with_reply (cb_data->applet->connection, message, &vendor_pcall, -1); dbus_message_unref (message); if (vendor_pcall) { HalInfoCBData * vendor_cb_data = g_malloc0 (sizeof (HalInfoCBData)); vendor_cb_data->applet = cb_data->applet; network_device_ref (cb_data->dev); vendor_cb_data->dev = cb_data->dev; vendor_cb_data->parent_op = g_strdup (op); dbus_pending_call_set_notify (vendor_pcall, hal_info_vendor_cb, vendor_cb_data, (DBusFreeFunction) free_hal_info_cb_data); cb_data->applet->dev_pending_call_list = g_slist_append (cb_data->applet->dev_pending_call_list, vendor_pcall); } } } dbus_message_unref (reply); out: cb_data->applet->dev_pending_call_list = g_slist_remove (cb_data->applet->dev_pending_call_list, pcall); nmwa_dbus_devices_schedule_copy (cb_data->applet); dbus_pending_call_unref (pcall); } /* * nmwa_dbus_update_device_info_from_hal * * Grab the info.product tag from hal for a specific UDI * */ static void nmwa_dbus_update_device_info_from_hal (NetworkDevice *dev, NMWirelessApplet *applet) { DBusMessage * message; DBusPendingCall * pcall = NULL; g_return_if_fail (applet != NULL); g_return_if_fail (applet->connection != NULL); g_return_if_fail (dev != NULL); if ((message = dbus_message_new_method_call ("org.freedesktop.Hal", network_device_get_hal_udi (dev), "org.freedesktop.Hal.Device", "GetPropertyString"))) { const char * prop = "info.parent"; dbus_message_append_args (message, DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID); dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) { HalInfoCBData * cb_data = g_malloc0 (sizeof (HalInfoCBData)); cb_data->applet = applet; network_device_ref (dev); cb_data->dev = dev; dbus_pending_call_set_notify (pcall, hal_info_parent_cb, cb_data, (DBusFreeFunction) free_hal_info_cb_data); applet->dev_pending_call_list = g_slist_append (applet->dev_pending_call_list, pcall); } } } void nmwa_free_gui_data_model (NMWirelessApplet *applet) { g_return_if_fail (applet != NULL); if (applet->gui_device_list) { g_slist_foreach (applet->gui_device_list, (GFunc) network_device_unref, NULL); g_slist_free (applet->gui_device_list); applet->gui_device_list = NULL; } if (applet->gui_active_device) { network_device_unref (applet->gui_active_device); applet->gui_active_device = NULL; } } void nmwa_free_dbus_data_model (NMWirelessApplet *applet) { GSList *elt; g_return_if_fail (applet != NULL); if (applet->dbus_device_list) { g_slist_foreach (applet->dbus_device_list, (GFunc) network_device_unref, NULL); g_slist_free (applet->dbus_device_list); applet->dbus_device_list = NULL; } if (applet->dbus_active_device) { network_device_unref (applet->dbus_active_device); applet->dbus_active_device = NULL; } g_free (applet->dbus_active_device_path); applet->dbus_active_device_path = NULL; } /* * nmwa_copy_data_model * * Copy the dbus data model over to the gui data model * */ void nmwa_copy_data_model (NMWirelessApplet *applet) { GSList *elt; NetworkDevice *act_dev = NULL; g_return_if_fail (applet != NULL); /* Free the existing GUI data model. */ nmwa_free_gui_data_model (applet); /* Deep-copy network devices to GUI data model */ for (elt = applet->dbus_device_list; elt; elt = g_slist_next (elt)) { NetworkDevice *src = (NetworkDevice *)(elt->data); NetworkDevice *dst = network_device_copy (src); if (dst) { /* Transfer ownership of device to list, don't need to unref it */ applet->gui_device_list = g_slist_append (applet->gui_device_list, dst); /* Make sure we get the right active device for the gui data model */ if (applet->dbus_active_device == src) { network_device_ref (dst); act_dev = dst; } } } /* active_device is just a pointer into the device list, no need to deep-copy it */ applet->gui_active_device = act_dev; applet->gui_nm_state = applet->dbus_nm_state; } /* * nmwa_dbus_schedule_driver_notification * * Schedule the driver notification routine to run in the main loop. * */ void nmwa_dbus_schedule_driver_notification (NMWirelessApplet *applet, NetworkDevice *dev) { DriverNotifyCBData *cb_data; g_return_if_fail (applet != NULL); g_return_if_fail (dev != NULL); cb_data = g_malloc0 (sizeof (DriverNotifyCBData)); cb_data->applet = applet; network_device_ref (dev); cb_data->dev = dev; g_idle_add (nmwa_driver_notify, (gpointer)cb_data); } /* * nmwa_dbus_check_drivers * * If a device got added, we notify the user if the device's driver * has any problems (no carrier detect, no wireless scanning, etc). * */ void nmwa_dbus_check_drivers (NMWirelessApplet *applet) { GSList *elt; g_return_if_fail (applet != NULL); /* For every device that's in the dbus data model but not in * the gui data model, signal the user. */ for (elt = applet->dbus_device_list; elt; elt = g_slist_next (elt)) { NetworkDevice *dbus_dev = (NetworkDevice *)(elt->data); GSList *elt2; gboolean found = FALSE; for (elt2 = applet->gui_device_list; elt2; elt2 = g_slist_next (elt2)) { NetworkDevice *gui_dev = (NetworkDevice *)(elt2->data); if ( !nm_null_safe_strcmp (network_device_get_iface (dbus_dev), network_device_get_iface (gui_dev)) && !nm_null_safe_strcmp (network_device_get_address (dbus_dev), network_device_get_address (gui_dev)) && !nm_null_safe_strcmp (network_device_get_hal_udi (dbus_dev), network_device_get_hal_udi (gui_dev))) { found = TRUE; break; } } if ( !found && ( (network_device_get_driver_support_level (dbus_dev) == NM_DRIVER_NO_CARRIER_DETECT) || (network_device_get_driver_support_level (dbus_dev) == NM_DRIVER_NO_WIRELESS_SCAN))) nmwa_dbus_schedule_driver_notification (applet, dbus_dev); } } typedef struct NetPropCBData { char * dev_op; char * act_net; NMWirelessApplet * applet; } NetPropCBData; void free_net_prop_cb_data (NetPropCBData *data) { if (data) { g_free (data->dev_op); g_free (data->act_net); } g_free (data); } /* * nmwa_dbus_net_properties_cb * * Callback for each network we called "getProperties" on in nmwa_dbus_device_properties_cb(). * */ void nmwa_dbus_net_properties_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; NetPropCBData * cb_data = (NetPropCBData *) user_data; NMWirelessApplet * applet; const char * op = NULL; const char * essid = NULL; const char * hw_addr = NULL; dbus_int32_t strength = -1; double freq = 0; dbus_int32_t rate = 0; dbus_bool_t enc = FALSE; dbus_uint32_t mode = 0; g_return_if_fail (pcall != NULL); g_return_if_fail (cb_data != NULL); g_return_if_fail (cb_data->applet != NULL); g_return_if_fail (cb_data->dev_op != NULL); applet = cb_data->applet; dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (dbus_message_is_error (reply, NM_DBUS_NO_NETWORKS_ERROR)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_STRING, &essid, DBUS_TYPE_STRING, &hw_addr, DBUS_TYPE_INT32, &strength, DBUS_TYPE_DOUBLE, &freq, DBUS_TYPE_INT32, &rate, DBUS_TYPE_BOOLEAN,&enc, DBUS_TYPE_UINT32, &mode, DBUS_TYPE_INVALID)) { NetworkDevice * dev; if ((dev = nmwa_get_device_for_nm_device (applet->dbus_device_list, cb_data->dev_op))) { WirelessNetwork * net = wireless_network_new (essid, op); WirelessNetwork * tmp_net; char * act_net = cb_data->act_net ? g_strdup (cb_data->act_net) : NULL; /* Remove any existing wireless network with this object path */ if ((tmp_net = network_device_get_wireless_network_by_nm_path (dev, op))) { if (!act_net && wireless_network_get_active (tmp_net)) act_net = g_strdup (wireless_network_get_nm_path (tmp_net)); network_device_remove_wireless_network (dev, tmp_net); } wireless_network_set_encrypted (net, enc); wireless_network_set_strength (net, strength); if (act_net && strlen (act_net) && (strcmp (act_net, op) == 0)) wireless_network_set_active (net, TRUE); network_device_add_wireless_network (dev, net); g_free (act_net); } } dbus_message_unref (reply); out: applet->dev_pending_call_list = g_slist_remove (applet->dev_pending_call_list, pcall); nmwa_dbus_devices_schedule_copy (applet); dbus_pending_call_unref (pcall); } /* * nmwa_dbus_device_update_one_network * * Get properties on just one wireless network. * */ void nmwa_dbus_device_update_one_network (NMWirelessApplet *applet, const char *dev_path, const char *net_path, const char *active_net_path) { DBusMessage * message; DBusPendingCall * pcall = NULL; g_return_if_fail (applet != NULL); g_return_if_fail (dev_path != NULL); g_return_if_fail (net_path != NULL); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, net_path, NM_DBUS_INTERFACE_DEVICES, "getProperties"))) { dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) { NetPropCBData * cb_data = g_malloc0 (sizeof (NetPropCBData)); cb_data->dev_op = g_strdup (dev_path); cb_data->act_net = (active_net_path && strlen (active_net_path)) ? g_strdup (active_net_path) : NULL; cb_data->applet = applet; dbus_pending_call_set_notify (pcall, nmwa_dbus_net_properties_cb, cb_data, (DBusFreeFunction) free_net_prop_cb_data); applet->dev_pending_call_list = g_slist_append (applet->dev_pending_call_list, pcall); } } } /* * nmwa_dbus_device_remove_one_network * * Remove a wireless network from a device. * */ void nmwa_dbus_device_remove_one_network (NMWirelessApplet *applet, const char *dev_path, const char *net_path) { NetworkDevice * dev; g_return_if_fail (applet != NULL); g_return_if_fail (dev_path != NULL); g_return_if_fail (net_path != NULL); if ((dev = nmwa_get_device_for_nm_device (applet->dbus_device_list, dev_path))) { WirelessNetwork * net; if ((net = network_device_get_wireless_network_by_nm_path (dev, net_path))) { network_device_remove_wireless_network (dev, net); nmwa_dbus_devices_schedule_copy (applet); } } } /* * nmwa_dbus_device_properties_cb * * Callback for each device we called "getProperties" on in nmwa_dbus_update_devices_cb(). * */ void nmwa_dbus_device_properties_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; NMWirelessApplet * applet = (NMWirelessApplet *) user_data; char * op = NULL; const char * iface = NULL; dbus_uint32_t type = 0; const char * udi = NULL; dbus_uint32_t ip4_address = 0; const char * hw_addr = NULL; dbus_uint32_t mode = 0; dbus_int32_t strength = -1; char * active_network_path = NULL; dbus_bool_t link_active = FALSE; dbus_uint32_t driver_support_level = 0; char ** networks = NULL; int num_networks = 0; g_return_if_fail (pcall != NULL); g_return_if_fail (applet != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &op, DBUS_TYPE_STRING, &iface, DBUS_TYPE_UINT32, &type, DBUS_TYPE_STRING, &udi, DBUS_TYPE_UINT32, &ip4_address, DBUS_TYPE_STRING, &hw_addr, DBUS_TYPE_UINT32, &mode, DBUS_TYPE_INT32, &strength, DBUS_TYPE_BOOLEAN,&link_active, DBUS_TYPE_UINT32, &driver_support_level, DBUS_TYPE_STRING, &active_network_path, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &networks, &num_networks, DBUS_TYPE_INVALID)) { NetworkDevice *dev = network_device_new (iface, type, op); NetworkDevice *tmp_dev = nmwa_get_device_for_nm_device (applet->dbus_device_list, op); network_device_set_hal_udi (dev, udi); network_device_set_address (dev, hw_addr); network_device_set_link (dev, link_active); network_device_set_driver_support_level (dev, driver_support_level); /* If the device already exists in our list for some reason, remove it so we * can add the new one with updated data. */ if (tmp_dev) { applet->dbus_device_list = g_slist_remove (applet->dbus_device_list, tmp_dev); network_device_unref (tmp_dev); } applet->dbus_device_list = g_slist_append (applet->dbus_device_list, dev); nmwa_dbus_update_device_info_from_hal (dev, applet); if (type == DEVICE_TYPE_WIRELESS_ETHERNET) { network_device_set_strength (dev, strength); /* Call the "getProperties" method on each wireless network the device may have. */ if (num_networks > 0) { char ** item; for (item = networks; *item; item++) nmwa_dbus_device_update_one_network (applet, op, *item, active_network_path); } } dbus_free_string_array (networks); } dbus_message_unref (reply); out: applet->dev_pending_call_list = g_slist_remove (applet->dev_pending_call_list, pcall); nmwa_dbus_devices_schedule_copy (applet); dbus_pending_call_unref (pcall); } /* * nmwa_dbus_device_update_one_device * * Get properties on just one device. * */ void nmwa_dbus_device_update_one_device (NMWirelessApplet *applet, const char *dev_path) { DBusMessage * message; DBusPendingCall * pcall = NULL; g_return_if_fail (applet != NULL); g_return_if_fail (dev_path != NULL); nmwa_dbus_get_active_device (applet); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, dev_path, NM_DBUS_INTERFACE_DEVICES, "getProperties"))) { dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) { dbus_pending_call_set_notify (pcall, nmwa_dbus_device_properties_cb, applet, NULL); applet->dev_pending_call_list = g_slist_append (applet->dev_pending_call_list, pcall); } } } /* * nmwa_dbus_update_devices_cb * * nmwa_dbus_update_devices callback. * */ void nmwa_dbus_update_devices_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; NMWirelessApplet * applet = (NMWirelessApplet *) user_data; char ** devices; int num_devices; g_return_if_fail (pcall != NULL); g_return_if_fail (applet != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (dbus_message_is_error (reply, NM_DBUS_NO_DEVICES_ERROR)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &devices, &num_devices, DBUS_TYPE_INVALID)) { char ** item; /* For each device, fire off a "getProperties" call */ for (item = devices; *item; item++) nmwa_dbus_device_update_one_device (applet, *item); dbus_free_string_array (devices); } dbus_message_unref (reply); out: dbus_pending_call_unref (pcall); } /* * nmwa_dbus_update_devices * * Do a full update of network devices and wireless networks. * */ void nmwa_dbus_update_devices (NMWirelessApplet *applet) { DBusMessage * message; DBusPendingCall * pcall; g_return_if_fail (applet->data_mutex != NULL); nmwa_free_dbus_data_model (applet); nmwa_dbus_get_active_device (applet); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "getDevices"))) { dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) dbus_pending_call_set_notify (pcall, nmwa_dbus_update_devices_cb, applet, NULL); } nmwa_dbus_update_scanning_enabled (applet); nmwa_dbus_update_wireless_enabled (applet); } /* * nmwa_dbus_device_remove_one_device * * Remove a device from our list. * */ void nmwa_dbus_device_remove_one_device (NMWirelessApplet *applet, const char *dev_path) { NetworkDevice * dev; g_return_if_fail (applet != NULL); if ((dev = nmwa_get_device_for_nm_device (applet->dbus_device_list, dev_path))) { applet->dbus_device_list = g_slist_remove (applet->dbus_device_list, dev); network_device_unref (dev); nmwa_dbus_devices_schedule_copy (applet); } } /* * nmwa_dbus_set_device * * Tell NetworkManager to use a specific network device that the user picked, and * possibly a specific wireless network too. * */ void nmwa_dbus_set_device (DBusConnection *connection, NetworkDevice *dev, const char *essid, NMEncKeyType key_type, const char *passphrase) { DBusMessage *message; g_return_if_fail (connection != NULL); g_return_if_fail (dev != NULL); if ((network_device_get_type (dev) == DEVICE_TYPE_WIRED_ETHERNET) && !passphrase && (key_type != -1)) return; if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "setActiveDevice"))) { const char *dev_path = network_device_get_nm_path (dev); if ((network_device_get_type (dev) == DEVICE_TYPE_WIRELESS_ETHERNET) && essid) { nm_info ("Forcing device '%s' and network '%s' %s passphrase\n", dev_path, essid, passphrase ? "with" : "without"); if (passphrase == NULL) passphrase = ""; dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_STRING, &essid, DBUS_TYPE_STRING, &passphrase, DBUS_TYPE_INT32, &key_type, DBUS_TYPE_INVALID); } else { nm_info ("Forcing device '%s'\n", network_device_get_nm_path (dev)); dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_INVALID); } dbus_connection_send (connection, message, NULL); } else nm_warning ("nmwa_dbus_set_device(): Couldn't allocate the dbus message\n"); } /* * nmwa_dbus_create_network * * Tell NetworkManager to create an Ad-Hoc wireless network * */ void nmwa_dbus_create_network (DBusConnection *connection, NetworkDevice *dev, const char *essid, NMEncKeyType key_type, const char *passphrase) { DBusMessage *message; g_return_if_fail (connection != NULL); g_return_if_fail (dev != NULL); g_return_if_fail (essid != NULL); g_return_if_fail (network_device_get_type (dev) == DEVICE_TYPE_WIRELESS_ETHERNET); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "createWirelessNetwork"))) { const char *dev_path = network_device_get_nm_path (dev); if (dev_path) { nm_info ("Creating network '%s' %s passphrase on device '%s'.\n", essid, passphrase ? "with" : "without", dev_path); if (passphrase == NULL) passphrase = ""; dbus_message_append_args (message, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_STRING, &essid, DBUS_TYPE_STRING, &passphrase, DBUS_TYPE_INT32, &key_type, DBUS_TYPE_INVALID); dbus_connection_send (connection, message, NULL); } } else nm_warning ("nmwa_dbus_set_device(): Couldn't allocate the dbus message\n"); } /* * nmwa_dbus_enable_scanning * * Tell NetworkManager to start/stop scanning. * */ void nmwa_dbus_enable_scanning (NMWirelessApplet *applet, gboolean enabled) { DBusMessage *message; g_return_if_fail (applet != NULL); g_return_if_fail (applet->connection != NULL); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "setScanningEnabled"))) { dbus_message_append_args (message, DBUS_TYPE_BOOLEAN, &enabled, DBUS_TYPE_INVALID); dbus_connection_send (applet->connection, message, NULL); nmwa_dbus_update_scanning_enabled (applet); } } /* * nmwa_dbus_enable_wireless * * Tell NetworkManager to enabled or disable all wireless devices. * */ void nmwa_dbus_enable_wireless (NMWirelessApplet *applet, gboolean enabled) { DBusMessage *message; g_return_if_fail (applet != NULL); g_return_if_fail (applet->connection != NULL); if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_INTERFACE, "setWirelessEnabled"))) { dbus_message_append_args (message, DBUS_TYPE_BOOLEAN, &enabled, DBUS_TYPE_INVALID); dbus_connection_send (applet->connection, message, NULL); nmwa_dbus_update_wireless_enabled (applet); } } typedef struct StrengthCBData { NMWirelessApplet * applet; char * dev_path; } StrengthCBData; void free_strength_cb_data (StrengthCBData *data) { if (data) g_free (data->dev_path); g_free (data); } /* * nmwa_dbus_update_device_strength_cb * * nmwa_dbus_update_active_device_strength callback. * */ void nmwa_dbus_update_device_strength_cb (DBusPendingCall *pcall, void *user_data) { DBusMessage * reply; StrengthCBData * cb_data = user_data; NMWirelessApplet * applet; int strength; g_return_if_fail (pcall != NULL); g_return_if_fail (cb_data != NULL); applet = cb_data->applet; g_return_if_fail (applet != NULL); dbus_pending_call_ref (pcall); if (!dbus_pending_call_get_completed (pcall)) goto out; if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; if (message_is_error (reply)) { dbus_message_unref (reply); goto out; } if (dbus_message_get_args (reply, NULL, DBUS_TYPE_INT32, &strength, DBUS_TYPE_INVALID)) { /* Update strength on dbus active device */ if ( cb_data->dev_path && applet->dbus_active_device && !strcmp (cb_data->dev_path, network_device_get_nm_path (applet->dbus_active_device))) network_device_set_strength (applet->dbus_active_device, strength); /* Update strength on gui active device too */ if ( cb_data->dev_path && applet->gui_active_device && !strcmp (cb_data->dev_path, network_device_get_nm_path (applet->gui_active_device))) network_device_set_strength (applet->gui_active_device, strength); } dbus_message_unref (reply); out: dbus_pending_call_unref (pcall); } /* * nmwa_dbus_update_active_device_strength * * Update the active device's strength. * */ gboolean nmwa_dbus_update_active_device_strength (NMWirelessApplet *applet) { NetworkDevice * dev; DBusMessage * message; DBusPendingCall * pcall; g_return_val_if_fail (applet != NULL, TRUE); if (!(dev = applet->dbus_active_device)) return TRUE; if ((message = dbus_message_new_method_call (NM_DBUS_SERVICE, network_device_get_nm_path (dev), NM_DBUS_INTERFACE_DEVICES, "getStrength"))) { dbus_connection_send_with_reply (applet->connection, message, &pcall, -1); dbus_message_unref (message); if (pcall) { StrengthCBData * cb_data = g_malloc0 (sizeof (StrengthCBData)); cb_data->applet = applet; cb_data->dev_path = g_strdup (network_device_get_nm_path (dev)); dbus_pending_call_set_notify (pcall, nmwa_dbus_update_device_strength_cb, cb_data, (DBusFreeFunction) free_strength_cb_data); } } return TRUE; } /* * sort_devices_function * * Sort the devices for display... Wired devices at the top. * */ static int sort_devices_function (gconstpointer a, gconstpointer b) { NetworkDevice *dev_a = (NetworkDevice *) a; NetworkDevice *dev_b = (NetworkDevice *) b; const char *name_a; const char *name_b; if (network_device_get_desc (dev_a)) name_a = network_device_get_desc (dev_a); else if (network_device_get_nm_path (dev_a)) name_a = network_device_get_nm_path (dev_a); else name_a = ""; if (network_device_get_desc (dev_b)) name_b = network_device_get_desc (dev_b); else if (network_device_get_nm_path (dev_b)) name_b = network_device_get_nm_path (dev_b); else name_b = ""; if (network_device_get_type (dev_a) == network_device_get_type (dev_b)) { return strcmp (name_a, name_b); } if (network_device_get_type (dev_a) == DEVICE_TYPE_WIRED_ETHERNET) return -1; if (network_device_get_type (dev_b) == DEVICE_TYPE_WIRED_ETHERNET) return 1; if (network_device_get_type (dev_a) == DEVICE_TYPE_WIRELESS_ETHERNET) return -1; if (network_device_get_type (dev_b) == DEVICE_TYPE_WIRELESS_ETHERNET) return 1; /* Unknown device types. Sort by name only at this point. */ return strcmp (name_a, name_b); } static int devices_copy_idle_id = 0; /* * nmwa_dbus_devices_lock_and_copy * * Copy our network model over to the GUI thread. * */ static gboolean nmwa_dbus_devices_lock_and_copy (NMWirelessApplet *applet) { devices_copy_idle_id = 0; g_return_val_if_fail (applet != NULL, FALSE); /* Only copy over if we have a complete data model */ if (g_slist_length (applet->dev_pending_call_list) == 0) { nmwa_dbus_check_drivers (applet); /* Sort the devices for display */ applet->dbus_device_list = g_slist_sort (applet->dbus_device_list, sort_devices_function); /* Match up the active device path with a device in the list */ if (applet->dbus_active_device_path && (applet->dbus_active_device = nmwa_get_device_for_nm_device (applet->dbus_device_list, applet->dbus_active_device_path))) network_device_ref (applet->dbus_active_device); /* Now copy the data over to the GUI side */ g_mutex_lock (applet->data_mutex); nmwa_copy_data_model (applet); g_mutex_unlock (applet->data_mutex); nmwa_dbus_update_active_device_strength (applet); } return FALSE; } /* * nmwa_dbus_devices_schedule_copy * * Schedule a copy of our model over to the gui thread, batching copy requests. * */ void nmwa_dbus_devices_schedule_copy (NMWirelessApplet *applet) { g_return_if_fail (applet != NULL); if (devices_copy_idle_id == 0) { GSource *source = g_idle_source_new (); /* We want this idle source to run before any other idle source */ g_source_set_priority (source, G_PRIORITY_HIGH_IDLE); g_source_set_callback (source, (GSourceFunc) nmwa_dbus_devices_lock_and_copy, applet, NULL); devices_copy_idle_id = g_source_attach (source, applet->thread_context); g_source_unref (source); } }