summary refs log tree commit diff
path: root/clients/cli/settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'clients/cli/settings.c')
-rw-r--r--clients/cli/settings.c261
1 files changed, 83 insertions, 178 deletions
diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index a04c8eb6..2446cb08 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -24,7 +24,7 @@
 #include <stdlib.h>
 #include <arpa/inet.h>
 
-#include "nm-common-macros.h"
+#include "nm-libnm-core-intern/nm-common-macros.h"
 
 #include "nm-client-utils.h"
 #include "nm-vpn-helpers.h"
@@ -89,7 +89,7 @@ ipv4_addresses_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_dat
 static void
 ipv4_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
 {
-	static GValue value = G_VALUE_INIT;
+	static GPtrArray *old_value = NULL;
 	static gboolean answered = FALSE;
 	static gboolean answer = FALSE;
 
@@ -103,17 +103,17 @@ ipv4_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
 				answer = get_answer ("ipv4.addresses", NULL);
 			}
 			if (answer) {
-				if (G_IS_VALUE (&value))
-					g_value_unset (&value);
-				nmc_property_get_gvalue (NM_SETTING (object), NM_SETTING_IP_CONFIG_ADDRESSES, &value);
+				nm_clear_pointer (&old_value, g_ptr_array_unref);
+				g_object_get (object, NM_SETTING_IP_CONFIG_ADDRESSES, &old_value, NULL);
 				g_object_set (object, NM_SETTING_IP_CONFIG_ADDRESSES, NULL, NULL);
 			}
 		}
 	} else {
 		answered = FALSE;
-		if (G_IS_VALUE (&value)) {
-			nmc_property_set_gvalue (NM_SETTING (object), NM_SETTING_IP_CONFIG_ADDRESSES, &value);
-			g_value_unset (&value);
+		if (old_value) {
+			gs_unref_ptrarray GPtrArray *v = g_steal_pointer (&old_value);
+
+			g_object_set (object, NM_SETTING_IP_CONFIG_ADDRESSES, v, NULL);
 		}
 	}
 
@@ -142,6 +142,25 @@ ipv6_addresses_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_dat
 		}
 	} else {
 		answered = FALSE;
+		/* FIXME: editor_init_existing_connection() and registering handlers is not the
+		 *  right approach.
+		 *
+		 * This only happens to work because in nmcli's edit mode
+		 * tends to append addresses -- instead of setting them.
+		 * If we would change that (to behavior I'd expect), we'd get:
+		 *
+		 *   nmcli> set ipv6.addresses fc01::1:5/68
+		 *   Do you also want to set 'ipv6.method' to 'manual'? [yes]: y
+		 *   nmcli> set ipv6.addresses fc01::1:6/68
+		 *   Do you also want to set 'ipv6.method' to 'manual'? [yes]:
+		 *
+		 * That's because nmc_setting_set_property() calls set_fcn(). With modifier '\0'
+		 * (set), it would first clear all addresses before adding the address. Thereby
+		 * emitting multiple property changed signals.
+		 *
+		 * That can be avoided by freezing/thawing the signals, but this solution
+		 * here is ugly in general.
+		 */
 		if (!g_strcmp0 (nm_setting_ip_config_get_method (NM_SETTING_IP_CONFIG (object)), NM_SETTING_IP6_CONFIG_METHOD_MANUAL))
 			g_object_set (object, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL);
 	}
