mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-31 18:20:10 +01:00
Create a new clients/ subdirectory at the top level, and move cli/ and tui/ into it, as well as nm-online.c (which was previously in test/, which made no sense). cli/ was split into two subdirectories, src/ and completion/. While this does simplify things (given that the completion file and the binary both need to be named "nmcli"), it bloats the source tree, and we can work around it by just renaming the completion file at install time. Then we can combine the two directories into one and just have it all under clients/cli/.
1676 lines
53 KiB
C
1676 lines
53 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 <dbus/dbus-glib.h>
|
|
|
|
#include "nm-editor-bindings.h"
|
|
#include "nm-gvaluearray-compat.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
|
|
ip_string_parse (const char *text,
|
|
int family,
|
|
gpointer addr,
|
|
guint32 *prefix)
|
|
{
|
|
const char *slash;
|
|
char *addrstr, *end;
|
|
gboolean valid;
|
|
|
|
slash = strchr (text, '/');
|
|
|
|
if (slash) {
|
|
if (!prefix)
|
|
return FALSE;
|
|
addrstr = g_strndup (text, slash - text);
|
|
} else
|
|
addrstr = g_strdup (text);
|
|
valid = (inet_pton (family, addrstr, addr) == 1);
|
|
g_free (addrstr);
|
|
|
|
if (!valid)
|
|
return FALSE;
|
|
|
|
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;
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_addresses_with_prefix_to_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
GArray *addr;
|
|
guint32 addrbytes, prefix;
|
|
char buf[INET_ADDRSTRLEN], **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];
|
|
addrbytes = g_array_index (addr, guint32, 0);
|
|
prefix = g_array_index (addr, guint32, 1);
|
|
|
|
if (addrbytes) {
|
|
strings[i] = g_strdup_printf ("%s/%d",
|
|
inet_ntop (AF_INET, &addrbytes, buf, sizeof (buf)),
|
|
(int) prefix);
|
|
} else
|
|
strings[i] = g_strdup ("");
|
|
}
|
|
|
|
g_value_take_boxed (target_value, strings);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_addresses_with_prefix_from_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
char **strings;
|
|
GPtrArray *addrs;
|
|
GArray *addr;
|
|
guint32 *addrvals;
|
|
int i;
|
|
|
|
strings = g_value_get_boxed (source_value);
|
|
/* Fetch the original property value, so as to preserve the gateway elements */
|
|
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) {
|
|
guint32 val;
|
|
|
|
addr = g_array_sized_new (FALSE, FALSE, sizeof (guint32), 3);
|
|
val = 0;
|
|
g_array_append_val (addr, val);
|
|
val = 32;
|
|
g_array_append_val (addr, val);
|
|
val = 0;
|
|
g_array_append_val (addr, val);
|
|
g_ptr_array_add (addrs, addr);
|
|
} else
|
|
addr = addrs->pdata[i];
|
|
addrvals = (guint32 *)addr->data;
|
|
|
|
if (!ip_string_parse (strings[i], AF_INET, &addrvals[0], &addrvals[1])) {
|
|
g_ptr_array_unref (addrs);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
g_ptr_array_set_size (addrs, i);
|
|
g_value_take_boxed (target_value, addrs);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip4_addresses_with_prefix_to_strv:
|
|
* @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 %DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT property
|
|
* @source_property on @source to the %G_TYPE_STRV property
|
|
* @target_property on @target.
|
|
*
|
|
* Each address/prefix/gateway triplet in @source_property will be
|
|
* converted to a string of the form "ip.ad.dr.ess/prefix" in
|
|
* @target_property (and vice versa if %G_BINDING_BIDIRECTIONAL) is
|
|
* specified. The "gateway" fields in @source_property are ignored
|
|
* when converting to strings, and unmodified when converting from
|
|
* strings.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip4_addresses_with_prefix_to_strv (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,
|
|
ip4_addresses_with_prefix_to_strv,
|
|
ip4_addresses_with_prefix_from_strv,
|
|
NULL, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
ip4_addresses_to_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GArray *addrs;
|
|
guint32 addrbytes;
|
|
char buf[INET_ADDRSTRLEN], **strings;
|
|
int i;
|
|
|
|
addrs = g_value_get_boxed (source_value);
|
|
strings = g_new0 (char *, addrs->len + 1);
|
|
|
|
for (i = 0; i < addrs->len; i++) {
|
|
addrbytes = g_array_index (addrs, guint32, i);
|
|
if (addrbytes)
|
|
inet_ntop (AF_INET, &addrbytes, buf, sizeof (buf));
|
|
else
|
|
buf[0] = '\0';
|
|
strings[i] = g_strdup (buf);
|
|
}
|
|
|
|
g_value_take_boxed (target_value, strings);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_addresses_from_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
char **strings;
|
|
GArray *addrs;
|
|
guint32 addr;
|
|
int i;
|
|
|
|
strings = g_value_get_boxed (source_value);
|
|
addrs = g_array_new (FALSE, FALSE, sizeof (guint32));
|
|
|
|
for (i = 0; strings[i]; i++) {
|
|
if (!ip_string_parse (strings[i], AF_INET, &addr, NULL)) {
|
|
g_array_unref (addrs);
|
|
return FALSE;
|
|
}
|
|
g_array_append_val (addrs, addr);
|
|
}
|
|
|
|
g_value_take_boxed (target_value, addrs);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip4_addresses_to_strv:
|
|
* @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 %DBUS_TYPE_G_UINT_ARRAY property @source_property on
|
|
* @source to the %G_TYPE_STRV property @target_property on @target.
|
|
*
|
|
* Each address in @source_property will be converted to a string of
|
|
* the form "ip.ad.dr.ess" in @target_property (and vice versa if
|
|
* %G_BINDING_BIDIRECTIONAL) is specified.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip4_addresses_to_strv (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,
|
|
ip4_addresses_to_strv,
|
|
ip4_addresses_from_strv,
|
|
NULL, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
ip4_gateway_to_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
GArray *addr;
|
|
guint32 gateway = 0;
|
|
const char *str;
|
|
char buf[INET_ADDRSTRLEN];
|
|
int i;
|
|
|
|
addrs = g_value_get_boxed (source_value);
|
|
for (i = 0; i < addrs->len; i++) {
|
|
addr = addrs->pdata[i];
|
|
gateway = g_array_index (addr, guint32, 2);
|
|
if (gateway)
|
|
break;
|
|
}
|
|
|
|
if (gateway)
|
|
str = inet_ntop (AF_INET, &gateway, buf, sizeof (buf));
|
|
else
|
|
str = "";
|
|
g_value_set_string (target_value, str);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_gateway_from_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
const char *text;
|
|
GPtrArray *addrs;
|
|
GArray *addr;
|
|
guint32 addrbytes, *addrvals;
|
|
int i;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (!ip_string_parse (text, AF_INET, &addrbytes, NULL))
|
|
return FALSE;
|
|
|
|
/* Fetch the original property value, so as to preserve the IP address elements */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &addrs,
|
|
NULL);
|
|
if (!addrs->len) {
|
|
g_ptr_array_unref (addrs);
|
|
return FALSE;
|
|
}
|
|
addr = addrs->pdata[0];
|
|
addrvals = (guint32 *)addr->data;
|
|
if (addrbytes == addrvals[2]) {
|
|
g_ptr_array_unref (addrs);
|
|
return FALSE;
|
|
}
|
|
addrvals[2] = addrbytes;
|
|
|
|
for (i = 1; i < addrs->len; i++) {
|
|
addr = addrs->pdata[i];
|
|
addrvals = (guint32 *)addr->data;
|
|
addrvals[2] = 0;
|
|
}
|
|
|
|
g_value_take_boxed (target_value, addrs);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip4_gateway_to_string:
|
|
* @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 #NmtNewtEntry)
|
|
* @target_property: the property on @target to bind
|
|
* (eg, "text")
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the %DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT property
|
|
* @source_property on @source to the %G_TYPE_STRING property
|
|
* @target_property on @target.
|
|
*
|
|
* Specifically, this binds the "gateway" field of the first address
|
|
* in @source_property; all other addresses in @source_property are
|
|
* ignored, and its "address" and "prefix" fields are unmodified.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip4_gateway_to_string (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,
|
|
ip4_gateway_to_string,
|
|
ip4_gateway_from_string,
|
|
NULL, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
ip4_route_transform_to_dest_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP4Route *route;
|
|
char buf[INET_ADDRSTRLEN], *string;
|
|
guint32 addrbytes;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route)
|
|
addrbytes = nm_ip4_route_get_dest (route);
|
|
else
|
|
addrbytes = 0;
|
|
|
|
if (addrbytes) {
|
|
string = g_strdup_printf ("%s/%d",
|
|
inet_ntop (AF_INET, &addrbytes, buf, sizeof (buf)),
|
|
(int) nm_ip4_route_get_prefix (route));
|
|
g_value_take_string (target_value, string);
|
|
} else
|
|
g_value_set_string (target_value, "");
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_route_transform_to_next_hop_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP4Route *route;
|
|
char buf[INET_ADDRSTRLEN];
|
|
guint32 addrbytes;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route)
|
|
addrbytes = nm_ip4_route_get_next_hop (route);
|
|
else
|
|
addrbytes = 0;
|
|
|
|
if (addrbytes)
|
|
inet_ntop (AF_INET, &addrbytes, buf, sizeof (buf));
|
|
else
|
|
buf[0] = '\0';
|
|
g_value_set_string (target_value, buf);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_route_transform_to_metric_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP4Route *route;
|
|
char *string;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route && nm_ip4_route_get_dest (route)) {
|
|
string = g_strdup_printf ("%lu", (gulong) nm_ip4_route_get_metric (route));
|
|
g_value_take_string (target_value, string);
|
|
} else
|
|
g_value_set_string (target_value, "");
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_route_transform_from_dest_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP4Route *route;
|
|
const char *text;
|
|
guint32 addrbytes, prefix;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (!ip_string_parse (text, AF_INET, &addrbytes, &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_ip4_route_set_dest (route, addrbytes);
|
|
nm_ip4_route_set_prefix (route, prefix);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_route_transform_from_next_hop_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP4Route *route;
|
|
const char *text;
|
|
guint32 addrbytes;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (*text) {
|
|
if (!ip_string_parse (text, AF_INET, &addrbytes, NULL))
|
|
return FALSE;
|
|
} else
|
|
addrbytes = 0;
|
|
|
|
/* Fetch the original property value */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &route,
|
|
NULL);
|
|
|
|
nm_ip4_route_set_next_hop (route, addrbytes);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip4_route_transform_from_metric_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP4Route *route;
|
|
const char *text;
|
|
guint32 metric;
|
|
|
|
text = g_value_get_string (source_value);
|
|
metric = strtoul (text, NULL, 10);
|
|
|
|
/* Fetch the original property value */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &route,
|
|
NULL);
|
|
|
|
nm_ip4_route_set_metric (route, metric);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip4_route_to_strings:
|
|
* @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 #NMIP4Route-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
|
|
* is a plain IP address, and @metric_target is a number.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip4_route_to_strings (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,
|
|
ip4_route_transform_to_dest_string,
|
|
ip4_route_transform_from_dest_string,
|
|
NULL, NULL);
|
|
g_object_bind_property_full (source, source_property,
|
|
next_hop_target, next_hop_target_property,
|
|
flags,
|
|
ip4_route_transform_to_next_hop_string,
|
|
ip4_route_transform_from_next_hop_string,
|
|
NULL, NULL);
|
|
g_object_bind_property_full (source, source_property,
|
|
metric_target, metric_target_property,
|
|
flags,
|
|
ip4_route_transform_to_metric_string,
|
|
ip4_route_transform_from_metric_string,
|
|
NULL, NULL);
|
|
}
|
|
|
|
#define IP6_ADDRESS_SET(addr) ( addr \
|
|
&& addr->len == sizeof (struct in6_addr) \
|
|
&& memcmp (addr->data, &in6addr_any, addr->len) != 0)
|
|
|
|
static gboolean
|
|
ip6_addresses_with_prefix_to_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
GValueArray *addr;
|
|
GValue *val;
|
|
GByteArray *addrbytes;
|
|
guint prefix;
|
|
char **strings, buf[INET6_ADDRSTRLEN];
|
|
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];
|
|
val = g_value_array_get_nth (addr, 0);
|
|
addrbytes = g_value_get_boxed (val);
|
|
val = g_value_array_get_nth (addr, 1);
|
|
prefix = g_value_get_uint (val);
|
|
|
|
if (IP6_ADDRESS_SET (addrbytes)) {
|
|
strings[i] = g_strdup_printf ("%s/%d",
|
|
inet_ntop (AF_INET6, addrbytes->data, buf, sizeof (buf)),
|
|
prefix);
|
|
} else
|
|
strings[i] = g_strdup ("");
|
|
}
|
|
|
|
g_value_take_boxed (target_value, strings);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip6_addresses_with_prefix_from_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
char **strings;
|
|
GPtrArray *addrs;
|
|
GValueArray *addr;
|
|
guint32 prefix;
|
|
GValue val = G_VALUE_INIT, *valp;
|
|
GByteArray *ba;
|
|
int i;
|
|
|
|
strings = g_value_get_boxed (source_value);
|
|
|
|
/* Fetch the original property value, so as to preserve the gateway elements */
|
|
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) {
|
|
addr = g_value_array_new (3);
|
|
|
|
g_value_init (&val, DBUS_TYPE_G_UCHAR_ARRAY);
|
|
ba = g_byte_array_sized_new (sizeof (struct in6_addr));
|
|
g_byte_array_append (ba, (guint8 *) &in6addr_any, sizeof (struct in6_addr));
|
|
g_value_take_boxed (&val, ba);
|
|
g_value_array_append (addr, &val);
|
|
g_value_unset (&val);
|
|
|
|
g_value_init (&val, G_TYPE_UINT);
|
|
g_value_set_uint (&val, 128);
|
|
g_value_array_append (addr, &val);
|
|
g_value_unset (&val);
|
|
|
|
g_value_init (&val, DBUS_TYPE_G_UCHAR_ARRAY);
|
|
ba = g_byte_array_sized_new (sizeof (struct in6_addr));
|
|
g_byte_array_append (ba, (guint8 *) &in6addr_any, sizeof (struct in6_addr));
|
|
g_value_take_boxed (&val, ba);
|
|
g_value_array_append (addr, &val);
|
|
g_value_unset (&val);
|
|
|
|
g_ptr_array_add (addrs, addr);
|
|
} else
|
|
addr = addrs->pdata[i];
|
|
|
|
valp = g_value_array_get_nth (addr, 0);
|
|
ba = g_value_get_boxed (valp);
|
|
g_assert (ba->len == sizeof (struct in6_addr));
|
|
|
|
if (!ip_string_parse (strings[i], AF_INET6, ba->data, &prefix)) {
|
|
g_ptr_array_unref (addrs);
|
|
return FALSE;
|
|
}
|
|
|
|
valp = g_value_array_get_nth (addr, 1);
|
|
g_value_set_uint (valp, prefix);
|
|
}
|
|
|
|
g_ptr_array_set_size (addrs, i);
|
|
g_value_set_boxed (target_value, addrs);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip6_addresses_with_prefix_to_strv:
|
|
* @source: the source object (eg, an #NMSettingIP6Config)
|
|
* @source_property: the property on @source to bind (eg,
|
|
* %NM_SETTING_IP6_CONFIG_ADDRESSES)
|
|
* @target: the target object (eg, an #NmtAddressList)
|
|
* @target_property: the property on @target to bind
|
|
* (eg, "strings")
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the %DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS property
|
|
* @source_property on @source to the %G_TYPE_STRV property
|
|
* @target_property on @target.
|
|
*
|
|
* Each address/prefix/gateway triplet in @source_property will be
|
|
* converted to a string of the form "ip::ad:dr:ess/prefix" in
|
|
* @target_property (and vice versa if %G_BINDING_BIDIRECTIONAL) is
|
|
* specified. The "gateway" fields in @source_property are ignored
|
|
* when converting to strings, and unmodified when converting from
|
|
* strings.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip6_addresses_with_prefix_to_strv (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,
|
|
ip6_addresses_with_prefix_to_strv,
|
|
ip6_addresses_with_prefix_from_strv,
|
|
NULL, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
ip6_addresses_to_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
GByteArray *addrbytes;
|
|
char buf[INET6_ADDRSTRLEN], **strings;
|
|
int i;
|
|
|
|
addrs = g_value_get_boxed (source_value);
|
|
strings = g_new0 (char *, addrs->len + 1);
|
|
|
|
for (i = 0; i < addrs->len; i++) {
|
|
addrbytes = addrs->pdata[i];
|
|
if (IP6_ADDRESS_SET (addrbytes))
|
|
inet_ntop (AF_INET6, addrbytes->data, buf, sizeof (buf));
|
|
else
|
|
buf[0] = '\0';
|
|
strings[i] = g_strdup (buf);
|
|
}
|
|
|
|
g_value_take_boxed (target_value, strings);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip6_addresses_from_strv (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
char **strings;
|
|
GPtrArray *addrs;
|
|
GByteArray *addr;
|
|
struct in6_addr addrbytes;
|
|
int i;
|
|
|
|
strings = g_value_get_boxed (source_value);
|
|
addrs = g_ptr_array_new ();
|
|
|
|
for (i = 0; strings[i]; i++) {
|
|
if (!ip_string_parse (strings[i], AF_INET6, &addrbytes, NULL)) {
|
|
while (i--)
|
|
g_byte_array_unref (addrs->pdata[i]);
|
|
g_ptr_array_unref (addrs);
|
|
return FALSE;
|
|
}
|
|
|
|
addr = g_byte_array_sized_new (sizeof (addrbytes));
|
|
g_byte_array_append (addr, (guint8 *)&addrbytes, sizeof (addrbytes));
|
|
g_ptr_array_add (addrs, addr);
|
|
}
|
|
|
|
g_value_take_boxed (target_value, addrs);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip6_addresses_to_strv:
|
|
* @source: the source object (eg, an #NMSettingIP6Config)
|
|
* @source_property: the property on @source to bind (eg,
|
|
* %NM_SETTING_IP6_CONFIG_DNS)
|
|
* @target: the target object (eg, an #NmtAddressList)
|
|
* @target_property: the property on @target to bind
|
|
* (eg, "strings")
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the %DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR property
|
|
* @source_property on @source to the %G_TYPE_STRV property
|
|
* @target_property on @target.
|
|
*
|
|
* Each address in @source_property will be converted to a string of
|
|
* the form "ip::ad:dr:ess" in @target_property (and vice versa if
|
|
* %G_BINDING_BIDIRECTIONAL) is specified.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip6_addresses_to_strv (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,
|
|
ip6_addresses_to_strv,
|
|
ip6_addresses_from_strv,
|
|
NULL, NULL);
|
|
}
|
|
|
|
static gboolean
|
|
ip6_gateway_to_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
GValueArray *addr;
|
|
GValue *val;
|
|
GByteArray *gateway;
|
|
char buf[INET6_ADDRSTRLEN];
|
|
const char *str;
|
|
|
|
addrs = g_value_get_boxed (source_value);
|
|
if (addrs->len == 0)
|
|
return FALSE;
|
|
|
|
addr = addrs->pdata[0];
|
|
val = g_value_array_get_nth (addr, 2);
|
|
gateway = g_value_get_boxed (val);
|
|
|
|
if (IP6_ADDRESS_SET (gateway))
|
|
str = inet_ntop (AF_INET6, gateway->data, buf, sizeof (buf));
|
|
else
|
|
str = "";
|
|
g_value_set_string (target_value, str);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip6_gateway_from_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GPtrArray *addrs;
|
|
const char *text;
|
|
GValueArray *addr;
|
|
struct in6_addr gateway;
|
|
GValue *val;
|
|
GByteArray *ba;
|
|
int i;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (!ip_string_parse (text, AF_INET6, &gateway, NULL))
|
|
return FALSE;
|
|
|
|
/* Fetch the original property value, so as to preserve the IP address elements */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &addrs,
|
|
NULL);
|
|
if (!addrs->len) {
|
|
g_ptr_array_unref (addrs);
|
|
return FALSE;
|
|
}
|
|
|
|
addr = addrs->pdata[0];
|
|
|
|
ba = g_byte_array_sized_new (sizeof (gateway));
|
|
g_byte_array_append (ba, (guint8 *) &gateway, sizeof (gateway));
|
|
|
|
val = g_value_array_get_nth (addr, 2);
|
|
g_value_take_boxed (val, ba);
|
|
|
|
for (i = 1; i < addrs->len; i++) {
|
|
addr = addrs->pdata[i];
|
|
val = g_value_array_get_nth (addr, 2);
|
|
ba = g_value_get_boxed (val);
|
|
|
|
if (ba)
|
|
memset (ba->data, 0, ba->len);
|
|
}
|
|
|
|
g_value_take_boxed (target_value, addrs);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip6_gateway_to_string:
|
|
* @source: the source object (eg, an #NMSettingIP6Config)
|
|
* @source_property: the property on @source to bind (eg,
|
|
* %NM_SETTING_IP6_CONFIG_ADDRESSES)
|
|
* @target: the target object (eg, an #NmtNewtEntry)
|
|
* @target_property: the property on @target to bind
|
|
* (eg, "text")
|
|
* @flags: %GBindingFlags
|
|
*
|
|
* Binds the %DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS property
|
|
* @source_property on @source to the %G_TYPE_STRING property
|
|
* @target_property on @target.
|
|
*
|
|
* Specifically, this binds the "gateway" field of the first address
|
|
* in @source_property; all other addresses in @source_property are
|
|
* ignored, and its "address" and "prefix" fields are unmodified.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip6_gateway_to_string (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,
|
|
ip6_gateway_to_string,
|
|
ip6_gateway_from_string,
|
|
NULL, NULL);
|
|
}
|
|
|
|
#define IN6_ADDR_SET(bytes) (memcmp (bytes, &in6addr_any, sizeof (struct in6_addr)) != 0)
|
|
|
|
static gboolean
|
|
ip6_route_transform_to_dest_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP6Route *route;
|
|
char buf[INET6_ADDRSTRLEN], *string;
|
|
const struct in6_addr *addrbytes;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route)
|
|
addrbytes = nm_ip6_route_get_dest (route);
|
|
else
|
|
addrbytes = &in6addr_any;
|
|
|
|
if (IN6_ADDR_SET (addrbytes)) {
|
|
string = g_strdup_printf ("%s/%d",
|
|
inet_ntop (AF_INET6, addrbytes, buf, sizeof (buf)),
|
|
(int) nm_ip6_route_get_prefix (route));
|
|
g_value_take_string (target_value, string);
|
|
} else
|
|
g_value_set_string (target_value, "");
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip6_route_transform_to_next_hop_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP6Route *route;
|
|
char buf[INET6_ADDRSTRLEN];
|
|
const struct in6_addr *addrbytes;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route)
|
|
addrbytes = nm_ip6_route_get_next_hop (route);
|
|
else
|
|
addrbytes = &in6addr_any;
|
|
|
|
if (IN6_ADDR_SET (addrbytes))
|
|
inet_ntop (AF_INET6, addrbytes, buf, sizeof (buf));
|
|
else
|
|
buf[0] = '\0';
|
|
g_value_set_string (target_value, buf);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip6_route_transform_to_metric_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP6Route *route;
|
|
char *string;
|
|
|
|
route = g_value_get_boxed (source_value);
|
|
if (route && IN6_ADDR_SET (nm_ip6_route_get_dest (route))) {
|
|
string = g_strdup_printf ("%lu", (gulong) nm_ip6_route_get_metric (route));
|
|
g_value_take_string (target_value, string);
|
|
} else
|
|
g_value_set_string (target_value, "");
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip6_route_transform_from_dest_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP6Route *route;
|
|
const char *text;
|
|
struct in6_addr addrbytes;
|
|
guint32 prefix;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (!ip_string_parse (text, AF_INET6, &addrbytes, &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_ip6_route_set_dest (route, &addrbytes);
|
|
nm_ip6_route_set_prefix (route, prefix);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip6_route_transform_from_next_hop_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP6Route *route;
|
|
const char *text;
|
|
struct in6_addr addrbytes;
|
|
|
|
text = g_value_get_string (source_value);
|
|
if (*text) {
|
|
if (!ip_string_parse (text, AF_INET6, &addrbytes, NULL))
|
|
return FALSE;
|
|
} else
|
|
addrbytes = in6addr_any;
|
|
|
|
/* Fetch the original property value */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &route,
|
|
NULL);
|
|
|
|
nm_ip6_route_set_next_hop (route, &addrbytes);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
ip6_route_transform_from_metric_string (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
NMIP6Route *route;
|
|
const char *text;
|
|
guint32 metric;
|
|
|
|
text = g_value_get_string (source_value);
|
|
metric = strtoul (text, NULL, 10);
|
|
|
|
/* Fetch the original property value */
|
|
g_object_get (g_binding_get_source (binding),
|
|
g_binding_get_source_property (binding), &route,
|
|
NULL);
|
|
|
|
nm_ip6_route_set_metric (route, metric);
|
|
|
|
g_value_take_boxed (target_value, route);
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* nm_editor_bind_ip6_route_to_strings:
|
|
* @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 #NMIP6Route-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_ip6_addresses_with_prefix_to_strv(). @next_hop_target
|
|
* is a plain IP address, and @metric_target is a number.
|
|
*/
|
|
void
|
|
nm_editor_bind_ip6_route_to_strings (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,
|
|
ip6_route_transform_to_dest_string,
|
|
ip6_route_transform_from_dest_string,
|
|
NULL, NULL);
|
|
g_object_bind_property_full (source, source_property,
|
|
next_hop_target, next_hop_target_property,
|
|
flags,
|
|
ip6_route_transform_to_next_hop_string,
|
|
ip6_route_transform_from_next_hop_string,
|
|
NULL, NULL);
|
|
g_object_bind_property_full (source, source_property,
|
|
metric_target, metric_target_property,
|
|
flags,
|
|
ip6_route_transform_to_metric_string,
|
|
ip6_route_transform_from_metric_string,
|
|
NULL, 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;
|
|
|
|
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_vlan_get_interface_name (binding->s_vlan);
|
|
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)
|
|
{
|
|
NMEditorVlanWidgetBinding *binding;
|
|
const char *ifname;
|
|
|
|
binding = g_slice_new0 (NMEditorVlanWidgetBinding);
|
|
binding->s_vlan = s_vlan;
|
|
|
|
g_signal_connect (s_vlan, "notify::" NM_SETTING_VLAN_INTERFACE_NAME,
|
|
G_CALLBACK (vlan_settings_changed), binding);
|
|
|
|
g_object_weak_ref (G_OBJECT (s_vlan), vlan_target_destroyed, binding);
|
|
|
|
ifname = nm_setting_vlan_get_interface_name (s_vlan);
|
|
if (!parse_interface_name (ifname, &binding->last_ifname_parent, &binding->last_ifname_id)) {
|
|
binding->last_ifname_parent = NULL;
|
|
binding->last_ifname_id = 0;
|
|
}
|
|
}
|