Blame src/applet-device-wifi.c

Packit Service d328f3
// SPDX-License-Identifier: GPL-2.0+
Packit Service d328f3
/* NetworkManager Applet -- allow user control over networking
Packit Service d328f3
 *
Packit Service d328f3
 * Dan Williams <dcbw@redhat.com>
Packit Service d328f3
 *
Packit Service d328f3
 * Copyright 2008 - 2014 Red Hat, Inc.
Packit Service d328f3
 */
Packit Service d328f3
Packit Service d328f3
#include "nm-default.h"
Packit Service d328f3
Packit Service d328f3
#include <netinet/in.h>
Packit Service d328f3
#include <arpa/inet.h>
Packit Service d328f3
#include <netinet/ether.h>
Packit Service d328f3
#include <ctype.h>
Packit Service d328f3
Packit Service d328f3
#include "applet.h"
Packit Service d328f3
#include "applet-device-wifi.h"
Packit Service d328f3
#include "ap-menu-item.h"
Packit Service d328f3
#include "utils.h"
Packit Service d328f3
#include "nma-wifi-dialog.h"
Packit Service d328f3
#include "mobile-helpers.h"
Packit Service d328f3
Packit Service d328f3
#define ACTIVE_AP_TAG "active-ap"
Packit Service d328f3
Packit Service d328f3
static void wifi_dialog_response_cb (GtkDialog *dialog, gint response, gpointer user_data);
Packit Service d328f3
Packit Service d328f3
static NMAccessPoint *update_active_ap (NMDevice *device, NMDeviceState state, NMApplet *applet);
Packit Service d328f3
Packit Service d328f3
/*****************************************************************************/
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	NMApplet *applet;
Packit Service d328f3
	NMDevice *device;
Packit Service d328f3
	NMAccessPoint *ap;
Packit Service d328f3
	gulong signal_id;
