diff options
| author | Sebastien Bacher <seb128@ubuntu.com> | 2021-08-25 15:24:42 +0200 |
|---|---|---|
| committer | Sebastien Bacher <seb128@ubuntu.com> | 2021-08-25 15:24:42 +0200 |
| commit | dbb91282fa488964fb20595f9494a9f0e4f36a58 (patch) | |
| tree | 142bc942e5320b35514cdf03a5f9f47a9b89df0e /src/libnm-core-impl | |
| parent | 5f2ede3a2813b0e9204befdcfc67509d34be71c6 (diff) | |
| parent | cfb80376641fa49137b9996130352697e7f8b436 (diff) | |
Update upstream source from tag 'upstream/1.32.10'
Update to upstream version '1.32.10' with Debian dir fcf2778b50b013ede3e7375bc1d829e984175658
Diffstat (limited to 'src/libnm-core-impl')
| -rw-r--r-- | src/libnm-core-impl/meson.build | 36 | ||||
| -rw-r--r-- | src/libnm-core-impl/nm-connection.c | 2 | ||||
| -rw-r--r-- | src/libnm-core-impl/nm-keyfile-utils.c | 4 | ||||
| -rw-r--r-- | src/libnm-core-impl/nm-keyfile.c | 3 | ||||
| -rw-r--r-- | src/libnm-core-impl/nm-setting-bond.c | 37 | ||||
| -rw-r--r-- | src/libnm-core-impl/nm-setting-ip-config.c | 61 | ||||
| -rw-r--r-- | src/libnm-core-impl/nm-setting-ip4-config.c | 2 | ||||
| -rw-r--r-- | src/libnm-core-impl/nm-setting-ip6-config.c | 9 | ||||
| -rw-r--r-- | src/libnm-core-impl/nm-setting-wireless.c | 60 | ||||
| -rw-r--r-- | src/libnm-core-impl/tests/meson.build | 2 | ||||
| -rw-r--r-- | src/libnm-core-impl/tests/test-general.c | 14 |
11 files changed, 201 insertions, 29 deletions
diff --git a/src/libnm-core-impl/meson.build b/src/libnm-core-impl/meson.build index 2b769616..f175ea3b 100644 --- a/src/libnm-core-impl/meson.build +++ b/src/libnm-core-impl/meson.build @@ -2,23 +2,27 @@ libnm_core_impl_inc = include_directories('.') -libnm_crypto_nss = static_library( - 'nm-crypto-nss', - sources: 'nm-crypto-nss.c', - dependencies: [ - libnm_core_public_dep, - crypto_nss_dep, - ], -) +if crypto_nss_dep.found() + libnm_crypto_nss = static_library( + 'nm-crypto-nss', + sources: 'nm-crypto-nss.c', + dependencies: [ + libnm_core_public_dep, + crypto_nss_dep, + ], + ) +endif -libnm_crypto_gnutls = static_library( - 'nm-crypto-gnutls', - sources: 'nm-crypto-gnutls.c', - dependencies: [ - libnm_core_public_dep, - crypto_gnutls_dep, - ], -) +if crypto_gnutls_dep.found() + libnm_crypto_gnutls = static_library( + 'nm-crypto-gnutls', + sources: 'nm-crypto-gnutls.c', + dependencies: [ + libnm_core_public_dep, + crypto_gnutls_dep, + ], + ) +endif if crypto == 'nss' libnm_crypto = libnm_crypto_nss diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index ed864db8..4ac7b322 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -649,7 +649,7 @@ nm_connection_replace_settings_from_connection(NMConnection *connection, { NMConnectionPrivate *priv; NMConnectionPrivate *new_priv; - gboolean changed; + gboolean changed = FALSE; int i; g_return_if_fail(NM_IS_CONNECTION(connection)); diff --git a/src/libnm-core-impl/nm-keyfile-utils.c b/src/libnm-core-impl/nm-keyfile-utils.c index 88f9c4f9..f8c2f387 100644 --- a/src/libnm-core-impl/nm-keyfile-utils.c +++ b/src/libnm-core-impl/nm-keyfile-utils.c @@ -531,7 +531,7 @@ _keyfile_key_encode(const char *name, char **out_to_free) if (ch == '\0') return name; - if (ch < 0x20 || ch >= 127 || NM_IN_SET(ch, '=', '[', ']') + if (!nm_ascii_is_regular(ch) || NM_IN_SET(ch, '=', '[', ']') || (ch == '\\' && g_ascii_isxdigit(name[i + 1]) && g_ascii_isxdigit(name[i + 2])) || (ch == ' ' && name[i + 1] == '\0')) break; @@ -557,7 +557,7 @@ _keyfile_key_encode(const char *name, char **out_to_free) if (ch == '\0') break; - if (ch < 0x20 || ch >= 127 || NM_IN_SET(ch, '=', '[', ']') + if (!nm_ascii_is_regular(ch) || NM_IN_SET(ch, '=', '[', ']') || (ch == '\\' && g_ascii_isxdigit(name[i + 1]) && g_ascii_isxdigit(name[i + 2])) || (ch == ' ' && name[i + 1] == '\0')) { nm_str_buf_append_c(&str, '\\'); diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c index 88aa0d46..c6c4a2eb 100644 --- a/src/libnm-core-impl/nm-keyfile.c +++ b/src/libnm-core-impl/nm-keyfile.c @@ -2781,6 +2781,9 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { .parser = mac_address_parser_ETHER_cloned, ), PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_MAC_ADDRESS, .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_SEEN_BSSIDS, + .parser_skip = TRUE, + .writer_skip = TRUE, ), PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_SSID, .parser = ssid_parser, .writer = ssid_writer, ), ), ), diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c index 93baa9d6..252adc73 100644 --- a/src/libnm-core-impl/nm-setting-bond.c +++ b/src/libnm-core-impl/nm-setting-bond.c @@ -90,6 +90,7 @@ static const char *const valid_options_lst[] = { NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, NM_SETTING_BOND_OPTION_LP_INTERVAL, + NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, NULL, }; @@ -207,6 +208,7 @@ static NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE( {NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, {"1", NM_BOND_OPTION_TYPE_INT, 0, 255}}, {NM_SETTING_BOND_OPTION_NUM_UNSOL_NA, {"1", NM_BOND_OPTION_TYPE_INT, 0, 255}}, {NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, {"1", NM_BOND_OPTION_TYPE_INT, 0, 65535}}, + {NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}}, {NM_SETTING_BOND_OPTION_PRIMARY, {"", NM_BOND_OPTION_TYPE_IFNAME}}, {NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, {"always", NM_BOND_OPTION_TYPE_BOTH, 0, 2, _option_default_strv_primary_reselect}}, @@ -782,6 +784,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) int arp_interval; int num_grat_arp; int num_unsol_na; + int peer_notif_delay; const char * mode_str; const char * arp_ip_target = NULL; const char * lacp_rate; @@ -810,6 +813,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) arp_interval = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_ARP_INTERVAL)); num_grat_arp = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP)); num_unsol_na = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA)); + peer_notif_delay = + _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY)); /* Option restrictions: * @@ -818,6 +823,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) * arp_validate does not work with [ BOND_MODE_8023AD, BOND_MODE_TLB, BOND_MODE_ALB ] * downdelay needs miimon * updelay needs miimon + * peer_notif_delay needs miimon enabled + * peer_notif_delay must be a miimon multiple * primary needs [ active-backup, tlb, alb ] */ @@ -926,6 +933,36 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } } + if (peer_notif_delay) { + if (miimon == 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' option requires '%s' option to be enabled"), + NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, + NM_SETTING_BOND_OPTION_MIIMON); + g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + return FALSE; + } + + /* The code disables miimon when arp is set, so they never occur together. + * But this occurs after this verification, so this check can occur in + * an invalid state, when both arp and miimon are enabled. To assure not + * dealing with an invalid state, this arp_interval == 0 condition, + * that is implicit, was made explicit. + */ + if ((peer_notif_delay % miimon) && (arp_interval == 0)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' option needs to be a value multiple of '%s' value"), + NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, + NM_SETTING_BOND_OPTION_MIIMON); + g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + return FALSE; + } + } + /* arp_ip_target can only be used with arp_interval, and must * contain a comma-separated list of IPv4 addresses. */ diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c index 59ab5ca2..f37e9d35 100644 --- a/src/libnm-core-impl/nm-setting-ip-config.c +++ b/src/libnm-core-impl/nm-setting-ip-config.c @@ -3905,6 +3905,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingIPConfig, PROP_MAY_FAIL, PROP_DAD_TIMEOUT, PROP_DHCP_TIMEOUT, + PROP_REQUIRED_TIMEOUT, PROP_DHCP_IAID, PROP_DHCP_REJECT_SERVERS, ); @@ -3925,6 +3926,7 @@ typedef struct { int dns_priority; int dad_timeout; int dhcp_timeout; + int required_timeout; guint32 route_table; bool ignore_auto_routes : 1; bool ignore_auto_dns : 1; @@ -5206,6 +5208,25 @@ nm_setting_ip_config_get_dhcp_timeout(NMSettingIPConfig *setting) } /** + * nm_setting_ip_config_get_required_timeout: + * @setting: the #NMSettingIPConfig + * + * Returns the value contained in the #NMSettingIPConfig:required-timeout + * property. + * + * Returns: the required timeout for the address family + * + * Since: 1.34, 1.32.4 + **/ +int +nm_setting_ip_config_get_required_timeout(NMSettingIPConfig *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IP_CONFIG(setting), -1); + + return NM_SETTING_IP_CONFIG_GET_PRIVATE(setting)->required_timeout; +} + +/** * nm_setting_ip_config_get_dhcp_iaid: * @setting: the #NMSettingIPConfig * @@ -5908,6 +5929,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_DHCP_TIMEOUT: g_value_set_int(value, nm_setting_ip_config_get_dhcp_timeout(setting)); break; + case PROP_REQUIRED_TIMEOUT: + g_value_set_int(value, nm_setting_ip_config_get_required_timeout(setting)); + break; case PROP_DHCP_IAID: g_value_set_string(value, nm_setting_ip_config_get_dhcp_iaid(setting)); break; @@ -6018,7 +6042,11 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps case PROP_DHCP_TIMEOUT: priv->dhcp_timeout = g_value_get_int(value); break; + case PROP_REQUIRED_TIMEOUT: + priv->required_timeout = g_value_get_int(value); + break; case PROP_DHCP_IAID: + g_free(priv->dhcp_iaid); priv->dhcp_iaid = g_value_dup_string(value); break; case PROP_DHCP_HOSTNAME_FLAGS: @@ -6048,6 +6076,7 @@ nm_setting_ip_config_init(NMSettingIPConfig *setting) priv->dhcp_send_hostname = TRUE; priv->may_fail = TRUE; priv->dad_timeout = -1; + priv->required_timeout = -1; } static void @@ -6483,6 +6512,38 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) G_PARAM_READWRITE | NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_STATIC_STRINGS); /** + * NMSettingIPConfig:required-timeout: + * + * The minimum time interval in milliseconds for which dynamic IP configuration + * should be tried before the connection succeeds. + * + * This property is useful for example if both IPv4 and IPv6 are enabled and + * are allowed to fail. Normally the connection succeeds as soon as one of + * the two address families completes; by setting a required timeout for + * e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, + * NetworkManager waits some time for IPv4 before the connection becomes + * active. + * + * Note that if #NMSettingIPConfig:may-fail is FALSE for the same address + * family, this property has no effect as NetworkManager needs to wait for + * the full DHCP timeout. + * + * A zero value means that no required timeout is present, -1 means the + * default value (either configuration ipvx.required-timeout override or + * zero). + * + * Since: 1.34, 1.32.4 + **/ + obj_properties[PROP_REQUIRED_TIMEOUT] = g_param_spec_int( + NM_SETTING_IP_CONFIG_REQUIRED_TIMEOUT, + "", + "", + -1, + G_MAXINT32, + -1, + G_PARAM_READWRITE | NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_STATIC_STRINGS); + + /** * NMSettingIPConfig:dhcp-iaid: * * A string containing the "Identity Association Identifier" (IAID) used diff --git a/src/libnm-core-impl/nm-setting-ip4-config.c b/src/libnm-core-impl/nm-setting-ip4-config.c index 15bae0cd..b3a18bca 100644 --- a/src/libnm-core-impl/nm-setting-ip4-config.c +++ b/src/libnm-core-impl/nm-setting-ip4-config.c @@ -967,6 +967,8 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * format: a comma separated list of addresses * description: A list of IPv4 addresses and their prefix length. Multiple addresses * can be separated by comma. For example "192.168.1.5/24, 10.1.0.5/24". + * The addresses are listed in increasing priority, meaning the last address will + * be the primary address. * ---end--- */ _nm_properties_override_gobj( diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c index f6d59a46..ee72de57 100644 --- a/src/libnm-core-impl/nm-setting-ip6-config.c +++ b/src/libnm-core-impl/nm-setting-ip6-config.c @@ -1030,6 +1030,15 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * that subnet. * ---end--- */ + /* ---nmcli--- + * property: addresses + * format: a comma separated list of addresses + * description: A list of IPv6 addresses and their prefix length. Multiple addresses + * can be separated by comma. For example "2001:db8:85a3::8a2e:370:7334/64, 2001:db8:85a3::5/64". + * The addresses are listed in increasing priority, meaning the last address will + * be the primary address. + * ---end--- + */ _nm_properties_override_gobj( properties_override, g_object_class_find_property(G_OBJECT_CLASS(setting_class), NM_SETTING_IP_CONFIG_ADDRESSES), diff --git a/src/libnm-core-impl/nm-setting-wireless.c b/src/libnm-core-impl/nm-setting-wireless.c index 11111696..5bdedf9b 100644 --- a/src/libnm-core-impl/nm-setting-wireless.c +++ b/src/libnm-core-impl/nm-setting-wireless.c @@ -750,19 +750,54 @@ _to_dbus_fcn_seen_bssids(const NMSettInfoSetting * sett_info, NMConnectionSerializationFlags flags, const NMConnectionSerializationOptions *options) { + if (options && options->seen_bssids) + return options->seen_bssids[0] ? g_variant_new_strv(options->seen_bssids, -1) : NULL; + + /* The seen-bssid property is special. It cannot be converted to D-Bus + * like regular properties, only via the "options". + * + * This basically means, that only the daemon can provide seen-bssids as GVariant, + * while when a client converts the property to GVariant, it gets lost. + * + * This has the odd effect, that when the client converts the setting to GVariant + * and back, the seen-bssids gets lost. That is kinda desired here, because the to_dbus_fcn() + * and from_dbus_fcn() have the meaning of how a setting gets transferred via D-Bus, + * and not necessarily a loss-less conversion into another format and back. And when + * transferring via D-Bus, then the option makes only sense when sending it from + * the daemon to the client, not otherwise. */ + return NULL; +} + +static gboolean +_from_dbus_fcn_seen_bssids(NMSetting * setting, + GVariant * connection_dict, + const char * property, + GVariant * value, + NMSettingParseFlags parse_flags, + GError ** error) +{ NMSettingWirelessPrivate *priv; + gs_free const char ** s = NULL; + gsize len; + gsize i; - if (options && options->seen_bssids) { - return options->seen_bssids[0] ? g_variant_new_strv(options->seen_bssids, -1) : NULL; + if (_nm_utils_is_manager_process) { + /* in the manager process, we don't accept seen-bssid from the client. + * Do nothing. */ + return TRUE; } priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting); - if (!priv->seen_bssids || priv->seen_bssids->len == 0) - return NULL; + nm_clear_pointer(&priv->seen_bssids, g_ptr_array_unref); - return g_variant_new_strv((const char *const *) priv->seen_bssids->pdata, - priv->seen_bssids->len); + s = g_variant_get_strv(value, &len); + if (len > 0) { + priv->seen_bssids = g_ptr_array_new_full(len, g_free); + for (i = 0; i < len; i++) + g_ptr_array_add(priv->seen_bssids, g_strdup(s[i])); + } + return TRUE; } /** @@ -1075,12 +1110,18 @@ compare_property(const NMSettInfoSetting *sett_info, NMSetting * set_b, NMSettingCompareFlags flags) { - if (nm_streq(sett_info->property_infos[property_idx].name, - NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)) { + if (sett_info->property_infos[property_idx].param_spec + == obj_properties[PROP_CLONED_MAC_ADDRESS]) { return !set_b || nm_streq0(NM_SETTING_WIRELESS_GET_PRIVATE(set_a)->cloned_mac_address, NM_SETTING_WIRELESS_GET_PRIVATE(set_b)->cloned_mac_address); } + if (sett_info->property_infos[property_idx].param_spec == obj_properties[PROP_SEEN_BSSIDS]) { + return !set_b + || (nm_strv_ptrarray_cmp(NM_SETTING_WIRELESS_GET_PRIVATE(set_a)->seen_bssids, + NM_SETTING_WIRELESS_GET_PRIVATE(set_b)->seen_bssids) + == 0); + } return NM_SETTING_CLASS(nm_setting_wireless_parent_class) ->compare_property(sett_info, property_idx, con_a, set_a, con_b, set_b, flags); @@ -1744,7 +1785,8 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass) properties_override, obj_properties[PROP_SEEN_BSSIDS], NM_SETT_INFO_PROPERT_TYPE_DBUS(G_VARIANT_TYPE_STRING_ARRAY, - .to_dbus_fcn = _to_dbus_fcn_seen_bssids, )); + .to_dbus_fcn = _to_dbus_fcn_seen_bssids, + .from_dbus_fcn = _from_dbus_fcn_seen_bssids, )); /** * NMSettingWireless:mtu: diff --git a/src/libnm-core-impl/tests/meson.build b/src/libnm-core-impl/tests/meson.build index ca1d1c1a..988c60db 100644 --- a/src/libnm-core-impl/tests/meson.build +++ b/src/libnm-core-impl/tests/meson.build @@ -32,8 +32,8 @@ foreach test_unit: test_units libnm_core_impl, libnm_crypto, libnm_base, - libnm_log_null, libnm_systemd_shared, + libnm_log_null, libnm_glib_aux, libnm_std_aux, libc_siphash, diff --git a/src/libnm-core-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c index f9cc5e54..57864948 100644 --- a/src/libnm-core-impl/tests/test-general.c +++ b/src/libnm-core-impl/tests/test-general.c @@ -3868,6 +3868,7 @@ test_connection_diff_a_only(void) {NM_SETTING_IP_CONFIG_NEVER_DEFAULT, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_MAY_FAIL, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DAD_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_IP_CONFIG_REQUIRED_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DNS_PRIORITY, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DHCP_IAID, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER, NM_SETTING_DIFF_RESULT_IN_A}, @@ -9136,6 +9137,12 @@ _do_test_utils_str_utf8safe(const char * str, ((nmtst_get_rand_bool()) ? NM_UTILS_STR_UTF8_SAFE_FLAG_NONE \ : NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET) + if (expected && strlen(expected) == str_len && memcmp(str, expected, str_len) == 0) { + g_error("Test error: pass expected as NULL (instead of \"%s\", if the escaping will " + "produce no difference.", + expected); + } + buf_safe = nm_utils_buf_utf8safe_escape(str, str_len, flags | RND_FLAG, &str_free_1); str_safe = nm_utils_str_utf8safe_escape(str, flags | RND_FLAG, &str_free_2); @@ -9272,6 +9279,13 @@ test_utils_str_utf8safe(void) do_test_utils_str_utf8safe_unescape("\n\\012", "\n\012"); do_test_utils_str_utf8safe_unescape("\n\\.", "\n."); do_test_utils_str_utf8safe_unescape("\\n\\.3\\r", "\n.3\r"); + + do_test_utils_str_utf8safe("ab∞c", NULL, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL); + do_test_utils_str_utf8safe("ab\ab∞c", "ab\\007b∞c", NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL); + do_test_utils_str_utf8safe("ab\ab∞c", + "ab\\007b\\342\\210\\236c", + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL + | NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII); } /*****************************************************************************/ |