/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager Applet -- allow user control over networking
*
* Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright 2007 - 2017 Red Hat, Inc.
*/
#include "nm-default.h"
#include <string.h>
#include <netinet/ether.h>
#include <NetworkManager.h>
#include "nma-wifi-dialog.h"
#include "wireless-security.h"
#include "eap-method.h"
G_DEFINE_TYPE (NMAWifiDialog, nma_wifi_dialog, GTK_TYPE_DIALOG)
#define NMA_WIFI_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
NMA_TYPE_WIFI_DIALOG, \
NMAWifiDialogPrivate))
typedef struct {
NMAWifiDialog *self;
NMConnection *connection;
gboolean canceled;
} GetSecretsInfo;
typedef struct {
NMClient *client;
GtkBuilder *builder;
NMConnection *specific_connection;
NMConnection *connection;
NMDevice *device;
NMAccessPoint *ap;
guint operation;
GtkTreeModel *device_model;
GtkTreeModel *connection_model;
GtkSizeGroup *group;
GtkWidget *sec_combo;
GtkWidget *ok_response_button;
gboolean network_name_focus;
gboolean secrets_only;
guint revalidate_id;
GetSecretsInfo *secrets_info;
} NMAWifiDialogPrivate;
enum {
OP_NONE = 0,
OP_CREATE_ADHOC,
OP_CONNECT_HIDDEN,
};
#define D_NAME_COLUMN 0
#define D_DEV_COLUMN 1
#define S_NAME_COLUMN 0
#define S_SEC_COLUMN 1
#define C_NAME_COLUMN 0
#define C_CON_COLUMN 1
#define C_SEP_COLUMN 2
#define C_NEW_COLUMN 3
static gboolean security_combo_init (NMAWifiDialog *self, gboolean secrets_only,
const char *secrets_setting_name,
const char *const*secrets_hints);
static void ssid_entry_changed (GtkWidget *entry, gpointer user_data);
void
nma_wifi_dialog_set_nag_ignored (NMAWifiDialog *self, gboolean ignored)
{
}
gboolean
nma_wifi_dialog_get_nag_ignored (NMAWifiDialog *self)
{
return TRUE;
}
static void
size_group_clear (GtkSizeGroup *group)
{
GSList *iter;
g_return_if_fail (group != NULL);
iter = gtk_size_group_get_widgets (group);
while (iter) {
gtk_size_group_remove_widget (group, GTK_WIDGET (iter->data));
iter = gtk_size_group_get_widgets (group);
}
}
static void
_set_ok_sensitive (NMAWifiDialog *self, gboolean is_sensitive, const char *error_tooltip)
{
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK, is_sensitive);
if (priv->ok_response_button) {
gtk_widget_set_tooltip_text (priv->ok_response_button,
is_sensitive ? _("Click to connect") : error_tooltip);
}
}
static void
size_group_add_permanent (GtkSizeGroup *group,
GtkBuilder *builder)
{
GtkWidget *widget;
g_return_if_fail (group != NULL);
g_return_if_fail (builder != NULL);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "network_name_label"));
gtk_size_group_add_widget (group, widget);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "security_combo_label"));
gtk_size_group_add_widget (group, widget);
widget = GTK_WIDGET (gtk_builder_get_object (builder, "device_label"));
gtk_size_group_add_widget (group, widget);
}
static void
security_combo_changed (GtkWidget *combo,
gpointer user_data)
{
NMAWifiDialog *self = NMA_WIFI_DIALOG (user_data);
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GtkWidget *vbox, *sec_widget, *def_widget;
GList *elt, *children;
GtkTreeIter iter;
GtkTreeModel *model;
WirelessSecurity *sec = NULL;
vbox = GTK_WIDGET (gtk_builder_get_object (priv->builder, "security_vbox"));
g_assert (vbox);
size_group_clear (priv->group);
/* Remove any previous wireless security widgets */
children = gtk_container_get_children (GTK_CONTAINER (vbox));
for (elt = children; elt; elt = g_list_next (elt))
gtk_container_remove (GTK_CONTAINER (vbox), GTK_WIDGET (elt->data));
g_list_free (children);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
g_warning ("%s: no active security combo box item.", __func__);
return;
}
gtk_tree_model_get (model, &iter, S_SEC_COLUMN, &sec, -1);
if (!sec) {
/* Revalidate dialog if the user picked "None" so the OK button
* gets enabled if there's already a valid SSID.
*/
ssid_entry_changed (NULL, self);
return;
}
sec_widget = wireless_security_get_widget (sec);
g_assert (sec_widget);
gtk_widget_unparent (sec_widget);
size_group_add_permanent (priv->group, priv->builder);
wireless_security_add_to_size_group (sec, priv->group);
gtk_container_add (GTK_CONTAINER (vbox), sec_widget);
/* Re-validate */
wireless_security_changed_cb (NULL, sec);
/* Set focus to the security method's default widget, but only if the
* network name entry should not be focused.
*/
if (!priv->network_name_focus && sec->default_field) {
def_widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, sec->default_field));
if (def_widget)
gtk_widget_grab_focus (def_widget);
}
wireless_security_unref (sec);
}
static void
security_combo_changed_manually (GtkWidget *combo,
gpointer user_data)
{
NMAWifiDialog *self = NMA_WIFI_DIALOG (user_data);
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
/* Flag that the combo was changed manually to allow focus to move
* to the security method's default widget instead of the network name.
*/
priv->network_name_focus = FALSE;
security_combo_changed (combo, user_data);
}
static GBytes *
validate_dialog_ssid (NMAWifiDialog *self)
{
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GtkWidget *widget;
const char *ssid;
GBytes *ssid_bytes;
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "network_name_entry"));
ssid = gtk_entry_get_text (GTK_ENTRY (widget));
if (!ssid || strlen (ssid) == 0 || strlen (ssid) > 32)
return NULL;
ssid_bytes = g_bytes_new (ssid, strlen (ssid));
return ssid_bytes;
}
static void
stuff_changed_cb (WirelessSecurity *sec, gpointer user_data)
{
NMAWifiDialog *self = NMA_WIFI_DIALOG (user_data);
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GBytes *ssid = NULL;
gboolean free_ssid = TRUE;
gboolean valid = FALSE;
GtkTreeModel *model;
GtkTreeIter iter;
WirelessSecurity *sel_sec = NULL;
gs_free_error GError *error = NULL;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->sec_combo));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (priv->sec_combo), &iter))
gtk_tree_model_get (model, &iter, S_SEC_COLUMN, &sel_sec, -1);
if (sel_sec)
wireless_security_unref (sel_sec);
if (sel_sec != sec)
return;
if (priv->connection) {
NMSettingWireless *s_wireless;
s_wireless = nm_connection_get_setting_wireless (priv->connection);
g_assert (s_wireless);
ssid = nm_setting_wireless_get_ssid (s_wireless);
free_ssid = FALSE;
} else {
ssid = validate_dialog_ssid (self);
}
if (ssid) {
valid = wireless_security_validate (sec, &error);
if (free_ssid)
g_bytes_unref (ssid);
}
/* But if there's an in-progress secrets call (which might require authorization)
* then we don't want to enable the OK button because we don't have all the
* connection details yet.
*/
if (priv->secrets_info)
valid = FALSE;
_set_ok_sensitive (self, valid, error ? error->message : NULL);
}
static void
ssid_entry_changed (GtkWidget *entry, gpointer user_data)
{
NMAWifiDialog *self = NMA_WIFI_DIALOG (user_data);
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GtkTreeIter iter;
WirelessSecurity *sec = NULL;
GtkTreeModel *model;
gboolean valid = FALSE;
GBytes *ssid;
gs_free_error GError *error = NULL;
/* If the network name entry was touched at all, allow focus to go to
* the default widget of the security method now.
*/
priv->network_name_focus = FALSE;
ssid = validate_dialog_ssid (self);
if (!ssid)
goto out;
g_bytes_unref (ssid);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->sec_combo));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (priv->sec_combo), &iter))
gtk_tree_model_get (model, &iter, S_SEC_COLUMN, &sec, -1);
if (sec) {
valid = wireless_security_validate (sec, &error);
wireless_security_unref (sec);
} else {
valid = TRUE;
}
out:
/* But if there's an in-progress secrets call (which might require authorization)
* then we don't want to enable the OK button because we don't have all the
* connection details yet.
*/
if (priv->secrets_info)
valid = FALSE;
_set_ok_sensitive (self, valid, error ? error->message : NULL);
}
static void
connection_combo_changed (GtkWidget *combo,
gpointer user_data)
{
NMAWifiDialog *self = NMA_WIFI_DIALOG (user_data);
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GtkTreeIter iter;
GtkTreeModel *model;
gboolean is_new = FALSE;
NMSettingWireless *s_wireless;
char *utf8_ssid;
GtkWidget *widget;
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
g_warning ("%s: no active connection combo box item.", __func__);
return;
}
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
if (priv->connection)
g_object_unref (priv->connection);
gtk_tree_model_get (model, &iter,
C_CON_COLUMN, &priv->connection,
C_NEW_COLUMN, &is_new, -1);
if (priv->connection)
eap_method_ca_cert_ignore_load (priv->connection);
if (!security_combo_init (self, priv->secrets_only, NULL, NULL)) {
g_warning ("Couldn't change Wi-Fi security combo box.");
return;
}
security_combo_changed (priv->sec_combo, self);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "network_name_entry"));
if (priv->connection) {
GBytes *ssid;
s_wireless = nm_connection_get_setting_wireless (priv->connection);
ssid = nm_setting_wireless_get_ssid (s_wireless);
utf8_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid));
gtk_entry_set_text (GTK_ENTRY (widget), utf8_ssid);
g_free (utf8_ssid);
} else {
gtk_entry_set_text (GTK_ENTRY (widget), "");
}
gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "network_name_entry")), is_new);
gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "network_name_label")), is_new);
gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "security_combo")), is_new);
gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "security_combo_label")), is_new);
gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (priv->builder, "security_vbox")), is_new);
}
static gboolean
connection_combo_separator_cb (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
gboolean is_separator = FALSE;
gtk_tree_model_get (model, iter, C_SEP_COLUMN, &is_separator, -1);
return is_separator;
}
static gint
alphabetize_connections (NMConnection *a, NMConnection *b)
{
NMSettingConnection *asc, *bsc;
asc = nm_connection_get_setting_connection (a);
bsc = nm_connection_get_setting_connection (b);
return strcmp (nm_setting_connection_get_id (asc),
nm_setting_connection_get_id (bsc));
}
static gboolean
connection_combo_init (NMAWifiDialog *self)
{
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GtkListStore *store;
int num_added = 0;
GtkTreeIter tree_iter;
GtkWidget *widget;
NMSettingConnection *s_con;
GtkCellRenderer *renderer;
const char *id;
g_clear_object (&priv->connection_model);
g_clear_object (&priv->connection);
/* New model */
store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_OBJECT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
priv->connection_model = GTK_TREE_MODEL (store);
if (priv->specific_connection) {
s_con = nm_connection_get_setting_connection (priv->specific_connection);
g_assert (s_con);
id = nm_setting_connection_get_id (s_con);
if (id == NULL) {
/* New connections which will be completed by NM won't have an ID
* yet, but that doesn't matter because we don't show the connection
* combo anyway when there's a predefined connection.
*/
id = "blahblah";
}
gtk_list_store_append (store, &tree_iter);
gtk_list_store_set (store, &tree_iter,
C_NAME_COLUMN, id,
C_CON_COLUMN, priv->specific_connection, -1);
} else {
GSList *to_add = NULL, *iter;
const GPtrArray *connections;
int i;
gtk_list_store_append (store, &tree_iter);
gtk_list_store_set (store, &tree_iter,
C_NAME_COLUMN, _("New…"),
C_NEW_COLUMN, TRUE, -1);
gtk_list_store_append (store, &tree_iter);
gtk_list_store_set (store, &tree_iter, C_SEP_COLUMN, TRUE, -1);
connections = nm_client_get_connections (priv->client);
for (i = 0; i < connections->len; i++) {
NMConnection *candidate = NM_CONNECTION (connections->pdata[i]);
NMSettingWireless *s_wireless;
const char *connection_type;
const char *mode;
const char *setting_mac, *hw_addr;
s_con = nm_connection_get_setting_connection (candidate);
connection_type = s_con ? nm_setting_connection_get_connection_type (s_con) : NULL;
if (!connection_type)
continue;
if (strcmp (connection_type, NM_SETTING_WIRELESS_SETTING_NAME))
continue;
s_wireless = nm_connection_get_setting_wireless (candidate);
if (!s_wireless)
continue;
/* If creating a new Ad-Hoc network, only show shared network connections */
if (priv->operation == OP_CREATE_ADHOC) {
NMSettingIPConfig *s_ip4;
const char *method = NULL;
s_ip4 = nm_connection_get_setting_ip4_config (candidate);
if (s_ip4)
method = nm_setting_ip_config_get_method (s_ip4);
if (!s_ip4 || strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED))
continue;
/* Ignore non-Ad-Hoc connections too */
mode = nm_setting_wireless_get_mode (s_wireless);
if (!mode || (strcmp (mode, "adhoc") && strcmp (mode, "ap")))
continue;
}
/* Ignore connections that don't apply to the selected device */
setting_mac = nm_setting_wireless_get_mac_address (s_wireless);
hw_addr = nm_device_wifi_get_hw_address (NM_DEVICE_WIFI (priv->device));
if ( setting_mac
&& hw_addr
&& !nm_utils_hwaddr_matches (setting_mac, -1, hw_addr, -1))
continue;
to_add = g_slist_append (to_add, candidate);
}
/* Alphabetize the list then add the connections */
to_add = g_slist_sort (to_add, (GCompareFunc) alphabetize_connections);
for (iter = to_add; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = NM_CONNECTION (iter->data);
s_con = nm_connection_get_setting_connection (candidate);
gtk_list_store_append (store, &tree_iter);
gtk_list_store_set (store, &tree_iter,
C_NAME_COLUMN, nm_setting_connection_get_id (s_con),
C_CON_COLUMN, candidate, -1);
num_added++;
}
g_slist_free (to_add);
}
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "connection_combo"));
gtk_cell_layout_clear (GTK_CELL_LAYOUT (widget));
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (widget), renderer,
"text", C_NAME_COLUMN);
gtk_combo_box_set_wrap_width (GTK_COMBO_BOX (widget), 1);
gtk_combo_box_set_model (GTK_COMBO_BOX (widget), priv->connection_model);
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (widget),
connection_combo_separator_cb,
NULL,
NULL);
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
g_signal_handlers_disconnect_by_func (widget, connection_combo_changed, self);
if (priv->specific_connection || !num_added) {
gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (priv->builder, "connection_label")));
gtk_widget_hide (widget);
} else {
g_signal_connect (widget, "changed",
G_CALLBACK (connection_combo_changed), self);
}
if (gtk_tree_model_get_iter_first (priv->connection_model, &tree_iter))
gtk_tree_model_get (priv->connection_model, &tree_iter, C_CON_COLUMN, &priv->connection, -1);
return TRUE;
}
static void
device_combo_changed (GtkWidget *combo,
gpointer user_data)
{
NMAWifiDialog *self = NMA_WIFI_DIALOG (user_data);
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GtkTreeIter iter;
GtkTreeModel *model;
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
g_warning ("%s: no active device combo box item.", __func__);
return;
}
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
g_object_unref (priv->device);
gtk_tree_model_get (model, &iter, D_DEV_COLUMN, &priv->device, -1);
if (!connection_combo_init (self)) {
g_warning ("Couldn't change connection combo box.");
return;
}
if (!security_combo_init (self, priv->secrets_only, NULL, NULL)) {
g_warning ("Couldn't change Wi-Fi security combo box.");
return;
}
security_combo_changed (priv->sec_combo, self);
}
static void
add_device_to_model (GtkListStore *model, NMDevice *device)
{
GtkTreeIter iter;
const char *desc;
desc = nm_device_get_description (device);
gtk_list_store_append (model, &iter);
gtk_list_store_set (model, &iter, D_NAME_COLUMN, desc, D_DEV_COLUMN, device, -1);
}
static gboolean
can_use_device (NMDevice *device)
{
/* Ignore unsupported devices */
if (!(nm_device_get_capabilities (device) & NM_DEVICE_CAP_NM_SUPPORTED))
return FALSE;
if (!NM_IS_DEVICE_WIFI (device))
return FALSE;
if (nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED)
return FALSE;
return TRUE;
}
static gboolean
device_combo_init (NMAWifiDialog *self, NMDevice *device)
{
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
const GPtrArray *devices;
GtkListStore *store;
int i, num_added = 0;
g_return_val_if_fail (priv->device == NULL, FALSE);
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_OBJECT);
priv->device_model = GTK_TREE_MODEL (store);
if (device) {
if (!can_use_device (device))
return FALSE;
add_device_to_model (store, device);
num_added++;
} else {
devices = nm_client_get_devices (priv->client);
if (!devices)
return FALSE;
for (i = 0; devices && (i < devices->len); i++) {
device = NM_DEVICE (g_ptr_array_index (devices, i));
if (can_use_device (device)) {
add_device_to_model (store, device);
num_added++;
}
}
}
if (num_added > 0) {
GtkWidget *widget;
GtkTreeIter iter;
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "device_combo"));
gtk_combo_box_set_model (GTK_COMBO_BOX (widget), priv->device_model);
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
g_signal_connect (G_OBJECT (widget), "changed",
G_CALLBACK (device_combo_changed), self);
if (num_added == 1) {
gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (priv->builder, "device_label")));
gtk_widget_hide (widget);
}
if (gtk_tree_model_get_iter_first (priv->device_model, &iter))
gtk_tree_model_get (priv->device_model, &iter, D_DEV_COLUMN, &priv->device, -1);
}
return num_added > 0 ? TRUE : FALSE;
}
static gboolean
find_proto (NMSettingWirelessSecurity *sec, const char *item)
{
guint32 i;
for (i = 0; i < nm_setting_wireless_security_get_num_protos (sec); i++) {
if (!strcmp (item, nm_setting_wireless_security_get_proto (sec, i)))
return TRUE;
}
return FALSE;
}
static NMUtilsSecurityType
get_default_type_for_security (NMSettingWirelessSecurity *sec,
gboolean have_ap,
guint32 ap_flags,
guint32 dev_caps)
{
const char *key_mgmt, *auth_alg;
g_return_val_if_fail (sec != NULL, NMU_SEC_NONE);
key_mgmt = nm_setting_wireless_security_get_key_mgmt (sec);
auth_alg = nm_setting_wireless_security_get_auth_alg (sec);
/* No IEEE 802.1x */
if (!strcmp (key_mgmt, "none"))
return NMU_SEC_STATIC_WEP;
if ( !strcmp (key_mgmt, "ieee8021x")
&& (!have_ap || (ap_flags & NM_802_11_AP_FLAGS_PRIVACY))) {
if (auth_alg && !strcmp (auth_alg, "leap"))
return NMU_SEC_LEAP;
return NMU_SEC_DYNAMIC_WEP;
}
if ( !strcmp (key_mgmt, "wpa-none")
|| !strcmp (key_mgmt, "wpa-psk")) {
if (!have_ap || (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)) {
if (find_proto (sec, "rsn"))
return NMU_SEC_WPA2_PSK;
else if (find_proto (sec, "wpa"))
return NMU_SEC_WPA_PSK;
else
return NMU_SEC_WPA_PSK;
}
}
if ( !strcmp (key_mgmt, "wpa-eap")
&& (!have_ap || (ap_flags & NM_802_11_AP_FLAGS_PRIVACY))) {
if (find_proto (sec, "rsn"))
return NMU_SEC_WPA2_ENTERPRISE;
else if (find_proto (sec, "wpa"))
return NMU_SEC_WPA_ENTERPRISE;
else
return NMU_SEC_WPA_ENTERPRISE;
}
return NMU_SEC_INVALID;
}
static void
add_security_item (NMAWifiDialog *self,
WirelessSecurity *sec,
GtkListStore *model,
GtkTreeIter *iter,
const char *text)
{
wireless_security_set_changed_notify (sec, stuff_changed_cb, self);
gtk_list_store_append (model, iter);
gtk_list_store_set (model, iter, S_NAME_COLUMN, text, S_SEC_COLUMN, sec, -1);
wireless_security_unref (sec);
}
static void
get_secrets_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GetSecretsInfo *info = user_data;
NMRemoteConnection *connection = NM_REMOTE_CONNECTION (object);
NMAWifiDialogPrivate *priv;
GVariant *secrets;
GVariantIter variant_iter;
const char *setting_name;
GVariant *setting_dict;
GtkTreeModel *model;
GtkTreeIter iter;
GError *error = NULL;
gboolean current_secrets = FALSE;
if (info->canceled)
goto out;
priv = NMA_WIFI_DIALOG_GET_PRIVATE (info->self);
if (priv->secrets_info == info) {
priv->secrets_info = NULL;
/* Buttons should only be re-enabled if this secrets response is the
* in-progress one.
*/
gtk_dialog_set_response_sensitive (GTK_DIALOG (info->self), GTK_RESPONSE_CANCEL, TRUE);
current_secrets = TRUE;
}
secrets = nm_remote_connection_get_secrets_finish (connection, result, &error);
if (error) {
g_warning ("%s: error getting connection secrets: (%d) %s",
__func__,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
goto out;
}
if (current_secrets)
_set_ok_sensitive (info->self, TRUE, NULL);
/* User might have changed the connection while the secrets call was in
* progress, so don't try to update the wrong connection with the secrets
* we just received.
*/
if ( (priv->connection != info->connection)
|| !secrets)
goto out;
/* Try to update the connection's secrets; log errors but we don't care */
g_variant_iter_init (&variant_iter, secrets);
while (g_variant_iter_next (&variant_iter, "{&s@a{sv}}", &setting_name, &setting_dict)) {
GError *update_error = NULL;
if (!nm_connection_update_secrets (priv->connection,
setting_name,
setting_dict,
&update_error)) {
g_warning ("%s: error updating connection secrets: (%d) %s",
__func__,
update_error ? update_error->code : -1,
update_error && update_error->message ? update_error->message : "(unknown)");
g_clear_error (&update_error);
}
g_variant_unref (setting_dict);
}
/* Update each security method's UI elements with the new secrets */
model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->sec_combo));
if (gtk_tree_model_get_iter_first (model, &iter)) {
do {
WirelessSecurity *sec = NULL;
gtk_tree_model_get (model, &iter, S_SEC_COLUMN, &sec, -1);
if (sec) {
wireless_security_update_secrets (sec, priv->connection);
wireless_security_unref (sec);
}
} while (gtk_tree_model_iter_next (model, &iter));
}
out:
g_object_unref (info->connection);
g_free (info);
}
static gboolean
security_valid (NMUtilsSecurityType sectype,
NM80211Mode mode,
NMDeviceWifiCapabilities wifi_caps,
gboolean have_ap,
NM80211ApFlags ap_flags,
NM80211ApSecurityFlags ap_wpa,
NM80211ApSecurityFlags ap_rsn)
{
switch (mode) {
case NM_802_11_MODE_AP:
return nm_utils_ap_mode_security_valid (sectype, wifi_caps);
case NM_802_11_MODE_ADHOC:
case NM_802_11_MODE_INFRA:
default:
return nm_utils_security_valid (sectype,
wifi_caps,
have_ap,
(mode == NM_802_11_MODE_ADHOC),
ap_flags, ap_wpa, ap_rsn);
}
g_assert_not_reached ();
}
static gboolean
security_combo_init (NMAWifiDialog *self, gboolean secrets_only,
const char *secrets_setting_name, const char *const*secrets_hints)
{
NMAWifiDialogPrivate *priv;
GtkListStore *sec_model;
GtkTreeIter iter;
guint32 ap_flags = 0;
guint32 ap_wpa = 0;
guint32 ap_rsn = 0;
guint32 dev_caps;
NMSettingWirelessSecurity *wsec = NULL;
NMUtilsSecurityType default_type = NMU_SEC_NONE;
NMWepKeyType wep_type = NM_WEP_KEY_TYPE_KEY;
int active = -1;
int item = 0;
NMSettingWireless *s_wireless = NULL;
NM80211Mode mode;
const char *setting_name;
g_return_val_if_fail (self != NULL, FALSE);
priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
g_return_val_if_fail (priv->device != NULL, FALSE);
g_return_val_if_fail (priv->sec_combo != NULL, FALSE);
mode = (priv->operation == OP_CREATE_ADHOC) ? NM_802_11_MODE_ADHOC : NM_802_11_MODE_INFRA;
/* The security options displayed are filtered based on device
* capabilities, and if provided, additionally by access point capabilities.
* If a connection is given, that connection's options should be selected
* by default. If hints is non-empty only filter based on the setting
* keys on the hints list.
*/
dev_caps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (priv->device));
if (priv->ap != NULL) {
ap_flags = nm_access_point_get_flags (priv->ap);
ap_wpa = nm_access_point_get_wpa_flags (priv->ap);
ap_rsn = nm_access_point_get_rsn_flags (priv->ap);
}
if (priv->connection) {
const char *mode_str;
s_wireless = nm_connection_get_setting_wireless (priv->connection);
mode_str = nm_setting_wireless_get_mode (s_wireless);
if (mode_str && !strcmp (mode_str, "adhoc"))
mode = NM_802_11_MODE_ADHOC;
else if (mode_str && !strcmp (mode_str, "ap"))
mode = NM_802_11_MODE_AP;
else
mode = NM_802_11_MODE_INFRA;
wsec = nm_connection_get_setting_wireless_security (priv->connection);
if (wsec) {
default_type = get_default_type_for_security (wsec, !!priv->ap, ap_flags, dev_caps);
if (default_type == NMU_SEC_STATIC_WEP)
wep_type = nm_setting_wireless_security_get_wep_key_type (wsec);
if (wep_type == NM_WEP_KEY_TYPE_UNKNOWN)
wep_type = NM_WEP_KEY_TYPE_KEY;
}
} else if (mode == NM_802_11_MODE_ADHOC) {
default_type = NMU_SEC_STATIC_WEP;
wep_type = NM_WEP_KEY_TYPE_PASSPHRASE;
}
sec_model = gtk_list_store_new (2, G_TYPE_STRING, WIRELESS_TYPE_SECURITY);
if (security_valid (NMU_SEC_NONE, mode, dev_caps, !!priv->ap, ap_flags, ap_wpa, ap_rsn)) {
gtk_list_store_append (sec_model, &iter);
gtk_list_store_set (sec_model, &iter,
S_NAME_COLUMN, C_("Wifi/wired security", "None"),
-1);
if (default_type == NMU_SEC_NONE)
active = item;
item++;
}
/* Don't show Static WEP if both the AP and the device are capable of WPA,
* even though technically it's possible to have this configuration.
*/
if ( security_valid (NMU_SEC_STATIC_WEP, mode, dev_caps, !!priv->ap, ap_flags, ap_wpa, ap_rsn)
&& ((!ap_wpa && !ap_rsn) || !(dev_caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN)))) {
WirelessSecurityWEPKey *ws_wep;
ws_wep = ws_wep_key_new (priv->connection, NM_WEP_KEY_TYPE_KEY, mode == NM_802_11_MODE_ADHOC, secrets_only);
if (ws_wep) {
add_security_item (self, WIRELESS_SECURITY (ws_wep), sec_model,
&iter, _("WEP 40/128-bit Key (Hex or ASCII)"));
if ((active < 0) && (default_type == NMU_SEC_STATIC_WEP) && (wep_type == NM_WEP_KEY_TYPE_KEY))
active = item;
item++;
}
ws_wep = ws_wep_key_new (priv->connection, NM_WEP_KEY_TYPE_PASSPHRASE, mode == NM_802_11_MODE_ADHOC, secrets_only);
if (ws_wep) {
add_security_item (self, WIRELESS_SECURITY (ws_wep), sec_model,
&iter, _("WEP 128-bit Passphrase"));
if ((active < 0) && (default_type == NMU_SEC_STATIC_WEP) && (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE))
active = item;
item++;
}
}
/* Don't show LEAP if both the AP and the device are capable of WPA,
* even though technically it's possible to have this configuration.
*/
if ( security_valid (NMU_SEC_LEAP, mode, dev_caps, !!priv->ap, ap_flags, ap_wpa, ap_rsn)
&& ((!ap_wpa && !ap_rsn) || !(dev_caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN)))) {
WirelessSecurityLEAP *ws_leap;
ws_leap = ws_leap_new (priv->connection, secrets_only);
if (ws_leap) {
add_security_item (self, WIRELESS_SECURITY (ws_leap), sec_model,
&iter, _("LEAP"));
if ((active < 0) && (default_type == NMU_SEC_LEAP))
active = item;
item++;
}
}
if (security_valid (NMU_SEC_DYNAMIC_WEP, mode, dev_caps, !!priv->ap, ap_flags, ap_wpa, ap_rsn)) {
WirelessSecurityDynamicWEP *ws_dynamic_wep;
ws_dynamic_wep = ws_dynamic_wep_new (priv->connection, FALSE, secrets_only);
if (ws_dynamic_wep) {
add_security_item (self, WIRELESS_SECURITY (ws_dynamic_wep), sec_model,
&iter, _("Dynamic WEP (802.1x)"));
if ((active < 0) && (default_type == NMU_SEC_DYNAMIC_WEP))
active = item;
item++;
}
}
if ( security_valid (NMU_SEC_WPA_PSK, mode, dev_caps, !!priv->ap, ap_flags, ap_wpa, ap_rsn)
|| security_valid (NMU_SEC_WPA2_PSK, mode, dev_caps, !!priv->ap, ap_flags, ap_wpa, ap_rsn)) {
WirelessSecurityWPAPSK *ws_wpa_psk;
ws_wpa_psk = ws_wpa_psk_new (priv->connection, secrets_only);
if (ws_wpa_psk) {
add_security_item (self, WIRELESS_SECURITY (ws_wpa_psk), sec_model,
&iter, _("WPA & WPA2 Personal"));
if ((active < 0) && ((default_type == NMU_SEC_WPA_PSK) || (default_type == NMU_SEC_WPA2_PSK)))
active = item;
item++;
}
}
if ( security_valid (NMU_SEC_WPA_ENTERPRISE, mode, dev_caps, !!priv->ap, ap_flags, ap_wpa, ap_rsn)
|| security_valid (NMU_SEC_WPA2_ENTERPRISE, mode, dev_caps, !!priv->ap, ap_flags, ap_wpa, ap_rsn)) {
WirelessSecurityWPAEAP *ws_wpa_eap;
const char *const*hints = NULL;
if (secrets_setting_name && !strcmp (secrets_setting_name, NM_SETTING_802_1X_SETTING_NAME))
hints = secrets_hints;
ws_wpa_eap = ws_wpa_eap_new (priv->connection, FALSE, secrets_only, hints);
if (ws_wpa_eap) {
add_security_item (self, WIRELESS_SECURITY (ws_wpa_eap), sec_model,
&iter, _("WPA & WPA2 Enterprise"));
if ((active < 0) && ((default_type == NMU_SEC_WPA_ENTERPRISE) || (default_type == NMU_SEC_WPA2_ENTERPRISE)))
active = item;
item++;
}
}
gtk_combo_box_set_model (GTK_COMBO_BOX (priv->sec_combo), GTK_TREE_MODEL (sec_model));
gtk_combo_box_set_active (GTK_COMBO_BOX (priv->sec_combo), active < 0 ? 0 : (guint32) active);
g_object_unref (G_OBJECT (sec_model));
/* If the dialog was given a connection when it was created, that connection
* will already be populated with secrets. If no connection was given,
* then we need to get any existing secrets to populate the dialog with.
*/
if (priv->connection) {
if (secrets_setting_name)
setting_name = secrets_setting_name;
else
setting_name = nm_connection_need_secrets (priv->connection, NULL);
} else
setting_name = NULL;
if (setting_name && NM_IS_REMOTE_CONNECTION (priv->connection)) {
GetSecretsInfo *info;
/* Desensitize the dialog's buttons while we wait for the secrets
* operation to complete.
*/
_set_ok_sensitive (self, FALSE, NULL);
gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_CANCEL, FALSE);
info = g_malloc0 (sizeof (GetSecretsInfo));
info->self = self;
info->connection = g_object_ref (priv->connection);
priv->secrets_info = info;
nm_remote_connection_get_secrets_async (NM_REMOTE_CONNECTION (priv->connection),
setting_name, NULL, get_secrets_cb, info);
}
return TRUE;
}
static gboolean
revalidate (gpointer user_data)
{
NMAWifiDialog *self = NMA_WIFI_DIALOG (user_data);
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
priv->revalidate_id = 0;
security_combo_changed (priv->sec_combo, self);
return FALSE;
}
static gboolean
internal_init (NMAWifiDialog *self,
NMConnection *specific_connection,
NMDevice *specific_device,
gboolean secrets_only,
const char *secrets_setting_name,
const char *const*secrets_hints)
{
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GtkWidget *widget;
char *label, *icon_name = "network-wireless";
gboolean security_combo_focus = FALSE;
gtk_window_set_position (GTK_WINDOW (self), GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_set_default_size (GTK_WINDOW (self), 488, -1);
gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
priv->secrets_only = secrets_only;
if (secrets_only)
icon_name = "dialog-password";
else
icon_name = "network-wireless";
if (specific_connection)
priv->specific_connection = g_object_ref (specific_connection);
gtk_window_set_icon_name (GTK_WINDOW (self), icon_name);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "image1"));
gtk_image_set_from_icon_name (GTK_IMAGE (widget), icon_name, GTK_ICON_SIZE_DIALOG);
gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 2);
widget = gtk_dialog_add_button (GTK_DIALOG (self), _("_Cancel"), GTK_RESPONSE_CANCEL);
/* Connect/Create button */
if (priv->operation == OP_CREATE_ADHOC) {
widget = gtk_dialog_add_button (GTK_DIALOG (self), _("C_reate"), GTK_RESPONSE_OK);
} else {
widget = gtk_dialog_add_button (GTK_DIALOG (self), _("C_onnect"), GTK_RESPONSE_OK);
priv->ok_response_button = widget;
}
g_object_set (G_OBJECT (widget), "can-default", TRUE, NULL);
gtk_widget_grab_default (widget);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "wifi_dialog"));
if (!widget) {
g_warning ("Couldn't find Wi-Fi_dialog widget.");
return FALSE;
}
gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (self))), widget);
/* If given a valid connection, hide the SSID bits and connection combo */
if (specific_connection) {
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "network_name_label"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "network_name_entry"));
gtk_widget_hide (widget);
security_combo_focus = TRUE;
priv->network_name_focus = FALSE;
} else {
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "network_name_entry"));
g_signal_connect (G_OBJECT (widget), "changed", (GCallback) ssid_entry_changed, self);
priv->network_name_focus = TRUE;
}
_set_ok_sensitive (self, FALSE, NULL);
if (!device_combo_init (self, specific_device)) {
g_warning ("No Wi-Fi devices available.");
return FALSE;
}
if (!connection_combo_init (self)) {
g_warning ("Couldn't set up connection combo box.");
return FALSE;
}
if (!security_combo_init (self, priv->secrets_only, secrets_setting_name, secrets_hints)) {
g_warning ("Couldn't set up Wi-Fi security combo box.");
return FALSE;
}
security_combo_changed (priv->sec_combo, self);
g_signal_connect (G_OBJECT (priv->sec_combo), "changed",
G_CALLBACK (security_combo_changed_manually), self);
if (secrets_only) {
gtk_widget_hide (priv->sec_combo);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "security_combo_label"));
gtk_widget_hide (widget);
}
if (security_combo_focus && !secrets_only)
gtk_widget_grab_focus (priv->sec_combo);
else if (priv->network_name_focus) {
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "network_name_entry"));
gtk_widget_grab_focus (widget);
}
if (priv->connection) {
char *tmp;
char *esc_ssid = NULL;
NMSettingWireless *s_wireless;
GBytes *ssid;
s_wireless = nm_connection_get_setting_wireless (priv->connection);
ssid = s_wireless ? nm_setting_wireless_get_ssid (s_wireless) : NULL;
if (ssid)
esc_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid));
tmp = g_strdup_printf (_("Passwords or encryption keys are required to access the Wi-Fi network “%s”."),
esc_ssid ? esc_ssid : "<unknown>");
gtk_window_set_title (GTK_WINDOW (self), _("Wi-Fi Network Authentication Required"));
label = g_markup_printf_escaped ("<span size=\"larger\" weight=\"bold\">%s</span>\n\n%s",
_("Authentication required by Wi-Fi network"),
tmp);
g_free (esc_ssid);
g_free (tmp);
} else if (priv->operation == OP_CREATE_ADHOC) {
gtk_window_set_title (GTK_WINDOW (self), _("Create New Wi-Fi Network"));
label = g_strdup_printf ("<span size=\"larger\" weight=\"bold\">%s</span>\n\n%s",
_("New Wi-Fi network"),
_("Enter a name for the Wi-Fi network you wish to create."));
} else if (priv->operation == OP_CONNECT_HIDDEN) {
gtk_window_set_title (GTK_WINDOW (self), _("Connect to Hidden Wi-Fi Network"));
label = g_strdup_printf ("<span size=\"larger\" weight=\"bold\">%s</span>\n\n%s",
_("Hidden Wi-Fi network"),
_("Enter the name and security details of the hidden Wi-Fi network you wish to connect to."));
} else
g_assert_not_reached ();
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "caption_label"));
gtk_label_set_markup (GTK_LABEL (widget), label);
g_free (label);
/* Re-validate from an idle handler so that widgets like file choosers
* have had time to find their files.
*/
priv->revalidate_id = g_idle_add (revalidate, self);
return TRUE;
}
/**
* nma_wifi_dialog_get_connection:
* @self: an #NMAWifiDialog
* @device: (out):
* @ap: (out):
*
* Returns: (transfer full):
*/
NMConnection *
nma_wifi_dialog_get_connection (NMAWifiDialog *self,
NMDevice **device,
NMAccessPoint **ap)
{
NMAWifiDialogPrivate *priv;
GtkWidget *combo;
GtkTreeModel *model;
WirelessSecurity *sec = NULL;
GtkTreeIter iter;
NMConnection *connection;
NMSettingWireless *s_wireless;
g_return_val_if_fail (self != NULL, NULL);
priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
if (!priv->connection) {
NMSettingConnection *s_con;
char *uuid;
GBytes *ssid;
connection = nm_simple_connection_new ();
s_con = (NMSettingConnection *) nm_setting_connection_new ();
uuid = nm_utils_uuid_generate ();
g_object_set (s_con,
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_CONNECTION_UUID, uuid,
NULL);
g_free (uuid);
nm_connection_add_setting (connection, (NMSetting *) s_con);
s_wireless = (NMSettingWireless *) nm_setting_wireless_new ();
ssid = validate_dialog_ssid (self);
g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, ssid, NULL);
g_bytes_unref (ssid);
if (priv->operation == OP_CREATE_ADHOC) {
NMSetting *s_ip4;
g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, "adhoc", NULL);
s_ip4 = nm_setting_ip4_config_new ();
g_object_set (s_ip4,
NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED,
NULL);
nm_connection_add_setting (connection, s_ip4);
} else if (priv->operation == OP_CONNECT_HIDDEN) {
/* Mark as a hidden SSID network */
g_object_set (s_wireless, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL);
} else
g_assert_not_reached ();
nm_connection_add_setting (connection, (NMSetting *) s_wireless);
} else
connection = g_object_ref (priv->connection);
/* Fill security */
model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->sec_combo));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (priv->sec_combo), &iter))
gtk_tree_model_get (model, &iter, S_SEC_COLUMN, &sec, -1);
if (sec) {
wireless_security_fill_connection (sec, connection);
wireless_security_unref (sec);
}
/* Save new CA cert ignore values to GSettings */
eap_method_ca_cert_ignore_save (connection);
/* Fill device */
if (device) {
combo = GTK_WIDGET (gtk_builder_get_object (priv->builder, "device_combo"));
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
gtk_tree_model_get (priv->device_model, &iter, D_DEV_COLUMN, device, -1);
g_object_unref (*device);
}
if (ap)
*ap = priv->ap;
return connection;
}
static GtkWidget *
internal_new_dialog (NMClient *client,
NMConnection *connection,
NMDevice *device,
NMAccessPoint *ap,
gboolean secrets_only,
const char *secrets_setting_name,
const char *const*secrets_hints)
{
NMAWifiDialog *self;
NMAWifiDialogPrivate *priv;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
self = NMA_WIFI_DIALOG (g_object_new (NMA_TYPE_WIFI_DIALOG, NULL));
if (self) {
priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
priv->client = g_object_ref (client);
if (ap)
priv->ap = g_object_ref (ap);
priv->sec_combo = GTK_WIDGET (gtk_builder_get_object (priv->builder, "security_combo"));
priv->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
/* Handle CA cert ignore stuff */
eap_method_ca_cert_ignore_load (connection);
if (!internal_init (self, connection, device, secrets_only, secrets_setting_name, secrets_hints)) {
g_warning ("Couldn't create Wi-Fi security dialog.");
gtk_widget_destroy (GTK_WIDGET (self));
self = NULL;
}
}
return GTK_WIDGET (self);
}
/**
* nma_wifi_dialog_new:
* @client: client to retrieve list of devices or connections from
* @connection: connection to be shown/edited or %NULL
* @device: device to check connection compatibility against
* @ap: AP to check connection compatibility against
* @secrets_only: whether to only ask for secrets for given connection
*
* Creates a wifi connection dialog and populates it with settings from
* @connection if given. If @device is not given a device selection combo box
* will be included. If @connection is not given a connection selection combo
* box will be included. If @secrets_only is %FALSE a complete connection
* creator/editor dialog is returned, otherwise only wifi security secrets
* relevant to the security settings in @connection are going to be shown and
* will be editable.
*
* Returns: the dialog widget or %NULL in case of error
*/
GtkWidget *
nma_wifi_dialog_new (NMClient *client,
NMConnection *connection,
NMDevice *device,
NMAccessPoint *ap,
gboolean secrets_only)
{
guint32 dev_caps;
/* Ensure device validity */
if (device) {
dev_caps = nm_device_get_capabilities (device);
g_return_val_if_fail (dev_caps & NM_DEVICE_CAP_NM_SUPPORTED, NULL);
g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL);
}
return internal_new_dialog (client,
connection,
device,
ap,
secrets_only,
NULL,
NULL);
}
/**
* nma_wifi_dialog_new_for_secrets:
* @client: client to retrieve list of devices or connections from
* @connection: connection for which secrets are requested
* @secrets_setting_name: setting name whose secrets are requested
* or %NULL
* @secrets_hints: array of setting key names within the setting given in
* @secrets_setting_name which are requested or %NULL
*
* Creates a wifi secrets dialog and populates it with setting values from
* @connection. If @secrets_setting_name and @secrets_hints are not given
* this function creates an identical dialog as nma_wifi_dialog_new() would
* create with the @secrets_only parameter %TRUE. Otherwise
* @secrets_setting_name and @secrets_hints determine the list of specific
* secrets that are being requested from the user and no editable entries
* are shown for any other settings.
*
* Note: only a subset of all settings and setting keys is supported as
* @secrets_setting_name and @secrets_hints.
*
* Returns: the dialog widget or %NULL in case of error
*/
GtkWidget *
nma_wifi_dialog_new_for_secrets (NMClient *client,
NMConnection *connection,
const char *secrets_setting_name,
const char *const*secrets_hints)
{
return internal_new_dialog (client,
connection,
NULL,
NULL,
TRUE,
secrets_setting_name,
secrets_hints);
}
static GtkWidget *
internal_new_operation (NMClient *client,
guint operation)
{
NMAWifiDialog *self;
NMAWifiDialogPrivate *priv;
g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
self = NMA_WIFI_DIALOG (g_object_new (NMA_TYPE_WIFI_DIALOG, NULL));
if (!self)
return NULL;
priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
priv->client = g_object_ref (client);
priv->sec_combo = GTK_WIDGET (gtk_builder_get_object (priv->builder, "security_combo"));
priv->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
priv->operation = operation;
if (!internal_init (self, NULL, NULL, FALSE, NULL, NULL)) {
g_warning ("Couldn't create Wi-Fi security dialog.");
gtk_widget_destroy (GTK_WIDGET (self));
return NULL;
}
return GTK_WIDGET (self);
}
GtkWidget *
nma_wifi_dialog_new_for_hidden (NMClient *client)
{
return internal_new_operation (client, OP_CONNECT_HIDDEN);
}
GtkWidget *
nma_wifi_dialog_new_for_other (NMClient *client)
{
return internal_new_operation (client, OP_CONNECT_HIDDEN);
}
GtkWidget *
nma_wifi_dialog_new_for_create (NMClient *client)
{
return internal_new_operation (client, OP_CREATE_ADHOC);
}
/**
* nma_wifi_dialog_nag_user:
* @self:
*
* Returns: (transfer full):
*/
GtkWidget *
nma_wifi_dialog_nag_user (NMAWifiDialog *self)
{
return NULL;
}
static void
nma_wifi_dialog_init (NMAWifiDialog *self)
{
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (self);
GError *error = NULL;
priv->builder = gtk_builder_new ();
if (!gtk_builder_add_from_resource (priv->builder, "/org/freedesktop/network-manager-applet/wifi.ui", &error)) {
g_warning ("Couldn't load builder resource: %s", error->message);
g_error_free (error);
}
}
static void
dispose (GObject *object)
{
NMAWifiDialogPrivate *priv = NMA_WIFI_DIALOG_GET_PRIVATE (object);
if (priv->secrets_info) {
priv->secrets_info->canceled = TRUE;
priv->secrets_info = NULL;
}
g_clear_object (&priv->client);
g_clear_object (&priv->builder);
g_clear_object (&priv->device_model);
g_clear_object (&priv->connection_model);
g_clear_object (&priv->group);
g_clear_object (&priv->specific_connection);
g_clear_object (&priv->connection);
g_clear_object (&priv->device);
g_clear_object (&priv->ap);
if (priv->revalidate_id) {
g_source_remove (priv->revalidate_id);
priv->revalidate_id = 0;
}
G_OBJECT_CLASS (nma_wifi_dialog_parent_class)->dispose (object);
}
static void
nma_wifi_dialog_class_init (NMAWifiDialogClass *nmad_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (nmad_class);
g_type_class_add_private (nmad_class, sizeof (NMAWifiDialogPrivate));
/* virtual methods */
object_class->dispose = dispose;
}