Packit Service d328f3
} ActiveAPData;
Packit Service d328f3
Packit Service d328f3
static void _active_ap_set (NMApplet *applet, NMDevice *device, NMAccessPoint *ap);
Packit Service d328f3
static void _active_ap_set_weakref (gpointer data, GObject *where_the_object_was);
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
_active_ap_set_notify (NMAccessPoint *ap, GParamSpec *pspec, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	ActiveAPData *d = user_data;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (NM_IS_ACCESS_POINT (ap));
Packit Service d328f3
	g_return_if_fail (d);
Packit Service d328f3
	g_return_if_fail (NM_IS_APPLET (d->applet));
Packit Service d328f3
	g_return_if_fail (NM_IS_DEVICE (d->device));
Packit Service d328f3
	g_return_if_fail (d->ap == ap);
Packit Service d328f3
	g_return_if_fail (d->signal_id);
Packit Service d328f3
Packit Service d328f3
	applet_schedule_update_icon (d->applet);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
_active_ap_data_free (ActiveAPData *d)
Packit Service d328f3
{
Packit Service d328f3
	if (d->device)
Packit Service d328f3
		g_object_weak_unref ((GObject *) d->device, _active_ap_set_weakref, d);
Packit Service d328f3
	if (d->ap) {
Packit Service d328f3
		g_object_weak_unref ((GObject *) d->ap, _active_ap_set_weakref, d);
Packit Service d328f3
		g_signal_handler_disconnect (d->ap, d->signal_id);
Packit Service d328f3
	}
Packit Service d328f3
	g_slice_free (ActiveAPData, d);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static NMAccessPoint *
Packit Service d328f3
_active_ap_get (NMApplet *applet, NMDevice *device)
Packit Service d328f3
{
Packit Service d328f3
	GSList *list, *iter;
Packit Service d328f3
Packit Service d328f3
	g_return_val_if_fail (NM_IS_APPLET (applet), NULL);
Packit Service d328f3
	g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
Packit Service d328f3
Packit Service d328f3
	list = g_object_get_data ((GObject *) applet, ACTIVE_AP_TAG);
Packit Service d328f3
	for (iter = list; iter; iter = iter->next) {
Packit Service d328f3
		ActiveAPData *d = iter->data;
Packit Service d328f3
Packit Service d328f3
		if (device == d->device && d->ap)
Packit Service d328f3
			return d->ap;
Packit Service d328f3
	}
Packit Service d328f3
	return NULL;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
_active_ap_set_destroy (gpointer data)
Packit Service d328f3
{
Packit Service d328f3
	g_slist_free_full (data, (GDestroyNotify) _active_ap_data_free);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
_active_ap_set_weakref (gpointer data, GObject *where_the_object_was)
Packit Service d328f3
{
Packit Service d328f3
	ActiveAPData *d = data;
Packit Service d328f3
	NMApplet *applet = d->applet;
Packit Service d328f3
Packit Service d328f3
	if ((GObject *) d->ap == where_the_object_was)
Packit Service d328f3
		d->ap = NULL;
Packit Service d328f3
	else if ((GObject *) d->device == where_the_object_was)
Packit Service d328f3
		d->device = NULL;
Packit Service d328f3
	else
Packit Service d328f3
		g_return_if_reached ();
Packit Service d328f3
	_active_ap_set (applet, NULL, NULL);
Packit Service d328f3
Packit Service d328f3
	applet_schedule_update_icon (applet);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
_active_ap_set (NMApplet *applet, NMDevice *device, NMAccessPoint *ap)
Packit Service d328f3
{
Packit Service d328f3
	GSList *list, *iter, *list0, *pcurrent;
Packit Service d328f3
	ActiveAPData *d;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (NM_IS_APPLET (applet));
Packit Service d328f3
	g_return_if_fail (!device || NM_IS_DEVICE (device));
Packit Service d328f3
	g_return_if_fail (!ap || NM_IS_ACCESS_POINT (ap));
Packit Service d328f3
Packit Service d328f3
	list0 = g_object_get_data ((GObject *) applet, ACTIVE_AP_TAG);
Packit Service d328f3
	list = list0;
Packit Service d328f3
Packit Service d328f3
remove_empty:
Packit Service d328f3
	pcurrent = NULL;
Packit Service d328f3
	for (iter = list; iter; iter = iter->next) {
Packit Service d328f3
		d = iter->data;
Packit Service d328f3
		if (!d->device || !d->ap) {
Packit Service d328f3
			_active_ap_data_free (d);
Packit Service d328f3
			list = g_slist_delete_link (list, iter);
Packit Service d328f3
			goto remove_empty;
Packit Service d328f3
		}
Packit Service d328f3
		if (device && d->device == device)
Packit Service d328f3
			pcurrent = iter;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (!device)
Packit Service d328f3
		goto out;
Packit Service d328f3
Packit Service d328f3
	if (!ap) {
Packit Service d328f3
		if (pcurrent) {
Packit Service d328f3
			_active_ap_data_free (pcurrent->data);
Packit Service d328f3
			list = g_slist_delete_link (list, pcurrent);
Packit Service d328f3
		}
Packit Service d328f3
		goto out;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	if (pcurrent) {
Packit Service d328f3
		d = pcurrent->data;
Packit Service d328f3
Packit Service d328f3
		if (d->ap == ap)
Packit Service d328f3
			goto out;
Packit Service d328f3
		g_object_weak_unref ((GObject *) d->ap, _active_ap_set_weakref, d);
Packit Service d328f3
		g_signal_handler_disconnect (d->ap, d->signal_id);
Packit Service d328f3
	} else {
Packit Service d328f3
		d = g_slice_new (ActiveAPData);
Packit Service d328f3
Packit Service d328f3
		d->applet = applet;
Packit Service d328f3
		d->device = device;
Packit Service d328f3
		g_object_weak_ref ((GObject *) device, _active_ap_set_weakref, d);
Packit Service d328f3
		list = g_slist_append (list, d);
Packit Service d328f3
	}
Packit Service d328f3
	d->ap = ap;
Packit Service d328f3
	g_object_weak_ref ((GObject *) ap, _active_ap_set_weakref, d);
Packit Service d328f3
	d->signal_id = g_signal_connect (ap,
Packit Service d328f3
	                                 "notify::" NM_ACCESS_POINT_STRENGTH,
Packit Service d328f3
	                                 G_CALLBACK (_active_ap_set_notify),
Packit Service d328f3
	                                 d);
Packit Service d328f3
Packit Service d328f3
out:
Packit Service d328f3
	if (list0 != list) {
Packit Service d328f3
		g_object_replace_data ((GObject *) applet, ACTIVE_AP_TAG,
Packit Service d328f3
		                       list0, list,
Packit Service d328f3
		                       _active_ap_set_destroy, NULL);
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
/*****************************************************************************/
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
show_ignore_focus_stealing_prevention (GtkWidget *widget)
Packit Service d328f3
{
Packit Service d328f3
	gtk_widget_realize (widget);
Packit Service d328f3
	gtk_widget_show (widget);
Packit Service d328f3
	gtk_window_present (GTK_WINDOW (widget));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
gboolean
Packit Service d328f3
applet_wifi_connect_to_hidden_network (NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	GtkWidget *dialog;
Packit Service d328f3
Packit Service d328f3
	dialog = nma_wifi_dialog_new_for_hidden (applet->nm_client);
Packit Service d328f3
	if (dialog) {
Packit Service d328f3
		g_signal_connect (dialog, "response",
Packit Service d328f3
		                  G_CALLBACK (wifi_dialog_response_cb),
Packit Service d328f3
		                  applet);
Packit Service d328f3
		show_ignore_focus_stealing_prevention (dialog);
Packit Service d328f3
	}
Packit Service d328f3
	return !!dialog;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
nma_menu_add_hidden_network_item (GtkWidget *menu, NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	GtkWidget *menu_item;
Packit Service d328f3
	GtkWidget *label;
Packit Service d328f3
Packit Service d328f3
	menu_item = gtk_menu_item_new ();
Packit Service d328f3
	label = gtk_label_new_with_mnemonic (_("_Connect to Hidden Wi-Fi Network…"));
Packit Service d328f3
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
Packit Service d328f3
	gtk_container_add (GTK_CONTAINER (menu_item), label);
Packit Service d328f3
	gtk_widget_show_all (menu_item);
Packit Service d328f3
	gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
Packit Service d328f3
	g_signal_connect_swapped (menu_item, "activate",
Packit Service d328f3
	                          G_CALLBACK (applet_wifi_connect_to_hidden_network),
Packit Service d328f3
	                          applet);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
gboolean
Packit Service d328f3
applet_wifi_can_create_wifi_network (NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	gboolean disabled, allowed = FALSE;
Packit Service d328f3
	NMClientPermissionResult perm;
Packit Service d328f3
Packit Service d328f3
	/* FIXME: check WIFI_SHARE_PROTECTED too, and make the wifi dialog
Packit Service d328f3
	 * handle the permissions as well so that admins can restrict open network
Packit Service d328f3
	 * creation separately from protected network creation.
Packit Service d328f3
	 */
Packit Service d328f3
	perm = nm_client_get_permission_result (applet->nm_client, NM_CLIENT_PERMISSION_WIFI_SHARE_OPEN);
Packit Service d328f3
	if (perm == NM_CLIENT_PERMISSION_RESULT_YES || perm == NM_CLIENT_PERMISSION_RESULT_AUTH) {
Packit Service d328f3
		disabled = g_settings_get_boolean (applet->gsettings, PREF_DISABLE_WIFI_CREATE);
Packit Service d328f3
		if (!disabled)
Packit Service d328f3
			allowed = TRUE;
Packit Service d328f3
	}
Packit Service d328f3
	return allowed;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
gboolean
Packit Service d328f3
applet_wifi_create_wifi_network (NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	GtkWidget *dialog;
Packit Service d328f3
Packit Service d328f3
	dialog = nma_wifi_dialog_new_for_create (applet->nm_client);
Packit Service d328f3
	if (dialog) {
Packit Service d328f3
		g_signal_connect (dialog, "response",
Packit Service d328f3
		                  G_CALLBACK (wifi_dialog_response_cb),
Packit Service d328f3
		                  applet);
Packit Service d328f3
		show_ignore_focus_stealing_prevention (dialog);
Packit Service d328f3
	}
Packit Service d328f3
	return !!dialog;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
void
Packit Service d328f3
nma_menu_add_create_network_item (GtkWidget *menu, NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	GtkWidget *menu_item;
Packit Service d328f3
	GtkWidget *label;
Packit Service d328f3
Packit Service d328f3
	menu_item = gtk_menu_item_new ();
Packit Service d328f3
	label = gtk_label_new_with_mnemonic (_("Create _New Wi-Fi Network…"));
Packit Service d328f3
	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
Packit Service d328f3
	gtk_container_add (GTK_CONTAINER (menu_item), label);
Packit Service d328f3
	gtk_widget_show_all (menu_item);
Packit Service d328f3
	gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
Packit Service d328f3
	g_signal_connect_swapped (menu_item, "activate",
Packit Service d328f3
	                          G_CALLBACK (applet_wifi_create_wifi_network),
Packit Service d328f3
	                          applet);
Packit Service d328f3
Packit Service d328f3
	if (!applet_wifi_can_create_wifi_network (applet))
Packit Service d328f3
		gtk_widget_set_sensitive (GTK_WIDGET (menu_item), FALSE);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	NMApplet *applet;
Packit Service d328f3
	NMDeviceWifi *device;
Packit Service d328f3
	NMAccessPoint *ap;
Packit Service d328f3
	NMConnection *connection;
Packit Service d328f3
} WifiMenuItemInfo;
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_menu_item_info_destroy (gpointer data, GClosure *closure)
Packit Service d328f3
{
Packit Service d328f3
	WifiMenuItemInfo *info = (WifiMenuItemInfo *) data;
Packit Service d328f3
Packit Service d328f3
	g_object_unref (G_OBJECT (info->device));
Packit Service d328f3
	g_object_unref (G_OBJECT (info->ap));
Packit Service d328f3
Packit Service d328f3
	if (info->connection)
Packit Service d328f3
		g_object_unref (G_OBJECT (info->connection));
Packit Service d328f3
Packit Service d328f3
	g_slice_free (WifiMenuItemInfo, data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
/*
Packit Service d328f3
 * NOTE: this list should *not* contain networks that you would like to
Packit Service d328f3
 * automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot".
Packit Service d328f3
 */
Packit Service d328f3
static const char *manf_default_ssids[] = {
Packit Service d328f3
	"linksys",
Packit Service d328f3
	"linksys-a",
Packit Service d328f3
	"linksys-g",
Packit Service d328f3
	"default",
Packit Service d328f3
	"belkin54g",
Packit Service d328f3
	"NETGEAR",
Packit Service d328f3
	"o2DSL",
Packit Service d328f3
	"WLAN",
Packit Service d328f3
	"ALICE-WLAN",
Packit Service d328f3
	NULL
Packit Service d328f3
};
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
is_ssid_in_list (GBytes *ssid, const char **list)
Packit Service d328f3
{
Packit Service d328f3
	while (*list) {
Packit Service d328f3
		if (g_bytes_get_size (ssid) == strlen (*list)) {
Packit Service d328f3
			if (!memcmp (*list, g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)))
Packit Service d328f3
				return TRUE;
Packit Service d328f3
		}
Packit Service d328f3
		list++;
Packit Service d328f3
	}
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
is_manufacturer_default_ssid (GBytes *ssid)
Packit Service d328f3
{
Packit Service d328f3
	return is_ssid_in_list (ssid, manf_default_ssids);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static char *
Packit Service d328f3
get_ssid_utf8 (NMAccessPoint *ap)
Packit Service d328f3
{
Packit Service d328f3
	char *ssid_utf8 = NULL;
Packit Service d328f3
	GBytes *ssid;
Packit Service d328f3
Packit Service d328f3
	if (ap) {
Packit Service d328f3
		ssid = nm_access_point_get_ssid (ap);
Packit Service d328f3
		if (ssid)
Packit Service d328f3
			ssid_utf8 = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid));
Packit Service d328f3
	}
Packit Service d328f3
	if (!ssid_utf8)
Packit Service d328f3
		ssid_utf8 = g_strdup (_("(none)"));
Packit Service d328f3
Packit Service d328f3
	return ssid_utf8;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
/* List known trojan networks that should never be shown to the user */
Packit Service d328f3
static const char *blacklisted_ssids[] = {
Packit Service d328f3
	/* http://www.npr.org/templates/story/story.php?storyId=130451369 */
Packit Service d328f3
	"Free Public Wi-Fi",
Packit Service d328f3
	NULL
Packit Service d328f3
};
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
is_blacklisted_ssid (GBytes *ssid)
Packit Service d328f3
{
Packit Service d328f3
	return is_ssid_in_list (ssid, blacklisted_ssids);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
clamp_ap_to_bssid (NMAccessPoint *ap, NMSettingWireless *s_wifi)
Packit Service d328f3
{
Packit Service d328f3
	const char *str_bssid;
Packit Service d328f3
	struct ether_addr *eth_addr;
Packit Service d328f3
	GByteArray *bssid;
Packit Service d328f3
Packit Service d328f3
	/* For a certain list of known ESSIDs which are commonly preset by ISPs
Packit Service d328f3
	 * and manufacturers and often unchanged by users, lock the connection
Packit Service d328f3
	 * to the BSSID so that we don't try to auto-connect to your grandma's
Packit Service d328f3
	 * neighbor's Wi-Fi.
Packit Service d328f3
	 */
Packit Service d328f3
Packit Service d328f3
	str_bssid = nm_access_point_get_bssid (ap);
Packit Service d328f3
	if (str_bssid) {
Packit Service d328f3
		eth_addr = ether_aton (str_bssid);
Packit Service d328f3
		if (eth_addr) {
Packit Service d328f3
			bssid = g_byte_array_sized_new (ETH_ALEN);
Packit Service d328f3
			g_byte_array_append (bssid, eth_addr->ether_addr_octet, ETH_ALEN);
Packit Service d328f3
			g_object_set (G_OBJECT (s_wifi),
Packit Service d328f3
			              NM_SETTING_WIRELESS_BSSID, bssid,
Packit Service d328f3
			              NULL);
Packit Service d328f3
			g_byte_array_free (bssid, TRUE);
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	NMApplet *applet;
Packit Service d328f3
	AppletNewAutoConnectionCallback callback;
Packit Service d328f3
	gpointer callback_data;
Packit Service d328f3
} MoreInfo;
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
more_info_wifi_dialog_response_cb (GtkDialog *foo,
Packit Service d328f3
                                   gint response,
Packit Service d328f3
                                   gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMAWifiDialog *dialog = NMA_WIFI_DIALOG (foo);
Packit Service d328f3
	MoreInfo *info = user_data;
Packit Service d328f3
	NMConnection *connection = NULL;
Packit Service d328f3
	NMDevice *device = NULL;
Packit Service d328f3
	NMAccessPoint *ap = NULL;
Packit Service d328f3
Packit Service d328f3
	if (response != GTK_RESPONSE_OK) {
Packit Service d328f3
		info->callback (NULL, FALSE, TRUE, info->callback_data);
Packit Service d328f3
		goto done;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* nma_wifi_dialog_get_connection() returns a connection with the
Packit Service d328f3
	 * refcount incremented, so the caller must remember to unref it.
Packit Service d328f3
	 */
Packit Service d328f3
	connection = nma_wifi_dialog_get_connection (dialog, &device, &ap);
Packit Service d328f3
	g_assert (connection);
Packit Service d328f3
	g_assert (device);
Packit Service d328f3
Packit Service d328f3
	info->callback (connection, TRUE, FALSE, info->callback_data);
Packit Service d328f3
Packit Service d328f3
	/* Balance nma_wifi_dialog_get_connection() */
Packit Service d328f3
	g_object_unref (connection);
Packit Service d328f3
Packit Service d328f3
done:
Packit Service d328f3
	g_free (info);
Packit Service d328f3
	gtk_widget_hide (GTK_WIDGET (dialog));
Packit Service d328f3
	gtk_widget_destroy (GTK_WIDGET (dialog));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
can_get_permission (NMApplet *applet, NMClientPermission perm)
Packit Service d328f3
{
Packit Service d328f3
	if (   applet->permissions[perm] == NM_CLIENT_PERMISSION_RESULT_YES
Packit Service d328f3
	    || applet->permissions[perm] == NM_CLIENT_PERMISSION_RESULT_AUTH)
Packit Service d328f3
		return TRUE;
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
wifi_new_auto_connection (NMDevice *device,
Packit Service d328f3
                          gpointer dclass_data,
Packit Service d328f3
                          AppletNewAutoConnectionCallback callback,
Packit Service d328f3
                          gpointer callback_data)
Packit Service d328f3
{
Packit Service d328f3
	WifiMenuItemInfo *info = (WifiMenuItemInfo *) dclass_data;
Packit Service d328f3
	NMApplet *applet;
Packit Service d328f3
	NMAccessPoint *ap;
Packit Service d328f3
	NMConnection *connection;
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	NMSettingWireless *s_wifi = NULL;
Packit Service d328f3
	NMSettingWirelessSecurity *s_wsec;
Packit Service d328f3
	NMSetting8021x *s_8021x = NULL;
Packit Service d328f3
	GBytes *ssid;
Packit Service d328f3
	NM80211ApSecurityFlags wpa_flags, rsn_flags;
Packit Service d328f3
	GtkWidget *dialog;
Packit Service d328f3
	MoreInfo *more_info;
Packit Service d328f3
	char *uuid;
Packit Service d328f3
Packit Service d328f3
	g_return_val_if_fail (dclass_data, FALSE);
Packit Service d328f3
	g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
Packit Service d328f3
	g_return_val_if_fail (NM_IS_ACCESS_POINT (info->ap), FALSE);
Packit Service d328f3
	g_return_val_if_fail (NM_IS_APPLET (info->applet), FALSE);
Packit Service d328f3
Packit Service d328f3
	applet = info->applet;
Packit Service d328f3
	ap = info->ap;
Packit Service d328f3
Packit Service d328f3
	connection = nm_simple_connection_new ();
Packit Service d328f3
Packit Service d328f3
	/* Make the new connection available only for the current user */
Packit Service d328f3
	s_con = (NMSettingConnection *) nm_setting_connection_new ();
Packit Service d328f3
	nm_setting_connection_add_permission (s_con, "user", g_get_user_name (), NULL);
Packit Service d328f3
	nm_connection_add_setting (connection, NM_SETTING (s_con));
Packit Service d328f3
Packit Service d328f3
	ssid = nm_access_point_get_ssid (ap);
Packit Service d328f3
	if (   (nm_access_point_get_mode (ap) == NM_802_11_MODE_INFRA)
Packit Service d328f3
	    && (is_manufacturer_default_ssid (ssid) == TRUE)) {
Packit Service d328f3
Packit Service d328f3
		/* Lock connection to this AP if it's a manufacturer-default SSID
Packit Service d328f3
		 * so that we don't randomly connect to some other 'linksys'
Packit Service d328f3
		 */
Packit Service d328f3
		s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
Packit Service d328f3
		clamp_ap_to_bssid (ap, s_wifi);
Packit Service d328f3
		nm_connection_add_setting (connection, NM_SETTING (s_wifi));
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* If the AP is WPA[2]-Enterprise then we need to set up a minimal 802.1x
Packit Service d328f3
	 * setting and ask the user for more information.
Packit Service d328f3
	 */
Packit Service d328f3
	rsn_flags = nm_access_point_get_rsn_flags (ap);
Packit Service d328f3
	wpa_flags = nm_access_point_get_wpa_flags (ap);
Packit Service d328f3
	if (   (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
Packit Service d328f3
	    || (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
Packit Service d328f3
Packit Service d328f3
		/* Need a UUID for the "always ask" stuff in the Dialog of Doom */
Packit Service d328f3
		uuid = nm_utils_uuid_generate ();
Packit Service d328f3
		g_object_set (s_con, NM_SETTING_CONNECTION_UUID, uuid, NULL);
Packit Service d328f3
		g_free (uuid);
Packit Service d328f3
Packit Service d328f3
		if (!s_wifi) {
Packit Service d328f3
			s_wifi = (NMSettingWireless *) nm_setting_wireless_new ();
Packit Service d328f3
			nm_connection_add_setting (connection, NM_SETTING (s_wifi));
Packit Service d328f3
		}
Packit Service d328f3
		g_object_set (s_wifi,
Packit Service d328f3
		              NM_SETTING_WIRELESS_SSID, ssid,
Packit Service d328f3
		              NULL);
Packit Service d328f3
Packit Service d328f3
		s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
Packit Service d328f3
		g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
Packit Service d328f3
		nm_connection_add_setting (connection, NM_SETTING (s_wsec));
Packit Service d328f3
Packit Service d328f3
		s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
Packit Service d328f3
		nm_setting_802_1x_add_eap_method (s_8021x, "ttls");
Packit Service d328f3
		g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", NULL);
Packit Service d328f3
		nm_connection_add_setting (connection, NM_SETTING (s_8021x));
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* If it's an 802.1x connection, we need more information, so pop up the
Packit Service d328f3
	 * Dialog Of Doom.
Packit Service d328f3
	 */
Packit Service d328f3
	if (s_8021x) {
Packit Service d328f3
		if (!can_get_permission (applet, NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM) &&
Packit Service d328f3
		    !can_get_permission (applet, NM_CLIENT_PERMISSION_SETTINGS_MODIFY_OWN)) {
Packit Service d328f3
			const char *text = _("Failed to add new connection");
Packit Service d328f3
			const char *err_text = _("Insufficient privileges.");
Packit Service d328f3
			g_warning ("%s: %s", text, err_text);
Packit Service d328f3
			utils_show_error_dialog (_("Connection failure"), text, err_text, FALSE, NULL);
Packit Service d328f3
			g_clear_object (&connection);
Packit Service d328f3
			return FALSE;
Packit Service d328f3
		}
Packit Service d328f3
		more_info = g_malloc0 (sizeof (*more_info));
Packit Service d328f3
		more_info->applet = applet;
Packit Service d328f3
		more_info->callback = callback;
Packit Service d328f3
		more_info->callback_data = callback_data;
Packit Service d328f3
Packit Service d328f3
		dialog = nma_wifi_dialog_new (applet->nm_client, connection, device, ap, FALSE);
Packit Service d328f3
		if (dialog) {
Packit Service d328f3
			g_signal_connect (dialog, "response",
Packit Service d328f3
				              G_CALLBACK (more_info_wifi_dialog_response_cb),
Packit Service d328f3
				              more_info);
Packit Service d328f3
			show_ignore_focus_stealing_prevention (dialog);
Packit Service d328f3
		}
Packit Service d328f3
	} else {
Packit Service d328f3
		/* Everything else can just get activated right away */
Packit Service d328f3
		callback (connection, TRUE, FALSE, callback_data);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	return TRUE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_menu_item_activate (GtkMenuItem *item, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	WifiMenuItemInfo *info = (WifiMenuItemInfo *) user_data;
Packit Service d328f3
	const char *specific_object = NULL;
Packit Service d328f3
Packit Service d328f3
	if (info->ap)
Packit Service d328f3
		specific_object = nm_object_get_path (NM_OBJECT (info->ap));
Packit Service d328f3
	applet_menu_item_activate_helper (NM_DEVICE (info->device),
Packit Service d328f3
	                                  info->connection,
Packit Service d328f3
	                                  specific_object ? specific_object : "/",
Packit Service d328f3
	                                  info->applet,
Packit Service d328f3
	                                  user_data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
struct dup_data {
Packit Service d328f3
	NMDevice *device;
Packit Service d328f3
	NMNetworkMenuItem *found;
Packit Service d328f3
	char *hash;
Packit Service d328f3
};
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
find_duplicate (gpointer d, gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	struct dup_data * data = (struct dup_data *) user_data;
Packit Service d328f3
	NMDevice *device;
Packit Service d328f3
	const char *hash;
Packit Service d328f3
	GtkWidget *widget = GTK_WIDGET (d);
Packit Service d328f3
Packit Service d328f3
	g_assert (d && widget);
Packit Service d328f3
	g_return_if_fail (data);
Packit Service d328f3
	g_return_if_fail (data->hash);
Packit Service d328f3
Packit Service d328f3
	if (data->found || !NM_IS_NETWORK_MENU_ITEM (widget))
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	device = g_object_get_data (G_OBJECT (widget), "device");
Packit Service d328f3
	if (NM_DEVICE (device) != data->device)
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	hash = nm_network_menu_item_get_hash (NM_NETWORK_MENU_ITEM (widget));
Packit Service d328f3
	if (hash && (strcmp (hash, data->hash) == 0))
Packit Service d328f3
		data->found = NM_NETWORK_MENU_ITEM (widget);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static NMNetworkMenuItem *
Packit Service d328f3
create_new_ap_item (NMDeviceWifi *device,
Packit Service d328f3
                    NMAccessPoint *ap,
Packit Service d328f3
                    struct dup_data *dup_data,
Packit Service d328f3
                    const GPtrArray *connections,
Packit Service d328f3
                    NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	WifiMenuItemInfo *info;
Packit Service d328f3
	int i;
Packit Service d328f3
	GtkWidget *item;
Packit Service d328f3
	GPtrArray *dev_connections;
Packit Service d328f3
	GPtrArray *ap_connections;
Packit Service d328f3
Packit Service d328f3
	dev_connections = nm_device_filter_connections (NM_DEVICE (device), connections);
Packit Service d328f3
	ap_connections = nm_access_point_filter_connections (ap, dev_connections);
Packit Service d328f3
	g_ptr_array_unref (dev_connections);
Packit Service d328f3
Packit Service d328f3
	item = nm_network_menu_item_new (ap,
Packit Service d328f3
	                                 nm_device_wifi_get_capabilities (device),
Packit Service d328f3
	                                 dup_data->hash,
Packit Service d328f3
	                                 ap_connections->len != 0,
Packit Service d328f3
	                                 applet);
Packit Service d328f3
	g_object_set_data (G_OBJECT (item), "device", NM_DEVICE (device));
Packit Service d328f3
Packit Service d328f3
	/* If there's only one connection, don't show the submenu */
Packit Service d328f3
	if (ap_connections->len > 1) {
Packit Service d328f3
		GtkWidget *submenu;
Packit Service d328f3
Packit Service d328f3
		submenu = gtk_menu_new ();
Packit Service d328f3
Packit Service d328f3
		for (i = 0; i < ap_connections->len; i++) {
Packit Service d328f3
			NMConnection *connection = NM_CONNECTION (ap_connections->pdata[i]);
Packit Service d328f3
			NMSettingConnection *s_con;
Packit Service d328f3
			GtkWidget *subitem;
Packit Service d328f3
Packit Service d328f3
			s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
			subitem = gtk_menu_item_new_with_label (nm_setting_connection_get_id (s_con));
Packit Service d328f3
Packit Service d328f3
			info = g_slice_new0 (WifiMenuItemInfo);
Packit Service d328f3
			info->applet = applet;
Packit Service d328f3
			info->device = g_object_ref (device);
Packit Service d328f3
			info->ap = g_object_ref (ap);
Packit Service d328f3
			info->connection = g_object_ref (connection);
Packit Service d328f3
Packit Service d328f3
			g_signal_connect_data (subitem, "activate",
Packit Service d328f3
			                       G_CALLBACK (wifi_menu_item_activate),
Packit Service d328f3
			                       info,
Packit Service d328f3
			                       wifi_menu_item_info_destroy, 0);
Packit Service d328f3
Packit Service d328f3
			gtk_menu_shell_append (GTK_MENU_SHELL (submenu), GTK_WIDGET (subitem));
Packit Service d328f3
			gtk_widget_show (subitem);
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
Packit Service d328f3
	} else {
Packit Service d328f3
		NMConnection *connection;
Packit Service d328f3
Packit Service d328f3
		info = g_slice_new0 (WifiMenuItemInfo);
Packit Service d328f3
		info->applet = applet;
Packit Service d328f3
		info->device = g_object_ref (device);
Packit Service d328f3
		info->ap = g_object_ref (ap);
Packit Service d328f3
Packit Service d328f3
		if (ap_connections->len == 1) {
Packit Service d328f3
			connection = NM_CONNECTION (ap_connections->pdata[0]);
Packit Service d328f3
			info->connection = g_object_ref (connection);
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		g_signal_connect_data (GTK_WIDGET (item),
Packit Service d328f3
		                       "activate",
Packit Service d328f3
		                       G_CALLBACK (wifi_menu_item_activate),
Packit Service d328f3
		                       info,
Packit Service d328f3
		                       wifi_menu_item_info_destroy,
Packit Service d328f3
		                       0);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	g_ptr_array_unref (ap_connections);
Packit Service d328f3
	return NM_NETWORK_MENU_ITEM (item);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static NMNetworkMenuItem *
Packit Service d328f3
get_menu_item_for_ap (NMDeviceWifi *device,
Packit Service d328f3
                      NMAccessPoint *ap,
Packit Service d328f3
                      const GPtrArray *connections,
Packit Service d328f3
                      GSList *menu_list,
Packit Service d328f3
                      NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	GBytes *ssid;
Packit Service d328f3
	struct dup_data dup_data = { NULL, NULL };
Packit Service d328f3
Packit Service d328f3
	/* Don't add BSSs that hide their SSID or are blacklisted */
Packit Service d328f3
	ssid = nm_access_point_get_ssid (ap);
Packit Service d328f3
	if (   !ssid
Packit Service d328f3
	    || nm_utils_is_empty_ssid (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid))
Packit Service d328f3
	    || is_blacklisted_ssid (ssid))
Packit Service d328f3
		return NULL;
Packit Service d328f3
Packit Service d328f3
	/* Find out if this AP is a member of a larger network that all uses the
Packit Service d328f3
	 * same SSID and security settings.  If so, we'll already have a menu item
Packit Service d328f3
	 * for this SSID, so just update that item's strength and add this AP to
Packit Service d328f3
	 * menu item's duplicate list.
Packit Service d328f3
	 */
Packit Service d328f3
	dup_data.found = NULL;
Packit Service d328f3
	dup_data.hash = g_object_get_data (G_OBJECT (ap), "hash");
Packit Service d328f3
	g_return_val_if_fail (dup_data.hash != NULL, NULL);
Packit Service d328f3
Packit Service d328f3
	dup_data.device = NM_DEVICE (device);
Packit Service d328f3
	g_slist_foreach (menu_list, find_duplicate, &dup_data);
Packit Service d328f3
Packit Service d328f3
	if (dup_data.found) {
Packit Service d328f3
		nm_network_menu_item_set_strength (dup_data.found, nm_access_point_get_strength (ap), applet);
Packit Service d328f3
		nm_network_menu_item_add_dupe (dup_data.found, ap);
Packit Service d328f3
		return NULL;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	return create_new_ap_item (device, ap, &dup_data, connections, applet);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gint
Packit Service d328f3
sort_by_name (gconstpointer tmpa, gconstpointer tmpb)
Packit Service d328f3
{
Packit Service d328f3
	NMNetworkMenuItem *a = NM_NETWORK_MENU_ITEM (tmpa);
Packit Service d328f3
	NMNetworkMenuItem *b = NM_NETWORK_MENU_ITEM (tmpb);
Packit Service d328f3
	const char *a_ssid, *b_ssid;
Packit Service d328f3
	gboolean a_adhoc, b_adhoc;
Packit Service d328f3
	int i;
Packit Service d328f3
Packit Service d328f3
	if (a && !b)
Packit Service d328f3
		return 1;
Packit Service d328f3
	else if (!a && b)
Packit Service d328f3
		return -1;
Packit Service d328f3
	else if (a == b)
Packit Service d328f3
		return 0;
Packit Service d328f3
Packit Service d328f3
	a_ssid = nm_network_menu_item_get_ssid (a);
Packit Service d328f3
	b_ssid = nm_network_menu_item_get_ssid (b);
Packit Service d328f3
Packit Service d328f3
	if (a_ssid && !b_ssid)
Packit Service d328f3
		return 1;
Packit Service d328f3
	if (b_ssid && !a_ssid)
Packit Service d328f3
		return -1;
Packit Service d328f3
Packit Service d328f3
	if (a_ssid && b_ssid) {
Packit Service d328f3
		i = g_ascii_strcasecmp (a_ssid, b_ssid);
Packit Service d328f3
		if (i != 0)
Packit Service d328f3
			return i;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* If the names are the same, sort infrastructure APs first */
Packit Service d328f3
	a_adhoc = nm_network_menu_item_get_is_adhoc (a);
Packit Service d328f3
	b_adhoc = nm_network_menu_item_get_is_adhoc (b);
Packit Service d328f3
	if (a_adhoc && !b_adhoc)
Packit Service d328f3
		return 1;
Packit Service d328f3
	else if (!a_adhoc && b_adhoc)
Packit Service d328f3
		return -1;
Packit Service d328f3
Packit Service d328f3
	return 0;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
/* Sort menu items for the top-level menu:
Packit Service d328f3
 * 1) whether there's a saved connection or not
Packit Service d328f3
 *    a) sort alphabetically within #1
Packit Service d328f3
 * 2) encrypted without a saved connection
Packit Service d328f3
 * 3) unencrypted without a saved connection
Packit Service d328f3
 */
Packit Service d328f3
static gint
Packit Service d328f3
sort_toplevel (gconstpointer tmpa, gconstpointer tmpb)
Packit Service d328f3
{
Packit Service d328f3
	NMNetworkMenuItem *a = NM_NETWORK_MENU_ITEM (tmpa);
Packit Service d328f3
	NMNetworkMenuItem *b = NM_NETWORK_MENU_ITEM (tmpb);
Packit Service d328f3
	gboolean a_fave, b_fave;
Packit Service d328f3
Packit Service d328f3
	if (a && !b)
Packit Service d328f3
		return 1;
Packit Service d328f3
	else if (!a && b)
Packit Service d328f3
		return -1;
Packit Service d328f3
	else if (a == b)
Packit Service d328f3
		return 0;
Packit Service d328f3
Packit Service d328f3
	a_fave = nm_network_menu_item_get_has_connections (a);
Packit Service d328f3
	b_fave = nm_network_menu_item_get_has_connections (b);
Packit Service d328f3
Packit Service d328f3
	/* Items with a saved connection first */
Packit Service d328f3
	if (a_fave && !b_fave)
Packit Service d328f3
		return -1;
Packit Service d328f3
	else if (!a_fave && b_fave)
Packit Service d328f3
		return 1;
Packit Service d328f3
	else if (!a_fave && !b_fave) {
Packit Service d328f3
		gboolean a_enc = nm_network_menu_item_get_is_encrypted (a);
Packit Service d328f3
		gboolean b_enc = nm_network_menu_item_get_is_encrypted (b);
Packit Service d328f3
Packit Service d328f3
		/* If neither item has a saved connection, sort by encryption */
Packit Service d328f3
		if (a_enc && !b_enc)
Packit Service d328f3
			return -1;
Packit Service d328f3
		else if (!a_enc && b_enc)
Packit Service d328f3
			return 1;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* For all other cases (both have saved connections, both are encrypted, or
Packit Service d328f3
	 * both are unencrypted) just sort by name.
Packit Service d328f3
	 */
Packit Service d328f3
	return sort_by_name (a, b);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_add_menu_item (NMDevice *device,
Packit Service d328f3
                    gboolean multiple_devices,
Packit Service d328f3
                    const GPtrArray *connections,
Packit Service d328f3
                    NMConnection *active,
Packit Service d328f3
                    GtkWidget *menu,
Packit Service d328f3
                    NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	NMDeviceWifi *wdev;
Packit Service d328f3
	char *text;
Packit Service d328f3
	const GPtrArray *aps;
Packit Service d328f3
	int i;
Packit Service d328f3
	NMAccessPoint *active_ap = NULL;
Packit Service d328f3
	GSList *iter;
Packit Service d328f3
	gboolean wifi_enabled = TRUE;
Packit Service d328f3
	gboolean wifi_hw_enabled = TRUE;
Packit Service d328f3
	GSList *menu_items = NULL;  /* All menu items we'll be adding */
Packit Service d328f3
	NMNetworkMenuItem *item, *active_item = NULL;
Packit Service d328f3
	GtkWidget *widget;
Packit Service d328f3
Packit Service d328f3
	wdev = NM_DEVICE_WIFI (device);
Packit Service d328f3
	aps = nm_device_wifi_get_access_points (wdev);
Packit Service d328f3
Packit Service d328f3
	if (multiple_devices) {
Packit Service d328f3
		const char *desc;
Packit Service d328f3
Packit Service d328f3
		desc = nm_device_get_description (device);
Packit Service d328f3
		if (aps && aps->len > 1)
Packit Service d328f3
			text = g_strdup_printf (_("Wi-Fi Networks (%s)"), desc);
Packit Service d328f3
		else
Packit Service d328f3
			text = g_strdup_printf (_("Wi-Fi Network (%s)"), desc);
Packit Service d328f3
	} else
Packit Service d328f3
		text = g_strdup (ngettext ("Wi-Fi Network", "Wi-Fi Networks", aps ? aps->len : 0));
Packit Service d328f3
Packit Service d328f3
	widget = applet_menu_item_create_device_item_helper (device, applet, text);
Packit Service d328f3
	g_free (text);
Packit Service d328f3
Packit Service d328f3
	gtk_widget_set_sensitive (widget, FALSE);
Packit Service d328f3
	gtk_menu_shell_append (GTK_MENU_SHELL (menu), widget);
Packit Service d328f3
	gtk_widget_show (widget);
Packit Service d328f3
Packit Service d328f3
	/* Add the active AP if we're connected to something and the device is available */
Packit Service d328f3
	if (!nma_menu_device_check_unusable (device)) {
Packit Service d328f3
		active_ap = nm_device_wifi_get_active_access_point (wdev);
Packit Service d328f3
		if (active_ap) {
Packit Service d328f3
			active_item = item = get_menu_item_for_ap (wdev, active_ap, connections, NULL, applet);
Packit Service d328f3
			if (item) {
Packit Service d328f3
				nm_network_menu_item_set_active (item, TRUE);
Packit Service d328f3
				menu_items = g_slist_append (menu_items, item);
Packit Service d328f3
Packit Service d328f3
				gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (item));
Packit Service d328f3
				gtk_widget_show_all (GTK_WIDGET (item));
Packit Service d328f3
			}
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Notify user of unmanaged or unavailable device */
Packit Service d328f3
	wifi_enabled = nm_client_wireless_get_enabled (applet->nm_client);
Packit Service d328f3
	wifi_hw_enabled = nm_client_wireless_hardware_get_enabled (applet->nm_client);
Packit Service d328f3
	widget = nma_menu_device_get_menu_item (device, applet,
Packit Service d328f3
	                                        wifi_hw_enabled ?
Packit Service d328f3
	                                            (wifi_enabled ? NULL : _("Wi-Fi is disabled")) :
Packit Service d328f3
	                                            _("Wi-Fi is disabled by hardware switch"));
Packit Service d328f3
	if (widget) {
Packit Service d328f3
		gtk_menu_shell_append (GTK_MENU_SHELL (menu), widget);
Packit Service d328f3
		gtk_widget_show (widget);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* If disabled or rfkilled or whatever, nothing left to do */
Packit Service d328f3
	if (nma_menu_device_check_unusable (device))
Packit Service d328f3
		goto out;
Packit Service d328f3
Packit Service d328f3
	/* Create menu items for the rest of the APs */
Packit Service d328f3
	for (i = 0; aps && (i < aps->len); i++) {
Packit Service d328f3
		NMAccessPoint *ap = g_ptr_array_index (aps, i);
Packit Service d328f3
Packit Service d328f3
		item = get_menu_item_for_ap (wdev, ap, connections, menu_items, applet);
Packit Service d328f3
		if (item)
Packit Service d328f3
			menu_items = g_slist_append (menu_items, item);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Now remove the active AP item from the list, as we've already dealt with
Packit Service d328f3
	 * it.  (Needed it when creating menu items for the rest of the APs though
Packit Service d328f3
	 * to ensure duplicate APs are handled correctly)
Packit Service d328f3
	 */
Packit Service d328f3
	if (active_item)
Packit Service d328f3
		menu_items = g_slist_remove (menu_items, active_item);
Packit Service d328f3
Packit Service d328f3
	/* Sort all the rest of the menu items for the top-level menu */
Packit Service d328f3
	menu_items = g_slist_sort (menu_items, sort_toplevel);
Packit Service d328f3
Packit Service d328f3
	if (g_slist_length (menu_items)) {
Packit Service d328f3
		GSList *submenu_items = NULL;
Packit Service d328f3
		GSList *topmenu_items = NULL;
Packit Service d328f3
		guint32 num_for_toplevel = 5;
Packit Service d328f3
Packit Service d328f3
		applet_menu_item_add_complex_separator_helper (menu, applet, _("Available"));
Packit Service d328f3
Packit Service d328f3
		if (g_slist_length (menu_items) == (num_for_toplevel + 1))
Packit Service d328f3
			num_for_toplevel++;
Packit Service d328f3
Packit Service d328f3
		/* Add the first 5 APs (or 6 if there are only 6 total) from the sorted
Packit Service d328f3
		 * toplevel list.
Packit Service d328f3
		 */
Packit Service d328f3
		for (iter = menu_items; iter && num_for_toplevel; iter = g_slist_next (iter)) {
Packit Service d328f3
			topmenu_items = g_slist_append (topmenu_items, iter->data);
Packit Service d328f3
			num_for_toplevel--;
Packit Service d328f3
			submenu_items = iter->next;
Packit Service d328f3
		}
Packit Service d328f3
		topmenu_items = g_slist_sort (topmenu_items, sort_by_name);
Packit Service d328f3
Packit Service d328f3
		for (iter = topmenu_items; iter; iter = g_slist_next (iter)) {
Packit Service d328f3
			gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (iter->data));
Packit Service d328f3
			gtk_widget_show_all (GTK_WIDGET (iter->data));
Packit Service d328f3
		}
Packit Service d328f3
		g_slist_free (topmenu_items);
Packit Service d328f3
		topmenu_items = NULL;
Packit Service d328f3
Packit Service d328f3
		/* If there are any submenu items, make a submenu for those */
Packit Service d328f3
		if (submenu_items) {
Packit Service d328f3
			GtkWidget *subitem, *submenu;
Packit Service d328f3
			GSList *sorted_subitems;
Packit Service d328f3
Packit Service d328f3
			subitem = gtk_menu_item_new_with_mnemonic (_("More networks"));
Packit Service d328f3
			submenu = gtk_menu_new ();
Packit Service d328f3
			gtk_menu_item_set_submenu (GTK_MENU_ITEM (subitem), submenu);
Packit Service d328f3
Packit Service d328f3
			/* Sort the subitems alphabetically */
Packit Service d328f3
			sorted_subitems = g_slist_copy (submenu_items);
Packit Service d328f3
			sorted_subitems = g_slist_sort (sorted_subitems, sort_by_name);
Packit Service d328f3
Packit Service d328f3
			/* And add the rest to the submenu */
Packit Service d328f3
			for (iter = sorted_subitems; iter; iter = g_slist_next (iter))
Packit Service d328f3
				gtk_menu_shell_append (GTK_MENU_SHELL (submenu), GTK_WIDGET (iter->data));
Packit Service d328f3
			g_slist_free (sorted_subitems);
Packit Service d328f3
Packit Service d328f3
			gtk_menu_shell_append (GTK_MENU_SHELL (menu), subitem);
Packit Service d328f3
			gtk_widget_show_all (subitem);
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
out:
Packit Service d328f3
	g_slist_free (menu_items);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
notify_active_ap_changed_cb (NMDeviceWifi *device,
Packit Service d328f3
                             GParamSpec *pspec,
Packit Service d328f3
                             NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	NMRemoteConnection *connection;
Packit Service d328f3
	NMSettingWireless *s_wireless;
Packit Service d328f3
	NMAccessPoint *new;
Packit Service d328f3
	GBytes *ssid_ap, *ssid;
Packit Service d328f3
	NMDeviceState state;
Packit Service d328f3
Packit Service d328f3
	state = nm_device_get_state (NM_DEVICE (device));
Packit Service d328f3
Packit Service d328f3
	new = update_active_ap (NM_DEVICE (device), state, applet);
Packit Service d328f3
	if (!new || (state != NM_DEVICE_STATE_ACTIVATED))
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	connection = applet_get_exported_connection_for_device (NM_DEVICE (device), applet);
Packit Service d328f3
	if (!connection)
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	s_wireless = nm_connection_get_setting_wireless (NM_CONNECTION (connection));
Packit Service d328f3
	if (!s_wireless)
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	ssid_ap = nm_access_point_get_ssid (new);
Packit Service d328f3
	ssid = nm_setting_wireless_get_ssid (s_wireless);
Packit Service d328f3
	if (   !ssid_ap
Packit Service d328f3
	    || !ssid
Packit Service d328f3
	    || !nm_utils_same_ssid (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid),
Packit Service d328f3
	                            g_bytes_get_data (ssid_ap, NULL), g_bytes_get_size (ssid_ap),
Packit Service d328f3
	                            TRUE))
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	applet_schedule_update_icon (applet);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
add_hash_to_ap (NMAccessPoint *ap)
Packit Service d328f3
{
Packit Service d328f3
	char *hash;
Packit Service d328f3
Packit Service d328f3
	hash = utils_hash_ap (nm_access_point_get_ssid (ap),
Packit Service d328f3
	                      nm_access_point_get_mode (ap),
Packit Service d328f3
	                      nm_access_point_get_flags (ap),
Packit Service d328f3
	                      nm_access_point_get_wpa_flags (ap),
Packit Service d328f3
	                      nm_access_point_get_rsn_flags (ap));
Packit Service d328f3
	g_object_set_data_full (G_OBJECT (ap), "hash", hash, (GDestroyNotify) g_free);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
notify_ap_prop_changed_cb (NMAccessPoint *ap,
Packit Service d328f3
                           GParamSpec *pspec,
Packit Service d328f3
                           NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	const char *prop = g_param_spec_get_name (pspec);
Packit Service d328f3
Packit Service d328f3
	if (   !strcmp (prop, NM_ACCESS_POINT_FLAGS)
Packit Service d328f3
	    || !strcmp (prop, NM_ACCESS_POINT_WPA_FLAGS)
Packit Service d328f3
	    || !strcmp (prop, NM_ACCESS_POINT_RSN_FLAGS)
Packit Service d328f3
	    || !strcmp (prop, NM_ACCESS_POINT_SSID)
Packit Service d328f3
	    || !strcmp (prop, NM_ACCESS_POINT_FREQUENCY)
Packit Service d328f3
	    || !strcmp (prop, NM_ACCESS_POINT_MODE)) {
Packit Service d328f3
		add_hash_to_ap (ap);
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_available_dont_show_cb (NotifyNotification *notify,
Packit Service d328f3
			                 gchar *id,
Packit Service d328f3
			                 gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMApplet *applet = NM_APPLET (user_data);
Packit Service d328f3
Packit Service d328f3
	if (!id || strcmp (id, "dont-show"))
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	g_settings_set_boolean (applet->gsettings,
Packit Service d328f3
	                        PREF_SUPPRESS_WIFI_NETWORKS_AVAILABLE,
Packit Service d328f3
	                        TRUE);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
Packit Service d328f3
struct ap_notification_data 
Packit Service d328f3
{
Packit Service d328f3
	NMApplet *applet;
Packit Service d328f3
	NMDeviceWifi *device;
Packit Service d328f3
	guint id;
Packit Service d328f3
	gulong last_notification_time;
Packit Service d328f3
	guint new_con_id;
Packit Service d328f3
};
Packit Service d328f3
Packit Service d328f3
/* Scan the list of access points, looking for the case where we have no
Packit Service d328f3
 * known (i.e. autoconnect) access points, but we do have unknown ones.
Packit Service d328f3
 * 
Packit Service d328f3
 * If we find one, notify the user.
Packit Service d328f3
 */
Packit Service d328f3
static gboolean
Packit Service d328f3
idle_check_avail_access_point_notification (gpointer datap)
Packit Service d328f3
{	
Packit Service d328f3
	struct ap_notification_data *data = datap;
Packit Service d328f3
	NMApplet *applet = data->applet;
Packit Service d328f3
	NMDeviceWifi *device = data->device;
Packit Service d328f3
	int i;
Packit Service d328f3
	const GPtrArray *aps;
Packit Service d328f3
	GPtrArray *all_connections;
Packit Service d328f3
	GPtrArray *connections;
Packit Service d328f3
	GTimeVal timeval;
Packit Service d328f3
	gboolean have_unused_access_point = FALSE;
Packit Service d328f3
	gboolean have_no_autoconnect_points = TRUE;
Packit Service d328f3
Packit Service d328f3
	data->id = 0;
Packit Service d328f3
Packit Service d328f3
	if (nm_client_get_state (data->applet->nm_client) != NM_STATE_DISCONNECTED)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	if (nm_device_get_state (NM_DEVICE (device)) != NM_DEVICE_STATE_DISCONNECTED)
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	g_get_current_time (&timeval);
Packit Service d328f3
	if ((timeval.tv_sec - data->last_notification_time) < 60*60) /* Notify at most once an hour */
Packit Service d328f3
		return FALSE;	
Packit Service d328f3
Packit Service d328f3
	all_connections = applet_get_all_connections (applet);
Packit Service d328f3
	connections = nm_device_filter_connections (NM_DEVICE (device), all_connections);
Packit Service d328f3
	g_ptr_array_unref (all_connections);	
Packit Service d328f3
Packit Service d328f3
	aps = nm_device_wifi_get_access_points (device);
Packit Service d328f3
	for (i = 0; i < aps->len; i++) {
Packit Service d328f3
		NMAccessPoint *ap = aps->pdata[i];
Packit Service d328f3
		GPtrArray *ap_connections;
Packit Service d328f3
		int a;
Packit Service d328f3
		gboolean is_autoconnect = FALSE;
Packit Service d328f3
Packit Service d328f3
		if (!nm_access_point_get_ssid (ap))
Packit Service d328f3
			continue;
Packit Service d328f3
Packit Service d328f3
		ap_connections = nm_access_point_filter_connections (ap, connections);
Packit Service d328f3
Packit Service d328f3
		for (a = 0; a < ap_connections->len; a++) {
Packit Service d328f3
			NMConnection *connection = NM_CONNECTION (ap_connections->pdata[a]);
Packit Service d328f3
			NMSettingConnection *s_con;
Packit Service d328f3
Packit Service d328f3
			s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
			if (nm_setting_connection_get_autoconnect (s_con))  {
Packit Service d328f3
				is_autoconnect = TRUE;
Packit Service d328f3
				break;
Packit Service d328f3
			}
Packit Service d328f3
		}
Packit Service d328f3
		g_ptr_array_unref (ap_connections);
Packit Service d328f3
Packit Service d328f3
		if (!is_autoconnect)
Packit Service d328f3
			have_unused_access_point = TRUE;
Packit Service d328f3
		else
Packit Service d328f3
			have_no_autoconnect_points = FALSE;
Packit Service d328f3
	}
Packit Service d328f3
	g_ptr_array_unref (connections);
Packit Service d328f3
Packit Service d328f3
	if (!(have_unused_access_point && have_no_autoconnect_points))
Packit Service d328f3
		return FALSE;
Packit Service d328f3
Packit Service d328f3
	/* Avoid notifying too often */
Packit Service d328f3
	g_get_current_time (&timeval);
Packit Service d328f3
	data->last_notification_time = timeval.tv_sec;
Packit Service d328f3
Packit Service d328f3
	applet_do_notify (applet,
Packit Service d328f3
	                  NOTIFY_URGENCY_LOW,
Packit Service d328f3
	                  _("Wi-Fi Networks Available"),
Packit Service d328f3
	                  _("Use the network menu to connect to a Wi-Fi network"),
Packit Service d328f3
	                  "nm-device-wireless",
Packit Service d328f3
	                  "dont-show",
Packit Service d328f3
	                  _("Don’t show this message again"),
Packit Service d328f3
	                  wifi_available_dont_show_cb,
Packit Service d328f3
	                  applet);
Packit Service d328f3
	return FALSE;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
queue_avail_access_point_notification (NMDevice *device)
Packit Service d328f3
{
Packit Service d328f3
	struct ap_notification_data *data;
Packit Service d328f3
Packit Service d328f3
	data = g_object_get_data (G_OBJECT (device), "notify-wifi-avail-data");	
Packit Service d328f3
	if (data->id != 0)
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	if (g_settings_get_boolean (data->applet->gsettings,
Packit Service d328f3
	                            PREF_SUPPRESS_WIFI_NETWORKS_AVAILABLE))
Packit Service d328f3
		return;
Packit Service d328f3
Packit Service d328f3
	data->id = g_timeout_add_seconds (3, idle_check_avail_access_point_notification, data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
access_point_added_cb (NMDeviceWifi *device,
Packit Service d328f3
                       NMAccessPoint *ap,
Packit Service d328f3
                       gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMApplet *applet = NM_APPLET  (user_data);
Packit Service d328f3
Packit Service d328f3
	add_hash_to_ap (ap);
Packit Service d328f3
	g_signal_connect (G_OBJECT (ap),
Packit Service d328f3
	                  "notify",
Packit Service d328f3
	                  G_CALLBACK (notify_ap_prop_changed_cb),
Packit Service d328f3
	                  applet);
Packit Service d328f3
Packit Service d328f3
	queue_avail_access_point_notification (NM_DEVICE (device));
Packit Service d328f3
	applet_schedule_update_menu (applet);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
access_point_removed_cb (NMDeviceWifi *device,
Packit Service d328f3
                         NMAccessPoint *ap,
Packit Service d328f3
                         gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMApplet *applet = NM_APPLET  (user_data);
Packit Service d328f3
	NMAccessPoint *old;
Packit Service d328f3
Packit Service d328f3
	/* If this AP was the active AP, make sure ACTIVE_AP_TAG gets cleared from
Packit Service d328f3
	 * its device.
Packit Service d328f3
	 */
Packit Service d328f3
	old = _active_ap_get (applet, (NMDevice *) device);
Packit Service d328f3
	if (old == ap) {
Packit Service d328f3
		_active_ap_set (applet, (NMDevice *) device, NULL);
Packit Service d328f3
		applet_schedule_update_icon (applet);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	applet_schedule_update_menu (applet);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
on_new_connection (NMClient *client,
Packit Service d328f3
                   NMRemoteConnection *connection,
Packit Service d328f3
                   gpointer datap)
Packit Service d328f3
{
Packit Service d328f3
	struct ap_notification_data *data = datap;
Packit Service d328f3
	queue_avail_access_point_notification (NM_DEVICE (data->device));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
free_ap_notification_data (gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	struct ap_notification_data *data = user_data;
Packit Service d328f3
	NMClient *client = data->applet->nm_client;
Packit Service d328f3
Packit Service d328f3
	nm_clear_g_source (&data->id);
Packit Service d328f3
Packit Service d328f3
	if (client)
Packit Service d328f3
		g_signal_handler_disconnect (client, data->new_con_id);
Packit Service d328f3
	memset (data, 0, sizeof (*data));
Packit Service d328f3
	g_free (data);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_device_added (NMDevice *device, NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	NMDeviceWifi *wdev = NM_DEVICE_WIFI (device);
Packit Service d328f3
	const GPtrArray *aps;
Packit Service d328f3
	int i;
Packit Service d328f3
	struct ap_notification_data *data;
Packit Service d328f3
	guint id;
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (wdev,
Packit Service d328f3
	                  "notify::" NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT,
Packit Service d328f3
	                  G_CALLBACK (notify_active_ap_changed_cb),
Packit Service d328f3
	                  applet);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (wdev,
Packit Service d328f3
	                  "access-point-added",
Packit Service d328f3
	                  G_CALLBACK (access_point_added_cb),
Packit Service d328f3
	                  applet);
Packit Service d328f3
Packit Service d328f3
	g_signal_connect (wdev,
Packit Service d328f3
	                  "access-point-removed",
Packit Service d328f3
	                  G_CALLBACK (access_point_removed_cb),
Packit Service d328f3
	                  applet);
Packit Service d328f3
Packit Service d328f3
	/* Now create the per-device hooks for watching for available wifi
Packit Service d328f3
	 * connections.
Packit Service d328f3
	 */
Packit Service d328f3
	data = g_new0 (struct ap_notification_data, 1);
Packit Service d328f3
	data->applet = applet;
Packit Service d328f3
	data->device = wdev;
Packit Service d328f3
	/* We also need to hook up to the client to find out when we have new connections
Packit Service d328f3
	 * that might be candididates.  Keep the ID around so we can disconnect
Packit Service d328f3
	 * when the device is destroyed.
Packit Service d328f3
	 */ 
Packit Service d328f3
	id = g_signal_connect (applet->nm_client,
Packit Service d328f3
	                       NM_CLIENT_CONNECTION_ADDED,
Packit Service d328f3
	                       G_CALLBACK (on_new_connection),
Packit Service d328f3
	                       data);
Packit Service d328f3
	data->new_con_id = id;
Packit Service d328f3
	g_object_set_data_full (G_OBJECT (wdev), "notify-wifi-avail-data",
Packit Service d328f3
	                        data, free_ap_notification_data);
Packit Service d328f3
Packit Service d328f3
	queue_avail_access_point_notification (device);
Packit Service d328f3
Packit Service d328f3
	/* Hash all APs this device knows about */
Packit Service d328f3
	aps = nm_device_wifi_get_access_points (wdev);
Packit Service d328f3
	for (i = 0; aps && (i < aps->len); i++)
Packit Service d328f3
		add_hash_to_ap (g_ptr_array_index (aps, i));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static NMAccessPoint *
Packit Service d328f3
update_active_ap (NMDevice *device, NMDeviceState state, NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	NMAccessPoint *new = NULL;
Packit Service d328f3
Packit Service d328f3
	if (state == NM_DEVICE_STATE_PREPARE ||
Packit Service d328f3
	    state == NM_DEVICE_STATE_CONFIG ||
Packit Service d328f3
	    state == NM_DEVICE_STATE_IP_CONFIG ||
Packit Service d328f3
	    state == NM_DEVICE_STATE_NEED_AUTH ||
Packit Service d328f3
	    state == NM_DEVICE_STATE_ACTIVATED) {
Packit Service d328f3
		new = nm_device_wifi_get_active_access_point (NM_DEVICE_WIFI (device));
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	_active_ap_set (applet, device, new);
Packit Service d328f3
	return new;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_device_state_changed (NMDevice *device,
Packit Service d328f3
                           NMDeviceState new_state,
Packit Service d328f3
                           NMDeviceState old_state,
Packit Service d328f3
                           NMDeviceStateReason reason,
Packit Service d328f3
                           NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	update_active_ap (device, new_state, applet);
Packit Service d328f3
Packit Service d328f3
	if (new_state == NM_DEVICE_STATE_DISCONNECTED)
Packit Service d328f3
		queue_avail_access_point_notification (device);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_notify_connected (NMDevice *device,
Packit Service d328f3
                       const char *msg,
Packit Service d328f3
                       NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	NMAccessPoint *ap;
Packit Service d328f3
	char *esc_ssid;
Packit Service d328f3
	char *ssid_msg;
Packit Service d328f3
	const char *signal_strength_icon;
Packit Service d328f3
Packit Service d328f3
	ap = _active_ap_get (applet, device);
Packit Service d328f3
Packit Service d328f3
	esc_ssid = get_ssid_utf8 (ap);
Packit Service d328f3
Packit Service d328f3
	if (!ap)
Packit Service d328f3
		signal_strength_icon = "nm-device-wireless";
Packit Service d328f3
	else
Packit Service d328f3
		signal_strength_icon = mobile_helper_get_quality_icon_name (nm_access_point_get_strength (ap));
Packit Service d328f3
Packit Service d328f3
	ssid_msg = g_strdup_printf (_("You are now connected to the Wi-Fi network “%s”."), esc_ssid);
Packit Service d328f3
	applet_do_notify_with_pref (applet, _("Connection Established"),
Packit Service d328f3
	                            ssid_msg, signal_strength_icon,
Packit Service d328f3
	                            PREF_DISABLE_CONNECTED_NOTIFICATIONS);
Packit Service d328f3
	g_free (ssid_msg);
Packit Service d328f3
	g_free (esc_ssid);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_get_icon (NMDevice *device,
Packit Service d328f3
               NMDeviceState state,
Packit Service d328f3
               NMConnection *connection,
Packit Service d328f3
               GdkPixbuf **out_pixbuf,
Packit Service d328f3
               const char **out_icon_name,
Packit Service d328f3
               char **tip,
Packit Service d328f3
               NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	NMSettingConnection *s_con;
Packit Service d328f3
	NMAccessPoint *ap;
Packit Service d328f3
	const char *id;
Packit Service d328f3
	guint8 strength;
Packit Service d328f3
Packit Service d328f3
	g_return_if_fail (out_icon_name && !*out_icon_name);
Packit Service d328f3
	g_return_if_fail (tip && !*tip);
Packit Service d328f3
Packit Service d328f3
	ap = _active_ap_get (applet, device);
Packit Service d328f3
Packit Service d328f3
	id = nm_device_get_iface (device);
Packit Service d328f3
	if (connection) {
Packit Service d328f3
		s_con = nm_connection_get_setting_connection (connection);
Packit Service d328f3
		id = nm_setting_connection_get_id (s_con);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	switch (state) {
Packit Service d328f3
	case NM_DEVICE_STATE_PREPARE:
Packit Service d328f3
		*tip = g_strdup_printf (_("Preparing Wi-Fi network connection “%s”…"), id);
Packit Service d328f3
		break;
Packit Service d328f3
	case NM_DEVICE_STATE_CONFIG:
Packit Service d328f3
		*tip = g_strdup_printf (_("Configuring Wi-Fi network connection “%s”…"), id);
Packit Service d328f3
		break;
Packit Service d328f3
	case NM_DEVICE_STATE_NEED_AUTH:
Packit Service d328f3
		*tip = g_strdup_printf (_("User authentication required for Wi-Fi network “%s”…"), id);
Packit Service d328f3
		break;
Packit Service d328f3
	case NM_DEVICE_STATE_IP_CONFIG:
Packit Service d328f3
		*tip = g_strdup_printf (_("Requesting a Wi-Fi network address for “%s”…"), id);
Packit Service d328f3
		break;
Packit Service d328f3
	case NM_DEVICE_STATE_ACTIVATED:
Packit Service d328f3
		strength = ap ? nm_access_point_get_strength (ap) : 0;
Packit Service d328f3
		strength = MIN (strength, 100);
Packit Service d328f3
Packit Service d328f3
		*out_icon_name = mobile_helper_get_quality_icon_name (strength);
Packit Service d328f3
Packit Service d328f3
		if (ap) {
Packit Service d328f3
			char *ssid = get_ssid_utf8 (ap);
Packit Service d328f3
Packit Service d328f3
			*tip = g_strdup_printf (_("Wi-Fi network connection “%s” active: %s (%d%%)"),
Packit Service d328f3
			                        id, ssid, strength);
Packit Service d328f3
			g_free (ssid);
Packit Service d328f3
		} else
Packit Service d328f3
			*tip = g_strdup_printf (_("Wi-Fi network connection “%s” active"), id);
Packit Service d328f3
		break;
Packit Service d328f3
	default:
Packit Service d328f3
		break;
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
activate_existing_cb (GObject *client,
Packit Service d328f3
                      GAsyncResult *result,
Packit Service d328f3
                      gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	GError *error = NULL;
Packit Service d328f3
	NMActiveConnection *active;
Packit Service d328f3
Packit Service d328f3
	active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error);
Packit Service d328f3
	g_clear_object (&active);
Packit Service d328f3
	if (error) {
Packit Service d328f3
		const char *text = _("Failed to activate connection");
Packit Service d328f3
		char *err_text = g_strdup_printf ("(%d) %s", error->code,
Packit Service d328f3
		                                  error->message ? error->message : _("Unknown error"));
Packit Service d328f3
Packit Service d328f3
		g_warning ("%s: %s", text, err_text);
Packit Service d328f3
		utils_show_error_dialog (_("Connection failure"), text, err_text, FALSE, NULL);
Packit Service d328f3
		g_free (err_text);
Packit Service d328f3
		g_error_free (error);
Packit Service d328f3
	}
Packit Service d328f3
	applet_schedule_update_icon (NM_APPLET (user_data));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
activate_new_cb (GObject *client,
Packit Service d328f3
                 GAsyncResult *result,
Packit Service d328f3
                 gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	GError *error = NULL;
Packit Service d328f3
	NMActiveConnection *active;
Packit Service d328f3
Packit Service d328f3
	active = nm_client_add_and_activate_connection_finish (NM_CLIENT (client), result, &error);
Packit Service d328f3
	g_clear_object (&active);
Packit Service d328f3
	if (error) {
Packit Service d328f3
		const char *text = _("Failed to add new connection");
Packit Service d328f3
		char *err_text = g_strdup_printf ("(%d) %s", error->code,
Packit Service d328f3
		                                  error->message ? error->message : _("Unknown error"));
Packit Service d328f3
Packit Service d328f3
		g_warning ("%s: %s", text, err_text);
Packit Service d328f3
		utils_show_error_dialog (_("Connection failure"), text, err_text, FALSE, NULL);
Packit Service d328f3
		g_free (err_text);
Packit Service d328f3
		g_error_free (error);
Packit Service d328f3
	}
Packit Service d328f3
	applet_schedule_update_icon (NM_APPLET (user_data));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
wifi_dialog_response_cb (GtkDialog *foo,
Packit Service d328f3
                         gint response,
Packit Service d328f3
                         gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	NMAWifiDialog *dialog = NMA_WIFI_DIALOG (foo);
Packit Service d328f3
	NMApplet *applet = NM_APPLET (user_data);
Packit Service d328f3
	NMConnection *connection = NULL, *fuzzy_match = NULL;
Packit Service d328f3
	NMDevice *device = NULL;
Packit Service d328f3
	NMAccessPoint *ap = NULL;
Packit Service d328f3
	GPtrArray *all;
Packit Service d328f3
	int i;
Packit Service d328f3
Packit Service d328f3
	if (response != GTK_RESPONSE_OK)
Packit Service d328f3
		goto done;
Packit Service d328f3
Packit Service d328f3
	/* nma_wifi_dialog_get_connection() returns a connection with the
Packit Service d328f3
	 * refcount incremented, so the caller must remember to unref it.
Packit Service d328f3
	 */
Packit Service d328f3
	connection = nma_wifi_dialog_get_connection (dialog, &device, &ap);
Packit Service d328f3
	g_assert (connection);
Packit Service d328f3
	g_assert (device);
Packit Service d328f3
Packit Service d328f3
	/* Find a similar connection and use that instead */
Packit Service d328f3
	all = applet_get_all_connections (applet);
Packit Service d328f3
	for (i = 0; i < all->len; i++) {
Packit Service d328f3
		if (nm_connection_compare (connection,
Packit Service d328f3
		                           NM_CONNECTION (all->pdata[i]),
Packit Service d328f3
		                           (NM_SETTING_COMPARE_FLAG_FUZZY | NM_SETTING_COMPARE_FLAG_IGNORE_ID))) {
Packit Service d328f3
			fuzzy_match = NM_CONNECTION (all->pdata[i]);
Packit Service d328f3
			break;
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
	g_ptr_array_unref (all);
Packit Service d328f3
Packit Service d328f3
	if (fuzzy_match) {
Packit Service d328f3
		nm_client_activate_connection_async (applet->nm_client,
Packit Service d328f3
		                                     fuzzy_match,
Packit Service d328f3
		                                     device,
Packit Service d328f3
		                                     ap ? nm_object_get_path (NM_OBJECT (ap)) : NULL,
Packit Service d328f3
		                                     NULL,
Packit Service d328f3
		                                     activate_existing_cb,
Packit Service d328f3
		                                     applet);
Packit Service d328f3
	} else {
Packit Service d328f3
		NMSetting *s_con;
Packit Service d328f3
		NMSettingWireless *s_wifi = NULL;
Packit Service d328f3
		const char *mode = NULL;
Packit Service d328f3
Packit Service d328f3
		/* Entirely new connection */
Packit Service d328f3
Packit Service d328f3
		/* Don't autoconnect adhoc networks by default for now */
Packit Service d328f3
		s_wifi = nm_connection_get_setting_wireless (connection);
Packit Service d328f3
		if (s_wifi)
Packit Service d328f3
			mode = nm_setting_wireless_get_mode (s_wifi);
Packit Service d328f3
		if (g_strcmp0 (mode, "adhoc") == 0 || g_strcmp0 (mode, "ap") == 0) {
Packit Service d328f3
			s_con = nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
Packit Service d328f3
			if (!s_con) {
Packit Service d328f3
				s_con = nm_setting_connection_new ();
Packit Service d328f3
				nm_connection_add_setting (connection, s_con);
Packit Service d328f3
			}
Packit Service d328f3
			g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, NULL);
Packit Service d328f3
		}
Packit Service d328f3
Packit Service d328f3
		nm_client_add_and_activate_connection_async (applet->nm_client,
Packit Service d328f3
		                                             connection,
Packit Service d328f3
		                                             device,
Packit Service d328f3
		                                             ap ? nm_object_get_path (NM_OBJECT (ap)) : NULL,
Packit Service d328f3
		                                             NULL,
Packit Service d328f3
		                                             activate_new_cb,
Packit Service d328f3
		                                             applet);
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Balance nma_wifi_dialog_get_connection() */
Packit Service d328f3
	g_object_unref (connection);
Packit Service d328f3
Packit Service d328f3
done:
Packit Service d328f3
	gtk_widget_hide (GTK_WIDGET (dialog));
Packit Service d328f3
	gtk_widget_destroy (GTK_WIDGET (dialog));
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static GVariant *
Packit Service d328f3
remove_unwanted_secrets (GVariant *secrets, gboolean keep_8021X)
Packit Service d328f3
{
Packit Service d328f3
	GVariant *copy, *setting_dict;
Packit Service d328f3
	const char *setting_name;
Packit Service d328f3
	GVariantBuilder conn_builder;
Packit Service d328f3
	GVariantIter conn_iter;
Packit Service d328f3
Packit Service d328f3
	g_variant_builder_init (&conn_builder, NM_VARIANT_TYPE_CONNECTION);
Packit Service d328f3
	g_variant_iter_init (&conn_iter, secrets);
Packit Service d328f3
	while (g_variant_iter_next (&conn_iter, "{&s@a{sv}}", &setting_name, &setting_dict)) {
Packit Service d328f3
		if (   !strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME)
Packit Service d328f3
		    || (!strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) && keep_8021X))
Packit Service d328f3
			g_variant_builder_add (&conn_builder, "{s@a{sv}}", setting_name, setting_dict);
Packit Service d328f3
Packit Service d328f3
		g_variant_unref (setting_dict);
Packit Service d328f3
	}
Packit Service d328f3
	copy = g_variant_builder_end (&conn_builder);
Packit Service d328f3
	g_variant_unref (secrets);
Packit Service d328f3
Packit Service d328f3
	return copy;
Packit Service d328f3
}
Packit Service d328f3
	
Packit Service d328f3
Packit Service d328f3
typedef struct {
Packit Service d328f3
	SecretsRequest req;
Packit Service d328f3
Packit Service d328f3
	GtkWidget *dialog;
Packit Service d328f3
} NMWifiInfo;
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
free_wifi_info (SecretsRequest *req)
Packit Service d328f3
{
Packit Service d328f3
	NMWifiInfo *info = (NMWifiInfo *) req;
Packit Service d328f3
Packit Service d328f3
	if (info->dialog) {
Packit Service d328f3
		gtk_widget_hide (info->dialog);
Packit Service d328f3
		gtk_widget_destroy (info->dialog);
Packit Service d328f3
		info->dialog = NULL;
Packit Service d328f3
	}
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static void
Packit Service d328f3
get_secrets_dialog_response_cb (GtkDialog *foo,
Packit Service d328f3
                                gint response,
Packit Service d328f3
                                gpointer user_data)
Packit Service d328f3
{
Packit Service d328f3
	SecretsRequest *req = user_data;
Packit Service d328f3
	NMWifiInfo *info = (NMWifiInfo *) req;
Packit Service d328f3
	NMAWifiDialog *dialog = NMA_WIFI_DIALOG (info->dialog);
Packit Service d328f3
	NMConnection *connection = NULL;
Packit Service d328f3
	NMSettingWirelessSecurity *s_wireless_sec;
Packit Service d328f3
	GVariant *secrets = NULL;
Packit Service d328f3
	const char *key_mgmt, *auth_alg;
Packit Service d328f3
	gboolean keep_8021X = FALSE;
Packit Service d328f3
	GError *error = NULL;
Packit Service d328f3
Packit Service d328f3
	if (response != GTK_RESPONSE_OK) {
Packit Service d328f3
		g_set_error (&error,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR_USER_CANCELED,
Packit Service d328f3
		             "%s.%d (%s): canceled",
Packit Service d328f3
		             __FILE__, __LINE__, __func__);
Packit Service d328f3
		goto done;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	connection = nma_wifi_dialog_get_connection (dialog, NULL, NULL);
Packit Service d328f3
	if (!connection) {
Packit Service d328f3
		g_set_error (&error,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR_FAILED,
Packit Service d328f3
		             "%s.%d (%s): couldn't get connection from Wi-Fi dialog.",
Packit Service d328f3
		             __FILE__, __LINE__, __func__);
Packit Service d328f3
		goto done;
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Second-guess which setting NM wants secrets for. */
Packit Service d328f3
	s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
Packit Service d328f3
	if (!s_wireless_sec) {
Packit Service d328f3
		g_set_error (&error,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
Packit Service d328f3
		             "%s.%d (%s): requested setting '802-11-wireless-security'"
Packit Service d328f3
		             " didn't exist in the connection.",
Packit Service d328f3
		             __FILE__, __LINE__, __func__);
Packit Service d328f3
		goto done;  /* Unencrypted */
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	secrets = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
Packit Service d328f3
	if (!secrets) {
Packit Service d328f3
		g_set_error (&error,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR_FAILED,
Packit Service d328f3
		             "%s.%d (%s): failed to hash connection '%s'.",
Packit Service d328f3
		             __FILE__, __LINE__, __func__, nm_connection_get_id (connection));
Packit Service d328f3
		goto done;
Packit Service d328f3
	}
Packit Service d328f3
	/* If the user chose an 802.1x-based auth method, return 802.1x secrets,
Packit Service d328f3
	 * not wireless secrets.  Can happen with Dynamic WEP, because NM doesn't
Packit Service d328f3
	 * know the capabilities of the AP (since Dynamic WEP APs don't broadcast
Packit Service d328f3
	 * beacons), and therefore defaults to requesting WEP secrets from the
Packit Service d328f3
	 * wireless-security setting, not the 802.1x setting.
Packit Service d328f3
	 */
Packit Service d328f3
	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);
Packit Service d328f3
	if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) {
Packit Service d328f3
		/* LEAP secrets aren't in the 802.1x setting */
Packit Service d328f3
		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wireless_sec);
Packit Service d328f3
		if (!auth_alg || strcmp (auth_alg, "leap")) {
Packit Service d328f3
			NMSetting8021x *s_8021x;
Packit Service d328f3
Packit Service d328f3
			s_8021x = nm_connection_get_setting_802_1x (connection);
Packit Service d328f3
			if (!s_8021x) {
Packit Service d328f3
				g_set_error (&error,
Packit Service d328f3
				             NM_SECRET_AGENT_ERROR,
Packit Service d328f3
				             NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
Packit Service d328f3
				             "%s.%d (%s): requested setting '802-1x' didn't"
Packit Service d328f3
				             " exist in the connection.",
Packit Service d328f3
				             __FILE__, __LINE__, __func__);
Packit Service d328f3
				goto done;
Packit Service d328f3
			}
Packit Service d328f3
			keep_8021X = TRUE;
Packit Service d328f3
		}
Packit Service d328f3
	}
Packit Service d328f3
Packit Service d328f3
	/* Remove all not-relevant secrets (inner dicts) */
Packit Service d328f3
	secrets = remove_unwanted_secrets (secrets, keep_8021X);
Packit Service d328f3
	g_variant_take_ref (secrets);
Packit Service d328f3
Packit Service d328f3
done:
Packit Service d328f3
	applet_secrets_request_complete (req, secrets, error);
Packit Service d328f3
	applet_secrets_request_free (req);
Packit Service d328f3
Packit Service d328f3
	if (secrets)
Packit Service d328f3
		g_variant_unref (secrets);
Packit Service d328f3
	if (connection)
Packit Service d328f3
		nm_connection_clear_secrets (connection);
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
static gboolean
Packit Service d328f3
wifi_get_secrets (SecretsRequest *req, GError **error)
Packit Service d328f3
{
Packit Service d328f3
	NMWifiInfo *info = (NMWifiInfo *) req;
Packit Service d328f3
Packit Service d328f3
	g_return_val_if_fail (!info->dialog, FALSE);
Packit Service d328f3
Packit Service d328f3
	info->dialog = nma_wifi_dialog_new_for_secrets (req->applet->nm_client,
Packit Service d328f3
	                                                req->connection,
Packit Service d328f3
	                                                req->setting_name,
Packit Service d328f3
	                                                (const char *const*) req->hints);
Packit Service d328f3
	if (info->dialog) {
Packit Service d328f3
		applet_secrets_request_set_free_func (req, free_wifi_info);
Packit Service d328f3
		g_signal_connect (info->dialog, "response",
Packit Service d328f3
		                  G_CALLBACK (get_secrets_dialog_response_cb),
Packit Service d328f3
		                  info);
Packit Service d328f3
		show_ignore_focus_stealing_prevention (info->dialog);
Packit Service d328f3
	} else {
Packit Service d328f3
		g_set_error (error,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR,
Packit Service d328f3
		             NM_SECRET_AGENT_ERROR_FAILED,
Packit Service d328f3
		             "%s.%d (%s): couldn't display secrets UI",
Packit Service d328f3
		             __FILE__, __LINE__, __func__);
Packit Service d328f3
	}
Packit Service d328f3
	return !!info->dialog;
Packit Service d328f3
}
Packit Service d328f3
Packit Service d328f3
NMADeviceClass *
Packit Service d328f3
applet_device_wifi_get_class (NMApplet *applet)
Packit Service d328f3
{
Packit Service d328f3
	NMADeviceClass *dclass;
Packit Service d328f3
Packit Service d328f3
	dclass = g_slice_new0 (NMADeviceClass);
Packit Service d328f3
	if (!dclass)
Packit Service d328f3
		return NULL;
Packit Service d328f3
Packit Service d328f3
	dclass->new_auto_connection = wifi_new_auto_connection;
Packit Service d328f3
	dclass->add_menu_item = wifi_add_menu_item;
Packit Service d328f3
	dclass->device_added = wifi_device_added;
Packit Service d328f3
	dclass->device_state_changed = wifi_device_state_changed;
Packit Service d328f3
	dclass->notify_connected = wifi_notify_connected;
Packit Service d328f3
	dclass->get_icon = wifi_get_icon;
Packit Service d328f3
	dclass->get_secrets = wifi_get_secrets;
Packit Service d328f3
	dclass->secrets_request_size = sizeof (NMWifiInfo);
Packit Service d328f3
Packit Service d328f3
	return dclass;
Packit Service d328f3
}
Packit Service d328f3