@@ -152,7 +171,7 @@ ipv6_addresses_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_dat
 static void
 ipv6_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
 {
-	static GValue value = G_VALUE_INIT;
+	static GPtrArray *old_value = NULL;
 	static gboolean answered = FALSE;
 	static gboolean answer = FALSE;
 
@@ -166,17 +185,17 @@ ipv6_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
 				answer = get_answer ("ipv6.addresses", NULL);
 			}
 			if (answer) {
-				if (G_IS_VALUE (&value))
-					g_value_unset (&value);
-				nmc_property_get_gvalue (NM_SETTING (object), NM_SETTING_IP_CONFIG_ADDRESSES, &value);
+				nm_clear_pointer (&old_value, g_ptr_array_unref);
+				g_object_get (object, NM_SETTING_IP_CONFIG_ADDRESSES, &old_value, NULL);
 				g_object_set (object, NM_SETTING_IP_CONFIG_ADDRESSES, NULL, NULL);
 			}
 		}
 	} else {
 		answered = FALSE;
-		if (G_IS_VALUE (&value)) {
-			nmc_property_set_gvalue (NM_SETTING (object), NM_SETTING_IP_CONFIG_ADDRESSES, &value);
-			g_value_unset (&value);
+		if (old_value) {
+			gs_unref_ptrarray GPtrArray *v = g_steal_pointer (&old_value);
+
+			g_object_set (object, NM_SETTING_IP_CONFIG_ADDRESSES, v, NULL);
 		}
 	}
 
@@ -319,7 +338,7 @@ _set_fcn_precheck_connection_secondaries (NMClient *client,
 	char **iter;
 	gboolean modified = FALSE;
 
-	strv0 = nm_utils_strsplit_set (value, " \t,", FALSE);
+	strv0 = nm_utils_strsplit_set (value, " \t,");
 	if (!strv0)
 		return TRUE;
 
@@ -509,152 +528,73 @@ nmc_setting_get_property_parsable (NMSetting *setting, const char *prop, GError
 	return get_property_val (setting, prop, NM_META_ACCESSOR_GET_TYPE_PARSABLE, TRUE, error);
 }
 
-static gboolean
-_set_fcn_call (const NMMetaPropertyInfo *property_info,
-               NMSetting *setting,
-               const char *value,
-               GError **error)
-{
-	return property_info->property_type->set_fcn (property_info,
-	                                              nmc_meta_environment,
-	                                              nmc_meta_environment_arg,
-	                                              setting,
-	                                              value,
-	                                              error);
-}
-
-/*
- * Generic function for setting property value.
- *
- * Sets property=value in setting by calling specialized functions.
- * If value is NULL then default property value is set.
- *
- * Returns: TRUE on success; FALSE on failure and sets error
- */
 gboolean
-nmc_setting_set_property (NMClient *client, NMSetting *setting, const char *prop, const char *value, GError **error)
+nmc_setting_set_property (NMClient *client,
+                          NMSetting *setting,
+                          const char *prop,
+                          char modifier,
+                          const char *value,
+                          GError **error)
 {
 	const NMMetaPropertyInfo *property_info;
+	gs_free char *value_to_free = NULL;
+	gboolean success;
 
 	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	g_return_val_if_fail (NM_IN_SET (modifier, '\0', '-', '+'), FALSE);
 
-	if ((property_info = nm_meta_property_info_find_by_setting (setting, prop))) {
-
-		if (!value) {
-			/* No value argument sets default value */
-			nmc_property_set_default_value (setting, prop);
-			return TRUE;
-		}
-
-		if (property_info->property_type->set_fcn) {
-			switch (property_info->setting_info->general->meta_type) {
-			case NM_META_SETTING_TYPE_CONNECTION:
-				if (nm_streq (property_info->property_name, NM_SETTING_CONNECTION_SECONDARIES)) {
-					gs_free char *value_coerced = NULL;
-
-					if (!_set_fcn_precheck_connection_secondaries (client, value, &value_coerced, error))
-						return FALSE;
+	if (!(property_info = nm_meta_property_info_find_by_setting (setting, prop)))
+		goto out_fail_read_only;
+	if (!property_info->property_type->set_fcn)
+		goto out_fail_read_only;
 
-					return _set_fcn_call (property_info,
-					                      setting,
-					                      value_coerced ?: value,
-					                      error);
-				}
-				break;
-			default:
-				break;
-			}
-			return _set_fcn_call (property_info,
-			                      setting,
-			                      value,
-			                      error);
-		}
+	if (   NM_IN_SET (modifier, '+', '-')
+	    && !value) {
+		/* nothing to do. */
+		return TRUE;
 	}
 
-	g_set_error_literal (error, 1, 0, _("the property can't be changed"));
-	return FALSE;
-}
-
-void
-nmc_property_set_default_value (NMSetting *setting, const char *prop)
-{
-	GValue value = G_VALUE_INIT;
-	GParamSpec *param_spec;
-
-	param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
-	if (param_spec) {
-		g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (param_spec));
-		g_param_value_set_default (param_spec, &value);
-		g_object_set_property (G_OBJECT (setting), prop, &value);
+	if (   modifier == '-'
+	    && !property_info->property_type->set_supports_remove) {
+		/* The property is a plain property. It does not support '-'.
+		 *
+		 * Maybe we should fail, but just return silently. */
+		return TRUE;
 	}
-}
-
-/*
- * Generic function for resetting (single value) properties.
- *
- * The function resets the property value to the default one. It respects
- * nmcli restrictions for changing properties. So if 'set_func' is NULL,
- * resetting the value is denied.
- *
- * Returns: TRUE on success; FALSE on failure and sets error
- */
-gboolean
-nmc_setting_reset_property (NMSetting *setting, const char *prop, GError **error)
-{
-	const NMMetaPropertyInfo *property_info;
-
-	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	if ((property_info = nm_meta_property_info_find_by_setting (setting, prop))) {
-		if (property_info->property_type->set_fcn) {
-			nmc_property_set_default_value (setting, prop);
-			return TRUE;
+	if (value) {
+		switch (property_info->setting_info->general->meta_type) {
+		case NM_META_SETTING_TYPE_CONNECTION:
+			if (nm_streq (property_info->property_name, NM_SETTING_CONNECTION_SECONDARIES)) {
+				if (!_set_fcn_precheck_connection_secondaries (client, value, &value_to_free, error))
+					return FALSE;
+				if (value_to_free)
+					value = value_to_free;
+			}
+			break;
+		default:
+			break;
 		}
 	}
 
-	g_set_error_literal (error, 1, 0, _("the property can't be changed"));
+	g_object_freeze_notify (G_OBJECT (setting));
+	success = property_info->property_type->set_fcn (property_info,
+	                                                 nmc_meta_environment,
+	                                                 nmc_meta_environment_arg,
+	                                                 setting,
+	                                                 modifier,
+	                                                 value,
+	                                                 error);
+	g_object_thaw_notify (G_OBJECT (setting));
+	return success;
+
+out_fail_read_only:
+	nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, _("the property can't be changed"));
 	return FALSE;
 }
 
 /*
- * Generic function for removing items for collection-type properties.
- *
- * If 'option' is not NULL, it tries to remove it, otherwise 'idx' is used.
- * For single-value properties (not having specialized remove function) this
- * function does nothing and just returns TRUE.
- *
- * Returns: TRUE on success; FALSE on failure and sets error
- */
-gboolean
-nmc_setting_remove_property_option (NMSetting *setting,
-                                    const char *prop,
-                                    const char *option,
-                                    guint32 idx,
-                                    GError **error)
-{
-	const NMMetaPropertyInfo *property_info;
-
-	g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
-	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
-	if ((property_info = nm_meta_property_info_find_by_setting (setting, prop))) {
-		if (property_info->property_type->remove_fcn) {
-			return property_info->property_type->remove_fcn (property_info,
-			                                                 nmc_meta_environment,
-			                                                 nmc_meta_environment_arg,
-			                                                 setting,
-			                                                 option,
-			                                                 idx,
-			                                                 error);
-		}
-	}
-
-	return TRUE;
-}
-
-/*
  * Get valid property names for a setting.
  *
  * Returns: string array with the properties or NULL on failure.
@@ -749,41 +689,6 @@ nmc_setting_get_property_desc (NMSetting *setting, const char *prop)
 	                        nmcli_desc ?: "");
 }
 
-/*
- * Gets setting:prop property value and returns it in 'value'.
- * Caller is responsible for freeing the GValue resources using g_value_unset()
- */
-gboolean
-nmc_property_get_gvalue (NMSetting *setting, const char *prop, GValue *value)
-{
-	GParamSpec *param_spec;
-
-	param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
-	if (param_spec) {
-		memset (value, 0, sizeof (GValue));
-		g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (param_spec));
-		g_object_get_property (G_OBJECT (setting), prop, value);
-		return TRUE;
-	}
-	return FALSE;
-}
-
-/*
- * Sets setting:prop property value from 'value'.
- */
-gboolean
-nmc_property_set_gvalue (NMSetting *setting, const char *prop, GValue *value)
-{
-	GParamSpec *param_spec;
-
-	param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop);
-	if (param_spec && G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (param_spec)) {
-		g_object_set_property (G_OBJECT (setting), prop, value);
-		return TRUE;
-	}
-	return FALSE;
-}
-
 /*****************************************************************************/
 
 gboolean