
Rather than randomly including one or more of <glib.h>, <glib-object.h>, and <gio/gio.h> everywhere (and forgetting to include "nm-glib-compat.h" most of the time), rename nm-glib-compat.h to nm-glib.h, include <gio/gio.h> from there, and then change all .c files in NM to include "nm-glib.h" rather than including the glib headers directly. (Public headers files still have to include the real glib headers, since nm-glib.h isn't installed...) Also, remove glib includes from header files that are already including a base object header file (which must itself already include the glib headers).
1101 lines
35 KiB
C
1101 lines
35 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Copyright 2013 Red Hat, Inc.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:nm-editor-bindings
|
|
* @short_description: #GBinding-based NM connection editor helpers
|
|
*
|
|
* nm-editor-bindings contains helper functions to bind NMSettings objects
|
|
* to connection editing widgets. The goal is that this should eventually be
|
|
* shared between nmtui, nm-connection-editor, and gnome-control-center.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <arpa/inet.h>
|
|
#include <netinet/in.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "nm-editor-bindings.h"
|
|
|
|
static void
|
|
value_transform_string_int (const GValue *src_value,
|
|
GValue *dest_value)
|
|
{
|
|
long val;
|
|
char *end;
|
|
|
|
val = strtol (g_value_get_string (src_value), &end, 10);
|
|
if (val < G_MININT || val > G_MAXINT || *end)
|
|
return;
|
|
|
|
g_value_set_int (dest_value, (int) val);
|
|
}
|
|
|
|
static void
|
|
value_transform_string_uint (const GValue *src_value,
|
|
GValue *dest_value)
|
|
{
|
|
long val;
|
|
char *end;
|
|
|
|
val = strtol (g_value_get_string (src_value), &end, 10);
|
|
if (val < 0 || val > G_MAXUINT || *end)
|
|
return;
|
|
|
|
g_value_set_uint (dest_value, (gint) val);
|
|
}
|
|
|
|
void
|
|
nm_editor_bindings_init (void)
|
|
{
|
|
/* glib registers number -> string, but not string -> number */
|
|
g_value_register_transform_func (G_TYPE_STRING, G_TYPE_INT, value_transform_string_int);
|
|
g_value_register_transform_func (G_TYPE_STRING, G_TYPE_UINT, value_transform_string_uint);
|
|
}
|
|
|
|
static gboolean
|
|
parse_addr_prefix (const char *text,
|
|
int family,
|
|
char **addr,
|
|
guint32 *prefix)
|
|
{
|
|
const char *slash;
|
|
char *addrstr, *end;
|
|
gboolean valid;
|
|
|
|
slash = strchr (text, '/');
|
|
|
|
if (slash)
|
|
addrstr = g_strndup (text, slash - text);
|
|
else
|
|
addrstr = g_strdup (text);
|
|
valid = nm_utils_ipaddr_valid (family, addrstr);
|
|
|
|
if (slash) {
|
|
*prefix = strtoul (slash + 1, &end, 10);
|
|
if ( *end
|
|
|| *prefix == 0
|
|
|| (family == AF_INET && *prefix > 32)
|
|
|| (family == AF_INET6 && *prefix > 128))
|
|
valid = FALSE;
|
|
} else if (prefix) {
|
|
if (family == AF_INET)
|
|
*prefix = 32;
|
|
else
|
|
*prefix = 128;
|
|
}
|
|
|
|
if (addr && valid)
|
|
*addr = addrstr;
|
|
else
|
|
g_free (addrstr);
|
|
return valid;
|
|
}
|
|
|
|
static gboolean
|
|
ip_addresses_with_prefix_to_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
NMIPAddress *addr;
|
|
const char *addrstr;
|
|
guint32 prefix;
|
|
char **strings;
|
|
int i;
|
|
|
|
addrs = g_value_get_boxed (source_value);
|
|
strings = g_new0 (char *, addrs->len + 1);
|
|
|
|
for (i = 0; i < addrs->len; i++) {
|
|
addr = addrs->pdata[i];
|
|
addrstr = nm_ip_address_get_address (addr);
|
|
prefix = nm_ip_address_get_prefix (addr);
|
|
|
|
if (addrstr)
|
|
strings[i] = g_strdup_printf ("%s/%d", addrstr, (int) prefix);
|
|
else
|
|
strings[i] = g_strdup ("");
|
|
}
|
|
|
|
g_value_take_boxed (target_value, strings);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_addresses_with_prefix_from_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
int family = GPOINTER_TO_INT (user_data);
|
|
char **strings;
|
|
GPtrArray *addrs;
|
|
NMIPAddress *addr;
|
|
char *addrstr;
|
|
guint32 prefix;
|
|
int i;
|
|
|
|
strings = g_value_get_boxed (source_value);
|
|
/* Fetch the original property value, so as to preserve their extra attributes */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &addrs,
|
|
NULL);
|
|
|
|
for (i = 0; strings[i]; i++) {
|
|
if (i >= addrs->len) {
|
|
if (family == AF_INET)
|
|
addr = nm_ip_address_new (AF_INET, "0.0.0.0", 32, NULL);
|
|
else
|
|
addr = nm_ip_address_new (AF_INET6, "::", 128, NULL);
|
|
g_ptr_array_add (addrs, addr);
|
|
} else
|
|
addr = addrs->pdata[i];
|
|
|
|
if (!parse_addr_prefix (strings[i], family, &addrstr, &prefix)) {
|
|
g_ptr_array_unref (addrs);
|
|
return FALSE;
|
|
}
|
|
|
|
nm_ip_address_set_address (addr, addrstr);
|
|
nm_ip_address_set_prefix (addr, prefix);
|
|
g_free (addrstr);
|
|
}
|
|
|
|
g_ptr_array_set_size (addrs, i);
|
|
g_value_take_boxed (target_value, addrs);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip_addresses_with_prefix_to_strv:
|
|
* @family: the IP address family
|
|
* @source: the source object (eg, an #NMSettingIP4Config)
|
|
* @source_property: the property on @source to bind (eg,
|
|
* %NM_SETTING_IP4_CONFIG_ADDRESSES)
|
|
* @target: the target object (eg, an #NmtAddressList)
|
|
* @target_property: the property on @target to bind
|
|
* (eg, "strings")
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the #GPtrArray-of-#NMIPAddress property @source_property on @source to
|
|
* the %G_TYPE_STRV property @target_property on @target.
|
|
*
|
|
* Each #NMIPAddress in @source_property will be converted to a string of the
|
|
* form "ip.ad.dr.ess/prefix" or "ip:ad:dr:ess/prefix" in @target_property (and
|
|
* vice versa if %G_BINDING_BIDIRECTIONAL) is specified.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip_addresses_with_prefix_to_strv (int family,
|
|
gpointer source,
|
|
const gchar *source_property,
|
|
gpointer target,
|
|
const gchar *target_property,
|
|
GBindingFlags flags)
|
|
{
|
|
g_object_bind_property_full (source, source_property,
|
|
target, target_property,
|
|
flags,
|
|
ip_addresses_with_prefix_to_strv,
|
|
ip_addresses_with_prefix_from_strv,
|
|
GINT_TO_POINTER (family), NULL);
|
|
}
|
|
|
|
static gboolean
|
|
ip_addresses_check_and_copy (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
int family = GPOINTER_TO_INT (user_data);
|
|
char **strings;
|
|
int i;
|
|
|
|
strings = g_value_get_boxed (source_value);
|
|
|
|
for (i = 0; strings[i]; i++) {
|
|
if (!nm_utils_ipaddr_valid (family, strings[i]))
|
|
return FALSE;
|
|
}
|
|
|
|
g_value_set_boxed (target_value, strings);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip_addresses_to_strv:
|
|
* @family: the IP address family
|
|
* @source: the source object (eg, an #NMSettingIP4Config)
|
|
* @source_property: the property on @source to bind (eg,
|
|
* %NM_SETTING_IP4_CONFIG_DNS)
|
|
* @target: the target object (eg, an #NmtAddressList)
|
|
* @target_property: the property on @target to bind
|
|
* (eg, "strings")
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the %G_TYPE_STRV property @source_property on @source to the
|
|
* %G_TYPE_STRV property @target_property on @target, verifying that
|
|
* each string is a valid address of type @family when copying.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip_addresses_to_strv (int family,
|
|
gpointer source,
|
|
const gchar *source_property,
|
|
gpointer target,
|
|
const gchar *target_property,
|
|
GBindingFlags flags)
|
|
{
|
|
g_object_bind_property_full (source, source_property,
|
|
target, target_property,
|
|
flags,
|
|
ip_addresses_check_and_copy,
|
|
ip_addresses_check_and_copy,
|
|
GINT_TO_POINTER (family), NULL);
|
|
}
|
|
|
|
static gboolean
|
|
ip_gateway_to_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
g_value_set_string (target_value, g_value_get_string (source_value));
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_gateway_from_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
int family = GPOINTER_TO_INT (user_data);
|
|
const char *gateway;
|
|
|
|
gateway = g_value_get_string (source_value);
|
|
if (gateway && !nm_utils_ipaddr_valid (family, gateway))
|
|
gateway = NULL;
|
|
|
|
g_value_set_string (target_value, gateway);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_addresses_to_gateway (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
|
|
addrs = g_value_get_boxed (source_value);
|
|
if (addrs->len == 0) {
|
|
g_value_set_string (target_value, NULL);
|
|
return TRUE;
|
|
} else
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_addresses_to_sensitivity (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
|
|
addrs = g_value_get_boxed (source_value);
|
|
g_value_set_boolean (target_value, addrs->len != 0);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip_gateway_to_string:
|
|
* @family: the IP address family
|
|
* @source: the source #NMSettingIPConfig
|
|
* @target: the target object (eg, an #NmtIPEntry)
|
|
* @target_property: the property on @target to bind (eg, "text")
|
|
* @target_sensitive_property: the "sensitivity" property on @target to bind
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the #NMSettingIPConfig:gateway property on @source to the
|
|
* %G_TYPE_STRING property @target_property and %G_TYPE_BOOLEAN property
|
|
* @target_sensitive_property on @target, also taking the
|
|
* #NMSettingIPConfig:addresses property on @source into account.
|
|
*
|
|
* In particular, if @source has no static IP addresses, then @target_property
|
|
* will be set to "" and @target_sensitive_property will be set to %FALSE.
|
|
*
|
|
* If @source has at least one static IP address, then
|
|
* @target_sensitive_property will be set to %TRUE, @target_property will be
|
|
* initialized from @source's #NMSettingIPConfig:gateway, and @source will be
|
|
* updated with the value of @target_property whenever it contains a valid IP
|
|
* address.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip_gateway_to_string (int family,
|
|
NMSettingIPConfig *source,
|
|
gpointer target,
|
|
const gchar *target_property,
|
|
const gchar *target_sensitive_property,
|
|
GBindingFlags flags)
|
|
{
|
|
g_object_bind_property_full (source, "gateway",
|
|
target, target_property,
|
|
flags,
|
|
ip_gateway_to_string,
|
|
ip_gateway_from_string,
|
|
GINT_TO_POINTER (family), NULL);
|
|
g_object_bind_property_full (source, "addresses",
|
|
source, "gateway",
|
|
(flags & G_BINDING_SYNC_CREATE),
|
|
ip_addresses_to_gateway,
|
|
NULL,
|
|
NULL, NULL);
|
|
g_object_bind_property_full (source, "addresses",
|
|
target, target_sensitive_property,
|
|
(flags & G_BINDING_SYNC_CREATE),
|
|
ip_addresses_to_sensitivity,
|
|
NULL,
|
|
NULL, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
ip_route_transform_to_dest_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIPRoute *route;
|
|
const char *addrstr;
|
|
char *string;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route)
|
|
addrstr = nm_ip_route_get_dest (route);
|
|
else
|
|
addrstr = NULL;
|
|
|
|
if (addrstr) {
|
|
string = g_strdup_printf ("%s/%d", addrstr, (int) nm_ip_route_get_prefix (route));
|
|
g_value_take_string (target_value, string);
|
|
} else
|
|
g_value_set_string (target_value, "");
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_route_transform_to_next_hop_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIPRoute *route;
|
|
const char *addrstr;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route) {
|
|
addrstr = nm_ip_route_get_next_hop (route);
|
|
if (!addrstr)
|
|
addrstr = "";
|
|
} else
|
|
addrstr = "";
|
|
|
|
g_value_set_string (target_value, addrstr);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_route_transform_to_metric_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIPRoute *route;
|
|
char *string;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route && nm_ip_route_get_dest (route) && nm_ip_route_get_metric (route) != -1) {
|
|
string = g_strdup_printf ("%lu", (gulong) nm_ip_route_get_metric (route));
|
|
g_value_take_string (target_value, string);
|
|
} else
|
|
g_value_set_string (target_value, "");
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_route_transform_from_dest_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
int family = GPOINTER_TO_INT (user_data);
|
|
NMIPRoute *route;
|
|
const char *text;
|
|
char *addrstr;
|
|
guint32 prefix;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (!parse_addr_prefix (text, family, &addrstr, &prefix))
|
|
return FALSE;
|
|
|
|
/* Fetch the original property value */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &route,
|
|
NULL);
|
|
|
|
nm_ip_route_set_dest (route, addrstr);
|
|
nm_ip_route_set_prefix (route, prefix);
|
|
g_free (addrstr);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_route_transform_from_next_hop_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
int family = GPOINTER_TO_INT (user_data);
|
|
NMIPRoute *route;
|
|
const char *text;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (*text) {
|
|
if (!nm_utils_ipaddr_valid (family, text))
|
|
return FALSE;
|
|
} else
|
|
text = NULL;
|
|
|
|
/* Fetch the original property value */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &route,
|
|
NULL);
|
|
|
|
nm_ip_route_set_next_hop (route, text);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip_route_transform_from_metric_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIPRoute *route;
|
|
const char *text;
|
|
gint64 metric;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (*text)
|
|
metric = strtoul (text, NULL, 10);
|
|
else
|
|
metric = -1;
|
|
|
|
/* Fetch the original property value */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &route,
|
|
NULL);
|
|
|
|
nm_ip_route_set_metric (route, metric);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip_route_to_strings:
|
|
* @family: the IP address family
|
|
* @source: the source object
|
|
* @source_property: the source property
|
|
* @dest_target: the target object for the route's destionation
|
|
* @dest_target_property: the property on @dest_target
|
|
* @next_hop_target: the target object for the route's next hop
|
|
* @next_hop_target_property: the property on @next_hop_target
|
|
* @metric_target: the target object for the route's metric
|
|
* @metric_target_property: the property on @metric_target
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the #NMIPRoute-valued property @source_property on @source to the
|
|
* three indicated string-valued target properties (and vice versa if
|
|
* %G_BINDING_BIDIRECTIONAL is specified).
|
|
*
|
|
* @dest_target_property should be an "address/prefix" string, as with
|
|
* nm_editor_bind_ip4_addresses_with_prefix_to_strv(). @next_hop_target_property
|
|
* is a plain IP address, and @metric_target_property is a number.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip_route_to_strings (int family,
|
|
gpointer source,
|
|
const gchar *source_property,
|
|
gpointer dest_target,
|
|
const gchar *dest_target_property,
|
|
gpointer next_hop_target,
|
|
const gchar *next_hop_target_property,
|
|
gpointer metric_target,
|
|
const gchar *metric_target_property,
|
|
GBindingFlags flags)
|
|
{
|
|
g_object_bind_property_full (source, source_property,
|
|
dest_target, dest_target_property,
|
|
flags,
|
|
ip_route_transform_to_dest_string,
|
|
ip_route_transform_from_dest_string,
|
|
GINT_TO_POINTER (family), NULL);
|
|
g_object_bind_property_full (source, source_property,
|
|
next_hop_target, next_hop_target_property,
|
|
flags,
|
|
ip_route_transform_to_next_hop_string,
|
|
ip_route_transform_from_next_hop_string,
|
|
GINT_TO_POINTER (family), NULL);
|
|
g_object_bind_property_full (source, source_property,
|
|
metric_target, metric_target_property,
|
|
flags,
|
|
ip_route_transform_to_metric_string,
|
|
ip_route_transform_from_metric_string,
|
|
GINT_TO_POINTER (family), NULL);
|
|
}
|
|
|
|
/* Wireless security method binding */
|
|
typedef struct {
|
|
NMConnection *connection;
|
|
NMSettingWirelessSecurity *s_wsec;
|
|
gboolean s_wsec_in_use;
|
|
|
|
GObject *target;
|
|
char *target_property;
|
|
|
|
gboolean updating;
|
|
} NMEditorWirelessSecurityMethodBinding;
|
|
|
|
static const char *
|
|
get_security_type (NMEditorWirelessSecurityMethodBinding *binding)
|
|
{
|
|
const char *key_mgmt, *auth_alg;
|
|
|
|
if (!binding->s_wsec_in_use)
|
|
return "none";
|
|
|
|
key_mgmt = nm_setting_wireless_security_get_key_mgmt (binding->s_wsec);
|
|
auth_alg = nm_setting_wireless_security_get_auth_alg (binding->s_wsec);
|
|
|
|
/* No IEEE 802.1x */
|
|
if (!strcmp (key_mgmt, "none")) {
|
|
NMWepKeyType wep_type = nm_setting_wireless_security_get_wep_key_type (binding->s_wsec);
|
|
|
|
if (wep_type == NM_WEP_KEY_TYPE_KEY)
|
|
return "wep-key";
|
|
else
|
|
return "wep-passphrase";
|
|
}
|
|
|
|
if (!strcmp (key_mgmt, "ieee8021x")) {
|
|
if (auth_alg && !strcmp (auth_alg, "leap"))
|
|
return "leap";
|
|
return "dynamic-wep";
|
|
}
|
|
|
|
if ( !strcmp (key_mgmt, "wpa-none")
|
|
|| !strcmp (key_mgmt, "wpa-psk"))
|
|
return "wpa-personal";
|
|
|
|
if (!strcmp (key_mgmt, "wpa-eap"))
|
|
return "wpa-enterprise";
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
wireless_security_changed (GObject *object,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMEditorWirelessSecurityMethodBinding *binding = user_data;
|
|
|
|
if (binding->updating)
|
|
return;
|
|
|
|
binding->updating = TRUE;
|
|
g_object_set (binding->target,
|
|
binding->target_property, get_security_type (binding),
|
|
NULL);
|
|
binding->updating = FALSE;
|
|
}
|
|
|
|
static void
|
|
wireless_connection_changed (NMConnection *connection,
|
|
gpointer user_data)
|
|
{
|
|
NMEditorWirelessSecurityMethodBinding *binding = user_data;
|
|
NMSettingWirelessSecurity *s_wsec;
|
|
|
|
if (binding->updating)
|
|
return;
|
|
|
|
s_wsec = nm_connection_get_setting_wireless_security (connection);
|
|
if ( (s_wsec && binding->s_wsec_in_use)
|
|
|| (!s_wsec && !binding->s_wsec_in_use))
|
|
return;
|
|
|
|
binding->s_wsec_in_use = !binding->s_wsec_in_use;
|
|
wireless_security_changed (NULL, NULL, binding);
|
|
}
|
|
|
|
static void
|
|
wireless_security_target_changed (GObject *object,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMEditorWirelessSecurityMethodBinding *binding = user_data;
|
|
char *method;
|
|
|
|
if (binding->updating)
|
|
return;
|
|
|
|
g_object_get (binding->target,
|
|
binding->target_property, &method,
|
|
NULL);
|
|
|
|
binding->updating = TRUE;
|
|
|
|
if (!strcmp (method, "none")) {
|
|
if (!binding->s_wsec_in_use)
|
|
return;
|
|
binding->s_wsec_in_use = FALSE;
|
|
nm_connection_remove_setting (binding->connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
|
|
|
|
binding->updating = FALSE;
|
|
return;
|
|
}
|
|
|
|
if (!binding->s_wsec_in_use) {
|
|
binding->s_wsec_in_use = TRUE;
|
|
nm_connection_add_setting (binding->connection, NM_SETTING (binding->s_wsec));
|
|
}
|
|
|
|
if (!strcmp (method, "wep-key")) {
|
|
g_object_set (binding->s_wsec,
|
|
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
|
|
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_KEY,
|
|
NULL);
|
|
} else if (!strcmp (method, "wep-passphrase")) {
|
|
g_object_set (binding->s_wsec,
|
|
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
|
|
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_PASSPHRASE,
|
|
NULL);
|
|
} else if (!strcmp (method, "leap")) {
|
|
g_object_set (binding->s_wsec,
|
|
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
|
|
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN,
|
|
NULL);
|
|
} else if (!strcmp (method, "dynamic-wep")) {
|
|
g_object_set (binding->s_wsec,
|
|
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
|
|
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN,
|
|
NULL);
|
|
} else if (!strcmp (method, "wpa-personal")) {
|
|
g_object_set (binding->s_wsec,
|
|
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
|
|
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, NULL,
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN,
|
|
NULL);
|
|
} else if (!strcmp (method, "wpa-enterprise")) {
|
|
g_object_set (binding->s_wsec,
|
|
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
|
|
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, NULL,
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN,
|
|
NULL);
|
|
} else
|
|
g_warn_if_reached ();
|
|
|
|
binding->updating = FALSE;
|
|
}
|
|
|
|
static void
|
|
wireless_security_target_destroyed (gpointer user_data,
|
|
GObject *ex_target)
|
|
{
|
|
NMEditorWirelessSecurityMethodBinding *binding = user_data;
|
|
|
|
g_signal_handlers_disconnect_by_func (binding->s_wsec, G_CALLBACK (wireless_security_changed), binding);
|
|
g_object_unref (binding->s_wsec);
|
|
g_object_unref (binding->connection);
|
|
|
|
g_free (binding->target_property);
|
|
|
|
g_slice_free (NMEditorWirelessSecurityMethodBinding, binding);
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_wireless_security_method:
|
|
* @connection: an #NMConnection
|
|
* @s_wsec: an #NMSettingWirelessSecurity
|
|
* @target: the target widget
|
|
* @target_property: the string-valued property on @target to bind
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the wireless security method on @connection to
|
|
* @target_property on @target (and vice versa if
|
|
* %G_BINDING_BIDIRECTIONAL).
|
|
*
|
|
* @target_property will be of the values "none", "wpa-personal",
|
|
* "wpa-enterprise", "wep-key", "wep-passphrase", "dynamic-wep", or
|
|
* "leap".
|
|
*
|
|
* If binding bidirectionally, @s_wsec will be automatically added to
|
|
* or removed from @connection as needed when @target_property
|
|
* changes.
|
|
*/
|
|
void
|
|
nm_editor_bind_wireless_security_method (NMConnection *connection,
|
|
NMSettingWirelessSecurity *s_wsec,
|
|
gpointer target,
|
|
const char *target_property,
|
|
GBindingFlags flags)
|
|
{
|
|
NMEditorWirelessSecurityMethodBinding *binding;
|
|
char *notify;
|
|
|
|
binding = g_slice_new0 (NMEditorWirelessSecurityMethodBinding);
|
|
|
|
binding->target = target;
|
|
binding->target_property = g_strdup (target_property);
|
|
if (flags & G_BINDING_BIDIRECTIONAL) {
|
|
notify = g_strdup_printf ("notify::%s", target_property);
|
|
g_signal_connect (target, notify, G_CALLBACK (wireless_security_target_changed), binding);
|
|
g_free (notify);
|
|
}
|
|
g_object_weak_ref (target, wireless_security_target_destroyed, binding);
|
|
|
|
binding->connection = g_object_ref (connection);
|
|
g_signal_connect (connection, NM_CONNECTION_CHANGED,
|
|
G_CALLBACK (wireless_connection_changed), binding);
|
|
binding->s_wsec_in_use = (nm_connection_get_setting_wireless_security (connection) != NULL);
|
|
|
|
binding->s_wsec = g_object_ref (s_wsec);
|
|
g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_KEY_MGMT,
|
|
G_CALLBACK (wireless_security_changed), binding);
|
|
g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_AUTH_ALG,
|
|
G_CALLBACK (wireless_security_changed), binding);
|
|
g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
|
|
G_CALLBACK (wireless_security_changed), binding);
|
|
|
|
if (flags & G_BINDING_SYNC_CREATE)
|
|
wireless_security_changed (NULL, NULL, binding);
|
|
}
|
|
|
|
/* WEP key binding */
|
|
|
|
typedef struct {
|
|
NMSettingWirelessSecurity *s_wsec;
|
|
GObject *entry, *key_selector;
|
|
char *entry_property, *key_selector_property;
|
|
|
|
gboolean updating;
|
|
} NMEditorWepKeyBinding;
|
|
|
|
static void
|
|
wep_key_setting_changed (GObject *object,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMEditorWepKeyBinding *binding = user_data;
|
|
const char *key;
|
|
int index;
|
|
|
|
if (binding->updating)
|
|
return;
|
|
|
|
index = nm_setting_wireless_security_get_wep_tx_keyidx (binding->s_wsec);
|
|
key = nm_setting_wireless_security_get_wep_key (binding->s_wsec, index);
|
|
|
|
binding->updating = TRUE;
|
|
g_object_set (binding->key_selector,
|
|
binding->key_selector_property, index,
|
|
NULL);
|
|
g_object_set (binding->entry,
|
|
binding->entry_property, key,
|
|
NULL);
|
|
binding->updating = FALSE;
|
|
}
|
|
|
|
static void
|
|
wep_key_ui_changed (GObject *object,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMEditorWepKeyBinding *binding = user_data;
|
|
char *key;
|
|
int index;
|
|
|
|
if (binding->updating)
|
|
return;
|
|
|
|
g_object_get (binding->key_selector,
|
|
binding->key_selector_property, &index,
|
|
NULL);
|
|
g_object_get (binding->entry,
|
|
binding->entry_property, &key,
|
|
NULL);
|
|
|
|
binding->updating = TRUE;
|
|
g_object_set (binding->s_wsec,
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, index,
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, index == 0 ? key : NULL,
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY1, index == 1 ? key : NULL,
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY2, index == 2 ? key : NULL,
|
|
NM_SETTING_WIRELESS_SECURITY_WEP_KEY3, index == 3 ? key : NULL,
|
|
NULL);
|
|
binding->updating = FALSE;
|
|
|
|
g_free (key);
|
|
}
|
|
|
|
static void
|
|
wep_key_target_destroyed (gpointer user_data,
|
|
GObject *ex_target)
|
|
{
|
|
NMEditorWepKeyBinding *binding = user_data;
|
|
|
|
g_signal_handlers_disconnect_by_func (binding->s_wsec, G_CALLBACK (wep_key_setting_changed), binding);
|
|
|
|
if (ex_target != binding->entry) {
|
|
g_signal_handlers_disconnect_by_func (binding->entry, G_CALLBACK (wep_key_ui_changed), binding);
|
|
g_object_weak_unref (binding->entry, wep_key_target_destroyed, binding);
|
|
} else {
|
|
g_signal_handlers_disconnect_by_func (binding->key_selector, G_CALLBACK (wep_key_ui_changed), binding);
|
|
g_object_weak_unref (binding->key_selector, wep_key_target_destroyed, binding);
|
|
}
|
|
|
|
g_object_unref (binding->s_wsec);
|
|
g_free (binding->entry_property);
|
|
g_free (binding->key_selector_property);
|
|
|
|
g_slice_free (NMEditorWepKeyBinding, binding);
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_wireless_security_wep_key:
|
|
* @s_wsec: an #NMSettingWirelessSecurity
|
|
* @entry: an entry widget
|
|
* @entry_property: the string-valued property on @entry to bind
|
|
* @key_selector: a pop-up widget of some sort
|
|
* @key_selector_property: the integer-valued property on
|
|
* @key_selector to bind
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the "wep-tx-keyidx" property on @s_wsec to
|
|
* @key_selector_property on @key_selector, and the corresponding
|
|
* "wep-keyN" property to @entry_property on @entry (and vice versa if
|
|
* %G_BINDING_BIDIRECTIONAL).
|
|
*/
|
|
void
|
|
nm_editor_bind_wireless_security_wep_key (NMSettingWirelessSecurity *s_wsec,
|
|
gpointer entry,
|
|
const char *entry_property,
|
|
gpointer key_selector,
|
|
const char *key_selector_property,
|
|
GBindingFlags flags)
|
|
{
|
|
NMEditorWepKeyBinding *binding;
|
|
char *notify;
|
|
|
|
binding = g_slice_new0 (NMEditorWepKeyBinding);
|
|
binding->s_wsec = g_object_ref (s_wsec);
|
|
binding->entry = entry;
|
|
binding->entry_property = g_strdup (entry_property);
|
|
binding->key_selector = key_selector;
|
|
binding->key_selector_property = g_strdup (key_selector_property);
|
|
|
|
g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
|
|
G_CALLBACK (wep_key_setting_changed), binding);
|
|
g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY1,
|
|
G_CALLBACK (wep_key_setting_changed), binding);
|
|
g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY2,
|
|
G_CALLBACK (wep_key_setting_changed), binding);
|
|
g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_KEY3,
|
|
G_CALLBACK (wep_key_setting_changed), binding);
|
|
|
|
g_signal_connect (s_wsec, "notify::" NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX,
|
|
G_CALLBACK (wep_key_setting_changed), binding);
|
|
|
|
if (flags & G_BINDING_BIDIRECTIONAL) {
|
|
notify = g_strdup_printf ("notify::%s", entry_property);
|
|
g_signal_connect (entry, notify, G_CALLBACK (wep_key_ui_changed), binding);
|
|
g_free (notify);
|
|
|
|
notify = g_strdup_printf ("notify::%s", key_selector_property);
|
|
g_signal_connect (key_selector, notify, G_CALLBACK (wep_key_ui_changed), binding);
|
|
g_free (notify);
|
|
}
|
|
|
|
g_object_weak_ref (entry, wep_key_target_destroyed, binding);
|
|
g_object_weak_ref (key_selector, wep_key_target_destroyed, binding);
|
|
|
|
if (flags & G_BINDING_SYNC_CREATE)
|
|
wep_key_setting_changed (NULL, NULL, binding);
|
|
}
|
|
|
|
/* VLAN binding */
|
|
|
|
typedef struct {
|
|
NMSettingVlan *s_vlan;
|
|
NMSettingConnection *s_con;
|
|
|
|
char *last_ifname_parent;
|
|
int last_ifname_id;
|
|
|
|
gboolean updating;
|
|
} NMEditorVlanWidgetBinding;
|
|
|
|
static gboolean
|
|
parse_interface_name (const char *ifname,
|
|
char **parent_ifname,
|
|
int *id)
|
|
{
|
|
const char *ifname_end;
|
|
char *end;
|
|
|
|
if (!ifname || !*ifname)
|
|
return FALSE;
|
|
|
|
if (g_str_has_prefix (ifname, "vlan")) {
|
|
ifname_end = ifname + 4;
|
|
*id = strtoul (ifname_end, &end, 10);
|
|
if (*end || end == (char *)ifname_end || *id < 0)
|
|
return FALSE;
|
|
*parent_ifname = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
ifname_end = strchr (ifname, '.');
|
|
if (ifname_end) {
|
|
*id = strtoul (ifname_end + 1, &end, 10);
|
|
if (*end || end == (char *)ifname_end + 1 || *id < 0)
|
|
return FALSE;
|
|
*parent_ifname = g_strndup (ifname, ifname_end - ifname);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
vlan_settings_changed (GObject *object,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
NMEditorVlanWidgetBinding *binding = user_data;
|
|
const char *ifname, *parent;
|
|
char *ifname_parent;
|
|
int ifname_id, id;
|
|
|
|
if (binding->updating)
|
|
return;
|
|
|
|
ifname = nm_setting_connection_get_interface_name (binding->s_con);
|
|
parent = nm_setting_vlan_get_parent (binding->s_vlan);
|
|
id = nm_setting_vlan_get_id (binding->s_vlan);
|
|
|
|
if (!parse_interface_name (ifname, &ifname_parent, &ifname_id))
|
|
return;
|
|
|
|
/* If the id in INTERFACE_NAME changed, and ID is either unset, or was previously
|
|
* in sync with INTERFACE_NAME, then update ID.
|
|
*/
|
|
if ( id != ifname_id
|
|
&& (id == binding->last_ifname_id || id == 0)) {
|
|
binding->updating = TRUE;
|
|
g_object_set (G_OBJECT (binding->s_vlan),
|
|
NM_SETTING_VLAN_ID, ifname_id,
|
|
NULL);
|
|
binding->updating = FALSE;
|
|
}
|
|
|
|
/* If the PARENT in INTERFACE_NAME changed, and PARENT is either unset, or was
|
|
* previously in sync with INTERFACE_NAME, then update PARENT.
|
|
*/
|
|
if ( g_strcmp0 (parent, ifname_parent) != 0
|
|
&& ( g_strcmp0 (parent, binding->last_ifname_parent) == 0
|
|
|| !parent || !*parent)) {
|
|
binding->updating = TRUE;
|
|
g_object_set (G_OBJECT (binding->s_vlan),
|
|
NM_SETTING_VLAN_PARENT, ifname_parent,
|
|
NULL);
|
|
binding->updating = FALSE;
|
|
}
|
|
|
|
g_free (binding->last_ifname_parent);
|
|
binding->last_ifname_parent = ifname_parent;
|
|
binding->last_ifname_id = ifname_id;
|
|
}
|
|
|
|
static void
|
|
vlan_target_destroyed (gpointer user_data,
|
|
GObject *ex_target)
|
|
{
|
|
NMEditorVlanWidgetBinding *binding = user_data;
|
|
|
|
g_free (binding->last_ifname_parent);
|
|
g_slice_free (NMEditorVlanWidgetBinding, binding);
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_vlan_name:
|
|
* @s_vlan: an #NMSettingVlan
|
|
*
|
|
* Binds together several properties on @s_vlan, so that if the
|
|
* %NM_SETTING_VLAN_INTERFACE_NAME matches %NM_SETTING_VLAN_PARENT
|
|
* and %NM_SETTING_VLAN_ID in the obvious way, then changes to
|
|
* %NM_SETTING_VLAN_INTERFACE_NAME will propagate to the other
|
|
* two properties automatically.
|
|
*/
|
|
void
|
|
nm_editor_bind_vlan_name (NMSettingVlan *s_vlan,
|
|
NMSettingConnection *s_con)
|
|
{
|
|
NMEditorVlanWidgetBinding *binding;
|
|
const char *ifname;
|
|
|
|
binding = g_slice_new0 (NMEditorVlanWidgetBinding);
|
|
binding->s_vlan = s_vlan;
|
|
binding->s_con = s_con;
|
|
|
|
g_signal_connect (s_con, "notify::" NM_SETTING_CONNECTION_INTERFACE_NAME,
|
|
G_CALLBACK (vlan_settings_changed), binding);
|
|
|
|
g_object_weak_ref (G_OBJECT (s_vlan), vlan_target_destroyed, binding);
|
|
|
|
ifname = nm_setting_connection_get_interface_name (s_con);
|
|
if (!parse_interface_name (ifname, &binding->last_ifname_parent, &binding->last_ifname_id)) {
|
|
binding->last_ifname_parent = NULL;
|
|
binding->last_ifname_id = 0;
|
|
}
|
|
}
|